Skip to content

Coord layer

The coord layer was extracted from years of running multiple Claude Code / Cursor / Codex sessions against the same checkout. It solves three failure modes that hit you the moment you run more than one agent at a time:

  1. Commit contamination: Agent A’s unstaged changes get swept into Agent B’s commit
  2. Overlapping edits: both agents edit the same file, and the second write clobbers the first
  3. Submodule-pointer thrash: Agent A bumps a submodule pointer, and Agent B unwittingly folds the wrong bump into a commit

Three primitives on disk, plus hook scripts wired into Claude Code, Cursor, Codex, and git:

  • .harnery/ledgers/v3/: canonical append-only ledger, validating catalog, and immutable control pair
  • .harnery/active/<id>.json: disposable generation-bound caches projected from the ledger
  • .harnery/journal/: operator and peer messages that remain separate from event authority

The hooks fire before an edit lands (claim time) and before a commit lands (commit time), block conflicts, and record structured V3 events. The web UI reads the same validated projection.

The agent sees nothing when nothing’s going wrong. Single-agent runs are indistinguishable from no coord layer at all.

Resumed sessions keep their name; forked ones get a new one

Section titled “Resumed sessions keep their name; forked ones get a new one”

Names are assigned per instance, and the assignment is idempotent, so resuming a session recovers the name it already had. Forking is different. When an adapter branches a conversation to try a second direction, it mints a new conversation id, so the coord layer sees a new session and draws a fresh name from the pool. That is the right outcome, since the branches edit files independently and each needs its own claims.

The relationship itself is recorded, not just tolerated. On Claude Code the branch’s transcript preserves the parent’s message uuids, so Harnery detects the parent, stamps forked_from on the branch’s name-history row, and uses it in two places. Session-start context names the parent (“branched from agent-X’s session…”), because the branch is about to read a transcript full of that exact name asserting a task and file claims that are not its own. And agents identity assume refuses a target that is the caller’s fork ancestor, since a branch trying to become its parent is usually a session misled by its scrollback rather than a deliberate successor; --force-ancestor overrides it when succession is the intent. Adapters with no detectable parent signal fall back to a generic clause stating that any different name in earlier context was inherited. Full rationale: ADR 0057.

One cosmetic seam remains. Adapters usually title a conversation once and never revise it, so a forked chat keeps the parent’s title even though it is now a different agent. Harnery cannot rename it. The first non-empty set-task of any session prints a suggested_session_name, and that is the value to retitle to.

The primitives above are machine-local. When more than one machine shares a repo (two people, or one person on a desktop and a laptop), presence closes the gap: each machine publishes its live sessions to refs/harnery/presence/<machine> on the repo’s own origin (zero config: repo access is the credential), and peers render them in the agents list, status box, and peer tables, labeled @<machine>. An optional end-to-end-encrypted relay upgrades latency from minutes to seconds. Remote peers are advisory: they inform, but they do not grant or block local claim authority. Details: harn presence and decision record 0016.