emerik installation & usage

A living knowledge substrate for AI-assisted engineering

emerik keeps the decisions behind your code honest — it harvests source-bound notes as you work, lets stewards author verifiable contracts, and surfaces drift as a failing check. It is a git-native CLI: no server, no database, just your repository.

Node 20+ Package manager pnpm Backend git only Version 0.1.0 License MIT

What is emerik

As you build software with AI agents, the reasons behind the code — why a value is what it is, which invariant must hold, what was tried and rejected — evaporate. emerik captures that knowledge as small, content-addressed artifacts committed alongside your code, and gives you commands to reach it, verify it, and keep it from rotting.

Everything lives in a .emerik/ directory in your repo, stored append-only. There is no external service: your git remote is the only source of truth, so knowledge travels with the code and is versioned by the same history.

The name

emerik is named for Emerik Blum, founder of Energoinvest — the same namesake as bloomteq, whose design system dresses these pages.

The mental model

Four ideas carry the whole system. Learn these and every command reads naturally.

Pin

A low-ceremony, source-bound note harvested automatically from a commit. When its source changes, emerik re-derives it; when the source is deleted, it is invalidated. Pins are how knowledge stays fresh.

Anchor

A steward-authored, reviewed contract that carries a check. When the check fails, drift surfaces at the severity you chose. Anchors are how knowledge stays true.

Lease

A time-bounded, exclusive-write claim on a territory, recorded on a dedicated git ref via compare-and-swap. Two machines can never hold the same turf — with no lock server.

The substrate

The append-only .emerik/ store. A change is a new artifact that supersedes the old; a deletion is a tombstone. The current graph is a projection over git history.

The load-bearing promise is honesty: a check that guards an invariant must be able to fail when the invariant breaks. You will see this proven end-to-end in the honesty loop.

Requirements

  • Node.js 20 or newer. The CLI is tested on Node 20 and 22.
  • git. emerik is git-native — every command operates on a git repository.
  • pnpm. The project's package manager; the lockfile is committed. Install it with corepack enable or from pnpm.io.

Installation

emerik v0.1.0 installs from source. Clone the repository, install dependencies, and build the CLI bundle.

01

Clone & build

git clone <emerik-repo-url> emerik
cd emerik
pnpm install
pnpm build          # tsc --noEmit + tsup + oclif manifest → dist/
02

Verify the binary runs

./bin/run.js --version   # → emerik/0.1.0 …
./bin/run.js --help      # show the full command tree
03

Put emerik on your PATH (optional)

So you can call emerik from any repository instead of the full path:

# option A — symlink the launcher into a directory already on PATH
ln -s "$(pwd)/bin/run.js" /usr/local/bin/emerik

# option B — npm link (from the emerik project root)
npm link
Note

The rest of this guide writes emerik <command>. If you skipped step 03, substitute the path to bin/run.js.

Quickstart

From inside any git repository, three commands take you from nothing to a verified knowledge graph.

cd your-project
emerik init                 # create .emerik/, ignore rules, git hooks + wire your agent
git commit -am "chore: emerik init"
emerik harvest              # harvest source-bound Pins from HEAD
emerik verify               # run the convention + Anchor gate (exit 0 = clean)

Working inside a coding agent? The guided path is the front door — start with emerik-guide (orient, tour, or step-through). Starting from an empty repo? Start a new project walks the greenfield front door — brainstorm to first Goal, on emerik alone.

Contributor aside

Do not run emerik init inside emerik's own source repo — a root .emerik/ there pollutes emerik's self-hosted CI. Dogfood on a separate project.

Start a new project

emerik is the greenfield front door too: from an empty directory to a first implemented, harvested, verified Goal on emerik alone — no separate planning tool, no document that rots away from the code. The five planning skills carry an idea down to sequenced Goal briefs the engineering loop picks up directly. Each step deposits durable substrate: a committed session doc harvested into Pins, constraint-Anchors on their stewards, the brief / prd / architecture heads, and the sequenced Goal briefs.

What is proven, and what you do

The mechanical path — init → the planning tool sequence → first Goal started → work committed → verify green → Goal completed — is exercised end-to-end by a deterministic CI proof, through the real MCP server and the real CLI on a throwaway fixture, so the successor claim is demonstrated, not asserted. The narrative below is the live version of that same path: what a founder does by talking to the five planning skills inside their coding agent. Same tools, same order — a person driving instead of a test.

01

Create the repo and initialize

Start from nothing but an empty directory and wire emerik in.

mkdir task-inbox && cd task-inbox
git init
emerik init                 # store, hooks + the planning skills, wired into your agent

An empty substrate — a fresh repo with zero Pins — is a valid entry state, not a special mode. Greenfield is simply what it looks like when the grounding reads come back empty.

02

Brainstorm the idea

Inside the coding agent, run emerik-brainstorm. It facilitates an honest ideation session grounded in whatever the substrate already says (nothing, on a fresh repo — stated plainly, never fabricated), and lands two things: a committed session doc under .emerik-planning/brainstorm-<slug>.md that the harvest hook captures as Pins, and any constraint stated in-session deposited as a constraint-Anchor on its steward at the moment it is stated — queryable the instant it lands.

03

Grow the planning head

Three skills turn the idea into durable, append-only planning heads — each a committed markdown body the hook harvests, plus a minted artifact that references it:

  • emerik-brief — the idea becomes a committed brief artifact: problem, users, outcome, scope fence.
  • emerik-prd — the brief grows into a prd, and each binding requirement is offered as a candidate constraint-Anchor at the moment of statement.
  • emerik-architect — the prd becomes a durable architecture, and each decision that governs a code region lands as a governing Anchor (inverted CODEOWNERS) — the design document and the enforcement surface are the same thing.

A revision never edits in place: a changed head is a superseding artifact (--supersedes), so the old one stays replayable in lineage.

04

Break it down into Goals

emerik-breakdown converts the live prd and architecture into an ordered sequence: one committed initiative brief under .emerik-planning/initiative-<slug>.md, then delivery-sized Goal briefs under .emerik-goals/, each opening with a Sequence block (Initiative: / Priority: P0/P1/P2 / Depends on:) so the order and the dependencies are explicit.

05

Pick up the first Goal — and build

Now the planning path meets the engineering loop you already know. Pick up a brief with emerik-goal (one brief → one Goal, its priority read from the Sequence block), or hand the whole sequence to emerik-orchestrate to fan the briefs out in dependency order. From there it is the shipped loop: plan grounded in retrieved Pins and Anchors, implement test-first under a Lease, and emerik verify as the green gate — then complete the Goal. That closes the path: mkdir to a first implemented, harvested, verified Goal, on emerik alone.

One substrate, two halves

Planning and engineering live on the same append-only substrate — the brief, prd and architecture heads, the constraint- and governing-Anchors, and the Pins harvested from every committed doc all feed the same retrieval cascade the implementation loop grounds in. See Use with an AI agent for the full skills grid and the tool surface.

Initialize a repo

emerik init is idempotent — safe to run again. It creates:

  • .emerik/ — the append-only, content-addressed store (committed with your code).
  • .emerik/.gitignore and a root .gitignore rule for the ephemeral local index.
  • a post-commit hook (auto-harvest) and a pre-push hook (freshness re-derive).

It also wires your coding agent (additive and idempotent — pass --no-agents to skip):

  • .claude/skills/ — the fourteen shipped skills, loaded by Claude Code and by Cursor (2.4+, which reads .claude/skills/ natively): emerik-brainstorm, emerik-brief, emerik-prd, emerik-architect, emerik-breakdown, emerik-discover, emerik-goal, emerik-plan, emerik-implement, emerik-review, emerik-guide, emerik-retro, emerik-orchestrate and emerik-onboard.
  • .claude/agents/ — the four reviewer roles the emerik-review skill fans out: blind-hunter, edge-case-hunter, acceptance-auditor and substrate-auditor.
  • .mcp.json — registers the emerik mcp server for Claude Code (merged additively, other servers untouched).
  • .cursor/mcp.json — the same emerik mcp server for Cursor, same mcpServers shape, merged additively the same way.
  • a delimited <!-- emerik:begin -->…<!-- emerik:end --> block in AGENTS.md (created if absent) and in CLAUDE.md (only when it already exists), describing the substrate and the skills. Content outside the markers is never touched, and re-running init heals a missing piece without duplicating anything.
