@iceinvein/agent-skills 0.1.19 → 0.1.21
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/README.md +20 -0
- package/package.json +2 -1
- package/skills/cover-letter/SKILL.md +161 -0
- package/skills/cover-letter/evals/evals.json +38 -0
- package/skills/cover-letter/evals/inputs/jd-linear-senior-backend.md +43 -0
- package/skills/cover-letter/evals/inputs/jd-pathway-junior-fullstack.md +44 -0
- package/skills/cover-letter/evals/inputs/jd-ramp-senior-go-platform.md +39 -0
- package/skills/cover-letter/evals/inputs/resume-jordan-martinez.md +39 -0
- package/skills/cover-letter/evals/inputs/resume-priya-iyer.md +38 -0
- package/skills/cover-letter/evals/inputs/resume-sam-wu.md +48 -0
- package/skills/cover-letter-audit/SKILL.md +314 -0
- package/skills/cover-letter-persona/SKILL.md +231 -0
- package/skills/cover-letter-rewrite/SKILL.md +298 -0
- package/skills/cover-letter-write/SKILL.md +267 -0
- package/skills/improve-my-codebase/CATALOGUE-FIELDS.md +26 -0
- package/skills/improve-my-codebase/SKILL.md +516 -0
- package/skills/index.json +114 -26
- package/skills/terse/SKILL.md +55 -26
- package/skills/terse/skill.json +6 -3
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: improve-my-codebase
|
|
3
|
+
description: Use when the user wants a prioritized improvement report across an entire codebase or a scoped subset. Orchestrates the existing audit skills (Parnas, Ousterhout, Hickey, Martin, Evans, Rams, etc.) in parallel and produces a ranked, per-file report. Trigger on "/improve-my-codebase", "audit my codebase", "what should I improve", "review the whole repo", or scoped variants.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Improve My Codebase
|
|
7
|
+
|
|
8
|
+
A meta-orchestrator that runs the existing audit skills in this package across a codebase, then synthesizes their findings into a single prioritized report. Default invocation runs a full sweep; positional args switch modes (quick, diff, interactive) or narrow scope (focus area, module path).
|
|
9
|
+
|
|
10
|
+
**Core principle:** every issue surfaced should be one a senior engineer would agree is worth a developer's attention. Convergent findings (multiple audits flagging the same file or symbol) rank above single-axis findings, because independent perspectives agreeing is the strongest signal of real problems.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- A user types `/improve-my-codebase` or asks for a codebase-wide audit.
|
|
15
|
+
- A user wants to know what's worth improving in a repo before planning work.
|
|
16
|
+
- A user wants a scoped audit of changed files (`diff` mode) or a single module (`module <path>`).
|
|
17
|
+
|
|
18
|
+
**Not for:**
|
|
19
|
+
- Reviewing a single function or short snippet. Invoke the relevant single-axis audit directly.
|
|
20
|
+
- Auto-applying fixes. This skill emits a report only.
|
|
21
|
+
- Replacing the individual audit skills. They remain the source of truth and are dispatched here, not duplicated.
|
|
22
|
+
|
|
23
|
+
## Invocation
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
/improve-my-codebase # full sweep
|
|
27
|
+
/improve-my-codebase quick # fast subset, top 5 issues
|
|
28
|
+
/improve-my-codebase diff # only changed files vs. main
|
|
29
|
+
/improve-my-codebase interactive # interview-driven
|
|
30
|
+
/improve-my-codebase focus <area> # narrow to one axis
|
|
31
|
+
/improve-my-codebase module <path> # scope to a directory or file
|
|
32
|
+
/improve-my-codebase diff focus <area> # composition
|
|
33
|
+
/improve-my-codebase module <path> focus <area>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Argument rules:
|
|
37
|
+
- Positional. No leading `--`.
|
|
38
|
+
- Modes: `quick`, `diff`, `interactive`. First match wins; mutually exclusive.
|
|
39
|
+
- Scope filters: `focus <area>`, `module <path>`. Compose freely with each other and with default/diff modes.
|
|
40
|
+
- `quick` and `interactive` ignore scope tokens (warn, do not error).
|
|
41
|
+
- Unknown tokens: warn and drop, do not abort.
|
|
42
|
+
|
|
43
|
+
## Process Overview
|
|
44
|
+
|
|
45
|
+
Six sequential phases. Each phase is described in its own section below.
|
|
46
|
+
|
|
47
|
+
1. Parse args.
|
|
48
|
+
2. Detect stack.
|
|
49
|
+
3. Route audits.
|
|
50
|
+
4. Dispatch subagents in parallel.
|
|
51
|
+
5. Synthesize findings.
|
|
52
|
+
6. Write report.
|
|
53
|
+
|
|
54
|
+
The orchestrator is read-only until phase 6.
|
|
55
|
+
|
|
56
|
+
## Phase 1: Parse args
|
|
57
|
+
|
|
58
|
+
The orchestrator receives a single string of positional args after the command. Tokenize on whitespace and classify each token.
|
|
59
|
+
|
|
60
|
+
**Token classes:**
|
|
61
|
+
- **Mode tokens**: `quick`, `diff`, `interactive`. The first one encountered wins; later mode tokens are warned and dropped.
|
|
62
|
+
- **Scope tokens**: `focus`, `module`. Each consumes the next token as its value.
|
|
63
|
+
- **Unknown tokens**: warn and drop.
|
|
64
|
+
|
|
65
|
+
**Output structure:**
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mode": "full" | "quick" | "diff" | "interactive",
|
|
70
|
+
"scope": {
|
|
71
|
+
"module": "<path>" | null,
|
|
72
|
+
"focus": "<area>" | null
|
|
73
|
+
},
|
|
74
|
+
"raw": "<original arg string>"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Rules:**
|
|
79
|
+
- Empty args produce `{mode: "full", scope: {module: null, focus: null}}`.
|
|
80
|
+
- `quick` or `interactive` with scope tokens present: keep mode, set scope to `{module: null, focus: null}`, emit warning "scope tokens ignored in <mode> mode".
|
|
81
|
+
- `focus` without a value: emit error listing valid areas (from catalogue), exit before dispatch.
|
|
82
|
+
- `module` without a value: emit error "module requires a path argument", exit before dispatch.
|
|
83
|
+
- `module <path>` where path does not exist: emit error "no such module: <path>", exit before dispatch.
|
|
84
|
+
|
|
85
|
+
**Valid focus areas** (derived from the `applies` vocabulary):
|
|
86
|
+
`any`, `ui`, `domain`, `integration`, `architecture`, `errors`, `legacy`.
|
|
87
|
+
|
|
88
|
+
**Worked examples:**
|
|
89
|
+
|
|
90
|
+
| Input | Output |
|
|
91
|
+
|-------|--------|
|
|
92
|
+
| `""` | `{mode: "full", scope: {module: null, focus: null}}` |
|
|
93
|
+
| `"quick"` | `{mode: "quick", scope: {module: null, focus: null}}` |
|
|
94
|
+
| `"diff"` | `{mode: "diff", scope: {module: null, focus: null}}` |
|
|
95
|
+
| `"focus architecture"` | `{mode: "full", scope: {module: null, focus: "architecture"}}` |
|
|
96
|
+
| `"diff focus architecture"` | `{mode: "diff", scope: {module: null, focus: "architecture"}}` |
|
|
97
|
+
| `"module src/auth focus architecture"` | `{mode: "full", scope: {module: "src/auth", focus: "architecture"}}` |
|
|
98
|
+
| `"quick focus ui"` | `{mode: "quick", scope: {module: null, focus: null}}` plus warning |
|
|
99
|
+
| `"banana"` | `{mode: "full", scope: {module: null, focus: null}}` plus warning |
|
|
100
|
+
|
|
101
|
+
## Phase 2: Detect stack
|
|
102
|
+
|
|
103
|
+
Determine which audit categories apply to this repo. Use cheap signals only; do not walk the full repo tree.
|
|
104
|
+
|
|
105
|
+
**Detection output:**
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"languages": ["typescript", "..."],
|
|
110
|
+
"frameworks": ["react", "..."],
|
|
111
|
+
"hasUI": true,
|
|
112
|
+
"hasDomainLayer": false,
|
|
113
|
+
"hasIntegration": false,
|
|
114
|
+
"hasArchitecture": true
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Defaults**: all booleans default to `false`; `languages` and `frameworks` default to `[]`. A signal flipping a field to `true` or appending an entry is the only way values get populated.
|
|
119
|
+
|
|
120
|
+
**Signals to gather (run all four; the steps are cheap and orthogonal):**
|
|
121
|
+
|
|
122
|
+
1. **`package.json` if present**: read `dependencies` and `devDependencies`.
|
|
123
|
+
- Frameworks: any of `react`, `vue`, `@angular/core`, `svelte`, `solid-js`. Sets `frameworks` and `hasUI: true`.
|
|
124
|
+
- Integration: any of `kafkajs`, `amqplib`, `bullmq`, `nats`, `mqtt`. Sets `hasIntegration: true`.
|
|
125
|
+
2. **Top-level directory listing**: one `find . -maxdepth 3 -type d -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" -not -path "*/build/*" -not -path "*/coverage/*" -not -path "*/tests/fixtures/*"`.
|
|
126
|
+
- `domain/`, `entities/`, `aggregates/`: sets `hasDomainLayer: true`.
|
|
127
|
+
- `events/`, `messaging/`, `queues/`, `consumers/`: sets `hasIntegration: true`.
|
|
128
|
+
3. **File extension frequency**: one `find . -maxdepth 4 -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" -not -path "*/build/*" -not -path "*/coverage/*" -not -path "*/tests/fixtures/*"`, count by extension.
|
|
129
|
+
- **Frequency threshold for UI**: at least 3 files matching `.tsx`/`.jsx`/`.vue`/`.svelte`/`.html`/`.css`/`.scss` sets `hasUI: true`. A single fixture file should not flip the signal.
|
|
130
|
+
- `.ts`/`.js`: adds `typescript`/`javascript` to `languages` (>= 1 file).
|
|
131
|
+
- `.py`: adds `python` (>= 1).
|
|
132
|
+
- `.rs`: adds `rust` (>= 1).
|
|
133
|
+
- `.go`: adds `go` (>= 1).
|
|
134
|
+
4. **`hasArchitecture`**: true if total non-test source files >= 5 (excluding the same paths above).
|
|
135
|
+
|
|
136
|
+
**Failure behavior:**
|
|
137
|
+
- If no `package.json` and no source-file extensions are detected, treat as "no signal" and warn: "no recognizable codebase signals detected; running only `applies: any` audits".
|
|
138
|
+
- Detection is best-effort. False positives (e.g. an empty `events/` directory) are acceptable; the per-audit applicability check upstream will already drop irrelevant ones.
|
|
139
|
+
|
|
140
|
+
**What NOT to do:**
|
|
141
|
+
- Do not read source file contents for detection.
|
|
142
|
+
- Do not run language-specific tooling (no `tsc`, no `eslint`).
|
|
143
|
+
- Do not exceed two `find` invocations and one `package.json` read.
|
|
144
|
+
|
|
145
|
+
## Phase 3: Route audits
|
|
146
|
+
|
|
147
|
+
Choose which audits to dispatch.
|
|
148
|
+
|
|
149
|
+
**Inputs:**
|
|
150
|
+
- Detection result from Phase 2.
|
|
151
|
+
- Parsed args from Phase 1.
|
|
152
|
+
- Catalogue: `skills/index.json`.
|
|
153
|
+
|
|
154
|
+
**Algorithm:**
|
|
155
|
+
|
|
156
|
+
1. Load catalogue from `skills/index.json`. If the file is missing, unreadable, or fails JSON parse, hard fail per the error table (the orchestrator cannot route without a catalogue). Filter to entries with both `applies` and `quick` fields (i.e. audit skills).
|
|
157
|
+
2. **Apply detection filter:** keep an audit if any of its `applies` values matches an active signal:
|
|
158
|
+
- `any` always matches.
|
|
159
|
+
- `ui` matches if `hasUI`.
|
|
160
|
+
- `domain` matches if `hasDomainLayer`.
|
|
161
|
+
- `integration` matches if `hasIntegration`.
|
|
162
|
+
- `architecture` matches if `hasArchitecture`.
|
|
163
|
+
- `errors` matches if `hasArchitecture` (proxy: any non-trivial codebase has error-handling concerns).
|
|
164
|
+
- `legacy` matches only if `mode === "diff"`.
|
|
165
|
+
3. **Apply mode filter:**
|
|
166
|
+
- `quick` mode: keep only entries with `quick: true`.
|
|
167
|
+
- `diff` mode: no further filter (handled by `legacy` matching above).
|
|
168
|
+
- `interactive` and `full` modes: no further filter.
|
|
169
|
+
4. **Apply focus filter:** if `scope.focus` is set, keep only entries whose `applies` array contains that focus area.
|
|
170
|
+
5. If the resulting list is empty, abort dispatch and emit one of:
|
|
171
|
+
- "No audits applicable to detected stack: <signals>. Override with `focus <area>`."
|
|
172
|
+
- "No audits matched `focus <area>`. Valid areas: <list>."
|
|
173
|
+
- "No quick audits applicable; rerun without `quick`."
|
|
174
|
+
|
|
175
|
+
**Module scope** is **not** applied here. It carries forward to Phase 4 as a per-subagent scope hint, because audit routing is the same regardless of whether the audit examines the whole repo or one path.
|
|
176
|
+
|
|
177
|
+
**Worked example:**
|
|
178
|
+
- Repo: Bun backend with `events/` directory.
|
|
179
|
+
- Detection: `{hasUI: false, hasDomainLayer: false, hasIntegration: true, hasArchitecture: true}`.
|
|
180
|
+
- Args: `quick focus architecture`.
|
|
181
|
+
- Step 2: keep audits with `any`, `architecture`, or `integration`.
|
|
182
|
+
- Step 3: `quick` mode keeps only `quick: true`. Result: `module-secret-auditor`, `coupling-auditor`, `cohesion-analyzer`, `demeter-enforcer`, `dependency-direction-auditor`, `cqs-auditor`, `temporal-coupling-detector`, plus any `any+quick` audits.
|
|
183
|
+
- Step 4: `focus architecture` drops audits whose `applies` does not include `architecture`. Result: `module-secret-auditor`, `coupling-auditor`, `cohesion-analyzer`, `demeter-enforcer`, `dependency-direction-auditor`, `cqs-auditor`.
|
|
184
|
+
|
|
185
|
+
### Diff mode file set
|
|
186
|
+
|
|
187
|
+
When `mode === "diff"`, before dispatch the orchestrator computes the changed-file set:
|
|
188
|
+
|
|
189
|
+
1. Run `git diff --name-only origin/main...HEAD` (fall back to `git diff --name-only main...HEAD` if no `origin` remote).
|
|
190
|
+
2. Filter out paths that no longer exist (deleted files) and paths in the standard ignored set (`node_modules/`, `.git/`, `dist/`, `build/`, `coverage/`, `tests/fixtures/`).
|
|
191
|
+
3. If the resulting list is empty, emit "diff mode: no changed files vs. main; rerun without `diff` or specify a commit range" per the error table and exit before dispatch.
|
|
192
|
+
4. Otherwise, this list is passed to each subagent as the `Scope` (the `Diff:` form of the prompt template in Phase 4).
|
|
193
|
+
|
|
194
|
+
## Phase 4: Dispatch subagents
|
|
195
|
+
|
|
196
|
+
For each routed audit, spawn one parallel `Agent` call with `subagent_type: general-purpose`. All dispatches go in **a single message with multiple tool calls** so they execute concurrently.
|
|
197
|
+
|
|
198
|
+
**Per-subagent prompt template:**
|
|
199
|
+
|
|
200
|
+
````
|
|
201
|
+
You are running the <audit-id> audit on a codebase.
|
|
202
|
+
|
|
203
|
+
# Principles to apply
|
|
204
|
+
|
|
205
|
+
<paste the full content of skills/<audit-id>/SKILL.md verbatim>
|
|
206
|
+
|
|
207
|
+
# Scope
|
|
208
|
+
|
|
209
|
+
<one of:>
|
|
210
|
+
- Whole repo at <repo-root-absolute-path>.
|
|
211
|
+
- Module: <module-path-absolute>.
|
|
212
|
+
- Diff: only the following files changed vs. main: <newline-separated list>.
|
|
213
|
+
|
|
214
|
+
# Method
|
|
215
|
+
|
|
216
|
+
1. Read the principles above.
|
|
217
|
+
2. Examine the in-scope files. Use Read, Grep, and Glob. Do not run commands that mutate state.
|
|
218
|
+
3. Identify violations of the principles. For each, capture: file path, optional line and symbol, severity, the specific principle violated, evidence (a short quoted or paraphrased snippet), and a 1-2 sentence recommendation.
|
|
219
|
+
4. Severity: high = a senior engineer would advocate fixing this in the next sprint; med = should be fixed during related work; low = nice to have.
|
|
220
|
+
5. Be conservative. If you are not confident a violation is real, omit it.
|
|
221
|
+
|
|
222
|
+
# Output contract
|
|
223
|
+
|
|
224
|
+
Return ONLY a JSON array of Finding objects. No markdown fences. No commentary before or after. If you find nothing, return [].
|
|
225
|
+
|
|
226
|
+
Schema:
|
|
227
|
+
|
|
228
|
+
[
|
|
229
|
+
{
|
|
230
|
+
"audit": "<audit-id>",
|
|
231
|
+
"file": "<repo-relative path>",
|
|
232
|
+
"line": <int or null>,
|
|
233
|
+
"symbol": "<string or null>",
|
|
234
|
+
"severity": "high" | "med" | "low",
|
|
235
|
+
"principle": "<short principle name, e.g. 'control coupling'>",
|
|
236
|
+
"evidence": "<1-3 sentence quote or paraphrase>",
|
|
237
|
+
"recommendation": "<1-2 sentence fix>"
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
# Constraints
|
|
242
|
+
|
|
243
|
+
- Do not exceed 25 findings. If more exist, emit the 25 highest severity.
|
|
244
|
+
- Do not invent file paths or line numbers. Cite real locations.
|
|
245
|
+
- Do not include findings outside the declared scope.
|
|
246
|
+
````
|
|
247
|
+
|
|
248
|
+
**Concurrency**: dispatch all subagents in a single tool-call batch. Subagents do not communicate with each other.
|
|
249
|
+
|
|
250
|
+
**Soft cap**: if a subagent has not returned within 5 minutes, drop it. The orchestrator does not have a wall-clock timer; this cap is enforced by treating any subagent that fails to return cleanly as `status: failed` and continuing.
|
|
251
|
+
|
|
252
|
+
**Retry policy:**
|
|
253
|
+
- If a subagent returns prose, markdown fences, or text that does not parse as JSON, retry **once** with this follow-up prompt:
|
|
254
|
+
> Your previous response was not valid JSON. Return ONLY a JSON array conforming to the schema specified earlier. No prose, no markdown fences, no commentary. If you found nothing, return `[]`.
|
|
255
|
+
- After the second failure, drop the audit and record `{audit, status: 'failed', reason: 'malformed JSON after 2 attempts'}`.
|
|
256
|
+
- Do not retry on timeout or tool-call crash.
|
|
257
|
+
|
|
258
|
+
**Per-finding validation:**
|
|
259
|
+
- Required fields: `audit`, `file`, `severity`, `principle`, `evidence`, `recommendation`.
|
|
260
|
+
- `severity` must be one of `"high"`, `"med"`, `"low"`.
|
|
261
|
+
- `audit` must equal the dispatched audit ID.
|
|
262
|
+
- A finding that fails validation is dropped; the count is added to that audit's metadata.
|
|
263
|
+
|
|
264
|
+
**Per-audit metadata produced** (consumed by Phase 5):
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"audit": "<audit-id>",
|
|
269
|
+
"status": "ok" | "failed",
|
|
270
|
+
"reason": "<string or null>",
|
|
271
|
+
"dropped_findings": <int, count of findings dropped at validation>,
|
|
272
|
+
"retried": <bool, true if recovered on attempt 2>
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
One such record is emitted per dispatched audit. Successful runs use `status: "ok"`, `reason: null`. Failed runs use `status: "failed"` and a reason string (e.g. `"timeout"`, `"crashed"`, `"malformed JSON after 2 attempts"`).
|
|
277
|
+
|
|
278
|
+
## Phase 5: Synthesize
|
|
279
|
+
|
|
280
|
+
Merge all `Finding[]` arrays into a single `Report` object.
|
|
281
|
+
|
|
282
|
+
**Inputs:**
|
|
283
|
+
- Map of `audit-id -> Finding[]` (one entry per dispatched audit; failed audits omitted from this map).
|
|
284
|
+
- Per-audit metadata: `{audit, status, dropped_findings, retried, reason}`.
|
|
285
|
+
|
|
286
|
+
**Algorithm:**
|
|
287
|
+
|
|
288
|
+
1. **Flatten** all findings into a single list, keeping `audit` on each.
|
|
289
|
+
2. **Group by file**: for each unique `file`, collect every finding on that file across all audits.
|
|
290
|
+
3. **Compute per-finding weight:**
|
|
291
|
+
- `severity_weight`: high = 3, med = 2, low = 1.
|
|
292
|
+
- `convergence_weight = min(3.0, 1 + 0.5 * (distinct_audits_on_file - 1))` where `distinct_audits_on_file` counts how many distinct audit IDs appear in the findings on this file.
|
|
293
|
+
- `symbol_boost`: if the finding has a non-null `symbol` AND at least one other finding on the same file shares that symbol AND comes from a different audit, multiply by `1.25`.
|
|
294
|
+
- `weight = severity_weight * convergence_weight * symbol_boost`.
|
|
295
|
+
4. **Per-file score**: sum of `weight` across all findings on that file.
|
|
296
|
+
5. **Sort files** by per-file score descending. For each file in the result, attach `top_issue` = the `principle` of the highest-weight finding on that file. Take the top N files (`N = 5` if `mode === "quick"`, else `10`; or all if fewer) for the "files most worth fixing" section.
|
|
297
|
+
6. **Sort findings** flat by `weight` descending. For each finding in the result, attach `convergence` = `"<distinct_audits_on_file> audits on this file"` (e.g. "4 audits on this file"). Take the top M findings (`M = 5` if `mode === "quick"`, else `25`; or all if fewer) for the "top cross-cutting findings" section.
|
|
298
|
+
7. **Build per-audit summaries**: for each audit ID present in the input map and with `findings.length > 0`, compute `{finding_count: <int>, unique_file_count: <int>, findings_by_file: [{file, findings: [...sorted by weight desc]}, ...]}`. Audits that returned `[]` are omitted from `by_audit_summary` (so Phase 6's per-axis index does not link to empty files).
|
|
299
|
+
8. **Preserve raw findings**: copy the input `audit-id -> Finding[]` map to `Report.by_audit` verbatim (audits with empty arrays are still present here for completeness; the per-axis index in Phase 6 reads `by_audit_summary` instead, which omits empty audits).
|
|
300
|
+
9. **Compute `audits_na`**: `audits_na = catalogue_audit_count - audits_dispatched_count` where `catalogue_audit_count` is the total number of audits in the catalogue with `applies` and `quick` fields, and `audits_dispatched_count` is the number routed by Phase 3 (regardless of pass/fail).
|
|
301
|
+
|
|
302
|
+
**Output `Report` structure:**
|
|
303
|
+
|
|
304
|
+
```json
|
|
305
|
+
{
|
|
306
|
+
"metadata": {
|
|
307
|
+
"date": "YYYY-MM-DD",
|
|
308
|
+
"mode": "full" | "quick" | "diff" | "interactive",
|
|
309
|
+
"scope": { "module": "...", "focus": "..." },
|
|
310
|
+
"audits_succeeded": 14,
|
|
311
|
+
"audits_failed": 2,
|
|
312
|
+
"audits_na": 4,
|
|
313
|
+
"audits_total": 30,
|
|
314
|
+
"failures": [{"audit": "event-design-reviewer", "reason": "malformed JSON after 2 attempts"}],
|
|
315
|
+
"retries": [{"audit": "rams-design-audit", "recovered_on_attempt": 2}],
|
|
316
|
+
"findings_high": 47,
|
|
317
|
+
"findings_med": 89,
|
|
318
|
+
"findings_low": 34
|
|
319
|
+
},
|
|
320
|
+
"top_files": [
|
|
321
|
+
{
|
|
322
|
+
"file": "src/checkout/order.ts",
|
|
323
|
+
"score": 31.0,
|
|
324
|
+
"audits_hit": ["coupling-auditor", "complexity-accountant", "cohesion-analyzer", "cqs-auditor"],
|
|
325
|
+
"top_issue": "<principle of highest-weight finding on this file>"
|
|
326
|
+
}
|
|
327
|
+
],
|
|
328
|
+
"top_findings": [
|
|
329
|
+
{
|
|
330
|
+
"weight": 11.25,
|
|
331
|
+
"finding": { "<full Finding object>": "..." },
|
|
332
|
+
"convergence": "4 audits on this file"
|
|
333
|
+
}
|
|
334
|
+
],
|
|
335
|
+
"by_audit": {
|
|
336
|
+
"coupling-auditor": [],
|
|
337
|
+
"complexity-accountant": []
|
|
338
|
+
},
|
|
339
|
+
"by_audit_summary": {
|
|
340
|
+
"coupling-auditor": {
|
|
341
|
+
"finding_count": 12,
|
|
342
|
+
"unique_file_count": 7,
|
|
343
|
+
"findings_by_file": [
|
|
344
|
+
{
|
|
345
|
+
"file": "src/checkout/order.ts",
|
|
346
|
+
"findings": []
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Worked example (scoring):**
|
|
355
|
+
|
|
356
|
+
Three findings on `src/checkout/order.ts`:
|
|
357
|
+
- `coupling-auditor`, severity high, symbol `OrderService.applyDiscount`.
|
|
358
|
+
- `cohesion-analyzer`, severity med, symbol `OrderService.applyDiscount`.
|
|
359
|
+
- `complexity-accountant`, severity high, symbol `OrderService` (different).
|
|
360
|
+
|
|
361
|
+
`distinct_audits_on_file = 3` so `convergence_weight = 1 + 0.5 * 2 = 2.0`.
|
|
362
|
+
|
|
363
|
+
- Finding 1: `severity = 3`, `convergence = 2.0`, `symbol_boost = 1.25` (shares symbol with finding 2 from a different audit). `weight = 7.5`.
|
|
364
|
+
- Finding 2: `severity = 2`, `convergence = 2.0`, `symbol_boost = 1.25`. `weight = 5.0`.
|
|
365
|
+
- Finding 3: `severity = 3`, `convergence = 2.0`, `symbol_boost = 1.0` (its symbol is unique among the file's findings). `weight = 6.0`.
|
|
366
|
+
|
|
367
|
+
Per-file score: `7.5 + 5.0 + 6.0 = 18.5`. Findings sorted by weight: 1, 3, 2.
|
|
368
|
+
|
|
369
|
+
## Phase 6: Write report
|
|
370
|
+
|
|
371
|
+
The only filesystem-mutating phase. Produces one top-level rollup and one per-axis file per fired audit.
|
|
372
|
+
|
|
373
|
+
**Output paths:**
|
|
374
|
+
- `docs/improvements/YYYY-MM-DD/audit.md` (top-level rollup).
|
|
375
|
+
- `docs/improvements/YYYY-MM-DD/audit/<audit-id>.md` (one per audit that returned at least one finding).
|
|
376
|
+
|
|
377
|
+
If `docs/improvements/YYYY-MM-DD/` already exists for today, append a numeric suffix: `audit-2.md`, `audit-3.md`, etc. Do not overwrite a previous run.
|
|
378
|
+
|
|
379
|
+
**`audit.md` template:**
|
|
380
|
+
|
|
381
|
+
````markdown
|
|
382
|
+
# Codebase audit: {{date}}
|
|
383
|
+
|
|
384
|
+
**Mode**: {{mode}}{{#if scope.focus}} focus {{scope.focus}}{{/if}}{{#if scope.module}} module {{scope.module}}{{/if}}
|
|
385
|
+
**Audits run**: {{audits_succeeded}} succeeded / {{audits_failed}} failed / {{audits_na}} N/A / {{audits_total}} total
|
|
386
|
+
**Findings**: {{findings_high}} high, {{findings_med}} med, {{findings_low}} low
|
|
387
|
+
|
|
388
|
+
{{#if failures}}
|
|
389
|
+
**Failed audits**: {{#each failures}}{{audit}} ({{reason}}){{#unless @last}}, {{/unless}}{{/each}}
|
|
390
|
+
{{/if}}
|
|
391
|
+
{{#if retries}}
|
|
392
|
+
**Retries recovered**: {{#each retries}}{{audit}}{{#unless @last}}, {{/unless}}{{/each}}
|
|
393
|
+
{{/if}}
|
|
394
|
+
|
|
395
|
+
## Files most worth fixing
|
|
396
|
+
|
|
397
|
+
| File | Score | Audits hit | Top issue |
|
|
398
|
+
|------|-------|------------|-----------|
|
|
399
|
+
{{#each top_files}}| {{file}} | {{score}} | {{audits_hit}} | {{top_issue}} |
|
|
400
|
+
{{/each}}
|
|
401
|
+
|
|
402
|
+
## Top cross-cutting findings
|
|
403
|
+
|
|
404
|
+
{{#each top_findings}}
|
|
405
|
+
{{@index}}. **{{convergence}}**: `{{finding.file}}{{#if finding.line}}:{{finding.line}}{{/if}}` flagged by {{finding.audit}}: {{finding.principle}}. [details](audit/{{finding.audit}}.md)
|
|
406
|
+
- Evidence: {{finding.evidence}}
|
|
407
|
+
- Recommendation: {{finding.recommendation}}
|
|
408
|
+
{{/each}}
|
|
409
|
+
|
|
410
|
+
## Per-axis reports
|
|
411
|
+
|
|
412
|
+
{{#each by_audit_summary}}
|
|
413
|
+
- [{{@key}}](audit/{{@key}}.md): {{this.finding_count}} findings
|
|
414
|
+
{{/each}}
|
|
415
|
+
````
|
|
416
|
+
|
|
417
|
+
**Per-axis `audit/<audit-id>.md` template:**
|
|
418
|
+
|
|
419
|
+
The template renders against `Report.by_audit_summary[<audit-id>]` (produced in Phase 5 step 7).
|
|
420
|
+
|
|
421
|
+
````markdown
|
|
422
|
+
# {{audit-id}} findings
|
|
423
|
+
|
|
424
|
+
{{finding_count}} findings on {{unique_file_count}} files.
|
|
425
|
+
|
|
426
|
+
{{#each findings_by_file}}
|
|
427
|
+
## `{{file}}`
|
|
428
|
+
|
|
429
|
+
{{#each findings}}
|
|
430
|
+
### {{principle}} ({{severity}}){{#if line}} (line {{line}}){{/if}}{{#if symbol}} (`{{symbol}}`){{/if}}
|
|
431
|
+
|
|
432
|
+
**Evidence:** {{evidence}}
|
|
433
|
+
|
|
434
|
+
**Recommendation:** {{recommendation}}
|
|
435
|
+
|
|
436
|
+
{{/each}}
|
|
437
|
+
{{/each}}
|
|
438
|
+
````
|
|
439
|
+
|
|
440
|
+
**Terminal summary** (printed after writing files):
|
|
441
|
+
|
|
442
|
+
```
|
|
443
|
+
Codebase audit complete.
|
|
444
|
+
|
|
445
|
+
Mode: <mode>
|
|
446
|
+
Findings: <high>H / <med>M / <low>L across <audits_succeeded> audits
|
|
447
|
+
|
|
448
|
+
Top 5 files to fix:
|
|
449
|
+
1. <file> (score <score>, hit by <audits_hit>)
|
|
450
|
+
2. ...
|
|
451
|
+
|
|
452
|
+
Top 5 cross-cutting issues:
|
|
453
|
+
1. [<convergence>] <file>:<line> : <principle>
|
|
454
|
+
2. ...
|
|
455
|
+
|
|
456
|
+
Full report: docs/improvements/<date>/audit.md
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Failure handling:**
|
|
460
|
+
- If the target directory cannot be created or written to (permissions, disk full): fall back to printing the full `audit.md` content to the terminal, surface the write error, and do not write the per-axis files. The user can copy-paste the report.
|
|
461
|
+
- If a per-axis file fails to write but `audit.md` succeeds: emit a warning with the audit ID, continue, and link in `audit.md` is left as a broken link with an explanatory note.
|
|
462
|
+
|
|
463
|
+
## Orchestration: putting it together
|
|
464
|
+
|
|
465
|
+
When the user invokes `/improve-my-codebase [args]`, execute phases in order. Stop early on hard failures (per the error table). Soft failures (subagent issues) are recorded in metadata and do not stop the run.
|
|
466
|
+
|
|
467
|
+
Pseudocode:
|
|
468
|
+
|
|
469
|
+
```
|
|
470
|
+
parsed = parseArgs(rawArgs)
|
|
471
|
+
if parsed.errors: emit, exit
|
|
472
|
+
|
|
473
|
+
detection = detectStack(repoRoot)
|
|
474
|
+
if detection.noSignal: warn, continue with applies:any audits only
|
|
475
|
+
|
|
476
|
+
audits = routeAudits(catalogue, detection, parsed)
|
|
477
|
+
if audits.empty: emit specific message, exit
|
|
478
|
+
|
|
479
|
+
if parsed.mode == "interactive":
|
|
480
|
+
invoke interactive interview (see Interactive Mode section); produces a refined `parsed`,
|
|
481
|
+
then re-run routeAudits.
|
|
482
|
+
|
|
483
|
+
findings = dispatchSubagents(audits, parsed.scope, repoRoot) // parallel
|
|
484
|
+
report = synthesize(findings, audits, parsed)
|
|
485
|
+
writeReport(report, todaysDateDir)
|
|
486
|
+
printTerminalSummary(report)
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Interactive Mode
|
|
490
|
+
|
|
491
|
+
When `parsed.mode === "interactive"`:
|
|
492
|
+
|
|
493
|
+
1. Show the user the detected stack and the audit set the orchestrator would run by default.
|
|
494
|
+
2. Ask, one at a time:
|
|
495
|
+
- "Anything you've been losing time on lately?" (free text, suggests a `focus` area)
|
|
496
|
+
- "Any directory you want to scope to?" (path or skip; sets `module`)
|
|
497
|
+
- "Quick scan or thorough?" (sets `quick` or full)
|
|
498
|
+
3. Apply the answers as if they were args, re-route, then proceed to dispatch.
|
|
499
|
+
4. Confirm the final audit list before dispatching: "Running these audits: <list>. OK?"
|
|
500
|
+
|
|
501
|
+
Interactive mode is the only path that reroutes after Phase 3.
|
|
502
|
+
|
|
503
|
+
## Error handling
|
|
504
|
+
|
|
505
|
+
| Failure | Phase | Response |
|
|
506
|
+
|---------|-------|----------|
|
|
507
|
+
| No audits applicable | 3 | Skip dispatch. Emit message. Suggest `focus <area>` to override. |
|
|
508
|
+
| `module <path>` does not exist | 1 | Hard fail. Print path + suggestion. |
|
|
509
|
+
| `diff` mode with no changed files | 3 | Tell user, suggest `full` or commit-range. Do not run. |
|
|
510
|
+
| `focus <area>` matches no audits | 3 | List valid areas. Exit. |
|
|
511
|
+
| Subagent timeout | 4 | Drop. Record `{audit, status: 'failed', reason: 'timeout'}`. Continue. |
|
|
512
|
+
| Subagent crash | 4 | Drop. Record. Continue. No retry. |
|
|
513
|
+
| Subagent malformed JSON | 4 | Retry up to 1 time (2 attempts total). Then drop. |
|
|
514
|
+
| Finding fails schema | 5 | Drop bad finding only. Note count in metadata. |
|
|
515
|
+
| Cannot write report file | 6 | Fall back to terminal-only. Print full report. Surface write error. |
|
|
516
|
+
| `index.json` missing/malformed | 3 | Hard fail. Suggest reinstalling. |
|