opencode-thrum-pro 0.1.6 → 0.1.8

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.
Files changed (74) hide show
  1. package/assets/commands/thrum-compact-extended.md +36 -21
  2. package/assets/commands/thrum-compact.md +19 -18
  3. package/assets/commands/thrum-restart-extended.md +1 -5
  4. package/assets/commands/thrum-restart.md +2 -2
  5. package/assets/commands/thrum-sleep-extended.md +1 -5
  6. package/assets/commands/thrum-sleep.md +1 -5
  7. package/assets/commands/thrum-update-project.md +1 -1
  8. package/assets/skills/brainstorm-queue-aware/SKILL.md +1 -1
  9. package/assets/skills/brainstorm-steward/SKILL.md +3 -3
  10. package/assets/skills/choosing-subagent-models/SKILL.md +183 -74
  11. package/assets/skills/closing-findings-while-warm/SKILL.md +1 -2
  12. package/assets/skills/configure-roles/SKILL.md +2 -2
  13. package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +11 -10
  14. package/assets/skills/coordinator-branch-split-on-block/SKILL.md +1 -2
  15. package/assets/skills/coordinator-context-monitoring/SKILL.md +11 -12
  16. package/assets/skills/coordinator-deploying-a-node/SKILL.md +3 -1
  17. package/assets/skills/coordinator-dispatching-work/SKILL.md +5 -4
  18. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +9 -7
  19. package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +1 -2
  20. package/assets/skills/coordinator-maintaining-memory/SKILL.md +1 -1
  21. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +10 -3
  22. package/assets/skills/coordinator-merging-code/SKILL.md +21 -14
  23. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +4 -5
  24. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +1 -2
  25. package/assets/skills/coordinator-rolling-out-to-nodes/SKILL.md +1 -0
  26. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +4 -5
  27. package/assets/skills/coordinator-running-review-cycles/SKILL.md +1 -2
  28. package/assets/{commands/thrum-_deviations-protocol.md → skills/deviations-protocol/SKILL.md} +6 -12
  29. package/assets/skills/efficient-multi-agent-research/SKILL.md +2 -2
  30. package/assets/skills/generator-idempotency-protocol/SKILL.md +9 -0
  31. package/assets/skills/implementer-maintaining-memory/SKILL.md +3 -4
  32. package/assets/skills/implementer-orchestrating-execution/SKILL.md +1 -2
  33. package/assets/skills/implementer-receiving-dispatch/SKILL.md +15 -17
  34. package/assets/skills/implementer-receiving-review-feedback/SKILL.md +3 -4
  35. package/assets/skills/implementer-status-and-handoff/SKILL.md +1 -14
  36. package/assets/skills/implementer-tdd-and-quality/SKILL.md +2 -2
  37. package/assets/skills/memory-audit-recover/SKILL.md +7 -5
  38. package/assets/skills/memory-curate/SKILL.md +3 -3
  39. package/assets/skills/memory-maintenance/SKILL.md +2 -0
  40. package/assets/skills/memory-write-discipline/SKILL.md +1 -1
  41. package/assets/skills/orchestrate/SKILL.md +34 -5
  42. package/assets/skills/persistent-watcher-archetype/SKILL.md +2 -2
  43. package/assets/skills/persistent-watcher-archetype/resources/jev_watcher_filter.py +5 -5
  44. package/assets/skills/persistent-watcher-archetype/resources/roster-watch.sh +5 -5
  45. package/assets/skills/persistent-watcher-archetype/resources/roster-watch_test.sh +2 -2
  46. package/assets/skills/persistent-watcher-archetype/resources/thrum-capture-fallback.sh +1 -1
  47. package/assets/skills/persistent-watcher-archetype/resources/thrum-watch-pane-capture.sh +3 -3
  48. package/assets/skills/prime-agent/SKILL.md +1 -1
  49. package/assets/skills/project-hotpath-gate/SKILL.md +1 -2
  50. package/assets/skills/project-philosophy/SKILL.md +2 -3
  51. package/assets/skills/project-rules-protocol/SKILL.md +12 -0
  52. package/assets/skills/project-setup/SKILL.md +9 -10
  53. package/assets/skills/project-setup/resources/implementation-agent.md +1 -2
  54. package/assets/skills/researcher-answering-queries/SKILL.md +1 -2
  55. package/assets/skills/researcher-investigating/SKILL.md +6 -8
  56. package/assets/skills/researcher-maintaining-memory/SKILL.md +3 -1
  57. package/assets/{commands/thrum-_snapshot-protocol.md → skills/snapshot-protocol/SKILL.md} +10 -15
  58. package/assets/{commands/thrum-_stamp-protocol.md → skills/stamp-protocol/SKILL.md} +5 -6
  59. package/assets/skills/thrum/SKILL.md +9 -4
  60. package/assets/skills/thrum/resources/CLI_REFERENCE.md +32 -27
  61. package/assets/skills/thrum-memory/SKILL.md +1 -1
  62. package/assets/skills/using-monitors/SKILL.md +198 -0
  63. package/assets/skills/using-the-queue/SKILL.md +2 -3
  64. package/assets/skills/using-thrum-state/SKILL.md +3 -3
  65. package/assets/skills/verify-against-plan/SKILL.md +2 -2
  66. package/dist/hooks/block-sync-cd.js +1 -1
  67. package/dist/hooks/block-sync-cd.test.js +1 -1
  68. package/dist/installer-assets.test.d.ts +1 -0
  69. package/dist/installer-assets.test.js +41 -0
  70. package/package.json +1 -1
  71. package/assets/commands/thrum-_compact-runtime-commands.md +0 -61
  72. package/assets/commands/thrum-_generator-idempotency-protocol.md +0 -15
  73. package/assets/commands/thrum-_project-rules-protocol.md +0 -18
  74. package/assets/commands/thrum-_verify-before-write-protocol.md +0 -27
