Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.enagrams.com/llms.txt

Use this file to discover all available pages before exploring further.

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

git clone git@github.com:org/chatgpt-wrapper.git
cd chatgpt-wrapper
npx enagrams login
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

This repo is exactly already bound to an Enagrams workspace:
  ChatGPT Wrapper (chatgpt-wrapper)

  Ask one of its admins for an invite:
    • Aaron Siddiky <aaron@example.com>
    • Jimmy Charter <jimmy@example.com>

Once you accept the invite, re-run `enagrams login`.
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

npx enagrams 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:
npx enagrams init
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:
StatusWhat the CLI saysFix
no_gitThis directory is not inside a git worktreecd into your project or git init
no_commitsThis git repo has no commits yetgit add -A && git commit -m "first"
no_remoteNo remote configured — binding on SHA alonegit remote add origin <url> (optional; SHA still works)
shallowShallow clone; binding on URL alonegit fetch --unshallow for the full fingerprint
no_remote_and_shallowNo signal availableFix one of the two above first

Members

Roles

RolePermissions
ownerFull access, delete workspace, bind/unbind repo, manage all members
adminManage members, bind/unbind repo, change settings
memberCreate decisions, claim work packages, propose conventions, use MCP tools

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:
POST /workspaces/:id/members
Authorization: Bearer ek_...

{ "user_id": "usr_...", "role": "member" }

Removing Members

DELETE /workspaces/:id/members/:userId
Authorization: Bearer ek_...
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:
GET /workspaces/:id/workstreams?status=active
Authorization: Bearer ek_...
Or via MCP: workstream_list.

Reservations

View current reservations (file and symbol level):
GET /workspaces/:id/reservations
Authorization: Bearer ek_...
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:
enagrams workspace migrate-repo
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

SettingDescription
nameDisplay name
slugURL-safe identifier — changing requires updating every .env and MCP config
default_base_branchBranch new workstreams fork from (defaults to main)
repo_url / repo_root_commitThe current binding. Read-only in PATCH — use POST /workspaces/:id/repo-binding or the CLI instead.
GitHub App bindingManaged entirely from the dashboard. Disconnect releases the binding cleanly.
PATCH /workspaces/:id
Authorization: Bearer ek_...

{ "name": "New Name", "default_base_branch": "develop" }