opencode-thrum-pro 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/commands/thrum-compact-extended.md +367 -0
- package/assets/commands/thrum-compact.md +301 -0
- package/assets/commands/thrum-inbox.md +1 -1
- package/assets/commands/thrum-restart-extended.md +85 -16
- package/assets/commands/thrum-restart.md +106 -14
- package/assets/commands/thrum-send.md +4 -1
- package/assets/commands/thrum-sleep-extended.md +68 -51
- package/assets/commands/thrum-sleep.md +68 -63
- package/assets/commands/thrum-update-project.md +1 -1
- package/assets/skills/adversarial-critique/SKILL.md +5 -8
- package/assets/skills/brainstorm-steward/SKILL.md +65 -11
- package/assets/skills/brainstormer-staying-current/SKILL.md +1 -4
- package/assets/skills/choosing-subagent-models/SKILL.md +200 -70
- package/assets/skills/closing-findings-while-warm/SKILL.md +1 -2
- package/assets/skills/configure-roles/SKILL.md +2 -2
- package/assets/skills/conversation-only-context/SKILL.md +11 -11
- package/assets/skills/conversation-only-context/resources/driver-subagent-pattern.md +1 -1
- package/assets/skills/conversation-only-context/resources/remote-environment-scenarios.md +1 -1
- package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +98 -6
- package/assets/skills/coordinator-branch-split-on-block/SKILL.md +1 -2
- package/assets/skills/coordinator-context-monitoring/SKILL.md +29 -19
- package/assets/skills/coordinator-deploying-a-node/SKILL.md +124 -0
- package/assets/skills/coordinator-dispatching-work/SKILL.md +26 -14
- package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +65 -21
- package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +1 -2
- package/assets/skills/coordinator-maintaining-memory/SKILL.md +1 -1
- package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +7 -8
- package/assets/skills/coordinator-merging-code/SKILL.md +43 -22
- package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +29 -9
- package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +4 -5
- package/assets/skills/coordinator-rolling-out-to-nodes/SKILL.md +92 -0
- package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +3 -3
- package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +25 -25
- package/assets/skills/coordinator-running-review-cycles/SKILL.md +16 -6
- package/assets/{commands/thrum-_deviations-protocol.md → skills/deviations-protocol/SKILL.md} +6 -12
- package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +0 -2
- package/assets/skills/efficient-multi-agent-research/SKILL.md +3 -3
- package/assets/skills/generator-idempotency-protocol/SKILL.md +9 -0
- package/assets/skills/implementer-maintaining-memory/SKILL.md +3 -4
- package/assets/skills/implementer-orchestrating-execution/SKILL.md +12 -16
- package/assets/skills/implementer-receiving-dispatch/SKILL.md +15 -17
- package/assets/skills/implementer-receiving-review-feedback/SKILL.md +3 -4
- package/assets/skills/implementer-status-and-handoff/SKILL.md +1 -14
- package/assets/skills/implementer-tdd-and-quality/SKILL.md +2 -2
- package/assets/skills/memory-curate/SKILL.md +1 -1
- package/assets/skills/memory-write-discipline/SKILL.md +1 -1
- package/assets/skills/orchestrate/SKILL.md +77 -36
- package/assets/skills/persistent-watcher-archetype/SKILL.md +172 -25
- package/assets/skills/persistent-watcher-archetype/resources/capture_archive.py +618 -0
- package/assets/skills/persistent-watcher-archetype/resources/jev_watcher_filter.py +837 -0
- package/assets/skills/persistent-watcher-archetype/resources/roster-watch.sh +1140 -0
- package/assets/skills/persistent-watcher-archetype/resources/roster-watch_test.sh +291 -0
- package/assets/skills/persistent-watcher-archetype/resources/thrum-capture-fallback.sh +2 -2
- package/assets/skills/persistent-watcher-archetype/resources/thrum-watch-pane-capture.sh +20 -8
- package/assets/skills/prime-agent/SKILL.md +10 -0
- package/assets/skills/project-hotpath-gate/SKILL.md +1 -2
- package/assets/skills/project-philosophy/SKILL.md +1 -2
- package/assets/skills/project-rules-protocol/SKILL.md +12 -0
- package/assets/skills/project-setup/SKILL.md +27 -22
- package/assets/skills/project-setup/resources/implementation-agent.md +55 -35
- package/assets/skills/researcher-answering-queries/SKILL.md +1 -2
- package/assets/skills/researcher-investigating/SKILL.md +8 -13
- package/assets/skills/researcher-maintaining-memory/SKILL.md +1 -1
- package/assets/{commands/thrum-_snapshot-protocol.md → skills/snapshot-protocol/SKILL.md} +27 -21
- package/assets/{commands/thrum-_stamp-protocol.md → skills/stamp-protocol/SKILL.md} +14 -8
- package/assets/skills/thrum/SKILL.md +14 -7
- package/assets/skills/thrum/resources/ANTI_PATTERNS.md +16 -18
- package/assets/skills/thrum/resources/CLI_REFERENCE.md +17 -11
- package/assets/skills/thrum/resources/LISTENER_PATTERN.md +9 -3
- package/assets/skills/thrum/resources/MESSAGING.md +18 -11
- package/assets/skills/thrum/resources/WORKTREES.md +1 -1
- package/assets/skills/thrum-memory/SKILL.md +1 -1
- package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +1 -1
- package/assets/skills/update-queue/SKILL.md +6 -8
- package/assets/skills/using-the-dashboard/SKILL.md +30 -0
- package/assets/skills/using-the-queue/SKILL.md +76 -5
- package/assets/skills/using-thrum-state/SKILL.md +85 -2
- package/assets/skills/verify-against-plan/SKILL.md +122 -7
- package/assets/skills/watcher-archetype/SKILL.md +18 -0
- package/assets/skills/writing-durable-markdown/SKILL.md +5 -0
- package/dist/installer-assets.test.js +41 -0
- package/dist/installer.js +4 -4
- package/dist/permission-fixture.integration.test.js +4 -4
- package/package.json +1 -1
- package/assets/commands/thrum-_generator-idempotency-protocol.md +0 -15
- package/assets/commands/thrum-_project-rules-protocol.md +0 -18
- package/assets/commands/thrum-_verify-before-write-protocol.md +0 -27
- package/assets/skills/coordinator-deploying-the-fleet/SKILL.md +0 -396
- package/dist/allowlist-sync.test.js +0 -44
- /package/dist/{allowlist-sync.test.d.ts → installer-assets.test.d.ts} +0 -0
|
@@ -35,9 +35,13 @@ When filling this template to create an implementation prompt:
|
|
|
35
35
|
- `{{WORKTREE_PATH}}` — Absolute path to the working worktree
|
|
36
36
|
- `{{BRANCH_NAME}}` — Git branch for this work (e.g., `feature/auth`)
|
|
37
37
|
- `{{BASE_BRANCH}}` — The branch this work merges into. **Resolve it from the
|
|
38
|
-
project's actual merge target**
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
project's actual merge target**
|
|
39
|
+
(`CONFIG=.thrum/config.json;
|
|
40
|
+
[ -f .thrum/redirect ] && CONFIG="$(cat .thrum/redirect)/config.json";
|
|
41
|
+
jq -r '.orchestration.merge_target' "$CONFIG"`
|
|
42
|
+
— a worktree's `.thrum/` holds only a `redirect` file, not its own
|
|
43
|
+
`config.json`); do not assume `main` and do not carry a branch name from
|
|
44
|
+
another document
|
|
41
45
|
- `{{DESIGN_DOC}}` — **Absolute path** to the design spec (if applicable)
|
|
42
46
|
- `{{REFERENCE_CODE}}` — Paths to reference implementations (if any)
|
|
43
47
|
- `{{QUALITY_COMMANDS}}` — Commands for test/lint, **scoped to packages this
|
|
@@ -88,12 +92,12 @@ Otherwise, orchestrate via the agent table below.
|
|
|
88
92
|
|
|
89
93
|
| Dispatch | Agent type | Model | Background? |
|
|
90
94
|
| ------------------------------ | ------------------------------ | --------------------------------------- | ----------- |
|
|
91
|
-
| Research / explore a code area | `Explore` or `general-purpose` | `
|
|
92
|
-
| Implement a task | `general-purpose` | `
|
|
93
|
-
| Verify a task against the plan | `general-purpose` | `
|
|
94
|
-
| Run tests / lint | `general-purpose` | `
|
|
95
|
+
| Research / explore a code area | `Explore` or `general-purpose` | per `choosing-subagent-models` | yes |
|
|
96
|
+
| Implement a task | `general-purpose` | per `choosing-subagent-models` (low effort if purely mechanical) | no |
|
|
97
|
+
| Verify a task against the plan | `general-purpose` | per `choosing-subagent-models` | no |
|
|
98
|
+
| Run tests / lint | `general-purpose` | per `choosing-subagent-models` (low effort) | yes |
|
|
95
99
|
|
|
96
|
-
Always pass `model:` explicitly — never let a sub-agent inherit your
|
|
100
|
+
Always pass `model:` explicitly — never let a sub-agent inherit your own
|
|
97
101
|
model. Label every dispatch's `description` with `research:` / `implement:` /
|
|
98
102
|
`verify:` (the evaluation harness classifies delegation shape from these
|
|
99
103
|
labels).
|
|
@@ -115,7 +119,7 @@ labels).
|
|
|
115
119
|
|
|
116
120
|
### Verifier dispatch (per task)
|
|
117
121
|
|
|
118
|
-
After an implementation dispatch returns, spawn a `
|
|
122
|
+
After an implementation dispatch returns, spawn a verifier sub-agent (model per `choosing-subagent-models`) against the
|
|
119
123
|
plan the implementing sub-agent was given — confirm the diff meets the
|
|
120
124
|
acceptance criteria. This is the in-loop check; the full code review still
|
|
121
125
|
happens at Phase 3: Self-Review Gate.
|
|
@@ -131,7 +135,7 @@ section.
|
|
|
131
135
|
cd {{WORKTREE_PATH}}
|
|
132
136
|
thrum quickstart --name {{AGENT_NAME}} --role implementer --module {{BRANCH_NAME}} --intent "Implementing {{EPIC_ID}}"
|
|
133
137
|
thrum inbox --unread
|
|
134
|
-
# Tip: thrum inbox --unread peeks without marking read; thrum message read --all to mark all
|
|
138
|
+
# Tip: thrum inbox --unread peeks without marking read; thrum message read --all --force to mark all unread (run `--all` alone first — dry run)
|
|
135
139
|
# Tip: default page is 10 newest-first — stale unread sorts LAST; use `thrum message search "<term>"` to find it
|
|
136
140
|
thrum send --to @{{SUPERVISOR_NAME}} --stdin <<'EOF'
|
|
137
141
|
Starting work on {{EPIC_ID}}
|
|
@@ -177,11 +181,13 @@ EOF
|
|
|
177
181
|
Whether starting fresh or resuming after context loss, always begin here. This
|
|
178
182
|
phase is idempotent — running it multiple times is safe and expected.
|
|
179
183
|
|
|
180
|
-
🔴 **BEFORE ANYTHING ELSE — OBTAIN THE PLAN INTO YOUR WORKTREE AND CONFIRM YOU CAN OPEN IT.**
|
|
184
|
+
🔴 **BEFORE ANYTHING ELSE — OBTAIN THE PLAN INTO YOUR WORKTREE AND CONFIRM YOU CAN OPEN IT.**
|
|
185
|
+
Do NOT implement from plan detail relayed to you in messages or beads — relay is lossy and drifts as the
|
|
186
|
+
plan is updated.
|
|
181
187
|
|
|
182
188
|
```bash
|
|
183
189
|
cd {{WORKTREE_PATH}}
|
|
184
|
-
git pull
|
|
190
|
+
git pull --no-rebase # pull the committed plan into this worktree (merge; a bare pull aborts on divergence)
|
|
185
191
|
head -1 {{PLAN_FILE}} # confirm the plan file actually opens here
|
|
186
192
|
```
|
|
187
193
|
|
|
@@ -216,7 +222,7 @@ git status
|
|
|
216
222
|
git --no-pager log --oneline -10
|
|
217
223
|
|
|
218
224
|
# Pull latest changes (if remote tracking is set up) — merge, never rebase
|
|
219
|
-
git pull
|
|
225
|
+
git pull --no-rebase
|
|
220
226
|
```
|
|
221
227
|
|
|
222
228
|
### Step 3: Explore Existing Code
|
|
@@ -432,35 +438,40 @@ bd list --type=epic | grep -i refactor
|
|
|
432
438
|
|
|
433
439
|
If no refactoring epic exists, create one:
|
|
434
440
|
|
|
435
|
-
`--description` is multi-line prose — never double-quoted inline.
|
|
436
|
-
`scripts/bd-shared
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
441
|
+
`--description` is multi-line prose — never double-quoted inline. Write it to a
|
|
442
|
+
scratch file and pass `--body-file <file>`; see the heredoc-or-file rule in your role preamble. `scripts/bd-shared` delivers `--body-file` (and `--stdin`)
|
|
443
|
+
content: it reads the file on YOUR box and pipes those bytes to bd, and an empty
|
|
444
|
+
or blank body is refused loudly. Only `-f`/`--file` and `--graph` (bulk-plan
|
|
445
|
+
files) are refused there. Scratch files go in `/private/tmp` on macOS, where
|
|
446
|
+
`/tmp` is a symlink (check `[ -L /tmp ]`), and in `/tmp` elsewhere.
|
|
440
447
|
|
|
441
448
|
```bash
|
|
442
|
-
|
|
449
|
+
# Scratch dir: /private/tmp on macOS (where /tmp is a symlink), /tmp elsewhere.
|
|
450
|
+
SCRATCH=$([ -L /tmp ] && echo /private/tmp || echo /tmp)
|
|
451
|
+
cat > "$SCRATCH/refactor-epic-desc.md" <<'EOF'
|
|
443
452
|
Persistent backlog for refactoring, DRY improvements, and code organization
|
|
444
453
|
opportunities discovered during feature work. Tasks are added by
|
|
445
454
|
implementation agents as they encounter opportunities. Reviewed and
|
|
446
455
|
prioritized by the coordinator periodically.
|
|
447
456
|
EOF
|
|
448
|
-
bd create --title="Refactoring & DRY Opportunities" --type=epic --priority=3 -
|
|
457
|
+
bd create --title="Refactoring & DRY Opportunities" --type=epic --priority=3 --body-file "$SCRATCH/refactor-epic-desc.md"
|
|
449
458
|
```
|
|
450
459
|
|
|
451
460
|
#### 2. Log the Opportunity
|
|
452
461
|
|
|
453
|
-
Same `--description` handling as §1 above (scratch file +
|
|
462
|
+
Same `--description` handling as §1 above (scratch file + `--body-file`).
|
|
454
463
|
|
|
455
464
|
```bash
|
|
456
|
-
|
|
465
|
+
# Scratch dir: /private/tmp on macOS (where /tmp is a symlink), /tmp elsewhere.
|
|
466
|
+
SCRATCH=$([ -L /tmp ] && echo /private/tmp || echo /tmp)
|
|
467
|
+
cat > "$SCRATCH/refactor-task-desc.md" <<'EOF'
|
|
457
468
|
**Discovered during:** {{EPIC_ID}}
|
|
458
469
|
**Files:** <file paths>
|
|
459
470
|
**Opportunity:** <what could be improved — duplicated code, hardcoded values, missed abstraction>
|
|
460
471
|
**Suggested approach:** <how to fix it>
|
|
461
472
|
**Effort estimate:** small/medium/large
|
|
462
473
|
EOF
|
|
463
|
-
bd create --title="Refactor: <short description>" --type=task --parent=<refactoring-epic-id> --priority=3 -
|
|
474
|
+
bd create --title="Refactor: <short description>" --type=task --parent=<refactoring-epic-id> --priority=3 --body-file "$SCRATCH/refactor-task-desc.md"
|
|
464
475
|
```
|
|
465
476
|
|
|
466
477
|
#### 3. Continue With Your Assigned Work
|
|
@@ -494,11 +505,13 @@ If a task is blocked:
|
|
|
494
505
|
|
|
495
506
|
```bash
|
|
496
507
|
# Ask the blocking agent for help
|
|
497
|
-
# NOTE: --mention @implementer (with no --to) delivers
|
|
498
|
-
#
|
|
499
|
-
#
|
|
500
|
-
#
|
|
501
|
-
#
|
|
508
|
+
# NOTE: --mention @implementer (with no --to) only delivers if "implementer"
|
|
509
|
+
# is itself a registered agent ID — mentions resolve exact agent IDs only, no
|
|
510
|
+
# role fan-out (P0 ruling: removed by design, do not
|
|
511
|
+
# restore). A message with ZERO addressing (no --to, no mentions) routes to
|
|
512
|
+
# the local coordinator instead. There is no broadcast-to-everyone mechanism —
|
|
513
|
+
# --broadcast and @everyone were removed by design; name every recipient
|
|
514
|
+
# explicitly (--to is repeatable for multiple recipients).
|
|
502
515
|
thrum send --mention @implementer --stdin <<'EOF'
|
|
503
516
|
BLOCKED: {{TASK_ID}} — waiting for {{BLOCKER_ID}}. Can you prioritize?
|
|
504
517
|
EOF
|
|
@@ -603,18 +616,25 @@ Fix any failures before proceeding. Do not submit broken code for review.
|
|
|
603
616
|
|
|
604
617
|
### Step 2: Spec Compliance Review (Stage 1)
|
|
605
618
|
|
|
606
|
-
Verify the implementation covers everything specified in the plan,
|
|
607
|
-
|
|
608
|
-
|
|
619
|
+
Verify the implementation covers everything specified in the plan and, when the
|
|
620
|
+
epic has a design doc, in the design doc. Also cross-check each task's
|
|
621
|
+
acceptance criteria against the code: run
|
|
622
|
+
`bd show <task_id>` for every task in the epic and confirm each acceptance
|
|
623
|
+
criterion is met. No code-style judgments at this stage — only "does the code do
|
|
624
|
+
what was asked?"
|
|
609
625
|
|
|
610
626
|
Invoke `verify-against-plan` with these inputs:
|
|
611
627
|
|
|
612
628
|
```text
|
|
613
|
-
/verify-against-plan plan={{PLAN_FILE}} branch={{BRANCH_NAME}}
|
|
629
|
+
/verify-against-plan plan={{PLAN_FILE}} design={{DESIGN_DOC}} branch={{BRANCH_NAME}}
|
|
614
630
|
```
|
|
615
631
|
|
|
632
|
+
Drop the `design=` input only when this epic has no design doc (`{{DESIGN_DOC}}`
|
|
633
|
+
was left unset). With it, requirements that only the design states are checked
|
|
634
|
+
too, not just the plan's tasks.
|
|
635
|
+
|
|
616
636
|
The skill produces structured `BLOCKING` / `IMPORTANT` / `MINOR` findings with
|
|
617
|
-
plan-reference + file:line evidence.
|
|
637
|
+
plan-reference (or design-reference) + file:line evidence.
|
|
618
638
|
|
|
619
639
|
**When findings come back:**
|
|
620
640
|
|
|
@@ -643,7 +663,7 @@ results before proceeding). The reviewer is a separate agent — you cannot
|
|
|
643
663
|
influence its findings.
|
|
644
664
|
|
|
645
665
|
```text
|
|
646
|
-
Agent(subagent_type="feature-dev:code-reviewer", model="
|
|
666
|
+
Agent(subagent_type="feature-dev:code-reviewer", model="<per choosing-subagent-models>",
|
|
647
667
|
prompt="Review code quality of the implementation on branch {{BRANCH_NAME}}
|
|
648
668
|
in {{WORKTREE_PATH}}. Focus only on quality of the code that was written —
|
|
649
669
|
spec compliance is covered separately by verify-against-plan.
|
|
@@ -814,7 +834,7 @@ the minimal sequence:
|
|
|
814
834
|
cd {{WORKTREE_PATH}}
|
|
815
835
|
thrum quickstart --name {{AGENT_NAME}} --role implementer --module {{BRANCH_NAME}} --intent "Resuming {{EPIC_ID}}"
|
|
816
836
|
thrum inbox --unread
|
|
817
|
-
# Tip: thrum inbox --unread peeks without marking read; thrum message read --all to mark all
|
|
837
|
+
# Tip: thrum inbox --unread peeks without marking read; thrum message read --all --force to mark all unread (run `--all` alone first — dry run)
|
|
818
838
|
# Tip: default page is 10 newest-first — stale unread sorts LAST; use `thrum message search "<term>"` to find it
|
|
819
839
|
|
|
820
840
|
# 2. Orient from beads and git
|
|
@@ -75,8 +75,7 @@ where inlining is genuinely cheaper than the round-trip.
|
|
|
75
75
|
|
|
76
76
|
## Project-specific rules (already loaded)
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
`claude-plugin/commands/_project-rules-protocol.md`
|
|
78
|
+
Load the /thrum:project-rules-protocol skill and follow it.
|
|
80
79
|
|
|
81
80
|
If you accumulate a new rule mid-session (the user corrects you), capture it via
|
|
82
81
|
the `researcher-maintaining-memory` skill — it references the
|
|
@@ -24,16 +24,13 @@ specific symbol, or a specific question. Get a focused report back. For research
|
|
|
24
24
|
across N > 6 items, invoke `efficient-multi-agent-research` instead of bespoke
|
|
25
25
|
dispatch — it handles partition + parallelization + consolidation.
|
|
26
26
|
|
|
27
|
-
> **Model tiers:** pass an explicit `model:` on every dispatch
|
|
28
|
-
> (low effort) mechanical, `sonnet` (medium effort) judgment, Opus only on
|
|
29
|
-
> operator-ask or a skill step that names it. See the
|
|
30
|
-
> `choosing-subagent-models` skill for the full policy.
|
|
27
|
+
> **Model tiers:** pass an explicit `model:` on every dispatch; choose model and effort per the `choosing-subagent-models` skill (read `runtime.role_models` at the moment of use). Never let a sub-agent inherit your own model.
|
|
31
28
|
|
|
32
29
|
### Prefer `efficient-multi-agent-research` for multi-part research
|
|
33
30
|
|
|
34
31
|
When a research or investigation task has independent parts, reach for the
|
|
35
32
|
`efficient-multi-agent-research` skill FIRST — it partitions the work across
|
|
36
|
-
many cheap parallel subagents (
|
|
33
|
+
many cheap parallel subagents (cheap gatherers, judgment-tier synthesizers) instead of
|
|
37
34
|
one expensive serial subagent. It is the preferred research path: cheaper,
|
|
38
35
|
faster, and it keeps each subagent's context tight.
|
|
39
36
|
|
|
@@ -77,8 +74,8 @@ sessions and re-readable by other agents.
|
|
|
77
74
|
|
|
78
75
|
**How to apply:** After reporting to the requester, write the finding as a
|
|
79
76
|
`research_note` memory with cited file:line refs and a verification footer. Tag
|
|
80
|
-
with
|
|
81
|
-
`thrum memory search --tag
|
|
77
|
+
it with `--tag <slug>` so other agents can find it later via
|
|
78
|
+
`thrum memory search --tag <slug>`:
|
|
82
79
|
|
|
83
80
|
```bash
|
|
84
81
|
cat > /tmp/research-note-body.md <<EOF
|
|
@@ -88,19 +85,18 @@ Verified: $(date +%Y-%m-%d) @ $(git rev-parse HEAD)
|
|
|
88
85
|
EOF
|
|
89
86
|
thrum memory create --kind research_note --scope role \
|
|
90
87
|
--title "<finding prose, ~80 char soft limit>" \
|
|
91
|
-
--tag
|
|
88
|
+
--tag <slug> \
|
|
92
89
|
--oneline "<one-line summary>" \
|
|
93
90
|
--full "@/tmp/research-note-body.md"
|
|
94
91
|
```
|
|
95
92
|
|
|
96
93
|
`--full` here is multi-line prose — compose via heredoc or a captured
|
|
97
|
-
variable, never double-quoted inline like this; see your role preamble
|
|
98
|
-
PROSE INTO A COMMAND rule.
|
|
94
|
+
variable, never double-quoted inline like this; see the heredoc-or-file rule in your role preamble.
|
|
99
95
|
|
|
100
96
|
Then add one line to `.thrum/context/research.md` under Tracked Topics (note: `thrum queue` now supersedes free-text Open Questions tracking):
|
|
101
97
|
|
|
102
98
|
```markdown
|
|
103
|
-
-
|
|
99
|
+
- `<slug>` — <one-line description, ≤ 80 chars>
|
|
104
100
|
```
|
|
105
101
|
|
|
106
102
|
The full index format and staleness-check protocol live in
|
|
@@ -124,8 +120,7 @@ gaps — you surface them, the implementer ships them.
|
|
|
124
120
|
|
|
125
121
|
## Project-specific rules (already loaded)
|
|
126
122
|
|
|
127
|
-
|
|
128
|
-
`claude-plugin/commands/_project-rules-protocol.md`
|
|
123
|
+
Load the /thrum:project-rules-protocol skill and follow it.
|
|
129
124
|
|
|
130
125
|
If you accumulate a new rule mid-session (the user corrects you), capture it via
|
|
131
126
|
the `researcher-maintaining-memory` skill — it references the
|
|
@@ -158,7 +158,7 @@ thrum memory create --kind agent_rule --scope role \
|
|
|
158
158
|
```
|
|
159
159
|
|
|
160
160
|
`--short`/`--full` carry real prose — compose via heredoc or file, never
|
|
161
|
-
double-quoted inline; see
|
|
161
|
+
double-quoted inline; see the heredoc-or-file rule in your role preamble.
|
|
162
162
|
|
|
163
163
|
This is the SAME pattern as coordinator/implementer role-rule writes — see
|
|
164
164
|
`memory-write-discipline` for the canonical shape.
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Not user-invocable directly.
|
|
2
|
+
name: snapshot-protocol
|
|
3
|
+
description: "Use when composing a restart snapshot or continuation - snapshot structure, worktree resolution, write rules."
|
|
5
4
|
---
|
|
6
5
|
|
|
7
|
-
# Snapshot Composition Protocol (shared partial)
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
added or dropped. Note: plain `/thrum:restart` does NOT consume this partial; it
|
|
13
|
-
carries its own inline snapshot template.
|
|
7
|
+
# Snapshot Composition Protocol
|
|
8
|
+
Note: plain `/thrum:restart` carries its own inline snapshot template rather
|
|
9
|
+
than consuming this skill.
|
|
14
10
|
|
|
15
|
-
This is the canonical source-of-truth for snapshot composition discipline.
|
|
16
|
-
|
|
17
|
-
variant-specific terminal action. Do NOT invoke this file directly; it has no
|
|
11
|
+
This is the canonical source-of-truth for snapshot composition discipline.
|
|
12
|
+
Invoke this skill to compose a snapshot, then take the variant-specific
|
|
18
13
|
terminal action.
|
|
19
14
|
|
|
20
15
|
## Step 1 — Resolve identity and your worktree
|
|
21
16
|
|
|
22
17
|
```bash
|
|
23
18
|
# $REPO must be YOUR worktree — the directory `thrum prime` reads the restart
|
|
24
|
-
# snapshot back from. Resolve it
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
# snapshot back from. Resolve it ONLY via the daemon's authoritative,
|
|
20
|
+
# peercred-resolved identity (`thrum agent worktree --authoritative`) — NEVER
|
|
21
|
+
# via `thrum whoami --field worktree` (cwd-resolved) or `git rev-parse
|
|
22
|
+
# --show-toplevel` (also cwd-resolved). A cwd-derived pattern
|
|
23
|
+
# could silently resolve to a DIFFERENT agent's worktree, or the main repo,
|
|
24
|
+
# saving this snapshot where nothing ever reads it back. There is NO git
|
|
25
|
+
# fallback — if the daemon can't answer, refuse and stop rather than guess.
|
|
26
|
+
REPO=$(
|
|
27
|
+
thrum agent worktree --authoritative 2>/dev/null
|
|
28
|
+
) || { echo "ERROR: cannot authoritatively resolve your worktree via the daemon. Refusing to fall back to cwd/git-toplevel — that would risk silently saving this snapshot to the wrong repo. Check daemon connectivity and retry."; exit 1; }
|
|
29
|
+
[ -n "$REPO" ] || { echo "ERROR: thrum agent worktree --authoritative returned empty"; exit 1; }
|
|
30
30
|
AGENT=$(thrum whoami --field agent_id) || { echo "ERROR: agent not registered"; exit 1; }
|
|
31
31
|
[ -n "$AGENT" ] || { echo "ERROR: empty agent_id"; exit 1; }
|
|
32
32
|
mkdir -p "${REPO}/.thrum/restart"
|
|
@@ -66,14 +66,14 @@ shapes everything else you write below it.
|
|
|
66
66
|
|
|
67
67
|
**Stamp your snapshot with the base it was authored against.**
|
|
68
68
|
Derive and emit the **Authored-against** stamp per
|
|
69
|
-
|
|
69
|
+
the /thrum:stamp-protocol skill and place it at the very top of your
|
|
70
70
|
§1 section (that protocol computes the SHA and merge_target for you — never
|
|
71
71
|
hand-type them). This is what lets `thrum prime` diff your snapshot at the next
|
|
72
72
|
wake and flag which cited files have MOVED; an unstamped snapshot reads as
|
|
73
73
|
"current", indistinguishable from one that never drifted.
|
|
74
74
|
|
|
75
75
|
Any commit your snapshot names as its own stamped SHA must also be readable
|
|
76
|
-
under `
|
|
76
|
+
under `stamp-protocol.md`'s "Read-time provenance re-derivation" section
|
|
77
77
|
(SHA-resolves, then merge-status) — link to that section rather than restating
|
|
78
78
|
its checks here.
|
|
79
79
|
|
|
@@ -109,7 +109,7 @@ session's conversation context. Refer to the previous session in third person.
|
|
|
109
109
|
|
|
110
110
|
### Choose your structure
|
|
111
111
|
|
|
112
|
-
The variant skill that invoked this
|
|
112
|
+
The variant skill that invoked this skill tells you which structure to use:
|
|
113
113
|
|
|
114
114
|
- **`/thrum:sleep`** → use the STANDARD 11-section structure below.
|
|
115
115
|
- **`/thrum:restart-extended` and `/thrum:sleep-extended`** → use the EXTENDED
|
|
@@ -261,5 +261,11 @@ ${REPO}/.thrum/restart/${AGENT}.md
|
|
|
261
261
|
comes from `thrum tmux restart` or `thrum tmux create`). No bash heredoc or
|
|
262
262
|
`cat <<EOF` redirection is needed — write the file directly.
|
|
263
263
|
|
|
264
|
+
Variants that have a verify step (`/thrum:compact`, `/thrum:compact-extended`,
|
|
265
|
+
`/thrum:restart`, `/thrum:restart-extended`) mint a `SNAPSHOT_PATH` and
|
|
266
|
+
`SNAPSHOT_NONCE` in their own Step 3 PREP block: write to exactly that path, end
|
|
267
|
+
the file with `<!-- snapshot-nonce: <nonce> -->`, and record both for the verify
|
|
268
|
+
block. The sleep variants have no verify block and need no nonce.
|
|
269
|
+
|
|
264
270
|
After writing, return control to your variant skill (`/thrum:restart-extended`,
|
|
265
271
|
`/thrum:sleep`, or `/thrum:sleep-extended`) for the terminal action.
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
commands, and never-type rule. Not user-invocable directly.
|
|
2
|
+
name: stamp-protocol
|
|
3
|
+
description: "Use when stamping a plan, prompt, or snapshot - Authored-against format, derivation commands, never-type rule."
|
|
5
4
|
---
|
|
6
5
|
|
|
7
|
-
# Authored-against Stamp Protocol (shared partial)
|
|
8
6
|
|
|
7
|
+
# Authored-Against Stamp Protocol
|
|
9
8
|
This is the canonical source-of-truth for the Authored-against stamp: its format,
|
|
10
9
|
derivation commands, and the never-type rule. Consuming files point here instead of
|
|
11
|
-
restating the recipe. Do
|
|
12
|
-
(To find what currently points here: `grep -rn "
|
|
10
|
+
restating the recipe. Do not run this as a command; it has no terminal action — other skills and commands load it by name.
|
|
11
|
+
(To find what currently points here: `grep -rn "thrum:stamp-protocol" claude-plugin/commands/ claude-plugin/skills/`
|
|
13
12
|
— a hand-listed consumer roster in this file would rot the moment a new emitter or
|
|
14
13
|
reader is added, so none is kept here.)
|
|
15
14
|
|
|
@@ -46,8 +45,15 @@ diffs if the remote-tracking ref might be stale.
|
|
|
46
45
|
# SHA of the current HEAD
|
|
47
46
|
git rev-parse HEAD
|
|
48
47
|
|
|
49
|
-
# Configured merge target
|
|
50
|
-
|
|
48
|
+
# Configured merge target -- resolve through .thrum/redirect when present.
|
|
49
|
+
# A worktree's .thrum/ holds only a `redirect` file (a single line: the
|
|
50
|
+
# absolute path to the MAIN REPO'S .thrum directory itself), not its own
|
|
51
|
+
# config.json -- reading .thrum/config.json directly from a worktree
|
|
52
|
+
# silently returns empty. Root repos have no redirect file, so CONFIG falls
|
|
53
|
+
# through to the direct path.
|
|
54
|
+
CONFIG=".thrum/config.json"
|
|
55
|
+
[ -f .thrum/redirect ] && CONFIG="$(cat .thrum/redirect)/config.json"
|
|
56
|
+
jq -r '.orchestration.merge_target' "$CONFIG"
|
|
51
57
|
```
|
|
52
58
|
|
|
53
59
|
The author must never type or remember either value by hand — both come from the
|
|
@@ -8,8 +8,9 @@ license: "Apache-2.0"
|
|
|
8
8
|
|
|
9
9
|
# Thrum - Git-Backed Multi-Agent Coordination (Messaging, Groups, Shared Context)
|
|
10
10
|
|
|
11
|
-
Run `thrum prime` for full session context (auto-injected by
|
|
12
|
-
|
|
11
|
+
Run `thrum prime` for full session context (auto-injected by the SessionStart
|
|
12
|
+
hook; also fires on post-compact resume). PreCompact is not registered — use
|
|
13
|
+
`/thrum:compact` to save a snapshot before deliberately compacting.
|
|
13
14
|
|
|
14
15
|
## Quick Command Reference
|
|
15
16
|
|
|
@@ -17,19 +18,23 @@ SessionStart and PreCompact).
|
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
20
|
thrum send --to @name --body-file msg.md # Direct message (body from file)
|
|
20
|
-
thrum send --
|
|
21
|
-
thrum send --to @everyone --body-file msg.md # Broadcast (legacy keyword; --broadcast preferred)
|
|
21
|
+
thrum send --to @name1 --to @name2 --body-file msg.md # Multiple explicit recipients (repeatable --to)
|
|
22
22
|
thrum reply <msg-id> --body-file reply.md # Reply (same audience; NO --to — recipient comes from the message)
|
|
23
23
|
thrum inbox List messages (auto-marks displayed as read)
|
|
24
24
|
thrum inbox --unread Unread only (does not mark as read)
|
|
25
25
|
thrum message search "<term>" Full-text search — use instead of paging; stale unread sorts last
|
|
26
26
|
thrum sent List messages you sent
|
|
27
27
|
thrum sent --unread Sent messages with unread recipients
|
|
28
|
-
thrum message read --all
|
|
28
|
+
thrum message read --all --force Mark ALL unread as read (run `read --all` alone first — dry run)
|
|
29
29
|
thrum wait Block until message arrives (30s timeout)
|
|
30
30
|
thrum wait --timeout 120s Custom timeout (duration)
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
One-to-many fan-out (`--broadcast`, `@everyone`, role-based mentions/groups)
|
|
34
|
+
was removed by design (P0 ruling); do not restore it. Name
|
|
35
|
+
every recipient explicitly with repeatable `--to @name`, or address a scoped
|
|
36
|
+
agent-type group.
|
|
37
|
+
|
|
33
38
|
### Agents
|
|
34
39
|
|
|
35
40
|
```bash
|
|
@@ -140,8 +145,10 @@ processing. See [LISTENER_PATTERN.md](resources/LISTENER_PATTERN.md).
|
|
|
140
145
|
### Context Management
|
|
141
146
|
|
|
142
147
|
- `thrum prime` gathers identity, team, inbox, git context, sync health
|
|
143
|
-
- SessionStart hook auto-runs `thrum prime` on session start
|
|
144
|
-
-
|
|
148
|
+
- SessionStart hook auto-runs `thrum prime` on session start (including
|
|
149
|
+
post-compact resume)
|
|
150
|
+
- PreCompact is NOT registered — run `/thrum:compact` to save a restart
|
|
151
|
+
snapshot deliberately before compacting
|
|
145
152
|
- **After compaction:** run `/thrum:load-context` to restore your work context
|
|
146
153
|
- Agent identity persists in `.thrum/identities/`
|
|
147
154
|
|
|
@@ -26,9 +26,9 @@ Task(subagent_type="message-listener", run_in_background=true, prompt="...")
|
|
|
26
26
|
|
|
27
27
|
## 4. Sending Without an Explicit Recipient Flag
|
|
28
28
|
|
|
29
|
-
`thrum send 'msg'` with no `--to`
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
`thrum send 'msg'` with no `--to` is a hard error. The previous default —
|
|
30
|
+
silent broadcast to every team agent — was a real footgun, so the CLI now
|
|
31
|
+
requires the recipient to be explicit:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
# Wrong — hard-errors with a "missing recipient" prompt
|
|
@@ -39,19 +39,15 @@ thrum send --to @your_coordinator --stdin <<'EOF'
|
|
|
39
39
|
msg
|
|
40
40
|
EOF
|
|
41
41
|
|
|
42
|
-
# Right — explicit
|
|
43
|
-
thrum send --
|
|
44
|
-
msg
|
|
45
|
-
EOF
|
|
46
|
-
|
|
47
|
-
# Right — legacy keyword form (still works; --broadcast preferred)
|
|
48
|
-
thrum send --to @everyone --stdin <<'EOF'
|
|
42
|
+
# Right — repeatable --to for multiple explicit recipients
|
|
43
|
+
thrum send --to @alice --to @bob --stdin <<'EOF'
|
|
49
44
|
msg
|
|
50
45
|
EOF
|
|
51
46
|
```
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
(P0 ruling): `--broadcast` and `@everyone` were removed by
|
|
49
|
+
design; do not restore them. There is no team-wide fanout — name every
|
|
50
|
+
recipient explicitly, or address a scoped agent-type group.
|
|
55
51
|
|
|
56
52
|
## 5. Skipping Registration
|
|
57
53
|
|
|
@@ -102,14 +98,16 @@ finishing the main task.
|
|
|
102
98
|
Include Beads IDs, file paths, commit hashes — anything that helps the recipient
|
|
103
99
|
act on the message.
|
|
104
100
|
|
|
105
|
-
## 12.
|
|
101
|
+
## 12. Assuming @role Fans Out to a Role's Agents
|
|
106
102
|
|
|
107
|
-
**Wrong:** `thrum send --to @implementer --body-file msg.md`
|
|
108
|
-
|
|
109
|
-
agent's name.
|
|
103
|
+
**Wrong:** assuming `thrum send --to @implementer --body-file msg.md` reaches
|
|
104
|
+
every implementer. **Right:** `thrum send --to @alice --body-file msg.md` —
|
|
105
|
+
use the agent's name.
|
|
110
106
|
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
(P0 ruling): role-based mention/group fan-out was removed by
|
|
108
|
+
design; do not restore it. `--to` and `--mention` only resolve exact agent
|
|
109
|
+
IDs — `@implementer` matches nobody unless an agent is literally named
|
|
110
|
+
`implementer`. Use `@name` for direct messages. Check names with
|
|
113
111
|
`thrum team`.
|
|
114
112
|
|
|
115
113
|
## 13. Sending to Unknown Recipients
|
|
@@ -60,20 +60,23 @@ Full reference: [docs/cli-hints.md](https://thrum.team/docs/cli-hints.html)
|
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
62
|
thrum send --to @name --body-file ./body.md # Direct message (canonical form)
|
|
63
|
-
thrum send --
|
|
64
|
-
thrum send --to @everyone --body-file ./body.md # Broadcast (legacy keyword form)
|
|
63
|
+
thrum send --to @name1 --to @name2 --body-file ./body.md # Multiple explicit recipients (repeatable --to)
|
|
65
64
|
thrum send --to @name --scope type:value --scope type:value2 --body-file ./body.md
|
|
66
65
|
thrum send --to @name --ref type:value --body-file ./body.md
|
|
67
|
-
thrum send --to @name --mention @
|
|
66
|
+
thrum send --to @name --mention @other_agent --body-file ./body.md
|
|
68
67
|
thrum send --to @name --format plain --body-file ./body.md
|
|
69
68
|
thrum send --to @name --structured '{"key":"value"}' --body-file ./body.md
|
|
70
69
|
thrum send --to @name --body-file ./body.md # Shell-safe body (file)
|
|
71
70
|
generator | thrum send --to @name - # '-' is a --stdin alias
|
|
72
71
|
```
|
|
73
72
|
|
|
74
|
-
A recipient flag is REQUIRED — `thrum send 'msg'` with no `--to`
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
A recipient flag is REQUIRED — `thrum send 'msg'` with no `--to` is a hard
|
|
74
|
+
error.
|
|
75
|
+
|
|
76
|
+
(P0 ruling): `--broadcast` and `@everyone` were removed by
|
|
77
|
+
design across the whole product; do not restore them. There is no one-to-many
|
|
78
|
+
fan-out — name every recipient explicitly with repeatable `--to`, or address a
|
|
79
|
+
scoped agent-type group.
|
|
77
80
|
|
|
78
81
|
Shell-safe bodies: backticks, `$(...)`, `$VAR`, and quotes in a
|
|
79
82
|
double-quoted message are interpreted by the shell BEFORE thrum runs, silently
|
|
@@ -85,9 +88,8 @@ trailing newline is stripped from stdin/file bodies.
|
|
|
85
88
|
Flags:
|
|
86
89
|
|
|
87
90
|
```text
|
|
88
|
-
--to
|
|
89
|
-
--
|
|
90
|
-
--mention strings Mention a role (repeatable, format: @role)
|
|
91
|
+
--to strings Recipient — @agent_name, explicit only (repeatable; no @everyone/@role fan-out)
|
|
92
|
+
--mention strings Mention an explicit agent (repeatable, format: @agent_name)
|
|
91
93
|
--ref strings Add reference (repeatable, format: type:value)
|
|
92
94
|
--scope strings Add scope (repeatable, format: type:value)
|
|
93
95
|
--format string Message format: markdown, plain, json (default "markdown")
|
|
@@ -198,7 +200,9 @@ thrum message edit <msg-id> --body-file ./new-body.md # Full replacement (autho
|
|
|
198
200
|
thrum message edit <msg-id> --body-file ./new.md # Full replacement from file
|
|
199
201
|
thrum message delete <msg-id> --force # Delete (--force required)
|
|
200
202
|
thrum message read <msg-id> [<msg-id>...] # Mark as read
|
|
201
|
-
thrum message read --all #
|
|
203
|
+
thrum message read --all # DRY RUN: list what --apply/--force would mark, marks nothing
|
|
204
|
+
thrum message read --all --apply # Mark the shown (already-seen) candidates
|
|
205
|
+
thrum message read --all --force # Mark ALL unread, seen or not (needs a fresh `--all` dry run first)
|
|
202
206
|
thrum message search "<term>" # Full-text search across all messages (see § inbox above)
|
|
203
207
|
thrum message reindex # Rebuild the FTS index if search looks wrong
|
|
204
208
|
```
|
|
@@ -214,7 +218,9 @@ Subcommand flags:
|
|
|
214
218
|
--force Confirm deletion (required)
|
|
215
219
|
|
|
216
220
|
# message read
|
|
217
|
-
--all
|
|
221
|
+
--all List seen+unread candidates (dry run); combine with --apply or --force to mark
|
|
222
|
+
--apply With --all: mark the shown (already-seen) candidates
|
|
223
|
+
--force With --all: mark ALL unread, seen or not (needs a fresh --all dry run first)
|
|
218
224
|
```
|
|
219
225
|
|
|
220
226
|
---
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
> at zero token cost with no background listener needed. See
|
|
5
5
|
> [TMUX_SESSIONS.md](TMUX_SESSIONS.md). Use the listener pattern below when tmux
|
|
6
6
|
> is not available or not practical for your setup.
|
|
7
|
+
>
|
|
8
|
+
> **Deprecated for newly initialized agents:** the hook injection and
|
|
9
|
+
> scheduled backstop that `thrum init` installs deliver message nudges without a
|
|
10
|
+
> listener. The pattern below still works and is supported, but it holds tokens in
|
|
11
|
+
> the agent's context for the entire session. Cross-runtime agents (codex, cursor,
|
|
12
|
+
> etc.) without hook support still use it.
|
|
7
13
|
|
|
8
14
|
The message-listener is a background sub-agent that blocks on `thrum wait` and
|
|
9
15
|
returns when messages arrive. A PID file (`.thrum/var/<agent_id>-listener.pid`)
|
|
@@ -14,7 +20,7 @@ prevents duplicate listeners — spawning when one is already running is safe.
|
|
|
14
20
|
```text
|
|
15
21
|
Task(
|
|
16
22
|
subagent_type="message-listener",
|
|
17
|
-
model="
|
|
23
|
+
model="<per choosing-subagent-models>", # cheapest tier
|
|
18
24
|
prompt="Listen for Thrum messages.\nSTEP_1: /path/to/repo/scripts/thrum-startup.sh --listener-heartbeat\nSTEP_2: thrum wait --timeout 8m --after -15s --agent-name <agent_id>"
|
|
19
25
|
)
|
|
20
26
|
```
|
|
@@ -49,7 +55,7 @@ Automatically respawn the listener if it dies or is lost after compaction.
|
|
|
49
55
|
```text
|
|
50
56
|
CronCreate(
|
|
51
57
|
cron="*/30 * * * *",
|
|
52
|
-
prompt="Check the listener PID file at .thrum/var/<agent_id>-listener.pid.\nIf the file does not exist, or if kill -0 <pid> fails (process not running),\nspawn a new listener:\n\nAgent(subagent_type=\"message-listener\", model=\"
|
|
58
|
+
prompt="Check the listener PID file at .thrum/var/<agent_id>-listener.pid.\nIf the file does not exist, or if kill -0 <pid> fails (process not running),\nspawn a new listener:\n\nAgent(subagent_type=\"message-listener\", model=\"<per choosing-subagent-models>\", prompt=\"Listen for Thrum messages.\\nSTEP_1: /path/to/repo/scripts/thrum-startup.sh --listener-heartbeat\\nSTEP_2: thrum wait --timeout 8m --after -15s --agent-name <agent_id>\")"
|
|
53
59
|
)
|
|
54
60
|
```
|
|
55
61
|
|
|
@@ -60,5 +66,5 @@ Spawn the initial listener on session start, then create the cron watchdog.
|
|
|
60
66
|
- **Spawn freely** — PID file prevents duplicates
|
|
61
67
|
- **Return immediately** when messages arrive (don't wait for more)
|
|
62
68
|
- **Read-only** — the listener never sends messages
|
|
63
|
-
- **Cost-efficient** — runs on
|
|
69
|
+
- **Cost-efficient** — runs on a cheap tier, blocks instead of polling
|
|
64
70
|
- Listener uses CLI only (`Bash` tool), not MCP tools
|