Elyra
Elyra The coding agent e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Start here
Concepts
Elyra

Permissions

Two gates, deliberately not merged.

Gate::define('admin', fn (User $user) => (bool) $user->is_admin);

Gate::define('administer-workspace', function (User $user, ?Workspace $workspace = null) {
    $workspace ??= $user->currentWorkspace();

    return $user->roleIn($workspace)?->canManageMembers() === true;
});

Why two

admin is the operator of Félagi itself, across every workspace. administer-workspace is an owner or admin inside one workspace.

Collapsing them would mean a customer could only manage their own agents by being handed access to every other customer's data. A test locks the separation:

it does not grant workspace administration to a platform admin from outside — an operator has admin but not administer-workspace in a workspace they are not a member of.


Roles inside a workspace

Role Can
Member Work on issues: create, comment, assign, mention agents, run existing agents
Developer Everything a member can, plus hire agents, connect machines, write skills and build autopilots
Admin Everything a developer can, plus manage people and workspace settings
Owner Everything an admin can, plus delete the workspace

Developer exists because running the machines and deciding who works here are different kinds of trust. A contractor can be handed the agent workforce without also being handed the member list; a team forced to merge the two ends up giving everyone everything.

Two gates carry the split:

Gate Roles Covers
administer-agents owner, admin, developer Agents, runtimes, skills, autopilots
administer-workspace owner, admin Members, workspace settings, webhooks, import, cycles
write-knowledge every member Knowledge base articles, whiteboards

Navigation follows the gates rather than guessing: a developer is never shown a link that answers 403.

Two invariants are enforced when roles change:

  • A workspace cannot lose its last owner, by demotion or removal
  • Nobody can remove themselves, which would lock them out of their own workspace

Removing a membership never deletes the account or anything the person wrote.


Where each area lives

The widest gate in the product

write-knowledge grants to anybody who works here, which makes it look pointless — the check that matters is membership of the workspace, and every role passes it.

It is deliberate. A knowledge base only admins may write to is a knowledge base nobody writes to, and the failure mode of documentation is always that it was never written rather than that the wrong person wrote it. The same is true of a whiteboard: the early, messy phase of a project does not survive being gated.

Two narrower rules live on the records themselves rather than in a gate, because they are about what a deletion takes with it:

Action Who
Delete an article Its author, or a workspace admin — a section takes its children
Delete a whiteboard Its author, or a workspace admin
Change who sees a whiteboard Its author alone. The setting is about their comfort
Edit or delete a time entry Its author alone. Somebody else's hours are their statement
Edit an agent's time entry Nobody. The run is the record
Prefix Gate Contents
/app authenticated member Dashboard, projects, issues, agent roster, settings
/admin administer-workspace Members, agents, runtimes, skills, workspace settings
/system admin All users, analytics, system information

The agent roster stays in /app and is readable by every member. Seeing who is on the team is part of the product, the same way the member list is; only hiring, editing and archiving are administration.


Joining a workspace

Everybody is invited; nobody is inserted. An administrator sends an invitation to an email address, and nothing happens to any account until the recipient accepts it themselves.

That is a deliberate reversal of the obvious design. Creating an account for somebody means choosing their first password, which means knowing it — and a colleague should not have to trust that.

  • Invitation tokens are stored hashed and expire after 14 days
  • Re-inviting replaces the open invitation and invalidates the previous link
  • An address that already has an account joins with one click; a new one is created on the way in
  • The address is fixed by the invitation, never by the form. Otherwise the link is a free pass to a pre-verified account at any address
  • Accepting marks the address verified, because the link reached it
  • Being signed in as somebody else does not accept on their behalf — a forwarded invitation must not put the wrong person in a workspace

Where a platform admin comes from

Not from the interface. is_admin is not fillable, nothing grants it in a form or a route, and a test asserts that only one file in the codebase sets it — so if somebody adds a second way, that test asks whether they meant to.

php artisan felagi:admin ops@yourcompany.com

Shell access, in other words. Platform administration reaches across every workspace, and the boundary for it is the machine rather than a role somebody can be given from inside a customer's workspace.

Revoking the last one is refused: an installation with no platform admin cannot reach its own single sign-on or allowlist settings.


Two-factor authentication is not a role

It applies to everybody who signs in, regardless of role, and the exemption list is per address rather than per account or per workspace — deliberately, since anybody can create a workspace and a workspace-scoped exemption would be a way for any user to switch off a security control.

It lives in /system, on the platform-admin gate, for the same reason.

See Two-factor authentication.


Guarded attributes

is_admin and email_verified_at are not in User::$fillable, and a test enforces it. They must be set explicitly with forceFill, so no registration or profile-update path can ever grant platform administration through mass assignment.