My Claudes Have a Group Chat Now

My Claudes Have a Group Chat Now
claudes-group-chat.html

My Claudes Have a Group Chat Now

…so they stop rebooting the server under each other.

$ tail -3 BOARD.md

This showed up in a text file on my desktop (trimmed, names changed):

15:10host-maintABOUT TO restart Docker on Server-1 in ~10 min. Holding @host/server-1. Object here if that hurts you.
15:17host-maintREBOOTING Server-1 NOW. Holding @host/server-1.
15:20host-maintDONE. Back at 15:19, all containers up. Checks ALL PASS. Released @host/server-1.

That isn’t me. An AI session wrote that, to the other AI sessions: the ones in terminals it can’t see, who might have been in the middle of something on that server.

You’d never let two engineers reboot the same server without saying something in Slack. So why do you let two AIs?

Just want it? Jump to the setup prompt: one copy-paste, and your Claude builds it and proves it works.

$ ps aux | grep claude

Four terminals, zero awareness

A confession first. I don’t run one Claude Code session. I run four. Sometimes six. One is fixing the blog theme, one is adding health checks, one is working on a side project, one is cleaning up docs. Each is its own terminal, its own conversation, its own little world.

They cannot see each other. Not at all. Session A has no idea session B exists, let alone that B is halfway through a deploy to the server A is about to restart.

Quick word on terms, because Claude Code people will notice: these are separate sessions, sibling terminals. Subagents, the helpers one session spawns, can use the same trick, but at least they have a parent watching. Sibling sessions have nobody. That’s where this earns its keep.

One AI session is a tool. Two at once is a team. And a team without a whiteboard is a hazard.

So I gave them a whiteboard. Since I turned it on, about twenty sessions have posted dozens of messages on it. Here’s what it buys you.


$ diff without/ with/

What it buys you

Without itWith it
Two sessions edit the same file. The last save wins. The first one’s work silently vanishes.The second session asks for the file and gets REFUSED: held by site-header-fix for 3m. It waits, or works on something else.
A session reboots a shared server in the middle of another session’s deploy.It claims the server, posts ABOUT TO, does the thing, posts DONE, lets go.
Session A needs something from session B. B’s terminal closed an hour ago. The request dies in scrollback.ask puts it on the board, and it stays open until someone answers it (DONE or DECLINED). It outlives the session that was asked.
You have no idea what your four terminals are doing right now.One text file. Who holds what, who said what, when. You can read it in any editor.
Why a text file and not a database, an MCP server or a message queue? Every Claude can already read a file and append to it. You can read it too. There is nothing to install, run, patch or back up. The locks use mkdir, because creating a folder is atomic on one disk: you either made it or you didn’t. No race, no server, no dependency.

$ ./do-i-need-this.sh

Do you need this?

Thirty seconds. Two or more yeses and you need this.

  • Do you ever have two Claude Code terminals open at once?
  • Do they ever touch the same repo, server, DNS, monitoring or CMS?
  • Have you come back to a file and thought “I didn’t write that”? You didn’t. The other one did.
  • Do you hand work from one session to the next (“pick up where the last one left off”)?
  • Is there something shared and fragile in your setup: one network config, one theme, one shared server?

The cost: one shell script and one markdown file. Free. Your Claude writes the script. You don’t.


$ grep -i “oops” BOARD.md

Greatest hits

Every one of these is real. Some happened live; two were bugs an audit caught before they bit anyone. Most became a rule.

Three Claudes, one lock, all confident. An audit had three test sessions claim the same file under three spellings: a short relative path, the full path, and just the bare filename. Three successful claims. Zero conflicts detected. Any one of them would have edited away, sure it had the file to itself. Fix: every path gets rewritten to one spelling before the lock is checked.

The note nobody answered. The session that ran that audit posted both bugs to the session that owns the tool’s wrapper. That session kept working and never replied. The bug reports just sat there until a review of the board turned them up and another session fixed both. So now there’s ask and reply: an ask stays open on the board until somebody answers it, whoever is still around.

Shouting into a closet. The same audit linked the tool into a PATH folder. It looked for “the board” next to itself, found the link’s folder instead of the real one, and cheerfully posted to a private file nobody else would ever read. Fix: find the tool’s real location before doing anything.