$ emerik init
 initialized .emerik/ — Pin, Anchor and Glacier store ready
  created .emerik/config.yaml
  created .emerik/pins/.gitkeep
  created .emerik/anchors/.gitkeep
  created .emerik/glacier/.gitkeep
  created .emerik/goals/.gitkeep
  created .emerik/dependencies/.gitkeep
  created .emerik/reviews/.gitkeep
  created .emerik/briefs/.gitkeep
  created .emerik/prds/.gitkeep
  created .emerik/architectures/.gitkeep
  created .emerik/.gitignore
  created .gitignore
  created .git/hooks/post-commit
  created .git/hooks/pre-push
  created .claude/skills/emerik-plan/SKILL.md
  created .claude/skills/emerik-plan/template.md
  created .claude/skills/emerik-implement/SKILL.md
  created .claude/skills/emerik-discover/SKILL.md
  created .claude/skills/emerik-guide/SKILL.md
  created .claude/skills/emerik-guide/steps/orient.md
  created .claude/skills/emerik-guide/steps/step-through.md
  created .claude/skills/emerik-guide/steps/tour.md
  created .claude/skills/emerik-goal/SKILL.md
  created .claude/skills/emerik-goal/checklist.md
  created .claude/skills/emerik-goal/template.md
  created .claude/skills/emerik-review/SKILL.md
  created .claude/skills/emerik-review/checklist.md
  created .claude/skills/emerik-review/template.md
  created .claude/skills/emerik-retro/SKILL.md
  created .claude/skills/emerik-retro/checklist.md
  created .claude/skills/emerik-retro/template.md
  created .claude/skills/emerik-orchestrate/SKILL.md
  created .claude/skills/emerik-brainstorm/SKILL.md
  created .claude/skills/emerik-brainstorm/template.md
  created .claude/skills/emerik-brief/SKILL.md
  created .claude/skills/emerik-brief/checklist.md
  created .claude/skills/emerik-brief/template.md
  created .claude/skills/emerik-prd/SKILL.md
  created .claude/skills/emerik-prd/checklist.md
  created .claude/skills/emerik-prd/template.md
  created .claude/skills/emerik-architect/SKILL.md
  created .claude/skills/emerik-architect/checklist.md
  created .claude/skills/emerik-architect/template.md
  created .claude/skills/emerik-breakdown/SKILL.md
  created .claude/skills/emerik-breakdown/checklist.md
  created .claude/skills/emerik-breakdown/template.md
  created .claude/skills/emerik-onboard/SKILL.md
  created .claude/skills/emerik-onboard/checklist.md
  created .claude/skills/emerik-onboard/template.md
  created .claude/agents/blind-hunter.md
  created .claude/agents/edge-case-hunter.md
  created .claude/agents/acceptance-auditor.md
  created .claude/agents/substrate-auditor.md
  created .mcp.json
  created .cursor/mcp.json
  created AGENTS.md

Prefer just the substrate, no agent wiring? Run emerik init --no-agents.

Works with Cursor. One emerik init wires both harnesses. Cursor 2.4+ loads the shipped skills through its native .claude/skills/ support (the Agent Skills standard), and AGENTS.md is first-class in Cursor, so the same substrate context, lexicon and skills reach a Cursor agent unchanged. Two caveats worth knowing: the emerik-review fan-out uses the host's native subagents where present, else the documented prompt-file fallback (one prompt per reviewer under .emerik-local/reviews/, run manually) — that fallback is the guaranteed path on any harness; and emerik exposes thirty-five MCP tools, comfortably under Cursor's historically undocumented per-server tool cap. Leases, hooks and harvest are plain git, so a Cursor agent and a Claude Code agent on the same repo coordinate through the same leases and the same harvest hooks.

The harvest hook resolves emerik robustly: it prefers a global emerik on your PATH, and otherwise falls back to the absolute CLI path baked in at init time — so a commit auto-harvests even when emerik is not installed globally. The hook swallows its own output and always exits 0, so it never blocks a commit or push. If emerik cannot be resolved at all — no global install and no reachable fallback (a moved clone or a deleted build) — the hook prints one stderr line (emerik: harvest skipped — emerik not found …) so a missed harvest is visible rather than silent; it still exits 0 and never blocks the commit.

Harvest Pins

emerik harvest reads a commit, extracts source-bound Pins, and re-derives any Pin whose source changed. With the post-commit hook installed it runs automatically on every commit; you can also invoke it directly.

$ emerik harvest
{"level":"info","message":"harvest: committed run","harvested":1,"rederived":0,"invalidated":0}
 harvested 1 Pin

Freshness — the honest part

Every Pin is bound to the bytes it came from. On the next harvest:

  • Source changed → the Pin is re-derived; the stale predecessor is superseded.
  • Source deleted / became binary → the Pin is invalidated with a tombstone.
  • Nothing changed → no-op (re-harvest is idempotent).

This is why a Pin never silently drifts out of sync with the code it describes.

Harvest never pins emerik's own scaffolding: the .emerik/ store, the whole .claude/ tree, and the root-level .mcp.json, AGENTS.md and CLAUDE.md that init wrote are excluded — so a git add -A right after init mints Pins only for your real source, never for the wiring outputs. A nested CLAUDE.md (your own knowledge file) is still harvested.

Anchors & verify

An Anchor is a reviewed contract with a machine-checkable assertion. You choose a subtype, an enforcement level, and a check.

FlagOptionsMeaning
--subtypecontract · constraint · steward · antibodyWhat kind of contract this is.
--enforcementblock warn advisoryWhat happens when the check fails.
--check-kindgrep · test · lint · fitness · agentHow the Anchor is checked.
--check-ref<pattern | command>The concrete target — a grep pattern, a test, a shell command.
--steward<who>Who owns this Anchor (required — an honesty label).
--governs<path glob>The code region this Anchor stewards (repeatable; inverted CODEOWNERS, resolved by emerik steward resolve).

Author a block-level constraint guarded by a grep pattern:

emerik anchor author \
  --content "Auth token TTL must remain 3600s to match the gateway." \
  --subtype constraint --enforcement block --steward you \
  --check-kind grep --check-ref "TOKEN_TTL_SECONDS = 3600"

List what exists, and run the gate:

emerik anchor list        # inventory of Anchors + lineage
emerik verify             # check every Anchor + convention lint
Enforcement levels

block fails emerik verify with exit code 1 — a hard CI gate. warn reports but does not fail. advisory is informational only.

Promote a Pin into an Anchor

A load-bearing Pin can be promoted through a review gate. Without --approve it is a no-write preview; with it, a reviewed Anchor is minted carrying promotedFrom lineage.

emerik anchor author --from-pin <pin-ulid> --subtype contract \
  --enforcement block --steward you \
  --check-kind grep --check-ref "requireAuth" --approve

The honesty loop

This is the whole promise in one worked example: a green check must go red the moment the invariant it guards is broken. Start from the constraint Anchor above.

Terminal
$ emerik verify                          # invariant holds
 conventions OK — no violations
✓ BLOCK  constraint 01KWH64…  grep — grep matched: TOKEN_TTL_SECONDS = 3600
1 Anchor(s) checked · 1  · 0 blocking
exit 0

$ sed -i '' 's/3600/7200/' src/auth.ts   # break the invariant

$ emerik verify                          # drift introduced
⛔ BLOCK  constraint 01KWH64…  grep — grep found no match for: TOKEN_TTL_SECONDS = 3600
1 Anchor(s) checked · 0  · 1 blocking
exit 1
Why this matters

A drift detector that can never detect drift is worse than none — it lends false confidence. Always test an Anchor by forcing it to fail, not only by confirming it passes.

Retrieve context

emerik retrieve answers a query with a cost-tiered cascade: it reaches for hot Pins (semantic search) first, falls through to Anchors, then to raw code — stopping as soon as it has enough. This is what an AI agent calls to get the right context cheaply.

emerik retrieve "how is the auth token TTL enforced?"
emerik retrieve "auth token TTL" --limit 5 --json

Results carry a heat bar (▁▂▃▅▇) showing how frequently each Pin is referenced.

The local index

Semantic retrieval is powered by a local, ephemeral index built from your committed Pins. It lives under .emerik-local/ (gitignored) and is rebuilt from the source of truth on demand — the index is disposable, the Pins are not.

CommandWhat it does
emerik index rebuildRebuild the index from scratch, then atomically swap it in.
emerik index refreshIncrementally bring the index up to date.
emerik index statusReport freshness and whether a rebuild is needed.
Offline by default

The embedder (ONNX all-MiniLM-L6-v2) runs locally. No query or content leaves your machine.

Heat & glacier

Every Pin has heat — a score blending recency-decay with how often it is referenced. Cold Pins can be frozen into a lossless glacier archive to keep the active index lean, and thawed back when they matter again. Freezing is a relocation, never a deletion: the Pin's identity and bytes are preserved.

emerik glacier freeze --threshold <heat>   # freeze Pins colder than a threshold
emerik glacier list                        # what's archived
emerik glacier thaw <pin-ulid>              # bring one back

Goals

A Goal is the concurrent work-unit: a team pursues one active Goal against the shared decision graph while other teams pursue theirs — many Goals run at once with no single-tree bottleneck. A Goal is a first-class, content-addressed, append-only artifact under .emerik/goals/: starting one mints an active Goal; advancing supersedes it with a progress entry; completing supersedes it with a completion stamp. The committed markdown brief under .emerik-goals/ stays the durable narrative — the Goal links it with --brief; they coexist.

