frameworkagent-coordination-protocol-v1 · v11099:cowork-audit-architect2026-08-12served from databaseAll documents

Agent Coordination Protocol v1 — stopping multi-chat, multi-vendor overwrites (proposed 2026-08-12)

JBNX Agent Coordination Protocol (ACP) v1

Status: proposed 2026-08-12, pending CEO approval and directive publication. Problem: multiple chats, across multiple AI vendors, working the same estate at the same time, overwriting each other's work. Applies to: every agent on JBNX and FedM8 work — Claude, Cursor, Gemini, Codex, scheduled tasks, and anything else with a keyboard.


0. What already works — verified live 2026-08-12

The portal lease is enforced server-side, not advisory. A second actor attempting to claim a held slug is refused:

POST /api/1099/claim {"actor":"1099:collision-probe","slug":"automation"}
→ {"error":"HELD by 1099:cowork-audit-architect until 21:54 UTC. Do not start."}

So the coordination primitive exists and it works. Do not build a second one. ACP closes the four gaps around it, and nothing more.


1. The four gaps

Gap 1 — identity collision (the serious one)

A lease is held by an actor handle. Claiming a slug you already hold does not fail — it renews. So two different chats that both sign in as 1099:claude each get a successful claim, each believe they hold an exclusive lease, and both start writing. The server cannot tell them apart, so it cannot protect them from each other.

This is the most likely way work gets lost today, and it gets more likely the more chats run in parallel.

Rule 1 — one handle per chat, never reused.

1099:<vendor>-<surface>-<4 random chars>

Examples: 1099:claude-cowork-k3f9, 1099:cursor-ide-a71c, 1099:gemini-web-9dq2.

Generate the suffix at the start of the chat and keep it for the life of that chat. Never carry a handle from a previous chat. Never use a bare vendor name. If two chats collide on a handle, the estate loses work silently and nothing in the logs will say so.

Gap 2 — the lease is checked at claim time, not at write time

A claim lasts 8 hours. Agents routinely think for longer than they hold. An expired or released lease does not stop a later write, and a long-running chat can be writing hours after its lease lapsed.

Rule 2 — re-verify immediately before writing, and again before pushing.

./scripts/agent.sh held        # must list the slug you are about to touch

If the slug is not listed, or is listed against another actor: stop writing. Re-claim if it is free, or pick different work. Do not "just finish this one file."

Gap 3 — the shared working tree has no lock

D:\gh is one checkout shared by every local chat on the machine. The portal lease lives in Postgres and cannot see the filesystem. Two agents editing the same file in the same tree destroy each other's work before git ever sees it, so none of git's protections apply.

Rule 3 — take the working-tree lock.

On claim, write .agent-lock.json at the repo root:

{
  "actor": "1099:claude-cowork-k3f9",
  "slug": "automation",
  "vendor": "claude",
  "surface": "cowork",
  "claimed_at": "2026-08-12T13:54:55Z",
  "expires_at": "2026-08-12T21:54:55Z",
  "intent": "files or areas this agent will touch"
}

Before the first edit in any repo, read it. If it names a different actor and expires_at is in the future, do not write — that tree is in use. If it is expired, overwrite it and proceed. Delete it on release.

.agent-lock.json is a local coordination file. Add it to .gitignore; it must never be committed.

Gap 4 — no branch discipline

Most of this estate is PROD-IT: a push to main is a production deploy with no gate. Two agents committing to main in a shared tree is a production incident, not a merge conflict.

Rule 4 — branch, never force, never auto-merge.

not resolve someone else's concurrent work by overwriting it.

known paths, so a dirty tree from another agent cannot ride along in your commit. Note git status --porcelain collapses a new untracked directory to .github/ — pass -uall or a path matcher silently skips whole repositories.


2. Declare intent so others can see it

The lease says who holds a project. It does not say what they are changing. One extra call makes concurrent work legible:

./scripts/agent.sh status --state "editing <files/areas>" --next "<what comes after>"

Post it when you start writing and when the target changes. Another agent running boot on that slug sees it in the Compiled Brief. This costs almost nothing and is the difference between "someone is on this project" and "someone is in this file."


3. When you collide

The live lease holder wins. Always. No negotiation, no waiting.

The agent without the lease:

  1. Does not wait-loop, does not poll, does not retry. Polling burns tokens and the

directive rates verification loops a defect.

  1. Takes different work: GET /api/1099/board?free=1 or ./scripts/agent.sh claim next.
  2. Or reports the collision to the human and stops.

If the lease holder is genuinely stuck or gone, the human breaks the tie. An agent never force-takes a live lease from another actor.

Sessions open more than 12 hours are auto-closed and flagged. An abandoned lease is a billing problem as well as a coordination one — an idle open lease inflates a customer's bill.


