| name | smalltalk |
|---|---|
| description | The smalltalk message-bus + agent-status layer, driven by the `st` (long form `smalltalk`) CLI. Reach for it whenever you need to COMMUNICATE with another actor on this machine — send or read a message, reply to a `[DING]` poke, orchestrate work, deliver a result, ask a blocker, or check who's around and their status — instead of printing to your own (unattended) terminal. Also covers your lossless-restart working state (context). |
| when_to_use | Use when a task involves talking to another agent or human on the bus (send/reply/ls/read/archive a message), reading or setting agent status, or reading/writing your own restart context. NOT for spawning agents (that is convoy) and NOT for wrapping a terminal session (that is pty). |
What it is. smalltalk is the file-folder message bus + agent-status layer
for humans and agents on this machine. The CLI is st (long form
smalltalk). A message is just a markdown file in <agent>/inbox/; sending
is writing that file. No server, no schema.
When to reach for it. Any time you need to talk to another actor —
deliver a result, ask a blocker, reply to a [DING] poke, check who's around
or a peer's status. Use st, not your own terminal output: your REPL is
unattended, so a message you never send is work that silently halts. (Spawning
agents is convoy; wrapping a session is pty — different tools.)
- Boot ritual — set status, then drain your inbox:
st status $ST_AGENT --set available, thenst message lsand for each filest message read <file>→st message reply <file> -m '<reply>'if a reply is warranted →st message archive <file>. - Reach a peer —
echo 'hi bob' | st message send bob --subject hello(orst message send bob -m 'body'). - See who's around —
st agents --status available; your status —st status --set busy. - Keep restart state —
st context write(rewritenow.mdfrom stdin) /st context append --decision '...' --why '...'.
smalltalk ships Claude Code lifecycle hooks so an agent is a good bus citizen automatically — set them up once when adopting the tool:
- SessionStart — runs the boot ritual (status
available+ inbox drain) on every session boundary (cold start,--resume,/clear,/compact), so a resumed agent never sits silent. - PreCompact — flushes your working state (
context) before a compaction. - StopFailure — surfaces an API-error wedge (rate-limit / auth / billing) to the operator over the bus.
Install with st hooks path — it prints the exact
.claude/settings.local.json block to paste (read-only; never edits your
settings). See the README's "Adopt smalltalk standalone" section for the
copy-pasteable steps. The scripts call st via $ST_BIN, so they work even
when st is not on $PATH.
Sending a message wakes the recipient's whole agent loop — a full turn of reading, reasoning, and acting, on both ends. Communicate what the work needs — a blocker, a question you can't resolve yourself, a decision or closure to hand off, info the recipient must have to act — then stop. Batch related points into one message instead of a flurry. Skip pure acks ("got it" / "thanks"), status with no ask, and anything they already know. A message that needs no action needs no reply — just archive it. The test: would this change what the recipient does? If not, don't send it.
A message is a pointer + the ask, not a container. Never inline bulk content — logs, large output, long docs, diffs. Write it to a file (anywhere the recipient can read) and send the path plus the ask:
# instead of pasting 500 lines of build output into the message body:
mybuild > /tmp/build.log 2>&1
st message send teammate -m 'build failed — full log at /tmp/build.log, error near the bottom (undefined symbol); look when you can.'- Backticks in
-m "..."are shell command-substitution. A double-quoted body containing backticks runs them as a command and mangles the message. Fix: single-quote the body (-m '...'), or pipe it via stdin / a here-doc / a body file. - A scripted send can hang on a blocking stdin. When
-mis omitted the body is read from stdin; a stdin that never reaches EOF (an inherited pipe) blocks forever. Append</dev/nullto any scriptedst message send/replyas cheap insurance. (Current builds add a timeout, but the habit costs nothing.) - Delivery is at-least-once. The ding re-scans your inbox and can re-poke an item you haven't archived. Archive the moment you act on a message — not at the end of the task — or a restart will re-surface (and you may re-do) it.
- Threads stay on the bus. A thread that began from a
[DING]or inbox message is answered only viast message reply— questions, blockers, "I think I'm done", all of it. Your correspondent is your interlocutor, not your REPL.
Run st --help (lists every subcommand with a one-line purpose) and
st <subcommand> --help (usage, every flag, and a concrete example).
st --version prints <semver>+<short-sha>. See LAYOUT.md for the on-disk
data format.