Skip to main content

Workspaces

A workspace is the shared coordination context for a team working on one codebase. All agents connected to the same workspace share decisions, conventions, reservations, workstreams, tasks, and the symbol graph. Every workspace is bound to exactly one git repository. Binding is what makes “which workspace is this?” an unambiguous question — any teammate who clones the repo gets routed to the same workspace without guessing at a name.

Creating a Workspace

Pick whichever path matches how you’re onboarding — they all produce the same workspace.

Repo Binding

A binding is the pair (repo_url, repo_root_commit):
  • repo_url — normalized form of git remote get-url origin. git@github.com:Org/Repo.git, https://github.com/Org/Repo, and https://user:token@github.com/org/repo.git?ref=x all fold to the same canonical URL. Host is lowercased; org+repo are lowercased on GitHub/GitLab/Bitbucket (case-insensitive hosts).
  • repo_root_commit — SHA of the earliest commit (git rev-list --max-parents=0 --all, sorted). Stable across branches, clones, and forks of the same history.
The binding is 1:1: any given repo can be bound to at most one workspace, and any given workspace can be bound to at most one repo. This is what the CLI uses to detect “teammate B just cloned the repo teammate A already bound.”
Shallow clones (git clone --depth=N) don’t carry the real root commit. The CLI detects this, skips the SHA, and binds on URL alone. Run git fetch --unshallow for the full fingerprint.

Workspace Slug

The slug is a URL-safe identifier (e.g. my-startup). It’s what you supply for ENAGRAMS_WORKSPACE in each developer’s .env. Slugs are unique across all workspaces. When you create a workspace in the dashboard for a repo that doesn’t exist locally yet, set the slug to the repo’s basename (github.com/org/chatgpt-wrapper → slug chatgpt-wrapper). The CLI uses slug-matches-basename as the trigger for its one-keystroke bind shortcut.

Sharing a Workspace

Enagrams is invite-only. A teammate can’t join a workspace by guessing its slug or by running enagrams init in a bound repo — workspace owners and admins invite from the dashboard, and teammates accept.

The flow

1

Teammate clones the repo and runs the CLI

The CLI fingerprints the repo and asks the API whether any workspace already owns it.
2

CLI detects the binding and prints the invite hint

The CLI exits cleanly — it won’t create a duplicate workspace or offer to bind over the top of the existing one.
3

Admin invites from the dashboard

Owner or admin goes to Dashboard → Team → Invite and enters the teammate’s email. The teammate gets an email with the invite link, clicks to accept, and is added as a member.
4

Teammate re-runs login

This time the CLI sees the teammate is a member of the bound workspace, fast-paths them to a one-keystroke Continue with <workspace> prompt, and writes the workspace into .env.
5

Run init to drop IDE configs (optional)

If the teammate wants Cursor / Claude Code / Codex hooks and MCP configs:
init detects the already-bound workspace and skips straight to writing the IDE files — no bind prompts.
The “ask for an invite” hint is fired by an unauthenticated POST /repo-lookup probe, rate-limited to prevent enumeration. The endpoint only returns admin contacts when the fingerprint matches a real workspace — random probes get {match: null}.

Fingerprint edge cases

The CLI surfaces actionable messages for the five non-happy git states before showing any menu:

Members

Roles

Inviting Members

From the dashboard: Workspace → Team → Invite (enter email). The invitee gets an email; once they accept they’re added as member by default (admins can change the role before or after). You can also use the API:

Removing Members

When a member is removed their active sessions end, reservations release, and any workstreams they were the sole owner of are marked abandoned.

API Keys

Each team member has their own API key:
  1. npx enagrams login creates one automatically and saves it to ~/.config/enagrams/config.json.
  2. Or generate one manually at Dashboard → API Keys.
API keys have the prefix ek_ and are tied to a user account. A key can access any workspace the user is a member of.

Revoking Keys

Revoke from Dashboard → API Keys → Revoke. Active sessions using the key are terminated immediately.

Workstreams

Workstreams are the primary unit of shared work within a workspace. Each one maps to a branch (ena/<slug>). See Workstreams for the full lifecycle. List active workstreams:
Or via MCP: workstream_list.

Reservations

View current reservations (file and symbol level):
Reservations auto-expire after 10 minutes of inactivity and release on sessionEnd. Manual release: end the owning conversation.

Conventions

Conventions are workspace-scoped rules. must-tier conventions are enforced by the preToolUse hook. Manage them through:

Moving a Workspace to a New Repo

If your team renames the repo or migrates hosts (GitHub → GitLab, etc.), the normalized URL usually still matches — the server silently backfills the new URL on the next bind. No action required. If you’re moving the workspace to a different repo (history and all), use:
Owner/admin only. From within a clone of the new repo, this releases the workspace’s current binding and rebinds it to the new repo’s fingerprint. Atomic in practice: if the new repo is already claimed by another workspace, the migrate aborts and the workspace stays bound to the old repo.
For workspaces bound through the GitHub App (Dashboard → Connect GitHub), migrate-repo is disabled — the CLI would leave the App’s installation_id pointing at the old repo while webhooks fired against the new one. Disconnect from the dashboard and reconnect the new repo instead.

Workspace Settings