4. Cross-vendor notes

vendor-specific path and no excuse for skipping the loop. AGENT_API_BASE=https://projects.jbnx.io.

POST. They cannot take the working-tree lock, so they must not be asked to edit the shared tree — they propose diffs a shell-capable agent applies under the lock.

interactive chats. Each scheduled task uses its own handle, e.g. 1099:sched-database-audit.


5. Enforcement ladder

Rules 1, 2 and 4 are behavioural — they work when the directive says them and agents read it. Rule 3 needs a file. The order to implement:

StepWhatWhereEffort
1Publish rules 1–4 in both directiveshi.jbnx.io, hi.fedm8.comsmall — text
2Copy-paste block for every chat's first turnhuman-side, no deploynone
3.agent-lock.json read/write in agent.sh claim and releaseprojects-portal/scripts/agent.shsmall
4ship.py refuses to commit when the lock names a live foreign actorD:\gh\ship.pysmall
5Portal rejects a claim whose handle lacks a session suffixprojects-portal APImedium
6Portal warns when one handle claims from two source IPs inside a leaseprojects-portal APImedium — the real fix for Gap 1

Steps 1–2 remove most of the risk for the cost of text. Steps 5–6 are what make Gap 1 impossible rather than merely discouraged, and should follow once 1–4 have settled.


6. Acceptance tests

  1. Two chats sign in with distinct handles, both claim the same slug → second is refused

with HELD by …. Verified working 2026-08-12.

  1. Two chats sign in with the same handle, both claim the same slug → both currently

succeed. This is Gap 1. After step 6, the second is refused or flagged.

  1. An agent whose lease has expired runs held before writing → slug absent → it stops.
  2. Agent A holds .agent-lock.json in a repo; agent B tries to edit that repo → B reads

the lock, sees a live foreign actor, and stops.

  1. ship.py invoked while a foreign live lock is present → refuses to commit.

The block to paste into every AI and every chat

Paste this as the first message of any chat that will touch JBNX or FedM8 work — Claude, Cursor, Gemini, Codex, anything. It is deliberately short; the directive holds the detail and the agent fetches it itself.


