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.
- package/assets/commands/thrum-_deviations-protocol.md +87 -0
- package/assets/commands/thrum-_generator-idempotency-protocol.md +15 -0
- package/assets/commands/thrum-_project-rules-protocol.md +18 -0
- package/assets/commands/thrum-_snapshot-protocol.md +265 -0
- package/assets/commands/thrum-_stamp-protocol.md +112 -0
- package/assets/commands/thrum-_verify-before-write-protocol.md +27 -0
- package/assets/commands/thrum-inbox.md +22 -0
- package/assets/commands/thrum-load-context.md +17 -0
- package/assets/commands/thrum-overview.md +17 -0
- package/assets/commands/thrum-prime.md +30 -0
- package/assets/commands/thrum-quickstart.md +14 -0
- package/assets/commands/thrum-reply.md +28 -0
- package/assets/commands/thrum-restart-extended.md +195 -0
- package/assets/commands/thrum-restart.md +293 -0
- package/assets/commands/thrum-send.md +31 -0
- package/assets/commands/thrum-sleep-extended.md +186 -0
- package/assets/commands/thrum-sleep.md +212 -0
- package/assets/commands/thrum-team.md +12 -0
- package/assets/commands/thrum-update-project.md +259 -0
- package/assets/commands/thrum-wait.md +14 -0
- package/assets/skills/adversarial-critique/SKILL.md +242 -0
- package/assets/skills/brainstorm-queue-aware/SKILL.md +167 -0
- package/assets/skills/brainstorm-steward/SKILL.md +181 -0
- package/assets/skills/choosing-subagent-models/SKILL.md +244 -0
- package/assets/skills/closing-findings-while-warm/SKILL.md +104 -0
- package/assets/skills/configure-roles/SKILL.md +229 -0
- package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +205 -0
- package/assets/skills/coordinator-assessing-agent-completion/scan.py +117 -0
- package/assets/skills/coordinator-branch-split-on-block/SKILL.md +168 -0
- package/assets/skills/coordinator-context-monitoring/SKILL.md +674 -0
- package/assets/skills/coordinator-dispatching-work/SKILL.md +288 -0
- package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +522 -0
- package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +171 -0
- package/assets/skills/coordinator-maintaining-memory/SKILL.md +89 -0
- package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +192 -0
- package/assets/skills/coordinator-merging-code/SKILL.md +331 -0
- package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +442 -0
- package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +198 -0
- package/assets/skills/coordinator-post-restart-sweep/SKILL.md +135 -0
- package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +199 -0
- package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +654 -0
- package/assets/skills/coordinator-running-review-cycles/SKILL.md +153 -0
- package/assets/skills/coordinator-single-responsibility-merge-gate/SKILL.md +14 -0
- package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +255 -0
- package/assets/skills/efficient-multi-agent-research/SKILL.md +177 -0
- package/assets/skills/fixing-documentation-errors/SKILL.md +258 -0
- package/assets/skills/implementer-maintaining-memory/SKILL.md +84 -0
- package/assets/skills/implementer-orchestrating-execution/SKILL.md +125 -0
- package/assets/skills/implementer-receiving-dispatch/SKILL.md +127 -0
- package/assets/skills/implementer-receiving-review-feedback/SKILL.md +125 -0
- package/assets/skills/implementer-status-and-handoff/SKILL.md +150 -0
- package/assets/skills/implementer-tdd-and-quality/SKILL.md +99 -0
- package/assets/skills/memory-audit-recover/SKILL.md +153 -0
- package/assets/skills/memory-curate/SKILL.md +139 -0
- package/assets/skills/memory-maintenance/SKILL.md +87 -0
- package/assets/skills/memory-read-discipline/SKILL.md +164 -0
- package/assets/skills/memory-search-advanced/SKILL.md +217 -0
- package/assets/skills/memory-write-discipline/SKILL.md +135 -0
- package/assets/skills/orchestrate/SKILL.md +795 -0
- package/assets/skills/persistent-watcher-archetype/SKILL.md +225 -0
- package/assets/skills/prime-agent/SKILL.md +92 -0
- package/assets/skills/project-hotpath-gate/SKILL.md +255 -0
- package/assets/skills/project-philosophy/SKILL.md +418 -0
- package/assets/skills/project-philosophy/resources/philosophy-template.md +155 -0
- package/assets/skills/project-philosophy/resources/reliability-class-library.md +653 -0
- package/assets/skills/project-setup/SKILL.md +1007 -0
- package/assets/skills/project-setup/resources/implementation-agent.md +826 -0
- package/assets/skills/researcher-answering-queries/SKILL.md +100 -0
- package/assets/skills/researcher-investigating/SKILL.md +152 -0
- package/assets/skills/researcher-maintaining-memory/SKILL.md +176 -0
- package/assets/skills/state-migration/SKILL.md +54 -0
- package/assets/skills/thrum/SKILL.md +161 -0
- package/assets/skills/thrum/resources/ANTI_PATTERNS.md +132 -0
- package/assets/skills/thrum/resources/BOUNDARIES.md +56 -0
- package/assets/skills/thrum/resources/CLI_REFERENCE.md +1066 -0
- package/assets/skills/thrum/resources/IDENTITY.md +49 -0
- package/assets/skills/thrum/resources/LISTENER_PATTERN.md +64 -0
- package/assets/skills/thrum/resources/MESSAGING.md +163 -0
- package/assets/skills/thrum/resources/TMUX_SESSIONS.md +118 -0
- package/assets/skills/thrum/resources/WORKTREES.md +117 -0
- package/assets/skills/thrum-memory/SKILL.md +138 -0
- package/assets/skills/trace-spec-to-plan/SKILL.md +104 -0
- package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +57 -0
- package/assets/skills/update-queue/SKILL.md +149 -0
- package/assets/skills/using-the-queue/SKILL.md +172 -0
- package/assets/skills/using-thrum-state/SKILL.md +104 -0
- package/assets/skills/verify-against-plan/SKILL.md +323 -0
- package/assets/skills/verify-against-source/SKILL.md +237 -0
- package/assets/skills/watcher-archetype/SKILL.md +84 -0
- package/assets/skills/writing-durable-markdown/SKILL.md +66 -0
- package/dist/hooks/block-sync-cd.d.ts +9 -0
- package/dist/hooks/block-sync-cd.js +71 -0
- package/dist/hooks/block-sync-cd.test.d.ts +1 -0
- package/dist/hooks/block-sync-cd.test.js +61 -0
- package/dist/hooks/shell-env.d.ts +8 -0
- package/dist/hooks/shell-env.js +22 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +25 -0
- package/dist/installer.d.ts +2 -0
- package/dist/installer.js +86 -0
- 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.
|