---
title: "Documentation · Cork"
description: "Everything you need to integrate Cork: the protocol, every MCP tool, hooks for Claude Code, Codex, Cursor and Hermes, typed operations, CAS writes, anchored memory, and enforcement options."
canonical: "https://corkcli.com/docs"
last_updated: "2026-11-13"
---

# Cork documentation

Cork is an MCP server that gives every AI coding agent live, symbol-level awareness of everyone else's in-flight changes — plus a shared memory that admits when it might be stale. This page is everything an integrator needs; agents themselves learn the protocol automatically from the MCP handshake.

By tool

- [Claude Code](https://corkcli.com/docs/claude-code)
- [Codex](https://corkcli.com/docs/codex)
- [Cursor](https://corkcli.com/docs/cursor)
- [Gemini CLI](https://corkcli.com/docs/gemini-cli)
- [Cork CLI (the cork command)](https://corkcli.com/docs/cli)
- [Cork MCP server](https://corkcli.com/docs/mcp-tools)
- [Cork API reference (REST v1)](https://corkcli.com/docs/api)
- [API versioning and deprecation policy](https://corkcli.com/docs/api/versioning)
- [Sandbox and test environment](https://corkcli.com/docs/sandbox): Cork free and local, no account or key, and the endpoints that need no key

Is the service up? [Status](https://corkcli.com/status): every component now and since checks began, with incidents (for agents: [status.json](https://corkcli.com/status.json), [status.md](https://corkcli.com/status.md)).

## Quickstart

1. Install Cork on your machine, once. It covers every repo on the machine, with nothing written into any of them:

   ```
   curl -fsSL https://corkcli.com/install.sh | sh
   ```

   (Or `npx corkcli`.) That is the free version: no account, and everything stays on the machine.
2. Or connect your agent to the MCP server instead, once, for every project:

   ```
   claude mcp add --scope user --transport http cork   https://mcp.corkcli.com
   ```

   Your agent signs in through the browser on first use, and its first Cork call installs the same machine hooks.
3. **Repos are found, not configured.** The hooks report any repo with a git remote the first time an agent works in it, and Cork picks it up from there. To watch a repo before anyone has worked in it, add it by id from the dashboard's repo menu.
4. Open the [dashboard](https://corkcli.com/dashboard). Edits, intents, and collisions appear live as agents work.

### Workspaces and repos

A **workspace** is a team: its members, its pool of agent hours, and any number of repos. Every account gets a personal one ("Kevin's workspace") the moment it signs in; the free plan includes that one workspace with unlimited repos and agents and 10 agent hours a month, with you the one player (invitees join as viewers). Units of 100 agent hours a month, pooled across the workspace, make every member a player and lift the cap on workspaces. The dashboard header has two dropdowns — workspace and repo — each with a create form at the bottom: one creates a workspace and nothing else, the other adds a repo to the current workspace (type its id, e.g. `github.com/acme/api`).

**Placement is automatic.** The first Cork call an agent makes in a repo adds it to the right workspace: the one named after the repo's GitHub org (`github.com/acme/…` lands in "acme"), else your personal one. When that is a guess — you also own a workspace that matches neither — the agent gets a `workspace_choice` notice and asks you once: keep it there, or use the one created for you? Its answer is `move_repo`, which also moves a repo between workspaces any time (history comes along); Settings → Repo does the same from the dashboard. Workspaces and repos can both be renamed; a repo renamed on GitHub renames itself here from the git remote the hooks report.

**Access is per repo.** An invite checks off which repos the invitee may work in; the owner adjusts the list any time under Settings → Members. A member calling Cork about a repo outside their list is refused — there is no ghost mode, because the rest of the team reports there — and someone who isn't in the workspace at all cannot read teammates' updates. Cork's own membership is the only gate: removing someone from a repo on GitHub does *not* remove them from Cork. To cut someone off, the owner removes them or unticks repos under Settings → Members. Established repos always route to their home workspace; `switch_workspace` only changes the default for brand-new ones. The connection itself covers every workspace you belong to, including ones you join later — approve once and never reconnect for a new workspace (you can narrow it on the approval screen if you want to).

### GitHub is only a sign-in

GitHub is only how you sign in. Cork gets your GitHub username, avatar and email, and nothing else. It cannot see your repositories and never reads code from GitHub. What Cork knows about your code comes only from your own agents: the structure Cork's hooks parse on your machine, or a file an agent reports through the MCP tools, which the server parses in memory and discards.

### Moved or renamed repos

Cork knows a repo by the git remote your agents report, not by asking GitHub. After a repo is renamed or moved to another owner, rename it here under Settings → Repo → Rename; its history stays intact. Teammates whose clones still use the old address should point them at the new one (`git remote set-url origin <new url>`) so every agent reports under the same repo.

## The protocol

Six verbs, shipped to every agent in-band. Nothing requires manual prompting — the MCP handshake instructs agents, and the hooks make reporting mechanical.

1. **Absorb** — `get_briefing` at session start: renames to adapt to, hotspots, scars, abandoned work, convention drift.
2. **Announce** — `declare_intent` with typed operations before starting; conflicts with other live intents come back instantly.
3. **Check** — `check_collisions` before touching files; adapt to confidence-certain results and read the anchored notes that ride along.
4. **Report** — `report_edit` after writing (or let the hooks do it); pass `expected_hashes` for contested symbols.
5. **Conclude** — `complete_intent` with a rationale; `remember` durable facts with an anchor; `defer_intent` to tripwire unfinished areas.
6. **Merge-check** — `simulate_merge` and `differential_check` before landing parallel work.

## Tools reference

Every tool takes `repo_id`. Responses may carry two piggyback fields anywhere: `since_your_last_call` (cross-agent events since your previous call — the realtime channel) and `usage_notice` (soft-cap warning, never a block).

### Session & awareness

`get_briefing``(repo_id, days=7)`

The distilled recent history: per-user activity, renames, collision hotspots, scars (auto-mined failed attempts), active/fired tripwires, convention drift, and protocol-health counters. Call it once at session start.

`list_activity``(repo_id)`

Live state: each workspace's root hash, current focus (reading/editing, with model and token totals), active intents, and the recent event ring. This is what the dashboard renders.

`blind_spots``(repo_id)`

Where the map is unreliable: files that never parsed cleanly, files serving stale state, and workspaces gone quiet.

`compliance_report``(repo_id, since?)`

Check-before-write rates per user and per agent version — the behavioral canary for model swaps. (Enterprise.)

### Intents

`declare_intent``(repo_id, paths, operations | change_type, summary?, …)`

Registers in-flight work (15-minute TTL). Prefer typed `operations` (see below) — you get `intent_conflicts` (provable COMMUTE/CONFLICT/UNKNOWN against other live intents), `settled` notices (a prior rationale fires if your ops would reverse a settled decision), and `anchored_memories` for the code you named.

`heartbeat``(repo_id, intent_id)`

Extends the TTL while you work; the response carries the delta feed.

`complete_intent``(repo_id, intent_id, rationale?)`

Completes the intent. Pass `rationale` for anything non-trivial: it is stored anchored to the changed symbols and returns as a blocking-level notice to anyone who later declares the reverse.

`defer_intent``(repo_id, note, paths?, symbols?)`

Leaves a tripwire on the paths or symbols: the next agent to touch them gets your warning. Deferred work is the task list — with a CRM connected, the server files it there as a task.

### Checking & writing

`check_collisions``(repo_id, paths?, symbols_referenced?)`

The main call. Empty result = no collisions (root fast path). Otherwise each entry names the symbol, what happened (renamed / modified / removed / added), the new signature, who did it, confidence (certain / likely / unconfirmed) and freshness. Also returns matching live intents and anchored notes for everything you touched.

`report_edit``(repo_id, path, content, draft?, expected_hashes?)`

Submit a file's full content after writing. The server parses in memory, updates your tree, and discards the source. `draft=true` broadcasts which symbols are in motion without changing state. `expected_hashes` makes the write compare-and-swap (see below). With hooks installed you don't need it: the hook reports every write itself, as structure parsed on your machine, never the file.

`get_symbol``(repo_id, path, symbol)`

The freshest clean state of one symbol across all workspaces — signature, hash, author, provenance (agent-claimed vs disk-confirmed), plus its anchored notes.

### Memory

`remember``(repo_id, fact, tags?, anchor?, supersedes?)`

Saves a durable team fact. Anchor it to code — `"auth.py::validateToken"`, `"auth.py"`, or `"src/auth/"` — and it surfaces automatically to whoever touches that code, with honest staleness. `supersedes` retires a conflicting note (a ledger event, never a silent delete).

`recall``(repo_id, query?, tags?)`

Search saved facts; every anchored note comes back annotated with `stale`, `rewrites`, `confidence`, `conflict`, and `possibly_stale`.

### Merging

`simulate_merge``(repo_id, users?)`

Counterfactual dry-run: which symbols would disagree if these workspaces landed together — plus which anchored notes would go stale and which settled rationales would fire.

`differential_check``(repo_id, other_user)`

The narrow verification oracle: does your workspace preserve the interfaces the other side's code references? Returns PASS / FAIL / UNKNOWN and states exactly what was and was not checked — it never claims beyond its oracle.

### Setup & integration

`switch_workspace``(workspace?)`

The in-agent workspace switch. Without an argument it lists every workspace on your account and which one this credential is bound to — ask your agent to "switch my Cork workspace" and it presents the choice. With an id or name it re-binds the credential immediately: membership-checked, no re-authentication. Established repos keep auto-routing to their home workspace; switching governs where brand-new repos land. Workspace names are unique per account, so a name is always an unambiguous target.

`setup``(repo_id)`

Returns one install command that sets Cork up for every repo on the machine (Claude Code, Codex, Cursor and Hermes) and links it to your account. Nothing is written into the repo; run at a repo's root, it also retires that repo's old per-repo setup and stages the removal.

`connect_agents``(repo_id, mode='')`

The same install command as setup. With `mode="files"`, the protocol rules files and MCP configs to commit for agents without hooks (Windsurf, Cline, GitHub Copilot).

`sync_agents_block``(repo_id, file_content)`

Idempotently merges the canonical protocol block between markers in AGENTS.md — everything outside the markers is untouched.

## Typed operations

`declare_intent` accepts a closed set of structured operations instead of prose. Typed intents get provable conflict prediction — a commutativity-table lookup, not a guess.

```
{op: "rename",        symbol, new_name}
{op: "add_param",     symbol, name, type?, default?}
{op: "remove_param",  symbol, name}
{op: "change_return", symbol, type}
{op: "extract",       symbol, new_name, range?}
{op: "move",          symbol, new_path}
{op: "delete",        symbol}
{op: "add",           symbol, signature?}
{op: "modify",        symbol}            // body edit, interface preserved
```

Rules: operations on disjoint symbol names **commute**; overlapping names **conflict**; `extract` and anything untyped return an honest **UNKNOWN**. There is deliberately no "refactor" bucket.

## Compare-and-swap writes

Every check is stale by the time a write lands. For contested symbols, pass the hashes you read:

```
report_edit(repo_id, path, content,
  expected_hashes={"place_order": "<hash-you-read>",   // must still match
                   "helper_fn":   null})               // "I expect it absent"
```

If anything moved since your read, the write is rejected with the current state of each conflicting symbol — re-read, adapt, retry. Two safety properties: a rejection changes nothing, and a "conflict" where the current state already equals what you're submitting (your own auto-hook racing ahead) is treated as agreement, not an error.

## The memory system

Notes are annotations on tree nodes, not rows in a search index. What that buys you, concretely:

- **Locality** — touching a symbol surfaces its notes (and its file's, and every ancestor directory's) in the responses you already receive. No query needed.
- **Staleness** — a note whose anchor was rewritten says so: `stale: true`, with a rewrite count. Stale notes are flagged, never deleted.
- **Confidence** — earned by surviving rewrites uncontradicted, capped by conflicts, docked when the anchor changed right after writing. History, never timestamps.
- **Conflicts** — two notes on one anchor written against different versions of the code are flagged as contradicting; resolve with `supersedes`.
- **Ripples** — `possibly_stale` flags a note whose anchor is untouched but whose dependencies changed (static reference slicing, deliberately over-warning).
- **Scars** — failed attempts mined automatically from the ledger: declared, edited, reverted. Nobody writes these; Cork does.
- **Settled decisions** — a completion rationale fires as a blocking-level notice when a later intent would reverse it.

## Context without a tool call

A fact an agent has to ask for costs a message, and that message replays the whole conversation so far. The hooks are a second channel into the same session: they run on events the agent did not choose, and what they print becomes context. Nothing below is a tool call, and none of it is in the model's hands.

### At session start

The tracked tree joins the map, then one page prints: the repository's shape (files, symbols, edges, subsystems with their hubs, the per-directory conventions it infers) followed by the modules changed in the last week, each with exact signatures, docstrings, anchored notes and whether the repo's own check passed after it was written. After a compaction the same hook leads with the working set of the session being resumed and the last check verdict, because that is the context that just went missing.

### At prompt submit

The hook extracts the identifiers a prompt names — paths, backticked names, and words whose shape can only be code — and asks for the modules they touch plus everything within two hops that depends on them. Never the prose: only the identifiers leave the machine. The answer carries a coverage line saying when that dependent list is complete, so the agent knows it has the whole blast radius and does not spend a call confirming it.

### After a batch of writes

The repository's own check runs detached, and its verdict rides the next tool result — whose failures are new, which were already broken before this agent started, which are flaky, and which are oscillating between two constraints. A passing run stamps every file it covered as verified, and that mark travels into the next agent's briefing. No hook ever holds the turn waiting.

### While other agents work

A session that read or wrote a file has a working set. When someone else changes something that set depends on, one compressed line arrives on the next tool result: the symbol, its new signature, who changed it, how long ago, and which of your files calls it. Sessions are distinguished from each other, so your own edits are never reported back to you as someone else's.

### Work, not just facts

A verified batch of typed operations is saved as a recipe with its target abstracted. A later agent whose prompt names the same symbol is offered one command that replays the whole transformation against its own target, computes the call sites, writes, verifies with the repo check and restores on failure. This is the only mechanism that makes the fourth agent cheaper than the first rather than merely better informed.

The hooks also grade themselves. Each briefed file is classified once per turn — edited without being read, read and then edited, or read and abandoned — and the counts become a rate on the dashboard along with an estimate of the reads avoided.

## Hooks & harnesses

Reporting should be mechanical — no model in the loop, no forgotten calls. The hooks are installed once per machine, by the install command or by an agent's first Cork call: one native program in `~/.cork/bin`, registered in each agent's user-level settings (Claude Code, Codex, Cursor and Hermes). Nothing is written into your repositories; each repo is identified by its git remote. Your credential stays on the machine in `~/.cork/credentials.json`. Every path is hard fail-open: any error, timeout, missing config or non-200 silently allows the operation.

### The seven events

**SessionStart** indexes the tree and prints the briefing. **UserPromptSubmit** narrows it to what the prompt names. **PreToolUse** is the gate. **PostToolUse** reports writes, places reads, and carries notes back. **PostToolBatch** runs the repo check. **Stop** reports a usage limit so the team sees a paused agent rather than a silent one, and tallies what the briefings were worth. **ConfigChange** fires when the settings file changes, which is itself proof the hooks loaded.

### One hook, four harnesses

Each harness names its events differently and reads a different answer. The one program translates at both edges and speaks one vocabulary in between; the harness is named on the command line by the install's config, never guessed from the payload.

| Harness | Config | Gate | Notes back mid-turn |
| --- | --- | --- | --- |
| Claude Code | ~/.claude/settings.json | yes | yes · all seven events |
| Codex | ~/.codex/hooks.json | yes | yes · no batch or config event |
| Cursor | ~/.cursor/hooks.json | yes · allow, deny or ask | yes · no batch event |
| Hermes | ~/.hermes/plugins/cork | yes | queued to the next turn |

Hermes discards a post-tool return value by design, so anything that would have ridden a tool result is held and delivered with the following turn's briefing instead. Every other harness gets it in step.

### Enforcement

The pre-tool hook calls `check_collisions` before every write and refuses one that lands on a certain, breaking collision, in the shape that harness reads: an exit code and stderr for Claude Code and Codex, a JSON decision for Cursor and Hermes.

### Repos set up the old way

Cork used to commit hook scripts into each repo under `.collide/` and wire them from the repo's own settings. That per-repo setup is retired. Until a repo is migrated its own hooks keep running and the machine's stand aside, so nothing is reported twice; its agents are told to migrate. Running the install at the repo's root, or this on a machine that already has Cork, removes it and stages the change to commit:

```
cork migrate
```

### Any agent: the watcher

```
cork watch --repo-id github.com/acme/api
```

Run at the repo root; the server and token come from this machine's credential (`cork login`), or pass `--server` and `--token`. `--once` reports once and exits. Polls the working tree and reports edits from disk — the enforcement floor for agents with no hook support. Disk-confirmed edits are marked as such.

### Humans: the VS Code extension

The `vscode-extension/` in the repo puts Cork in your editor: gutter marks where teammates' agents recently edited the open file (who, model, branch, tokens on hover), red marks where their changes overlap your own uncommitted lines, a Team view with live presence and in-flight intents, and a status-bar presence counter. Zero configuration — it reads the machine's install and the per-user credentials the hooks use.

### Everyone: the git pre-commit gate

```
printf '#!/bin/sh\nexec "$HOME/.cork/bin/cork" pre-commit\n' > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
```

Git is the one chokepoint every agent and human funnels through. The gate blocks a commit whose staged files land on a certain in-flight collision; override a false positive with `git commit --no-verify`.

## The badge

Show that a repo's agents work together through Cork: paste this into its README.

```
[![coordinated by cork](https://corkcli.com/badge.svg)](https://corkcli.com)
```

It is a plain SVG, 20 pixels tall like the badges beside it, and reads on GitHub's light and dark themes. A larger copy is at `/badge-lg.svg`.

Pull requests your agents open end with the same line. In Claude Code and Codex, Cork's hooks add it to the description right after an agent runs `gh pr create`, with your own `gh` sign-in; in Cursor and Hermes the agent is asked to add it. It goes in once, only where the description has no badge yet: take it out and it stays out. `cork badge off` stops it on the machine (`cork badge on` brings it back), and so does `CORK_PR_BADGE=0` in the environment; see [the cork command](https://corkcli.com/docs/cli).

## Cork in pull requests

Install Cork's GitHub App on an org or account and every pull request in the repos you pick gets a check named `Cork`: *✓ no overlap with 6 open PRs*, or *⚠ overlaps #42 (renames `userId`)*. When there is something worth reading, Cork also leaves one comment on the PR, edits it on every push, and marks it resolved when the findings clear. Everyone reading the PR sees it, including people who never installed Cork.

- Other open PRs that change the same symbols, or rename, remove or re-signature one this PR calls (both PRs are told).
- Other people's agents working on those files or symbols right now. Never the PR author's own.
- Callers of what the PR renames, removes or re-signatures that the PR leaves alone.
- Pinned notes and standing decisions on the code it changes.
- What Cork stopped on the PR's branch while it was open: *Cork stopped 2 overwrites on this branch*.

The check concludes `success`, or `neutral` when there are findings. It never fails a PR: like the rest of Cork, it fails open.

The App also adds the *coordinated by cork* badge to the end of each PR's description, once, when the PR opens or leaves draft. It never adds a second one, never touches a closed PR, and if someone removes the badge it stays removed. The workspace owner turns it off under Settings, Integrations.

**Reading code is your choice.** Right after install the dashboard asks the workspace owner, and the answer stays under Settings, Integrations. *Read code for PR checks* works on day one: Cork reads each PR's changed files and the default branch once, parses them in memory, and keeps only structure in the same map your agents' hooks fill. *Keep code off Cork's servers* uses only file names, changed line ranges and what your agents' Cork reports. Until the owner answers, code stays off. Exactly what each reads and keeps is on [What Cork sends](https://corkcli.com/data#pr-checks).

Free and unlimited on public repos, included for private repos with any Cork account (installing creates the workspace), and it uses no agent hours. [Install Cork's GitHub App](https://corkcli.com/dashboard/github/install) and pick the repos on GitHub's page.

## Plans & soft caps

See [pricing](https://corkcli.com/pricing) for the tiers. Two standing rules: every limit is a **soft cap** (over it, responses carry a `usage_notice`; nothing is ever blocked), and every price is **grandfathered forever** — locked on your billing record at subscribe time.

## Privacy model

Your source files never leave your machine with Cork's hooks (v75 and later): they parse each file locally and send its structure (symbol names, signatures, docstrings, imports and calls) with a hash per line. Older hooks and the MCP `report_edit` tool send the file's text, which the server parses in memory and discards. What persists: symbol names, kinds, signatures, docstrings, hashes, line *ranges*, events, and the notes you save; never a file's text. Exactly what is sent is on [What Cork sends](https://corkcli.com/data), and the rest in the [privacy policy](https://corkcli.com/privacy).

## Self-hosting

Enterprise deployments run the same server in your VPC: a single container with SQLite on a volume (or Postgres via `DATABASE_URL`), Firebase project for auth, optional Stripe keys for billing, and `NEXT_PUBLIC_CORK_SERVER_URL` baked into the dashboard build. [Talk to us](mailto:kevin@lithometric.com?subject=Cork%20Enterprise) for the deployment guide, custom retention, and audit-artifact exports.

**Autonomous reconciliation (Enterprise):** a runner in your VPC — where a repo checkout can safely live — that reacts to a teammate's confidence-certain interface change by launching a headless agent to adapt affected in-flight work, gated by CAS and the pre-commit hook, proposing the result as a branch. The hosted product never holds your source, so this runs on your infrastructure only. On every plan, agents already get pushed awareness: the report hook injects teammates' certain changes into the session within one tool call of their save.

That is the whole surface. Adding the server to your agent is one command, and approving it in the browser creates the account and the workspace together.

[Connect an agent](https://corkcli.com/start)

This page in HTML: https://corkcli.com/docs