“Is it dead, or just between turns?” A session saw another’s claim, checked the process ID, found it dead, and decided that session was finished. It took the claim. The “dead” session came back and committed its own work to those files. Nothing was lost, but only because it committed by file name. An AI that’s waiting for your reply has no process running. It looks exactly like one that’s gone. Fix: only the claim’s age counts, and taking a fresh claim needs the human.

“REFUSED” … exit code 0. Trying to release someone else’s claim printed REFUSED, then returned success. Any script checking the exit code thought it worked. One session found it, a second confirmed it, and a third, the one that owns the underlying script, fixed it. The AIs filed a bug report on the AIs’ tool, and the AIs fixed it.

The generic deploy script. Have more than one site and a script called deploy.sh? Sooner or later a session runs it meaning site A and ships site B. It happened here, and the rule came out of it: every deploy script names its site. deploy_site_a.sh, never deploy.sh.

The public correction. “CORRECTION to my 15:37 post: those commits were NOT already in HEAD. My check counted diff lines with a pattern that skips edited markdown bullets.” Nobody asked. The board just made a quiet mistake loud, which is exactly what you want from a mistake.

“Object here if that hurts you.” The polite heads-up from the opening. Lovely manners. Nobody answered. It rebooted anyway, with my OK, and that day it was fine. The catch: it only works if somebody’s reading. More on that below.

None of these were dumb AI mistakes. They’re the exact mistakes two humans make without a whiteboard. That’s the point.


$ cat HOWTO.md

How it works: five habits

Name yourself

Every command starts with COORD_SESSION=site-header-fix.

// an unnamed claim is worse than no claim

Look first

coord.sh status shows who holds what, open asks, and the last few posts.

Call dibs

coord.sh claim @dashboards --why "adding a check". A second claimant gets REFUSED and the holder’s name.

Say it out loud

ABOUT TO before anything risky, DONE after.

// ~300 characters and a pointer, not a diary

Let go

coord.sh release @dashboards, and post “Released.”

A claim doesn’t have to be a file. Anything shared gets an @name:

ClaimMeans
@host/server-1that server: reboots, upgrades, container restarts
@dashboardsthe status dashboards and their checks
@dnsDNS records
@site/themethe site theme
@site/menuthe site menu, which several pages share
It’s advisory, on purpose. Nothing physically stops a session that skips it. The habit is the control, just like a team’s whiteboard. That’s also its weakness, and I’ll get to that.

$ claude < setup-prompt.txt

Make your Claudes do it

You don’t need my script, and you’re not getting it. It’s shaped around my folders. Instead, paste this into Claude Code in the folder where your sessions work. Your Claude builds the tool, the board and the CLAUDE.md rules for your setup, then proves they work.

It will stop first and show you a list of the shared things in your project. Fix the list, say yes, and it builds.

> setup prompt: paste into Claude Code
I run several Claude Code sessions at the same time, and they sometimes change the same files or servers.
Build a small coordination system so they don't step on each other.

STEP 1 — before writing any file: list the shared things in this project that sessions should claim
(servers, databases, DNS, deploy configs, CMS, shared docs — only what actually exists here). Then STOP and
ask me to confirm the list.

STEP 2 — after I confirm, build this:

1. A bash script `coord.sh` (bash, coreutils, grep, sed and awk; nothing else). It keeps its state in `.coord/`
   and its board in `BOARD.md`, both next to the script. Commands:
   - `claim <name>... [--why "text"]` — an advisory lock made with `mkdir` (atomic) under `.coord/claims/`.
     If another session holds it, refuse, print who holds it and for how long, and exit 1. Several names are
     all-or-nothing: if one is held, take none.
   - `release <name>...` — only the holder can release. Anyone else, or an unclaimed name, exits 1.
   - `say "message"` — append one line to BOARD.md:  - **YYYY-MM-DD HH:MM:SS** · `<session>` — <message>
     Timestamps must be unique on the board (wait a second if needed): an ask's timestamp is its ID.
   - `ask <session-or-prefix-*> "message"` — a say whose message is "ASK → <target>: message". It stays OPEN
     until a post whose message BEGINS "DONE re <its timestamp>" or "DECLINED re <its timestamp>".
   - `reply "<timestamp>" DONE|ACK|DECLINED "message"` — posts "<KIND> re <timestamp> — message". Refuse if no
     ASK has that timestamp. ACK means "seen, working on it" and keeps the ask open.
   - `asks [session]` — open asks addressed to that session (prefix-* targets match).
   - `takeover <name> --human-ok "<my exact words>"` — take a claim someone else holds; it records my words
     on the board. Sessions may use it only after I say yes in chat.
   - `status` — claims held (with age; anything over 90 minutes is flagged STALE), open asks, last 8 posts.
   The session name comes from the COORD_SESSION environment variable; claiming or posting without it fails.
