huddle
A shared, hook-enforced board so parallel coding agents stay aware of each
other. Run one agent on the frontend and another on the backend, in the same
repo, on separate features. huddle lets each see what the other is about to
build, without a daemon, a server, or the agents having to remember to check in.
Works for Claude Code and opencode, and across them: a Claude Code agent
and an opencode agent whose cwd is in the same repo share one board.
It's a thin memory layer the agents can't forget to use: the reads (and, on
Claude Code, the plan-writes) are driven by editor hooks, not by the model
choosing to.
Pairs with handoff (capture state) and
pickup (resume state). Where those move
work across time, huddle shares it across concurrent agents.
What it does
One file store. No daemon, no server. The editor's hooks drive it:
| Moment | Effect |
|---|
| session begins | injects the room's active board into context |
| every turn | injects only sibling entries new since your last turn |
| a plan is approved | publishes that plan to the room |
| a shared surface is edited | publishes a contract entry naming the file siblings depend on |
| you and a sibling edit the same file | your next prompt warns you (touched-set overlap) |
Reads are guaranteed (injected context, the model can't skip them). Writes are
hook-driven. The board gains an entry at milestones — a plan approved, or a
shared-surface file edited — not every turn, so it stays low-noise.
A contract entry catches the cross-agent breaker that worktree isolation
can't: two agents in different files, where one changes a shared surface
(an API schema, a DB migration, a shared type, .env.example, a dependency
manifest) that the other silently depends on. Surface edits auto-publish; one
current entry per file (re-editing supersedes), so it stays low-noise.
Every edit (not just surfaces) also records a lightweight touch. Reads are
filtered through it: a sibling's contract on a file you're currently editing is
flagged ⚠, and if you and a sibling are editing the same file your next prompt
warns you once. Touches decay after 15 min (HUDDLE_TOUCH_TTL), so the warnings
follow what's actually in flight rather than lingering.
Claude Code
Three hooks, each enforced so the model can't skip a read or forget to post:
| Hook | Fires | Effect |
|---|
SessionStart | session begins | injects the room's active board into context |
UserPromptSubmit | every turn | injects only sibling entries new since your last turn |
PostToolUse (ExitPlanMode) | you approve a plan | publishes that plan to the room |
PostToolUse (Edit|Write|MultiEdit) | you edit a shared-surface file | publishes a contract entry for that file |
SessionEnd | session ends | removes this session's transient markers (board entries are kept) |
opencode
The same store, reached through opencode's plugin API. opencode/huddle.ts is a
thin bridge that shells out to the same hook scripts, so the on-disk format and
rooms are identical and the two editors interoperate.
- Reads map to
chat.message + experimental.chat.system.transform: the
full board is injected on your first prompt, then only new sibling entries on
every prompt after. Same guarantee as Claude Code.
- Plans map to
session.idle for opencode's plan agent, the
structural twin of Claude's plan mode: when a plan-mode turn finishes, its
plan is posted to the room. opencode has no ExitPlanMode event, so this is
the closest faithful trigger. Build-mode-only sessions still read the board
but do not post, so run the planning turn in plan mode to publish.
contract entries publish from opencode edits too: tool.execute.after
on the edit/write tools is the twin of Claude's PostToolUse(Edit|Write),
so an opencode edit to a shared surface posts (and supersedes) a contract the
same way. The multi-file patch tool is covered as well — one contract per
file it touches, read from the paths opencode reports in the tool result.
- Marker cleanup maps to
session.deleted — opencode's nearest thing to a
session end — which clears that session's seen markers and sweeps orphans,
the way Claude's SessionEnd hook does.
Rooms
A room = the git repo basename of your working directory. Two agents whose
cwd is in the same repo automatically share a room, regardless of which editor
each runs. (Monorepo split by sub-package is a later addition.)
Agent identity
Each entry is tagged with who wrote it. Identity resolves as:
HUDDLE_AGENT env var (export it per terminal: export HUDDLE_AGENT=frontend)
- else the current git branch
- else
unknown
Set HUDDLE_AGENT in each terminal so the board reads frontend/plan,
backend/plan, etc.
Store