A Goal carries a first-class priorityP0, P1, or P2, set with goal start --priority (default P1). It is the attention rank the orchestrator's simple-priority mode orders assignments by (P0 before P1 before P2), and it is carried through advance unchanged. The field is optional for append-only compatibility: a Goal committed before priority existed carries none and reads as P1.

CommandWhat it does
emerik goal start "<title>"Start a team's active Goal (--team, --brief to link the committed brief, --priority P0/P1/P2 — default P1); flags recently-changed depended-on contracts as coordination events.
emerik goal advanceRecord progress (--note) or finish it (--complete).
emerik goal statusShow a team's active Goal (or one by --id) — no active Goal is not an error.
emerik goal listLive Goals — active by default, --all includes completed.
emerik dependency declareDeclare a contract-dependency on a published Anchor (--anchor, --team, --note) — never live code under lease.
emerik dependency statusShow the currency of a team's dependencies — current, changed (a coordination event), or retired.
emerik dependency listLive dependencies — --team / --anchor (lineage-aware) filters.
One active per team

Starting a second Goal for a team while one is active is refused (GOAL_ACTIVE_EXISTS) — advance or complete the first. This is a local projection check, not distributed locking: two machines racing a start for one team can both land (the append-only union merges without corruption). The projection then reconciles the race deterministically — among a team's live active Goals it picks one winner (earliest createdAt, ties broken by lineage-origin id) as the Goal every team-selector read and write targets, and flags the rest as raced losers. Both stay visible in goal list; a loser carries a note naming the winner, its bare goal advance is refused with the same voice, and goal advance <loser> --complete retires it (the reconciliation move). No compare-and-swap, no goal ref, no committed-bytes change. Cross-machine write arbitration is still the Lease's job.

A coordination event at start, not a gate

When you start a Goal, emerik checks your team's declared contract-dependencies: if a depended-on Anchor changed since you declared it, goal start flags it after the STARTED line — “the ‘AuthGuard’ contract changed (2026-07-02…) — coordination event”, with the exact re-declare sync command. It is a heads-up to sync first, never an alarm: the Goal starts regardless (exit 0, never “conflict”) — a stale contract does not block starting work; the Lease is the only write arbiter. The --json payload stays exactly the Goal; agents pull the same report via dependency_status.

The flywheel

Completing a Goal outputs Pins that feed retrieval — Goals → Pins → RAG — because the Goal's committed brief and work commits are harvested by the hooks. The Goal surface itself mints no Pin: the emerik(goal): lifecycle commits are skipped by the harvest recursion guard. Learning is a byproduct of working.

Contract-dependencies

When your team builds on another team's work, you depend on the published Anchor — the contract — not on their live, leased-out code. It is the microservice-contract version pin: you declare a dependency on the contract you built against, and when the steward supersedes it, that change is an explicit coordination event you are notified about. The surface accepts only an Anchor id — it structurally cannot name live code, a path, or a leased territory, so “never against live code under lease” is a property of the shape, not a convention.

CommandWhat it does
emerik dependency declare --anchor <id>Declare a contract-dependency (--team, --note) on a live-head Anchor.
emerik dependency statusEach of a team's dependencies as current, changed, or retired.
emerik dependency listLive dependencies — --team / --anchor (lineage-aware “who depends on this contract”).

Declared against the contract, notified when it changes

A dependency is an append-only artifact naming a published Anchor's id. It is recorded once; when the steward supersedes the contract, you find out four ways:

  • The event log. The emerik(anchor): supersede <id> commit is the coordination event — a git-native, durable record, replayable via emerik history.
  • Your read surface. emerik dependency status (and the dependency_status MCP tool) reports a moved contract as changed and names the new head — the pull-based notification the dependent polls.
  • The author's render. When the steward runs emerik anchor author --supersedes, the human output names the dependent teams affected — a courtesy heads-up at change time (the --json envelope is unchanged; the notification surface for agents is the pull-based status).
  • At Goal start. emerik goal start renders the coordination event automatically (human output) for any depended-on contract that moved — sync before building on it. It is a heads-up, not a gate: the Goal starts regardless. Agents on the MCP path pull the same report via dependency_status right after starting.

Sync is a re-declare

There is no separate sync verb: re-declaring on the new head mints a superseding Dependency (append-only), which dependency status tells you the exact command for. A same-head re-declare is refused (DEPENDENCY_EXISTS) — it is never a silent no-op. If two machines race that declare for the same team and anchor and both land, the byte-identical duplicates dedup at projection (kept: earliest) and count as one dependent — append-only, both files stay on disk.

A coordination event, not a conflict

A changed contract is surfaced in coordination-event voice — a heads-up to reconcile, never an alarm. A live dependent now drives the risk tier: a review that edits an Anchor with dependents is risk-tiered high and routed to a human — see Review at scale.

Exclusive-write leases

When several agents or machines write to the same repo, a lease gives one of them exclusive rights to a territory for a bounded time. Leases are recorded on a dedicated git ref (refs/emerik/leases) via compare-and-swap push — your git remote is the serialization point, so no lock server is needed. A lease expires on crash or stall, so turf never deadlocks.

