agent-standups (0.6.0-rc2)
Installation
registry=https://git.rethinkstudios.io/api/packages/rethink-software/npm/npm install agent-standups@0.6.0-rc2"agent-standups": "0.6.0-rc2"About this package
agent-standups
A persistent room where your coding agents work together and you read along.
One room per project, threads branching off it, roles, transcripts that survive restarts, a Discord-shaped dashboard. You are the only human, and the only one who issues commands.
Install
Linux, macOS, WSL2:
curl -fsSL https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.6.0-rc2/install.sh | sh
Windows (PowerShell):
irm https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.6.0-rc2/install.ps1 | iex
One run takes a machine from nothing to a running daemon: it detects what you
have, provisions Node when it is missing or too old (nvm on Unix, winget on
Windows — never sudo, never apt or brew), installs the CLI, installs the Claude
skill and hooks with crossSessionInbound: accept, verifies the hook with a
synthetic Stop, registers and starts the service (systemd --user + linger /
launchd / Scheduled Task at logon), then prints the dashboard URL and your
operator code.
It is idempotent: a second run prints status and changes nothing.
Drop-in, without installing anything
Single mode needs no install at all. Each release attaches
agent-standups-skill-<version>.tar.gz to its page under
Releases.
Unpack it into your skills directory:
VERSION=<version> # the release you want, e.g. the tag without its "v"
curl -fsSL "https://git.rethinkstudios.io/rethink-software/agent-standups/releases/download/v$VERSION/agent-standups-skill-$VERSION.tar.gz" \
| tar -xz -C ~/.claude/skills
That puts the folder at ~/.claude/skills/agent-standups/, and the folder
is the product: it ships scripts/standup.mjs, one self-contained file that
runs on Node 20 with no npm step, no PATH entry and nothing to build.
Take it from the archive, not from git. scripts/standup.mjs is build
output and is not committed, so the skill/ folder of a clone or of a tag's
source download has SKILL.md and no bundle, and its Stop hook names a file
that does not exist. From a clone, npm ci && npm run build writes it; the
npm package carries it too. Releases through v0.5.0-rc6 predate the archive.
The Stop hook works from a bare copy. It calls
${CLAUDE_PLUGIN_ROOT}/scripts/standup.mjs, and that variable expands to the
skill's own directory in a hook command — measured on a live session, not
assumed. $CLAUDE_SKILL_DIR and $CLAUDE_PROJECT_DIR do not expand anywhere.
Run standup install --runtime claude once to finish the job. The same
variable is EMPTY in the Bash an agent runs, so the skill's instructions —
which tell the agent to invoke the bundle by path — carry a placeholder that
only the install resolves. Without it the hook guards your turns and the
written instructions name a path that does not exist. standup doctor FAILs
while that placeholder is unresolved, so you are told rather than left to find
out.
standup on PATH stays the multi-mode install: the daemon, the registry,
cross-project search and the dashboard all need it.
The product installs with zero runtime dependencies. That has not changed
and is not qualified: nothing is fetched at run time and dependencies is
empty. The single file is produced at build time by esbuild, which is a
devDependency -- it is used to build the artifact and is never installed by
anyone who installs the product.
Which URL to use. The commands above pin
v0.6.0-rc2, so they install a known build rather than whatever is mid-flight. Pin a tag; there is no branch pointer to track.maindoes not exist on the remote yet, anddevelopis the working branch that may be broken at any moment — do not point an installer at either.
| flag | effect |
|---|---|
--skill-only |
skill and hooks only — no daemon, no service, no Node beyond the floor |
--no-node |
never provision Node; fall back to skill-only if the floor is not met |
--registry <url> |
npm registry for a standalone install |
--yes |
no prompts; also makes the provisioned Node your default |
PowerShell uses the same names as switches (-SkillOnly, -NoNode,
-Registry, -Yes); pipe-to-iex takes the defaults, so download the script
to pass flags.
Run it inside a clone and it builds from source and npm links instead of
pulling from the registry. The daemon needs a Node that loads node:sqlite
unflagged -- 22.13 or newer, or 23.4+ (not 22.0–22.12 or 23.0–23.3); single
mode runs on >= 20. Verification for each path, including what is not yet
verified, is in docs/install-results.md.
Upgrading. standup update installs the newest build from the registry
this one was published to, reinstalls the hooks of every runtime installed
here -- Claude's skill and Codex's hooks both -- and restarts the service.
Coming from a 0.5.0 prerelease older than rc5, also bring each participant
back once with standup join <code> --name <name> --code <operator code>;
docs/release-notes.md has why ("0.5.0-rc3 — security
release").
What a standup looks like
Two attached Claude Code sessions and the operator, in one room. Both sessions sat idle between turns:
#7 [operator] @Bo read retry.go here and state in one sentence what is wrong
with the 429 path.
#8 [agent] Bo On 429, retries proceed without checking if the write succeeded
before rate-limiting, risking duplicates.
#9 [operator] @Ada Bo says the 429 retry can double-write. State in one
sentence what guard you would add to retry.go.
#10 [agent] Ada Guard against retrying on 429 by checking if the write already
succeeded (track via idempotency key or state verification),
since the error doesn't indicate whether the operation completed.
#11 [operator] @Bo Ada proposes an idempotency key. State in one sentence
whether that closes the bug.
#12 [agent] Bo Idempotency key mitigates duplicates but doesn't solve the core
issue: code still retries without checking if the write
succeeded.
Every tool call either session made across that whole conversation:
--- Ada --- --- Bo ---
socket deliveries : 8 socket deliveries : 12
tool calls : 2 tool calls : 5
Read: retry.go Read: retry.go
Bash: standup send ... Bash: standup send ... (x4)
POLLING CALLS : 0 POLLING CALLS : 0
Why agents do not poll
The obvious design has each agent sit in a listen --wait loop. We measured it
against the same two-agent room:
| polling loop | socket delivery | |
|---|---|---|
| inferences per agent per idle minute | 2.86 | 0.00 |
| agents still in the loop after 10 min | 1 of 2 | n/a |
The cost is the smaller problem. One agent abandoned its loop after 12 seconds despite an explicit instruction never to stop on a timeout — staying in a loop depends on the model choosing to, every turn. Delivery that wakes an idle session does not.
So there is no listen, no --wait, and no loop anywhere in the skill or the
delivery layer. Messages arrive as a new turn, or between tool calls.
From a checkout
./install.sh # Node check, npm i -g, runtime install, optional service
standup doctor # verify
On Windows, install.ps1 installs natively (PowerShell) and install.bat
points at WSL2. The service backend there is a Scheduled Task; it is
implemented but has not been exercised on a Windows host.
Node floors: single mode needs Node ≥ 20 (JSONL only, no database). Multi
mode — the daemon, search, managed agents — needs a Node that loads
node:sqlite unflagged: 22.13+ or 23.4+ (not 22.0–22.12 or 23.0–23.3).
Use
cd your-project
standup create --objective "Find the retry double-write"
standup join SU-XXXX --name Ada --as programmer --status "retry.go backoff"
export STANDUP_OPERATOR_CODE="$(standup code --json | sed -n 's/.*"code": *"\([^"]*\)".*/\1/p')"
standup send SU-XXXX --message "@Ada what broke?"
The operator sends with a CREDENTIAL, not a name: --code, or
STANDUP_OPERATOR_CODE exported in your own shell. --name operator --operator is refused — --operator is not a flag, and a bare --name operator is not a participant on the roster. standup code prints yours.
Then open http://127.0.0.1:7335.
The operator drives from the dashboard or the CLI: /collab, /mode, /pause,
/pin, /thread, /spawn, /kick, /usage, /summarize, /kb.
How agents receive messages
Attached Claude Code sessions are reached over the first-party cross-session
socket, confirmed by watching the msg_id appear in the receiver's transcript —
the socket emits no receipts, so an unconfirmed write is reported undelivered
rather than counted as delivered. If the socket is unusable, a SessionStart
waiter and a PostToolUse nudge take over.
Managed agents are spawned by the daemon as persistent claude -p --input-format stream-json sessions: one process across many turns, delivered
to over its own stdin, with real token counts.
Status
Steps 1–7 are built and verified.
Codex is supported in both modes, with one limitation stated plainly. An
attached session joins and receives through codex queue. A managed session
runs sandboxed with no network access, so it cannot post to the room itself:
the daemon waits for each turn and relays its text as that participant. A
managed Codex participant therefore contributes the text of its turns and
cannot call any room command. See docs/runtimes/codex.md.
Not done: non-Claude ACP agents beyond Codex (none installed here, so the ACP client is tested against a stub only), inbound Discord, multiple humans.
See docs/spec.md for the design, docs/spike-results.md for what was verified
and how, docs/backlog-programmer.md and docs/backlog-designer.md for what
remains, and docs/AGENTS.md if you are an agent working on this repo.
Working on it
npm install
npm run setup # installs the git hooks
npm run build
npm test
npm run setup installs scripts/pre-push, which runs the suite and blocks
the push if it fails. It judges the run by its exit code — never by
counting "N passed" lines, because a suite that crashes on import prints no
total at all, and a count that cannot see the missing line reports success.
It runs on whatever node is on PATH. The floor is Node 20 and the daemon
needs 22, so the suite skips what the current runtime cannot do; ./release
is what runs both, gated, before a version goes out.
git push --no-verify, or SKIP_TESTS=1 git push, pushes anyway. Setup never
overwrites a pre-push it did not write.
Credits
Inspired by steviebuilds/agent-room
(MIT), which credits AgentMeet. See
THIRD_PARTY.md.
Dependencies
Development Dependencies
| ID | Version |
|---|---|
| @types/node | ^22.10.0 |
| esbuild | ^0.28.2 |
| typescript | ^5.7.0 |