@@ -255,7 +255,7 @@ Flags:
255
255
  --runtime string Runtime preset: claude, codex, cursor, gemini, opencode, auggie, cli-only
256
256
  --preamble-file string Custom preamble file to compose with default preamble
257
257
  --no-init Skip runtime config generation, just register agent
258
- --force Overwrite existing runtime config files
258
+ --force Force runtime config reinitialization; project instruction files are preserved
259
259
  --dry-run Preview changes without writing files or registering
260
260
  --no-agent-pid Persist agent_pid=0 instead of detecting the runtime ancestor; defers PID claim to first /thrum:prime (used for inline tmux quickstart)
261
261
  ```
@@ -379,6 +379,10 @@ thrum agent delete <name>
379
379
  thrum agent delete coordinator_1B9K --force
380
380
  ```
381
381
 
382
+ Refuses an agent whose linked worktree still exists (run `worktree teardown`
383
+ first), a live pid/tmux process, and coordinators. Order: teardown (with
384
+ salvage), then delete.
385
+
382
386
  Flags:
383
387
 
384
388
  ```text
@@ -858,7 +862,7 @@ thrum tmux cancel <command-id> # Cancel a queued or active comma
858
862
  --intent string Initial work intent description
859
863
  --runtime string Runtime preset: claude, codex, cursor, gemini, opencode, auggie
860
864
  --no-agent Skip agent registration (create session only)
861
- --force Overwrite existing runtime config files
865
+ --force Re-register even if agent exists; kill and recreate an existing session
862
866
  ```
863
867
 
864
868
  Without `--no-agent`, the command errors if `--name`, `--role`, and `--module`
@@ -900,7 +904,7 @@ thrum worktree create <name> --detach # Detached HEAD worktree
900
904
  thrum worktree create <name> \
901
905
  --name <agent> --role <role> --module <mod> # Create worktree + register agent
902
906
  thrum worktree setup <name> # Alias for worktree create
903
- thrum worktree teardown <name> # Remove worktree, keep branch
907
+ thrum worktree teardown <name> # Retire agent + remove worktree, keep branch (does NOT delete the agent; reap with `thrum agent delete` after)
904
908
  thrum worktree teardown <name> --delete-branch # Also delete the worktree's branch
905
909
  thrum worktree list # List worktrees with agent info
906
910
  ```
@@ -939,51 +943,52 @@ later.
939
943
 
940
944
  ## Monitor Jobs
941
945
 
942
- Run a long-lived command, filter output through a regex, and deliver matching
943
- lines as Thrum messages. Jobs persist across daemon restarts. Max 100
944
- concurrent. The command must follow `--`.
946
+ Run a command, filter its output through a regex, and deliver matching lines as
947
+ Thrum messages. Without `--schedule` the command runs continuously and restarts
948
+ with backoff; with `--schedule` it runs once per cron tick. Jobs persist across
949
+ daemon restarts. Max 100 concurrent. The command must follow `--`.
945
950
 
946
951
  ```bash
947
952
  thrum monitor start --name <n> --match <re> --to @agent -- <cmd> [args...]
948
953
  thrum monitor start --name <n> --match <re> --to @agent \
949
- --debounce 120s --env KEY=VALUE -- <cmd>
954
+ --schedule "*/5 * * * *" --notify-on-success --debounce 120s --env KEY=VALUE -- <cmd>
950
955
  thrum monitor list # Running jobs only
951
956
  thrum monitor list --all # Include stopped/dead (<1 week)
952
957
  thrum monitor show <id|name> # Full detail (env values redacted)
953
- thrum monitor stop <id|name> # SIGTERM → 5s → SIGKILL
954
- thrum monitor logs <id|name> # Last 20 matched lines
955
- thrum monitor logs <id|name> -n 50 # Last 50 matched lines
958
+ thrum monitor logs <id|name> -n 50 # Last 50 matched lines (default 20)
959
+ thrum monitor update <id|name> --match <re> # Change match/schedule/target/debounce in place
960
+ thrum monitor stop <id|name> # SIGTERM, 5s, SIGKILL
956
961
  thrum monitor restart <id|name> # Restart dead/stopped monitor
