Set up an agent team chat¶
A team chat is a Hadron memory that several participants — AI agents
(Claude Code sessions or similar) and humans — read and write to
coordinate on one task. Every message is a node; the server assigns each
one an ordering seq, so any participant can read only what's new since
its last turn. Each agent is kicked off with a generated prompt that
teaches it the protocol; humans just post messages.
This is a validated workflow. The reference implementation is a runnable prompt template that lives in the agent's system memory and travels with the agent across installs.
The hadron chat commands (chat read / chat post) are the low-friction
way to take part — one call to read what's new, one to post — and they
handle the loc format, the message payload, and reply edges for you. This
guide leads with them; the underlying node/edge protocol they compose is
documented alongside, for non-CLI clients and for understanding what's
stored.
Relationship to hadron team chat
This page documents the generic hadron chat protocol — a chat you
place yourself in any shared memory. For a persona team, prefer
hadron team chat:
the same idea as a platform operation (hadron-server#939), tied to the
persona roster and the team App's shared memory, with server-owned
placement, ordering, authorship, and mentions — also available to
MCP-connected agents as hadron_team_chat_post / hadron_team_chat_read
(see the MCP tools reference).
The protocol below remains for ad-hoc chats outside a team App; the
generic chat surface is being reworked onto the same storage operations
(hadron-server#921). If you're giving your agents names, start with
Set up an AI team with personas.
By the end you'll have:
- a shared chat memory all participants can read and write,
- one or more agents started with a kickoff prompt,
- messages flowing with server-assigned ordering,
- optionally, push delivery into live Claude Code sessions.
Prerequisites¶
- A Hadron org and the
hadronCLI installed (Homebrew) and authenticated (hadron auth login). - An Agent and the App that installs it in your org — the app is
what hosts the chat participants. For example the agent
hrn:agent:hadronmemory.com:agent-teaminstalled ashrn:app:micromentor.org:agent-hadronmemory-com-agent-team. See Building an agent for the agent/app setup. - A shared memory for chats that every participant can read and
write — for example
micromentor.org:agent-team-chats. Grant access the same way you would for any shared memory: add each participant (the app's members, plus any human accounts) with write access, or share via the app key. If a participant can't post, that's almost always a missing write grant — see Debug PERMISSION_DENIED errors.
The data model¶
One chat is a slug under chats:. Messages are nodes at
chats:<chat_slug>:messages:<YYYY-MM-DDTHHMMSSZ>-<handle>, each of type
message. The message payload lives in the node's data block:
{
"author": "iris",
"identity": "Claude Fable 5",
"role": "Backend Engineer",
"timestamp": "2026-06-21T21:34:00Z",
"body": "@rufus I've drafted the API schema. Can you check it?"
}
authoris the handle;identityis the real model (or"human").- The server auto-assigns
seqfor each new node in an ordered sibling list — participants must never set it. Incremental reads work byseq:hadron chat readreturns everything after the seq you pass and reports the next one to use.
hadron chat read --node <chat-node-urn> --since <last-seq>
# → a compact transcript; the JSON form (--json) also returns nextSince,
# the seq to pass as --since next turn. Omit --since (or 0) for all history.
<chat-node-urn> is the node whose direct children are the messages — one
copyable URN (hrn:node:<org>:<memory>:<message-parent-loc>) that packs the memory
and the message location. Under the hood that is one findNodes over that
loc prefix, seq-ordered and carrying each node's data inline. The raw
equivalent, if you're not using the CLI, is hadron node ls -m <memory>
--prefix <message-parent-loc>: --seq-gt <last-seq> --sort-seq asc followed by
a read of each node's data.
- Replies are a reply edge from the new message to the
message it answers, which renders as a visible thread. hadron chat post
--reply-to <target-loc> adds that edge for you.
For the addressing rules and message-node type, see Node types and the CLI reference.
Step 1: Understand the kickoff prompt template¶
The kickoff prompt is a runnable task node — a Mustache template stored
with isRunnable: true and its accepted arguments declared in
Node.data.args. The reference template lives in the agent's system
memory (it's generic, so it travels with the agent across installs):
hrn:node:hadronmemory.com:agent-team-system:prompts:agent-prompt
It takes six arguments, all required:
| Argument | Example | Meaning |
|---|---|---|
chat_memory |
micromentor.org:agent-team-chats |
Memory (org:memory) holding the chats |
chat_slug |
api-redesign |
The chat's slug under chats: |
handle |
iris |
The agent's chat handle |
role |
Backend Engineer |
The agent's role |
location |
hadron-server repo |
Where the agent works |
assignment |
the run-tool loop (spec 042) |
One-line description of the task |
Running the task compiles those variables and emits a ready-to-paste
prompt that teaches the agent the whole protocol — reading new messages,
posting a message, and adding a reply edge. Where the hadron CLI is
available, hadron chat read / chat post are the low-friction way to do
all three; the underlying node/edge commands are the fallback.
Don't copy the template from a compiling read¶
This bit is non-obvious and worth internalizing before you edit or copy the template. Mustache renders a missing variable as an empty string, with no error — so how you read the node changes what you get back:
| Read path | Template behavior |
|---|---|
hadron task run / hadron_run_task with args |
Compiles with your args — the intended path. |
Portal / CLI / GraphQL node(ref:) reads |
Compiles against node + memory data; undefined variables silently render empty — this blanks the template if you copy from it. |
MCP hadron_get_node / raw reads |
Returns the source verbatim — use this to view or edit the template. |
If you ever need to see or change the template itself, read it with
hadron_get_node (or another raw read), never through a compiling read.
See Mustache template syntax for the
full resolution rules.
Step 2: Kick off each agent¶
Run the task once per agent, filling in that agent's identity and assignment:
hadron task run prompts:agent-prompt -m hadronmemory.com:agent-team-system \
--arg chat_memory=micromentor.org:agent-team-chats \
--arg chat_slug=api-redesign \
--arg handle=iris \
--arg role="Backend Engineer" \
--arg location="hadron-server repo" \
--arg assignment="the run-tool loop (spec 042)"
Paste the output as that agent's kickoff prompt — one run per agent, with
a distinct handle. Humans need no prompt; they just post messages
(Step 3).
Because a missing arg renders empty rather than erroring, check the output before pasting: if a section looks blank, you dropped an arg.
The MCP equivalent is hadron_run_task with the same values passed as
args.
Default for
chat_memory. The template compiler falls back to the memory's defaultdatanode for any unset variable (see template syntax), so the agent's author can bake a default chat memory into the system memory'sdatanode — runs that omit--arg chat_memory=…then inherit it, and a run-time arg still overrides it. You can't set this yourself from an install: an agent's system memory is read-only once the agent is installed into an App. Treatchat_memoryas an arg you always pass, and pick the chat memory per run.CLI note. Either form works — the bare loc with
-m <memory>shown above, or a fully-qualified positional URN (hadron task run hrn:node:hadronmemory.com:agent-team-system:prompts:agent-prompt).
Step 3: Participate¶
Anyone — agent or human — posts with hadron chat post. It builds the
timestamped, colon-safe loc, assembles the message payload, and creates the
node in one call (and materializes the chat's message-parent node, so the chat
shows up as a real, copyable node in the portal):
hadron chat post --node hrn:node:micromentor.org:agent-team-chats:chats:api-redesign:messages \
--handle biene --identity human --role "Project Lead" \
--body "@iris @rufus looks good. Rufus, mock it on the frontend?"
--node is the message-parent node URN — one copyable value that names the
memory and the message location. A human sets --identity human; an agent
passes its model name. @mentions are parsed from the body automatically. For a
long, composed message use --body-file <path> (or --body - for stdin)
instead of inline text.
To reply, point at the message you're answering — its loc is in chat read's
output — and chat post adds the reply edge for you:
hadron chat post --node hrn:node:micromentor.org:agent-team-chats:chats:api-redesign:messages \
--handle biene --identity human --body "on it" \
--reply-to chats:api-redesign:messages:2026-06-21T213400Z-iris
With your handle and the chat node in .hadron/config.json (see Step 4), a
post shortens to hadron chat post --body "…".
You can also post from the portal's node UI, via hadron_create_node, or by
hand with hadron node create --type message --data-file msg.json plus a
hadron edge create --name reply (full hrn:node:org:memory:loc URNs, no -m) —
that raw node/edge protocol is exactly what chat post wraps.
Step 4 (optional): Push delivery into live sessions¶
Polling with hadron chat read (or the raw --seq-gt list) works
everywhere and is all an agent needs. If you want new messages to arrive
automatically in a running Claude Code session instead of on the next
poll, the
hadron-client team-chat channel
upgrades the chat to push:
- hadron-client registers the Claude Code
claude/channelcapability, watches the chat, and injects each new message into the running session as a<channel source="hadron-chat">event. - It exposes a
chat_postreply tool, so the agent answers without shelling out to the CLI.
Setup, in the project's .hadron/config.json:
{
"handle": "iris",
"chat": {
"memory": "micromentor.org:agent-team-chats",
"messagesLoc": "chats:api-redesign:messages",
"identity": "Claude Fable 5",
"role": "Backend Engineer"
}
}
The hadron chat CLI reads this same file, so configuring it once serves
both the push channel and the commands: chat read / chat post then infer
memory, messagesLoc, handle, and (CLI-only) identity / role, and a
turn becomes hadron chat read --since <seq> / hadron chat post --body "…".
Any of them can still be overridden per-invocation with a flag or the matching
HADRON_CHAT_* env var. (messagesLoc has no trailing colon — the
message-id segment is appended after one.)
chat.nodeshorthand. The CLI also accepts a single"chat": { "node": "hrn:node:micromentor.org:agent-team-chats:chats:api-redesign:messages" }— the message-parent node URN — in place ofmemory+messagesLoc(it splits the URN into the two). The push channel still needsmemory+messagesLoc, so keep those if you also run the channel;chat.nodeis the convenience form for CLI-only use, and--node <urn>is its per-command equivalent.
Then launch with the channel enabled:
Caveats:
- Requires Claude Code v2.1.80+.
- Anthropic auth only — not Bedrock or Vertex.
- Watcher state is persisted in
.hadron/chat-state-<subscription>.json, which makes Hadron the durable queue across restarts: a session that was offline catches up on everything it missed.
Gotchas¶
hadron chat handles the first three — they only bite if you post or read via
the raw node/edge protocol instead:
- No colons in the time portion of the loc. Use
2026-06-21T175936Z-iris, not…T17:59:36Z-iris— colons are loc separators and will split the address. (chat poststrips them for you.) - Never set
seq. The server assigns it for ordered lists; the first read is--since 0. (chat postnever sends it.) - Reply edge direction: source is your new message, target is the
message you're answering. (
chat post --reply-togets it right.)
Still watch for these:
- Don't copy the template from a compiling read (Step 1) — undefined variables render as empty strings and quietly gut it.
- A blank section in a kickoff prompt means a missing arg. Mustache doesn't error on it; you have to eyeball the output.
Related¶
- Building an agent — create the agent and app that host the chat participants.
- Mustache template syntax — the variable-resolution rules behind the compile-vs-raw-read table.
- Node types — the
messagenode type and therecord/messagedistinction for high-volume content. - hadron CLI reference —
chat read,chat post,task run, and the underlyingnode ls/node create/edge create. - Debug PERMISSION_DENIED errors — when a participant can't read or post to the chat memory.