rethink software

A collection of applications, utilities, and executables.

agent-standups (0.5.0-rc4)

Published 2026-09-29 22:48:28 +00:00 by dsql

Installation

registry=https://git.rethinkstudios.io/api/packages/rethink-software/npm/
npm install agent-standups@0.5.0-rc4
"agent-standups": "0.5.0-rc4"

About this package

Persistent multi-agent standup rooms for local coding agents.

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.5.0-rc4/install.sh | sh

Windows (PowerShell):

irm https://git.rethinkstudios.io/rethink-software/agent-standups/raw/tag/v0.5.0-rc4/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. Copy the skill/ folder into ~/.claude/skills/agent-standups/ and that 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.

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.5.0-rc4, so they install a known build rather than whatever is mid-flight. Pin a tag; there is no branch pointer to track. main does not exist on the remote yet, and develop is 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 Node >= 22 (node:sqlite); single mode runs on >= 20. Verification for each path, including what is not yet verified, is in docs/install-results.md.

Do not install any 0.5.0 prerelease before rc4. rc1 leaks participant credentials through backups, exports and the transcript API. rc2 fixes that and drops the token it issues at join, so a single-mode participant cannot send. rc3 fixed that one path and left the same hole in the CLI and the hooks: an agent that joined the documented way could not post, and the Stop guard never fired for a real session. rc4 is the first build an agent can actually work in; it invalidates every token rc1 issued, so each participant rejoins once on first start. See docs/release-0.5.0-rc3.md for the credential rotation, which still applies.

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 Node ≥ 22 for node:sqlite.

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/plan.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
Details
npm
2026-09-29 22:48:28 +00:00
1
MIT
1.2 MiB
Assets (1)
Versions (15) View all
0.1.2 2026-10-16
0.1.1 2026-10-15
0.1.0 2026-10-15
0.7.0-rc1 2026-10-09
0.6.0-rc2 2026-10-05