962
+ thrum monitor delete <id|name> # Remove the record and free the name
963
+ thrum monitor adopt <id|name> # Claim a monitor for this daemon
957
964
  ```
958
965
 
959
- Note: `monitor add` is retained as an alias for `monitor start`.
966
+ `monitor add` is an alias for `monitor start`.
960
967
 
961
968
  `monitor start` flags:
962
969
 
963
970
  ```text
964
971
  --name string Unique monitor name (required)
965
- --match string Regex pattern — matching lines trigger a message (required)
972
+ --match string Regex pattern - matching lines trigger a message (required)
966
973
  --to string Target agent or group, e.g. @coordinator (required)
967
- --debounce duration Leading-edge debounce window, minimum 30s (default 60s)
968
- --env strings Environment variable in KEY=VALUE form (repeatable)
974
+ --schedule string 5-field cron expression; runs the command once per tick
975
+ --notify-on-success Deliver a generic [OK] message for a successful run in which no line matched
976
+ --debounce duration Leading-edge debounce window, minimum 30s (default 1m)
977
+ --env stringArray Environment variable in KEY=VALUE form (repeatable)
969
978
  --cwd string Working directory for the command (default: current dir)
970
979
  ```
971
980
 
972
- `monitor list` flags:
973
-
974
- ```text
975
- --all Include stopped/dead monitors younger than one week
976
- ```
981
+ `monitor update` flags: `--match`, `--to`, `--schedule`, `--debounce`.
982
+ `--schedule` changes the cron of a scheduled monitor at any time; setting or
983
+ removing a schedule switches the mode, which is refused while the monitor is
984
+ running and allowed while it is stopped.
977
985
 
978
- `monitor logs` flags:
979
-
980
- ```text
981
- -n, --limit int Max number of matches to return (default 20)
982
- ```
986
+ `monitor logs` flag: `-n, --limit int` (default 20).
983
987
 
984
- Key constraints: local Unix socket only, max line length 2KB (lines truncated),
985
- leading-edge debounce (min 30s), auto-persists across daemon restart, sends a
986
- notify-only message on child exit.
988
+ Key constraints: local Unix socket only, lines over 2KB are truncated with a
989
+ marker, one matching line is delivered per debounce window, and a message is
990
+ sent when the child exits non-zero. See the `using-monitors` skill for
991
+ reminders, script checks and delivery rules.
987
992
 
988
993
  ---
989
994
 
@@ -70,7 +70,7 @@ thrum memory edit <id> --short @newshort.md
70
70
  thrum memory edit <id> --add-tag v0.11 --rm-tag draft
71
71
  ```
72
72
 
73
- Link an edge:
73
+ Link an edge. `memory create`, `edit` and `link` need a license (memory.substrate); reads, `delete`, `purge` and `unlink` do not.
74
74
 