2. Names starting with @ (like @prod-db or @dns) are shared resources, compared exactly as typed. Every other
   name is a file path, even if the file doesn't exist yet: resolve symlinks, `..` and the current folder,
   then store it relative to the folder holding coord.sh, so two spellings of one file are the same claim.
3. A STALE claim is never released automatically and still blocks others.
4. Never delete board history. After each post, if BOARD.md is over 150,000 bytes, move posts from past
   months into archive/BOARD-YYYY-MM.md. Count posts before and after; if the counts differ, change nothing.
   `asks` and `reply` must search the archive too.
5. Add a short "Coordination" section to CLAUDE.md telling every session to: pick a COORD_SESSION name;
   run status at the start of every task; claim before changing anything on the confirmed list; post
   ABOUT TO before risky changes and DONE + "Released" after; use ask for anything it needs from another
   session; keep posts under ~300 characters. Put COORD_SESSION=<name> in front of every command (each Bash
   call is a fresh shell, so export doesn't stick). Include the confirmed list.
6. Write a test script that runs in a temporary folder and leaves nothing behind in the project. Prove:
   second claim refused, non-holder can't release, two spellings of one file collide, an ask stays open
   after ACK and closes on DONE, archiving loses no posts, and 20 sessions racing for one claim produce
   exactly one winner. Pair every "X is gone" test with a check that proves the test can see X when it is
   there; a test that can't fail proves nothing. Run it and show me the output. Don't call it done until
   every test passes.

Nothing is sent anywhere: the button only copies the text above.

I tested this prompt like code. A fresh Claude session got an earlier version in a fake project it had never seen (I answered its shared-list question in advance). It built a system that passed its own 41 tests, but it had to guess at about twenty points. So I tightened the prompt and handed this version to a second fresh session in a different fake project. That one stopped and asked about the shared list before writing a single file, then built a system with 69 passing tests. Twenty sessions racing for the same claim produced exactly one winner, every time: my main Claude session ran that race against the first build by hand, and the second build’s own tests ran it three times. My main session also re-ran both builders’ test suites, plus checks of its own, instead of taking their word for it.

Then the fun part. Both builds hit the same hidden bug on their first test run, and fixed it before they finished. The pattern that finds posts on the board silently matched nothing, so open asks and archiving were quietly dead. Both times, what caught it was a test that checks a thing is there. And both times, the test that only checked “the ask is closed” passed on the broken code, because nothing was found, so nothing was open. The first build’s report is why this version of the prompt makes it a rule: check that a thing is there before you check that it’s gone. The second build is the proof that the rule earns its place.

A test that can’t fail proves nothing. That line is in the prompt for a reason.

Would rather wire it by hand? This is the part that goes in CLAUDE.md:

## Coordination (other Claude sessions work here too)
- Name yourself: put `COORD_SESSION=<area>-<task>` in front of EVERY coord.sh call.
- Start of every task: `coord.sh status`. Claim before changing anything shared; release right after.
- Risky change? Post `ABOUT TO …` first, `DONE … Released` after. Need something? `coord.sh ask <session> "…"`.
- A REFUSED claim means wait or ask. Never take a claim that isn't yours without the human's OK.

$ cat KNOWN_ISSUES.md

Honest limits

Because you’ll hit them.

  • It only works when a session looks. The board is pull-only. “Object here if that hurts you” reaches nobody unless the other session runs status. The next step I’m planning is a hook that blocks the dangerous commands unless the session running them holds the claim. Move the control to where the harm happens.
  • One machine. mkdir locks are atomic on one disk. Across machines, shared folders lag. Post first, then wait for it to arrive before acting.
  • macOS needs a tweak. The test builds used realpath -m, a GNU option the Mac version doesn’t have. Tell your Claude to use something that works there, or install GNU coreutils.
  • I don’t know yet how often it actually saved me. So it logs every refused claim. That’s how I’ll find out whether it prevents real collisions, instead of assuming it does.

My Claudes didn’t need to be smarter. They needed a whiteboard.


So did every team I’ve ever been on.

Similar Posts

Leave a Reply