Shared context for coding agents.
When you run multiple AI coding agents on the same codebase — Claude Code, Cursor, Codex, or anything else — they have no awareness of each other. One agent can overwrite what another is working on. There's no shared history of what happened or why. Loom fixes that.
Loom is a small, local CLI tool that gives agents a shared event log and a coordination layer. It requires no account, no server, no VS Code fork, and nothing running in the background unless you want it to. It just works from the command line.
Loom tracks two things:
Events are an append-only log. Every time something meaningful happens — an agent refactors a module, you make an architectural decision, a bug gets fixed — that gets logged. Events are permanent and ordered. They answer the question: what has happened in this project?
Claims are temporary flags. When an agent starts working on a file or path, it claims it. Other agents can see what's claimed and avoid stepping on in-progress work. When the work is done, the claim is released — but it stays in the event history. Claims answer the question: what is being worked on right now?
Both are scoped to the project by default. Loom determines the project root by walking up from the current directory looking for a .git folder — the same way most tools do. If no .git is found anywhere above it, that directory itself becomes the project root instead of erroring, so non-git work still gets its own history. No init step required.
Everything lives under ~/.loom, outside your project repo. Nothing touches your working directory, nothing needs a .gitignore entry.
~/.loom/
├── settings.json # global settings (CLI-managed via `loom config`)
│
├── projects/
│ └── <slug>/ # slug = slugified absolute project path
│ └── loom.db # SQLite — events + claims for this project
│
└── global/
└── global.db # SQLite — the opt-in global knowledge hub
Project scope is the default. Any loom command run from inside a project resolves its slug from the current directory (walking up to find .git, or falling back to the current directory itself if none is found) and reads/writes projects/<slug>/loom.db.
Global scope is opt-in only. loom global log / loom global show explicitly target global/global.db — it is never touched by default project-scoped commands.
Slug derivation mirrors Claude Code's ~/.claude/projects/ convention: the absolute project root path is slugified (e.g. /Users/alice/code/myapp → Users-alice-code-myapp). This is deterministic and collision-proof — no registry or loom init step required.
Each project gets its own SQLite database. Two agents working in the same directory will always resolve to the same database with no coordination required.
go install github.com/nudoxorg/loom/cmd/loom@latestMake sure ~/go/bin is on your $PATH:
export PATH=$PATH:$(go env GOPATH)/binAdd that line to your ~/.zshrc or ~/.bashrc to make it permanent.
# Log an event
loom log "refactored auth middleware"
# Show recent events
loom show# Claim a path you're working on
loom claim internal/auth
# See what's currently claimed
loom status
# Release when done
loom release internal/authRe-claiming a path you already hold refreshes it instead of adding a duplicate row, and any claim left unreleased for 4 hours expires automatically — useful since automated claiming (e.g. from a hook) has no natural "done" signal the way running loom release does.
Global context is opt-in — a separate event log not tied to any project. Useful for cross-project notes or decisions that span multiple repos.
loom global log "switching all projects to Postgres"
loom global showTo see everything happening across every project Loom knows about at once — active claims and recent events, each labeled with which project they're from, merged with the global log above — use loom global all:
loom global all
loom global all --limit 50This doesn't require anything to be logged manually; it reads directly from every project's own loom.db under ~/.loom/projects/.
loom config get <key>
loom config set <key> <value>
loom config listSupported keys: default_agent (used on every log/claim/release/global log unless overridden by MCP client identity — see below) and default_limit (default row count for show/global show, overridable per-call with --limit).
Agents forget to check Loom unless they are reminded. Loom installs reminder hooks globally, so they are available to every project and every session for a supported harness:
loom hooks install claude
loom hooks install codex
loom hooks install cursor
loom hooks install all # all three supported harnessesThere are no project-scoped hook installers. Each command merges Loom's entries into the harness's existing user configuration and preserves unrelated settings and hook fields:
- Claude Code: scripts in
~/.claude/hooks/, wired through~/.claude/settings.jsontoSessionStartandUserPromptSubmit. - Codex: scripts in
~/.codex/hooks/, wired through~/.codex/hooks.jsontoSessionStartandUserPromptSubmit. Loom uses the dedicated JSON file and does not modify~/.codex/config.toml. - Cursor: scripts in
~/.cursor/hooks/, wired through~/.cursor/hooks.jsontosessionStartandbeforeSubmitPrompt. The prompt hook uses Cursor's documented Claude Code compatibility mapping (UserPromptSubmit→beforeSubmitPrompt) and nestedhookSpecificOutput.additionalContextresponse so the reminder is injected into agent context rather than shown only to the human.
Every hook only injects static reminder text into the agent's context. Hooks never execute Loom, create claims, or change project state. The reminders tell the agent to prefer the MCP server, check loom_global_all, claim and release paths, log meaningful decisions, and pass its actual current working directory to project-scoped tools.
Installation is idempotent: unchanged scripts are not rewritten and existing Loom entries are not duplicated. The same operation is available to agents as loom_hooks_install(harness), where harness is claude, codex, cursor, or all. The MCP tool is also global and takes no cwd.
Codex-specific: run /hooks in Codex after installation to review and trust newly installed or changed hooks. Loom cannot approve that trust prompt for you.
Migrating from an older Loom version: installing the new global hooks does not search for or delete project-local hooks created by the old commands. Remove old Loom entries and generated scripts under a project's .claude/, .codex/, .cursor/, or .agents/ directories if you previously installed them there. This repository no longer ships its former project-local hook files.
Every Loom operation above is also exposed as an MCP tool over stdio — no network exposure, no accounts, same local trust model as the CLI. This is how agents use Loom directly instead of shelling out to loom themselves.
loom mcpPoint your agent's MCP client config at the loom binary, e.g.:
{
"mcpServers": {
"loom": {
"command": "loom",
"args": ["mcp"]
}
}
}Tools exposed: loom_log, loom_show, loom_claim, loom_release, loom_status, loom_global_log, loom_global_show, loom_global_all, loom_config_get, loom_config_list, and loom_hooks_install. (loom config set stays CLI-only — global settings changes require a human at the terminal.)
Every project-scoped tool requires a cwd argument. loom mcp is a long-lived process serving one client for the whole session, and its own working directory never changes after it starts — so it can't infer where the agent is currently working just by calling os.Getwd(), especially once the agent has cd'd somewhere else (e.g. into a git repo nested under the non-git directory the session started in). Each call to loom_log, loom_show, loom_claim, loom_release, or loom_status must pass the agent's actual current working directory as cwd, and Loom resolves the project from that (git walk-up, or an ad-hoc root — see above). The global, config, and hook-installation tools don't take cwd; they're never project-scoped.
The server ships with detailed instructions in the MCP initialize response — the mental model, when to claim/release, how to pass cwd correctly, and how to write a log message that's actually useful to the next agent. Any MCP-aware client surfaces these automatically, so there's nothing extra to read or configure.
Events and claims created via MCP are attributed to the connecting client's own reported identity (e.g. claude-code, cursor) automatically, falling back to default_agent only if a client doesn't report one — no agent argument to pass, no config to keep in sync per client. Since every client we've seen reports that same name for every session, the server also appends a random ID generated once per loom mcp process, so two concurrent sessions of the same client (e.g. two Claude Code windows) stay distinguishable instead of silently sharing — and potentially releasing — each other's claims.
Traycer / other agent IDEs — these require installing a specific editor or environment. Loom is editor-agnostic and works with any agent that can run a CLI command.
A shared file in the repo — anything in the repo risks conflicts, accidental commits, and .gitignore noise. Loom keeps everything in ~/.loom.
Agent-native memory — per-agent memory is siloed. Claude Code doesn't know what Cursor just did. Loom is the shared layer across all of them.
Config, the local MCP server, and global reminder hooks are done (see above). What's next, in priority order — see IDEAS.md for full detail on each:
- Agent-to-agent thought sharing — let an agent ask why a path was implemented a certain way and get another agent's reasoning, not just a diff
- AGENTS.md generation + Markdown export — human/fallback-facing snapshots of project state for agents without MCP support, and for sharing or onboarding
- Daemon and Git integration — background automation for auto-logging events; nice-to-have, not load-bearing