docs: add docs/using-nats-cli.md + fix missing --reply-timeout flag#105
Conversation
A canonical cookbook for driving an agent from the `nats` CLI.
Consolidates the troubleshooting paragraphs that were copy-pasted
across four agent READMEs.
Also fixes four `nats req` prompt examples that were missing
`--reply-timeout=30s`. After §6.4 made the leading `status=ack`
chunk mandatory, every `nats req` call to a prompt subject without
this flag exits after the ack alone (default `--reply-timeout` is
300 ms — shorter than the gap between the ack and the model's
first response).
Fixed examples:
- client-sdk/python/README.md
- agents/claude-code/README.md
- agents/open-agent/README.md
- examples/open-agent-vercel/README.md
Discovery (`\$SRV.INFO.agents`), status (`agents.status.*`), and
control-plane RPCs (`agents.{spawn,list,stop}.*`) intentionally
left alone — they're single-reply, not streamed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @M64GitHub's task in 4m 38s —— View job PR Review
SummaryThe four The new cookbook ( Incorrect keepalive status value (inline comment posted at line 88) The wire diagram shows
Two secondary notes (not blocking, but worth a look):
|
| {"type":"status","data":"ack"} ← mandatory §6.4 leading chunk, sent instantly | ||
| {"type":"response","data":"Sure, here..."} ← model output (one or more) | ||
| {"type":"response","data":" are the files"} ← ... | ||
| {"type":"status","data":"keepalive"} ← optional periodic keep-alive |
There was a problem hiding this comment.
Wrong status value for keepalive. Both SDKs emit {"type":"status","data":"ack"} for the periodic mid-stream keep-alive — the same value as the leading ack. There is no distinct "keepalive" token on the wire.
From agent-sdk/typescript/src/service.ts (comment line 19):
{"type":"status","data":"ack"}everykeepaliveIntervalSseconds while the prompt handler is running
From agent-sdk/python/src/synadia_ai/agent_service/service.py (docstring line 208):
{"type":"status","data":"ack"}everykeepalive_interval_s
The line should read:
| {"type":"status","data":"keepalive"} ← optional periodic keep-alive | |
| {"type":"status","data":"ack"} ← optional periodic keep-alive (same "ack" token as the leading chunk) |
- Wire diagram: the periodic keep-alive emits {"type":"status","data":"ack"},
not "keepalive" — same token as the leading chunk. Both SDKs do this
(see agent-sdk/typescript/src/service.ts:19 and
agent-sdk/python/src/synadia_ai/agent_service/service.py:208).
- Clarify --wait-for-empty vs --replies=0: --wait-for-empty exits
immediately at the protocol terminator; --replies=0 doesn't know about
the terminator and waits the full --reply-timeout (30s dead tail).
Not equivalent.
- "Hangs forever" gotcha → "sits idle for 30 s before exiting" — with
--timeout in place the CLI does exit; the wait is just dead.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@claude - please review again |
|
Claude finished @M64GitHub's task in 1m 24s —— View job PR Review
SummaryAll three findings from the previous review have been addressed. The PR is clean and ready to merge. Previous findings — resolved1. Keepalive status value (was blocking) ✅ Fixed
This matches both SDK sources:
2. Lines 58–70 now clearly separate the two modes:
The recommendation to prefer 3. "hangs forever" wording (was secondary) ✅ Fixed The gotchas table row now reads "sits idle for 30 s before exiting" — accurate for the scenario where The four
|
| File | Invocation |
|---|---|
agents/claude-code/README.md:99 |
--replies=0 --reply-timeout=30s --timeout=90s |
agents/open-agent/README.md:57 |
--replies=0 --reply-timeout=30s --timeout=5m |
client-sdk/python/README.md:172 |
--replies=0 --reply-timeout=30s --timeout=60s |
examples/open-agent-vercel/README.md:82 |
--replies=0 --reply-timeout=30s --timeout=5m |
The client-sdk/python/README.md also adds a helpful inline pointer to docs/using-nats-cli.md.
Main README pointer
README.md now includes:
To prompt an agent directly from the CLI (no SDK), pass three flags —
--replies=0 --reply-timeout=30s --timeout=60s. The full CLI cookbook (prompts, attachments, status, control-plane, gotchas) lives atdocs/using-nats-cli.md.
Correctly placed, concise, and accurate.
No remaining issues. The cookbook is technically accurate, the flag fixes are correct, and the secondary findings about --replies=0 behavior and wording have been addressed cleanly.
Summary
After §6.4 made the leading
status=ackchunk mandatory, everynats reqcall to a prompt subject without--reply-timeout=30sexits after the ack alone (the CLI default is 300 ms — shorter than the gap between the leading ack and the model's first response). Four prompt examples in this repo were missing the flag.This PR:
docs/using-nats-cli.md— a canonical cookbook for driving an agent from thenatsCLI. Covers discovery, heartbeats, prompting (text + JSON envelope + attachments), the three load-bearing flags and why each one matters, status snapshots, headless control-plane RPCs, and a gotchas table. Consolidates content that was copy-pasted across four agent READMEs.--reply-timeout=30s:client-sdk/python/README.mdagents/claude-code/README.mdagents/open-agent/README.mdexamples/open-agent-vercel/README.mdIntentionally NOT changed
These
nats reqcalls don't stream — they're single-reply RPCs — so--reply-timeoutis moot:$SRV.INFO.agents,$SRV.PING.agents(inREADME.md,agents/{pi,openclaw,claude-code}/README.md).agents.status.*(single heartbeat-shaped reply).agents.{spawn,list,stop}.*(single JSON reply) in the headless examples.If you'd rather have the flag added uniformly to all
nats reqcalls regardless, let me know and I'll widen the sweep — it'd be a redundant no-op on the discovery/status/control-plane calls but harmless.Test plan
docs/using-nats-cli.mdon GitHub — verify the table formatting and code blocks survivenats req agents.prompt.pi.<owner>.<session> "hi" --replies=0 --reply-timeout=30s --timeout=60sactually streams chunks past the ack🤖 Generated with Claude Code