devflow-kit 3.2.0 → 3.3.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 (89) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +1 -1
  3. package/dist/cli/commands/learning.js +25 -5
  4. package/dist/commands/code-review.md +1 -1
  5. package/dist/commands/debug.md +1 -1
  6. package/dist/commands/dynamic-build.md +141 -94
  7. package/dist/commands/dynamic-plan.md +1 -1
  8. package/dist/commands/explore.md +1 -1
  9. package/dist/commands/implement.md +133 -133
  10. package/dist/commands/resolve.md +27 -16
  11. package/dist/commands/self-review.md +16 -11
  12. package/dist/core/agent-models.js +10 -7
  13. package/dist/core/learning-tuning-config.js +8 -0
  14. package/dist/core/plugins.js +7 -2
  15. package/dist/skills/git/references/tracker/github/gather-release-evidence.md +1 -1
  16. package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +1 -1
  17. package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +1 -1
  18. package/package.json +1 -1
  19. package/src/assets/agents/code.md +71 -18
  20. package/src/assets/agents/design.md +10 -0
  21. package/src/assets/agents/diagnose.md +16 -11
  22. package/src/assets/agents/evaluate.md +14 -25
  23. package/src/assets/agents/knowledge.md +5 -3
  24. package/src/assets/agents/learning.md +4 -6
  25. package/src/assets/agents/research.md +19 -0
  26. package/src/assets/agents/review.md +10 -0
  27. package/src/assets/agents/scrutinize.md +34 -10
  28. package/src/assets/agents/simplify.md +20 -0
  29. package/src/assets/agents/skim.md +4 -2
  30. package/src/assets/agents/synthesize.md +12 -0
  31. package/src/assets/agents/test.md +2 -2
  32. package/src/assets/agents/triage.md +7 -1
  33. package/src/assets/agents/validate.md +7 -2
  34. package/src/assets/commands/_partials/_engine.mds +21 -24
  35. package/src/assets/commands/_partials/_knowledge.mds +1 -1
  36. package/src/assets/commands/_partials/_plan_contract.mds +1 -1
  37. package/src/assets/commands/_partials/_wave.mds +8 -6
  38. package/src/assets/commands/code-review.mds +1 -1
  39. package/src/assets/commands/dynamic-build.mds +111 -63
  40. package/src/assets/commands/implement.mds +132 -132
  41. package/src/assets/commands/resolve.mds +26 -15
  42. package/src/assets/commands/self-review.mds +15 -10
  43. package/src/assets/mds/tracker/_common.mds +1 -1
  44. package/src/assets/scripts/ci-wait.cjs +636 -0
  45. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +1 -1
  46. package/src/assets/scripts/hooks/background-memory-update +290 -9
  47. package/src/assets/scripts/release-trace.cjs +27 -10
  48. package/src/assets/skills/accessibility/SKILL.md +1 -1
  49. package/src/assets/skills/apply-decisions/SKILL.md +12 -82
  50. package/src/assets/skills/apply-feature-knowledge/SKILL.md +8 -42
  51. package/src/assets/skills/architecture/SKILL.md +1 -1
  52. package/src/assets/skills/boundary-validation/SKILL.md +1 -1
  53. package/src/assets/skills/complexity/SKILL.md +1 -1
  54. package/src/assets/skills/compliance/SKILL.md +1 -1
  55. package/src/assets/skills/consistency/SKILL.md +1 -1
  56. package/src/assets/skills/database/SKILL.md +1 -1
  57. package/src/assets/skills/dependencies/SKILL.md +1 -1
  58. package/src/assets/skills/dependency-research/SKILL.md +3 -6
  59. package/src/assets/skills/design-review/SKILL.md +1 -1
  60. package/src/assets/skills/docs-framework/SKILL.md +1 -1
  61. package/src/assets/skills/documentation/SKILL.md +1 -1
  62. package/src/assets/skills/gap-analysis/SKILL.md +1 -1
  63. package/src/assets/skills/git/SKILL.md +1 -1
  64. package/src/assets/skills/go/SKILL.md +1 -1
  65. package/src/assets/skills/java/SKILL.md +1 -1
  66. package/src/assets/skills/patterns/SKILL.md +1 -1
  67. package/src/assets/skills/performance/SKILL.md +1 -1
  68. package/src/assets/skills/python/SKILL.md +1 -1
  69. package/src/assets/skills/qa/SKILL.md +1 -3
  70. package/src/assets/skills/quality-gates/SKILL.md +9 -12
  71. package/src/assets/skills/quality-gates/references/report-template.md +20 -20
  72. package/src/assets/skills/react/SKILL.md +1 -1
  73. package/src/assets/skills/regression/SKILL.md +1 -1
  74. package/src/assets/skills/reliability/SKILL.md +1 -1
  75. package/src/assets/skills/research-codebase/SKILL.md +1 -1
  76. package/src/assets/skills/research-competitor/SKILL.md +1 -1
  77. package/src/assets/skills/research-external/SKILL.md +1 -1
  78. package/src/assets/skills/research-technology/SKILL.md +1 -1
  79. package/src/assets/skills/review-methodology/SKILL.md +1 -1
  80. package/src/assets/skills/rust/SKILL.md +1 -1
  81. package/src/assets/skills/security/SKILL.md +1 -1
  82. package/src/assets/skills/software-design/SKILL.md +1 -1
  83. package/src/assets/skills/test-driven-development/SKILL.md +9 -29
  84. package/src/assets/skills/testing/SKILL.md +1 -1
  85. package/src/assets/skills/typescript/SKILL.md +1 -1
  86. package/src/assets/skills/ui-design/SKILL.md +1 -1
  87. package/src/assets/skills/worktree-support/SKILL.md +3 -55
  88. package/src/assets/skills/worktree-support/references/discovery.md +48 -0
  89. package/src/assets/skills/worktree-support/references/roots.md +2 -2