75
75
  ```bash
76
76
  thrum memory link <new-id> supersedes <old-id>
@@ -0,0 +1,198 @@
1
+ ---
2
+ name: using-monitors
3
+ description: "Use when scheduling a reminder, watching a log, or running a periodic check that must reach an agent - thrum monitor start, cron --schedule, --match, --notify-on-success, --debounce, recurring nudge, script check with exit codes, why a monitor message did not arrive, how to verify a monitor delivered."
4
+ ---
5
+
6
+ # Thrum Monitors - Reminders And Script Checks
7
+
8
+ ## Overview
9
+
10
+ A monitor runs a command, keeps the output lines that match a regex, and
11
+ delivers them as Thrum messages to a target: a continuous monitor sends each
12
+ kept line, a scheduled monitor sends all the lines of a run in one message. With
13
+ `--schedule` it runs the command once per cron tick; without it the command runs continuously
14
+ and restarts with backoff when it exits. Monitors persist across daemon
15
+ restarts and run only on the daemon that owns them.
16
+
17
+ Every flag below appears in `thrum monitor start --help`. Re-read the help
18
+ before relying on a flag not listed here.
19
+
20
+ ## Command Surface
21
+
22
+ ```bash
23
+ thrum monitor start --name <n> --match <re> --to @agent [--schedule "<cron>"] \
24
+ [--notify-on-success] [--debounce 60s] [--env K=V] [--cwd <dir>] -- <cmd> [args...]
25
+ thrum monitor list [--all]
26
+ thrum monitor show <name|id>
27
+ thrum monitor logs <name|id> [-n 50]
28
+ thrum monitor update <name|id> [--match <re>] [--to <t>] [--debounce <d>] [--schedule "<cron>"]
29
+ thrum monitor stop <name|id>
30
+ thrum monitor restart <name|id>
31
+ thrum monitor delete <name|id>
32
+ ```
33
+
34
+ - `--name`, `--match` and `--to` are required; the command follows `--`.
35
+ - `--schedule` takes a 5-field cron expression. `update --schedule` changes the
36
+ cron of a scheduled monitor at any time. Setting a first schedule or removing
37
+ it (`--schedule ""`) switches the mode, which is refused while the monitor is
38
+ running and allowed while it is stopped.
39
+ - `--debounce` is leading-edge with a 30s minimum (default 1m).
40
+ - `stop` leaves a stopped record that still holds the name; `delete` frees the
41
+ name. Use a unique name per monitor.
42
+
43
+ ## What Is Delivered
44
+
45
+ Each output line is tested against `--match` on its own. A line is truncated at
46
+ 2048 bytes with a marker appended.
47
+
48
+ A scheduled (`--schedule`) job is a one-shot run, so its exit code is
49
+ authoritative. It delivers ONE message at exit that carries every matched line,
50
+ in order. A continuous job has no exit code per line, so it classifies and
51
+ delivers and classifies each matched line on its own, by its words.
52
+
53
+ | Scheduled job | Delivered as |
54
+ | --------------------------------------------------------------- | --------------------------------------------- |
55
+ | Non-zero exit, or the command failed to start | `[FAIL] <name>: exit code N` with the output tail, then the matched lines |
56
+ | Exit 0, a matched line starts `ERROR:`, `FATAL:` or `FAIL:` | `[FAIL] <name>: matched error pattern` + all matched lines |
57
+ | Exit 0, highest prefix is `WARN:`, `WARNING:` or `ALERT:` | `[WARN] <name>: matched WARNING` + all matched lines |
58
+ | Exit 0, lines matched, no such prefix | All matched lines, in order, verbatim |
59
+ | Exit 0, nothing matched, `--notify-on-success` | `[OK] <name>: succeeded` |
60
+ | Exit 0, nothing matched | Nothing (logged only) |
61
+
62
+ Cadence: the first non-zero scheduled run sends its `[FAIL]` notice; repeats of
63
+ that failure are not sent again until the outcome changes or the re-escalation
64
+ interval (30 minutes) passes. An exit-0 run that matched lines sends its message
65
+ on every run.
66
+
67
+ On a scheduled job only these prefixes, at the very start of a line, label the
68
+ output, with the colon directly after the word: `ERROR:`, `FATAL:` and `FAIL:`
69
+ fail it; `WARN:`, `WARNING:` and `ALERT:` warn. Any other prefix, including
70
+ `ALERT-<NAME>:`, `ERROR :`, `INFO:`, `OK:`, `NOT_OK:` and lowercase forms, is
71
+ neutral. They are read before any wording in the body, and
72
+ the highest one decides the label. Words such as `done`, `ok`, `complete`, `failures` or `error` neither
73
+ drop nor relabel a line, and `WARN: batch not complete` stays a warning.
74
+ `--notify-on-success` adds the generic `[OK]` only for a run in which nothing
75
+ matched; an empty matched line counts as a match and is announced as
76
+ `[matched N empty line(s)]`.
77
+
78
+ The whole message, including its label and framing, never exceeds the daemon's
79
+ configured message-body limit. Matched lines are sent whole while they fit both
80
+ budgets: the in-memory retention budget (each line costs its bytes plus a small
81
+ fixed overhead, so a line close to the limit, or many short lines, can be cut
82
+ or omitted earlier than their plain total would suggest) and the final rendered
83
+ message including its label. Lines that do not fit are replaced by `[N more
84
+ matched lines omitted]`, and a first line that does not fit is cut and
85
+ marked. The limit is never below 1024 bytes (the configuration floor), enough for
86
+ the framing and an omission marker with ordinary job names; when variable
87
+ framing such as a very long job name does not fit, the monitor sends a bounded
88
+ summary that starts with `+N omitted` instead of the lines. A run keeps only a bounded prefix of its lines in memory (at most
89
+ the delivery limit, or 1 MiB when the limit is disabled, counting a small fixed
90
+ overhead per line) but
91
+ counts every match, so the omitted count is exact and an `ERROR:`/`WARN:` line
92
+ past the retained prefix still sets the label.
93
+
94
+ | Continuous job (no `--schedule`) | Delivered as |
95
+ | --------------------------------------------------------------- | --------------------------------------------- |
96
+ | Contains `error`, `fatal`, `fail`, `permission denied` | `[FAIL] <name>: matched error pattern` + line |
97
+ | Contains `warn` or `warning` | `[WARN] <name>: matched WARNING` + line |
98
+ | Contains a whole word `success`, `succeeded`, `complete`, `completed`, `done`, `ok` | Not delivered (logged only) |
99
+ | Any other matched line | The line, verbatim |
100
+
101
+ A continuous job checks a line for a negated completion word (`not complete`)
102
+ first, then for a level prefix (`ERROR:`, `WARN:`, `INFO:`, optionally after a
103
+ timestamp), then for the words above. Tokens such as `fail=0` are not failures;
104
+ the phrase `0 errors` still contains `error`.
105
+
106
+ Delivery limits:
107
+
108
+ - A continuous job delivers the first matching line in each debounce window at
109
+ once and holds later ones for a trailing summary. A scheduled job has no
110
+ debounce; its lines are aggregated as above.
111
+ - The `[FAIL]` body for a non-zero exit carries only the last 500 bytes of
112
+ output, so the message that matters goes last.
113
+
114
+ ## Prompt-Only Reminder
115
+
116
+ A reminder is a monitor whose command only prints a fixed line. Give the line a
117
+ stable prefix and match exactly that prefix.
118
+
119
+ ```bash
120
+ thrum monitor start --name standup-nudge --to @me \
121
+ --match '^REMINDER-STANDUP:' --schedule "0 9 * * 1-5" -- \
122
+ echo "REMINDER-STANDUP: post the status update, then reply to the open review"
123
+ ```
124
+
125
+ - Schedule the reminder; words in its text, including "failures", "error" and
126
+ "done", then neither relabel nor drop it, and the exit code decides success.
127
+ - Make the body an instruction with the next concrete step; a bare "reminder"
128
+ carries no action.
129
+ - Add `--notify-on-success` only when a delivered line must be guaranteed for a
130
+ run that matched nothing.
131
+ - A delivered reminder shows the schedule fired. It does not show that the work
132
+ moved. Check the work itself (commits, queue, state) before treating the
133
+ reminder as progress.
134
+
135
+ ## Script Check
136
+
137
+ A script check runs a bounded, synchronous probe and reports through its exit
138
+ code and one structured line.
139
+
140
+ ```bash
141
+ thrum monitor start --name disk-check --to @me \
142
+ --match '^CHECK-DISK:' --schedule "*/15 * * * *" -- \
143
+ bash -c 'u=$(df --output=pcent / | tail -1 | tr -dc 0-9)
144
+ [ "$u" -lt 90 ] && exit 0
145
+ echo "CHECK-DISK: root volume at ${u} percent used, free space then rerun df -h /"
146
+ exit 3'
147
+ ```
148
+
149
+ Rules:
150
+
151
+ 1. Bound every probe with `timeout <secs>`; a hung probe holds the tick.
152
+ 2. Exit 0 for healthy and print nothing matching, which keeps the run quiet.
153
+ 3. Exit non-zero for a failure; the daemon sends the `[FAIL]` notice with the
154
+ exit code and output tail.
155
+ 4. Print a matching line that names the subject, the observed value and the
156
+ next action. A generic `OK` or `done` line carries no information.
157
+ 5. Use a distinct stable prefix per outcome (`CHECK-DISK:` for a finding,
158
+ `REMINDER-DISK:` for a nudge) so `--match` selects what must reach the
159
+ target.
160
+
161
+ | Outcome | Script does | Target receives |
162
+ | -------- | ---------------------------------------- | ---------------------------------- |
163
+ | Quiet | Exit 0, no matching line | Nothing |
164
+ | Failure | Non-zero exit, finding line last | One `[FAIL] <name>: exit code N` message with the tail and the finding line |
165
+ | Finding | Exit 0, matching line(s) | The line(s), verbatim (labeled only by an `ERROR:`/`FATAL:`/`FAIL:` or `WARN:`/`WARNING:`/`ALERT:` prefix) |
166
+ | Reminder | Exit 0, one stable-prefix instruction | The line, verbatim |
167
+
168
+ A `--match` that never matches the script's real output delivers nothing and
169
+ raises no error. Test the regex against the exact output before starting.
170
+
171
+ ## Verify By Delivery
172
+
173
+ Start the monitor with a unique name, `--to` the verifying agent, and a
174
+ one-minute schedule, then read the delivered message back in full.
175
+
176
+ ```bash
177
+ thrum monitor start --name verify-<unique> --to @me --match '^VERIFY-<unique>:' \
178
+ --schedule "* * * * *" -- echo "VERIFY-<unique>: delivery body check"
179
+ thrum inbox --unread
180
+ thrum message get <message-id> # the complete delivered body
181
+ thrum monitor logs verify-<unique> # the matches the daemon recorded
182
+ thrum monitor delete verify-<unique>
183
+ ```
184
+
185
+ Confirm the body carries the prefix, the wording and no unexpected `[FAIL]`
186
+ or `[WARN]` label. Delete the monitor when done; never alter a monitor another
187
+ agent owns.
188
+
189
+ ## Troubleshooting
190
+
191
+ - Nothing arrived: `thrum monitor show` for state and last exit, `thrum
192
+ monitor logs` for recorded matches. No recorded match means the regex did not
193
+ match, or (continuous job) the line was completion-classified and suppressed;
194
+ run the command by hand and compare its output with the regex.
195
+ - Message labeled `[FAIL]` unexpectedly: the job exited non-zero, the line starts
196
+ with `ERROR:`/`FATAL:`/`FAIL:`, or (continuous job) the line contains a fail or
197
+ error substring.
198
+ - Name already in use: a stopped record holds it. `thrum monitor delete` it.
@@ -191,7 +191,7 @@ so this wrapper is defense-in-depth, not load-bearing on its own.
191
191
  non-peercred transport (browser/WS, unit tests) - but that is a general,
192
192
  already-documented property of the RPC layer (identity trust depends on
193
193
  transport), not something unique to `state.set`, and it is explicitly out
194
- of scope per `docs/security_model/master.md` §1.5: "Thrum does not attempt
194
+ of scope per the project's security model: "Thrum does not attempt
195
195
  to prevent agent identity forgery" is an owner ruling, stated as
196
196
  [INTENDED] and permanent, not tracked as debt.
197
197
 
@@ -204,8 +204,7 @@ shapes, chosen by domain, not an oversight.
204
204
 
205
205
  Non-goal: fail-closed reject-symmetry for `state.set` (mirroring queue's
206
206
  `RejectIdentityKeysHandler`) is a possible future non-security hardening
207
- preference, not built here - out of scope per `docs/security_model/master.md`
208
- §1.5.
207
+ preference, not built here - out of scope per the project's security model.
209
208
 
210
209
  ## Common Mistakes
211
210
 
@@ -42,8 +42,8 @@ time** — writing a fleet row without a fresh by-effect check, even to
42
42
  ## Reconcile, don't just read
43
43
 
44
44
  - **Agent-local** (all roles): check at session start
45
- (`thrum state list`), update as you go. Carried-over state is NOT
46
- auto-injected into prime — you must ask.
45
+ (`thrum state list`), update as you go. Prime injects only a capped digest
46
+ of agent-local state; `thrum state list` shows all.
47
47
  - **Fleet** (coordinators write; everyone reads): before citing a fleet
48
48
  fact in a decision, check `as_of`/`method`. Past the kind's threshold
49
49
  (`thrum state describe <kind>`)? Re-verify by effect before acting, or
@@ -73,7 +73,7 @@ yourself.
73
73
 
74
74
  ## Field Mutability Matrix
75
75
 
76
- `Entry` (`internal/state/types.go`) has five mutability classes, not one
76
+ The state `Entry` type has five mutability classes, not one
77
77
  uniform "immutable field" guard:
78
78
 
79
79
  - **immutable-identity** — part of the `(Kind, Scope)` addressing key, or
@@ -104,7 +104,7 @@ clear error — do not proceed with partial inputs.
104
104
  Regex: `^\*\*Authored-against:\*\* \`([0-9a-f]+)\` target: \`([^\`]+)\``