Territories collide by path overlap, not just exact string — so mutual exclusion is mechanical, not a naming convention. A lease on src/auth/ blocks a claim on src/auth/login.ts (and the reverse), and glob forms like src/auth/** collide the same way. A bare token with no / or glob metachar (e.g. payments) is opaque — it collides on exact match only. The refusal names the overlapping lease so an agent's routing reads it unmistakably.

A single-segment directory is still a bare token

A trailing slash alone does not make a territory path-aware: billing/ normalizes to the bare token billing and collides on exact match only — it will not collide with billing/invoice.ts. Write a multi-segment path (src/billing/) or a glob (billing/**) when you want collisions detected across an entire module.

CommandWhat it does
emerik lease claim <territory>Claim exclusive write on a territory (--ttl, --holder, --retries, --wait).
emerik lease renew <territory>Extend a lease you hold (--retries, --wait — a transiently-contended renew retries to success).
emerik lease release <territory>Give it back early (--retries, --wait).
emerik lease listActive leases (add --remote for a fresh cross-machine read).

Two machines, one territory

Run this on two clones of the same remote at nearly the same instant. Exactly one wins.

This is signed off end-to-end: two clones with distinct git identities, driven over both the CLI and the MCP twins, exercise cross-machine claim, territory overlap, version-skew tolerance, and goal/fork/dedup races against a shared remote — each producing exactly one winner or one surfaced, reconcilable fork. Since the git ref CAS is client-agnostic, the serialization holds identically across physical machines — the executed pass ran against a local bare remote (a hosted remote and a literal second physical machine are a documented follow-up; see the committed sign-off record).

Machine A Machine B
A$ emerik lease claim payments --holder machineA --retries 0
⛔ BLOCK  territory 'payments' contended — another machine claimed it first   exit 1

B$ emerik lease claim payments --holder machineB --retries 0
▣ LEASED  payments · holder machineB · expires in 15m                        exit 0
Retries

--retries 0 fails fast. The default (5) uses jittered back-off so a transiently-contended claim, renew, or release retries to success instead of failing spuriously — all three mutating verbs share the one retry discipline.

Version skew — tolerate the known, refuse the rest, never open

A lease this client reads may have been written by a newer emerik. The read posture is deliberate and single-winner by construction: a lease whose six core fields still validate (with unknown extra fields stripped on read) is tolerated — honored as held and listed; a blob it cannot fully read is refused as held — its territory stays blocked and its bytes are preserved untouched. A client never grants a territory it cannot prove free, and never rewrites a lease it cannot fully read (renewing a newer-format lease is refused — renew it with that version; releasing one you hold still works). The lease's six fields are a frozen core: any future growth is additive and optional over them, so old and new clients coordinate safely.

Clock skew — bounded, and it never touches the winner

A lease's expiresAt is written from the writer's clock; liveness is judged against each reader's clock. The compare-and-swap that picks the winner of an open territory never consults a clock — the git ref store serializes it — so single-winner exclusivity is skew-independent. Skew moves only the expiry edge: a contender whose clock runs ahead of the holder's by S seconds could claim over an expired lease S seconds early. With the holder renewing at least M seconds (its own clock) before expiry and treating a failed renew as loss-of-lease, a live holder stays exclusive for |S| < M. At the shipped default ttl 900 s and a renew-at-half cadence, M = 450 s — three to four orders of magnitude above NTP-disciplined skew (typically < 0.1 s). The operating rule: renew before the margin, treat a failed renew as lost. (--wait is accumulated back-off, not a wall clock, so it is unaffected by skew.)

Stigmergic self-deconfliction

Agents coordinate the way ants do — by reading shared state and routing around each other, with no direct messaging and no orchestrator. Before it chooses where to work, an agent reads the trailemerik trail status (MCP trail_status):

  • The heat trail. A recently-worked path is hot — a signal that someone is active there. This is FR-4's heat read as a pheromone: one mechanism, two uses, the same heat number retrieval ranks by, never a second subsystem. Recency travels through git (a fresh Pin's committed createdAt), so "someone just worked here" is visible cross-machine; reference counts add same-machine reinforcement. Heat never blocks — a hot zone is a routing signal, not an error.
  • The lease markers. The active Leases on refs/emerik/leases are the authoritative contested signal — territory · holder · expiry, shown so others route around them.
CommandWhat it does
emerik trail statusRead the trail — hot zones + lease markers — to route around, no messaging (--remote for a fresh cross-machine read, --limit to cap the zones). Pure read; mutates no ref.

Declaring a territory turns the trail into a guard. When an author declares the territory it holds — emerik anchor author … --territory <t> (MCP anchor_author territory) — the write is consulted against the live Leases before it lands using the same path-overlap check a claim uses: a declared territory that path-overlaps another holder's live Lease refuses the write (LEASE_HELD, exit 1, no partial write) in coordination-event voice — never "conflict", never "locked". Your own or an open territory proceeds. Heat is never consulted at write time; only a live Lease arbitrates.

The routine case, and the rare one

The routine workload self-deconflicts this way — N agents make N trail reads and zero pairwise messages, so coordination never grows with the square of the swarm (layer 1, ~95% of the work — an Epic-8-measured target). The rare genuine collision that cannot be routed around — two agents that truly need the same territory — is arbitrated by the emerik-orchestrate skill (layer 2, the ~5% path), which reads this same trail, then applies drafted rules in order: wait out a short-lived Lease, else let the higher-priority Goal proceed (P0 over P1 over P2), else first-holder by CAS order, else split at a published Anchor (declare a contract-dependency and build against it), and finally surface it to the human driver. The orchestrator arbitrates who proceeds — it grants territory only through Leases and never breaks one.

Onboard a brownfield repo

Adopting emerik on an existing codebase is an agent workflow, not a manual runbook. Point your coding agent at the emerik-onboard skill and it drives the whole cold start: ensure the store is initialized, emerik seed --analyze, emerik seed, build the index, and land a committed onboarding summary grounded in the seeded graph — with each phase's landing verified from the live surface (via the --json reports and emerik index status) before the next phase starts. Retrieval works warm from the first query.

A repo with nothing to seed is not forced through the pipeline: when the analyzer reports codeUnits === 0 (or there is no HEAD), emerik-onboard says so and routes to the greenfield planning path (emerik-brainstorm + emerik-guide) instead of seeding nothing — the store is still left initialized with a fresh index.

Deterministic seed content is a code/comment excerpt. When a coding agent drives the cold start it can do better: after the first analyze pass, it reads the enumerated code units and writes a short synthesized understanding of each file it can genuinely improve into a gitignored handshake file .emerik-seed/synthesis.json (keyed by repo-relative path), then re-analyzes with --synthesis. Those files' Pin content becomes the agent's understanding — provenance-marked synthesis: agent, a record of how the content was produced, not a trust upgrade — while the binding stays on the code, so re-derive keeps it fresh from there. No live agent or model is ever loaded into the engine: the intelligence arrives as data through the same extractor seam the deterministic pass uses.

Documents get the same two-tier treatment. Instead of admitting a whole file as one 2000-character dump, the analyzer splits each doc on its markdown headings into per-section candidates — the deterministic fallback, always available. When a coding agent drives the cold start it extracts the actual decision each section states (an ADR's "use PostgreSQL", not its prose) into a second handshake file .emerik-seed/doc-decisions.json and re-analyzes with --doc-decisions; those per-decision candidates replace the section chunks, marked synthesis: agent. Admission is then a real per-candidate review: bare emerik seed --json returns docCandidates — each with a stable candidateKey, its source and section, full content, and a proposed enforcement — and the steward admits them individually through an admissions manifest (below), each with its own steward and enforcement level. Two documents stating the same decision collapse to one candidate (and one Anchor). No Anchor is ever written without --approve-docs and a named steward — the machine still never mints an Anchor on its own.

Two ways in

A skill cannot be its own delivery vehicle — its premise is pre-init — so there are two documented doors:

  • Door 1 (recommended). Install emerik globally, run emerik init as the one manual command (it installs all fourteen skills), then invoke emerik-onboard in your agent. Its first phase detects the store, records init as already landed, and continues with analyze.
  • Door 2 (fully agent-driven). Point the agent at the packaged assets/skills/emerik-onboard/SKILL.md inside the globally-installed package and follow it — the skill drives emerik init itself as phase 1, self-installing for every future session.
Provenance

Seeded artifacts are stamped origin: seed — a lower trust tier than reviewed Anchors. Machine analysis never mints Anchors directly; doc Anchors wait in a review queue, admitted only behind an explicit steward gate the human names.

The manual runbook advanced

Prefer to drive it yourself (or running in CI / a non-agent harness)? The same pipeline is two review-gated steps. It requires an initialized store — run emerik init first.

# 1) analyze — walks HEAD + ingests docs into a gitignored .emerik-seed/
emerik seed --analyze

# 2) seed — bulk-write the analysis into the graph (code → Pins)
# bare seed also lists per-candidate doc previews (docCandidates) in --json
emerik seed

# admit ALL doc candidates under one steward (the bulk gate)
emerik seed --approve-docs --steward you

# or review per candidate: admit only the keys in an admissions manifest,
# each with its own steward + enforcement (see below)
emerik seed --approve-docs --admissions .emerik-seed/admissions.json

Seed from generated behavior docs

Already documented the codebase with a tool that emits a coverage.json feature index (mapping each feature to its docs and the code paths they describe)? Point --analyze at it and each covered code file's Pin content becomes that feature's behavior contract — bound to the code, so re-derive keeps it fresh from there.

# enrich covered code Pins with feature contracts (auto-discovers
# the index via doc-agent.config.json when --coverage is omitted)
emerik seed --analyze --coverage docs/features/coverage.json
emerik seed

Seed with agent-synthesized understanding

Have an agent (or a script) that can describe each file? Write its output as a handshake file — a { formatVersion, entries } map of repo-relative path to synthesized text — and point --analyze at it with --synthesis. Covered files are seeded with that text, stamped synthesis: agent; every uncovered file falls back to the deterministic excerpt. The named file must exist (a missing --synthesis path is a hard error, unlike auto-discovered --coverage).

# swap agent understanding in through the extractor seam
emerik seed --analyze --synthesis .emerik-seed/synthesis.json
emerik seed

Extract per-decision doc candidates

Without a handshake, each document is split on its markdown headings into per-section candidates. To capture the actual decision a section states (rather than its prose), write a { formatVersion, decisions } map of doc sourcePath to the decisions it states — an empty array is the honest "no decisions here" signal — and point --analyze at it with --doc-decisions. A matched doc's candidates are replaced, stamped synthesis: agent; a handshake path matching no ingested doc is reported as unmatchedDocDecisions, never silently dropped. The named file must exist.

# replace section chunks with the agent's per-decision candidates
emerik seed --analyze --doc-decisions .emerik-seed/doc-decisions.json
emerik seed

Admit per candidate

Bare emerik seed --json lists every admittable candidate under docCandidates with a stable candidateKey. To admit a reviewed subset — each with its own steward and enforcement level — write an admissions manifest and pass it with --admissions. Listed keys are admitted; unlisted candidates stay pending; an unknown key is a hard error before anything is written. All three enforcement levels are accepted (you chose), but an admitted doc Anchor is checkless, so even block/warn still surfaces as ⚠ WARN in emerik verify — admission records a decision, it does not add a runnable contract.

# .emerik-seed/admissions.json
# { "formatVersion": 1, "admit": [ { "key": "<candidateKey>", "steward": "data", "enforcement": "advisory" } ] }
emerik seed --approve-docs --admissions .emerik-seed/admissions.json
One-time boost

The docs seed the content; the binding stays on the code. After the first edit to a covered file, harvest re-derives its Pin back to code-derived content — re-run the seed to refresh. The feature docs are used as Pin content, not minted as duplicate Anchors (pass --include-feature-docs to keep both).

History & time

Because the substrate is append-only on git, the commit history is the decision log. Three read-and-maintain commands operate over time.

CommandWhat it does
emerik historyReplay the .emerik/ decision log, or one artifact's lineage — the why behind a fact.
emerik compactGarbage-collect superseded Pins (keep the latest fact; removed bytes stay replayable in git). Try --dry-run first.
emerik rollup <domain>Distil a domain's decision history into a retrievable narrative rollup.
emerik history <artifact-ulid>     # lineage + why
emerik compact --dry-run           # preview the GC, mutate nothing
emerik compact                     # report the before→after .emerik/ byte delta

Use with an AI agent

emerik is built to be an extension of your coding agent. When you run emerik init, it wires the repo so Claude Code (and other harnesses) can reach the substrate through a small, safe tool surface — the agent grounds its plan in your team's committed Pins and Anchors before it writes a line, then works one territory at a time under a Lease.

Start here — the guided path

Inside the coding agent, the front door is emerik-guide. It turns the suite of skills into a guided method — just say what you need:

  • Orient“orient me”, “where am I?”, “what should I do next?” It derives where the repo stands from live substrate facts (index_status, anchor_list, lease_list, a committed Goal brief) and the installed skills' own declarations, then recommends the next step as a short menu — never a hardcoded script.
  • Tour“give me the emerik tour”, “show me how this works”. A hands-on walkthrough of the whole loop, each leg delegating to the real skill.
  • Step-through“walk me through emerik-goal step by step”. It wraps any suite skill with its gates made explicit, confirms at each gate, and reports what was read from and deposited into the graph.

What emerik init wired

  • .mcp.json — registers the emerik mcp stdio server as an MCP server named emerik ({ "command": "emerik", "args": ["mcp"] }), merged additively so your other servers are untouched.
  • .claude/skills/ — the fourteen shipped skills: emerik-brainstorm, emerik-brief, emerik-prd, emerik-architect, emerik-breakdown, emerik-discover, emerik-goal, emerik-plan, emerik-implement, emerik-review, emerik-guide, emerik-retro, emerik-orchestrate and emerik-onboard.
  • .claude/agents/ — the four reviewer roles emerik-review fans out (blind-hunter, edge-case-hunter, acceptance-auditor, substrate-auditor).
  • a delimited <!-- emerik:begin -->…<!-- emerik:end --> block in AGENTS.md (and CLAUDE.md when present) so a non-Claude harness (Codex, Cursor) reads the same context.
One boundary

An agent touches the graph only through the MCP tools — never .emerik/ on the filesystem and never the engine directly. The tools are the sanctioned, audited surface; the store stays append-only and honest.

The thirty-five tools

The MCP surface is exactly thirty-five noun_verb tools, each a thin wrapper over the same engine the CLI calls:

ToolWhat it does
graph_retrieveResolve a query cost-tiered — hot Pins → Anchors → raw code.
anchor_listList the live Anchors and their checks / enforcement levels.
anchor_authorAuthor a steward Anchor, or promote a reviewed Pin (the --approve review gate is preserved). Optional territory/holder gate the write on the live Leases — a territory held by another refuses it (LEASE_HELD).
goal_startStart a team's active Goal — the concurrent work-unit (links a committed brief with --brief).
goal_advanceRecord progress on — or --complete — a Goal (append-only supersession).
goal_statusShow a team's active Goal (or one by id); null when none, never an error.
goal_listList the live Goals — active by default, --all includes completed.
dependency_declareDeclare a contract-dependency on a published Anchor — never live code under lease.
dependency_statusReport each dependency as current, changed (a coordination event), or retired.
dependency_listList live dependencies — team / anchorId (lineage-aware) filters.
lease_claimClaim exclusive write on a territory before writing.
lease_renewExtend a Lease you hold.
lease_releaseGive a territory back.
lease_listInventory the active Leases.
trail_statusRead the stigmergic trail — hot zones (heat) + lease markers — an agent routes around, no messaging (--remote, --limit).
review_openRecord + route an agent-quorum review — cleared by quorum, or escalated to a human when it edits a high-dependent Anchor. Declares edited Anchors with anchorIds, verdicts with verdicts, the steward's digest scope with domain.
review_listList the live routing records — routing filters cleared / escalated, domain filters the digest scope.
review_blessBless an escalated review — clear the change on the steward's authority, through code. Mints a superseding decision Review (optional note, self-asserted by); no status field.
review_adjustRequest adjustment on an escalated review — send the change back for rework, through code (a superseding decision Review).
steward_resolveResolve stewardship for a code path — the Anchor(s) that govern it and the accountable steward, most-specific first (inverted CODEOWNERS).
steward_constraintsList a steward-agent's standing constraint set — its constraint-Anchors, in accrual order (the design process is the training signal).
antibody_mintMint an antibody (a constraint learned from a past failure) attached to a domain steward — a block antibody requires a human bless before it binds.
antibody_blessBless a pending high-impact antibody so it binds — the human gate before a block antibody can fail CI (OQ-8).
antibody_listList a domain steward's antibodies — the constraints minted from past failures, with their bless state.
antibody_retractRetract a false antibody — an append-only Tombstone (no in-place delete); it no longer binds future agents.
metrics_reworkReport the drift-driven rework rate — a read-only, drafted SM-1 proxy over the decision log (baseline + an optional ongoing window).
metrics_review_timeReport the review funnel per Goal — the agent-quorum auto-clear rate + a drafted human-review-load proxy (reviewer-hours are not instrumented).
brief_authorAuthor a brief — the durable, append-only planning head; supersedes revises the live one (steward defaults to the git identity).
prd_authorAuthor a prd (product requirements document) — same append-only grammar as brief_author.
architecture_authorAuthor an architecture (a solution/architecture design) — same append-only grammar as brief_author.
brief_listList the briefs — live by default, all includes superseded/tombstoned history (returns the live head with supersedes). No brief_status tool — the live head is served here.
prd_listList the prds — live by default, all includes history.
architecture_listList the architectures — live by default, all includes history.
index_statusReport whether the local index is built and fresh.
index_refreshAbsorb newly-committed Pins into the local index.

emerik verify stays a shell gate, not a tool — it is the CI / verification step (exit 1 on any block-level failure), so an agent runs it from the terminal.

The fourteen shipped skills

emerik-brainstorm

Idea → grounded ideation, from anywhere — including a fresh repo with zero Pins (an empty substrate is a valid entry state, not a special mode). It reads what the substrate already committed first (index_statusgraph_retrieveanchor_list), and when those come back empty it says so and starts from a blank slate. It facilitates the session, deposits any constraint stated at the moment of statement as a constraint-Anchor through the review gate (anchor_author, confirmed with steward_constraints), then lands a committed session doc under .emerik-planning/ that harvest captures — and hands off to emerik-brief.

emerik-brief

Idea → durable brief. It grounds in the substrate, picks up the brainstorm session doc when one exists (a brief from scratch is valid too), and writes the brief body from a template. It commits the body under .emerik-planning/ before minting the artifact, then mints the brief via brief_author (--doc-path, --steward) referencing the committed body. A revision supersedes the live head (append-only, checked with brief_list first), never an in-place edit. The brief is the input the planning head grows from; it hands off to emerik-prd to grow a full PRD, or to emerik-goal for a delivery-sized slice.

emerik-prd

Brief → durable PRD. It reads the live brief the PRD grows from (brief_list, surfacing a fork if more than one live head exists, routing back to emerik-brief if none), then writes the PRD body from a template — descriptive features stay prose (harvested Pins), while each binding requirement is offered as a candidate constraint-Anchor at the moment of statement through the review gate (anchor_author with an owner-consented enforcement level — BLOCK / WARN / ADVISORY — confirmed with steward_constraints; a withheld consent is recorded as declined). It commits the body under .emerik-planning/ — collision-checked, so a revision writes a new file — before minting the prd via prd_author (--doc-path, --steward); a revision supersedes the live head (append-only, checked with prd_list first). It hands off to emerik-architect to turn the PRD into a solution design, or to emerik-goal for a delivery-sized slice.

emerik-architect

PRD → durable architecture. It grounds in the substrate — including the standing Anchors that already govern the code (anchor_list) — reads the live prd the design answers (prd_list, surfacing a fork if more than one live head exists, routing back to emerik-prd if none), then writes the architecture body from a template. Each decision that governs a code region is offered as a candidate governing Anchor at the moment of statementanchor_author --subtype contract --governs '<glob>' (the inverted-CODEOWNERS surface, confirmed with steward_resolve) — carrying a real grep/test/lint check where expressible, and an honest checkless advisory/warn sticky-note where not (an agent check reports skipped/WARN today; block only with a runnable check). Non-regional constraints keep the constraint-Anchor leg. The consent gate is conversational and agent-side — the machine never mints an Anchor unprompted. It commits the body under .emerik-planning/ — collision-checked, so a revision writes a new file — before minting the architecture via architecture_author (--doc-path, --steward); a revision supersedes the live head (append-only, checked with architecture_list first). The governing Anchors are the enforcement surface, so the document and the enforcement surface are the same thing. It hands off to emerik-breakdown to sequence the prd and architecture into ordered Goal briefs, or to emerik-goal for a single delivery-sized slice.

emerik-breakdown

PRD + architecture → an ordered sequence of Goal briefs the engineering loop picks up directly. It grounds in the substrate, reads BOTH live heads (prd_list and architecture_list, surfacing a fork on either if more than one live head exists, routing back to emerik-prd or emerik-architect if either is missing), then writes and commits one initiative brief at .emerik-planning/initiative-<slug>.md — collision-checked, committed before any Goal brief cites it. Each Goal brief is the standard Goal-brief shape plus a leading Sequence block — its initiative citation, a P0/P1/P2 priority (dependency-consistent: a brief never outranks a predecessor it depends on), and explicit Depends on: lines — written sequence-prefixed under .emerik-goals/<nn>-<slug>.md so lexical order is the breakdown order, its guardrails citing real Pin and Anchor ids with their levels. The initiative layer is a documented convention, not a mechanism: no schema field, no new work-unit type — the Goal stays the sole work unit. It hands off to emerik-goal per brief (goal_start --brief --priority, read from the Sequence block) and to emerik-orchestrate for the whole sequence (the swarm honors each brief's Depends on: lines; independent briefs fan out in parallel).

emerik-discover

Fuzzy problem → grounded exploration. It reads the substrate first (index_statusgraph_retrieveanchor_list), facilitates the exploration, then lands outcomes honestly: a decision summary you commit (harvest captures the Pins), and candidate constraint-Anchors offered through the review gate.

emerik-goal

Intent → Goal brief with cited guardrails. It reads the substrate first (index_statusgraph_retrieveanchor_list), then shapes a Goal and testable acceptance criteria whose guardrails cite the Pin and Anchor ids they must honor, with their enforcement levels. The brief is committed under .emerik-goals/ (harvest captures it), then started as a first-class Goal via goal_start (linking the brief with --brief) and handed to emerik-plan.

emerik-plan

Goal → committed plan doc. It refreshes the substrate (index_statusindex_refresh), runs the retrieval cascade over the Goal and each acceptance criterion, lists the standing constraint-Anchors, and drafts a plan whose every step cites the Pin and Anchor ids it relies on — then lands it as checkbox steps in .emerik-goals/<slug>-plan.md, the Goal brief's sibling, committed and harvested. The plan survives the chat window: a fresh session — or a different model — picks up the next unchecked step cold.

emerik-implement

Plan step → implementation, under coordination discipline and test-first rigor: claim a Lease, write the failing test first (watch it fail), implement to green (red-green-refactor), let the harvest hook capture the commit, run emerik verify green, then release the Lease. A step is done only when the new tests exist and pass and verify exits 0 — never claimed-but-unrun. Starts cold when it has to: goal_status → the committed plan doc → the first unchecked box, flipping each finished step's checkbox in the same commit as its code. On fixing a defect it offers a witness: a checked Anchor through the review gate that would have caught it, so the regression gate lives in the substrate. And it is extremely critical of its own TODOs: one it could finish now gets finished, not left; one bigger than the step trips a circuit breaker back to the driver — "this is bigger than the plan assumed — split it into its own Goal(s)?" — and only a genuinely blocked one may stand, recorded in deferred-work.md with its reason and unblock condition.

emerik-review

Change → adversarial review over the substrate. It fans out asymmetric reviewers — Blind Hunter (diff only), Edge Case Hunter (diff + repo), Acceptance Auditor (diff + Goal brief) — plus the Substrate Auditor, which audits the diff against the live graph (anchor_list / graph_retrieve for block/warn Anchors, lease_list for Lease discipline, harvest honesty). It triages every finding into exactly one bucket (decision-needed / patch / defer / dismiss), commits a review record under .emerik-reviews/ (harvest captures it), and offers recurring failures as antibody-Anchor candidates through the review gate. It then derives one verdict per reviewer layer and records the routing decision with review_open — see Review at scale. It never ends silently on undone work: a defer must be earned (a stated reason plus what would unblock it — actionable-but-large work is escalated for a split, never deferred), every TODO the diff introduces goes through triage, and the review closes with a deferral report — everything that could not be done, each with its reason — offering, with consent, to fold items into the active Goal, mint a cleanup Goal, or split oversized work into its own Goals.

emerik-guide

The guided front door, in three modes. Orient derives where the repo stands from live substrate facts and the installed skills' declarations, then recommends the next step as a short menu — never a hardcoded script. Tour is a hands-on walkthrough of the whole loop, each leg delegating to the real skill. Step-through wraps any suite skill with its gates made explicit, confirming at each gate and reporting what was read from and deposited into the graph.

emerik-retro

Completed Goal → lessons back in the substrate. It reconstructs what happened from the record first — emerik history (the decision log), the harvested Pins and the heat (graph_retrieve), the governing Anchors (anchor_list) — facilitates the lessons, then lands them: lessons worth keeping as antibody-Anchor candidates through the review gate (the bless loop lands with Epic 6), action items in a committed summary under .emerik-retros/ that harvest captures.

emerik-orchestrate

Active Goals → a two-layer swarm. It reads the substrate first (goal_list, trail_status, dependency_status), carves non-overlapping assignments, and fans out one host-agent subagent per Goal or plan step — each in its own git worktree running emerik-implement (sequential in-session where subagents are unavailable). Layer 1 is hands-off: the heat trail and the Leases deconflict the routine ~95%. Layer 2 is the rare genuine collision, arbitrated by drafted rules in order — wait out a short Lease, higher-priority Goal proceeds (P0/P1/P2), first-holder by CAS order, split at a published Anchor, else the human driver. It grants territory only through Leases — it holds none, claims none on a subagent's behalf, and never breaks one.

It orders the carved assignments before fanning out. Simple P0/P1/P2 priority is the default on every run. A market-maker mode is an opt-in, evaluable A/B option — never the default: it prices an attention bid (impact × risk) minus a congestion cost on contested territory (overlapping a trail_status hot zone or a live lease marker), nudging non-conflicting Goals first and degrading to simple ordering on any tie. It orders, it never gates — Leases stay the only write arbiter. The mode is announced and recorded so runs are A/B-comparable (OQ-4); the decision criteria — escalation share, time-to-complete, rework rate — are targets Epic-8 instrumentation measures.

emerik-onboard

Brownfield cold start → a warm substrate, as an agent workflow. Its premise is pre-init, so it requires nothing to start. Phase 0 preflights the git repo and checks for a HEAD; phase 1 is an idempotent ensure-init (store absent → emerik init, committed; store present → recorded pre-landed); then emerik seed --analyze and emerik seed mint the origin: seed Pin/Anchor graph, emerik index rebuild makes retrieval warm, and a committed summary under .emerik-planning/onboarding-<slug>.md is written from the seeded graph (real Pin and Anchor ids) — committed before the final emerik index refresh so the harvested Pins land. Each phase's landing is verified from the live surface (the --json reports, emerik index status) before the next begins. Doc Anchors are admitted only behind an explicit, consent-gated emerik seed --approve-docs --steward <id> — the machine never mints an Anchor unprompted. A repo with nothing to seed (codeUnits === 0, or no HEAD) is detected as greenfield and routed to emerik-brainstorm + emerik-guide with the store kept initialized. It hands off to emerik-discover, emerik-goal or emerik-guide — nothing auto-runs.

The reviewer roles emerik-review fans out over ship under .claude/agents/ (blind-hunter, edge-case-hunter, acceptance-auditor, substrate-auditor) — each a subagent with only its allowed inputs, so a defect one reviewer rationalizes away another cannot. Those reviewers are the agent quorum — their verdicts feed the risk-tiered routing record below; the steward's batched digest of those records ships too — emerik review [domain] collapses a day of output into a few team-level rows.

Review at scale — agent quorum + risk-tiered routing

When N independent agents adversarially agree a change is safe, it can clear without a human — but only a change below the risk tier. The Review artifact is the durable, append-only record of that decision: it names the change, the reviewers' verdicts, the edited Anchors and their live-dependent counts, and the routing outcome. emerik review open (MCP review_open) records + routes it; emerik review list projects the live records. Opening a review orders the outcome — it never gates a write; Leases stay the only write arbiter, and it exits 0 on both outcomes.

CommandWhat it does
emerik review [domain]Open the batched digest — the one v1 TUI screen. Boilerplate collapses to a single faint ✓ N cleared row; only escalated changes surface as attention rows; the header reads N cleared · M need you. An optional domain scopes it (exact match). Keyboard-only (j/k move, drill in, bless, adjust, / filter, q quits); non-TTY / --json print the static digest / model. --web opens the review surface in the browser instead — on-demand, localhost, ephemeral (TTY only; --json/--quiet/non-TTY keep today's behavior).
emerik review open <subject>Record + route an agent-quorum review — --anchor (repeatable, the edited Anchors), --verdict <reviewer>:<safe|unsafe> (repeatable), --goal, --domain (the steward's digest scope, declared), --record. --finding <file>:<line>:<severity>:<title> (repeatable, severity ∈ P0/P1/P2) pins structured findings to exact lines; --from-branch (with explicit --base/--head override) stores the reviewed range as commit SHAs so review --web can regenerate the diff live. Exits 0 whether cleared or escalated.
emerik review listLive routing records — --routing cleared|escalated and --domain filter.
emerik review bless <id>Bless an escalated review — clear the change on the steward's authority, through code (a superseding decision Review). Optional --note, --by (defaults to the git identity).
emerik review adjust <id>Request adjustment on an escalated review — send the change back for rework, through code. Optional --note, --by.

The engine owns these drafted OQ-9 defaults — engine-owned constants, tunable when Epic-8 instrumentation measures the queue reduction (never reported as achieved before then):

  • Quorum — a normal-tier change clears only with three distinct reviewers, unanimously safe. Any unsafe, a short quorum, or a missing layer escalates.
  • Risk tier — a change that edits an Anchor with at least one live dependent is high tier and is routed to a human regardless of the verdicts. Quorum can never override the tier.
  • Spot-auditone in ten auto-cleared reviews is flagged for a human spot-check, deterministically derived from the review's id (unpredictable before mint, verifiable after).

That last guarantee is structural, not a convention (the SM-C2 guardrail): the Review schema re-derives the tier and routing from the artifact's own recorded evidence, so a committed review whose bytes claim cleared on a high-tier change simply fails to parse — and fails emerik verify. A cleared-high artifact cannot exist. Routing speaks in coordination-event voice — cleared by quorum or escalated — routed to a human, never "conflict".

The batched digest — emerik review [domain]

Review is owned and scheduled — the steward starts it; it never pushes as an interrupt stream (no watcher, daemon, or notification surface exists anywhere in emerik). emerik review [domain] opens the one v1 TUI screen: a single full-height panel — a fixed header (surface + domain + summary), a scrollable digest body, and a fixed key-hint footer — that reflows legibly at 80 columns.

  • Boilerplate collapses to a single faint ✓ N cleared row, whether N is 12 or 12,043 — the collapse row is the scale answer.
  • Only escalated changes surface as their own attention rows: a selection caret + a state glyph + the change subject (bold) + fan-out:NN (the blast radius — the max declared dependents; omitted when the change names no Anchors). Reviews carry no heat, so there is no heat-bar.
  • A spot-audited clear earns its own dim · spot-audit row (it still counts in N cleared; M need you counts escalated only).
  • The header voice is byte-exact: 198 cleared · 2 need you., an all-clear 198 cleared · 0 need you., and an empty scope No changes since last review.
  • Domain scopes the digest by exact match — declared at review open --domain, never inferred; an undomained review appears only in the unscoped digest.

The screen is keyboard-only (j/k or / move the caret, q quits) and honest under constraint: NO_COLOR reads identically because every state is glyph + text, and a non-UTF-8 / dumb terminal falls back to ASCII glyphs. A piped / non-TTY run prints the same digest as static text; --json emits the digest model.

Drill in & resolve — review-as-code

Press on a flagged row to drill in: an inline accordion (one level deep, never a second window) shows why it escalated, the change-as-code (the reviewer verdicts + the record pointer), and the fan-out list — the edited Anchors with their dependent counts. Resolve it through code, not a heavy approval form: b blesses the change (clears it on the steward's authority) and a requests adjustment (sends it back for rework). Each mints a superseding decision Review — the escalated record is retired by supersession, not flipped by a status field (there is none). / filters the attention rows; esc collapses. The same resolutions are scriptable off-terminal: emerik review bless <id> / emerik review adjust <id> (and the MCP review_bless / review_adjust twins), each carrying an optional --note.

Read the change in the browser — emerik review --web

For a change too large to read in the terminal, emerik review --web opens the same review as a browser-grade surface: the diff regenerated live from git with syntax highlighting, each finding badged on its exact line (severity P0/P1/P2 shown as its BLOCK/WARN/ADVISORY affordance), boilerplate hunks collapsed with expand-on-demand, and the Anchor fan-out. It holds emerik's spine: the server is on-demand, ephemeral, stateless, zero-new-dependency, localhost-only — a 127.0.0.1 HTTP server on an ephemeral port with a one-time capability token in the opened URL, torn down on exit (Ctrl-C / browser-close / idle timeout). No always-on daemon, no database: git and .emerik/ stay the only truth and the page is a pure stateless projection over them (the HTTP sibling of the on-demand emerik mcp server). It is additive — the TUI screen stays, and --json/--quiet/non-TTY never launch it.

The reviewed change is captured as code, not snapshotted: emerik review open <subject> --from-branch stores the range as resolved commit SHAs (base = merge-base(HEAD, upstream/trunk), head = HEAD; --base/--head override), and the browser regenerates the diff from that range at view time — no committed diff bytes, yet the exact reviewed change. A review with no stored range degrades to the metadata view (why + verdicts + fan-out), never a fabricated diff. Bless and request-adjustment from the page call the same token-gated, review-as-code ops as the terminal — minting superseding Reviews, no new approval model — and the surface refetches so the resolved row leaves the attention set.

Impact-based routing & authority

When a change edits an Anchor, the dependency graph is the reviewer-routing graph: the teams that declared a contract-dependency on it are auto-enlisted as the review audience (the drill-in lists them, per Anchor). Review is team-level — a verdict is one team's voice (self-asserted; emerik keeps no per-person membership), so any one member clearing counts for the whole team and hundreds of per-person approvals collapse to a handful of team-level reviews. And the core owner — the Anchor's steward — can ship a wide-fan-out central change on their authority (a review bless): dependents are notified and can review adjust through code, but full consensus is not required. The review is never skipped — a high-fan-out change escalates by construction and reaches the steward, who ships with review rather than gating on stop-the-world consensus (pairs with versioned / expand-contract migration, OQ-10).

Forked supersession — surfaced and reconciled

A forked Anchor supersession (two Anchors racing to supersede one predecessor) is walked as a multi-edge lineage: dependentsOf counts the union across every branch, so a change's blast radius is never under-counted and review tiering can no longer under-tier it. The fork is surfaced, never silently resolved — dependency status reports the deterministic primary head and lists all live heads, and emerik history <id> names the divergent branch. The steward reconciles it by supersede-to-merge: author the merged successor over one head and tombstone the other, after which every branch's dependents re-point to the single live head. No new command and no committed-bytes change — the existing surfaces compose.

Stewardship — inverted CODEOWNERS

Decisions own code. An Anchor declares the code region it stewards with --governs <glob> (repeatable), and emerik steward resolve <path> (MCP steward_resolve) maps a path back to the Anchor(s) that govern it and the accountable steward, layered most-specific first — the inverse of a CODEOWNERS file (the decision owns the code, not a path→owner list). Every Anchor carries a required steward (human email or agent id — OQ-7 leaves per-domain agent-vs-human assignment open); a Pin at a governed path inherits the governing Anchor's steward. Stewardship is permanent and travels with the graph — it sits above transient Leases: resolving stewardship consults no lease, and a lease never changes who stewards. An ungoverned path resolves to nothing — a fact, not an error.

A steward-agent carries a standing constraint set — the constraints stated during PRD / scoping / design, each authored as a permanent subtype:'constraint' Anchor attached to the steward (emerik anchor author --subtype constraint --steward <who>). The design process is the steward-agent's training signal: the set evolves append-only as constraints accrue, retrievable in accrual order via emerik steward constraints <steward> (MCP steward_constraints). The review skill retrieves and applies a domain's constraint set when it reviews a change there.

The antibody loop —

A code-review rejection (or a recurring failure / gotcha) mints an antibody: a durable subtype:'antibody' constraint-Anchor attached to the domain steward, so every future agent there inherits the learned constraint — "never make the same mistake twice." An antibody is learned memory, not a current error — it carries the violet marker (never enforcement red) and its enforcement level. The bless gate (threshold drafted, OQ-8): a high-impact antibody — one at block enforcement, which could fail CI for every agent in the domain — is minted pending; it surfaces but does not bind or gate emerik verify until a human emerik antibody blesses it. A warn / advisory antibody is low-impact and binds on mint. Future agents retrieve a domain's antibodies with emerik antibody list <steward> (MCP antibody_list).

A false antibody must not permanently bind every future agent, so there are three append-only retirement paths (no in-place delete, AR-14). Retractemerik antibody retract <id> (MCP antibody_retract) writes a Tombstone; the antibody drops from the graph and stops binding. Supersedeemerik antibody mint --supersedes <id> replaces a wrong antibody with a corrected one. Expire — an antibody minted with --expires-at stops binding once its TTL passes. And an antibody-vs-Anchor conflict is steward-declared and resolved by retracting (--conflicts-with <anchorId>) or superseding, leaving one unambiguous live constraint (the rule is drafted, OQ-16). With this, Epic 6 — governance, stewardship & the antibody loop — is complete.

Instrumentation — the rework rate

emerik's whole thesis is that stale context drives rework — rebuilding work already marked "done". emerik metrics rework (MCP metrics_rework) measures it, as a read-only derivation over the .emerik/ decision log — it writes nothing, exactly like emerik history. It is a drafted proxy for SM-1: the share of decision commits whose verb rebuilds (supersede) or retracts (tombstone) an already-recorded fact; every other verb (create, mint, bless, …) is progression. It reports a baseline (the full log) and, with --since, an ongoing window, and carries the ~2% directional target and the rough ~5–10% baseline band in its machine-readable shape so a matched control run is directly comparable. It is honestly a drafted proxy — the effort-weighted measure is future work — not the final SM-1 number.

emerik metrics review-time (MCP metrics_review_time) measures the review funnel per Goal (SM-2), read-only over the Review artifacts + live Goals. It reports two things. (a) The auto-clear rate — the share of changes the agent quorum cleared without a human (routing = "cleared") — is solid from the bytes; a steep rise is the goal. (b) Human-review loadhumanReviews, the count of changes escalated to a human — is a drafted proxy: emerik instruments no per-reviewer timer, so actual reviewer-hours are not available and the report says so verbatim rather than fabricating hours from wall-clock. Both are reported per Goal (with the Goal's completed state), and the counter-metrics still apply — a high auto-clear rate must never be gamed past a genuine blast-radius change (SM-C2, structural in the risk-tiered routing). With this, Epic 8 — instrumentation — is complete.

The decision-log subject grammar (emerik(<type>): <verb> <id>) parses every shipped artifact familypin, anchor, lease, tombstone, goal, dependency, review, and the planning families brief/prd/architecture. So a Goal, Review, Dependency, or planning decision now surfaces typed in emerik history and counts in the rework denominator, rather than landing in unparsed. In particular a steward's adjustment-requested review resolution (emerik(review): adjust <id>) — a change literally sent back for rework, the closest real analogue the substrate has — is classified as rework alongside supersede and tombstone; a bless stays progression. Because these families now parse, the rate's denominator includes their decisions, and a planning supersede (a PRD or architecture revision) counts as rework under the same drafted proxy. Only a genuinely non-grammar .emerik/ commit (e.g. a hand-written chore: note) is still surfaced honestly as unparsed and never counted.

Those planning heads are first-class substrate: a brief, prd, or architecture is authored via emerik brief|prd|architecture author (or the MCP brief_author / prd_author / architecture_author twins) — a durable, append-only record whose prose lives in the committed markdown its --doc-path points at. A revision is a new head with --supersedes (never an in-place edit), so planning history replays, supersedes, and verifies like every other decision; emerik brief|prd|architecture list and status read the live head(s).

A worked example — goal to verified change

The loop opens with emerik-goal: you hand it an intent, and it shapes a Goal brief — Goal statement, testable acceptance criteria, and guardrails that cite the live Pins and Anchors they must honor — committed under .emerik-goals/, then started as a first-class Goal with goal_start --brief and handed to the plan skill. (You can also state a Goal and its acceptance criteria inline to the plan skill; the committed brief, the first-class Goal, or the pasted-in version all work.) From there the loop runs end-to-end:

Goal, stated to emerik-plan
# Goal Add rate-limiting to the login route.
# Acceptance criteria
#  1. Repeated failed logins are throttled.
#  2. Credentials are never written to a log.
01

Plan — grounded in the substrate

emerik-plan calls index_refresh so the plan reflects the latest committed facts, runs graph_retrieve for the Goal and each criterion, and lists live Anchors with anchor_list. A recently-moved Anchor is surfaced as a coordination note (a heads-up, not an alarm). It drafts checkbox steps that cite what they stand on, then commits the plan beside the Goal brief — the durable input to implementation, not chat:

 plan grounded in 3 Pins, 2 Anchors

- [ ] Step 1 — Add a retry counter to the login handler. Relies on Pin
         01J…A7 (login flow). Must honor constraint-Anchor 01J…D9
         "no unbounded retries" (BLOCK). P1.
- [ ] Step 2 — Redact credentials before logging. Relies on Pin 01J…B3
         (logger). Must honor antibody-Anchor 01J…E4 "never log
         credentials" (BLOCK). P0.

# the engineer commits the plan — the harvest hook fires
 .emerik-goals/rate-limit-login-plan.md

A step that cites no Pin or Anchor is grounded in raw code, not the substrate — the skill sends it back to the cascade. The committed doc means the next session (or a cheaper model) resumes from the first unchecked box — no need to keep this window open.

02

Implement — test-first, lease-guarded, verify-gated

emerik-implement picks up the first unchecked step from the committed plan doc (via goal_status — a fresh session needs nothing else), claims a Lease on the territory before writing, then writes the failing test first and watches it fail — implementing to green (red-green-refactor) only once the test proves the behavior is missing. It commits with the step's checkbox flipped (the post-commit hook harvests the new Pins for you — you never hand-craft them), runs emerik verify, and releases the Lease. The step is done only when the new tests exist and pass and verify is green — never on claimed-but-unrun tests.

next step: - [ ] Step 1 — Add a retry counter …   (.emerik-goals/rate-limit-login-plan.md)

▣ LEASED  auth/login · holder plan-agent · expires in 15m

# … edit, flip the box to [x], then commit — the harvest hook fires automatically …

$ emerik verify
 2 Anchor checks passed · no drift                                 exit 0

 released auth/login
Exact lexicon

The skills keep the vocabulary precise — Pin, Anchor, Goal, Lease, Steward, Antibody, Glacier; enforcement block / warn / advisory; priority P0/P1/P2 — and always write the product name emerik lowercase.

Continuous integration

emerik verify is the gate. It exits 1 when any block-level Anchor check fails, so it drops straight into CI as a required step.

.github/workflows/ci.yml
- name: emerik verify
  run: |
    pnpm install --frozen-lockfile
    pnpm build
    ./bin/run.js verify        # fails the job on drift (exit 1)

The pre-push hook installed by emerik init re-derives Pin freshness before a push; pair it with the CI gate above for defence in depth.

Conventions

  • Command grammar is emerik <noun> <verb>; flags are kebab-case; the global flags --json, --quiet, and --no-color work everywhere.
  • JSON is camelCase everywhere — artifacts, --json output, and any future MCP surface.
  • IDs are ULIDs; the source content hash lives inside the artifact, never in the filename.
  • Append-only: a change is a new artifact with supersedes; a deletion is a tombstone.
  • --quiet suppresses success output only — failures always print.

Command reference

CommandPurpose
initInitialize emerik in a git repo — store, ignore rules, hooks, and agent wiring (--no-agents to skip).
harvestHarvest source-bound Pins from a commit; re-derive stale ones.
anchor authorAuthor a steward Anchor, or promote a reviewed Pin (--territory/--holder gate the write on the live Leases — a territory held by another refuses it).
anchor listInventory Anchors with lineage.
verifyRun Anchor checks + convention lint — the CI gate.
retrieveResolve a query cost-tiered: hot Pins → Anchors → raw code.
index rebuild · refresh · statusManage the local semantic index.
glacier freeze · thaw · listArchive cold Pins losslessly; bring them back.
goal start · advance · status · listThe concurrent work-unit — one active Goal per team against the shared graph; start takes --priority (P0/P1/P2, default P1) and flags recently-changed depended-on contracts as coordination events.
dependency declare · status · listContract-dependency on a published Anchor; notified when the contract changes.
lease claim · renew · release · listExclusive-write territory leases via git-ref CAS.
trail statusRead the stigmergic trail — hot zones + lease markers — to route around, no messaging (--remote, --limit).
review [domain]Open the batched review digest (the one v1 TUI screen) — boilerplate collapses to one faint row, only escalated changes surface; an optional domain scopes it. Keyboard-only; non-TTY / --json print the static digest / model.
review open · listRecord + route an agent-quorum review — cleared by quorum, or escalated to a human when it edits a high-dependent Anchor (--anchor, --verdict, --domain, --routing filter on list).
review bless · adjustResolve an escalated review through code — bless clears it on the steward's authority, adjust sends it back; each mints a superseding decision Review (--note, --by).
steward resolveResolve stewardship for a code path — the governing Anchor(s) + accountable steward, most-specific first (inverted CODEOWNERS, FR-17).
steward constraintsList a steward-agent's standing constraint set — its constraint-Anchors in accrual order (FR-18).
antibody mint · bless · list · retractThe antibody loop (FR-19) — mint a constraint learned from a failure (--supersedes/--expires-at), bless a pending high-impact one (OQ-8), list a domain's antibodies, retract a false one (a Tombstone, AR-14).
metrics reworkReport the drift-driven rework rate (FR-26) — a read-only, drafted SM-1 proxy over the decision log; a baseline plus an optional --since ongoing window.
metrics review-timeReport the review funnel per Goal (FR-26, SM-2) — the agent-quorum auto-clear rate + a drafted human-review-load proxy (reviewer-hours are not instrumented). Read-only.
brief author · list · statusThe native planning head for a product brief (FR-33) — author commits a durable, append-only brief (--title, --doc-path the committed markdown body, --steward, --supersedes to revise the live one); list the live briefs (--all includes superseded history); status the live head(s).
prd author · list · statusThe native planning head for a PRD (FR-33) — same append-only grammar as brief: author (--supersedes revises), list (--all), status.
architecture author · list · statusThe native planning head for a solution/architecture design (FR-33) — same append-only grammar: author (--supersedes revises), list (--all), status.
seed --analyze · seedCold-start a brownfield repo into the graph.
historyReplay the decision log or an artifact's lineage.
compactGC superseded Pins; keep the latest fact.
rollupDistil a domain's history into a narrative rollup.
mcpStart the stdio MCP server exposing the substrate as agent tools.

Every command supports --help. Run emerik <command> --help for the full flag list.