@@ -2,7 +2,9 @@
2
2
 
3
3
  # background-memory-update — Eager working-memory refresh worker
4
4
  # Spawned as a detached background process by memory-worker (Stop hook) after the
5
- # 120s throttle expires. Drains .pending-turns.jsonl → calls `claude -p` (sonnet 5.5) →
5
+ # 120s throttle expires. Drains .pending-turns.jsonl → calls `claude -p` on the model
6
+ # and effort the `agents.memory` entry of ~/.devflow/agent-models.json names, else the
7
+ # shipped worker default, in a lean session (D-MEMORY-WORKER-LEAN) →
6
8
  # rewrites WORKING-MEMORY.md with a git-reconciliation stamp on line 1.
7
9
  #
8
10
  # Applies the LLM-vs-plumbing principle: artifact content (WORKING-MEMORY.md) is
@@ -118,6 +120,92 @@ if ! df_no_symlink_below "$PROJECT_ROOT" "$LOCK_DIR" "$QUEUE_FILE" "$PROCESSING_
118
120
  exit 0
119
121
  fi
120
122
 
123
+ # --- CLI version probe: choose the argv form (D-MEMORY-WORKER-LEAN) ---
124
+ # The lean argv (--effort, --safe-mode, --max-turns, ...) is verified from
125
+ # MEMORY_MIN_CLAUDE_VERSION up. A CLI older than that, or one whose version cannot be
126
+ # read, gets the legacy argv instead, because one flag a CLI does not know fails every
127
+ # run. The probe runs here, once $CLAUDE_BIN has resolved and the link check has
128
+ # passed, and before the lock is taken, so a slow or hung `--version` can never extend
129
+ # the lock's hold. It is bounded by DEVFLOW_BG_VERSION_PROBE_SECS (default 10, at most
130
+ # 60; tests override it as they do DEVFLOW_BG_WATCHDOG_SECS) with the watchdog's
131
+ # background-and-kill idiom. Its output is parsed, never executed.
132
+ #
133
+ # Errexit safety: the worker runs under `set -e`, and a helper's last non-zero status
134
+ # aborts the caller, so each helper below ends in an explicit return status and is
135
+ # called inside an `if` condition.
136
+ MEMORY_MIN_CLAUDE_VERSION="2.1.286"
137
+
138
+ # Sets CLAUDE_VERSION_TEXT to the first 512 bytes `claude --version` printed ("" on any
139
+ # failure). Returns 0 when it exited 0 inside the bound, else 1. A hung probe gets
140
+ # SIGTERM to its own process group (set -m, as for the spawn below) after the bound
141
+ # and SIGKILL 2s later; the watchdog subshell has its descriptors closed so a sleep it
142
+ # leaves behind holds no pipe open.
143
+ probe_claude_version() {
144
+ local _secs _out _pid _wd_pid _status=1
145
+ CLAUDE_VERSION_TEXT=""
146
+ _secs="${DEVFLOW_BG_VERSION_PROBE_SECS:-10}"
147
+ case "$_secs" in
148
+ ''|*[!0123456789]*|????*) _secs=10 ;;
149
+ esac
150
+ if [ "$_secs" -lt 1 ] || [ "$_secs" -gt 60 ]; then _secs=10; fi
151
+ _out=$(mktemp "${TMPDIR:-/tmp}/devflow-claude-version.XXXXXX" 2>/dev/null) || return 1
152
+ set -m
153
+ "$CLAUDE_BIN" --version </dev/null >"$_out" 2>/dev/null &
154
+ _pid=$!
155
+ set +m
156
+ (
157
+ sleep "$_secs"
158
+ kill -TERM -"$_pid" 2>/dev/null || true
159
+ sleep 2
160
+ kill -KILL -"$_pid" 2>/dev/null || true
161
+ ) </dev/null >/dev/null 2>&1 &
162
+ _wd_pid=$!
163
+ if wait "$_pid" 2>/dev/null; then _status=0; fi
164
+ kill "$_wd_pid" 2>/dev/null || true
165
+ wait "$_wd_pid" 2>/dev/null || true
166
+ if [ "$_status" -eq 0 ]; then
167
+ CLAUDE_VERSION_TEXT=$(head -c 512 "$_out" 2>/dev/null || true)
168
+ fi
169
+ rm -f "$_out" 2>/dev/null || true
170
+ return "$_status"
171
+ }
172
+
173
+ # Returns 0 when the first X.Y.Z in $1 is at or above the first X.Y.Z in $2, comparing
174
+ # the three components as base-10 numbers left to right (2.10.0 is above 2.1.286, and
175
+ # a leading zero is not octal). Returns 1 when it is below, or when either text holds
176
+ # no X.Y.Z or a component longer than six digits. The digit set is spelled out: a
177
+ # range such as 0-9 collates by locale on bash 3.2.
178
+ claude_version_at_least() {
179
+ local _text="$1" _floor="$2" _re='([0123456789]+)\.([0123456789]+)\.([0123456789]+)'
180
+ local _f1 _f2 _f3 _v1 _v2 _v3
181
+ [[ "$_floor" =~ $_re ]] || return 1
182
+ _f1=${BASH_REMATCH[1]}; _f2=${BASH_REMATCH[2]}; _f3=${BASH_REMATCH[3]}
183
+ [[ "$_text" =~ $_re ]] || return 1
184
+ _v1=${BASH_REMATCH[1]}; _v2=${BASH_REMATCH[2]}; _v3=${BASH_REMATCH[3]}
185
+ if [ "${#_v1}" -gt 6 ] || [ "${#_v2}" -gt 6 ] || [ "${#_v3}" -gt 6 ]; then return 1; fi
186
+ _v1=$((10#$_v1)); _v2=$((10#$_v2)); _v3=$((10#$_v3))
187
+ _f1=$((10#$_f1)); _f2=$((10#$_f2)); _f3=$((10#$_f3))
188
+ if [ "$_v1" -ne "$_f1" ]; then
189
+ if [ "$_v1" -gt "$_f1" ]; then return 0; fi
190
+ return 1
191
+ fi
192
+ if [ "$_v2" -ne "$_f2" ]; then
193
+ if [ "$_v2" -gt "$_f2" ]; then return 0; fi
194
+ return 1
195
+ fi
196
+ if [ "$_v3" -ge "$_f3" ]; then return 0; fi
197
+ return 1
198
+ }
199
+
200
+ CLAUDE_ARGV_FORM="legacy"
201
+ if ! probe_claude_version; then
202
+ log "claude --version probe failed or timed out — using the legacy argv"
203
+ elif claude_version_at_least "$CLAUDE_VERSION_TEXT" "$MEMORY_MIN_CLAUDE_VERSION"; then
204
+ CLAUDE_ARGV_FORM="lean"
205
+ else
206
+ log "claude --version is below ${MEMORY_MIN_CLAUDE_VERSION} or unparseable — using the legacy argv"
207
+ fi
208
+
121
209
  # --- Worker-level lock (300s stale-break — much longer than learning-lock's 30s) ---
122
210
  # This prevents a second worker (spawned 121s later) from double-writing WORKING-MEMORY.md
123
211
  # while the first worker's claude -p call (up to 120s) is still in flight.
@@ -171,7 +259,20 @@ fi
171
259
  # Clean up any staged file left by a watchdog-killed prior run.
172
260
  # Without this, a stale staged file with a valid stamp would be mistakenly
173
261
  # mv-ed to the real path on the NEXT run's CAS check (D-MEMORY-STAGED-CAS).
262
+ #
263
+ # D-MEMORY-WORKER-LEAN: the removal is also a CHECKED precondition. The model gets the
264
+ # Write tool alone, and Write refuses a file that exists and has not been read, which
265
+ # is how an earlier Write-only worker failed silently: every Write errored while the
266
+ # run exited 0. Once nothing stands at the staged path, the one Write is always a
267
+ # create, so Write-only is safe. A path `rm -f` cannot clear (a directory, say) would
268
+ # make every Write fail, so the run stops here instead: no LLM call, the batch and
269
+ # the queue untouched (nothing has been claimed yet), the lock released by the EXIT
270
+ # trap. `-e` or `-L`, so a link there counts as present.
174
271
  rm -f "$STAGED_FILE" 2>/dev/null || true
272
+ if [ -e "$STAGED_FILE" ] || [ -L "$STAGED_FILE" ]; then
273
+ log "SKIP: $STAGED_FILE could not be removed — a Write to it would fail, so no LLM run; the batch and the queue are left as they are"
274
+ exit 0
275
+ fi
175
276
 
176
277
  # --- Orphan-only skip: if queue has no assistant/qa turn, exit and leave the queue ---
177
278
  # This prevents fabrication-prone LLM runs with only user turns in the queue.
@@ -500,7 +601,107 @@ Instructions:
500
601
  EOF
501
602
  )
502
603
 
503
- log "Spawning claude -p (model claude-sonnet-5-5, ${TURN_COUNT} turns)"
604
+ # --- Model and effort (D-MEMORY-WORKER-LEAN) ---
605
+ # One authority: WORKER_AGENTS.memory in src/core/agent-models.ts, which `devflow
606
+ # agents` shows as the worker's default. The two defaults below are that row spelled
607
+ # out for bash, held equal to it by tests/agent-models-worker.test.ts, as are the
608
+ # alias and effort lists and the name rules. A personal `agents.memory` entry in
609
+ # $HOME/.devflow/agent-models.json (the machine root; nothing relocates it) overrides
610
+ # them. Each field is validated on its own against the worker domain, so a bad model
611
+ # keeps a good effort and the reverse:
612
+ # model = `default` (the shipped one), one of the aliases, or a `claude-` name;
613
+ # a name starts with a letter or digit, continues with those and . _ -,
614
+ # and is 64 characters at most (MODEL_NAME_RE in src/core/agent-frontmatter.ts)
615
+ # effort = `default` (the shipped one) or one of the levels
616
+ # `inherit` is outside both, since a background worker has no session to inherit from.
617
+ # Only a value that passed its match reaches argv. A value that is absent, empty or
618
+ # not a JSON string reads as absent and takes the shipped one silently; a string that
619
+ # fails its match takes it with one log line naming the field, never the value.
620
+ # The character sets are spelled out because a range such as A-Za-z matches accented
621
+ # letters in a UTF-8 locale on bash 3.2.
622
+ MEMORY_MODEL_DEFAULT="claude-sonnet-5-5"
623
+ MEMORY_EFFORT_DEFAULT="high"
624
+ MEMORY_MODEL_ALIASES="haiku sonnet opus fable"
625
+ MEMORY_MODEL_PREFIX="claude-"
626
+ MEMORY_MODEL_MAX_LEN=64
627
+ MEMORY_EFFORT_LEVELS="low medium high xhigh max"
628
+ MEMORY_NAME_HEAD="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
629
+ MEMORY_EFFORT_CHARS="abcdefghijklmnopqrstuvwxyz"
630
+
631
+ # Prints the string value of agents.memory.<field> followed by one `x` (the caller strips
632
+ # it, so a value's own trailing newline survives the command substitution). Prints just
633
+ # the `x` when the file, the field or a string there is missing. Always returns 0.
634
+ memory_agent_field() {
635
+ local _file="$HOME/.devflow/agent-models.json"
636
+ if [ "$_JSON_AVAILABLE" = "true" ] && [ -f "$_file" ]; then
637
+ json_string_field_file "$_file" "agents.memory.$1" 2>/dev/null || true
638
+ fi
639
+ printf x
640
+ return 0
641
+ }
642
+
643
+ # Sets MEMORY_MODEL. Always returns 0.
644
+ resolve_memory_model() {
645
+ local _raw _tail="${MEMORY_NAME_HEAD}._-" _ok=""
646
+ MEMORY_MODEL="$MEMORY_MODEL_DEFAULT"
647
+ _raw=$(memory_agent_field model)
648
+ _raw=${_raw%x}
649
+ case "$_raw" in
650
+ ''|default) return 0 ;;
651
+ [!$MEMORY_NAME_HEAD]*|*[!$_tail]*) ;;
652
+ *)
653
+ if [ "${#_raw}" -le "$MEMORY_MODEL_MAX_LEN" ]; then
654
+ case " $MEMORY_MODEL_ALIASES " in
655
+ *" $_raw "*) _ok="yes" ;;
656
+ esac
657
+ case "$_raw" in
658
+ "$MEMORY_MODEL_PREFIX"?*) _ok="yes" ;;
659
+ esac
660
+ fi
661
+ ;;
662
+ esac
663
+ if [ -n "$_ok" ]; then
664
+ MEMORY_MODEL="$_raw"
665
+ else
666
+ log "agents.memory.model: not a model the worker accepts (default, an alias or a ${MEMORY_MODEL_PREFIX} name) — using the shipped model"
667
+ fi
668
+ return 0
669
+ }
670
+
671
+ # Sets MEMORY_EFFORT. Always returns 0.
672
+ resolve_memory_effort() {
673
+ local _raw _ok=""
674
+ MEMORY_EFFORT="$MEMORY_EFFORT_DEFAULT"
675
+ _raw=$(memory_agent_field effort)
676
+ _raw=${_raw%x}
677
+ case "$_raw" in
678
+ ''|default) return 0 ;;
679
+ *[!$MEMORY_EFFORT_CHARS]*) ;;
680
+ *)
681
+ case " $MEMORY_EFFORT_LEVELS " in
682
+ *" $_raw "*) _ok="yes" ;;
683
+ esac
684
+ ;;
685
+ esac
686
+ if [ -n "$_ok" ]; then
687
+ MEMORY_EFFORT="$_raw"
688
+ else
689
+ log "agents.memory.effort: not an effort level the worker accepts (default or a level) — using the shipped effort"
690
+ fi
691
+ return 0
692
+ }
693
+
694
+ resolve_memory_model
695
+ resolve_memory_effort
696
+
697
+ if [ "$CLAUDE_ARGV_FORM" = "lean" ]; then
698
+ EFFORT_LOG="effort ${MEMORY_EFFORT}"
699
+ ARGV_LOG="lean argv"
700
+ else
701
+ EFFORT_LOG="no effort passed"
702
+ ARGV_LOG="legacy argv"
703
+ fi
704
+ log "Spawning claude -p (model ${MEMORY_MODEL}, ${EFFORT_LOG}, ${ARGV_LOG}, ${TURN_COUNT} turns)"
504
705
  # SECURITY: never log PROMPT — it contains turn content which may include secrets
