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.
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.
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.
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."
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.
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.
agent/<vendor>-<surface>/<topic>, e.g. agent/claude-cowork/fleet-registry.main on a PROD-IT repo.git push --force or --force-with-lease on a shared branch. Ever.git pull --rebase before pushing. If the push is rejected, stop and report — donot resolve someone else's concurrent work by overwriting it.
D:\gh\ship.py. It is lane-aware, dry-run by default, and commits only its own 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.
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."
The live lease holder wins. Always. No negotiation, no waiting.
The agent without the lease:
directive rates verification loops a defect.
GET /api/1099/board?free=1 or ./scripts/agent.sh claim next.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.
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.
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:
| Step | What | Where | Effort |
|---|---|---|---|
| 1 | Publish rules 1–4 in both directives | hi.jbnx.io, hi.fedm8.com | small — text |
| 2 | Copy-paste block for every chat's first turn | human-side, no deploy | none |
| 3 | .agent-lock.json read/write in agent.sh claim and release | projects-portal/scripts/agent.sh | small |
| 4 | ship.py refuses to commit when the lock names a live foreign actor | D:\gh\ship.py | small |
| 5 | Portal rejects a claim whose handle lacks a session suffix | projects-portal API | medium |
| 6 | Portal warns when one handle claims from two source IPs inside a lease | projects-portal API | medium — 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.
with HELD by …. Verified working 2026-08-12.
succeed. This is Gap 1. After step 6, the second is refused or flagged.
held before writing → slug absent → it stops..agent-lock.json in a repo; agent B tries to edit that repo → B readsthe lock, sees a live foreign actor, and stops.
ship.py invoked while a foreign live lock is present → refuses to commit.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.
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.
| Surface | Put it in |
|---|---|
| Claude Code / Cowork | CLAUDE.md at repo root |
| Cursor | .cursorrules or Project Rules |
| Codex / OpenAI agents | AGENTS.md at repo root |
| Gemini | project system instruction |
| Scheduled tasks | already 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-os → ownership.doctrine_boot). Putting the block in the first two means most agents pick it up without being told.
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.
hi.jbnx.ioWhere: 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 heldmust 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:\ghis one checkout shared by every local chat, and the portal lease cannot see the filesystem. On claim, write.agent-lock.jsonat the repo root with actor, slug,expires_atand 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 tomainon a PROD-IT repo — a push there is a production deploy. Nevergit push --forceon a shared branch.git pull --rebasebefore 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'sbootbrief. 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.jsonnames a live foreign actor. - Force-push, or resolve a rejected push by overwriting concurrent work. - Wait-loop or retry against a slug that isHELD— take other work or stop.
hi.fedm8.comWhere: 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 onprojects.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 slugfedm8before touching anything, re-checkheldbefore you write and before you push, respect.agent-lock.json, branch and never force-push, and onHELDtake other work rather than waiting.
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."