Sweep 22 Sep 2026 · 15:52Z Build v2.1.280 501 read Stable v2.1.267 Latest v2.1.280 Next v2.1.280 Feeds RSS JSON llms.txt Unofficial
Writing the changelog v2.1.280 merge candidates · 1/5
Tool description

Monitor, as sent

CLI Claude Code, interactive mode, seeded with flags-anon, v2.1.269. 27 model strings share this prompt, byte for byte.

Lines716,132 characters
Moved+0−0 against v2.1.268
Reach27model strings receive this description
Copies1distinct descriptions under this name
Parameters53 of them required Tools in captureall of themevery description on this arm
Plain text · sha256 abcbc10e2b81

The description, line by line

71 lines Line numbers are v2.1.268 on the left and this capture on the right.
1 1 Start a background monitor that streams events from a long-running script. Each stdout line is an event — you keep working and notifications arrive in the chat. Events arrive on their own schedule and are not replies from the user, even if one lands while you're waiting for the user to answer a question.
2 2
3 3 Pick by how many notifications you need:
4 4 - **One** ("tell me when the server is ready / the build finishes") → use **Bash with `run_in_background`** and a command that exits when the condition is true, e.g. `until grep -q "Ready in" dev.log; do sleep 0.5; done`. You get a single completion notification when it exits.
5 5 - **One per occurrence, indefinitely** ("tell me every time an ERROR line appears") → Monitor with an unbounded command (`tail -f`, `inotifywait -m`, `while true`).
6 6 - **One per occurrence, until a known end** ("emit each CI step result, stop when the run completes") → Monitor with a command that emits lines and then exits.
7 7
8 8 Your script's stdout is the event stream. Each line becomes a notification. Exit ends the watch.
9 9
10 10 # Each matching log line is an event
11 11 tail -f /var/log/app.log | grep --line-buffered "ERROR"
12 12
13 13 # Each file change is an event
14 14 inotifywait -m --format '%e %f' /watched/dir
15 15
16 16 # Poll GitHub for new PR comments and emit one line per new comment
17 17 last=$(date -u +%Y-%m-%dT%H:%M:%SZ)
18 18 while true; do
19 19 now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
20 20 gh api "repos/owner/repo/issues/123/comments?since=$last" --jq '.[] | "\(.user.login): \(.body)"'
21 21 last=$now; sleep 30
22 22 done
23 23
24 24 # Node script that emits events as they arrive (e.g. WebSocket listener)
25 25 node watch-for-events.js
26 26
27 27 # Per-occurrence with a natural end: emit each CI check as it lands, exit when the run completes
28 28 prev=""
29 29 while true; do
30 30 s=$(gh pr checks 123 --json name,bucket)
31 31 cur=$(jq -r '.[] | select(.bucket!="pending") | "\(.name): \(.bucket)"' <<<"$s" | sort)
32 32 comm -13 <(echo "$prev") <(echo "$cur")
33 33 prev=$cur
34 34 jq -e 'all(.bucket!="pending")' <<<"$s" >/dev/null && break
35 35 sleep 30
36 36 done
37 37
38 38 **Don't use an unbounded command for a single notification.** `tail -f`, `inotifywait -m`, and `while true` never exit on their own, so the monitor stays armed until timeout even after the event has fired. For "tell me when X is ready," use Bash `run_in_background` with an `until` loop instead (one notification, ends in seconds). Note that `tail -f log | grep -m 1 ...` does *not* fix this: if the log goes quiet after the match, `tail` never receives SIGPIPE and the pipeline hangs anyway.
39 39
40 40 **Script quality:**
41 41 - Every pipe stage must flush per line or matches sit in its buffer unseen: `grep` needs `--line-buffered`, `awk` needs `fflush()`. `head` cannot flush at all — `| head -N` delivers nothing until N matches accumulate, then ends the stream.
42 42 - In poll loops, handle transient failures (`curl ... || true`) — one failed request shouldn't kill the monitor.
43 43 - Poll intervals: 30s+ for remote APIs (rate limits), 0.5-1s for local checks.
44 44 - Write a specific `description` — it appears in every notification ("errors in deploy.log" not "watching logs").
45 45 - Only stdout is the event stream. Stderr goes to the output file (readable via Read) but does not trigger notifications — for a command you run directly (e.g. `python train.py 2>&1 | grep --line-buffered ...`), merge stderr with `2>&1` so its failures reach your filter. (No effect on `tail -f` of an existing log — that file only contains what its writer redirected.)
46 46
47 47 **Coverage — silence is not success.** When watching a job or process for an outcome, your filter must match every terminal state, not just the happy path. A monitor that greps only for the success marker stays silent through a crashloop, a hung process, or an unexpected exit — and silence looks identical to "still running." Before arming, ask: *if this process crashed right now, would my filter emit anything?* If not, widen it.
48 48
49 49 # Wrong — silent on crash, hang, or any non-success exit
50 50 tail -f run.log | grep --line-buffered "elapsed_steps="
51 51
52 52 # Right — one alternation covering progress + the failure signatures you'd act on
53 53 tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"
54 54
55 55 For poll loops checking job state, emit on every terminal status (`succeeded|failed|cancelled|timeout`), not just success. If you cannot confidently enumerate the failure signatures, broaden the grep alternation rather than narrow it — some extra noise is better than missing a crashloop.
56 56
57 57 **Output volume**: Every stdout line is a conversation message, so the filter should be selective — but selective means "the lines you'd act on," not "only good news." Never pipe raw logs; filter to exactly the success and failure signals you care about. Monitors that produce too many events are automatically stopped; restart with a tighter filter if this happens.
58 58
59 59 Stdout lines within 200ms are batched into a single notification, so multiline output from a single event groups naturally.
60 60
61 61 The script runs in the same shell environment as Bash. Exit ends the watch (exit code is reported). Timeout → killed. Set `persistent: true` for session-length watches (PR monitoring, log tails) — the monitor runs until you call TaskStop or the session ends. Use TaskStop to cancel early.
62 62 **ws source** — open a WebSocket and stream each incoming text frame as an event. No shell, no polling: the server pushes, you get notified.
63 63
64 64 Monitor({
65 65 ws: {url: 'wss://events.example.com/stream', protocols: ['v1']},
66 66 description: 'deploy events',
67 67 })
68 68
69 69 Each text frame becomes one notification (multiline frames stay as one event). Binary frames are reported as `[binary frame, N bytes]` rather than passed through. Socket close ends the watch with the close code surfaced; errors are surfaced before close. Same rate limiting as bash — a firehose will be suppressed and eventually stopped, so subscribe to a filtered feed where one exists.
70 70
71 71 Prefer this over `command: 'websocat wss://…'` — it avoids the extra process and line-buffering pitfalls. Use bash when you need to transform or filter frames with shell tools before they become events.