505
706
 
506
707
  # --- Watchdog timeout (overridable for tests: DEVFLOW_BG_WATCHDOG_SECS=2) ---
@@ -537,14 +738,94 @@ fi
537
738
  # Restore set +m immediately after capturing CLAUDE_PID so the watchdog subshell and
538
739
  # other subsequent background operations stay in the worker's group.
539
740
  # Job-control notifications go to stderr which is redirected to the log — suppress them.
741
+ #
742
+ # D-MEMORY-WORKER-LEAN — the spawn. The worker opens a headless session to make one
743
+ # Write, so the session is cut to what that Write needs. Prompt on stdin, output and
744
+ # errors to the log, as before. Two argv forms, chosen by the version probe above:
745
+ #
746
+ # lean (CLI at or above MEMORY_MIN_CLAUDE_VERSION):
747
+ # -p --model M --effort E --safe-mode --tools Write --disable-slash-commands \
748
+ # --strict-mcp-config --mcp-config '{"mcpServers":{}}' --max-turns 3 \
749
+ # --dangerously-skip-permissions --output-format text
750
+ # legacy (older, unreadable or timed-out probe):
751
+ # -p --model M --tools Write --dangerously-skip-permissions --output-format text
752
+ #
753
+ # What each flag is for:
754
+ # --model, --effort the resolved agents.memory values above. --effort is the only
755
+ # effort source: an inherited CLAUDE_CODE_EFFORT_LEVEL beats the
756
+ # flag (measured on 2026-10-09), so it is unset below, for both
757
+ # forms, and the log's "no effort passed" is then true.
758
+ # --safe-mode starts with the user's customisations off: instruction files,
759
+ # skills, plugins, hooks, MCP servers, custom commands and agents.
760
+ # Auth, model selection and built-in tools work as usual, and
761
+ # settings `env` (the provider URL and key) still applies under
762
+ # it (measured on 2026-10-09), so a routed or keyed install works.
763
+ # --tools Write Write is the only tool. `--allowedTools` only pre-approves, it
764
+ # leaves every tool, listing and MCP server loaded.
765
+ # --disable-slash-commands, --strict-mcp-config with an empty --mcp-config
766
+ # no slash-command or skill listing, no MCP server and none of the
767
+ # instructions they add to the context.
768
+ # --max-turns 3 the worker's own pattern is one Write and then the end of the
769
+ # turn, two requests; the third is margin. A run that reaches the
770
+ # cap exits non-zero, so its batch stays for the retry; the Write
771
+ # on the capped turn still runs. 3 was verified on claude 2.1.294
772
+ # on 2026-10-09 (cap 1 exits 1, caps 2 and 3 exit 0 on that
773
+ # pattern). `--max-turns` is not listed in `claude --help` there
774
+ # but is registered (`--max-turns abc` errors "must be a number"),
775
+ # which is why it was exercised rather than read off the help.
776
+ # --dangerously-skip-permissions headless: nothing could answer a prompt.
777
+ # --output-format text
778
+ # DEVFLOW_BG_UPDATER=1 the recursion guard stays on both forms, though --safe-mode
779
+ # also disables hooks. CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 and
780
+ # CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 keep the instruction files and
781
+ # auto-memory out on both forms, including the legacy one.
782
+ #
783
+ # Why Write-only is safe: the staged path is empty before every run (the removal and
784
+ # the checked precondition after the lock above), so the one Write is always a create.
785
+ # Write refuses an existing file that has not been read, and that is the whole history
786
+ # of this flag set:
787
+ # a472a490 passed `--tools "Write"` with `--allowedTools` for two memory files;
788
+ # e701cecc widened the tools to `Read,Write,Bash` after counting the silent
789
+ # read-before-write failures (the run exited 0 while every Write errored);
790
+ # baf02265 removed both flags, with no reason in its message;
791
+ # 6186645f raised the worker's model and kept `--allowedTools 'Read,Write'`.
792
+ #
793
+ # The version floor is 2.1.286, the lowest CLI on which the whole lean argv was run
794
+ # and its flags, the settings `env` under --safe-mode and the effort override were
795
+ # checked (2.1.286 and 2.1.292 to 2.1.294 behave identically; 2026-10-09, recorded in
796
+ # docs/reference/platform-assumptions.md). The legacy form carries no --effort,
797
+ # --safe-mode, --max-turns, --disable-slash-commands, --strict-mcp-config or
798
+ # --mcp-config, none of which is verified on older CLIs, so on it effort is not
799
+ # applied, MCP servers stay loaded and there is no turn cap.
800
+ #
801
+ # The turns input has no byte cap: the queue holds every turn whole by design, and the
802
+ # prompt is bounded by the newest-20-rows window above and the 64 KB existing-memory
803
+ # cap, not by cutting a turn.
804
+ unset CLAUDE_CODE_EFFORT_LEVEL
540
805
  set -m
