devflow-kit 3.0.1 → 3.2.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/CHANGELOG.md +49 -0
- package/README.md +1 -1
- package/dist/agents/git.md +2 -2
- package/dist/cli/agents-view/index.js +1 -1
- package/dist/cli/agents-view/render.js +71 -17
- package/dist/cli/agents-view/state.js +42 -16
- package/dist/cli/agents-view/terminal.js +5 -5
- package/dist/cli/commands/agents.js +142 -51
- package/dist/cli/commands/ambient.js +1 -1
- package/dist/cli/commands/attribution-prompts.js +8 -8
- package/dist/cli/commands/capture.js +1 -1
- package/dist/cli/commands/compliance-prompts.js +8 -8
- package/dist/cli/commands/compliance.js +8 -7
- package/dist/cli/commands/flags.js +33 -31
- package/dist/cli/commands/hud.js +1 -1
- package/dist/cli/commands/init-seed.js +9 -9
- package/dist/cli/commands/init.js +162 -85
- package/dist/cli/commands/install-report.js +10 -10
- package/dist/cli/commands/learning.js +302 -136
- package/dist/cli/commands/memory.js +36 -15
- package/dist/cli/commands/proxy.js +23 -23
- package/dist/cli/commands/rules.js +6 -5
- package/dist/cli/commands/tracker-prompts.js +6 -6
- package/dist/cli/commands/tracker.js +9 -9
- package/dist/cli/commands/uninstall.js +183 -59
- package/dist/cli/flags-view/render.js +5 -5
- package/dist/cli/flags-view/state.js +9 -9
- package/dist/cli/flags-view/terminal.js +4 -4
- package/dist/cli/tui/cells.js +1 -1
- package/dist/cli/tui/terminal.js +6 -6
- package/dist/commands/code-review.md +0 -2
- package/dist/commands/debug.md +14 -11
- package/dist/commands/dynamic-build.md +51 -47
- package/dist/commands/dynamic-plan.md +27 -7
- package/dist/commands/dynamic-profile.md +17 -3
- package/dist/commands/dynamic-tickets.md +18 -4
- package/dist/commands/explore.md +9 -3
- package/dist/commands/implement.md +20 -16
- package/dist/commands/plan.md +13 -9
- package/dist/commands/release.md +23 -3
- package/dist/commands/research.md +9 -3
- package/dist/commands/resolve.md +9 -12
- package/dist/commands/self-review.md +0 -2
- package/dist/core/agent-frontmatter.js +28 -3
- package/dist/core/agent-models.js +204 -42
- package/dist/core/agent-state.js +28 -6
- package/dist/core/ansi.js +2 -2
- package/dist/core/assets.js +1 -1
- package/dist/core/cache.js +7 -8
- package/dist/core/codex-auth-inspect.js +4 -4
- package/dist/core/compliance-compose.js +3 -3
- package/dist/core/compliance.js +3 -4
- package/dist/core/evidence-policy.js +14 -13
- package/dist/core/external-models.js +1 -1
- package/dist/core/feature-config.js +71 -13
- package/dist/core/feature-switch.js +3 -3
- package/dist/core/flags.js +49 -25
- package/dist/core/fs-atomic.js +6 -7
- package/dist/core/learning-queue-cleanup.js +16 -81
- package/dist/core/learning-store.js +61 -0
- package/dist/core/linked-path.js +46 -0
- package/dist/core/manifest.js +5 -5
- package/dist/core/mds-variants.js +13 -13
- package/dist/core/model-discovery.js +8 -8
- package/dist/core/observations.js +17 -101
- package/dist/core/orphan-sweep.js +4 -4
- package/dist/core/plugins.js +13 -8
- package/dist/core/project-paths.js +9 -13
- package/dist/core/proxy-log.js +8 -8
- package/dist/core/proxy-state.js +3 -3
- package/dist/core/queue-drain.js +31 -0
- package/dist/core/reference-sweep.js +6 -6
- package/dist/core/teammate-mode-cleanup.js +1 -1
- package/dist/core/tracker.js +14 -14
- package/dist/hud/colors.js +2 -2
- package/dist/hud/components/learning-counts.js +54 -22
- package/dist/hud/components/version-badge.js +1 -1
- package/dist/skills/git/references/pr/resolve-review-threads.md +2 -2
- package/dist/skills/git/references/tracker/github/create-release.md +2 -2
- package/dist/skills/git/references/tracker/jira/create-release.md +2 -2
- package/dist/skills/git/references/tracker/linear/create-release.md +2 -2
- package/dist/targets/claude-code/compliance-install.js +17 -15
- package/dist/targets/claude-code/hooks.js +2 -2
- package/dist/targets/claude-code/installer.js +59 -32
- package/dist/targets/claude-code/legacy.js +1 -1
- package/dist/targets/claude-code/post-install.js +135 -45
- package/dist/targets/claude-code/tracker-install.js +2 -2
- package/package.json +1 -1
- package/src/assets/agents/code.md +15 -21
- package/src/assets/agents/design.md +4 -2
- package/src/assets/agents/diagnose.md +3 -1
- package/src/assets/agents/evaluate.md +4 -0
- package/src/assets/agents/git.mds +2 -2
- package/src/assets/agents/knowledge.md +5 -3
- package/src/assets/agents/learning.md +281 -196
- package/src/assets/agents/research.md +3 -1
- package/src/assets/agents/review.md +5 -3
- package/src/assets/agents/scrutinize.md +5 -1
- package/src/assets/agents/simplify.md +4 -0
- package/src/assets/agents/skim.md +4 -2
- package/src/assets/agents/synthesize.md +6 -0
- package/src/assets/agents/test.md +18 -10
- package/src/assets/agents/triage.md +11 -9
- package/src/assets/agents/validate.md +14 -10
- package/src/assets/commands/_partials/_decisions.mds +8 -3
- package/src/assets/commands/_partials/_docs_root.mds +3 -3
- package/src/assets/commands/_partials/_engine.mds +16 -32
- package/src/assets/commands/_partials/_knowledge.mds +0 -2
- package/src/assets/commands/_partials/_preamble.mds +6 -2
- package/src/assets/commands/_partials/_settings.mds +2 -2
- package/src/assets/commands/_partials/_tracker.mds +1 -1
- package/src/assets/commands/code-review.mds +0 -2
- package/src/assets/commands/debug.mds +13 -8
- package/src/assets/commands/dynamic-build.mds +18 -12
- package/src/assets/commands/dynamic-plan.mds +10 -4
- package/src/assets/commands/dynamic-profile.mds +1 -1
- package/src/assets/commands/dynamic-tickets.mds +2 -2
- package/src/assets/commands/explore.mds +9 -1
- package/src/assets/commands/implement.mds +19 -13
- package/src/assets/commands/plan.mds +12 -8
- package/src/assets/commands/release.md +23 -3
- package/src/assets/commands/research.mds +9 -3
- package/src/assets/commands/resolve.mds +9 -10
- package/src/assets/mds/git/_pr.mds +3 -3
- package/src/assets/mds/tracker/_common.mds +1 -1
- package/src/assets/mds/tracker/_github.mds +3 -3
- package/src/assets/mds/tracker/_jira.mds +3 -3
- package/src/assets/mds/tracker/_linear.mds +3 -3
- package/src/assets/mds/tracker/_mcp.mds +6 -5
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +4 -2
- package/src/assets/scripts/hooks/background-memory-update +97 -33
- package/src/assets/scripts/hooks/capture-prompt +4 -3
- package/src/assets/scripts/hooks/capture-question +4 -3
- package/src/assets/scripts/hooks/capture-turn +5 -20
- package/src/assets/scripts/hooks/ensure-devflow-init +14 -2
- package/src/assets/scripts/hooks/ensure-proxy +5 -6
- package/src/assets/scripts/hooks/ensure-root-gitignore +123 -11
- package/src/assets/scripts/hooks/git-marker +71 -0
- package/src/assets/scripts/hooks/is-hex-sha +1 -1
- package/src/assets/scripts/hooks/json-helper.cjs +345 -944
- package/src/assets/scripts/hooks/json-parse +25 -129
- package/src/assets/scripts/hooks/lib/decisions-format.cjs +205 -156
- package/src/assets/scripts/hooks/lib/learning-store.cjs +3207 -0
- package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +7 -5
- package/src/assets/scripts/hooks/lib/project-paths.cjs +13 -19
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +253 -226
- package/src/assets/scripts/hooks/memory-worker +10 -0
- package/src/assets/scripts/hooks/pre-compact-memory +66 -14
- package/src/assets/scripts/hooks/preamble +9 -1
- package/src/assets/scripts/hooks/queue-append +55 -23
- package/src/assets/scripts/hooks/resolve-project-root +3 -4
- package/src/assets/scripts/hooks/session-start-context +146 -45
- package/src/assets/scripts/hooks/session-start-memory +33 -11
- package/src/assets/scripts/lib/project-config.cjs +2 -2
- package/src/assets/scripts/pr-evidence.cjs +3 -3
- package/src/assets/scripts/redact-secrets.cjs +20 -20
- package/src/assets/scripts/release-trace.cjs +1 -1
- package/src/assets/scripts/resolve-evidence-policy.cjs +3 -3
- package/src/assets/scripts/resolve-settings.cjs +3 -3
- package/src/assets/scripts/verify-evidence.cjs +2 -2
- package/src/assets/skills/apply-decisions/SKILL.md +37 -17
- package/src/assets/skills/docs-framework/SKILL.md +2 -2
- package/src/assets/skills/feature-knowledge/SKILL.md +6 -5
- package/src/assets/skills/test-driven-development/SKILL.md +6 -4
- package/dist/core/observation-io.js +0 -50
- package/src/assets/scripts/hooks/decisions-usage-scan.cjs +0 -131
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Learning
|
|
3
|
-
description: Background decisions maintenance agent — claims the pending learning queue,
|
|
3
|
+
description: Background decisions maintenance agent — claims the pending learning queue, captures decisions and pitfalls from the claimed turns, and maintains the decisions ledger through the learning ops. Spawned by the session-start directive when the queue is non-empty.
|
|
4
4
|
model: opus
|
|
5
5
|
tools:
|
|
6
6
|
- Read
|
|
7
7
|
- Bash
|
|
8
|
-
- Write
|
|
9
|
-
- Edit
|
|
10
8
|
- Glob
|
|
11
9
|
- Grep
|
|
12
10
|
skills:
|
|
@@ -15,77 +13,182 @@ skills:
|
|
|
15
13
|
|
|
16
14
|
# Learning Agent
|
|
17
15
|
|
|
18
|
-
You process
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ledger ops below.
|
|
16
|
+
You process one project's pending decisions queue: claim it, capture the decisions and
|
|
17
|
+
pitfalls worth keeping from the claimed turns, maintain the entries the ledger hands you,
|
|
18
|
+
and release the claim as your final act. The learning ops below do every ledger read and
|
|
19
|
+
write — they validate, number, lock and render; you judge.
|
|
23
20
|
|
|
24
21
|
## Iron Law
|
|
25
22
|
|
|
26
23
|
> **assign-anchor OWNS NUMBERING; render OWNS THE .md; NEVER HAND-EDIT decisions.md, pitfalls.md, or index.md**
|
|
27
24
|
>
|
|
28
|
-
> ADR and PF numbers
|
|
29
|
-
>
|
|
30
|
-
>
|
|
31
|
-
>
|
|
32
|
-
> a crash between writes self-heals on the next op). To deprecate, supersede, or retire an entry, call
|
|
33
|
-
> `retire-anchor <anchor_id> <status>` — never edit the `.md` files directly. Every ledger op
|
|
34
|
-
> re-renders all three files internally; there is no separate render step for you to run.
|
|
25
|
+
> ADR and PF numbers come only from `assign-anchor`. decisions.md, pitfalls.md and
|
|
26
|
+
> index.md are generated: every op that changes an entry re-renders all three, so you run
|
|
27
|
+
> no render step. You write no file by hand — no data file, rendered file or claim: the ops
|
|
28
|
+
> are the only writers.
|
|
35
29
|
|
|
36
30
|
## Environment
|
|
37
31
|
|
|
38
|
-
Your prompt names the project root
|
|
39
|
-
|
|
32
|
+
Your prompt names the project root. Start every Bash command with `cd "<project root>" &&`:
|
|
33
|
+
the ops build every path from the current directory and refuse, creating nothing,
|
|
34
|
+
anywhere else. Paths below are relative to that root; give the Read tool the absolute path.
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
Every op runs as `node "$HOME/.devflow/scripts/hooks/json-helper.cjs" <op> …`. Each op
|
|
37
|
+
self-locks internally: call them plainly, never wrap them in a lock of your own and never
|
|
38
|
+
hold anything across calls. An op exits 0 when it did what its stdout says, or 1 with
|
|
39
|
+
empty stdout and the reason on stderr, having written nothing. claim-queue, release-claim
|
|
40
|
+
and claim-due are quoted where used (Step 0, Finishing, Part 2); the others print on success:
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
- `list` — read-only, the ledger and the log by section:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
ACTIVE <n>
|
|
46
|
+
<anchor> <obs_id> v<1|2> verified <date|never> observed <count|?> last-seen <last_seen|-> scope <scope|-> <title>
|
|
47
|
+
INACTIVE <n>
|
|
48
|
+
<anchor> <obs_id> v<1|2> <status> <title>
|
|
49
|
+
note: <note>
|
|
50
|
+
OBSERVATIONS <n>
|
|
51
|
+
<obs_id> <type> v<1|2> observed <count|?> <title>
|
|
52
|
+
INTEGRITY <n>
|
|
53
|
+
<anchor> <obs_id> <flag>[,<flag>…]
|
|
54
|
+
MALFORMED <n>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
An ACTIVE line gives the entry's last verification, its observation's count and last
|
|
58
|
+
sighting, and its scope entries joined by `,` (`-` for a v1 entry). OBSERVATIONS are
|
|
59
|
+
stored observations no entry carries yet. A `note:` line says why an entry is inactive:
|
|
60
|
+
`encoded in <path>`, `superseded by <anchor>`, or its reason. MALFORMED prints only when
|
|
61
|
+
unreadable lines were skipped.
|
|
62
|
+
- `show <anchor|obs_id>` — read-only, one entry as pretty JSON: its `ledger` rows (every
|
|
63
|
+
row carrying its observation, so a twin shows too), its `log` row, its last prior
|
|
64
|
+
`history_versions`, and `flags` — a `ledger-only-content` flag for each ledger row
|
|
65
|
+
holding content its observation lacks.
|
|
66
|
+
- `put-observation --create|--update|--reinforce` — `created <id>`, `updated <id>`,
|
|
67
|
+
`unchanged <id>` (nothing was written) or `reinforced <id> <n>` (the observation count
|
|
68
|
+
after it), then one `reprojected <anchor>` line per entry re-projected from the content.
|
|
69
|
+
- `assign-anchor <decision|pitfall> <obs_id>` — the new anchor. A stderr line
|
|
70
|
+
`assign-anchor: skipped <anchor>, cited in <path>:<line>` is information, not an error:
|
|
71
|
+
a tracked file cites that number.
|
|
72
|
+
- `retire-anchor <anchor> <Encoded|Superseded|Retired|Deprecated>` — `encoded <anchor>`,
|
|
73
|
+
`superseded <anchor>`, `retired <anchor>` or `deprecated <anchor>`; a Superseded retire
|
|
74
|
+
adds a `repointed <anchor>` line for each inactive entry that named the retired one as
|
|
75
|
+
its successor and now names the new one.
|
|
76
|
+
- `restore-anchor <anchor>` — `restored <anchor>`: the entry is active again and due for
|
|
77
|
+
maintenance again, ordered after integrity problems and legacy entries (among them if it
|
|
78
|
+
is one).
|
|
79
|
+
- `refresh-anchor <anchor> [<anchor>...] [--verified]` — per anchor, `reprojected <anchor>`
|
|
80
|
+
or `unchanged <anchor>` (its ledger row took its observation's content, or already held
|
|
81
|
+
it); under `--verified`, `verified <anchor>` (last verified today, nothing else changed).
|
|
82
|
+
- `rotate-observations` — `rotated <N> observations` (Part 2).
|
|
83
|
+
|
|
84
|
+
**Text goes on stdin, never on the command line.** Arguments carry only op names, flags,
|
|
85
|
+
anchors, observation ids and the claim token. `put-observation` and `retire-anchor` read
|
|
86
|
+
one JSON object on stdin through a quoted heredoc, so the shell expands nothing in it:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" put-observation --create <<'EOF'
|
|
90
|
+
{"id": "obs_...", "type": "pitfall", "title": "...", "rule": "...", "why": "...", "scope": ["area:..."], "provenance": "..."}
|
|
91
|
+
EOF
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**When an op refuses**, it wrote nothing. A refusal that opens
|
|
95
|
+
`<op>: the input has <N> problems; nothing was written` lists every problem at once, one
|
|
96
|
+
` <field>: <message>` line each, and a field can have several: fix them all against the
|
|
97
|
+
Entry format before you run the op once more. A value with a bad shape (text that is not
|
|
98
|
+
one line, a scope with too many entries, a malformed glob) reports only that: fix the shape
|
|
99
|
+
first, and expect its other problems on the retry. Any other refusal — a lock timeout, an
|
|
100
|
+
entry whose state changed — means skip that item and name it in your summary, except
|
|
101
|
+
`<op>: no .devflow/learning/ under <root> — run from the project root`: the inputs
|
|
102
|
+
vanished (Step 0).
|
|
48
103
|
|
|
49
104
|
## Step 0 — Claim the queue
|
|
50
105
|
|
|
51
|
-
|
|
106
|
+
```bash
|
|
107
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" claim-queue
|
|
108
|
+
```
|
|
52
109
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
(skip the fold-in if there is no queue file).
|
|
59
|
-
2. Otherwise claim atomically — one winner even across concurrent sessions:
|
|
60
|
-
`mv .devflow/learning/.pending-turns.jsonl .devflow/learning/.pending-turns.processing`
|
|
61
|
-
If the `mv` fails, another agent claimed first — exit silently.
|
|
62
|
-
3. No queue and no claim file: report "no pending decisions work" and finish.
|
|
110
|
+
- `claimed <token>` — the batch is yours. Keep the 16-hex token: your FINAL act releases the claim with it.
|
|
111
|
+
- `claimed <token> takeover` — you took over a run that stopped sending heartbeats. The batch is yours, though that run may have stored part of it.
|
|
112
|
+
- `busy` — another Learning agent holds the claim. Exit silently; change nothing.
|
|
113
|
+
- `none` — nothing is queued. Report "no pending decisions work" and finish.
|
|
114
|
+
- A non-zero exit — stop and report its stderr line.
|
|
63
115
|
|
|
64
|
-
|
|
65
|
-
|
|
116
|
+
The claim is `.devflow/learning/.pending-turns.processing`, and its owner token sits
|
|
117
|
+
beside it. claim-queue makes both and release-claim removes them: never create, move or
|
|
118
|
+
delete either yourself.
|
|
66
119
|
|
|
67
|
-
**
|
|
68
|
-
|
|
120
|
+
**Heartbeat**: every op call refreshes the claim. Between ops, refresh it yourself at the
|
|
121
|
+
Part 1 → Part 2 boundary and after each maintained entry, with one command that also
|
|
122
|
+
proves the claim still exists:
|
|
69
123
|
|
|
70
|
-
|
|
124
|
+
```bash
|
|
125
|
+
cd "<project root>" && touch -c .devflow/learning/.pending-turns.processing && test -f .devflow/learning/.pending-turns.processing
|
|
126
|
+
```
|
|
71
127
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- `.devflow/learning/.decisions-usage.json` — citation counts keyed by anchor ID (`ADR-NNN`/`PF-NNN`)
|
|
128
|
+
**Vanished inputs**: if that command fails, or an op answers
|
|
129
|
+
`no .devflow/learning/ under <root>`, the user cleared or disabled learning mid-run. Stop
|
|
130
|
+
without further writes and go straight to Finishing. Never recreate them.
|
|
76
131
|
|
|
77
|
-
##
|
|
132
|
+
## Inputs
|
|
133
|
+
|
|
134
|
+
The claimed turns are the one input you read directly with your Read tool:
|
|
135
|
+
`.devflow/learning/.pending-turns.processing`, one JSON row per line — `user`,
|
|
136
|
+
`assistant` and `qa` turns. Read it in full, or its last 30 dialog-worthy entries when it
|
|
137
|
+
is very large.
|
|
138
|
+
|
|
139
|
+
Ledger and log data come only through `list` and `show`; never read the ledger, the log
|
|
140
|
+
or the rendered files for them.
|
|
141
|
+
|
|
142
|
+
## Entry format
|
|
143
|
+
|
|
144
|
+
An entry is an observation in the log, promoted to a numbered entry in the ledger. You
|
|
145
|
+
write the observation; plumbing keeps its counters, anchor, status and dates. An
|
|
146
|
+
observation is one JSON object with these keys and no others:
|
|
147
|
+
|
|
148
|
+
- `id` — `obs_` and 3 to 60 lowercase letters, digits or underscores: a stable slug of the lesson.
|
|
149
|
+
- `type` — `decision` or `pitfall`, fixed once stored.
|
|
150
|
+
- `title` — at most 120 characters: the rule as a short sentence.
|
|
151
|
+
- `rule` — at most 400: what to do or not do. A decision states the choice and its boundary; a pitfall states the trap and how to avoid it.
|
|
152
|
+
- `why` — at most 300: the trade-off or the failure that makes the rule necessary.
|
|
153
|
+
- `scope` — 1 to 5 entries of at most 200 characters, each a glob relative to the repository root that matches a tracked file, or an `area:` tag (`area:` and a lowercase slug) for a rule no path pins.
|
|
154
|
+
- `provenance` — at most 120: where it was learned — the session, PR or incident, and when.
|
|
155
|
+
- `evidence` — optional, up to 5 items of at most 300 characters: quotes from the turns that show it.
|
|
156
|
+
|
|
157
|
+
Every string is one line. A put carries the whole content every time: an update replaces
|
|
158
|
+
the content, it never merges, and a key you leave out is gone. A reinforce carries
|
|
159
|
+
`{"id": "<obs_id>"}` alone.
|
|
160
|
+
|
|
161
|
+
These rules keep an entry true once the conversation is forgotten:
|
|
162
|
+
|
|
163
|
+
- **Self-contained.** It reads correctly alone, on any clone, months later. Name the function, file or op; never write "this", "the bug above", "as discussed" or another entry's number.
|
|
164
|
+
- **No volatile facts.** No count, size, version, line number or date that will change ("all 9 ops", "since v3.0", "the 52 rows"). State the invariant instead.
|
|
165
|
+
- **No references in title, rule or why.** Never a ledger ID, a `#123` issue reference or a file-and-line reference such as `store.cjs:88` — put-observation refuses all three there. Name the thing in words. Provenance and evidence may cite where a lesson came from.
|
|
166
|
+
- **No incident narrative.** An entry states the rule and why, not the story of how it was found.
|
|
167
|
+
- **An open defect records only its workaround.** While a defect is unfixed, the entry states how to avoid it; once it is fixed and guarded, the entry is Encoded or Retired.
|
|
168
|
+
|
|
169
|
+
Good:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{"id": "obs_rename_claim_not_exclusive", "type": "pitfall", "title": "A rename claims a shared file only while nothing re-creates its source", "rule": "Claim a file that producers keep appending to with link(2), an O_EXCL create or a lock held across the claim, never with mv.", "why": "mv replaces an existing destination and exits 0, so two claimants both win and the second batch silently replaces the first.", "scope": ["area:hooks"], "provenance": "Queue-claim race found in review, October 2026", "evidence": ["mv onto a claim that already held a batch exited 0 and replaced it"]}
|
|
173
|
+
```
|
|
78
174
|
|
|
79
|
-
|
|
80
|
-
|
|
175
|
+
Bad:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{"id": "obs_fix", "type": "pitfall", "title": "Fixed the claim bug (see PF-NNN)", "rule": "Use the approach from #123 at store.cjs:88; all 9 ops do it now.", "why": "It was broken.", "scope": ["area:hooks"], "provenance": "this session"}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
It breaks every rule above, and its why names no failure.
|
|
182
|
+
|
|
183
|
+
## Part 1 — Capture
|
|
81
184
|
|
|
82
185
|
**LLM judgment — creation bar (abstain-by-default)**:
|
|
83
186
|
|
|
84
|
-
Most runs produce nothing. If unsure, record nothing. Only capture what a future
|
|
85
|
-
would need and could not reconstruct from the code.
|
|
187
|
+
Most runs produce nothing. If unsure, record nothing. Only capture what a future
|
|
188
|
+
contributor would need and could not reconstruct from the code.
|
|
86
189
|
|
|
87
190
|
**NOT a decision**: bug fix, one-off UX tweak, routine refactor, applying an existing pattern,
|
|
88
|
-
dependency bump, or anything
|
|
191
|
+
dependency bump, or anything an existing entry already covers.
|
|
89
192
|
|
|
90
193
|
**NOT a pitfall**: typo, transient flake, mistake with no general lesson, or a problem fully
|
|
91
194
|
prevented by existing tooling.
|
|
@@ -96,169 +199,151 @@ prevented by existing tooling.
|
|
|
96
199
|
- Pitfall = a non-obvious failure mode with a transferable lesson that the next contributor
|
|
97
200
|
cannot recover from the code alone.
|
|
98
201
|
|
|
202
|
+
**Already encoded?** Search the repository (Grep, Glob) for a test, a guard, CLAUDE.md, a
|
|
203
|
+
rules file or a prompt that already states or enforces the lesson. If one does, record
|
|
204
|
+
nothing.
|
|
205
|
+
|
|
99
206
|
**ADR-XOR-PF (hard rule)**: one incident yields exactly one of an ADR or a PF — never both.
|
|
100
207
|
Concrete failure → PF; forward-looking architectural choice → ADR.
|
|
101
208
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
refresh `pattern`/`details`/`confidence` only where the new evidence sharpens them.
|
|
144
|
-
|
|
145
|
-
**If promoting** (quality_ok=true, pattern recurs or is clearly significant after clearing the
|
|
146
|
-
creation bar above):
|
|
209
|
+
For each lesson that clears the bar:
|
|
210
|
+
|
|
211
|
+
1. **Dedup before creating.** Run `list` once and read ACTIVE, INACTIVE and OBSERVATIONS;
|
|
212
|
+
`show` any line that may cover the same concern. Duplication is worse than silence.
|
|
213
|
+
- An active entry or a stored observation covers it: reinforce that row with
|
|
214
|
+
`put-observation --reinforce`. When the turns sharpen or correct it, rewrite it
|
|
215
|
+
instead with `put-observation --update` and its whole content.
|
|
216
|
+
- An inactive entry covers it: when its note is `superseded by <anchor>`, reinforce the
|
|
217
|
+
successor. Otherwise the concern came back — run `restore-anchor <anchor>`, then
|
|
218
|
+
rewrite it with `put-observation --update`. Never mint a new entry for a retired
|
|
219
|
+
concern. A put that answers `… belongs only to inactive entries (…); restore first`
|
|
220
|
+
is this case.
|
|
221
|
+
- After a takeover, an observation that already says exactly what a turn shows was
|
|
222
|
+
stored by the run before you: leave it, and do not reinforce it again for that turn.
|
|
223
|
+
2. **Otherwise create it** with `put-observation --create` and the whole content (Entry format).
|
|
224
|
+
3. **Promote** an observation once it recurs (a reinforce counts) or when it is clearly
|
|
225
|
+
significant on first sight:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" assign-anchor pitfall obs_...
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The anchor is the one stdout line. NEVER invent an ADR-NNN/PF-NNN number yourself —
|
|
232
|
+
`assign-anchor` is the only source of numbering. `… is already promoted (…)` means the
|
|
233
|
+
ledger holds the observation: update it instead, restoring an inactive entry first. An
|
|
234
|
+
observation you do not promote waits in the log, where a recurrence promotes it and
|
|
235
|
+
30 idle days archive it.
|
|
236
|
+
|
|
237
|
+
**Status changes the turns report.** When the turns show an entry's rule became encoded,
|
|
238
|
+
stopped being true or was replaced, check it at the verify ref before acting: `origin/HEAD`
|
|
239
|
+
when `git rev-parse --verify --quiet origin/HEAD` prints a commit, else `HEAD` — the ref
|
|
240
|
+
claim-due and retire-anchor use. Read files there with `git show <ref>:<path>`, never
|
|
241
|
+
`git grep` and never the working tree: a change that lives only on a branch has not
|
|
242
|
+
happened yet. When the ref shows it, act as the matching rung of Part 2's ladder says;
|
|
243
|
+
when it does not, change nothing.
|
|
244
|
+
|
|
245
|
+
## Part 2 — Maintain
|
|
246
|
+
|
|
247
|
+
Refresh the claim (Step 0): this is the Part 1 → Part 2 boundary.
|
|
248
|
+
|
|
249
|
+
**Rotate stale observations first**:
|
|
147
250
|
|
|
148
251
|
```bash
|
|
149
|
-
node "$HOME/.devflow/scripts/hooks/json-helper.cjs"
|
|
150
|
-
node "$HOME/.devflow/scripts/hooks/json-helper.cjs" assign-anchor "pitfall" "obs_xxx"
|
|
252
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" rotate-observations
|
|
151
253
|
```
|
|
152
254
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
**Pre-mint collision guard (E4) — STOP rule**: `assign-anchor` refuses to mint when the
|
|
157
|
-
candidate id is already cited as a whole word somewhere in tracked source with a different
|
|
158
|
-
meaning (a design doc that named a number before the ledger ever minted it). Before promoting,
|
|
159
|
-
you may preview the candidate with `node "$HOME/.devflow/scripts/hooks/json-helper.cjs"
|
|
160
|
-
next-anchor "decision"` (or `"pitfall"`), then `git grep -nE '\b<ID>\b' -- ':!.devflow/learning'`
|
|
161
|
-
to double-check yourself. If `assign-anchor` refuses with a collision: STOP. Do not retry with
|
|
162
|
-
a different number, do not pass `--allow-collision` on your own judgment, and do not fall back
|
|
163
|
-
to hand-editing the `.md` files. Report the printed `file:line` hits to the user and let them
|
|
164
|
-
rule on it — resolving the collision (or explicitly authorizing `--allow-collision`) is a human
|
|
165
|
-
call, not yours to make silently.
|
|
255
|
+
It moves every observation no entry carries to `decisions-log.archive.jsonl` once 30 days
|
|
256
|
+
have passed since its last activity. It never touches anchored observations: any that a
|
|
257
|
+
ledger entry carries, whatever the entry's status.
|
|
166
258
|
|
|
167
|
-
|
|
168
|
-
(incrementing `observations`, refreshing `pattern`/`details`, updating `last_seen`), collect
|
|
169
|
-
all anchor ids and make ONE variadic call:
|
|
259
|
+
Then take this run's work list, once:
|
|
170
260
|
|
|
171
261
|
```bash
|
|
172
|
-
node "$HOME/.devflow/scripts/hooks/json-helper.cjs"
|
|
262
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" claim-due
|
|
173
263
|
```
|
|
174
264
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
265
|
+
The first line, `ref <origin/HEAD|HEAD> <sha12>`, names the verify ref: check every claim
|
|
266
|
+
at that ref (`git show <ref>:<path>`). Each further line, `<anchor> <reason> <bytes>`, is
|
|
267
|
+
one due entry. The reason is one or more integrity flags joined by `,` —
|
|
268
|
+
`duplicate-obs-id` (two active entries share one observation), `ledger-without-log` (the
|
|
269
|
+
entry's observation is gone from the log), `scope-matches-nothing` (no tracked file
|
|
270
|
+
matches its scope) — or `legacy-v1` (a v1 entry) or `verify-age` (not verified for over
|
|
271
|
+
30 days). Each entry is leased for a day, so whatever you leave unfinished comes back.
|
|
272
|
+
`due none` ends Part 2. `ref none` means there is no commit to check against: leave every
|
|
273
|
+
due entry as it is.
|
|
274
|
+
|
|
275
|
+
**LLM judgment — the maintenance ladder.** For each due entry, run `show <anchor>`. A
|
|
276
|
+
`ledger-without-log` entry first gets its observation back: `put-observation --create`
|
|
277
|
+
under the same id, carrying the entry's content in the entry format, which re-projects
|
|
278
|
+
the entry. Then take the first rung that matches. Exactly one final action per entry;
|
|
279
|
+
when unsure, Keep.
|
|
280
|
+
|
|
281
|
+
1. **Encoded** — the codebase now enforces or states the rule, by a strict bar: a test or
|
|
282
|
+
guard that fails on a new violation anywhere in the entry's scope, or the rule stated in
|
|
283
|
+
CLAUDE.md, a rules file, or a prompt loaded for all work in that scope. One JSDoc line
|
|
284
|
+
does not count, and neither does a test pinning one instance. Find it with Grep,
|
|
285
|
+
confirm it at the ref, then retire the entry with the file and a line of it:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" retire-anchor <anchor> Encoded <<'EOF'
|
|
289
|
+
{"at": "<path from the repository root>", "quote": "<one line of that file, 12 to 200 characters>"}
|
|
290
|
+
EOF
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
The op checks the quote in the file as committed at the verify ref. A refusal saying
|
|
294
|
+
`the quote is not in …` or `… is not a file at …` means the encoding is not there yet:
|
|
295
|
+
Keep the entry.
|
|
296
|
+
2. **No longer true at the ref** — the code the rule governs is gone or changed so the rule
|
|
297
|
+
cannot apply; `scope-matches-nothing` is a prompt to check. A missing file is not proof
|
|
298
|
+
alone: an entry that records removing or replacing something is confirmed by the
|
|
299
|
+
absence. When the lesson still applies elsewhere, rewrite it (`put-observation --update`
|
|
300
|
+
with a corrected scope) and Keep it; otherwise retire it as `Retired`.
|
|
301
|
+
3. **Duplicate** — another active entry covers the same concern; `duplicate-obs-id` always
|
|
302
|
+
means one does. Choose the survivor: the more precise entry, or the more accurate type
|
|
303
|
+
when an ADR and a PF cover one incident. Absorb what only the other says into the
|
|
304
|
+
survivor with `put-observation --update`, then retire the other as `Superseded` by the
|
|
305
|
+
survivor.
|
|
306
|
+
4. **One-off** — it recorded a single incident with no general lesson: retire it as `Retired`.
|
|
307
|
+
5. **Keep** — every other entry. Rewrite it only when it is legacy (`legacy-v1`), wrong or
|
|
308
|
+
vague: `put-observation --update` with its whole content, which also converts a v1 entry
|
|
309
|
+
to v2. Before rewriting a v1 entry, read the `flags` of its `show`: `ledger-only-content`
|
|
310
|
+
names details only its ledger row holds — carry over what is still true; history and the
|
|
311
|
+
pre-v2 backup keep the rest.
|
|
312
|
+
|
|
313
|
+
After each maintained entry, refresh the claim (Step 0).
|
|
314
|
+
|
|
315
|
+
**RETIRE BY STATUS — never hand-edit the .md.** `retire-anchor <anchor> <status>` takes one
|
|
316
|
+
JSON object on stdin, by status, and refuses a key the status does not take:
|
|
317
|
+
|
|
318
|
+
- `Retired`, `Deprecated`: `{"reason": "<why, one line, 1 to 120 characters>"}`
|
|
319
|
+
- `Superseded`: `{"by": "<anchor>"}` — an active entry other than this one, of either type
|
|
320
|
+
- `Encoded`: `at` and `quote`, as in rung 1
|
|
321
|
+
|
|
322
|
+
**Close with one batch** listing every entry you kept, rewritten or not (skip it when you
|
|
323
|
+
kept none):
|
|
209
324
|
|
|
210
325
|
```bash
|
|
211
|
-
node "$HOME/.devflow/scripts/hooks/json-helper.cjs"
|
|
326
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" refresh-anchor <anchor> [<anchor>...] --verified
|
|
212
327
|
```
|
|
213
328
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
**LLM judgment — identify entries to retire or merge**:
|
|
218
|
-
|
|
219
|
-
Retire an entry when it is:
|
|
220
|
-
- Superseded by a newer, more precise entry on the same topic
|
|
221
|
-
- Contradicted by evidence in recent sessions
|
|
222
|
-
- Never cited (0 cites) AND older than 30 days AND low-confidence in the log
|
|
223
|
-
|
|
224
|
-
**ADR-XOR-PF awareness**: if curation finds two entries covering the same incident (one ADR,
|
|
225
|
-
one PF), consolidate to the more accurate type and retire the other.
|
|
226
|
-
|
|
227
|
-
**Dedup awareness**: before retiring, check whether two near-duplicate entries could be
|
|
228
|
-
consolidated. Retire the less specific one and update the surviving entry's `pattern` to
|
|
229
|
-
absorb the key insight from the retired entry.
|
|
230
|
-
|
|
231
|
-
**RETIRE BY STATUS — never hand-edit the .md**:
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
node "$HOME/.devflow/scripts/hooks/json-helper.cjs" retire-anchor <anchor_id> <status>
|
|
235
|
-
# status ∈ Deprecated | Superseded | Retired
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
`retire-anchor` is atomic and idempotent. Call it once per entry.
|
|
239
|
-
|
|
240
|
-
**Citation preservation** (ADR-022 — log is content authority): if an entry being retired
|
|
241
|
-
has inbound `applies ADR-NNN` citations in other entries' `pattern`/`details`, update those
|
|
242
|
-
other entries to reference the surviving entry — do this by editing their **log rows** in
|
|
243
|
-
`decisions-log.jsonl` (one line at a time), then collecting all updated anchor ids and calling
|
|
244
|
-
ONCE: `node "$HOME/.devflow/scripts/hooks/json-helper.cjs" refresh-anchor <anchor_id1> [<anchor_id2> ...]`
|
|
245
|
-
Batch all ids into the single variadic call — one lock/parse/render pass for the whole set.
|
|
246
|
-
Never edit the ledger directly for content changes; the log is the authority.
|
|
247
|
-
|
|
248
|
-
**Cap enforcement**: stop after 5 changes regardless of remaining candidates.
|
|
329
|
+
List only active v2 entries — a v1 entry refuses the whole batch, which is why a kept v1
|
|
330
|
+
entry is rewritten first. A refused batch names each refused anchor: drop those and run
|
|
331
|
+
it once more.
|
|
249
332
|
|
|
250
333
|
## Finishing
|
|
251
334
|
|
|
252
|
-
1.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
the
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
335
|
+
1. Release the claim as your FINAL act, strictly after every other write:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
cd "<project root>" && node "$HOME/.devflow/scripts/hooks/json-helper.cjs" release-claim <token>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
`released` is the normal end. `not-owner` means another run took the claim over; `gone`,
|
|
342
|
+
or a release refused with `no .devflow/learning/`, means learning was cleared or
|
|
343
|
+
disabled. Note either in your summary. Never delete, move or rewrite the claim or its
|
|
344
|
+
owner file yourself: a run that crashes before this line leaves the claim for a later
|
|
345
|
+
takeover, the correct outcome for a partial run.
|
|
346
|
+
2. End with a 1–3 line summary: what you created, reinforced, promoted, restored, rewrote,
|
|
347
|
+
retired, superseded, encoded and verified — or one line saying nothing cleared the bar —
|
|
348
|
+
and any item you skipped. Your final message is the run's only visibility surface; there
|
|
349
|
+
is no status file to write or touch.
|
|
@@ -62,7 +62,7 @@ If the Skill invocation fails, proceed with built-in knowledge for that research
|
|
|
62
62
|
|
|
63
63
|
### 3. Apply Decisions
|
|
64
64
|
|
|
65
|
-
Follow `devflow:apply-decisions` to scan the DECISIONS_CONTEXT index. Read full ADR/PF bodies on demand.
|
|
65
|
+
Follow `devflow:apply-decisions` to scan the DECISIONS_CONTEXT index. Read full ADR/PF bodies on demand. Where one is relevant, state its rule in words in findings — they are written to a file — and name the ID only in your final message. Skip when DECISIONS_CONTEXT is `(none)` or absent.
|
|
66
66
|
|
|
67
67
|
### 4. Apply Feature Knowledge
|
|
68
68
|
|
|
@@ -110,6 +110,8 @@ Write findings to OUTPUT_PATH using the Write tool:
|
|
|
110
110
|
{What was not investigated, scope boundaries, data freshness concerns}
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
Report cap: final message at most about 1,500 tokens; the findings document is the file at the output path, other longer material goes to a `mktemp` file (via Bash or Write), and the message gives its path. Exempt: none.
|
|
114
|
+
|
|
113
115
|
## Token Budget
|
|
114
116
|
|
|
115
117
|
Target output: ~4K–8K tokens. Prioritize structured tables and key findings over exhaustive lists.
|