docs

Coordinate your agents in five minutes.

Datum installs as Claude Code hooks on each engineer's machine. One command writes them, registers the bus, and joins your workspace. From then on, a stale write is fenced before it lands.

Install

Claude Code plugin (recommended)

Run these two slash commands in Claude Code. The plugin is zero-init: the datum-join hook self-seeds your git-native identity (human, email, branch, and workspace from your git config) on the first session, so there is no separate init step.

/plugin marketplace add suraj-phanindra/datum
/plugin install datum@datum

The plugin wires everything an agent needs to coordinate natively: the four hooks (datum-join on SessionStart, datum-claim on PostToolUse, datum-fence on PreToolUse, and datum-guard on Stop), the MCP server, and five skills namespaced under /datum: (coordinate, claim, sync, resolve-fence, and decide). Solo users get http://127.0.0.1:4317 by default; teams read their bus from the committed datum.json.

CLI alternative

If you are not on the plugin path, wire the hooks and MCP directly, then run the bus your sessions point at:

npx datumctl init
datumctl serve

npx datumctl init writes the hooks into .claude/hooks/, adds the hooks block to .claude/settings.json, registers the datum MCP server, and joins your workspace. datumctl serve runs the coordination bus that every session points at. datumctl ships with zero runtime dependencies (Node built-ins only).

try it: npm run demo runs the full scenario end to end. Three agents build one feature, one renames users.email, and a teammate's stale write gets fenced and self-corrects. Then watch it in the read-only live tower.

Requirements

Claude Code and a datum workspace, which is free. The installed hooks run on Node 18 or newer; the bus (datumctl serve) uses node:sqlite and needs Node 22.5 or newer. Datum stores its registry in SQLite by default, so there is nothing else to stand up for a single repo.

Datum never blocks you if it cannot reach the bus. The fence fails open, surfaces a warning, and your agent keeps working. Coordination degrades; it never bricks an agent.

The datum

A contract is a thing your team builds against: a database schema, an API shape, a dependency version, or a free-form decision. Each contract has a monotonic version and a current value, and every version records who changed it, when, and why. The decision ledger sits alongside it and is append-only, so the truth lives in one place instead of being scattered across branches and Slack threads.

The registry is the namesake. In surveying, a datum is the fixed reference surface every measurement is taken from. Here it is the reference every agent reads before it writes.

The fence

On every tool call, the PreToolUse hook compares the contract version your session last synced against the live registry. If a fresh delta touches a file or symbol in your claimed scope, datum injects the mechanical change inline, or denies the write outright when it directly conflicts, with the reason attached. This path is deterministic and runs with no model call, under about 50ms on a cache hit, since it only reaches the network when the version has actually moved.

Hooks fire at tool-call boundaries, not mid-generation. That is the honest limit, and it is enough: every write is a tool call, so the guarantee is precise. No write executes against a stale contract.

The arbiter

The arbiter runs off the critical path, so it never makes an agent wait. When a delta lands, it first computes which sessions the change actually intersects, then sends only those pairs to Opus 4.8: the delta plus that one teammate's current task. It returns an advisory written for that teammate's exact file and work, and opens a pull request that patches docs/spec.md to the new contract.

Two teammates affected by the same change get two different advisories. That difference is the point: it is judgment about who breaks and how, not a broadcast notification.

Hooks reference

The plugin and npx datumctl init both wire these into .claude/hooks/.

PreToolUse
datum-fence.ts
The fence. Returns a deny with a reason naming the contract, the change, and the author, so the agent can re-sync and self-correct.
PostToolUse
datum-claim.ts
Streams each edit to the bus, bumps the registry version on a contract-surface change, and publishes the session's claim and activity.
SessionStart
datum-join.ts
Registers the session on the workspace and injects the current registry snapshot into context, so the agent starts on the latest truth.
Stop
datum-guard.ts
Optional. Blocks an agent from declaring itself done while unacknowledged deltas still intersect its diff.

A deny looks like this on the wire:

{ "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "db.users.email was renamed to contact_email (migration 0042, asha, 40s ago). Re-sync to v8 and use contact_email." } }

The deny is evaluated before any permission-mode check, so it holds even under --dangerously-skip-permissions.

Configuration

Datum watches a contract-surface list: schema files and migrations, route and type definitions, package manifests, and an explicit datumctl decide "...". A path match plus a light parse is enough to know which column, route, or version changed. Extend the list in datum.config.json:

// datum.config.json { "watch": { "db_schema": ["*.prisma", "schema.sql", "migrations/**"], "api_shape": ["routes/**", "*.controller.ts", "openapi.*"], "dep_version": ["package.json"], "decision": ["DECISIONS.md"] } }

Anything off the watchlist, like a README edit, streams to the ledger but never bumps a version or fences a write.