541
- DEVFLOW_BG_UPDATER=1 "$CLAUDE_BIN" -p \
542
- --model claude-sonnet-5-5 \
543
- --dangerously-skip-permissions \
544
- --allowedTools 'Read,Write' \
545
- --output-format text \
546
- <<< "$PROMPT" \
547
- >> "$LOG_FILE" 2>&1 &
806
+ if [ "$CLAUDE_ARGV_FORM" = "lean" ]; then
807
+ DEVFLOW_BG_UPDATER=1 CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 "$CLAUDE_BIN" -p \
808
+ --model "$MEMORY_MODEL" \
809
+ --effort "$MEMORY_EFFORT" \
810
+ --safe-mode \
811
+ --tools Write \
812
+ --disable-slash-commands \
813
+ --strict-mcp-config \
814
+ --mcp-config '{"mcpServers":{}}' \
815
+ --max-turns 3 \
816
+ --dangerously-skip-permissions \
817
+ --output-format text \
818
+ <<< "$PROMPT" \
819
+ >> "$LOG_FILE" 2>&1 &
820
+ else
821
+ DEVFLOW_BG_UPDATER=1 CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 "$CLAUDE_BIN" -p \
822
+ --model "$MEMORY_MODEL" \
823
+ --tools Write \
824
+ --dangerously-skip-permissions \
825
+ --output-format text \
826
+ <<< "$PROMPT" \
827
+ >> "$LOG_FILE" 2>&1 &
828
+ fi
548
829
  CLAUDE_PID=$!
