devflow-kit 3.3.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.
Files changed (138) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/agents/code.md +330 -0
  3. package/{src/assets → dist}/agents/design.md +1 -1
  4. package/{src/assets → dist}/agents/diagnose.md +1 -2
  5. package/dist/agents/git.md +29 -56
  6. package/{src/assets → dist}/agents/knowledge.md +4 -3
  7. package/{src/assets → dist}/agents/research.md +2 -2
  8. package/{src/assets → dist}/agents/review.md +8 -7
  9. package/{src/assets → dist}/agents/scrutinize.md +1 -1
  10. package/dist/agents/skim.md +148 -0
  11. package/{src/assets → dist}/agents/triage.md +1 -1
  12. package/dist/cli/commands/init.js +62 -0
  13. package/dist/cli/commands/learning.js +38 -3
  14. package/dist/cli/commands/uninstall.js +42 -1
  15. package/dist/commands/bug-analysis.md +30 -8
  16. package/dist/commands/code-review.md +141 -60
  17. package/dist/commands/debug.md +14 -12
  18. package/dist/commands/dynamic-build.md +37 -38
  19. package/dist/commands/dynamic-plan.md +30 -18
  20. package/dist/commands/dynamic-profile.md +27 -13
  21. package/dist/commands/dynamic-tickets.md +28 -14
  22. package/dist/commands/explore.md +15 -13
  23. package/dist/commands/implement.md +33 -28
  24. package/dist/commands/plan.md +37 -24
  25. package/dist/commands/release.md +69 -4
  26. package/dist/commands/research.md +33 -11
  27. package/dist/commands/resolve.md +35 -32
  28. package/dist/commands/self-review.md +36 -23
  29. package/dist/core/agent-models.js +43 -0
  30. package/dist/core/assets.js +55 -10
  31. package/dist/core/claude-md-audit.js +190 -0
  32. package/dist/core/feature-switch.js +20 -1
  33. package/dist/core/flags.js +28 -0
  34. package/dist/core/fs-atomic.js +8 -3
  35. package/dist/core/learning-variants.js +213 -0
  36. package/dist/core/manifest.js +62 -0
  37. package/dist/core/mds-variants.js +38 -1
  38. package/dist/core/plugins.js +71 -9
  39. package/{src/assets → dist/learning-off}/agents/code.md +6 -10
  40. package/dist/learning-off/agents/design.md +119 -0
  41. package/dist/learning-off/agents/diagnose.md +210 -0
  42. package/dist/learning-off/agents/knowledge.md +90 -0
  43. package/dist/learning-off/agents/research.md +149 -0
  44. package/dist/learning-off/agents/review.md +228 -0
  45. package/dist/learning-off/agents/scrutinize.md +117 -0
  46. package/{src/assets → dist/learning-off}/agents/skim.md +1 -8
  47. package/dist/learning-off/agents/triage.md +163 -0
  48. package/dist/learning-off/commands/bug-analysis.md +420 -0
  49. package/dist/learning-off/commands/code-review.md +525 -0
  50. package/dist/learning-off/commands/debug.md +294 -0
  51. package/dist/learning-off/commands/dynamic-build.md +1255 -0
  52. package/dist/learning-off/commands/dynamic-plan.md +424 -0
  53. package/dist/learning-off/commands/dynamic-profile.md +214 -0
  54. package/dist/learning-off/commands/dynamic-tickets.md +632 -0
  55. package/dist/learning-off/commands/explore.md +210 -0
  56. package/dist/learning-off/commands/implement.md +808 -0
  57. package/dist/learning-off/commands/plan.md +664 -0
  58. package/dist/learning-off/commands/release.md +310 -0
  59. package/dist/learning-off/commands/research.md +222 -0
  60. package/dist/learning-off/commands/resolve.md +837 -0
  61. package/dist/learning-off/commands/self-review.md +266 -0
  62. package/dist/skills/git/references/tracker/_contract.md +33 -0
  63. package/dist/skills/git/references/tracker/github/fetch-issue.md +2 -0
  64. package/dist/skills/git/references/tracker/github/fetch-issues-batch.md +2 -0
  65. package/dist/skills/git/references/tracker/github/gather-release-evidence.md +4 -0
  66. package/dist/skills/git/references/tracker/github/post-wave-report.md +2 -0
  67. package/dist/skills/git/references/tracker/github/setup-task.md +12 -0
  68. package/dist/skills/git/references/tracker/jira/associate-release.md +1 -1
  69. package/dist/skills/git/references/tracker/jira/fetch-issue.md +2 -0
  70. package/dist/skills/git/references/tracker/jira/fetch-issues-batch.md +2 -0
  71. package/dist/skills/git/references/tracker/jira/gather-release-evidence.md +4 -0
  72. package/dist/skills/git/references/tracker/jira/post-wave-report.md +2 -0
  73. package/dist/skills/git/references/tracker/jira/setup-task.md +14 -2
  74. package/dist/skills/git/references/tracker/linear/associate-release.md +1 -1
  75. package/dist/skills/git/references/tracker/linear/fetch-issue.md +2 -0
  76. package/dist/skills/git/references/tracker/linear/fetch-issues-batch.md +2 -0
  77. package/dist/skills/git/references/tracker/linear/gather-release-evidence.md +4 -0
  78. package/dist/skills/git/references/tracker/linear/post-wave-report.md +2 -0
  79. package/dist/skills/git/references/tracker/linear/setup-task.md +14 -2
  80. package/dist/targets/claude-code/installer.js +72 -36
  81. package/dist/targets/claude-code/language-stamp.js +185 -0
  82. package/dist/targets/claude-code/learning-install.js +489 -0
  83. package/package.json +1 -1
  84. package/src/assets/agents/code.mds +339 -0
  85. package/src/assets/agents/design.mds +149 -0
  86. package/src/assets/agents/diagnose.mds +225 -0
  87. package/src/assets/agents/evaluate.md +1 -3
  88. package/src/assets/agents/git.mds +29 -56
  89. package/src/assets/agents/knowledge.mds +125 -0
  90. package/src/assets/agents/research.mds +176 -0
  91. package/src/assets/agents/review.mds +286 -0
  92. package/src/assets/agents/scrutinize.mds +132 -0
  93. package/src/assets/agents/skim.mds +161 -0
  94. package/src/assets/agents/triage.mds +194 -0
  95. package/src/assets/agents/validate.md +8 -6
  96. package/src/assets/commands/_partials/_compliance.mds +5 -4
  97. package/src/assets/commands/_partials/_decisions.mds +31 -0
  98. package/src/assets/commands/_partials/_engine.mds +9 -1
  99. package/src/assets/commands/_partials/_knowledge.mds +25 -12
  100. package/src/assets/commands/_partials/_preamble.mds +33 -9
  101. package/src/assets/commands/_partials/_publication.mds +5 -4
  102. package/src/assets/commands/_partials/_settings.mds +13 -5
  103. package/src/assets/commands/_partials/_wave.mds +8 -0
  104. package/src/assets/commands/bug-analysis.mds +24 -2
  105. package/src/assets/commands/code-review.mds +147 -44
  106. package/src/assets/commands/debug.mds +17 -1
  107. package/src/assets/commands/dynamic-build.mds +33 -2
  108. package/src/assets/commands/dynamic-plan.mds +36 -6
  109. package/src/assets/commands/dynamic-profile.mds +9 -1
  110. package/src/assets/commands/dynamic-tickets.mds +16 -2
  111. package/src/assets/commands/explore.mds +27 -1
  112. package/src/assets/commands/implement.mds +41 -8
  113. package/src/assets/commands/plan.mds +47 -8
  114. package/src/assets/commands/{release.md → release.mds} +27 -24
  115. package/src/assets/commands/research.mds +28 -4
  116. package/src/assets/commands/resolve.mds +43 -2
  117. package/src/assets/commands/self-review.mds +30 -5
  118. package/src/assets/mds/tracker/_contract.mds +72 -0
  119. package/src/assets/mds/tracker/_github.mds +13 -2
  120. package/src/assets/mds/tracker/_jira.mds +17 -5
  121. package/src/assets/mds/tracker/_linear.mds +17 -5
  122. package/src/assets/mds/tracker/_mcp.mds +2 -2
  123. package/src/assets/mds/tracker/_steps.mds +97 -0
  124. package/src/assets/rules/context-economy.md +10 -0
  125. package/src/assets/rules/go.md +1 -0
  126. package/src/assets/rules/java.md +1 -0
  127. package/src/assets/rules/python.md +1 -0
  128. package/src/assets/rules/rust.md +1 -0
  129. package/src/assets/rules/typescript.md +1 -0
  130. package/src/assets/scripts/claude-md-audit.cjs +611 -0
  131. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +1 -2
  132. package/src/assets/scripts/hooks/json-helper.cjs +13 -5
  133. package/src/assets/scripts/hooks/json-parse +34 -10
  134. package/src/assets/scripts/hooks/session-start-context +315 -7
  135. package/src/assets/skills/apply-decisions/SKILL.md +1 -1
  136. package/src/assets/skills/apply-feature-knowledge/SKILL.md +5 -5
  137. package/src/assets/skills/feature-knowledge/SKILL.md +43 -12
  138. package/src/assets/skills/quality-gates/SKILL.md +1 -1
