devflow-kit 3.2.0 → 3.4.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 +34 -0
- package/README.md +1 -1
- package/dist/agents/code.md +330 -0
- package/{src/assets → dist}/agents/design.md +11 -1
- package/{src/assets → dist}/agents/diagnose.md +17 -13
- package/dist/agents/git.md +29 -56
- package/{src/assets → dist}/agents/knowledge.md +8 -5
- package/{src/assets → dist}/agents/research.md +21 -2
- package/{src/assets → dist}/agents/review.md +18 -7
- package/{src/assets → dist}/agents/scrutinize.md +35 -11
- package/dist/agents/skim.md +148 -0
- package/{src/assets → dist}/agents/triage.md +8 -2
- package/dist/cli/commands/init.js +62 -0
- package/dist/cli/commands/learning.js +63 -8
- package/dist/cli/commands/uninstall.js +42 -1
- package/dist/commands/bug-analysis.md +30 -8
- package/dist/commands/code-review.md +142 -61
- package/dist/commands/debug.md +15 -13
- package/dist/commands/dynamic-build.md +176 -130
- package/dist/commands/dynamic-plan.md +31 -19
- package/dist/commands/dynamic-profile.md +27 -13
- package/dist/commands/dynamic-tickets.md +28 -14
- package/dist/commands/explore.md +16 -14
- package/dist/commands/implement.md +163 -158
- package/dist/commands/plan.md +37 -24
- package/dist/commands/release.md +69 -4
- package/dist/commands/research.md +33 -11
- package/dist/commands/resolve.md +61 -47
- package/dist/commands/self-review.md +50 -32
- package/dist/core/agent-models.js +53 -7
- package/dist/core/assets.js +55 -10
- package/dist/core/claude-md-audit.js +190 -0
- package/dist/core/feature-switch.js +20 -1
- package/dist/core/flags.js +28 -0
- package/dist/core/fs-atomic.js +8 -3
- package/dist/core/learning-tuning-config.js +8 -0
- package/dist/core/learning-variants.js +213 -0
- package/dist/core/manifest.js +62 -0
- package/dist/core/mds-variants.js +38 -1
- package/dist/core/plugins.js +78 -11
- package/{src/assets → dist/learning-off}/agents/code.md +77 -28
- package/dist/learning-off/agents/design.md +119 -0
- package/dist/learning-off/agents/diagnose.md +210 -0
- package/dist/learning-off/agents/knowledge.md +90 -0
- package/dist/learning-off/agents/research.md +149 -0
- package/dist/learning-off/agents/review.md +228 -0
- package/dist/learning-off/agents/scrutinize.md +117 -0
- package/{src/assets → dist/learning-off}/agents/skim.md +5 -10
- package/dist/learning-off/agents/triage.md +163 -0
- package/dist/learning-off/commands/bug-analysis.md +420 -0
- package/dist/learning-off/commands/code-review.md +525 -0
- package/dist/learning-off/commands/debug.md +294 -0
- package/dist/learning-off/commands/dynamic-build.md +1255 -0
- package/dist/learning-off/commands/dynamic-plan.md +424 -0
- package/dist/learning-off/commands/dynamic-profile.md +214 -0
- package/dist/learning-off/commands/dynamic-tickets.md +632 -0
- package/dist/learning-off/commands/explore.md +210 -0
- package/dist/learning-off/commands/implement.md +808 -0
- package/dist/learning-off/commands/plan.md +664 -0
- package/dist/learning-off/commands/release.md +310 -0
- package/dist/learning-off/commands/research.md +222 -0
- package/dist/learning-off/commands/resolve.md +837 -0
- package/dist/learning-off/commands/self-review.md +266 -0
- package/dist/skills/git/references/tracker/_contract.md +33 -0
- package/dist/skills/git/references/tracker/github/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/github/gather-release-evidence.md +5 -1
- package/dist/skills/git/references/tracker/github/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/github/setup-task.md +12 -0
- package/dist/skills/git/references/tracker/jira/associate-release.md +1 -1
- package/dist/skills/git/references/tracker/jira/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +5 -1
- package/dist/skills/git/references/tracker/jira/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/jira/setup-task.md +14 -2
- package/dist/skills/git/references/tracker/linear/associate-release.md +1 -1
- package/dist/skills/git/references/tracker/linear/fetch-issue.md +2 -0
- package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +2 -0
- package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +5 -1
- package/dist/skills/git/references/tracker/linear/post-wave-report.md +2 -0
- package/dist/skills/git/references/tracker/linear/setup-task.md +14 -2
- package/dist/targets/claude-code/installer.js +72 -36
- package/dist/targets/claude-code/language-stamp.js +185 -0
- package/dist/targets/claude-code/learning-install.js +489 -0
- package/package.json +1 -1
- package/src/assets/agents/code.mds +339 -0
- package/src/assets/agents/design.mds +149 -0
- package/src/assets/agents/diagnose.mds +225 -0
- package/src/assets/agents/evaluate.md +12 -25
- package/src/assets/agents/git.mds +29 -56
- package/src/assets/agents/knowledge.mds +125 -0
- package/src/assets/agents/learning.md +4 -6
- package/src/assets/agents/research.mds +176 -0
- package/src/assets/agents/review.mds +286 -0
- package/src/assets/agents/scrutinize.mds +132 -0
- package/src/assets/agents/simplify.md +20 -0
- package/src/assets/agents/skim.mds +161 -0
- package/src/assets/agents/synthesize.md +12 -0
- package/src/assets/agents/test.md +2 -2
- package/src/assets/agents/triage.mds +194 -0
- package/src/assets/agents/validate.md +15 -8
- package/src/assets/commands/_partials/_compliance.mds +5 -4
- package/src/assets/commands/_partials/_decisions.mds +31 -0
- package/src/assets/commands/_partials/_engine.mds +29 -24
- package/src/assets/commands/_partials/_knowledge.mds +26 -13
- package/src/assets/commands/_partials/_plan_contract.mds +1 -1
- package/src/assets/commands/_partials/_preamble.mds +33 -9
- package/src/assets/commands/_partials/_publication.mds +5 -4
- package/src/assets/commands/_partials/_settings.mds +13 -5
- package/src/assets/commands/_partials/_wave.mds +16 -6
- package/src/assets/commands/bug-analysis.mds +24 -2
- package/src/assets/commands/code-review.mds +148 -45
- package/src/assets/commands/debug.mds +17 -1
- package/src/assets/commands/dynamic-build.mds +144 -65
- package/src/assets/commands/dynamic-plan.mds +36 -6
- package/src/assets/commands/dynamic-profile.mds +9 -1
- package/src/assets/commands/dynamic-tickets.mds +16 -2
- package/src/assets/commands/explore.mds +27 -1
- package/src/assets/commands/implement.mds +171 -138
- package/src/assets/commands/plan.mds +47 -8
- package/src/assets/commands/{release.md → release.mds} +27 -24
- package/src/assets/commands/research.mds +28 -4
- package/src/assets/commands/resolve.mds +69 -17
- package/src/assets/commands/self-review.mds +43 -13
- package/src/assets/mds/tracker/_common.mds +1 -1
- package/src/assets/mds/tracker/_contract.mds +72 -0
- package/src/assets/mds/tracker/_github.mds +13 -2
- package/src/assets/mds/tracker/_jira.mds +17 -5
- package/src/assets/mds/tracker/_linear.mds +17 -5
- package/src/assets/mds/tracker/_mcp.mds +2 -2
- package/src/assets/mds/tracker/_steps.mds +97 -0
- package/src/assets/rules/context-economy.md +10 -0
- package/src/assets/rules/go.md +1 -0
- package/src/assets/rules/java.md +1 -0
- package/src/assets/rules/python.md +1 -0
- package/src/assets/rules/rust.md +1 -0
- package/src/assets/rules/typescript.md +1 -0
- package/src/assets/scripts/ci-wait.cjs +636 -0
- package/src/assets/scripts/claude-md-audit.cjs +611 -0
- package/src/assets/scripts/hooks/assets/orchestrator-charter.md +2 -3
- package/src/assets/scripts/hooks/background-memory-update +290 -9
- package/src/assets/scripts/hooks/json-helper.cjs +13 -5
- package/src/assets/scripts/hooks/json-parse +34 -10
- package/src/assets/scripts/hooks/session-start-context +315 -7
- package/src/assets/scripts/release-trace.cjs +27 -10
- package/src/assets/skills/accessibility/SKILL.md +1 -1
- package/src/assets/skills/apply-decisions/SKILL.md +12 -82
- package/src/assets/skills/apply-feature-knowledge/SKILL.md +9 -43
- package/src/assets/skills/architecture/SKILL.md +1 -1
- package/src/assets/skills/boundary-validation/SKILL.md +1 -1
- package/src/assets/skills/complexity/SKILL.md +1 -1
- package/src/assets/skills/compliance/SKILL.md +1 -1
- package/src/assets/skills/consistency/SKILL.md +1 -1
- package/src/assets/skills/database/SKILL.md +1 -1
- package/src/assets/skills/dependencies/SKILL.md +1 -1
- package/src/assets/skills/dependency-research/SKILL.md +3 -6
- package/src/assets/skills/design-review/SKILL.md +1 -1
- package/src/assets/skills/docs-framework/SKILL.md +1 -1
- package/src/assets/skills/documentation/SKILL.md +1 -1
- package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
- package/src/assets/skills/gap-analysis/SKILL.md +1 -1
- package/src/assets/skills/git/SKILL.md +1 -1
- package/src/assets/skills/go/SKILL.md +1 -1
- package/src/assets/skills/java/SKILL.md +1 -1
- package/src/assets/skills/patterns/SKILL.md +1 -1
- package/src/assets/skills/performance/SKILL.md +1 -1
- package/src/assets/skills/python/SKILL.md +1 -1
- package/src/assets/skills/qa/SKILL.md +1 -3
- package/src/assets/skills/quality-gates/SKILL.md +10 -13
- package/src/assets/skills/quality-gates/references/report-template.md +20 -20
- package/src/assets/skills/react/SKILL.md +1 -1
- package/src/assets/skills/regression/SKILL.md +1 -1
- package/src/assets/skills/reliability/SKILL.md +1 -1
- package/src/assets/skills/research-codebase/SKILL.md +1 -1
- package/src/assets/skills/research-competitor/SKILL.md +1 -1
- package/src/assets/skills/research-external/SKILL.md +1 -1
- package/src/assets/skills/research-technology/SKILL.md +1 -1
- package/src/assets/skills/review-methodology/SKILL.md +1 -1
- package/src/assets/skills/rust/SKILL.md +1 -1
- package/src/assets/skills/security/SKILL.md +1 -1
- package/src/assets/skills/software-design/SKILL.md +1 -1
- package/src/assets/skills/test-driven-development/SKILL.md +9 -29
- package/src/assets/skills/testing/SKILL.md +1 -1
- package/src/assets/skills/typescript/SKILL.md +1 -1
- package/src/assets/skills/ui-design/SKILL.md +1 -1
- package/src/assets/skills/worktree-support/SKILL.md +3 -55
- package/src/assets/skills/worktree-support/references/discovery.md +48 -0
- package/src/assets/skills/worktree-support/references/roots.md +2 -2
|
@@ -23,6 +23,31 @@
|
|
|
23
23
|
# Section 4: Legacy install notice — one line when this repository still carries
|
|
24
24
|
# a retired project-local devflow install (its .claude/settings.json registers
|
|
25
25
|
# devflow hooks), pointing at `devflow uninstall --scope local`.
|
|
26
|
+
# Section 5: Compaction resume directive — on a `compact` SessionStart, one fixed
|
|
27
|
+
# line telling the model to re-read the devflow command it was running from the
|
|
28
|
+
# phase in progress (D-COMPACT-RESUME-DIRECTIVE).
|
|
29
|
+
# Section 6: CLAUDE.md import audit — a top-level systemMessage (shown to the user,
|
|
30
|
+
# never part of additionalContext) naming an `@path` import that puts a large file
|
|
31
|
+
# into every thread's always-loaded context, once per finding, with a stamp that
|
|
32
|
+
# makes an unchanged start free (D-CLAUDE-MD-IMPORT-AUDIT, D-AUDIT-STAMP,
|
|
33
|
+
# D-SYSTEMMESSAGE-ENVELOPE).
|
|
34
|
+
#
|
|
35
|
+
# Sections 5 and 6 add NO new exit path: neither calls `exit`, a failure in either
|
|
36
|
+
# leaves the other sections and the directive intact, and the hook still exits as it
|
|
37
|
+
# did before (the existing exits are the bad-CWD and re-entrancy returns, the
|
|
38
|
+
# no-JSON-tool return at the top, and the two sourcing failures). With neither jq nor
|
|
39
|
+
# node the hook returns before Section 5 can run, so there is no directive then; that
|
|
40
|
+
# is accepted and documented.
|
|
41
|
+
#
|
|
42
|
+
# Cost of Sections 5 and 6 (the [DR-10] table below belongs to Section 3):
|
|
43
|
+
# - Section 5: a `case` on a value parsed with the CWD, in the same single
|
|
44
|
+
# subprocess as before; zero extra forks.
|
|
45
|
+
# - Section 6, unchanged start (the stamp's root set equals the current one and no
|
|
46
|
+
# recorded path changed): shell builtins only, one bounded read of the stamp, no
|
|
47
|
+
# fork, no node process.
|
|
48
|
+
# - Section 6, changed start: ONE node process (claude-md-audit.cjs), and a
|
|
49
|
+
# sibling temp file renamed over the stamp. When none of the roots exists there
|
|
50
|
+
# is nothing to audit: the stamp is written with builtins, and node is not started.
|
|
26
51
|
|
|
27
52
|
# Safe no-op fallback: must exist before hook-bootstrap is sourced.
|
|
28
53
|
dbg() { :; }
|
|
@@ -49,7 +74,13 @@ source "$SCRIPT_DIR/hook-bootstrap" "session-start-context"
|
|
|
49
74
|
source "$SCRIPT_DIR/json-parse" || { echo "session-start-context: failed to source json-parse" >&2; exit 1; }
|
|
50
75
|
if [ "$_JSON_AVAILABLE" = "false" ]; then exit 0; fi
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
# One subprocess yields both fields: the working directory and the SessionStart
|
|
78
|
+
# `source` (startup|resume|clear|compact) that Section 5 gates on, so the directive
|
|
79
|
+
# costs no fork of its own. Sections 3 and 4 keep reading `source` themselves, where
|
|
80
|
+
# they gate (startup|clear), so neither depends on this value.
|
|
81
|
+
_SC_FIELDS=$(printf '%s' "$INPUT" | json_extract_cwd_field "source")
|
|
82
|
+
CWD="${_SC_FIELDS%%$'\001'*}"
|
|
83
|
+
SESSION_SOURCE="${_SC_FIELDS#*$'\001'}"
|
|
53
84
|
if [ -z "$CWD" ] || [ ! -d "$CWD" ]; then
|
|
54
85
|
dbg "EXIT: bad CWD"
|
|
55
86
|
exit 0
|
|
@@ -239,6 +270,7 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
239
270
|
# since the model would read the file the link names and pass that on.
|
|
240
271
|
# Builtins only: no fork, save the log line of a refused index.
|
|
241
272
|
_SC_INDEX="$LEARNING_DIR/index.md"; DECISIONS_INDEX_LINE=""
|
|
273
|
+
DECISIONS_PASS_RULE="Decisions (direct delegations only — workflow skills load their own): pass this index as DECISIONS_CONTEXT — its content, read once — to every agent that takes it."
|
|
242
274
|
if [ -n "$DIRECTIVE_LEDGER_SAFE" ] && df_file_below "$LEDGER_ROOT" "$_SC_INDEX" && [ -s "$_SC_INDEX" ]; then
|
|
243
275
|
_SC_IDX1=""; IFS= read -r _SC_IDX1 < "$_SC_INDEX" || true
|
|
244
276
|
[ "$_SC_IDX1" != "(none)" ] && DECISIONS_INDEX_LINE="Index: $_SC_INDEX"
|
|
@@ -250,10 +282,19 @@ if [ "$LEARNING_ENABLED" = "true" ]; then
|
|
|
250
282
|
DECISIONS_SECTION="${DECISIONS_SECTION}
|
|
251
283
|
$(printf '%b' "$DECISIONS_TLDR")"
|
|
252
284
|
fi
|
|
253
|
-
# The index line goes last.
|
|
285
|
+
# The index line goes last among the data lines, and the pass rule follows it.
|
|
286
|
+
# D-DECISIONS-CHARTER-HANDOFF: the rule that tells the main model to pass this
|
|
287
|
+
# index on as DECISIONS_CONTEXT lives here, not in the orchestrator charter. It
|
|
288
|
+
# is only useful with an index line to pass, so it is emitted only with one, and
|
|
289
|
+
# this block is already gated on the machine switch narrowed by the repository,
|
|
290
|
+
# so a learning-off machine or repo never sees it (the charter paid for it in
|
|
291
|
+
# every session, learning or not). It also reaches sessions with ambient off,
|
|
292
|
+
# which the charter never did. A static literal: no input is interpolated, so it
|
|
293
|
+
# needs no shape gate. The same text reaches the jq and the node envelope.
|
|
254
294
|
if [ -n "$DECISIONS_INDEX_LINE" ]; then
|
|
255
295
|
DECISIONS_SECTION="${DECISIONS_SECTION}
|
|
256
|
-
${DECISIONS_INDEX_LINE}
|
|
296
|
+
${DECISIONS_INDEX_LINE}
|
|
297
|
+
${DECISIONS_PASS_RULE}"
|
|
257
298
|
fi
|
|
258
299
|
if [ -n "$CONTEXT" ]; then
|
|
259
300
|
CONTEXT="${CONTEXT}
|
|
@@ -779,11 +820,270 @@ ${LEGACY_SECTION}"
|
|
|
779
820
|
fi
|
|
780
821
|
fi
|
|
781
822
|
|
|
823
|
+
# --- Section 5: Compaction resume directive ---
|
|
824
|
+
# D-COMPACT-RESUME-DIRECTIVE: after a compaction nothing tells the model to re-read
|
|
825
|
+
# the devflow command it was running; Claude Code re-injects a long command only in
|
|
826
|
+
# part (the plan records commands over about 5k tokens being truncated on re-injection,
|
|
827
|
+
# which this repository cannot verify). On the SessionStart whose source is `compact`
|
|
828
|
+
# this section adds one fixed line, appended to CONTEXT with the other sections'
|
|
829
|
+
# join, and never sent as a systemMessage.
|
|
830
|
+
#
|
|
831
|
+
# The line is a constant: a single-quoted string that interpolates nothing, so the
|
|
832
|
+
# `$CLAUDE_CONFIG_DIR` in it reaches the model as text and its bytes do not depend on
|
|
833
|
+
# the caller. It names, in at most 250 ASCII characters (tests/session-start-compact
|
|
834
|
+
# holds the cap and the numeric-floors ceiling `compact-directive-max-chars`):
|
|
835
|
+
# (a) an if-clause, so it applies only when a devflow command was running, with an
|
|
836
|
+
# explicit ignore clause;
|
|
837
|
+
# (b) where the command file lives, by rule: commands/devflow/ under the Claude
|
|
838
|
+
# config directory ($CLAUDE_CONFIG_DIR, else ~/.claude);
|
|
839
|
+
# (c) the read mechanics: list the headings, then read from the phase in progress,
|
|
840
|
+
# never the whole file;
|
|
841
|
+
# (d) that the command's input (COMMAND_INPUT in the commands that bind it, an
|
|
842
|
+
# ARGUMENTS line in the others) comes from the conversation summary, not from a
|
|
843
|
+
# placeholder in the file;
|
|
844
|
+
# (e) to resume after the last finished phase.
|
|
845
|
+
# The gate is a POSITIVE `compact` case, emitted on every compact run whatever the
|
|
846
|
+
# project (the directive does no project work), so it never becomes a denylist and a
|
|
847
|
+
# missing, absent or unrecognised source emits nothing. The model decides whether a
|
|
848
|
+
# command was running: detecting one here would be judgment, which stays out of hooks.
|
|
849
|
+
case "$SESSION_SOURCE" in
|
|
850
|
+
compact)
|
|
851
|
+
dbg "compaction resume directive emitted"
|
|
852
|
+
COMPACT_SECTION='If a devflow command was running: re-read {$CLAUDE_CONFIG_DIR or ~/.claude}/commands/devflow/<name>.md, list headings, read from current phase, take input (COMMAND_INPUT/ARGUMENTS) from the summary, resume after the last finished phase. Else ignore.'
|
|
853
|
+
if [ -n "$CONTEXT" ]; then
|
|
854
|
+
CONTEXT="${CONTEXT}
|
|
855
|
+
|
|
856
|
+
${COMPACT_SECTION}"
|
|
857
|
+
else
|
|
858
|
+
CONTEXT="$COMPACT_SECTION"
|
|
859
|
+
fi
|
|
860
|
+
;;
|
|
861
|
+
esac
|
|
862
|
+
|
|
863
|
+
# --- Section 6: CLAUDE.md import audit and its stamp ---
|
|
864
|
+
# D-CLAUDE-MD-IMPORT-AUDIT: a CLAUDE.md `@path` import loads its file into every
|
|
865
|
+
# thread at launch, so a large import is paid for in every session. This section
|
|
866
|
+
# reports the ones over the thresholds that claude-md-audit.cjs holds (and documents:
|
|
867
|
+
# grammar, bounds, thresholds, the upstream differences) in a top-level systemMessage,
|
|
868
|
+
# which the user sees and the model does not (D-SYSTEMMESSAGE-ENVELOPE, json-parse).
|
|
869
|
+
# It never enters CONTEXT, and the audit READS only: this section and init write the
|
|
870
|
+
# stamp, nothing else.
|
|
871
|
+
#
|
|
872
|
+
# D-AUDIT-STAMP: one machine-root file, $HOME/.devflow/.claude-md-audit, so a changed
|
|
873
|
+
# start costs one node process and an unchanged one costs none. Its rows are `V 1`,
|
|
874
|
+
# `R <root>` (the gated root set), `P <flag> <path>` (every path the last audit
|
|
875
|
+
# examined: 0 absent, 1 regular file, 2 exists but is not one), `K <key>` (a finding
|
|
876
|
+
# already displayed) and `E <reason>`; the format is specified in claude-md-audit.cjs.
|
|
877
|
+
# Gated roots: CLAUDE.md in the Claude config directory ($CLAUDE_CONFIG_DIR when
|
|
878
|
+
# absolute, else ~/.claude) always; in a git project that is not HOME
|
|
879
|
+
# (PROJECT_OK) also its CLAUDE.md, .claude/CLAUDE.md and CLAUDE.local.md.
|
|
880
|
+
# Fast path (builtins only, no fork): the audit is skipped when the stamp's R rows
|
|
881
|
+
# equal the current root set and every P row still holds: `-e` agrees with the
|
|
882
|
+
# flag, and a regular file is not `-nt` (newer than) the stamp. Mtimes are whole
|
|
883
|
+
# seconds. Two gaps are accepted: a file whose mtime is moved back before the stamp
|
|
884
|
+
# is missed until its next forward change, and a write landing while an audit runs
|
|
885
|
+
# can be missed the same way. The fast path decides only whether the audit runs.
|
|
886
|
+
# Slow path: ONE node process over the roots (none when no root exists: there is
|
|
887
|
+
# nothing to read, so the stamp records the absent roots with builtins). A finding is recorded as displayed
|
|
888
|
+
# only after the output below was emitted, so a lost stamp update can repeat a
|
|
889
|
+
# message and can never hide a new finding.
|
|
890
|
+
# Failure: node failing, the script missing or throwing, or output that is not the
|
|
891
|
+
# framed block shows nothing, and writes a stamp holding the R rows, the keys
|
|
892
|
+
# already displayed and an error marker; an unchanged broken state then starts no
|
|
893
|
+
# node process, and a changed root set retries. A root path holding a control byte
|
|
894
|
+
# is never recorded, so a setup with one re-audits at every start (rare).
|
|
895
|
+
# Skipped silently: no node on PATH, no ~/.devflow (a session never creates the
|
|
896
|
+
# machine root), or a stamp path that is a link or not a regular file.
|
|
897
|
+
# A stamp over 256 KiB, or one with a NUL byte, is read as absent.
|
|
898
|
+
SYSTEM_MESSAGE=""
|
|
899
|
+
AUDIT_STAMP_NEXT=""
|
|
900
|
+
AUDIT_STAMP_FILE="$TRACKER_DEVFLOW_DIR/.claude-md-audit"
|
|
901
|
+
AUDIT_SCRIPT="$SCRIPT_DIR/../claude-md-audit.cjs"
|
|
902
|
+
_SC_AUDIT_OLD_STAMP=""
|
|
903
|
+
_SC_AUDIT_ROOTS=()
|
|
904
|
+
|
|
905
|
+
# _sc_audit_stamp_blocked — succeeds when the stamp path is a link or exists and is
|
|
906
|
+
# not a regular file: the write is refused and the audit skipped (D-AUDIT-STAMP).
|
|
907
|
+
_sc_audit_stamp_blocked() {
|
|
908
|
+
if [ -L "$AUDIT_STAMP_FILE" ]; then return 0; fi
|
|
909
|
+
if [ -e "$AUDIT_STAMP_FILE" ] && [ ! -f "$AUDIT_STAMP_FILE" ]; then return 0; fi
|
|
910
|
+
return 1
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
# _sc_audit_stamp_fresh — succeeds when the audit can be skipped. Builtins only.
|
|
914
|
+
# Sets _SC_AUDIT_OLD_STAMP to the stamp text (empty when absent, over 256 KiB or
|
|
915
|
+
# holding a NUL: `read -d '' -n N` succeeds only when it stops short of the end of
|
|
916
|
+
# the file, which is a stamp the shell cannot vouch for). Ends in an explicit return
|
|
917
|
+
# so a caller running under set -e would not die on the normal path: a function's last
|
|
918
|
+
# status is the status of its call, and under errexit a non-zero one is fatal.
|
|
919
|
+
_sc_audit_stamp_fresh() {
|
|
920
|
+
local line="" have="" want="" root="" path=""
|
|
921
|
+
_SC_AUDIT_OLD_STAMP=""
|
|
922
|
+
[ -f "$AUDIT_STAMP_FILE" ] || return 1
|
|
923
|
+
if IFS= read -r -d '' -n 262145 _SC_AUDIT_OLD_STAMP 2>/dev/null < "$AUDIT_STAMP_FILE"; then
|
|
924
|
+
_SC_AUDIT_OLD_STAMP=""
|
|
925
|
+
return 1
|
|
926
|
+
fi
|
|
927
|
+
case "$_SC_AUDIT_OLD_STAMP" in
|
|
928
|
+
'V 1'|'V 1'$'\n'*) ;;
|
|
929
|
+
*) _SC_AUDIT_OLD_STAMP=""; return 1 ;;
|
|
930
|
+
esac
|
|
931
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
932
|
+
want="${want}R ${root}"$'\n'
|
|
933
|
+
done
|
|
934
|
+
while IFS= read -r line; do
|
|
935
|
+
case "$line" in
|
|
936
|
+
'R '*) have="${have}${line}"$'\n' ;;
|
|
937
|
+
esac
|
|
938
|
+
done <<< "$_SC_AUDIT_OLD_STAMP"
|
|
939
|
+
if [ "$have" != "$want" ]; then return 1; fi
|
|
940
|
+
while IFS= read -r line; do
|
|
941
|
+
case "$line" in
|
|
942
|
+
'P 0 '*)
|
|
943
|
+
path="${line#P 0 }"
|
|
944
|
+
if [ -e "$path" ]; then return 1; fi
|
|
945
|
+
;;
|
|
946
|
+
'P 1 '*)
|
|
947
|
+
path="${line#P 1 }"
|
|
948
|
+
if [ ! -e "$path" ] || [ "$path" -nt "$AUDIT_STAMP_FILE" ]; then return 1; fi
|
|
949
|
+
;;
|
|
950
|
+
'P 2 '*)
|
|
951
|
+
path="${line#P 2 }"
|
|
952
|
+
if [ ! -e "$path" ]; then return 1; fi
|
|
953
|
+
;;
|
|
954
|
+
esac
|
|
955
|
+
done <<< "$_SC_AUDIT_OLD_STAMP"
|
|
956
|
+
return 0
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
# _sc_audit_shell_stamp <absent|failed> — a stamp the shell writes without node, for the
|
|
960
|
+
# two cases that need no audit text. Sets AUDIT_STAMP_NEXT. The rows are the ones
|
|
961
|
+
# claude-md-audit.cjs renders for the same state (tests/session-start-compact.test.ts
|
|
962
|
+
# holds the two equal): a root with a control byte is left out, as the script leaves it
|
|
963
|
+
# out, and the keys of the previous stamp are kept.
|
|
964
|
+
# absent No root exists, so there is nothing to audit and nothing to show: the root
|
|
965
|
+
# rows and a `P 0` row each. A CLAUDE.md appearing at any of them re-audits.
|
|
966
|
+
# failed The audit could not run: the root rows and an error marker, no P rows, so
|
|
967
|
+
# only a changed root set retries.
|
|
968
|
+
_sc_audit_shell_stamp() {
|
|
969
|
+
local kind="$1" line="" root="" text='V 1'$'\n'
|
|
970
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
971
|
+
case "$root" in
|
|
972
|
+
*[[:cntrl:]]*) ;;
|
|
973
|
+
*) text="${text}R ${root}"$'\n' ;;
|
|
974
|
+
esac
|
|
975
|
+
done
|
|
976
|
+
if [ "$kind" = "absent" ]; then
|
|
977
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
978
|
+
case "$root" in
|
|
979
|
+
*[[:cntrl:]]*) ;;
|
|
980
|
+
*) text="${text}P 0 ${root}"$'\n' ;;
|
|
981
|
+
esac
|
|
982
|
+
done
|
|
983
|
+
fi
|
|
984
|
+
while IFS= read -r line; do
|
|
985
|
+
case "$line" in
|
|
986
|
+
'K '*) text="${text}${line}"$'\n' ;;
|
|
987
|
+
esac
|
|
988
|
+
done <<< "$_SC_AUDIT_OLD_STAMP"
|
|
989
|
+
if [ "$kind" = "failed" ]; then text="${text}E audit-failed"$'\n'; fi
|
|
990
|
+
AUDIT_STAMP_NEXT="$text"
|
|
991
|
+
return 0
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
# _sc_audit_no_root — succeeds when none of the gated roots exists. The common case on a
|
|
995
|
+
# machine with no CLAUDE.md anywhere, settled by `-e` tests alone: no node process.
|
|
996
|
+
_sc_audit_no_root() {
|
|
997
|
+
local root=""
|
|
998
|
+
for root in "${_SC_AUDIT_ROOTS[@]}"; do
|
|
999
|
+
if [ -e "$root" ]; then return 1; fi
|
|
1000
|
+
done
|
|
1001
|
+
return 0
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
# _sc_audit_run — the slow path: one node process, its framed block parsed with
|
|
1005
|
+
# builtins. `M ` rows are the systemMessage lines; V/R/P/K/E rows are the new stamp.
|
|
1006
|
+
# Sets SYSTEM_MESSAGE and AUDIT_STAMP_NEXT; a block that is not complete is a failure.
|
|
1007
|
+
_sc_audit_run() {
|
|
1008
|
+
local out="" line="" rc=0 magic="" end="" msg="" stamp=""
|
|
1009
|
+
out=$(node "$AUDIT_SCRIPT" hook "$HOME" "$AUDIT_STAMP_FILE" "${_SC_AUDIT_ROOTS[@]}" 2>/dev/null)
|
|
1010
|
+
rc=$?
|
|
1011
|
+
if [ "$rc" -eq 0 ]; then
|
|
1012
|
+
while IFS= read -r line; do
|
|
1013
|
+
case "$line" in
|
|
1014
|
+
'devflow-claude-md-audit 1') magic="yes" ;;
|
|
1015
|
+
'END') end="yes" ;;
|
|
1016
|
+
'M '*)
|
|
1017
|
+
if [ -n "$msg" ]; then msg="${msg}"$'\n'"${line#M }"; else msg="${line#M }"; fi
|
|
1018
|
+
;;
|
|
1019
|
+
[VRPKE]' '*) stamp="${stamp}${line}"$'\n' ;;
|
|
1020
|
+
esac
|
|
1021
|
+
done <<< "$out"
|
|
1022
|
+
fi
|
|
1023
|
+
if [ "$rc" -eq 0 ] && [ -n "$magic" ] && [ -n "$end" ] && [ -n "$stamp" ]; then
|
|
1024
|
+
SYSTEM_MESSAGE="$msg"
|
|
1025
|
+
AUDIT_STAMP_NEXT="$stamp"
|
|
1026
|
+
dbg "claude-md audit ran (message=${#msg} chars)"
|
|
1027
|
+
else
|
|
1028
|
+
dbg "claude-md audit failed — recording the failure, showing nothing"
|
|
1029
|
+
_sc_audit_shell_stamp failed
|
|
1030
|
+
fi
|
|
1031
|
+
return 0
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
# _sc_audit_record — write AUDIT_STAMP_NEXT, after the output has been emitted. A
|
|
1035
|
+
# sibling temp file (owner-only: the umask is set before the copy exists, because a rename
|
|
1036
|
+
# installs the copy's mode and not the replaced file's) is
|
|
1037
|
+
# renamed over the stamp; nothing stands at either name that is a link or not a
|
|
1038
|
+
# regular file (noclobber alone would still open a FIFO, and mv onto a linked directory
|
|
1039
|
+
# moves into it), and a failed write leaves the old stamp. Never fails the hook.
|
|
1040
|
+
_sc_audit_record() {
|
|
1041
|
+
local tmp="${AUDIT_STAMP_FILE}.tmp.$$"
|
|
1042
|
+
[ -n "$AUDIT_STAMP_NEXT" ] || return 0
|
|
1043
|
+
[ -d "$TRACKER_DEVFLOW_DIR" ] || return 0
|
|
1044
|
+
if _sc_audit_stamp_blocked; then return 0; fi
|
|
1045
|
+
if [ -e "$tmp" ] || [ -L "$tmp" ]; then return 0; fi
|
|
1046
|
+
if ( umask 077; set -o noclobber; printf '%s' "$AUDIT_STAMP_NEXT" > "$tmp" ) 2>/dev/null; then
|
|
1047
|
+
if _sc_audit_stamp_blocked; then
|
|
1048
|
+
rm -f -- "$tmp" 2>/dev/null
|
|
1049
|
+
return 0
|
|
1050
|
+
fi
|
|
1051
|
+
mv -f -- "$tmp" "$AUDIT_STAMP_FILE" 2>/dev/null || rm -f -- "$tmp" 2>/dev/null
|
|
1052
|
+
else
|
|
1053
|
+
rm -f -- "$tmp" 2>/dev/null
|
|
1054
|
+
fi
|
|
1055
|
+
return 0
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
if [ "$_HAS_NODE" = "true" ] && [ -d "$TRACKER_DEVFLOW_DIR" ]; then
|
|
1059
|
+
if _sc_audit_stamp_blocked; then
|
|
1060
|
+
dbg "claude-md audit skipped: the stamp path is a link or not a regular file"
|
|
1061
|
+
else
|
|
1062
|
+
_SC_AUDIT_CLAUDE_DIR="$HOME/.claude"
|
|
1063
|
+
case "${CLAUDE_CONFIG_DIR:-}" in /*) _SC_AUDIT_CLAUDE_DIR="$CLAUDE_CONFIG_DIR" ;; esac
|
|
1064
|
+
_SC_AUDIT_ROOTS=("$_SC_AUDIT_CLAUDE_DIR/CLAUDE.md")
|
|
1065
|
+
if [ -n "$PROJECT_OK" ]; then
|
|
1066
|
+
_SC_AUDIT_ROOTS+=("$PROJECT_ROOT/CLAUDE.md" "$PROJECT_ROOT/.claude/CLAUDE.md" "$PROJECT_ROOT/CLAUDE.local.md")
|
|
1067
|
+
fi
|
|
1068
|
+
if _sc_audit_stamp_fresh; then
|
|
1069
|
+
dbg "claude-md audit skipped: the stamp is current"
|
|
1070
|
+
elif _sc_audit_no_root; then
|
|
1071
|
+
dbg "claude-md audit skipped: no root exists — recording that"
|
|
1072
|
+
_sc_audit_shell_stamp absent
|
|
1073
|
+
else
|
|
1074
|
+
_sc_audit_run
|
|
1075
|
+
fi
|
|
1076
|
+
fi
|
|
1077
|
+
fi
|
|
1078
|
+
|
|
782
1079
|
# --- Output ---
|
|
783
1080
|
|
|
784
|
-
# Only output if we have something to inject
|
|
785
|
-
|
|
1081
|
+
# Only output if we have something to inject or to tell the user. The stamp is
|
|
1082
|
+
# recorded here too: an audit that found nothing to show still ran, and recording it
|
|
1083
|
+
# is what makes the next unchanged start free.
|
|
1084
|
+
if [ -z "$CONTEXT" ] && [ -z "$SYSTEM_MESSAGE" ]; then
|
|
786
1085
|
dbg "EXIT: no context to inject"
|
|
1086
|
+
_sc_audit_record
|
|
787
1087
|
exit 0
|
|
788
1088
|
fi
|
|
789
1089
|
|
|
@@ -791,5 +1091,13 @@ dbg "OUTPUT_LENGTH=${#CONTEXT}"
|
|
|
791
1091
|
log "Injecting context (${#CONTEXT} chars)"
|
|
792
1092
|
dbg "=== HOOK COMPLETE ==="
|
|
793
1093
|
|
|
794
|
-
# Output as additionalContext JSON envelope (Claude sees it as system context, not
|
|
795
|
-
|
|
1094
|
+
# Output as additionalContext JSON envelope (Claude sees it as system context, not
|
|
1095
|
+
# user-visible). The audit text, if any, travels in the envelope's top-level
|
|
1096
|
+
# systemMessage and never in the context (D-SYSTEMMESSAGE-ENVELOPE). With no message
|
|
1097
|
+
# the second argument is empty and the envelope is the one callers always got.
|
|
1098
|
+
json_session_output "$CONTEXT" "$SYSTEM_MESSAGE"
|
|
1099
|
+
_SC_OUT_RC=$?
|
|
1100
|
+
|
|
1101
|
+
# A finding is recorded as displayed only after it was shown (D-AUDIT-STAMP).
|
|
1102
|
+
if [ "$_SC_OUT_RC" -eq 0 ]; then _sc_audit_record; fi
|
|
1103
|
+
exit "$_SC_OUT_RC"
|
|
@@ -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
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
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
|
|
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
|
|
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 `,` (
|
|
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 (!
|
|
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
|
-
|
|
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",
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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)
|
|
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. Never load decisions files otherwise.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: apply-feature-knowledge
|
|
3
|
-
description:
|
|
3
|
+
description: Consume FEATURE_KNOWLEDGE, the pre-computed feature context
|
|
4
4
|
user-invocable: false
|
|
5
|
-
allowed-tools: Read
|
|
5
|
+
allowed-tools: Read, Bash
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Apply Feature Knowledge
|
|
@@ -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.
|
|
15
|
-
>
|
|
16
|
-
>
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 `FEATURE_KNOWLEDGE` block (headed `--- Feature knowledge: {slug} ---`): `Rules:` holds anti-patterns, gotchas and invariants; `KB:` is the full file's path (under `WORKTREE_PATH` when given).
|
|
23
|
+
2. **Apply** them: check your work against every bullet and cite it as `{slug} KB-AP-n` (a section-labelled bullet as `{slug} {section}`), never a bare ID. For architecture or integration context, Read that section on demand, with `offset` and `limit`: its start line is on the `Headings:` line, or comes from `command grep -n '^## ' "<KB path>"`. Quote KB text only from a Read view.
|
|
24
|
+
3. **Verify** against current code: where an assertion is outdated or contradicts the code, Read the source and trust it. Note a discrepancy in your output when it matters.
|
|
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
|
|
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, 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
|
|
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
|
---
|