opencode-thrum-pro 0.1.0

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 (101) hide show
  1. package/assets/commands/thrum-_deviations-protocol.md +87 -0
  2. package/assets/commands/thrum-_generator-idempotency-protocol.md +15 -0
  3. package/assets/commands/thrum-_project-rules-protocol.md +18 -0
  4. package/assets/commands/thrum-_snapshot-protocol.md +265 -0
  5. package/assets/commands/thrum-_stamp-protocol.md +112 -0
  6. package/assets/commands/thrum-_verify-before-write-protocol.md +27 -0
  7. package/assets/commands/thrum-inbox.md +22 -0
  8. package/assets/commands/thrum-load-context.md +17 -0
  9. package/assets/commands/thrum-overview.md +17 -0
  10. package/assets/commands/thrum-prime.md +30 -0
  11. package/assets/commands/thrum-quickstart.md +14 -0
  12. package/assets/commands/thrum-reply.md +28 -0
  13. package/assets/commands/thrum-restart-extended.md +195 -0
  14. package/assets/commands/thrum-restart.md +293 -0
  15. package/assets/commands/thrum-send.md +31 -0
  16. package/assets/commands/thrum-sleep-extended.md +186 -0
  17. package/assets/commands/thrum-sleep.md +212 -0
  18. package/assets/commands/thrum-team.md +12 -0
  19. package/assets/commands/thrum-update-project.md +259 -0
  20. package/assets/commands/thrum-wait.md +14 -0
  21. package/assets/skills/adversarial-critique/SKILL.md +242 -0
  22. package/assets/skills/brainstorm-queue-aware/SKILL.md +167 -0
  23. package/assets/skills/brainstorm-steward/SKILL.md +181 -0
  24. package/assets/skills/choosing-subagent-models/SKILL.md +244 -0
  25. package/assets/skills/closing-findings-while-warm/SKILL.md +104 -0
  26. package/assets/skills/configure-roles/SKILL.md +229 -0
  27. package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +205 -0
  28. package/assets/skills/coordinator-assessing-agent-completion/scan.py +117 -0
  29. package/assets/skills/coordinator-branch-split-on-block/SKILL.md +168 -0
  30. package/assets/skills/coordinator-context-monitoring/SKILL.md +674 -0
  31. package/assets/skills/coordinator-dispatching-work/SKILL.md +288 -0
  32. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +522 -0
  33. package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +171 -0
  34. package/assets/skills/coordinator-maintaining-memory/SKILL.md +89 -0
  35. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +192 -0
  36. package/assets/skills/coordinator-merging-code/SKILL.md +331 -0
  37. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +442 -0
  38. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +198 -0
  39. package/assets/skills/coordinator-post-restart-sweep/SKILL.md +135 -0
  40. package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +199 -0
  41. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +654 -0
  42. package/assets/skills/coordinator-running-review-cycles/SKILL.md +153 -0
  43. package/assets/skills/coordinator-single-responsibility-merge-gate/SKILL.md +14 -0
  44. package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +255 -0
  45. package/assets/skills/efficient-multi-agent-research/SKILL.md +177 -0
  46. package/assets/skills/fixing-documentation-errors/SKILL.md +258 -0
  47. package/assets/skills/implementer-maintaining-memory/SKILL.md +84 -0
  48. package/assets/skills/implementer-orchestrating-execution/SKILL.md +125 -0
  49. package/assets/skills/implementer-receiving-dispatch/SKILL.md +127 -0
  50. package/assets/skills/implementer-receiving-review-feedback/SKILL.md +125 -0
  51. package/assets/skills/implementer-status-and-handoff/SKILL.md +150 -0
  52. package/assets/skills/implementer-tdd-and-quality/SKILL.md +99 -0
  53. package/assets/skills/memory-audit-recover/SKILL.md +153 -0
  54. package/assets/skills/memory-curate/SKILL.md +139 -0
  55. package/assets/skills/memory-maintenance/SKILL.md +87 -0
  56. package/assets/skills/memory-read-discipline/SKILL.md +164 -0
  57. package/assets/skills/memory-search-advanced/SKILL.md +217 -0
  58. package/assets/skills/memory-write-discipline/SKILL.md +135 -0
  59. package/assets/skills/orchestrate/SKILL.md +795 -0
  60. package/assets/skills/persistent-watcher-archetype/SKILL.md +225 -0
  61. package/assets/skills/prime-agent/SKILL.md +92 -0
  62. package/assets/skills/project-hotpath-gate/SKILL.md +255 -0
  63. package/assets/skills/project-philosophy/SKILL.md +418 -0
  64. package/assets/skills/project-philosophy/resources/philosophy-template.md +155 -0
  65. package/assets/skills/project-philosophy/resources/reliability-class-library.md +653 -0
  66. package/assets/skills/project-setup/SKILL.md +1007 -0
  67. package/assets/skills/project-setup/resources/implementation-agent.md +826 -0
  68. package/assets/skills/researcher-answering-queries/SKILL.md +100 -0
  69. package/assets/skills/researcher-investigating/SKILL.md +152 -0
  70. package/assets/skills/researcher-maintaining-memory/SKILL.md +176 -0
  71. package/assets/skills/state-migration/SKILL.md +54 -0
  72. package/assets/skills/thrum/SKILL.md +161 -0
  73. package/assets/skills/thrum/resources/ANTI_PATTERNS.md +132 -0
  74. package/assets/skills/thrum/resources/BOUNDARIES.md +56 -0
  75. package/assets/skills/thrum/resources/CLI_REFERENCE.md +1066 -0
  76. package/assets/skills/thrum/resources/IDENTITY.md +49 -0
  77. package/assets/skills/thrum/resources/LISTENER_PATTERN.md +64 -0
  78. package/assets/skills/thrum/resources/MESSAGING.md +163 -0
  79. package/assets/skills/thrum/resources/TMUX_SESSIONS.md +118 -0
  80. package/assets/skills/thrum/resources/WORKTREES.md +117 -0
  81. package/assets/skills/thrum-memory/SKILL.md +138 -0
  82. package/assets/skills/trace-spec-to-plan/SKILL.md +104 -0
  83. package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +57 -0
  84. package/assets/skills/update-queue/SKILL.md +149 -0
  85. package/assets/skills/using-the-queue/SKILL.md +172 -0
  86. package/assets/skills/using-thrum-state/SKILL.md +104 -0
  87. package/assets/skills/verify-against-plan/SKILL.md +323 -0
  88. package/assets/skills/verify-against-source/SKILL.md +237 -0
  89. package/assets/skills/watcher-archetype/SKILL.md +84 -0
  90. package/assets/skills/writing-durable-markdown/SKILL.md +66 -0
  91. package/dist/hooks/block-sync-cd.d.ts +9 -0
  92. package/dist/hooks/block-sync-cd.js +71 -0
  93. package/dist/hooks/block-sync-cd.test.d.ts +1 -0
  94. package/dist/hooks/block-sync-cd.test.js +61 -0
  95. package/dist/hooks/shell-env.d.ts +8 -0
  96. package/dist/hooks/shell-env.js +22 -0
  97. package/dist/index.d.ts +6 -0
  98. package/dist/index.js +25 -0
  99. package/dist/installer.d.ts +2 -0
  100. package/dist/installer.js +86 -0
  101. package/package.json +49 -0
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: implementer-receiving-review-feedback
3
+ description: "Use when receiving review findings, when a reviewer flagged an issue, during a review cycle, or when responding to review. Loads implementer-specific discipline that complements superpowers:receiving-code-review."
4
+ ---
5
+
6
+ # Implementer: Receiving Review Feedback
7
+
8
+ This skill **complements** `superpowers:receiving-code-review` — it does not
9
+ restate the technical-rigor and no-performative-agreement content from that
10
+ skill. Layer the rules below on top of those universals.
11
+
12
+ ## The review gate is a hard stop, not a suggestion
13
+
14
+ **Why:** Review gates exist because unreviewed code from one epic may require
15
+ substantial changes before the next epic can build on it. Starting the next epic
16
+ before the current one is reviewed creates compounding rework — when round-2
17
+ fixes land in epic N, the early work on epic N+1 may need to be redone or
18
+ reverted.
19
+
20
+ **How to apply:** After sending DONE/DONE_WITH_CONCERNS for an epic: close beads
21
+ tasks for that epic, ensure work is durably preserved per project policy, then
22
+ enter idle. Do not claim tasks in the next epic. Do not pre-read its spec
23
+ section. Do not "just start the trivial first task". Wait for the coordinator's
24
+ explicit GREENLIT or APPROVED message.
25
+
26
+ ## Batch all review fixes into ONE commit
27
+
28
+ **Why:** A single fix commit makes re-review straightforward — the coordinator
29
+ inspects one diff against the numbered finding list. Per-finding commits multiply the surface the re-review has to traverse
30
+ and increase the chance that a finding fixed in commit A is regressed by commit
31
+ B.
32
+
33
+ **How to apply:** Read the full numbered finding list before writing any code.
34
+ Fix all BLOCKING and IMPORTANT findings in scope. Run tests once they're all
35
+ addressed. Commit with a message that lists each finding number and its
36
+ resolution:
37
+
38
+ ```bash
39
+ git commit -m "$(cat <<'EOF'
40
+ fix: address review findings #1-#5 for <task-id>
41
+
42
+ - #1 (BLOCKING) — <one-line resolution>
43
+ - #2 (IMPORTANT) — <one-line resolution>
44
+ - #3 (LOW) — <one-line resolution>
45
+ - #4 (LOW) — verified false positive: <one-line evidence>
46
+ - #5 (LOW) — deferred per <decision/rationale>
47
+
48
+ make test PASS (race), make lint PASS.
49
+
50
+ Refs: <task-id>
51
+ EOF
52
+ )"
53
+ ```
54
+
55
+ If a finding is truly independent and the coordinator explicitly requested
56
+ separate commits, that's the only time to fragment.
57
+
58
+ ## Don't reflexively bucket findings as "follow-ups"
59
+
60
+ **Why:** When the file you're already modifying contains a small adjacent issue,
61
+ deferring it to a follow-up issue is often the wrong trade. The marginal cost of
62
+ fixing it now is small (the file is already in your context, you already
63
+ understand the surrounding code). The cost of a future follow-up is real
64
+ (re-load context, re-read neighbors, redo verification). Default to fix-now when
65
+ the file is already being touched.
66
+
67
+ **How to apply:** For each finding categorized as "could defer", run the
68
+ trade-off explicitly:
69
+
70
+ - Is the file already in the diff? Default to fix-now
71
+ - Is the fix a few lines? Default to fix-now
72
+ - Does verification require running the same tests as the main fix? Default to
73
+ fix-now
74
+ - Is the fix a meaningful refactor or design change? Defer is legitimate; file
75
+ the bd issue and link it in the commit message
76
+
77
+ Don't reach for "deferred" as a shortcut to ship faster.
78
+
79
+ ## Push back with file:line evidence when the reviewer is wrong
80
+
81
+ **Why:** Reviewers reading large diffs sometimes cite wrong line numbers,
82
+ describe behavior that doesn't match the current code, or apply a universal rule
83
+ to a project-specific exception. Pushback is welcome — it's how the feedback
84
+ loop stays calibrated. But pushback without verification is just
85
+ opinion against opinion.
86
+
87
+ **How to apply:** When you disagree with a finding, verify against the source
88
+ first:
89
+
90
+ - For file/line claims: read the cited file at the cited lines, paste the actual
91
+ content
92
+ - For API claims: grep for the symbol, paste the signature
93
+ - For behavior claims: trace the call path and cite the relevant function
94
+
95
+ Format pushback as: "Finding #N — verified false positive. <one-line
96
+ restatement of what reviewer said>. Actual: <what the code does>, evidence at
97
+ `<file>:<line>`." Then ask the coordinator to drop or restate. If after
98
+ verification you're still convinced the finding is right, go fix it.
99
+
100
+ ## Re-review after fixes — don't ship the round-2 fix as DONE on round 1
101
+
102
+ **Why:** When the coordinator dispatches re-review on the round-2 commit, they
103
+ expect to find a clean diff from your fix work. Accidentally bundling unrelated
104
+ changes into the fix commit muddies the review and either gets sent back or
105
+ merges work the coordinator hasn't seen.
106
+
107
+ **How to apply:** Between round-1 review feedback and round-2 ping:
108
+
109
+ 1. Fix only what the findings ask for
110
+ 2. Don't refactor, rename, or "improve" surrounding code
111
+ 3. Verify tests pass with `-race`
112
+ 4. Commit and ping with the per-finding disposition format from
113
+ `implementer-status-and-handoff`
114
+
115
+ If you see additional issues during the fix work that weren't in the findings
116
+ list, file them as bd issues — don't slip them into the fix commit.
117
+
118
+ ## Project-specific rules (already loaded)
119
+
120
+ Read the shared partial at the absolute path:
121
+ `claude-plugin/commands/_project-rules-protocol.md`
122
+
123
+ If you accumulate a new rule mid-session (the user corrects you), capture it via
124
+ the `implementer-maintaining-memory` skill — it references the
125
+ `memory-write-discipline` common for the canonical `thrum memory create` shape.
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: implementer-status-and-handoff
3
+ description: "Use when reporting status to the coordinator, marking a task done, or handing off completed work. Loads implementer-specific discipline for closing the loop cleanly."
4
+ ---
5
+
6
+ # Implementer: Status and Handoff
7
+
8
+ ## Use the four-token status vocabulary exactly
9
+
10
+ **Why:** The coordinator uses your status token to decide whether to proceed,
11
+ hold for review, or unblock. Vague reports like "I finished the work"
12
+ or "mostly done" force the coordinator to re-read the full implementation to
13
+ judge state, which adds latency to every dispatch they manage. The token is a
14
+ 100ms decision instead of a five-minute re-read.
15
+
16
+ **How to apply:** Every completion or escalation message starts with exactly one
17
+ of:
18
+
19
+ | Token | Meaning | Send when |
20
+ | -------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------ |
21
+ | `DONE` | All tasks complete, tests pass, work committed, ready for review | Standard completion path |
22
+ | `DONE_WITH_CONCERNS` | Done but with caveats the coordinator should see | Unresolved finding, architectural concern, iteration cap hit |
23
+ | `NEEDS_CONTEXT` | Cannot proceed without more information | Missing design decision, ambiguous spec, unclear scope |
24
+ | `BLOCKED` | Cannot proceed — external dependency or tooling issue | Cross-epic dependency, test infra broken, auth problem |
25
+
26
+ For anything other than `DONE`, include a brief reason. For `BLOCKED`, state
27
+ exactly what would unblock you.
28
+
29
+ ## Commit per task with the bead ID in the trailer
30
+
31
+ **Why:** Beads links commits to issues via `Refs: <id>` trailers in the commit
32
+ message body. Skipping the trailer breaks the audit chain; using the
33
+ parent epic ID instead of the specific task ID flags as a traceability nit
34
+ during review. Per-task commits also keep the diff small enough that the
35
+ dual-review pass can reason about it without context exhaustion.
36
+
37
+ **How to apply:** Commit after each closed task — not in bulk at the end. Use
38
+ the heredoc form so the trailer renders correctly:
39
+
40
+ ```bash
41
+ git commit -m "$(cat <<'EOF'
42
+ <type>(<scope>): <description>
43
+
44
+ Refs: <task-id>
45
+ EOF
46
+ )"
47
+ ```
48
+
49
+ Use the **subtask** ID (`thrum-abc.1`), not the parent epic ID. Run
50
+ `bd show <task-id>` before committing if you need to confirm the ID.
51
+
52
+ ## Push your branch before reporting DONE
53
+
54
+ **Why:** once you exit, your in-session context is gone and the pushed branch is
55
+ the only artifact that survives you. An unpushed branch is unreachable from every
56
+ other machine and indistinguishable from work that was lost.
57
+
58
+ **How to apply:** commit, then push. Every time.
59
+
60
+ ```bash
61
+ git push origin <branch>
62
+ ```
63
+
64
+ Report the result as one line:
65
+
66
+ ```text
67
+ Branch pushed: <branch-name> @ <sha> (git ls-remote origin refs/heads/<branch-name> confirms)
68
+ ```
69
+
70
+ **Never push `thrum-agents`, `main`, or `website-dev`** — the coordinator merges
71
+ those.
72
+
73
+ Never report DONE with the push status silently omitted — an orchestrator
74
+ that removes a worktree assuming "DONE implies pushed" on a project that
75
+ does NOT push feature branches would destroy the only copy of the work.
76
+
77
+ ## Mark queue items done as you commit, push, and report
78
+
79
+ As each step lands, mark its queue item `done`. Do NOT `drop` the bundle at your own
80
+ DONE report — a review finding can reopen the task (`start` reopens a done bundle).
81
+ Drop the bundle only once the coordinator confirms the merge landed (R1); until then
82
+ it is your live record of what's addressed vs. still open.
83
+
84
+ ## Cite SHAs and per-finding dispositions in status messages
85
+
86
+ **Why:** A vague status message ("addressed all findings", "done with the
87
+ changes") forces the coordinator to re-read your diff to verify each finding was
88
+ handled. A status message with concrete SHAs and per-finding dispositions is a
89
+ 30-second confirmation. The cost is the same on your side; the time saved is the
90
+ coordinator's.
91
+
92
+ **How to apply:** Cite the commit SHA(s) and one disposition per finding:
93
+
94
+ ```text
95
+ DONE: Epic <id> review fixes complete.
96
+
97
+ Commits: <SHA1> <SHA2>
98
+
99
+ Per-finding disposition:
100
+ - #1 (BLOCKING, file:line) — fixed at <SHA>
101
+ - #2 (IMPORTANT, file:line) — fixed at <SHA>
102
+ - #3 (LOW) — verified false positive: <one-line evidence>
103
+ - #4 (LOW) — deferred per <decision/rationale>
104
+
105
+ make test PASS (race), make lint PASS.
106
+ ```
107
+
108
+ For first-pass DONE (not review-fix), cite the closing SHA and the test result.
109
+
110
+ ## Close beads tasks with `--suggest-next` when relevant
111
+
112
+ **Why:** `bd close <id>` works fine, but `bd close <id> --suggest-next` prints
113
+ newly-unblocked downstream issues immediately. If you're in the middle of an
114
+ epic, the next task is often the most useful next move; the flag saves a
115
+ `bd ready` round-trip.
116
+
117
+ **How to apply:** When closing a task that has dependents, use
118
+ `bd close <id> --suggest-next`. For the last task in an epic where you're
119
+ stopping at a review gate, plain `bd close` is fine — you're not picking up the
120
+ next task anyway.
121
+
122
+ ## Project-specific rules (already loaded)
123
+
124
+ Read the shared partial at the absolute path:
125
+ `claude-plugin/commands/_project-rules-protocol.md`
126
+
127
+ If you accumulate a new rule mid-session (the user corrects you), capture it via
128
+ the `implementer-maintaining-memory` skill — it references the
129
+ `memory-write-discipline` common for the canonical `thrum memory create` shape.
130
+
131
+ ## Pattern D self-write — set `agent_status=idle` on DONE handoff
132
+
133
+ When reporting DONE to the coordinator, write `agent_status="idle"` to your
134
+ local identity file. This closes the `working→idle` transition opened by the ACK
135
+ template's `set-status working` (sibling skill
136
+ `implementer-receiving-dispatch`). The sweep script reads this field to
137
+ distinguish "agent finished cleanly" from "agent stuck claiming to work" — see
138
+ `coordinator-context-monitoring` SKILL.md for the tier-ladder consumption.
139
+
140
+ ```bash
141
+ # Step 1: Report DONE to coordinator
142
+ thrum send --to @your_coordinator --stdin <<'EOF'
143
+ DONE: <task-id>. <one-line summary>. Commits: <SHA1>, <SHA2>.
144
+ EOF
145
+
146
+ # Step 2: Mark yourself idle (RPC-preferred; falls back to a local identity-file write if the daemon is unreachable)
147
+ thrum agent set-status idle
148
+ ```
149
+
150
+ The local-write path is identical to the ACK side.
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: implementer-tdd-and-quality
3
+ description: "Use when writing tests, running tests, hitting a quality gate, or before reporting a task done. Loads project-specific test and quality discipline that complements superpowers:test-driven-development."
4
+ ---
5
+
6
+ # Implementer: TDD and Quality
7
+
8
+ This skill **complements** `superpowers:test-driven-development` — it does not
9
+ restate the red-green-refactor discipline, the iron law on watching tests fail,
10
+ or any other content from that skill. Layer this content on top of those
11
+ universals: the rules below capture project-specific Go conventions and
12
+ quality-gate practice.
13
+
14
+ ## Race detector is mandatory
15
+
16
+ **Why:** Thrum's daemon has significant concurrent state (goroutines for
17
+ WebSocket, Unix socket, sync, telegram bridge, peer transport). Race conditions
18
+ that pass bare `go test` fail under `-race` — sometimes with silent data
19
+ corruption that takes hours to track down later. The
20
+ Makefile's `make test` includes `-race` by default for exactly this reason.
21
+
22
+ **How to apply:** Always run `go test -race ./...` (or scope to specific
23
+ packages with `-race`). Never report tests passing without having run with
24
+ `-race`. For a specific package:
25
+ `go test ./internal/daemon/... -race -count=1 -timeout=120s`. For everything:
26
+ `make test`.
27
+
28
+ ## Scope test runs to packages you touched
29
+
30
+ **Why:** Running the entire test tree on every iteration of a fix-test loop is
31
+ wasteful — most packages weren't touched and their tests will pass identically
32
+ every iteration. Scoping speeds the inner loop without sacrificing correctness;
33
+ the full tree gets one final run before reporting done.
34
+
35
+ **How to apply:** During the inner fix-test loop, run only the affected
36
+ packages: `go test -race ./internal/<pkg>/... -run <TestName>`. Once the scoped
37
+ tests pass and you're ready to report done, run `make test` once to confirm
38
+ nothing else broke.
39
+
40
+ ## Use `t.TempDir()` for filesystem fixtures — never hardcoded paths
41
+
42
+ **Why:** Hardcoded absolute paths (especially the implementer's home directory)
43
+ only work on one machine. A test that bakes in a literal path like
44
+ `<repo-root>` passes locally and fails everywhere else — the fix is usually as
45
+ small as swapping in `t.TempDir()`. The same pattern shows up with
46
+ `os.UserHomeDir()` results being baked into expected values.
47
+
48
+ **How to apply:** Any test that creates a temporary directory, writes files, or
49
+ needs an isolated git repo must use `t.TempDir()`. It is cleaned up
50
+ automatically and is unique per test run. If you need a git repo, initialize it
51
+ in the temp dir: `cmd := exec.Command("git", "init", t.TempDir())`. For fixtures
52
+ comparing paths, capture the temp dir into a variable and reference it in
53
+ expected values — never hardcode.
54
+
55
+ ## Avoid `go vet ./...` regressions before reporting
56
+
57
+ **Why:** `go vet` catches a class of bugs that compile but are wrong:
58
+ unreachable code, suspicious type conversions, malformed printf args. Lint-clean
59
+ code that fails `vet` will get caught in CI or by review; running `vet` locally
60
+ catches it pre-commit when the fix is one line.
61
+
62
+ **How to apply:** Before reporting done, run `go vet ./...` and `make lint`.
63
+ Both should pass clean. If a `vet` finding looks like a false positive, prefer a
64
+ small annotation or refactor to silencing the warning.
65
+
66
+ ## Two-stage self-review before pinging the coordinator
67
+
68
+ **Why:** A self-review pass before the coordinator's dual review reduces total
69
+ review round-trips. Self-review is not ceremony; it pre-pays the cost of issues
70
+ that would otherwise come back as findings.
71
+
72
+ **How to apply:** At task close, before sending DONE:
73
+
74
+ 1. **Spec compliance pass.** Read each acceptance criterion from the task
75
+ description. For every test case the spec mentions, verify it exists in the
76
+ test file. For every behavior change the spec specifies, verify it's
77
+ implemented and tested.
78
+ 2. **Code quality pass.** Read your full diff
79
+ (`git --no-pager diff <base>...HEAD`). Watch for: hardcoded paths,
80
+ `os.UserHomeDir` baked into tests, inline `exec.Command` calls that should
81
+ use `safecmd`, swallowed errors, missing `slog` calls on recoverable
82
+ failures.
83
+ 3. **Primitive ledger pass.** If this diff adds I/O or SQL under a hot root
84
+ (`Handle*`/tick/sweeper/`SyncApplier`/boot — see `.thrum/hotpath-gate.json`'s
85
+ `lenses.existing_primitive_bypass.hot_root_indicators`), confirm you have a ledger row: raw op -> callee
86
+ package searched -> primitive adopted, or none exists + bounded cost formula
87
+ (frequency x production cardinality, at production scale). Include it in
88
+ your DONE report.
89
+
90
+ Fix what you find before sending the ping.
91
+
92
+ ## Project-specific rules (already loaded)
93
+
94
+ Read the shared partial at the absolute path:
95
+ `claude-plugin/commands/_project-rules-protocol.md`
96
+
97
+ If you accumulate a new rule mid-session (the user corrects you), capture it via
98
+ the `implementer-maintaining-memory` skill — it references the
99
+ `memory-write-discipline` common for the canonical `thrum memory create` shape.
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: memory-audit-recover
3
+ description: "Use when investigating change history (`memory history`), recovering a soft-deleted memory, recovering the losing side of a concurrent edit (MEM-009 LWW loser), or running a confirmed hard-delete. Loads the audit walk, LWW conflict-resolution semantics, undelete flow, and the `Type DELETE <id>` hard-delete gate."
4
+ allowed-tools: "Bash(thrum memory:*)"
5
+ version: "0.11.0"
6
+ license: "Apache-2.0"
7
+ ---
8
+
9
+ # memory-audit-recover — history, undelete, hard-delete
10
+
11
+ Load this sub-skill from `thrum-memory` (umbrella) to look back at what changed
12
+ or recover something that was deleted or overwritten.
13
+
14
+ ## The JSONL is the audit log
15
+
16
+ Every event (`memory.create`, `memory.edit`, `memory.delete`, `memory.edge.add`,
17
+ `memory.edge.remove`, `memory.purge_executed`) appends to the author's
18
+ `memories/<agent_id>.jsonl`. Replay rebuilds the projection; the JSONL itself
19
+ never mutates. That makes the audit trail authoritative.
20
+
21
+ Walk the history of one memory:
22
+
23
+ ```bash
24
+ thrum memory history <id> # all events touching this memory, chronological
25
+ thrum memory history <id> --diff # unified diff of each edit's fields
26
+ ```
27
+
28
+ Projection stores `created_at` (first-event ts), `updated_at` (latest-event ts),
29
+ `created_by` (first-event author), and `last_edited_by` (latest-event author).
30
+ The full event timeline always comes from JSONL replay — per-memory event count
31
+ is typically <10, so replay is cheap.
32
+
33
+ Provenance now lives in the durable `memory-events-v2/` lane and is read by
34
+ `memory history` directly — it survives events.jsonl compaction and cold boot.
35
+
36
+ ## Conflict resolution (LWW by event ULID)
37
+
38
+ Memories use last-write-wins by event ULID — **not** semantic priority. ULID is
39
+ monotonic-ish and globally comparable; the larger ULID wins.
40
+
41
+ | Scenario | Result |
42
+ | ------------------------------------------------------------------------------- | -------------------------------------------------------- |
43
+ | Concurrent edits to disjoint fields | Both apply (no conflict). |
44
+ | Concurrent edits to the SAME field | Larger-ULID event wins. Loser preserved in JSONL. |
45
+ | Concurrent tombstones | Idempotent. One delete-event wins by ts; status=purged. |
46
+ | Edit + delete, delete-ULID > edit-ULID | Final `status=purged`. |
47
+ | Edit + delete, edit-ULID > delete-ULID AND edit explicitly sets `status=active` | Edit wins → `status=active` (undelete). |
48
+ | Edit + delete, edit-ULID > delete-ULID AND edit does NOT touch `status` | Patch applies to body/tags but `status=purged` persists. |
49
+
50
+ LWW is acceptable here because memories aren't a high-write-conflict surface
51
+ (single agent typically authors; cross-clone edits to the same field within a
52
+ sync window is a corner case). Audit preserves both edits so loss is recoverable
53
+ in practice.
54
+
55
+ ### Detecting and recovering a MEM-009 LWW loser
56
+
57
+ When `memory.edit` projection detects that LWW chose someone else's value, the
58
+ response surfaces hint `MEM-009: memory.edit.lww-loser`. (Trigger lights up when
59
+ LWW-loser surfacing lands in the projection response — code path exists today;
60
+ emission is the deferred half.)
61
+
62
+ Recovery:
63
+
64
+ ```bash
65
+ thrum memory history <id> --diff
66
+ ```
67
+
68
+ Find the losing edit in the diff stream; the JSONL preserves its body. Lift the
69
+ wanted value out and re-apply as a new edit:
70
+
71
+ ```bash
72
+ thrum memory edit <id> --short @rescued-short.md
73
+ ```
74
+
75
+ The new edit becomes the latest ULID, so it wins the next read. If both sides
76
+ actually had useful changes, consider a `comment` child memory recording the
77
+ alternative wording instead of overwriting.
78
+
79
+ ## Soft delete and undelete
80
+
81
+ Default delete is soft — `status` flips to `purged` but the JSONL keeps every
82
+ event:
83
+
84
+ ```bash
85
+ thrum memory delete <id> # default soft
86
+ ```
87
+
88
+ Soft-deleted memories are excluded from default search. Re-surface with
89
+ `--include-purged` (or `--status all`). Edges remain in place.
90
+
91
+ Undelete by writing `status=active`:
92
+
93
+ ```bash
94
+ thrum memory edit <id> --status active
95
+ ```
96
+
97
+ Undelete works regardless of who won the concurrent edit/delete race (see LWW
98
+ table above). The audit history is intact, so the recovered memory carries its
99
+ full provenance.
100
+
101
+ ## Hard delete (`--hard`)
102
+
103
+ Hard delete is irreversible after the next sync compaction. It reuses thrum's
104
+ `purge_metadata` mechanism (proven for messages) — `memory.delete --hard` emits
105
+ a `memory.purge_executed` event the existing purge logic recognizes; on next
106
+ sync compaction, the JSONL entries for that memory are physically removed across
107
+ all peers.
108
+
109
+ Mandatory confirmation gate:
110
+
111
+ ```bash
112
+ thrum memory delete <id> --hard
113
+ Type DELETE <id> to confirm: DELETE <id>
114
+ ```
115
+
116
+ The exact token (`DELETE <id>`) must be typed back — matches beads'
117
+ `DESTROY-<prefix>` pattern. There is no `--yes` bypass.
118
+
119
+ | Mode | Mechanism | Recovery |
120
+ | --------------- | -------------------------------------------------------------- | ---------------------------------------- |
121
+ | Soft (default) | `memory.delete` → projection `status=purged` | `thrum memory edit <id> --status active` |
122
+ | Hard (`--hard`) | `memory.purge_executed` → physical JSONL removal at compaction | Not recoverable post-compaction |
123
+
124
+ ## When NOT to hard-delete
125
+
126
+ Default to soft delete. The audit trail is the value memories add over ad-hoc
127
+ notes; hard-deleting throws it away.
128
+
129
+ Reach for `--hard` only when:
130
+
131
+ - The body contains secrets (API keys, credentials, customer PII) that must not
132
+ survive in JSONL or any clone.
133
+ - A misfire of `memory.create` recorded clearly wrong content the team agrees
134
+ should leave no trace.
135
+ - A legal/compliance requirement mandates physical removal.
136
+
137
+ For everything else — wrong tags, outdated decisions, deprecated rules — prefer
138
+ one of:
139
+
140
+ - Edit with the corrected content (audit preserves the original).
141
+ - Supersede with a new memory and let the old one go to `status=superseded`.
142
+ - Soft-delete; the audit trail stays.
143
+
144
+ ## Memory-history quick reference
145
+
146
+ ```bash
147
+ thrum memory history <id> # chronological events touching <id> (durable lane)
148
+ thrum memory history <id> --diff # with unified field-level diff
149
+ ```
150
+
151
+ The events that show up: `memory.create`, `memory.edit`, `memory.delete`,
152
+ `memory.edge.add`, `memory.edge.remove`, `memory.purge_executed`. Each carries
153
+ `author`, ULID timestamp, and (for edits) the field-level patch.
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: memory-curate
3
+ description: "Use when managing relationships between memories — adding/removing edges, superseding old decisions, threading comments, walking hierarchies, or deciding whether to unlink, supersede, or both. Loads edge kinds, status-driven read semantics, cycle and single-parent rules, and the unlink-supersede footgun."
4
+ allowed-tools: "Bash(thrum memory:*)"
5
+ version: "0.11.0"
6
+ license: "Apache-2.0"
7
+ ---
8
+
9
+ # memory-curate — edges, status, hierarchy
10
+
11
+ Load this sub-skill from `thrum-memory` (umbrella) when relationships between
12
+ memories matter — supersession, parent/child structure, comment threads, or
13
+ related-context grouping.
14
+
15
+ ## Edge kinds and when to use each
16
+
17
+ | Kind | Meaning | When to use |
18
+ | -------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
19
+ | `supersedes` | A replaces B. Adding the edge ALSO sets `B.status=superseded`. | A new `arch_decision` overrides an older one. A consolidated session summary replaces several stale ones. |
20
+ | `child_of` | A is a sub-piece of B; forms a tree. Single-parent. | A `worktree_status` row is `child_of` a `session_summary`. A `comment` is `child_of` its parent memory. |
21
+ | `related_to` | A and B share context; symmetric, advisory. | Two `arch_decision`s touching the same subsystem. |
22
+ | `derived_from` | A was generated or distilled from B. | A `short` summary `derived_from` the `full` body when an LLM expanded it. |
23
+
24
+ Edge kind is an open string (same hybrid pattern as memory kind). Future edges
25
+ like `blocks`, `duplicates`, or `parent-child` can be added without schema
26
+ change.
27
+
28
+ Add and remove edges:
29
+
30
+ ```bash
31
+ thrum memory link <a> supersedes <b>
32
+ thrum memory link <child> child_of <parent>
33
+ thrum memory unlink <a> supersedes <b>
34
+ ```
35
+
36
+ ## Status-driven read semantics
37
+
38
+ When A supersedes B, the supersede event writes B's status to `superseded` **in
39
+ addition to** creating the edge. Default assembly and `memory search` filter on
40
+ `status=active`. Edges are pure structural metadata; the answer to "is this
41
+ memory current" is always the status field, never an edge walk.
42
+
43
+ **Why it matters:** this avoids the "do I respect the edge or trust the status
44
+ field" ambiguity at read time. The status field wins.
45
+
46
+ ## The unlink-supersede footgun
47
+
48
+ Removing a supersede edge via `memory unlink` does **NOT** automatically restore
49
+ the superseded memory to active. The edge disappears but the `status=superseded`
50
+ set by the original supersede event persists.
51
+
52
+ Agents who try to "undo" a supersede by unlinking the edge will see the edge
53
+ gone while the memory stays hidden from default search and assembly.
54
+
55
+ To genuinely undo a supersede:
56
+
57
+ ```bash
58
+ thrum memory unlink <new-id> supersedes <old-id>
59
+ thrum memory edit <old-id> --status active
60
+ ```
61
+
62
+ Both steps are required. If you only need to keep the historical link but
63
+ re-surface the old memory, just run the `--status active` edit and leave the
64
+ edge in place.
65
+
66
+ ## Cycle prevention
67
+
68
+ | Edge kind | Cycle policy |
69
+ | -------------- | ---------------------------------------- |
70
+ | `supersedes` | Acyclic — write-time DFS reject. |
71
+ | `child_of` | Acyclic — write-time DFS reject. |
72
+ | `derived_from` | Acyclic — write-time DFS reject. |
73
+ | `related_to` | Symmetric / undirected — cycles allowed. |
74
+
75
+ Cycle detection runs a bounded DFS from the proposed edge's target node up the
76
+ existing graph in the same edge-kind direction, looking for the source. Bounded
77
+ by `memory.limits.edge_depth` (default 32) — worst-case O(32) per write,
78
+ constant-time in corpus size.
79
+
80
+ A chain that exceeds the depth limit returns `ErrMemoryEdgeChainTooDeep` with
81
+ the chain length, the configured limit, and a hint suggesting either
82
+ consolidation via `supersedes` or raising the limit in config.
83
+
84
+ ## Single-parent constraint for `child_of`
85
+
86
+ `child_of` is enforced single-parent at write-time. A memory has at most one
87
+ parent.
88
+
89
+ | Edge kind | Plurality |
90
+ | -------------- | --------------------------------------------------------- |
91
+ | `related_to` | Multiple — and obviously so. |
92
+ | `supersedes` | Multiple — A supersedes B AND C in a consolidation merge. |
93
+ | `child_of` | **One** — enforced. |
94
+ | `derived_from` | Multiple — a summary distilling several sources. |
95
+
96
+ If a v2 use case ever needs "comments threaded across multiple memories," the
97
+ single-parent constraint will need to be revisited. Not a v1 use case.
98
+
99
+ ## Comments-as-memories pattern
100
+
101
+ A comment on memory X is just another memory:
102
+
103
+ ```bash
104
+ thrum memory create --kind comment \
105
+ --title "Note on Tailscale sync" \
106
+ --oneline "Confirmed leaving git a-sync removes the dual-consumer conflict." \
107
+ --parent <X-id>
108
+ ```
109
+
110
+ `--short`/`--full` carry real prose — compose via heredoc or file, never
111
+ double-quoted inline; see your role preamble's 🔴 PROSE INTO A COMMAND rule.
112
+
113
+ `--parent` shorthand creates the `child_of` edge in the same operation. Author =
114
+ `agent_id`, timestamp = `created_at`. Threading walks via the daemon's
115
+ `memory.listByEdge` RPC on the parent.
116
+
117
+ No separate `comments` table exists. All the search predicates, audit history,
118
+ edges, and embeddings apply to comments just like any other memory kind.
119
+
120
+ ## Hierarchy navigation
121
+
122
+ Edge WRITES are CLI-exposed (`link`, `unlink`, `create --parent`). Edge READS
123
+ are daemon-RPC-only today: `memory.listByEdge` walks one hop along an edge kind
124
+ (`direction`: `inbound` finds rows pointing AT an id, `outbound` finds rows the
125
+ id points TO), but no `thrum memory` subcommand exposes it yet and
126
+ `thrum memory show` does not render edges. Until a CLI read surface ships,
127
+ navigate hierarchies by convention instead: give children a shared `--tag` (e.g.
128
+ the parent's slug) at create time and walk with
129
+ `thrum memory search --tag <slug>`.
130
+
131
+ ## Edge limits
132
+
133
+ | Limit | Default | Configurable via |
134
+ | -------------------------- | ----------- | -------------------------------- |
135
+ | Edge depth (acyclic kinds) | 32 | `memory.limits.edge_depth` |
136
+ | Edges per memory | 64 outbound | `memory.limits.edges_per_memory` |
137
+
138
+ Raise per deployment if a genuine workflow needs more — both bounds exist to
139
+ prevent pathological hierarchies and fan-out abuse, not to constrain real use.