549
830
  set +m
550
831
 
@@ -113,12 +113,28 @@ const FULL_SHA_RE = /^[0-9a-f]{40}$/;
113
113
  const KEY_RE = /^[A-Z][A-Z0-9_]{1,9}$/;
114
114
 
115
115
  /**
116
- * Step 3a's closing-keyword regex, byte-for-byte the literal the built
117
- * `gather-release-evidence` references state, applied case-insensitively WITHOUT
118
- * the `u` flag — so a non-ASCII letter (`ſ`, the Kelvin sign) never folds onto an
119
- * ASCII keyword letter. A parity test pins `.source` and `.flags` to the built text.
116
+ * D-TRACE-KEYWORDS: two keyword sets, deliberately unequal, because they answer
117
+ * two different questions.
118
+ *
119
+ * CLOSING_KEYWORD_RE is step 3a's closing-keyword regex, byte-for-byte the literal
120
+ * the built `gather-release-evidence` references state: a commit that carries one
121
+ * of these keywords ships the issue it names. `Refs #N` only mentions an issue, so
122
+ * `refs` is not a closing keyword and the prompt never lets such a commit reach
123
+ * SHIPPED_ISSUES. The script itself classifies with TRACE_KEYWORD_RE; this regex
124
+ * is exported so a parity test can pin the prompt's rule to a literal.
125
+ *
126
+ * TRACE_KEYWORD_RE is the closing set plus `refs`. The trace map asks the weaker
127
+ * question "does this commit name an issue at all?", and a `Refs #N` commit does,
128
+ * so it is `traced` and not `untraced`. Narrowing the closing set must not turn
129
+ * those commits into traceability gaps in the release confirm.
130
+ *
131
+ * Both apply case-insensitively WITHOUT the `u` flag — so a non-ASCII letter
132
+ * (`ſ`, the Kelvin sign) never folds onto an ASCII keyword letter. A parity test
133
+ * pins CLOSING_KEYWORD_RE's `.source` and `.flags` to the built text, and
134
+ * TRACE_KEYWORD_RE to the closing set plus `refs`.
120
135
  */