What it accepts

5 parameters The JSON parameter schema sent beside this description, 1,411 characters of it. Name, type, then whether the client marked it required.
command string optional Shell command or script. Each stdout line is an event; exit ends the watch.
description string required Short human-readable description of what you are monitoring (shown in notifications).
persistent boolean required Run for the lifetime of the session (no timeout). Use for session-length watches like PR monitoring or log tails. Stop with TaskStop.
timeout_ms number required Kill the monitor after this deadline. Default 300000ms, max 3600000ms. Ignored when persistent is true.
ws object optional WebSocket to open. Each text frame is an event; binary frames are reported as a placeholder line. Socket close ends the watch. Cannot be combined with command.

sha256 a7c7f33f088f · the schema as the client sent it:

{ "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "command": { "description": "Shell command or script. Each stdout line is an event; exit ends the watch.", "type": "string" }, "description": { "description": "Short human-readable description of what you are monitoring (shown in notifications).", "type": "string" }, "persistent": { "default": false, "description": "Run for the lifetime of the session (no timeout). Use for session-length watches like PR monitoring or log tails. Stop with TaskStop.", "type": "boolean" }, "timeout_ms": { "default": 300000, "description": "Kill the monitor after this deadline. Default 300000ms, max 3600000ms. Ignored when persistent is true.", "minimum": 1000, "type": "number" }, "ws": { "additionalProperties": false, "description": "WebSocket to open. Each text frame is an event; binary frames are reported as a placeholder line. Socket close ends the watch. Cannot be combined with command.", "properties": { "protocols": { "items": { "pattern": "^[!#$%&'*+.^_`|~0-9A-Za-z-]+$", "type": "string" }, "type": "array" }, "url": { "type": "string" } }, "required": [ "url" ], "type": "object" } }, "required": [ "description", "timeout_ms", "persistent" ], "type": "object" }