@@ -0,0 +1,420 @@
1
+ ---
2
+ description: Proactive bug finding with static and semantic analysis — hunts real bugs in changed code before merge
3
+ ---
4
+ # Bug Analysis Command
5
+
6
+ Run a proactive bug analysis on the current branch by combining static analysis tools with parallel semantic analyzers, then synthesizing results into an actionable bug report. Supports incremental analysis, timestamped report directories, and `/resolve` compatibility.
7
+
8
+ ## Usage
9
+
10
+ ```
11
+ /bug-analysis (analyze current branch — incremental if prior analysis exists)
12
+ /bug-analysis --full (force full analysis, ignore incremental state)
13
+ /bug-analysis --no-static (skip static analysis track, semantic-only)
14
+ ```
15
+
16
+ ## Phases
17
+
18
+ ### Phase 1: Pre-flight
19
+
20
+ **Produces:** BRANCH_INFO, PR_DESCRIPTION, EVIDENCE_POLICY, ISSUE_REQUIRED, APPLY_CONVENTIONS, REQUIRE_NON_AUTHOR_APPROVAL
21
+
22
+ **Resolve the evidence policy once per run**, from the repository root, before any step reads the values:
23
+
24
+ ```bash
25
+ node "$HOME/.devflow/scripts/resolve-evidence-policy.cjs" 2>/dev/null; echo "exit=$?"
26
+ ```
27
+
28
+ Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `EVIDENCE_POLICY=<required|standard> SOURCE=<file|worktree|default|invalid|error> REF=<branch|none>[ WARN=<remote-unavailable|invalid-file|raised-by-compliance|pr-changes-policy>[,…]] ISSUE_REQUIRED=<true|false> APPLY_CONVENTIONS=<true|false> REQUIRE_NON_AUTHOR_APPROVAL=<true|false>` — these fields, in this order, nothing else, where `<branch>` is a branch name such as `main`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `EVIDENCE_POLICY=required SOURCE=error REF=none ISSUE_REQUIRED=true APPLY_CONVENTIONS=true REQUIRE_NON_AUTHOR_APPROVAL=true` instead.
29
+
30
+ Set `EVIDENCE_POLICY`, `ISSUE_REQUIRED`, `APPLY_CONVENTIONS` and `REQUIRE_NON_AUTHOR_APPROVAL` from the accepted line. Pass agents only the three mechanism inputs, never `EVIDENCE_POLICY`. Report `Evidence policy: {EVIDENCE_POLICY} (source: {SOURCE})`, plus any `WARN` tokens as advisory, once in the final report.
31
+
32
+ **Docs root (D-DOCS-ROOT).** Every `.devflow/docs/` path this command reads or writes lives at the checkout's toplevel, never under the directory the session started in. Resolve `{worktree}` from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — by running
33
+
34
+ ```bash
35
+ git -C "{start}" rev-parse --show-toplevel
36
+ ```
37
+
38
+ and using its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. Every docs path below is written `{worktree}/.devflow/docs/…`; a repo-relative docs path handed to an agent always travels with a `WORKTREE_PATH` naming the checkout it is relative to.
39
+
40
+ Render the test-plan block from `/implement`'s evidence file, and from nothing else:
41
+ 1. `branch_slug` is `git branch --show-current` with every `/` replaced by `-`.
42
+ 2. Only when `branch_slug` matches `^[A-Za-z0-9._-]{1,200}$` and the file exists, run (the path double-quoted):
43
+
44
+ ```bash
45
+ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{worktree}/.devflow/docs/evidence-{branch_slug}.md"; echo "exit=$?"
46
+ ```
47
+
48
+ 3. On `exit=0`, `PR_TEST_PLAN_BLOCK` is its stdout byte for byte without that `exit=` line; in every other case it is `(none)`. Nothing here waits on it: the Git agent pastes it only behind its own check, and only into a PR it creates.
49
+
50
+ Spawn Git agent:
51
+
52
+ ```
53
+ Agent(subagent_type="Git", run_in_background=false):
54
+ "OPERATION: ensure-pr-ready
55
+ PR_TEST_PLAN_BLOCK: {PR_TEST_PLAN_BLOCK verbatim, or (none)}
56
+ APPLY_CONVENTIONS: {APPLY_CONVENTIONS}
57
+ Validate branch, commit if needed, push, create PR if needed.
58
+ Return: branch, base_branch, branch-slug, PR#"
59
+ ```
60
+
61
+ **Extract from response:** `branch`, `base_branch`, `branch_slug`, `pr_number`.
62
+
63
+ **Fetch PR body** (after extracting `pr_number`):
64
+ ```bash
65
+ PR_DESCRIPTION=$(gh pr view {pr_number} --json body --jq '.body' 2>/dev/null || echo "(none)")
66
+ ```
67
+ If `pr_number` is absent or the command fails, set `PR_DESCRIPTION` to `(none)`.
68
+
69
+ ### Phase 2: Static Analysis
70
+
71
+ **Requires:** BRANCH_INFO
72
+
73
+ #### Step 2a: Incremental Detection & Timestamp Setup
74
+
75
+ **Produces:** DIFF_RANGE, ANALYSIS_DIR
76
+ **Requires:** BRANCH_INFO
77
+
78
+ 1. Check `{worktree}/.devflow/docs/bug-analysis/{branch-slug}/.last-analysis-head`:
79
+ - **If exists AND `--full` NOT set:**
80
+ - Read the SHA from the file
81
+ - Verify reachable: `git cat-file -t {sha}` — if exit code non-zero (rebase invalidated SHA), fall through to full
82
+ - If SHA == current HEAD → "No new commits since last analysis. Use --full for a full re-analysis." Stop.
83
+ - Set `DIFF_RANGE` to `{sha}...HEAD`
84
+ - **If not exists, unreachable SHA, or `--full`:**
85
+ - Set `DIFF_RANGE` to `{base_branch}...HEAD`
86
+ 2. Generate timestamp: `YYYY-MM-DD_HHMM`. If directory already exists (same-minute collision), append seconds (`YYYY-MM-DD_HHMMSS`).
87
+ 3. Create timestamped analysis directory: `mkdir -p "{worktree}/.devflow/docs/bug-analysis/{branch-slug}/{timestamp}/"`
88
+ 4. Set `ANALYSIS_DIR` to that path.
89
+
90
+ #### Step 2b: Check Changed Files
91
+
92
+ **Requires:** DIFF_RANGE
93
+
94
+ ```bash
95
+ CHANGED_FILES=$(git diff --name-only {DIFF_RANGE})
96
+ ```
97
+
98
+ Store result as `CHANGED_FILES` — used throughout Steps 2d and Phase 4 to avoid repeated git invocations and ensure consistency.
99
+
100
+ If output is empty → "No changes to analyze." Stop.
101
+
102
+ #### Step 2c: Tool Availability Check
103
+
104
+ **Produces:** STATIC_TOOL_STATUS
105
+
106
+ Skip if `--no-static` flag provided.
107
+
108
+ ```bash
109
+ SEMGREP_AVAILABLE=$(which semgrep 2>/dev/null && echo "yes" || echo "no")
110
+ SNYK_AVAILABLE=$(which snyk 2>/dev/null && echo "yes" || echo "no")
111
+ CODEQL_AVAILABLE=$(which codeql 2>/dev/null && echo "yes" || echo "no")
112
+ ```
113
+
114
+ If all are `no`: warn user "No static analysis tools found. Proceeding with semantic analysis only. To enable static analysis, install semgrep (`pip install semgrep`) or snyk (`npm install -g snyk`)." Set `STATIC_FINDINGS` to `(none)`.
115
+
116
+ If some are available: note which tools will run.
117
+
118
+ #### Step 2d: Tiered Static Analysis
119
+
120
+ **Produces:** STATIC_FINDINGS
121
+ **Requires:** STATIC_TOOL_STATUS, DIFF_RANGE, ANALYSIS_DIR
122
+
123
+ Skip if `--no-static` flag provided or all tools unavailable.
124
+
125
+ Run available tools on the changed files (from `CHANGED_FILES` computed in Step 2b).
126
+
127
+ **Semgrep and Snyk run in parallel** — launch both in the background, then wait for both before proceeding to CodeQL. CodeQL is conditional and sequential (it needs Semgrep/Snyk results to decide whether to run).
128
+
129
+ **Semgrep** (if available):
130
+ ```bash
131
+ # tr '\n' '\0' + xargs -0 is portable across GNU and BSD xargs (macOS ships BSD xargs, which lacks -d)
132
+ echo "$CHANGED_FILES" | tr '\n' '\0' | xargs -0 timeout 300 semgrep scan --config auto --sarif --quiet 2>/dev/null
133
+ ```
134
+ Parse SARIF output → extract findings.
135
+
136
+ **Snyk Code** (if available):
137
+ ```bash
138
+ # Run a single project-level scan; filter SARIF results programmatically to CHANGED_FILES before LLM processing.
139
+ # Per-file invocation via xargs would invoke snyk O(n) times and --file is for dependency scanning, not source code.
140
+ SNYK_SARIF=$(timeout 300 snyk code test --sarif 2>/dev/null)
141
+ # Programmatic filter: keep only results whose file path appears in CHANGED_FILES.
142
+ # This is defense-in-depth — filtering at the data layer before the LLM agent sees any output.
143
+ SNYK_FILTERED=$(echo "$SNYK_SARIF" | jq --argjson files "$(echo "$CHANGED_FILES" | jq -R . | jq -s .)" \
144
+ '.runs[].results |= map(select(.locations[].physicalLocation.artifactLocation.uri as $uri | $files | index($uri) != null))' \
145
+ 2>/dev/null || echo "$SNYK_SARIF")
146
+ ```
147
+ Parse `SNYK_FILTERED` SARIF → extract findings. If `jq` is unavailable, fall back to the raw `SNYK_SARIF` and note the limitation.
148
+
149
+ **CodeQL** (if available AND (`--full` OR Semgrep/Snyk found HIGH/CRITICAL findings)):
150
+ ```bash
151
+ # Use a unique temp directory per run to prevent symlink attacks and concurrent-process clobbering
152
+ CODEQL_TMP=$(mktemp -d)
153
+ # Register cleanup trap immediately after mktemp — ensures rm -rf runs on EXIT, SIGTERM, and SIGINT
154
+ # even if the session is interrupted before reaching the explicit rm -rf below
155
+ trap 'rm -rf "${CODEQL_TMP}"' EXIT INT TERM
156
+ timeout 600 codeql database create "${CODEQL_TMP}/db" --language={detected-language} --source-root=. 2>/dev/null && \
157
+ timeout 600 codeql database analyze "${CODEQL_TMP}/db" --format=sarif-latest --output="${CODEQL_TMP}/results.sarif" 2>/dev/null
158
+ # Capture exit status before cleanup so cleanup doesn't mask failures
159
+ CODEQL_EXIT=$?
160
+ # Parse SARIF output BEFORE cleanup — rm -rf destroys results.sarif
161
+ CODEQL_SARIF=$(cat "${CODEQL_TMP}/results.sarif" 2>/dev/null || echo "")
162
+ # Explicit cleanup (trap also covers this path; explicit rm is belt-and-suspenders)
163
+ rm -rf "${CODEQL_TMP}"
164
+ trap - EXIT INT TERM
165
+ ```
166
+ Parse `CODEQL_SARIF` → extract findings. If database creation fails, `CODEQL_EXIT` is non-zero — skip CodeQL findings and note it. The `trap` guarantees cleanup on SIGTERM/SIGINT/EXIT so orphaned temp directories do not accumulate across interrupted sessions.
167
+
168
+ **Normalize** all findings to unified table, cap at top 50 by severity. Truncate each Description entry to 200 characters maximum to bound the serialized size of `STATIC_FINDINGS`:
169
+
170
+ | Tool | File:Line | CWE | Severity | Title | Description |
171
+ |------|-----------|-----|----------|-------|-------------|
172
+ | {tool} | {file}:{line} | {CWE or —} | {CRITICAL/HIGH/MEDIUM/LOW} | {title} | {description truncated to 200 chars} |
173
+
174
+ Write ALL raw findings to `{ANALYSIS_DIR}/static-findings.md`. Set `STATIC_FINDINGS` to the top-50 table.
175
+
176
+ If no tool produced findings: set `STATIC_FINDINGS` to `(none)`.
177
+
178
+ ### Phase 3: Context Loading
179
+
180
+ **Produces:** FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, PLAN_CONTEXT, ACCEPTANCE_RULES
181
+
182
+ #### Feature Knowledge
183
+
184
+ ### Load Feature Knowledge
185
+
186
+ Resolve `{worktree}` as the checkout's toplevel, because feature knowledge bases are committed with the branch (D-PROMPT-ROOT): from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`) — run
187
+
188
+ ```bash
189
+ git -C "{start}" rev-parse --show-toplevel
190
+ ```
191
+
192
+ and use its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. All paths below are relative to `{worktree}`.
193
+
194
+ **Step 1 — Read the index cache:**
195
+
196
+ Attempt to read `{worktree}/.devflow/features/index.md`. Each line follows the format:
197
+
198
+ ```
199
+ - **{slug}** — {areas} — {Use-when description}
200
+ ```
201
+
202
+ If `index.md` exists and contains at least one entry line, use it for relevance matching.
203
+
204
+ **Step 2 — Fallback: glob frontmatter (if `index.md` is absent or empty):**
205
+
206
+ Glob `{worktree}/.devflow/features/*/KNOWLEDGE.md`. For each file found, read only its YAML frontmatter block (between the opening and closing `---` delimiters). The frontmatter fields `name`, `description`, and `directories` are the authoritative relevance surface — `index.md` is only a cache.
207
+
208
+ **Step 3 — Pick relevant KBs:**
209
+
210
+ Match the current task area and description against each index line (or frontmatter `description` + `directories` on fallback). Select entries whose documented area overlaps the current task. This is a relevance judgment — prefer specificity over breadth.
211
+
212
+ **Step 4 — Read each selected KB's Rules:**
213
+
214
+ For each selected entry, `{kb}` is `{worktree}/.devflow/features/{slug}/KNOWLEDGE.md`:
215
+
216
+ 1. List its `##` headings with line numbers through Bash: `command grep -n '^## ' "{kb}"`. This only locates sections; the text of a KB comes from the Read view alone.
217
+ 2. Read the `## Rules` range (its line to the next heading) with the Read tool, using `offset` and `limit`, and choose the one to three bullets most relevant to the current task. The choice is yours, made per KB.
218
+ 3. If the KB has no `## Rules` section, choose one to three entries from its `## Anti-Patterns` or `## Gotchas` range the same way, and label them by that section's name instead of an ID.
219
+
220
+ When a KB contradicts the code you observe, **trust the code** — the code is the freshness mechanism; the KB may lag behind. A missing Rules section, a missing heading list and `(none)` are legitimate states, not errors.
221
+
222
+ **Step 5 — Set FEATURE_KNOWLEDGE and FEATURE_KNOWLEDGE_RULES:**
223
+
224
+ Write one block per selected KB. Paste each bullet verbatim from the Read view, never from a shell view. The path is relative to the checkout root; an agent resolves it under `WORKTREE_PATH` when one is provided.
225
+
226
+ ```
227
+ --- Feature knowledge: {slug} ---
228
+ KB: .devflow/features/{slug}/KNOWLEDGE.md
229
+ Rules:
230
+ - **KB-AP-2** {bullet text, verbatim}
231
+ - **KB-INV-1** {bullet text, verbatim}
232
+ Headings: L5 Rules · L40 Overview · L62 Anti-Patterns · L118 Key Files
233
+ ```
234
+
235
+ A KB with no Rules section labels its entries `Rules ({section name}):` and gives them no ID. `FEATURE_KNOWLEDGE` is these blocks; `FEATURE_KNOWLEDGE_RULES` is the same blocks without the `Headings:` line. Both come from this one selection, and each spawn names the variable its recipient takes. If no KBs exist, no KBs are relevant, or `.devflow/features/` is absent, set both to `(none)`.
236
+
237
+ **One git call, then direct reads — no `.cjs` script.** After resolving `{worktree}`, this step is 1 index read (or N frontmatter reads on fallback), plus one heading listing and one Rules read per selected KB, bounded by KB count.
238
+
239
+ #### Plan Artifact
240
+
241
+ 1. List `{worktree}/.devflow/docs/design/*.md` — sort descending by filename (timestamps are naturally sortable), scan the 10 most recent
242
+ 2. Read the most recent file if it exists
243
+ 3. Extract `## Acceptance Criteria` section → parse into table: `| ID | Criterion | Type | Testable Condition |`
244
+ 4. Set `PLAN_CONTEXT` to plan summary; `ACCEPTANCE_RULES` to the table
245
+ 5. If no plan files exist or section not found: `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)`
246
+
247
+ ### Phase 4: File Analysis
248
+
249
+ **Produces:** ACTIVE_FOCUSES
250
+ **Requires:** DIFF_RANGE
251
+
252
+ Determine which focus analyzers to run using `CHANGED_FILES` (already computed in Step 2b — do not re-run `git diff`):
253
+
254
+ | Focus | Condition |
255
+ |-------|-----------|
256
+ | `security` | Always |
257
+ | `functional` | Always |
258
+ | `integration` | 2+ distinct directories changed (`dirname` unique count ≥ 2) |
259
+ | `usability` | Any `.tsx`, `.jsx`, `.html`, or `.css` file changed |
260
+
261
+ ### Phase 5: Parallel Bug Analysis
262
+
263
+ **Produces:** ANALYZER_OUTPUTS
264
+ **Requires:** DIFF_RANGE, ANALYSIS_DIR, ACTIVE_FOCUSES, STATIC_FINDINGS, ACCEPTANCE_RULES, PLAN_CONTEXT, FEATURE_KNOWLEDGE
265
+
266
+ Spawn ALL active Diagnose agents **in a single message** (parallel, NOT background):
267
+
268
+ For each active focus, spawn:
269
+ ```
270
+ Agent(subagent_type="Diagnose", run_in_background=false):
271
+ "Analyze focusing on {focus}.
272
+ FOCUS: {focus}
273
+ DIFF_COMMAND: git diff {DIFF_RANGE}
274
+ ACCEPTANCE_RULES: {ACCEPTANCE_RULES filtered to this focus type, or (none)}
275
+ PLAN_CONTEXT: {PLAN_CONTEXT}
276
+ STATIC_FINDINGS: {STATIC_FINDINGS if focus == security, else (none)}
277
+ FEATURE_KNOWLEDGE: {FEATURE_KNOWLEDGE}
278
+ PR_DESCRIPTION: <pr-description>{PR_DESCRIPTION}</pr-description>
279
+ OUTPUT_PATH: {ANALYSIS_DIR}/{focus}.md
280
+ Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE.
281
+ IMPORTANT: Write report to {ANALYSIS_DIR}/{focus}.md using Write tool"
282
+ ```
283
+
284
+ Notes:
285
+ - Security analyzer receives full `STATIC_FINDINGS`; all others receive `(none)`
286
+ - Filter `ACCEPTANCE_RULES` by the `Type` column matching each focus: security criteria → security analyzer, functional criteria → functional analyzer, etc. Pass the filtered subset only
287
+ - Spawn all in a single message for true parallel execution
288
+
289
+ ### Phase 6: Synthesis
290
+
291
+ **Produces:** BUG_ANALYSIS_SUMMARY
292
+ **Requires:** ANALYZER_OUTPUTS, ANALYSIS_DIR, BRANCH_INFO
293
+
294
+ Spawn Synthesize agent:
295
+
296
+ ```
297
+ Agent(subagent_type="Synthesize", run_in_background=false):
298
+ "Mode: bug-analysis
299
+ ANALYSIS_BASE_DIR: {ANALYSIS_DIR}
300
+ BRANCH: {branch} -> {base_branch}
301
+ TIMESTAMP: {timestamp}
302
+ Output: {ANALYSIS_DIR}/bug-analysis-summary.md"
303
+ ```
304
+
305
+ ### Phase 7: Finalize
306
+
307
+ **Requires:** BRANCH_INFO, ANALYSIS_DIR
308
+
309
+ 1. Write current HEAD SHA to `{worktree}/.devflow/docs/bug-analysis/{branch-slug}/.last-analysis-head`
310
+ 2. Report to user:
311
+
312
+ ```
313
+ ## Bug Analysis Complete
314
+
315
+ **Branch**: {branch} -> {base_branch}
316
+ **Analysis**: {ANALYSIS_DIR}
317
+
318
+ ### Risk Assessment: {risk_level}
319
+
320
+ {brief_reasoning}
321
+
322
+ ### Bug Counts
323
+ | Category | CRITICAL | HIGH | MEDIUM | LOW | Total |
324
+ |----------|----------|------|--------|-----|-------|
325
+ | Security | {n} | {n} | {n} | {n} | {n} |
326
+ | Functional | {n} | {n} | {n} | {n} | {n} |
327
+ | Integration | {n} | {n} | {n} | {n} | {n} |
328
+ | Usability | {n} | {n} | {n} | {n} | {n} |
329
+
330
+ ### Top Findings
331
+ {List top 3-5 bugs by severity and confidence}
332
+
333
+ ### Artifacts
334
+ - Bug report: {ANALYSIS_DIR}/bug-analysis-summary.md
335
+ - Per-focus reports: {ANALYSIS_DIR}/{security|functional|integration|usability}.md
336
+ - Static findings: {ANALYSIS_DIR}/static-findings.md (if static analysis ran)
337
+
338
+ {if any CRITICAL or HIGH bugs found:}
339
+ Run `/resolve` to process and fix these findings.
340
+ ```
341
+
342
+ ## Architecture
343
+
344
+ ```
345
+ /bug-analysis (orchestrator — spawns agents only)
346
+ │
347
+ ├─ Phase 1: Pre-flight
348
+ │ └─ Git agent (ensure-pr-ready)
349
+ │
350
+ ├─ Phase 2: Static Analysis
351
+ │ ├─ Step 2a: Incremental detection + timestamp setup
352
+ │ ├─ Step 2b: Check changed files (stop if none)
353
+ │ ├─ Step 2c: Tool availability check
354
+ │ └─ Step 2d: Tiered static analysis (semgrep → snyk → codeql)
355
+ │ Write static-findings.md
356
+ │
357
+ ├─ Phase 3: Context Loading
358
+ │ ├─ Feature knowledge load → FEATURE_KNOWLEDGE
359
+ │ └─ {worktree}/.devflow/docs/design/*.md → PLAN_CONTEXT + ACCEPTANCE_RULES
360
+ │
361
+ ├─ Phase 4: File Analysis
362
+ │ └─ Detect active focuses (security + functional always; integration + usability conditional)
363
+ │
364
+ ├─ Phase 5: Bug Analysis (PARALLEL)
365
+ │ ├─ Diagnose agent: security (+ STATIC_FINDINGS)
366
+ │ ├─ Diagnose agent: functional
367
+ │ ├─ Diagnose agent: integration (conditional)
368
+ │ └─ Diagnose agent: usability (conditional)
369
+ │
370
+ ├─ Phase 6: Synthesis
371
+ │ └─ Synthesize agent (mode: bug-analysis)
372
+ │
373
+ └─ Phase 7: Finalize
374
+ ├─ Write .last-analysis-head
375
+ └─ Display results + suggest /resolve if blocking bugs found
376
+ ```
377
+
378
+ ## Edge Cases
379
+
380
+ | Case | Handling |
381
+ |------|----------|
382
+ | No new commits since last analysis | Stop: "No new commits since last analysis. Use --full for a full re-analysis." |
383
+ | Rebase invalidates `.last-analysis-head` SHA | `git cat-file -t` check fails → fallback to full diff |
384
+ | Zero changed files in DIFF_RANGE | Stop: "No changes to analyze." |
385
+ | Same-minute analysis collision | `mkdir` with seconds suffix (`YYYY-MM-DD_HHMMSS`) |
386
+ | All static tools unavailable | Warn, proceed with semantic-only analysis |
387
+ | `--no-static` flag | Skip Phase 2c and 2d entirely; `STATIC_FINDINGS=(none)` |
388
+ | `--full` flag | Bypass incremental detection (Step 2a), run full diff from base |
389
+ | CodeQL database creation fails | Skip CodeQL, note in output, continue with other tools |
390
+ | Static tool produces no findings | `STATIC_FINDINGS=(none)` — normal, proceed with semantic analysis |
391
+ | No plan artifact found | `PLAN_CONTEXT=(none)`, `ACCEPTANCE_RULES=(none)` — proceed without acceptance criteria |
392
+ | `integration` focus skipped | Not spawned when only 1 directory changed |
393
+ | `usability` focus skipped | Not spawned when no UI files changed |
394
+
395
+ ## Resolve Compatibility
396
+
397
+ Run `/resolve` after `/bug-analysis` to fix identified bugs. `/resolve` automatically detects and uses bug analysis reports when no code review report exists.
398
+
399
+ ## Principles
400
+
401
+ 1. **Orchestration only** — Command spawns agents, doesn't do analysis work itself
402
+ 2. **Parallel, not background** — Analyzers spawn in one message with `run_in_background=false`
403
+ 3. **Static + semantic** — Two complementary tracks, each validates the other
404
+ 4. **Incremental by default** — Only analyze new changes unless `--full` specified
405
+ 5. **Verify before reporting** — Diagnose agents self-verify every finding
406
+ 6. **Honest reporting** — Display risk level and counts directly from synthesis
407
+
408
+ ## Phase Completion Checklist
409
+
410
+ Before reporting results, verify every phase was executed:
411
+
412
+ - [ ] Phase 1: Pre-flight → BRANCH_INFO captured, PR_DESCRIPTION fetched (or `(none)`)
413
+ - [ ] Phase 2: Static Analysis → STATIC_FINDINGS captured (or `(none)` if skipped/no tools/no findings); ANALYSIS_DIR created; CHANGED_FILES populated
414
+ - [ ] Phase 3: Context Loading → FEATURE_KNOWLEDGE loaded (or `(none)`), PLAN_CONTEXT and ACCEPTANCE_RULES captured (or `(none)`)
415
+ - [ ] Phase 4: File Analysis → ACTIVE_FOCUSES determined (security + functional always present)
416
+ - [ ] Phase 5: Parallel Bug Analysis → ANALYZER_OUTPUTS captured per active focus; all reports written to ANALYSIS_DIR
417
+ - [ ] Phase 6: Synthesis → BUG_ANALYSIS_SUMMARY written to `{ANALYSIS_DIR}/bug-analysis-summary.md`
418
+ - [ ] Phase 7: Finalize → `.last-analysis-head` updated; results displayed to user
419
+
420
+ If any phase is unchecked, execute it before proceeding.