121
- const KEYWORD_RE = /^\(?(close[sd]?|fix(e[sd])?|resolve[sd]?|refs):?$/i;
136
+ const CLOSING_KEYWORD_RE = /^\(?(close[sd]?|fix(e[sd])?|resolve[sd]?):?$/i;
137
+ const TRACE_KEYWORD_RE = /^\(?(close[sd]?|fix(e[sd])?|resolve[sd]?|refs):?$/i;
122
138
 
123
139
  /** Step 3a's trailing-strip class, byte-for-byte the built literal (parity-pinned). */
124
140
  const TRAILING_CLASS = '[.,;:)\\]!?]';
@@ -377,11 +393,11 @@ function gateCandidate(candidate, grammar, key) {
377
393
 
378
394
  /**
379
395
  * Step 3a, executed, then the grammar's gate: the first reference `message`
380
- * yields, or null. Per line, a whitespace token matching KEYWORD_RE opens a run:
381
- * the next token, plus each further token while the previous one ends in `,`.
396
+ * yields, or null. Per line, a whitespace token matching TRACE_KEYWORD_RE opens a
397
+ * run: the next token, plus each further token while the previous one ends in `,`.
382
398
  * Each run token splits on `,`, is stripped, and non-empty parts are gated.
383
399
  *
384
- * Linear in the message: a keyword token never ends in `,` (KEYWORD_RE is
400
+ * Linear in the message: a keyword token never ends in `,` (TRACE_KEYWORD_RE is
385
401
  * anchored), so every comma run is walked by at most the one keyword before it.
386
402
  *
387
403
  * @param {string} message
@@ -393,7 +409,7 @@ function findReference(message, grammar, key) {
393
409
  for (const line of message.split('\n')) {
394
410
  const tokens = line.split(/\s+/).filter(t => t !== '');
395
411
  for (let i = 0; i < tokens.length; i++) {
396
- if (!KEYWORD_RE.test(tokens[i])) continue;
412
+ if (!TRACE_KEYWORD_RE.test(tokens[i])) continue;
397
413
  for (let j = i + 1; j < tokens.length; j++) {
398
414
  for (const part of tokens[j].split(',')) {
399
415
  const stripped = stripCandidate(part);
@@ -1117,7 +1133,8 @@ module.exports = Object.freeze({
1117
1133
  EXIT_CODES,
1118
1134
  LIMITS,
1119
1135
  RELEASE_TAG_RE,
1120
- KEYWORD_RE,
1136
+ CLOSING_KEYWORD_RE,
1137
+ TRACE_KEYWORD_RE,
1121
1138
  TRAILING_CLASS,
1122
1139
  GRAMMARS,
1123
1140
  GRAMMAR_RULES,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: accessibility
3
- description: This skill should be used when the user asks to "add accessibility", "check ARIA", "handle keyboard navigation", "add focus management", or creates UI components, forms, or interactive elements. Provides WCAG 2.2 AA patterns for keyboard navigation, ARIA roles and states, focus management, color contrast, and screen reader support.
3
+ description: This skill should be used when the user asks to "add accessibility", "check ARIA", "handle keyboard navigation", or creates UI components, forms, or interactive elements.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Grep, Glob
6
6
  activation:
@@ -1,14 +1,12 @@
1
1
  ---
2
2
  name: apply-decisions
3
- description: Canonical algorithm for consuming DECISIONS_CONTEXT index — scan index, identify relevant entries, Read full bodies on demand, cite verbatim IDs in-session and state the rule in words in anything committed or posted.
3
+ description: Consume the DECISIONS_CONTEXT index; cite IDs in-session only
4
4
  user-invocable: false
5
- allowed-tools: Read
5
+ allowed-tools: Read, Bash
6
6
  ---
7
7
 
8
8
  # Apply Decisions
9
9
 
10
- Canonical consumer algorithm for the `DECISIONS_CONTEXT` index passed by orchestrators. The index lists each active ADR/PF entry with its ID and title — plus a status tag and an area on a v1 line, or the entry's scope on a v2 line — not the full body. Use this skill to surface the right decisions and pitfalls for your task without loading the entire corpus.
11
-
12
10
  ## Iron Law
13
11
 
14
12
  > **VERBATIM IDs ONLY — NEVER FABRICATE**
@@ -17,104 +15,36 @@ Canonical consumer algorithm for the `DECISIONS_CONTEXT` index passed by orchest
17
15
  > in the index, do not cite it. If an entry looks relevant but you haven't Read its
18
16
  > full body, do not cite it. Fabricated citations are worse than no citations.
19
17
 
20
- ---
21
-
22
18
  ## 5-Step Algorithm
23
19
 
24
20
  ### Step 1: Scan the index
25
21
 
26
- Read through all entries in `DECISIONS_CONTEXT`. The index lists active entries only, in two line kinds:
27
-
28
- ```
29
- Decisions (N):
30
- ADR-NNN Return Result types from every fallible operation [Accepted]
31
- ADR-NNN Claim the learning queue with an op, never with mv — src/assets/scripts/hooks/**, area:learning
32
-
33
- Pitfalls (M):
34
- PF-NNN Background hook god scripts [Active] — src/assets/scripts/hooks/foo.cjs
35
- PF-NNN A rename claims a shared file only while nothing re-creates it — area:hooks
36
-
37
- ADR-NNN entries live in {worktree}/.devflow/learning/decisions.md
38
- PF-NNN entries live in {worktree}/.devflow/learning/pitfalls.md
39
- Read the relevant file and locate the matching `## ADR-NNN:` or `## PF-NNN:` heading for the full body.
40
- ```
41
-
42
- - **A v1 line** ends in a status tag — `[Accepted]` on a decision, `[Active]` on a pitfall — after a title cut to 60 characters, and a pitfall adds its area after `—`.
43
- - **A v2 line** has no tag. Its title is whole, and after `—` comes its scope: the globs and `area:` tags the rule governs, cut to 80 characters.
22
+ One line per active entry: its ID (`ADR-NNN` or `PF-NNN`), a title, then a status tag and/or, after `—`, its area or scope. The footer names the decisions and pitfalls files.
44
23
 
45
24
  ### Step 2: Identify plausibly-relevant entries
46
25
 
47
- From the index, identify entries whose title, area or scope plausibly overlaps with:
48
- - The files you are modifying or reviewing — a v2 scope glob that matches one of them is a strong signal
49
- - The category of issue you are addressing (e.g., error handling, hook scripts, JSON parsing)
50
- - The architectural area of your change
51
-
52
- A v1 title may be cut short — if a truncated title looks relevant, proceed to Step 3.
26
+ Pick entries whose title, area or scope overlaps the files you touch (a matching scope glob is a strong signal), the kind of issue or the architectural area. Follow up a cut-short title that looks relevant.
53
27
 
54
28
  ### Step 3: Read the full body
55
29
 
56
- For each plausibly-relevant entry, use the Read tool to open the decisions file listed in the `DECISIONS_CONTEXT` footer and locate the matching `## ADR-NNN:` or `## PF-NNN:` heading. Read the full section to confirm relevance and understand the decision or pitfall completely.
57
-
58
- A v2 body reads:
30
+ Find the entry's heading line in the file the footer names, then Read only that section:
59
31
 
32
+ ```bash
33
+ command grep -nF '## ADR-NNN:' "{worktree-from-footer}/.devflow/learning/decisions.md"
60
34
  ```
61
- ## ADR-NNN: {title}
62
35
 
63
- - **Status**: Accepted · verified {date}
64
- - **Scope**: `{glob}`, `area:{tag}`
65
- - **Decision**: {the rule}
66
- - **Why**: {why it holds}
67
- - **Source**: {where it was learned}
68
- ```
69
-
70
- A pitfall's Status is `Active` and its rule line is labelled `**Rule**`. The verified date is the day the entry was last confirmed true; a body without one has not been confirmed since it was written. A v1 body carries `**Date**`, `**Status**`, `**Context**`, `**Decision**` and `**Consequences**` for a decision, or `**Area**`, `**Issue**`, `**Impact**`, `**Resolution**` and `**Status**` for a pitfall.
71
-
72
- **The footer is the single source of truth for file paths.** Never substitute hardcoded paths — the footer resolves to the correct worktree, which may differ from your cwd in multi-worktree flows.
73
-
74
- ```
75
- Use the exact paths from the DECISIONS_CONTEXT footer, e.g.:
76
- {worktree-from-footer}/.devflow/learning/decisions.md → find ## ADR-NNN: heading
77
- {worktree-from-footer}/.devflow/learning/pitfalls.md → find ## PF-NNN: heading
78
- ```
79
-
80
- Only cite an entry after you have read its full body and confirmed it applies.
36
+ For a pitfall use `## PF-NNN:` and `pitfalls.md`. Read with `offset` at the printed line and a `limit` of about 25, stopping at the next `## `. The footer is the single source of truth for paths; the ledger is git-ignored, so only a shell search finds the line. A `verified` date is when the entry was last confirmed true; none means unconfirmed. Cite only after reading the body and confirming it applies.
81
37
 
82
38
  ### Step 4: Cite inline — in-session handoffs only
83
39
 
84
- When applying a prior decision, cite as `applies ADR-NNN`. When avoiding a known pitfall, cite as `avoids PF-NNN`. Place these citations only where they stay in the session: your reasoning, decision tables, prompts to downstream agents, and your report back to the caller.
40
+ Cite `applies ADR-NNN` or `avoids PF-NNN` in-session only: your reasoning, prompts to downstream agents, your report back.
85
41
 
86
- Anything committed, pushed or posted states the rule in words, never its ID: code, comments, tests, docs, KNOWLEDGE.md files, commit messages, PR and issue text, review and PR comments, resolution summaries — and any report a later step copies into one of those. The ledger is gitignored and numbered per machine, so no other clone can resolve an ID, and numbers get reused.
42
+ Anything committed, pushed or posted states the rule in words, never its ID (code, comments, tests, docs, commit messages, PR and issue text, review comments, and any report copied into those). IDs are numbered per machine, so no other clone can resolve one.
87
43
 
88
44
  ### Step 5: Use verbatim IDs only
89
45
 
90
- Cite only IDs that appear verbatim in `DECISIONS_CONTEXT`. Do not guess at IDs that might exist. Do not construct IDs from memory. If no entry is clearly relevant, skip citation entirely — silence is correct when nothing applies.
91
-
92
- ---
93
-
94
- ## Worked Example
95
-
96
- **Scenario**: Reviewing `src/assets/scripts/hooks/background-learning` for issues.
97
-
98
- 1. **Scan** — Index shows `PF-NNN Background hook god scripts [Active] — src/assets/scripts/hooks/foo.cjs`
99
- 2. **Identify** — Area field includes `src/assets/scripts/hooks/` which overlaps with the file under review
100
- 3. **Read** — Open the pitfalls file at the path given in the DECISIONS_CONTEXT footer (e.g., `<worktree>/.devflow/learning/pitfalls.md`), find `## PF-NNN:` section, read full body
101
- 4. **Cite** — If the file shows signs of the god-script pattern, note `avoids PF-NNN` in reasoning; a comment you commit for the fix says why in words ("hooks stay thin dispatchers"), never the ID
102
- 5. **Verbatim** — ID `PF-NNN` appeared in the index; citation is valid
103
-
104
- ---
46
+ Cite only IDs in `DECISIONS_CONTEXT`; never guess or rebuild one. When nothing clearly applies, cite nothing.
105
47
 
106
48
  ## Skip Guard
107
49
 
108
- When `DECISIONS_CONTEXT` is empty, `(none)`, or not provided: skip this skill entirely — unless your agent instructions tell you to read the decisions index yourself, in which case the index you read is your `DECISIONS_CONTEXT`. Do not otherwise load decisions files independently. Do not speculate about what decisions or pitfalls might exist.
109
-
110
- ---
111
-
112
- ## Citation Format Reference
113
-
114
- | Situation | Citation |
115
- |-----------|----------|
116
- | Applying a prior architectural decision | `applies ADR-NNN` |
117
- | Avoiding a known pitfall | `avoids PF-NNN` |
118
- | Entry not in index | (no citation — silence is correct) |
119
- | Entry in index but not read yet | (no citation — read first) |
120
- | Text that is committed, pushed or posted | (no ID — state the rule in words) |
50
+ When `DECISIONS_CONTEXT` is empty, `(none)` or not provided, skip this skill — unless your instructions tell you to read the decisions index yourself; that index is then your `DECISIONS_CONTEXT`. Never load decisions files otherwise.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: apply-feature-knowledge
3
- description: Consumption algorithm for FEATURE_KNOWLEDGE variable — pre-computed feature context
3
+ description: Consume FEATURE_KNOWLEDGE, the pre-computed feature context
4
4
  user-invocable: false
5
5
  allowed-tools: Read
6
6
  ---
@@ -11,37 +11,17 @@ allowed-tools: Read
11
11
 
12
12
  > **Pre-computed context, not a cage. Verify against current code — always.**
13
13
  >
14
- > A feature knowledge captures patterns AS THEY WERE when last written. Code evolves.
15
- > Use the feature knowledge as a starting point, not gospel truth. When something feels
16
- > off, Read the actual files. Code is authoritative; feature knowledge is supplementary.
14
+ > A feature knowledge captures patterns AS THEY WERE when last written. Use it as a
15
+ > starting point, not gospel truth; when something feels off, Read the actual files.
16
+ > Code is authoritative.
17
17
 
18
18
  ---
19
19
 
20
20
  ## 3-Step Algorithm
21
21
 
22
- ### Step 1: Read the Feature Knowledge
23
-
24
- When `FEATURE_KNOWLEDGE` is provided and is not `(none)`:
25
-
26
- 1. Read each feature knowledge section (separated by `--- Feature knowledge: {slug} ---` headers)
27
- 2. Absorb: architecture, data flow, key patterns, anti-patterns, gotchas
28
- 3. Note integration points that relate to your current task
29
-
30
- ### Step 2: Apply to Current Task
31
-
32
- 1. **Patterns as defaults**: Follow documented patterns unless you have a specific reason not to
33
- 2. **Anti-patterns as warnings**: Check your work against documented anti-patterns
34
- 3. **Gotchas as checklists**: Verify each gotcha doesn't apply to your changes
35
- 4. **Integration points**: Ensure your changes respect documented boundaries
36
- 5. **Key files**: Use as starting points for exploration
37
-
38
- ### Step 3: Verify Against Current Code
39
-
40
- The feature knowledge may not reflect recent changes:
41
- - If the feature knowledge doesn't address your specific area, explore further
42
- - **When an assertion seems outdated**: Read the relevant source files to confirm — code wins
43
- - When you find a contradiction between the KB and actual code, trust the code
44
- - Note discrepancies in your output when they matter for the task
22
+ 1. **Read** each section of `FEATURE_KNOWLEDGE` (headed `--- Feature knowledge: {slug} ---`) for architecture, data flow, patterns, anti-patterns, gotchas and the integration points your task touches.
23
+ 2. **Apply** it: follow documented patterns unless you have a specific reason not to; check your work against each anti-pattern and gotcha; respect documented integration boundaries; start exploring from the key files.
24
+ 3. **Verify** against current code: it may not reflect recent changes. Where it is silent on your area, explore further. Where an assertion seems outdated or contradicts the code, Read the source and trust it. Note a discrepancy in your output when it matters for the task.
45
25
 
46
26
  ---
47
27
 
@@ -52,18 +32,4 @@ Do not mention feature knowledge or its absence in your output.
52
32
 
53
33
  ## Freshness Model
54
34
 
55
- Feature knowledge uses **write-through + verify-on-read** for freshness:
56
- - KBs are written at the point a documented area changes (not on a background schedule)
57
- - Readers verify key assertions against current code rather than relying on staleness markers
58
- - When in doubt, Read the file — that resolves any uncertainty immediately
59
-
60
- ## Concatenation Format
61
-
62
- Multiple feature knowledge entries are concatenated with slug headers:
63
- ```
64
- --- Feature knowledge: payments ---
65
- [full KNOWLEDGE.md content]
66
-
67
- --- Feature knowledge: auth ---
68
- [full KNOWLEDGE.md content]
69
- ```
35
+ Feature knowledge is **verify-on-read**: check key assertions against current code, not staleness markers, and when in doubt Read the file.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: architecture
3
- description: This skill should be used when reviewing code for SOLID violations, tight coupling, or layering issues.
3
+ description: This skill should be used when reviewing code for SOLID or layering issues.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Grep, Glob
6
6
  ---
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: boundary-validation
3
- description: This skill should be used when the user asks to "validate input", "parse request data", "handle form data", "add Zod schema", "sanitize user input", or creates API endpoints and system boundaries. Provides parse-don't-validate patterns with schema validation for type-safe boundary enforcement and hostile input defense.
3
+ description: This skill should be used when the user asks to "validate input", "parse request data", "add Zod schema", or creates API endpoints and system boundaries.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Grep, Glob, AskUserQuestion
6
6
  ---
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: complexity
3
- description: This skill should be used when reviewing code for high cyclomatic complexity, deep nesting, or long functions.
3
+ description: This skill should be used when reviewing code for deep nesting or long functions.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Grep, Glob
6
6
  ---
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: compliance
3
- description: This skill should be used when reviewing code handling PII, payment data, health records, audit logs, data retention, or IaC under GDPR, HIPAA, PCI DSS, SOC 2, ISO 27001, or SOX.
3
+ description: This skill should be used when reviewing code that handles PII, payments or health data.
4
4
  user-invocable: false
5
5
  allowed-tools: Read, Grep, Glob
6
6
  ---