JBNX work. Read https://hi.jbnx.io before anything else and follow it.
(FedM8 product work: also read https://hi.fedm8.com.)

COORDINATION — other AIs are working this estate right now. Do not overwrite them.

1. IDENTITY. Sign in with a handle unique to THIS chat:
   1099:<vendor>-<surface>-<4 random chars>   e.g. 1099:cursor-ide-a71c
   Generate the 4 chars now. Never reuse a handle from another chat — two chats
   sharing a handle both hold the lease and both destroy each other's work.

2. CLAIM BEFORE YOU TOUCH ANYTHING.
   ./scripts/agent.sh sign-in <handle> <model> <vendor>
   ./scripts/agent.sh claim <slug> "what you'll do"
   Refused with "HELD by ..."? Someone else has it. Do NOT wait or retry —
   take other work (./scripts/agent.sh claim next) or tell me and stop.
   Slug names come from GET /api/1099/board — they are not repo folder names.

3. RE-CHECK BEFORE YOU WRITE. Run ./scripts/agent.sh held immediately before your
   first edit and again before any push. If your slug isn't listed, your lease is
   gone — stop writing. Don't "just finish this file."

4. WORKING TREE. Before editing any repo, read .agent-lock.json at its root. If it
   names a different actor with expires_at in the future, that tree is in use —
   stop. Otherwise write it with your actor/slug/expiry, and delete it on release.

5. GIT. Branch agent/<vendor>-<surface>/<topic>. Never commit to main. Never
   force-push. git pull --rebase before pushing; if the push is rejected, STOP and
   tell me — do not overwrite whoever got there first. Use D:\gh\ship.py.

6. SAY WHAT YOU'RE TOUCHING.
   ./scripts/agent.sh status --state "editing <files>" --next "<next step>"

7. CLOSE OUT. usage → status → release. One claim, one billable session, no
   duplicates. Release as soon as you're done — an open lease blocks everyone else
   and inflates the customer's bill.

Report token usage and the token-health band at the end of every reply.

Shorter version, if the above is too long for a system prompt

JBNX work — read https://hi.jbnx.io and follow it. Other AIs are live in this estate.
Sign in with a handle unique to THIS chat (1099:<vendor>-<surface>-<4 random chars>,
never reused). Claim the slug before touching anything; if it says HELD, take other
work rather than waiting. Re-run `agent.sh held` right before your first edit and
before any push — no lease, no writing. Check .agent-lock.json in the repo root first.
Branch, never commit to main, never force-push, stop on a rejected push instead of
overwriting. usage → status → release when done. Report token usage + health band.

Where to put it permanently, so you stop pasting

SurfacePut it in
Claude Code / CoworkCLAUDE.md at repo root
Cursor.cursorrules or Project Rules
Codex / OpenAI agentsAGENTS.md at repo root
Geminiproject system instruction
Scheduled tasksalready in each task's prompt

The estate already treats CLAUDE.md, AGENTS.md and https://hi.jbnx.io as the doctrine boot set (GET /api/1099/ai-osownership.doctrine_boot). Putting the block in the first two means most agents pick it up without being told.


Directive patch — agent coordination section

Proposed 2026-08-12. NOT published. Requires CEO chat approval before it goes live.

Two edits, both text-only. Neither changes behaviour on its own; they make the rules readable by every agent that fetches a directive.


Edit 1 — hi.jbnx.io

Where: new section immediately after Claims + portal updates, before Verify online before you call it done.

How to ship it (per the security-posture skill §4): the directive is stored once, in agent_ops.policy where key = 'project_llm_directive'. public.pf_llm_directive is a view and is not updatable. projects-portal/server.js derives the version, the bundled filename and the marker check from a single DIRECTIVE_VERSION constant.

So: bump DIRECTIVE_VERSION to 37, add sql/directive-v37.md, update the policy row. Then verify all four endpoints agree before calling it done:

for p in / /json /md /txt; do curl -s https://hi.jbnx.io$p | grep -o 'version[^0-9]*[0-9]*' | head -1; done

Section text:

## Coordination — don't overwrite another agent Multiple AIs work this estate at once, from different chats and different vendors. The claim lease is enforced server-side and a second actor is refused. It cannot protect you from a second chat using your own handle — that path renews the lease and both chats write. Handle discipline is the difference between parallel work and lost work. 1. One handle per chat. 1099:<vendor>-<surface>-<4 random chars>1099:cursor-ide-a71c. Generate the suffix at the start of the chat. Never reuse a handle from a previous chat, and never sign in as a bare vendor name. 2. Re-check the lease before you write, and again before you push. ./scripts/agent.sh held must list the slug. A claim lasts 8h and agents think for longer than they hold. No lease, no writing — re-claim or take other work. 3. Take the working-tree lock. D:\gh is one checkout shared by every local chat, and the portal lease cannot see the filesystem. On claim, write .agent-lock.json at the repo root with actor, slug, expires_at and intent. Before your first edit in any repo, read it — a live foreign actor means stop. Delete it on release. Never commit it. 4. Branch. Never force. agent/<vendor>-<surface>/<topic>. Never commit directly to main on a PROD-IT repo — a push there is a production deploy. Never git push --force on a shared branch. git pull --rebase before pushing; a rejected push means stop and report, never overwrite whoever got there first. 5. Say what you're touching. status --state "editing <files>" shows up in the next agent's boot brief. The lease says who holds a project; this says who is in a file. 6. Collisions: the live lease holder wins. No waiting, no polling, no retry loops — that is a verification loop and a defect. Take free work (GET /api/1099/board?free=1) or report and stop. Never force-take a live lease; the human breaks ties. Two chats sharing a handle is the most likely way work gets lost here, and nothing in the logs will say so.

Add to the Don't list:

- Sign in with a handle reused from another chat, or a bare vendor name. - Write to a repo whose .agent-lock.json names a live foreign actor. - Force-push, or resolve a rejected push by overwriting concurrent work. - Wait-loop or retry against a slug that is HELD — take other work or stop.

Edit 2 — hi.fedm8.com

Where: after the claim/billables paragraph.

How to ship it: source lives in hi/ on jbnx/fedm8-scan. FedM8 is a gated-lane project — open a PR, verify on test, present in chat, merge only on chat approval.

Section text:

## Coordination FedM8 claims and billables run on projects.jbnx.io / bill.jbnx.io, so the company coordination rules apply here unchanged — see the Coordination section of hi.jbnx.io. In short: a handle unique to this chat (1099:<vendor>-<surface>-<4 chars>, never reused), claim slug fedm8 before touching anything, re-check held before you write and before you push, respect .agent-lock.json, branch and never force-push, and on HELD take other work rather than waiting.

Also found while drafting — report, not part of this patch

hi.fedm8.com has the version disagreement the posture skill warns about on hi.jbnx.io. The page title reads "FedM8 LLM directive v5" while the inline marker in the body reads "version 2", with changelog text labelled v1.

Same defect class as the /md and /txt mismatch already recorded for hi.jbnx.io: an agent acting on this page cannot tell which version it has. Worth fixing in the same PR as Edit 2 — a directive that cannot state its own version undermines "re-fetch; don't trust a paste."