105
105
  (sha → capture group 1, merge_target → capture group 2)
106
106
 
107
- (Canonical stamp definition: `claude-plugin/commands/_stamp-protocol.md`. The
107
+ (Canonical stamp definition: the /thrum:stamp-protocol skill. The
108
108
  stamp follows the same literal `grep -F` / fixed-field-order / case-sensitive /
109
109
  ASCII-only convention as the `THRUM-REVIEW` marker — see
110
110
  `coordinator-running-brainstorm-cycles` skill § "Footer → commit → stamp".)
@@ -158,7 +158,7 @@ clear error — do not proceed with partial inputs.
158
158
  present" outcome above, since this check only needs the stamp's
159
159
  `<sha>`/`<merge_target>`, not the plan's cited-files list. Run the
160
160
  ordered, short-circuiting two-check sequence defined canonically in
161
- `_stamp-protocol.md` § "Read-time provenance re-derivation" (SHA-resolves
161
+ `stamp-protocol.md` § "Read-time provenance re-derivation" (SHA-resolves
162
162
  first, then merge-status) against the stamp's `<sha>`/`<merge_target>` —
163
163
  the exact commands live there as the single source of truth; this section
164
164
  states outcomes and severity only:
@@ -29,7 +29,7 @@ const SYNC = String.raw `\.git/thrum-sync/a-sync`;
29
29
  // Command-position anchor: line start or immediately after a shell separator
30
30
  // (;, &&, ||), then optional whitespace. This matches `cd`/`git` only when they
31
31
  // are the actual command — NOT when those words appear inside a quoted argument
32
- // preceded by a bare space (the D5 false-positive: `bd remember "... cd
32
+ // preceded by a bare space (the quoted-argument false-positive: `bd remember "... cd
33
33
  // .git/thrum-sync/a-sync ..."` must NOT be denied). Match op-shape, not the mere
34
34
  // presence of the path string.
35
35
  const CMDPOS = String.raw `(^|;|&&|\|\|)\s*`;
@@ -31,7 +31,7 @@ const ALLOW = [
31
31
  ["git -C a-sync push", `git -C ${ASYNC} push`],
32
32
  ["git -C a-sync log (not branch-changing)", `git -C ${ASYNC} log --oneline`],
33
33
  ["ls the path", `ls ${ASYNC}/`],
34
- // D5 false-positive guard: cd inside a quoted argument (bare space before it),
34
+ // quoted-argument false-positive guard: cd inside a quoted argument (bare space before it),
35
35
  // not at command position -> must be ALLOWED.
36
36
  ["quoted cd inside bd remember", `bd remember "note: do not cd ${ASYNC} directly"`],
37
37
  ];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ // Tests for installAssets skills/commands staging (o4jgf MINOR 13):
2
+ // expected content lands on first install, and the version gate makes a
3
+ // second install a no-op. Offline/deterministic: temp XDG_CONFIG_HOME,
4
+ // stub ctx, real asset tree, never the real $HOME or network.
5
+ //
6
+ // Run: npm test (builds, then `node --test dist`)
7
+ import { test } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import fs from "fs";
10
+ import os from "os";
11
+ import path from "path";
12
+ import { getConfigDir, installAssets } from "./installer.js";
13
+ function stubCtx() {
14
+ return { client: { app: { log: async () => { } } } };
15
+ }
16
+ test("installAssets stages skills and commands; version gate skips reinstall", async () => {
17
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "thrum-oc-install-"));
18
+ const prevXdg = process.env.XDG_CONFIG_HOME;
19
+ process.env.XDG_CONFIG_HOME = tmp;
20
+ try {
21
+ await installAssets(stubCtx());
22
+ const cfg = path.join(tmp, "opencode");
23
+ assert.equal(getConfigDir(), cfg);
24
+ // protocol skills ride the wholesale skills copy (o4jgf item 5)
25
+ const skillFile = path.join(cfg, "skills", "snapshot-protocol", "SKILL.md");
26
+ assert.ok(fs.existsSync(skillFile));
27
+ assert.ok(fs.existsSync(path.join(cfg, "commands", "thrum-sleep.md")));
28
+ const mtimeBefore = fs.statSync(skillFile).mtimeMs;
29
+ await installAssets(stubCtx());
30
+ assert.equal(fs.statSync(skillFile).mtimeMs, mtimeBefore);
31
+ }
32
+ finally {
33
+ if (prevXdg === undefined) {
34
+ delete process.env.XDG_CONFIG_HOME;
35
+ }
36
+ else {
37
+ process.env.XDG_CONFIG_HOME = prevXdg;
38
+ }
39
+ fs.rmSync(tmp, { recursive: true, force: true });
40
+ }
41
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-thrum-pro",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Thrum multi-agent coordination plugin for Open Code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,61 +0,0 @@
1
- ---
2
- description:
3
- Per-runtime compact-equivalent command table consumed by compact.md,
4
- compact-extended.md, and scripts/sync-skills.sh. Not user-invocable
5
- directly.
6
- ---
7
-
8
- # Per-Runtime Compact Command Table (shared partial)
9
-
10
- Consumers: `claude-plugin/commands/compact.md`, `compact-extended.md`
11
- (reference this table for the command each runtime's synced copy sends), and
12
- `scripts/sync-skills.sh`'s `compact_command_for_runtime()` (the executable
13
- mirror of this table — keep the two in lockstep; a row added/changed here
14
- without a matching case in that function is a defect at review, not a style
15
- nit).
16
-
17
- This is the canonical, cited source of truth for what "the compact command"
18
- means on each runtime thrum drives. Do NOT invent a command for a runtime not
19
- listed here or not sourced — an unverified guess sent to a runtime's pane is
20
- worse than no compaction at all (it either no-ops or does something
21
- unintended). A runtime found to have no equivalent is recorded as such, not
22
- silently omitted.
23
-
24
- | Runtime | Compact command | Source | Confidence |
25
- | ------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------ |
26
- | `claude` | `/compact` | Claude Code built-in slash command (already established in this project). | Verified — first-party. |
27
- | `codex` | `/compact` | OpenAI Codex CLI context-compaction architecture (server-side `POST /v1/responses/compact`, manual trigger `/compact`). | Verified — corroborated by two independent technical write-ups; not fetched from `codex --help` directly. |
28
- | `opencode` | `/compact` (alias `/summarize`) | opencode.ai official docs, keybinds reference — `session_compact` action, default slash command `/compact`. | Verified from official docs. **Caveat:** a differently-named community fork lacks this command — confirm against the specific `opencode` binary before relying on it blindly. |
29
- | `cursor` | `/summarize` (alias `/compress`) | cursor.com CLI reference, slash-commands page. | Verified from official docs. **Differs from Claude's `/compact`** — this is the one runtime where the sent text must actually change. `/clear` (aliases `/new`, `/new-chat`) is a separate full-reset command, not compaction — do not confuse the two. |
30
- | `copilot` | `/compact` | docs.github.com, "Managing context in GitHub Copilot CLI". | Verified from official docs. **Not currently shippable**: `copilot-plugin/` has no skills/commands-loading mechanism at all (pre-existing, documented in `scripts/sync-skills.sh`'s header) — this row exists for completeness/future readiness, not because the skill ships there today. Coverage tracked as a build-vs-accept scope call, owner-owned. |
31
- | `muse` | **NONE FOUND** | musecodes.io official docs — documented commands are `/plan`, `/grill`, `/goal`, `/workflows`, `/model`, `/effort`, `Esc Esc` (rewind), `muse replay`. No manual compact/summarize trigger is documented; marketing copy describing context "compaction" refers to an automatic/internal mechanism only, not a user-invocable command. | Verified absence, not an inferred gap. Per E9 (owner-ruled), muse falls to the `restart-extended` exception — it does not receive compact.md/compact-extended.md. |
32
- | `gemini` | **UNVERIFIED** | Not researched — no plugin tree exists for this runtime, and it was never included in this table's original research pass. | **Not a confirmed negative.** Go-side `internal/runtime.RuntimePreset` exists for this runtime with `CompactCommand` deliberately left empty (falls back to `/thrum:restart-extended`, never invented). This research is not yet done — do not research here; treat future work on this row as owned elsewhere. |
33
- | `kiro-cli` | **UNVERIFIED** | Same as `gemini` — not researched, no plugin tree. | Same as `gemini` — empty `CompactCommand`, safe fallback, research pending. |
34
- | `amp` | **UNVERIFIED** | Same as `gemini` — not researched, no plugin tree. | Same as `gemini` — empty `CompactCommand`, safe fallback, research pending. |
35
- | `shell` | **UNVERIFIED** | Same as `gemini` — not researched, no plugin tree. | Same as `gemini` — empty `CompactCommand`, safe fallback, research pending. |
36
-
37
- ## Notes
38
-
39
- - `codex` and `opencode` resolve to the same literal string Claude uses
40
- (`/compact`), so their synced copies are a functional no-op substitution —
41
- still routed through the same mechanism for consistency and so a future
42
- table change (e.g. if `opencode`'s fork situation resolves differently)
43
- propagates without a second code path.
44
- - `cursor` is the one runtime whose synced copy's sent command differs from
45
- Claude's and must be verified after every sync run (`grep` step in
46
- `scripts/sync-skills.sh`'s `compact_command_for_runtime` block).
47
- - `muse` and `copilot` are both absent from compact/compact-extended's sync
48
- targets today, for two *different* reasons — `muse` because no native
49
- command exists to send, `copilot` because the plugin has no delivery
50
- mechanism at all. Neither is a silent drop: both are recorded here and
51
- reported in the completion report for this table's original research pass.
52
- - `gemini`/`kiro-cli`/`amp`/`shell` are recorded as **UNVERIFIED**, not
53
- merged into the `muse`/`copilot` "no equivalent" rows above — those two are
54
- confirmed negatives (verified by reading official docs); the four
55
- UNVERIFIED rows are an absence of research, not an absence of a command.
56
- `scripts/sync-skills.sh`'s `compact_command_for_runtime()` already returns
57
- `""` for any of these four via its `*` default case, so the executable
58
- mirror and this table already agree — no code change is needed to keep
59
- them in lockstep, only this documentation. See also
60
- `dev-docs/reference/compaction-lifecycle-attach-points.md` for the same
61
- four runtimes' hook-attach-point status.
@@ -1,15 +0,0 @@
1
- ---
2
- description:
3
- Shared generator-skill idempotency invariant consumed by config/doc
4
- generator skills. Not user-invocable directly.
5
- ---
6
-
7
- # Generator Idempotency Protocol (shared partial)
8
-
9
- Consumers: run `grep -rl _generator-idempotency-protocol claude-plugin/skills/`
10
- for the current set — do NOT hardcode it here. A list of consumers inside the
11
- consumed file is a second copy of a git-answerable fact and rots the moment a
12
- skill is added or dropped.
13
-
14
- The modes are idempotent — running the skill repeatedly on a stable project
15
- should produce no file changes after the first run.
@@ -1,18 +0,0 @@
1
- ---
2
- description:
3
- Shared project-specific-rules protocol consumed by role skills. Not
4
- user-invocable directly.
5
- ---
6
-
7
- # Project-Specific Rules Protocol (shared partial)
8
-
9
- Consumers: run `grep -rl _project-rules-protocol claude-plugin/skills/` for the
10
- current set — do NOT hardcode it here. A list of consumers inside the consumed
11
- file is a second copy of a git-answerable fact and rots the moment a skill is
12
- added or dropped.
13
-
14
- Project-local rules of kind `agent_rule` at `--scope role` were loaded at
15
- session start by your preamble (see your role template's Memory model block).
16
- If a project-local rule conflicts with a universal rule above, the
17
- project-local rule wins; surface the conflict in your reply so the user can
18
- decide whether to graduate or remove the override.
@@ -1,27 +0,0 @@
1
- ---
2
- description:
3
- Shared "Verify before you write" invariant consumed by state-writing
4
- skills. Not user-invocable directly.
5
- ---
6
-
7
- # Verify Before You Write Protocol (shared partial)
8
-
9
- Consumers: run `grep -rl _verify-before-write-protocol claude-plugin/skills/`
10
- for the current set — do NOT hardcode it here. A list of consumers inside the
11
- consumed file is a second copy of a git-answerable fact and rots the moment a
12
- skill is added or dropped.
13
-
14
- A written fact is TRUE at the moment it's recorded and can silently become
15
- FALSE later — the reader can't tell, because a note doesn't present itself as
16
- a time-bound claim. Before writing anything:
17
-
18
- - Only write what you've verified against current state — not what you
19
- remember, assume, or were told once.
20
- - A note recording an UNEXPLAINED artifact must carry the unexplained-ness
21
- forward — "not mine, cause unknown, nobody has traced this" — rather than
22
- resolving it to a disposition like "ignore it." The note isn't wrong to cope
23
- with noise you can't act on; the defect is closing the question when
24
- nothing is actually known. "Ignore it" is unfalsifiable by construction —
25
- an instruction to not look can't be caught by looking, because diligence is
26
- exactly what it switches off — and it can silently train every future
27
- session to stop looking at the one visible symptom of a live bug.