aria-audit · diff

git:20260826.63e400f to git:20260914.6ff40c8

69 added, 51 removed. Audit A to A.

---
description: "ARIA audit skills — /audit dispatcher plus /audit-knowledge, /audit-config, /audit-style, /audit-usage. Use when user says 'audit knowledge', 'audit config', 'audit style', 'audit usage', 'review setup', or runs the slash commands."
globs: ["knowledge/intake/**/*", "knowledge/index.md", ".cursor/aria-knowledge.local.md", "AGENTS.md"]
alwaysApply: false
---
# ARIA — Audit Skills
This file ports the `/audit` dispatcher plus `/audit-knowledge`, `/audit-config`, `/audit-style`, and `/audit-usage` for the Cursor port. Triggers are natural-language ("audit knowledge", "audit config", "audit style", "mine my working style", "is ARIA worth it") in addition to slash-command names. The `/knowledge-audit` and `/config-audit` aliases are accepted equivalents. `/audit style` mines Cursor `agent-transcripts` JSONL (shape may differ from Claude Code; fail loud on drift).
---
---
## /audit
# /audit — Audit Family Dispatcher
- A thin umbrella over the four sub-audits. `/audit` does not scan anything itself — it resolves which sub-audit(s) the user means, then delegates to the sub-skill that owns the actual work. Think of it as a menu + router, not another audit implementation.
+ A thin umbrella over the six sub-audits. `/audit` does not scan anything itself — it resolves which
+ sub-audit(s) the user means, then delegates to the sub-skill that owns the actual work. Think of it
+ as a menu + router, not another audit implementation. **The `/audit <verb>` forms are the canonical
+ invocations for the whole family** (see "Canonical forms and compatibility" below).
- ## Step 0: Parse the Verb
+ ## Step 0: Parse the Verb (+ passthrough arguments)
- `/audit` takes at most one trailing verb. Resolve it against the grammar below before doing anything else.
+ `/audit` takes a **verb followed by optional arguments**. Resolve the FIRST token against the
+ grammar below before doing anything else. **Arguments are legal only AFTER a recognized verb** —
+ any remaining tokens after a recognized verb are passed through to the sub-skill unchanged (e.g.
+ `/audit style recent`, `/audit rules promote R1 R3`). An unrecognized first token always hits the
+ unknown-verb branch, exactly as before — passthrough never weakens the never-silently-guess rule.
| Input | Resolution |
|---|---|
| `/audit` (bare, no argument) | Present the **bare-menu** (Step 1) and wait for a pick. |
- | `/audit knowledge` | Delegate directly to `audit-knowledge` (Step 2). |
- | `/audit config` | Delegate directly to `audit-config` (Step 2). |
- | `/audit style` | Delegate directly to `audit-style` (Step 2). Style is **opt-in only** — see the note at the end of this section. |
- | `/audit usage` | Delegate directly to `audit-usage` (Step 2). Usage is **opt-in only** — same note as style. |
- | `/audit all` | Run all four sub-audits in sequence — knowledge → config → style → usage — each to completion, then print a combined one-line tally (Step 3). |
- | anything else (unrecognized verb) | **Unknown-verb branch** — do not guess or silently fall through. List the valid verbs and stop: *"'{verb}' is not a valid /audit sub-command. Valid verbs: knowledge, config, style, usage, all. Run bare `/audit` for a menu."* |
+ | `/audit knowledge [args…]` | Delegate to `audit-knowledge` with the args (Step 2). |
+ | `/audit config [args…]` | Delegate to `audit-config` with the args (Step 2). |
+ | `/audit style [args…]` | Delegate to `audit-style` with the args (Step 2). Style is **opt-in only** — see the note at the end of this section. |
+ | `/audit usage [args…]` | Delegate to `audit-usage` with the args (Step 2). Usage is **opt-in only** — same note as style. |
+ | `/audit rules [args…]` | Delegate to `audit-rules` with the args (Step 2) — e.g. `/audit rules promote R1 R3`. Rules is **opt-in only** — same note as style. |
+ | `/audit share [args…]` | Delegate to `audit-share` with the args (Step 2) — batch-review personal knowledge for promotion to the team-shared tier. Share is **opt-in only** — same note as style, and it additionally requires the shared-knowledge config (`projects_enabled` plus a non-empty `projects_shared_knowledge`). |
+ | anything else (unrecognized verb) | **Unknown-verb branch** — do not guess or silently fall through. List the valid verbs and stop: *"'{verb}' is not a valid /audit sub-command. Valid verbs: knowledge, config, style, usage, rules, share. Run bare `/audit` for a menu."* |
- **Style is opt-in, never routine.** `/audit style` only runs when explicitly selected — either the user types `/audit style` / `/audit all` directly, or picks "style" off the bare-menu in Step 1. It is never fired automatically by the SessionStart audit-cadence nudge the way `/audit-knowledge` and `/audit-config` can be — session-start cadence checks are a knowledge/config concern, not a style-mining concern, so `/audit style` stays a deliberate, explicit action every time.
+ **Style, usage, rules and share are opt-in, never routine.** They run only when explicitly
+ selected — the user types the `/audit <verb>` form directly, or picks it off the bare-menu in
+ Step 1. None of the four is ever fired automatically by the SessionStart audit-cadence nudge the
+ way `/audit knowledge` and `/audit config` can be — session-start cadence checks are a
+ knowledge/config concern; style-mining, usage reporting, rule-mining and cross-tier sharing stay
+ deliberate, explicit actions every time. Share carries the strongest form of this: it writes into
+ a team-shared and possibly public repo, so it is never anything but an explicit, per-item choice.
## Step 1: Bare `/audit` — Present the Menu
- When invoked with no argument, present the four options and wait for the user to pick one before doing anything else:
+ When invoked with no argument, present the options and wait for the user to pick one before doing anything else:
> **Which audit?**
> 1. `knowledge` — scan Claude memory and plans for extractable knowledge (backlog → promotion review)
> 2. `config` — check AGENTS.md files, plugin manifests, and knowledge docs for drift and staleness
> 3. `style` — mine session-log history for revealed working-style rules (opt-in — not part of routine cadence)
> 4. `usage` — value/ROI report for your own corpus (cost + quality + trends; opt-in — not routine cadence)
- > 5. `all` — run all four in sequence, then a combined tally
+ > 5. `rules` — mine your distilled corrections for promotable standing rules (opt-in — not routine cadence)
+ > 6. `share` — batch-review personal knowledge for promotion to the team-shared tier (opt-in; requires the shared-knowledge config)
Do not default to any one sub-audit and do not run anything before the user picks. A bare `/audit` with no reply is a no-op — exit cleanly, nothing was scanned.
## Step 2: Delegate to a Resolved Sub-Skill
- Once a verb is resolved (from Step 0's direct-invocation column or Step 1's menu pick), delegate to the matching sub-skill via the `Skill` tool, with no additional arguments — the sub-skill runs its own full step sequence (config resolution, cadence/mode determination, findings presentation, user review, promotion) exactly as it would under direct invocation:
+ Once a verb is resolved (from Step 0's direct-invocation column or Step 1's menu pick), delegate to the matching sub-skill via the `Skill` tool, **passing through any trailing arguments from the invocation** — the sub-skill runs its own full step sequence (config resolution, cadence/mode determination, findings presentation, user review, promotion) exactly as it would under direct invocation:
- - `knowledge` → Use the `Skill` tool to invoke `audit-knowledge`.
- - `config` → Use the `Skill` tool to invoke `audit-config`.
- - `style` → Use the `Skill` tool to invoke `audit-style`.
- - `usage` → Use the `Skill` tool to invoke `audit-usage`.
+ - `knowledge` → Use the `Skill` tool to invoke `audit-knowledge` (with any passthrough args).
+ - `config` → Use the `Skill` tool to invoke `audit-config` (with any passthrough args).
+ - `style` → Use the `Skill` tool to invoke `audit-style` (with any passthrough args).
+ - `usage` → Use the `Skill` tool to invoke `audit-usage` (with any passthrough args).
+ - `rules` → Use the `Skill` tool to invoke `audit-rules` (with any passthrough args).
+ - `share` → Use the `Skill` tool to invoke `audit-share` (with any passthrough args).
`/audit`'s job ends at the handoff — it does not re-implement, intercept, or post-process what the sub-skill does. Whatever the sub-skill reports (findings, promotions, "nothing new to extract") is the final output of that leg.
- ## Step 3: `/audit all` — Sequence + Tally
-
- `/audit all` runs the four sub-audits **in sequence, each to completion**, not in parallel and not short-circuited on an early empty result:
-
- 1. Use the `Skill` tool to invoke `audit-knowledge`. Let it run its full flow (including any user-review prompts) to completion.
- 2. Use the `Skill` tool to invoke `audit-config`. Let it run its full flow to completion.
- 3. Use the `Skill` tool to invoke `audit-style`. Let it run its full flow to completion.
- 4. Use the `Skill` tool to invoke `audit-usage`. Let it run its full flow to completion.
-
- After all four finish, print a combined one-line tally summarizing what each leg did, e.g.:
-
- > **Audit all — summary:** knowledge: 3 promoted, 1 rejected · config: 2 drift items flagged, 0 fixed · style: 1 rule candidate staged · usage: report written.
-
- If any leg errors or the user backs out mid-leg (e.g., declines a runtime-mismatch gate), note that leg as incomplete in the tally rather than silently omitting it, and continue to the next leg — one leg's early exit doesn't cancel the other two.
+ ## Canonical forms and compatibility
- ## Back-Compat: Direct Sub-Skill Invocation Still Works
+ **The `/audit <verb>` space forms are the canonical, advertised invocations for the whole family.**
+ Every doc, help table, and cadence nudge names them — the SessionStart audit-cadence nudge says
+ `/audit knowledge` and `/audit config`.
- `/audit` is an added convenience layer, not a replacement. `/audit-knowledge` and `/audit-config` remain **directly invocable** exactly as before — nothing about adding `/audit` changes their standalone triggers, and the SessionStart audit-cadence nudge continues to name them directly (`/audit-knowledge`, `/audit-config`) rather than routing through `/audit`. `/audit-style` and `/audit-usage` are likewise directly invocable. Use `/audit knowledge|config|style|usage` when you want the umbrella's menu/tally framing; use the bare `/audit-knowledge` / `/audit-config` / `/audit-style` / `/audit-usage` forms when you want that one audit with no dispatcher layer in between. Both paths land on the same sub-skill — this is a routing convenience, not a new code path.
+ **Compatibility aliases (never advertised):** `/audit-knowledge` · `/audit-config` · `/audit-style` · `/audit-usage` · `/audit-rules` — all still resolve.
+ The sub-skill files are this dispatcher's delegation targets and keep their names, but the
+ hyphenated forms are aliases, not separate behaviour, and are never advertised as the canonical
+ form (the same posture as the legacy `linear` spellings elsewhere in the family). Both paths land
+ on the same sub-skill.
## Rules
- - **Never silently guess a verb.** An unrecognized argument always hits the unknown-verb branch in Step 0 — list the valid verbs and stop.
- - **Never auto-run style or usage.** `/audit style` and `/audit usage` fire only on explicit selection (direct invocation or menu pick) — never as part of a cadence nudge or as part of resolving a bare `/audit` without a menu pick.
+ - **Never silently guess a verb.** An unrecognized first token always hits the unknown-verb branch in Step 0 — list the valid verbs and stop. Passthrough args exist only after a recognized verb.
+ - **Never auto-run style, usage, rules, or share.** They fire only on explicit selection (direct invocation or menu pick) — never as part of a cadence nudge or as part of resolving a bare `/audit` without a menu pick.
- **Never reimplement sub-audit logic here.** This skill's job is parse-and-delegate; all scanning, cadence math, and promotion logic lives in the sub-skill being delegated to.
- - **`/audit all` is sequential, not short-circuited.** Every leg runs to completion regardless of what the prior leg found, and every leg's outcome (including "declined" or "errored") shows up in the final tally.
+ - **There is no run-everything verb.** `all` was removed in v2.50.0: six sub-audits is past the point where a blind sequence is a sensible default, and four of the six are opt-in by design — a run-everything would have been firing them against their own stated posture.
---
## /audit-knowledge
- # /audit-knowledge — Knowledge Repository Audit
+ # /audit knowledge — Knowledge Repository Audit
+ Canonical invocation: **`/audit knowledge`**. The direct `/audit-knowledge` form is retained for compatibility and is not advertised.
+
Scan `~/.claude/` memory and plan files, compare against what's already in the knowledge folder and project-level docs, and surface anything worth extracting.
## Step 0: Resolve Config
Read `.cursor/aria-knowledge.local.md` and extract:
- `knowledge_folder` — required base path
- `audit_cadence_knowledge` — cadence in days (default 7); safety-net trigger for low-activity periods
- `audit_trigger_threshold` — backlog-entry count (default 20); primary activity-driven trigger. Tier boundaries derived via fixed offsets: `threshold` (suggested), `threshold + 15` (recommended), `threshold + 30` (overdue)
- `projects_enabled` — default `false`; controls whether project tier is audited (Step 5e)
- `projects_list` — default empty; comma-separated `tag:path` pairs; only relevant if `projects_enabled: true`
- `projects_promotion_threshold` — default `2`; minimum projects sharing a similar pattern before Step 5e suggests cross-project promotion
If the config file doesn't exist, stop: "aria-knowledge is not configured. Run /setup to get started."
Use `{knowledge_folder}` as the base path for all file operations in subsequent steps.
## Step 1: Read the Audit Log and Determine Mode
Read `{knowledge_folder}/logs/knowledge-audit-log.md`.
Note the "Last Audit" date and calculate days since.
**Compute the current trigger state** by counting `^### ` entries across the four action-eligible backlogs (insights, decisions, extraction, rules — exclude `intake/ideas/`, which routes out via the Accept submenu rather than promoting directly). Count only entries **below the first `---` separator** per file, matching the convention used by `/stats` and `/backlog`:
```bash
for f in {knowledge_folder}/intake/insights-backlog.md \
{knowledge_folder}/intake/decisions-backlog.md \
{knowledge_folder}/intake/extraction-backlog.md \
{knowledge_folder}/intake/rules-backlog.md; do
[ -f "$f" ] && awk '/^---$/{sep++; next} sep>=1 && /^### /{c++} END{print c+0}' "$f"
done | awk '{s+=$1} END{print s+0}'
```
Record the count — it feeds both the prompt message and Step 8's `Trigger:` audit-log subfield.
**Determine how this skill was invoked:**
- - **User-requested** (user said `/audit-knowledge`, "audit knowledge", "scan memory", etc.): **Always run the full audit**, regardless of how recently the last audit was. Skip directly to Step 2.
+ - **User-requested** (user said `/audit knowledge`, "audit knowledge", "scan memory", etc.): **Always run the full audit**, regardless of how recently the last audit was. Skip directly to Step 2.
- **Session-start check** (triggered by the SessionStart hook): Check whether either trigger fired.
- **Entry-count trigger** (primary): if `backlog_count >= audit_trigger_threshold`, prompt per tier:
- - `count ≥ threshold + 30` → *"Knowledge audit overdue — N entries, plan for multi-pass. Run /audit-knowledge?"*
- - `count ≥ threshold + 15` → *"Knowledge audit recommended — N entries, near one-pass ceiling. Run /audit-knowledge?"*
- - `count ≥ threshold` → *"Knowledge audit suggested — N entries ready for review. Run /audit-knowledge?"*
- - **Elapsed-days trigger** (safety net): if no entry-count tier fired AND `days_since >= audit_cadence_knowledge`, prompt: *"Knowledge audit due — N days since last audit. Run /audit-knowledge?"*
+ - `count ≥ threshold + 30` → *"Knowledge audit overdue — N entries, plan for multi-pass. Run /audit knowledge?"*
+ - `count ≥ threshold + 15` → *"Knowledge audit recommended — N entries, near one-pass ceiling. Run /audit knowledge?"*
+ - `count ≥ threshold` → *"Knowledge audit suggested — N entries ready for review. Run /audit knowledge?"*
+ - **Elapsed-days trigger** (safety net): if no entry-count tier fired AND `days_since >= audit_cadence_knowledge`, prompt: *"Knowledge audit due — N days since last audit. Run /audit knowledge?"*
- **Neither fired**: report the last audit date + current backlog count + days-since, then stop. *"Last knowledge audit was N day(s) ago (YYYY-MM-DD). Backlog at M entries (threshold T). Next trigger at M=T entries or N=C days."*
## Step 1b: Check Index Freshness
Read `{knowledge_folder}/index.md` if it exists.
Several audit steps depend on index data (Step 5b entity refs + skill-knowledge drift, Step 5c tag matching, Step 6 stale files). Running against a stale or missing index produces incomplete results.
**Check:**
1. If `index.md` doesn't exist → note: "No index found. Steps 5b (entity/skill checks), 5c (tag matching), and stale file detection will be limited. Consider running `/index` after this audit."
2. If `index.md` exists → read the `Last rebuilt:` date from the header. Compare against today.
- If **older than 7 days** AND there are pending backlog entries (from a quick line count of the 3 backlog files) → prompt: *"Index was last rebuilt N days ago and there are pending backlog items. Run `/index` first for more accurate integrity checks? (y/n)"*
- If user says yes → run the full `/index` logic (Steps 0-10 from the /index skill), then continue with Step 2
- If user says no → continue with degraded checks (note in Step 6 output which checks were limited)
- If **7 days or fewer** → continue normally, index is fresh enough
This is a lightweight check — it reads one file header and counts backlog lines. The expensive work (full index rebuild) only happens if the user opts in.
## Step 2: Review Insights Backlog
Read `{knowledge_folder}/intake/insights-backlog.md`. **If the file is missing**, report it in Step 6 and suggest running `/setup` to repair the structure. Do not create it.
If there are entries below the `---` separator, these are insights captured during work sessions that need review.
For each insight entry, note it for presentation in Step 6 alongside Category C items. Insights are reviewed with the same approve/reject flow — promoted ones go to the appropriate knowledge file, rejected ones get cleared from the backlog.
## Step 2b: Review Decisions Backlog
Read `{knowledge_folder}/intake/decisions-backlog.md`. **If the file is missing**, report it in Step 6 and suggest running `/setup` to repair the structure. Do not create it.
If there are entries below the `---` separator, these are cross-project architectural decisions captured during work sessions that need review.
For each decision entry, note it for presentation in Step 6. Decisions are reviewed with the same approve/reject flow — promoted ones become full ADRs in `{knowledge_folder}/decisions/` (using ADR format), rejected ones get cleared from the backlog.
## Step 2c: Review Extraction Backlog
Read `{knowledge_folder}/intake/extraction-backlog.md`. **If the file is missing**, report it in Step 6 and suggest running `/setup` to repair the structure. Do not create it.
If there are entries below the `---` separator, these are feedback, project context, and reference items captured via `/extract` during work sessions.
For each entry, note it for presentation in Step 6. Feedback items are promoted to `~/.claude/projects/` memory as feedback memories. Project context items become project memories. Reference items become reference memories or go to `{knowledge_folder}/references/`. Rejected items get cleared from the backlog.
**Reclassification check:** If any entry reads as a feature proposal, bug report, or design idea (rather than an observation about what IS), flag it for re-routing to `intake/ideas/` (as a new per-file idea) during Step 7. Common signals: "should", "could be better if", "missing handling for", "UX gap", "would help if". Misclassified proposals will otherwise get promoted into knowledge files where they sit as documentation of things that don't exist — a known drift mode.
## Step 2c2: Review Ideas Directory
Glob `{knowledge_folder}/intake/ideas/*.md`. **If the directory is missing**, report it in Step 6 and suggest running `/setup` to repair the structure. Do not create it.
**Counting note:** When reporting an idea count (Step 6's `Pending Ideas (N)` header and Step 8's `Plus N ideas` audit-log subfield), filter out `README.md` and `.gitkeep` from the glob result — they're directory-purpose files, not ideas, and inflate counts by 1-2 if included. The reads-and-categorize step below is unaffected since non-idea files lack the required `date:`/`project:`/`type:`/`title:` frontmatter and are skipped during per-file review. Concrete primitive: `ls intake/ideas/*.md 2>/dev/null | grep -v 'README\|\.gitkeep' | wc -l`.
**Legacy-file detection (one-time):** Also check for `{knowledge_folder}/intake/ideas-backlog.md`. If it exists alongside `intake/ideas/`, surface a finding in Step 6 under a "Legacy Ideas Backlog" note: *"Pre-2.11 `ideas-backlog.md` detected. Run `bash scripts/aria/migrate-ideas-backlog.sh {knowledge_folder}` or re-run `/setup` to migrate entries into per-file format."* Do not attempt the migration from within the audit flow.
For each `*.md` file in `intake/ideas/`: read the file (frontmatter + body). Each file is one idea — feature proposal, bug report, or design idea captured via `/extract`. Ideas have a **distinct disposition** from other backlogs — they do NOT promote to knowledge files directly. Present them in their own section in Step 6 with the options:
- **Accept** — pick a destination from the submenu below. After the user approves, run the **verify-no-loss check** (below). Idea file then moves either to its destination (full-body preservation) or to `{knowledge_folder}/archive/audit-{date}/` (summary-only destinations — body preserved in archive with `demoted-to: {destination}` frontmatter)
- **Reject** — idea file moves to `{knowledge_folder}/archive/audit-{date}/` with `dismissal-reason: {one-line}` frontmatter
- **Defer** — file stays in place for the next audit cycle (no-op)
- **Reclassify** — if on review the item is actually an observation, append its content to the appropriate knowledge backlog (insights/decisions/extraction) for normal promotion, then move the idea file to `{knowledge_folder}/archive/audit-{date}/` with `reclassified-to: {backlog#section}` frontmatter
**Never delete (v2.15.1+):** Idea files are NEVER `rm`'d. Every disposition that previously deleted now moves the file — to its destination (full-body preservation) or to `archive/audit-{date}/` (with a frontmatter pointer explaining why). Rule 6 ("Don't delete — archive") is preserved without relying on git history; archive-on-disk is the canonical surface, making non-git knowledge folders first-class.
**User override (explicit, v2.15.2+):** If the user explicitly approves or asks for a deletion (phrases like *"delete without archiving"*, *"really delete this"*, *"skip the archive for this one"*), the destructive operation is permitted. The default safety floor remains archive; the override exists for cases where the user has explicit reason to skip preservation (e.g., accidentally captured sensitive content, archive-growth aversion). **Before honoring an override, surface what would have been archived** — name the file(s) and the substance about to be lost — and confirm. User-approved deletes are then honored as one-off; the override does not flip the default for subsequent files in the same audit.
### Verify-no-loss check (Accept disposition)
Before the idea file moves to its Accept destination, verify the destination preserves the idea's substantive content. This protects against the silent-summarization-then-delete failure mode (where a destination's 1-line entry replaces a multi-paragraph body).
1. **Inventory original substance**: identify which of {Why, Motivation, Implementation sketches, Source} sections exist in the idea file (frontmatter + body).
2. **Inventory destination coverage**: read the planned destination entry — does it carry text covering each substantive section present in the source?
3. **Three outcomes per idea**:
- **Full coverage** → idea file `mv`'s to the destination as a standalone file (new ADR / approach / reference / plan / project decisions/patterns/), OR is fully expanded as a multi-paragraph entry in the destination (backlog/roadmap entries that carry the full Why/Motivation/Implementation paragraphs, not just a 1-liner). Original idea file gone from `intake/ideas/`; substance lives at destination.
- **Insufficient coverage** (typical for summary-style destinations: 1-line ROADMAP bullets, TODO entries, tracker summaries) → idea file `mv`'s to `archive/audit-{date}/{filename}` with `demoted-to: {destination#section}` frontmatter. The destination still receives its summary entry; the archive preserves the body.
- **Partial coverage** → surface to user: "Substantive sections X, Y from the original would be missing at {destination}. Choose: (a) expand destination to include them, (b) archive original alongside, (c) accept the compression as a knowing demotion." Default recommendation: (b) for backlog-style destinations, (a) for promotion-style destinations.
Edits/revisions during move are expected and welcome — the rule is *no useful substantive content is lost*, not *body is byte-identical to source*. Reformatting, condensing redundant phrasing, fixing grammar, recontextualizing for the destination format are all fine. The verification gate catches *loss*, not change.
**Accept submenu** — destinations:
| Destination | What happens | Detection / availability |
|-------------|--------------|--------------------------|
| `tracker` | User copies to external tracker (Linear / GitHub Issues / Jira / etc.). If `ticketing_plugins` config maps the idea's `project` tag to a plugin command, also print a one-line hint (e.g., *"Use `/foo-ticket` to draft this"*). Hint only — never auto-invoke. | always available |
| `roadmap` | Append idea body as a new entry to project-root `ROADMAP.md` (or `docs/ROADMAP.md`). Entry includes date prefix + Proposal/Motivation. | only if `ROADMAP.md` exists at project root or under `docs/` |
| `todo` | Append a single-line entry to project-root `TODO.md` (or `docs/TODO.md`). Format: `- [YYYY-MM-DD] {title} — {one-line proposal}`. | only if `TODO.md` exists at project root or under `docs/` |
| `adr` | Copy idea body into `intake/decisions-backlog.md` as a new `### YYYY-MM-DD — {title}` entry below the `---` separator. Reviewed as a decision in next audit. | always available |
| `backlog` | Append idea body to `IDEAS-BACKLOG.md` as a new `### YYYY-MM-DD — {title}` entry with Proposal/Motivation/Source. **Location depends on whether the idea's project tag appears in `projects_shared_knowledge`:** if NOT in the list (or list empty), write to `<project-root>/IDEAS-BACKLOG.md`; if IN the list, write to `<project-root>/_project-knowledge/IDEAS-BACKLOG.md` (team-visible, per `projects_list` resolution; see "Project-root detection" below). The user controls whether the project-root path is a parent container or a specific code repo via their `projects_list` config (e.g., `proj-a:proj-a` resolves the tag directly; `proj-b:path/to/proj-b` resolves to a parent of the code repo). Create the file with a header if it doesn't exist. | always available |
| `bundle` | Merge 2+ related ideas into a single file, then sub-prompt for one of the destinations above. After the merged file lands, source idea files all move to `archive/audit-{date}/` with `bundled-into: {merged-file-path}` frontmatter (bundle-merge typically compresses each source — archive preserves the originals for substance recovery). The verify-no-loss check runs against the *merged* file's destination, not the per-source individually. | offered when audit detects clusters (see "Bundle clustering" below) |
| `rule` | Append idea body to `intake/rules-backlog.md` as a new `### YYYY-MM-DD — {title}` entry. Reviewed during next audit alongside other rule candidates; promoted entries land in user memory as `feedback_*.md` records or in a project-local `working-rules.md`. | always available |
**Project-root detection:** for `roadmap`, `todo`, and `backlog` paths, the audit needs to resolve the idea's `project` tag to a filesystem path before probing for files. Resolution rules (in priority order):
1. **Tag in `projects_list`** — if `projects_enabled: true` AND the idea's `project` tag matches a `tag:path` pair in `projects_list`, resolve to that path. Paths in `projects_list` are relative to the parent directory of the knowledge folder (typically `~/Projects/`); the audit converts to absolute by prepending that parent.
2. **CWD fallback** — if the tag isn't resolvable via `projects_list` (projects tier disabled, tag missing from list, or idea's `project` is `cross` / `no-project`), fall back to the current working directory. Probe the closest ancestor of CWD containing either `.git/` or `CLAUDE.md`.
3. **No resolution possible** — if neither path strategy yields a valid directory (e.g., projects tier disabled AND CWD has no git/CLAUDE.md ancestor), omit `roadmap`, `todo`, and `backlog` from the submenu and append a one-line note to that idea's audit entry: *"roadmap/todo/backlog not offered: project path unresolved (project tag not in projects_list, no .git/ or CLAUDE.md ancestor of CWD)."* This makes the gap visible rather than silently shrinking the submenu.
Once the project root is resolved, probe for the relevant file in two locations in this order: (1) project root, (2) `docs/` subdirectory of the project root. **Tie-break when both exist:** route to the project root copy; the `docs/` copy is treated as secondary and not modified. Document the chosen path in the audit log entry so users can trace where each idea landed.
**Ticketing plugin lookup:** read `ticketing_plugins` from `.cursor/aria-knowledge.local.md` (format: comma-separated `tag:plugin-command` pairs, e.g., `proj-a:foo-ticket,proj-b:bar-ticket`). If the idea's `project` matches a mapped tag, append a hint line under the tracker option: *"Use `/{plugin-command}` to draft this as a ticket."* Never invoke the other plugin's skill from inside this audit — the hint is informational; the user invokes manually.
**No installed-plugin probe.** The audit does **not** verify that `{plugin-command}` is actually installed on the user's system before printing the hint. This is intentional: enumerating installed plugins from inside a skill couples ARIA to Claude Code internals that could change. If the user has `ticketing_plugins: cs:foo-ticket` set but `/foo-ticket` is uninstalled, the hint still prints; the user discovers via "command not found" on invocation. Loud-fail at invocation is preferred over a silent absent hint.
**Bundle clustering** — auto-detected at audit time. Group pending idea files where:
1. `project` frontmatter matches across 2+ files, AND
2. Titles share ≥2 significant words after tokenization (see below).
**Tokenization rules** (applied to the `title:` frontmatter field — fall back to the slug portion of the filename if `title:` is missing):
- Split on whitespace AND on hyphens (kebab-case + spaces both produce tokens).
- Lowercase all tokens.
- Strip leading/trailing ASCII punctuation from each token.
- A token is **significant** if its length ≥ 3 chars AND it is not in the stop-words list: a, an, and, the, to, for, of, in, on, with, from, by, is, be, or, but, not, no, do, did, has, had, will, can.
- Word match is exact (case-insensitive after normalization). No stemming, no fuzzy matching — keeps clustering deterministic across audit runs.
**Lead entry of a cluster:** the oldest idea by the `date:` frontmatter field; if `date:` is missing or malformed, fall back to the `YYYY-MM-DD` filename prefix. Tie-break: alphabetical by full filename. The lead entry is where the audit surfaces the `bundle` option in Step 6; the other cluster members reference back to the lead.
For each detected cluster, surface a `bundle` option once in the cluster's lead entry in Step 6 (with a list of cluster members). The user chooses bundle (then picks merged-file destination + writes a one-line cluster summary) OR disposes each idea individually.
**Bundle sub-prompt destinations:** when a bundle is accepted, the sub-prompt offers `tracker | roadmap | todo | adr | backlog` (the same conditional availability rules as a single idea's submenu). **Excluded from bundle sub-prompts:** `bundle` (would recurse) and `rule` (rule candidates are intentionally one-rule-per-entry — bundling rule candidates obscures their individual review under audit Step 2c3, which expects one rule per `### YYYY-MM-DD — {title}` block).
The archive folder `{knowledge_folder}/archive/audit-{date}/` is the canonical preservation surface for any idea file whose disposition was Reject, Reclassify, Bundle, or Accept-with-insufficient-coverage. Git tracking is no longer assumed — first-class support for non-git knowledge folders. Each archived file gains frontmatter (`dismissal-reason`, `reclassified-to`, `bundled-into`, or `demoted-to`) explaining why it was archived and where its substance lives (if anywhere). After all Step 2c2 dispositions resolve, write a per-audit `{knowledge_folder}/archive/audit-{date}/MANIFEST.md` capturing the cohort:
```yaml
---
audit_date: YYYY-MM-DD
audit_pass: <pass number from audit log>
ideas_touched: N
moved_to_destination: N (full-body preservation; see per-idea audit log entries for destinations)
archived: N
- dismissal (rejected): N
- reclassified-to-backlog: N
- bundled: N
- demoted-to-summary-destination: N
---
```
Followed by a per-archived-file list with the originating idea filename + frontmatter pointer. The MANIFEST is the human-readable counterpart to the audit log; the audit log records dispositions, the MANIFEST records the archive's contents.
**Prior versions (pre-v2.15.1)** assumed `git log --all -- intake/ideas/` would recover deleted bodies. That assumption silently failed for any idea file created since the last git commit (untracked file → working-tree delete → no history). v2.15.1 archives unconditionally; never delete is the new safety floor.
Ideas never promote to `approaches/`, `decisions/`, or `rules/` directly via Accept — those land in their respective backlogs (`adr` → `decisions-backlog.md`, `rule` → `rules-backlog.md`) for normal audit-cycle review. The audit report for ideas presents the submenu inline; routing is a user action invoked by their disposition choice.
**Age annotation and stale marker:** For each idea file, compute age as `(today - idea date)` in days. Derive the idea date as follows: (1) read `date:` from YAML frontmatter; (2) if missing or malformed, fall back to the `YYYY-MM-DD` prefix of the filename. Annotate each entry with its age (`filed N days ago`). Read the staleness threshold from `.cursor/aria-knowledge.local.md` (`ideas_staleness_threshold_days`, default 7) via `config.sh` or fallback. When `age > threshold`, append a `[STALE — still relevant?]` marker to the entry and escalate its visual weight in Step 6 (place stale entries first within the Pending Ideas section, and prompt explicitly for Accept/Reject/Defer rather than allowing implicit Defer).
This is the audit's mechanism for forcing action on long-sitting ideas. Without staleness surfacing, items accumulate silently; with it, every audit cycle either confirms an idea still matters or retires it.
## Step 2c3: Review Rules Backlog
Read `{knowledge_folder}/intake/rules-backlog.md`. **If the file is missing**, report it in Step 6 and suggest running `/setup` to repair the structure. Do not create it.
If there are entries below the `---` separator, these are rule candidates — observations or proposals about *how to work* (rather than *what is*) — staged via the `Accept → rule` path on prior idea audits, or appended directly when feedback in conversation matches a "rule of thumb" shape.
For each entry, note it for presentation in Step 6 alongside other backlogs. Rule candidates have three valid promotion targets, all inside the user memory directory or `{knowledge_folder}` (ARIA never writes to project source):
- **User memory `feedback_*.md`** — for personal/working-style rules that span projects (matches the existing feedback-memory pattern under the active project's `~/.claude/projects/{cwd-encoded}/memory/` directory)
- **Cross-project `{knowledge_folder}/rules/user-rules.md`** — for ARIA-behavior rules that should apply consistently across all the user's work (the user-owned counterpart to plugin-managed `working-rules.md`)
- **Project-tier `{knowledge_folder}/projects/{tag}/rules/working-rules.md`** — only when `projects_enabled: true` and the entry's `project` tag matches `projects_list`; for project-scoped discipline that doesn't generalize cross-project. Setup's Step 7c scaffolds the parent `rules/` subdirectory so this destination is always available when the projects tier is on.
Rejected entries get cleared from the backlog. All three promotion targets are reviewed at user approval time in Step 7 — do not auto-promote.
**Reclassification check:** if any entry reads as a feature proposal or bug report (rather than a "how to work" rule), flag it for re-routing to `intake/ideas/` during Step 7. Common signals indicating misclassification: "should add", "should fix", "would be nice if X existed". Rules describe behavior; ideas describe missing features.
## Step 2d: Review Task-Boundary Captures (Cursor port)
Scan `{knowledge_folder}/intake/task-boundary-captures/` for `.md` files. **If the directory doesn't exist or is empty**, skip silently to Step 2e.
**If captures exist**, report the count and total size, then ask the user:
> "Found N task-boundary capture(s) (total ~X KB) from Cursor `stop` hook or `/snapshot`. These are structural snapshots (git + hook state) — **not transcripts**. Options:"
> 1. **Skim** — read filenames + timestamps for forensic context (default)
> 2. **Detailed** — read full capture bodies (~1-5K tokens each)
> 3. **Skip** — leave for a future audit
> 4. **Clear** — move to `{knowledge_folder}/archive/audit-{date}/task-boundary-captures/` with a brief REMOVED.md ledger, then delete from intake
Do **not** run `digest-transcript.sh` on these files — they are not conversation transcripts.
For each reviewed capture, note findings for Step 6 under a "Task-Boundary Captures" section. Approved structural notes may append to `extraction-backlog.md` if they contain actionable project context; otherwise treat as informational only.
## Step 2e: Review Subagent Captures
Scan `{knowledge_folder}/intake/subagent-captures/` for `.md` files. **If the directory doesn't exist or is empty**, skip silently to Step 3.
**If captures exist**, report the count and total size, then ask the user:
> "Found N subagent transcript capture(s) (total ~X KB) archived from heavyweight subagents. A subagent cannot extract its own session, so these are held until reviewed. Options:"
> 1. **Digest** — extract high-signal content via script, then review (~1-3K tokens per capture; default)
> 2. **Detailed** — read full transcripts for exhaustive review (~30-50K tokens per capture)
> 3. **Skip** — leave for the next audit
There is **no bare-Clear option** for subagent captures. Unlike task-boundary captures (derived copies of Claude Code's canonical session `.jsonl`), a subagent capture is held under **sticky retention** — its body is only removed *after* its knowledge is folded into a backlog, because the subagent's source transcript is not assumed to persist.
**Digest mode (default):** for each capture, run:
```
bash scripts/aria/digest-transcript.sh "{capture_path}" "/tmp/aria-digest-{filename}"
```
Then read the digest (not the raw transcript). Extract findings into the standard six buckets (insights, decisions, feedback, project context, references, ideas) — same categorization as `/extract`.
**Detailed mode:** read the full capture directly. Use sparingly (a single capture can consume 30-50K+ tokens).
**Re-verify against HEAD before presenting any finding as live (REQUIRED)** — the same gate as Step 2d item 4, and it bites harder here: adversarial `/prospect` and `/retrospect` subagents exist precisely to find defects, so their captures are dense with present-tense claims, and the parent session very often fixed them immediately. Mark each finding **STILL LIVE (verified at HEAD)** or **ALREADY FIXED (closed by `<sha>`)** before Step 6.
For each reviewed capture:
- **Approved items** → append to the appropriate backlog (`insights-backlog.md`, `decisions-backlog.md`, or `extraction-backlog.md`), then apply the **ledger-clear pattern**: create `{knowledge_folder}/archive/audit-{date}/subagent-captures/` if needed, append an entry to its `REMOVED.md` (filename + parent-session-id + agent_type + agent_id + capture-timestamp), then `rm` the capture `.md`.
- **Rejected items** → ledger-clear with `disposition: rejected` and a one-line reason.
- **Skip** → leave the capture for the next audit.
Note findings for presentation in Step 6 under a "Subagent Captures" section.
## Step 2f: Review Clippings
Scan `{knowledge_folder}/references/sources/` for `.md` files **and image files** (`.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`). **If the directory doesn't exist or is empty**, skip silently to Step 3.
**If clippings exist**, report the count and total size — broken out as markdown vs images (e.g., "N clipping(s): M markdown, K images") — then ask the user:
> "Found N clipping(s) (total ~X KB) — saved URLs / snippets / threads (captured via `/intake` or dropped into the folder by hand), plus K image(s). Options:"
> 1. **Graduate** (default) — preserve each clipping whole as a durable source in `references/sources/` AND mine it for knowledge
> 2. **Skip** — leave for the next audit
**Image cost guard:** if there are **more than 5 images**, warn that each is a non-trivial vision read and offer **review all / review first N / defer the rest to next audit** before processing. (≤5: process inline.)
Under **Graduate**, for each clipping:
1. **Derive tags.** Propose tags from the clipping's content, matched against the existing tag vocabulary in `index.md` (mirror `/index`'s tagging). If the clipping already carries `/intake` frontmatter `tags:`, carry them over. **Show the proposed tags for confirm/edit** before writing.
2. **Preserve the source.** Ensure the clipping has `Last updated:` + the confirmed `tags:` frontmatter, then move the whole file to `{knowledge_folder}/references/sources/{filename}.md` (create `references/sources/` if absent). **Move rule:** use `git mv` only when the specific file is git-tracked — check with `git ls-files --error-unmatch "{path}"`; if it's untracked (even inside a git repo), use plain `mv` (a bare `git mv` fails on untracked files and would silently leave the clipping behind). This applies to image assets too.
3. **Mine all six buckets** (insights, decisions, feedback, project context, references, ideas) — same scan as `/extract`. Append findings to the appropriate backlog (`insights-backlog.md` / `decisions-backlog.md` / `extraction-backlog.md`) and route ideas to `intake/ideas/`. Reference-type fragments become curated notes destined for **top-level** `references/` (a distinct tier from the raw source now in `references/sources/`). Because the whole source is preserved in `references/sources/`, dedup any reference fragment against it before promoting — promote a fragment only when it is a distinct, smaller, independently-useful note, not a restatement of the source.
4. **Ledger as graduated.** Create `{knowledge_folder}/archive/audit-{date}/clippings/` if needed; append an entry to its `REMOVED.md`: filename + source + clip-date + `disposition: graduated` + destination `references/sources/{filename}.md`.
5. **No minable content:** the source STILL graduates to `references/sources/` (archival value). Ledger note `disposition: graduated (source only, no fragments mined)`.
**Image clippings (`.png`/`.jpg`/`.jpeg`/`.gif`/`.webp`)** take an image sub-flow instead of the markdown mine path above:
1. **Vision-read** the image via the Read tool (model-native; no OCR/script dependency). If the image is unreadable/corrupt, skip it with a one-line note in the Step 6 report and leave it in `clippings/` (don't graduate a file you couldn't open).
2. **Transcribe** the content to text — a faithful rendering of the visual (nodes + edges for a diagram, on-screen text for a screenshot, series/values for a chart), not just a caption. If content is ambiguous, transcribe what's legible and flag the uncertainty in the transcription body.
3. **Derive + confirm tags** (same as markdown step 1).
4. **Tier decision (per image):** ask whether the transcription is a **faithful-twin** of the image (→ write it to `references/sources/{name}.md`, beside the asset) or **distilled knowledge** that stands alone (→ write it to top-level `references/{name}.md`). Suggest a default — twin if it largely restates an existing synthesis, distilled if it stands alone — and let the user confirm.
5. **Graduate the asset:** move the image to `references/sources/{filename}` (see the tracked-file move rule in markdown step 2).
6. **Mine** the transcribed text into the six buckets exactly as a markdown source; dedup reference fragments against any existing synthesis (cross-link, never duplicate).
7. **Ledger** in `archive/audit-{date}/clippings/REMOVED.md`: `{image} | disposition: graduated (image; transcribed → {transcription-path}) | dest: references/sources/{image}`.
8. **No minable content** (decorative/illustrative): the asset still graduates; ledger `graduated (image, source only)`; still write a minimal caption/transcription so the asset is findable.
There is no discard-the-source path: every processed clipping graduates. "Skip" defers an uncertain clipping to the next audit.
Note findings for presentation in Step 6 under a "Clippings" section (report each as `graduated → references/sources/{filename}` plus any mined items).
## Step 3: Scan Memory Files
Read all `.md` files in `~/.claude/projects/` memory directories for the current project (excluding `MEMORY.md` itself).
Issue Read calls for all matching files in a single parallel tool-use block. A/B/C categorization runs in the main thread after all reads complete — do not categorize file-by-file serially.
**If the directory does not exist or contains no `.md` files:** report "No memory files found for the current project" in the Step 6 summary and skip to Step 4. Do not silently omit this section.
For each file, categorize:
- **(A) Already captured** — content is already in AGENTS.md files, `{knowledge_folder}/`, or project docs
- **(B) Claude-implementation-specific** — operational details about Claude sessions, plans, or tooling that don't contain reusable knowledge
- **(C) Worth extracting** — contains validated approaches, non-obvious patterns, or cross-project knowledge not yet captured
## Step 4: Scan Plan Files
Read all files in `~/.claude/plans/`.
Issue Read calls for all plan files in a single parallel tool-use block. Categorization runs in the main thread after reads complete.
**If the directory does not exist or contains no files:** report "No plan files found" in the Step 6 summary and skip to Step 5. Do not silently omit this section.
Apply the same A/B/C categorization. Most plans are Category B (implementation-specific). Look specifically for:
- Validated approaches or patterns that could go in `{knowledge_folder}/approaches/`
- Cross-project decisions that could go in `{knowledge_folder}/decisions/`
- Rules or principles validated through experience that could go in `{knowledge_folder}/rules/`
- Operational knowledge (tool setup, architecture, onboarding) that could go in `{knowledge_folder}/guides/`
## Step 5: Cross-Reference with Knowledge Repository
Read the existing knowledge files to avoid duplicates:
Expand the glob patterns first (via Glob), then issue Read calls for all resolved files in a single parallel tool-use block. These file contents feed Steps 5b (integrity lint) and 5c (cross-reference) — do not re-read in those steps.
```
{knowledge_folder}/README.md
{knowledge_folder}/rules/*.md
{knowledge_folder}/approaches/*.md
{knowledge_folder}/decisions/*.md
{knowledge_folder}/guides/**/*.md
{knowledge_folder}/references/*.md
```
Also check project-level CLAUDE.md and docs files in the current working directory for already-captured knowledge.
## Step 5b: Lint Knowledge Integrity
Using the knowledge files already read in Step 5 (do not re-read), scan for internal problems across the existing knowledge base. This is not about what's missing — it's about what's broken or disconnected in what we already have.
Check for:
- **Contradictions** — rules, approaches, or decisions that conflict with each other (e.g., a rule says "always X" but an approach says "avoid X in this context" without acknowledging the rule)
- **Stale references** — file paths, rule numbers, tool names, or class names mentioned in knowledge files that no longer exist in the codebase or knowledge repo. Verify by checking the filesystem — don't rely on memory.
- **Superseded content** — decisions in `decisions/` or the decisions backlog that modify or override an existing approach or rule, but the approach/rule hasn't been updated to reflect this
- **Missing connections** — files that discuss the same concepts, patterns, or components but don't reference each other (e.g., an approach that implements a rule but doesn't cite it, or two decisions about the same system with no cross-link)
- **Stale entity references** — if `index.md` has an `## Entities` section, check that listed files still exist and still mention the entity. Flag any entries pointing to archived, renamed, or deleted files.
- **Missing entities** — scan promoted files for named tools, services, or frameworks that appear in 2+ files but are not listed in the entity index. These should be picked up by the next `/index` run, but flagging them during audit ensures awareness.
- **Skill-knowledge drift** — if `index.md` has a `## Skill Connections` section, check each connection for staleness. For each row in the table: (1) Get the skill file's modification date via `stat` or `ls -l` on `${CLAUDE_PLUGIN_ROOT}/skills/{skill_name}/SKILL.md`. (2) Get the knowledge file's `Last updated` date from its YAML frontmatter. (3) If the skill file is newer than the knowledge file, flag as potential drift — the skill may have evolved past what the knowledge doc describes. Also scan the knowledge file content for terms that may be stale relative to the skill (e.g., old names, deprecated patterns). If no `## Skill Connections` section exists in the index, skip this check silently — it means `/index` hasn't been run with Step 8c yet.
**Scope:** Only check files in `{knowledge_folder}/rules/`, `{knowledge_folder}/approaches/`, `{knowledge_folder}/decisions/`, `{knowledge_folder}/guides/`, and `{knowledge_folder}/references/`. Do not lint backlogs, logs, or templates.
**Threshold:** Only flag issues where the inconsistency is clear and actionable. "This rule could be interpreted as conflicting" is not a finding. "Rule 14 says max 3 abstraction layers; approach X recommends 5 without addressing why" IS a finding.
Note all findings for presentation in Step 6 under the new "Integrity Issues" section.
## Step 5b3: Check Cross-Skill Shared-Block Drift
Some skills inline shared logic (e.g., the group-loader block shared between `/distill` and `/stitch`). Drift between inlined copies is a latent bug — users would see different behavior in each skill.
1. Grep all files under `${CLAUDE_PLUGIN_ROOT}/skills/**/SKILL.md` for `<!-- shared-block: NAME -->` markers.
2. For each unique block `NAME`, collect the content between `<!-- shared-block: NAME -->` and `<!-- /shared-block: NAME -->` in every skill that contains it.
3. Normalize whitespace (collapse multiple spaces and blank lines to single).
4. If collected contents differ across skills for the same block name, flag as drift.
Note findings for presentation in Step 6 under a "Shared-Block Drift" section.
**Do not auto-fix drift** — only surface the finding. The resolution is a deliberate choice: update one skill to match the other, or intentionally diverge (in which case rename the block in one skill — e.g., `group-loader-distill` — so it no longer shares the name with the other).
## Step 5c: Cross-Reference Backlog Against Promoted Docs
For each pending backlog entry (from Steps 2, 2b, 2c), check whether it overlaps with existing promoted knowledge files.
**How to match:**
1. If `{knowledge_folder}/index.md` exists, read it and use the tag index for matching. Extract keywords from the backlog entry and check if any match tags in the index.
2. If no index exists, fall back to keyword matching: scan headings and first paragraphs of files in `approaches/`, `decisions/`, `guides/`, `references/` for overlapping terms.
**Two types of overlap to detect:**
**Topic overlap** — the backlog entry covers a topic that already has a promoted doc:
- A backlog insight about pagination when `approaches/api-pagination.md` exists
- Flag: "This insight may relate to existing doc `approaches/api-pagination.md` — update existing rather than create new?"
**Potential invalidation** — the backlog entry describes a change that may affect existing promoted docs:
- A clipping about a new Stripe API version when `references/stripe-webhook-patterns.md` exists
- A decision that reverses or modifies an existing approach
- Flag: "New entry about [topic] — existing `[file]` may need review or update."
Note all cross-references for presentation in Step 6. These inform the user's promotion decisions — they're not blockers.
## Step 5d: Check Codemap Staleness
Scan the current working directory for CODEMAP.md files:
```
Glob for **/CODEMAP.md in the project root
```
For each CODEMAP.md found:
1. **Read the header only** (first ~10 lines) to extract the `Last updated:` date
2. **Calculate age** in days since last update
3. **Check for codebase changes** — run `git log --name-only --since="{last_updated}" --pretty=format:"" -- {project_path}` to count files changed since the codemap was last updated
4. **Read the Build Log** (last ~30 lines) to check per-section update dates
**Staleness criteria:**
- **Stale** if more than 30 days since last update AND the codebase has changed files in that period
- **Possibly stale** if more than 14 days and >20 files changed
- **Current** otherwise
Note findings for presentation in Step 6 under a "Codemap Staleness" section.
**Do not run `/codemap update` automatically** — it consumes significant tokens. Only present the finding and let the user decide.
## Step 5d2: Check Codemap Stack-Concern Coverage
For each CODEMAP.md found in Step 5d, verify stack-level cross-cutting concerns are captured. Feature-organized codemaps systematically under-document cross-cutting framework layers (signals, migrations, URLConfs, env matrices) because those don't attach to any single feature.
1. **Detect the stack** from the codemap (grep the first ~50 lines for `Django`, `Next.js`, `Laravel`, `Expo`, or the `Stack:` header).
2. **Grep the full codemap** for expected stack-concern keywords:
- **Django:** `URLConf tree`, `Signal registry|post_save|pre_save`, `Migration state|latest migration`, `Env matrix|env var table`
- **Next.js / React:** `Route tree|Route overview`, `API client|interceptor`, `Env matrix`
- **Laravel:** `Route file|routes/web.php`, `Job registry|queue`, `Service provider`, `Env matrix`
- **Expo / React Native:** `Screen tree|Navigation config`, `API client`, `Env matrix`
3. **Flag any concern with 0 hits** as a coverage gap.
Note findings for presentation in Step 6 under a "Codemap Coverage" section.
**Do not auto-add missing sections** — only surface the finding. Same deferral as Step 5d: section additions consume significant tokens and should be run as focused `/codemap section <name>` tasks in a separate session.
## Step 5e: Cross-Project Pattern Detection
Skip this step entirely if `projects_enabled: false` or `projects_list` has fewer than 2 entries.
Scan `{knowledge_folder}/projects/{*}/patterns/*.md` (and optionally `projects/{*}/decisions/*.md` for cross-project decision detection) for files that may represent the same pattern across multiple projects.
**Detection heuristics** (consistent with `/index` Step 8d so the two skills surface the same candidates):
1. **Filename similarity:** Files with similar kebab-case names (e.g., `state-management-patterns.md` in two project subfolders). Case-insensitive equality of stem; allow minor variants (`-patterns` vs `-pattern`, plural vs singular).
2. **Tag overlap:** Files sharing 3+ tags excluding the project tags themselves (which are auto-derived from path per Decision #9).
3. **Title/summary similarity:** Files whose H1 (first `#` heading) shares 3+ significant terms (excluding stop words and project names).
**Threshold:** if a pattern appears in ≥`projects_promotion_threshold` projects (default 2), surface as a candidate.
For each candidate group, present to the user:
```
## Cross-Project Promotion Candidates
1. Pattern: "state-sync between AI and wizard"
- projects/proj-a/patterns/state-sync.md (Last updated: 2026-04-12)
- projects/proj-b/patterns/state-sync.md (Last updated: 2026-04-14)
- Shared tags: state-management, agentic-ui
- Suggested cross-project location: approaches/state-sync-between-ai-and-ui.md
Promote to cross-project approach? (yes / no / skip)
```
If the user approves promotion:
1. **Synthesize content from the project-specific files.** Read each source file, identify common patterns, identify project-specific specializations. Draft a merged document with:
- The shared pattern as the core content
- Project-specific specializations called out as variants or notes
- Original example references preserved with project attribution
2. **Show the user the synthesized draft for review.** Ask for edits or approval before writing.
3. **Write the new cross-project file** at the suggested location (typically `approaches/{name}.md`).
4. **Add the `originally_at:` provenance frontmatter field** to the new file:
```yaml
---
Last updated: YYYY-MM-DD
tags: [tag1, tag2, ...]
originally_at: projects/proj-a/patterns/state-sync.md (merged with projects/proj-b/patterns/state-sync.md on YYYY-MM-DD during cross-project promotion)
---
```
This makes consolidations greppable (`grep -r "originally_at:" knowledge/`) and survives git history truncation.
5. **Decide what to do with the source files** — present to the user:
- **Remove** — delete each source file (the cross-project file is the new home; project context is preserved via `originally_at`). **(v2.15.2 note:** this is verify-no-loss-compliant under the never-delete rule — the cross-project destination carries the full body with revisions/edits as needed, and `originally_at:` frontmatter provides the audit trail. Source-file deletion here is delete-after-move, not delete-without-preservation. No archive needed.)
- **Stub-and-reference** — replace each source file with a 3-line redirect:
```markdown
# [Title]
This pattern was promoted to [approaches/{name}.md](../../approaches/{name}.md) on YYYY-MM-DD as it was validated across multiple projects.
```
- **Keep** — leave both source and cross-project files; useful when the project has unique context worth preserving alongside the shared pattern (rare)
Default: **stub-and-reference** — preserves discoverability while avoiding duplication. Document the choice in Step 8's audit log entry.
6. **Update `index.md`** — append the new file to the appropriate tag sections; remove deleted source files from the index. (This happens automatically in Step 7b's index rebuild.)
If no candidates are detected, skip silently.
If candidates are detected but the user declines all promotions, note in Step 8's audit log entry: "N cross-project promotion candidates declined" (so they don't get re-suggested every audit unless evidence changes).
## Step 6: Present Findings
Present a table with ALL files scanned and their category. Only show details for Category C items.
**Output policy:** emit every subsection defined below. Subsections with no findings must emit an explicit zero-state line (e.g., "**Pending Insights:** 0 — none pending.") rather than being omitted. The five subsections that explicitly permit silent omission (Task-Boundary Captures, Subagent Captures, Codemap Staleness, Codemap Coverage, Shared-Block Drift) are conditional-on-feature-presence — they omit when the feature doesn't apply to this project, not when findings are empty. Do not collapse or shorten the structured report in pursuit of brevity — empty sections with zero-count confirmations are informational signals that the audit ran the check.
Format:
```
## Knowledge Audit Results (YYYY-MM-DD)
**Last audit:** YYYY-MM-DD (N days ago)
**Files scanned:** X memory files, Y plan files
### Summary
- Category A (already captured): X files
- Category B (Claude-specific): Y files
- Category C (worth extracting): Z files
### Pending Insights (from insights-backlog.md)
For each insight entry:
- **Date / Project / Context:** from the entry header
- **Insight:** the bullet points
- **Suggested location:** where in the knowledge folder it should go (or "clear" if not worth keeping)
If none: emit "**Pending Insights:** 0 — none pending."
### Pending Ideas (from intake/ideas/)
Present ideas in their own section. **Sort stale entries first** (age > `ideas_staleness_threshold_days`, default 7). For each entry, show:
- Date, age annotation (`filed N days ago`), project tag, short title, type (feature/bug/design/refactor/workflow)
- Stale marker `[STALE — still relevant?]` appended when age > threshold
- Proposal and motivation (one-line summary if long)
- **Disposition prompt:** two-step format — top-level choice + Accept submenu
**Top-level options (always shown):**
- `Accept → [submenu]` — pick a destination from the per-idea submenu (computed per Step 2c2 detection probes)
- `Reject` — clear with one-line reason
- `Defer` — keep in place for next audit (disallowed implicitly for stale entries)
- `Reclassify` — move to insights/decisions/extraction backlog as observation
**Accept submenu (computed per idea):** always include `tracker | adr | backlog | rule`. Conditionally include `roadmap` if `ROADMAP.md` exists at the idea's project root or under `docs/`; `todo` if `TODO.md` exists similarly; `bundle` only on the lead entry of a detected cluster (and list cluster members inline).
For stale entries, prompt explicitly (don't allow implicit Defer). For non-stale entries, Defer is fine as a no-op.
Example output:
```
### Pending Ideas (3)
- 2026-03-12 (35 days ago) — aria — refactor — simplify blueprint merge logic [STALE — still relevant?]
Proposal: ...
Accept → [tracker | adr | backlog | rule] / Reject / Defer / Reclassify?
(no roadmap/todo: ROADMAP.md and TODO.md not found at aria project root or docs/)
- 2026-03-22 (25 days ago) — proj-a — bug — theme tokens missing from blueprint XYZ [STALE — still relevant?]
Proposal: ...
Accept → [tracker | roadmap | adr | backlog | rule] / Reject / Defer / Reclassify?
(no todo: TODO.md not found)
Hint: Use /foo-ticket to draft this as a ticket. (ticketing_plugins maps this project tag → foo-ticket)
- 2026-04-15 (1 day ago) — aria — feature — /setup diff prompts ahead vs diverged
Cluster: bundle option available — also see "/setup state-aware second run" (2026-04-15) and "/setup test-mode skip re-decided" (2026-04-15) under aria project.
Proposal: ...
Accept → [tracker | adr | backlog | rule | bundle] / Reject / Defer / Reclassify?
```
When the user picks `Accept`, prompt: *"Destination? [tracker | roadmap | todo | adr | backlog | bundle | rule]"* (showing only the items in that idea's available submenu). Then route per the Step 2c2 specification.
**Submenu validation:** if the user names a destination that is **not** in this idea's available submenu (e.g., picks `roadmap` when ROADMAP.md doesn't exist for this project, or picks `bundle` on a non-clustered idea), do **not** auto-route to a fallback. Instead, re-prompt with a one-line explanation:
> *"`{destination}` is not available for this idea — {reason}. Pick from: [{available submenu}]."*
Reasons by destination:
- `roadmap` / `todo`: *"ROADMAP.md / TODO.md not found at {resolved project root} or its docs/ subdirectory"* (or *"project path unresolved"* per Step 2c2 resolution rules).
- `bundle`: *"this idea is not part of a detected cluster — file matches no other pending idea on project + ≥2 significant title words"*.
This makes the gap visible and forces an informed re-pick rather than silently routing to a destination the user didn't ask for.
**Between audits:** remind the user that `/context {project}` also surfaces pending ideas scoped to that project (informational, non-selectable) — for keeping the staged list visible between audit cycles without running a full review. Audit-time is for disposition; `/context` is for awareness.
If no ideas exist: emit "**Pending Ideas:** 0 — none pending."
### Pending Decisions (from decisions-backlog.md)
For each decision entry:
- **Date / Project(s) / Context:** from the entry header
- **Decision:** what was decided and why
- **Recommendation:** promote to ADR in `{knowledge_folder}/decisions/` (with suggested filename) or "clear" if already captured elsewhere
If none: emit "**Pending Decisions:** 0 — none pending."
### Pending Rules (from rules-backlog.md)
For each rule entry:
- **Date / Project(s) / Context:** from the entry header
- **Rule:** the proposed rule statement (and the "why" / "how to apply" lines if present)
- **Recommendation:** suggested promotion target — (a) **user memory** (`feedback_*.md` under the active project's `~/.claude/projects/{cwd-encoded}/memory/`) for personal/working-style rules that span projects; (b) **cross-project ARIA rule** (`{knowledge_folder}/rules/user-rules.md`) for ARIA-behavior rules that apply across all work; (c) **project-tier working rule** (`{knowledge_folder}/projects/{tag}/rules/working-rules.md` — projects tier only) for project-scoped discipline. Or "clear" if already captured elsewhere.
If none: emit "**Pending Rules:** 0 — none pending."
### Task-Boundary Captures (from intake/task-boundary-captures/)
For each snapshot with extractable content:
- **Date / Session:** from the filename
- **Findings:** extracted insights, decisions, feedback, or references
- **Recommended action:** append to appropriate backlog and delete snapshot, or delete without extracting
If no snapshots exist or none had extractable content: omit this section.
### Subagent Captures (from intake/subagent-captures/)
For each capture with extractable content:
- **Date / Parent session / Agent type:** from the filename
- **Findings:** extracted insights, decisions, feedback, or references
- **Recommended action:** append to appropriate backlog and ledger-clear the capture (no bare-delete — sticky retention)
If the directory doesn't exist or no captures had extractable content: omit this section.
### Category C Items (if any)
For each Category C item:
- **Source:** file path
- **Knowledge type:** approaches / decisions / rules / references / **project-decisions / project-patterns** (when feature enabled)
- **Suggested location:** where in the knowledge folder it should go
- **Content summary:** what would be extracted
**Project routing logic (only if `projects_enabled: true`):**
Before defaulting to cross-project locations, check the item's tags or content for project context:
1. If the item carries a tag matching a configured project tag (from `projects_list`), suggest the corresponding project subfolder:
- Decisions → `projects/{tag}/decisions/`
- Reusable patterns → `projects/{tag}/patterns/`
- Operational guides specific to the project → `projects/{tag}/guides/` (will be created on first promotion)
- Project-specific external references → `projects/{tag}/references/` (will be created on first promotion)
2. If the item's content clearly references a project by name (e.g., mentions proj-a, proj-b, proj-c) but lacks the explicit tag, prompt the user to confirm the project tag before suggesting the location.
3. If neither tag nor content indicates a specific project, default to the cross-project tree (`approaches/`, `decisions/`, etc.) as before.
This biases new promotions toward project subfolders when the evidence is single-project, leaving the cross-project tree for genuinely cross-cutting knowledge.
If none: emit "**Category C Items:** 0 — all scanned files were Category A or B."
### Integrity Issues (from Step 5b)
If Step 5b found any issues, present them:
For each issue:
- **Type:** contradiction / stale reference / superseded content / missing connection / stale entity reference / missing entity / skill-knowledge drift
- **Files involved:** which knowledge files are affected (and which skill, for drift issues)
- **Issue:** what's wrong (for drift: include both dates — skill modified date and knowledge file last-updated date)
- **Suggested fix:** specific edit or addition to resolve it (for drift: "Review knowledge file for alignment with current skill behavior")
If no issues found: "No integrity issues detected."
### Emerging Themes (cluster detection + synthesis drafts)
Review ALL current backlog entries (not just new ones) plus any Category C items for thematic clusters. Look for:
- **Multiple insights on the same topic** → may warrant a new approach in `approaches/`
- **Multiple decisions with shared rationale** → may warrant an approach documenting the underlying pattern
- **Recurring feedback corrections** (check memory feedback files) → may warrant a new rule in `rules/`
If clusters are detected, present each one with a **draft synthesis document**:
- **Theme:** [description of the pattern]
- **Evidence:** [which backlog entries / memory files point to this]
- **Recommendation:** create new approach, rule, or rule amendment — or "not yet — need more evidence"
- **Draft:** (only if recommendation is to create)
```markdown
# [Proposed Title]
## When to Use
[Synthesized from the cluster evidence — conditions where this applies]
## When NOT to Use
[Conditions where this pattern is wrong or doesn't apply]
## The Approach / The Rule
[Core content synthesized from the individual backlog entries]
## Related
[Links to existing knowledge files that connect to this theme]
## Validated By
[Which sessions/projects produced the evidence]
```
The draft is a starting point for review, not final content. The user may edit, reject, or ask for revisions before promotion. If there isn't enough evidence for a concrete draft, say so and present the theme without one.
```
### Stale Knowledge
If `{knowledge_folder}/index.md` exists, read its `## Stale Files` section. If it has entries, present them as action items:
```
## Stale Knowledge
- N files past review threshold:
- [file path] ([age] months, threshold: [threshold] months)
For each: review and update Last updated date? Update content? Archive if no longer relevant?
```
If no index exists, skip this section with a note: "Run `/index` to enable staleness detection."
### Codemap Staleness (from Step 5d)
If any CODEMAP.md files were found, present their status:
```
## Codemap Status
| Codemap | Last Updated | Age | Files Changed Since | Status |
|---------|-------------|-----|--------------------| -------|
| proj-b/CODEMAP.md | 2026-04-09 | 14 days | 23 files | Possibly stale |
| proj-a/CODEMAP.md | 2026-03-01 | 53 days | 87 files | Stale |
Stale codemaps can be refreshed with `/codemap update` (runs in the project directory).
Note: codemap updates involve significant codebase scanning and may consume substantial tokens.
```
If no CODEMAP.md files found: omit this section silently.
### Codemap Coverage (from Step 5d2)
If any codemap is missing stack-level cross-cutting sections, present the gap:
```
## Codemap Coverage Gaps
{codemap path} ({stack}): missing stack-level cross-cutting sections:
- URLConf tree overview
- Signal registry
- Migration state
- Env matrix
Add each via `/codemap section <name>` in a focused session. Feature-organized codemaps tend to miss these because they span all features rather than attaching to one.
```
If all codemaps have full stack-concern coverage: omit this section silently.
### Shared-Block Drift (from Step 5b3)
If any shared block has drifted across skills, present the divergence:
```
## Shared-Block Drift
`group-loader` differs between:
- plugin-claude-code/skills/distill/SKILL.md
- plugin-claude-code/skills/stitch/SKILL.md
Diff: (show the key differing lines — first ~5 differences with line context)
Resolve by:
(a) update one skill to match the other (canonical version is the most recent intended change), or
(b) rename the block in one skill (e.g., `group-loader-distill`) if the divergence is intentional
```
If all shared blocks are consistent across skills: omit this section silently.
### Cross-Reference Findings (from Step 5c)
For each cross-reference found:
- **Type:** topic overlap | potential invalidation
- **Backlog entry:** which entry triggered the match
- **Existing file:** which promoted doc it overlaps with
- **Recommendation:** update existing, create new alongside, or review existing for staleness
If none: emit "**Cross-Reference Findings:** 0 — no overlaps detected against promoted docs."
## Step 7: Wait for User Review
**STOP here.** Do NOT extract anything automatically.
Present Category C items, pending insights, and pending decisions. Ask the user which ones to extract/promote. Only proceed after explicit approval.
### Step 7a: Declare Batch Manifest (v2.10.0+)
After user approval and *before* executing any promotions, declare a batch manifest to enable Rule 22 ceremony compression on mechanical promotions while preserving full Rule 22 scrutiny on high-impact items. See `OVERVIEW.md` "Batch Manifests for Ceremony Reduction" for the full mechanism.
**Classify each approved op as `low` or `high` impact:**
| Impact | Typical ops | Treatment |
|--------|-------------|-----------|
| **low** (compressed directive) | Stubs from Step 5e, cross-reference additions, backlog clears, log appends, new files under `approaches/`, `guides/`, `references/` | Hook emits short acknowledgment-only directive |
| **high** (full Rule 22 fires) | New `decisions/` ADRs (new architectural commitments), new or modified `rules/` entries, promotions that change guidance/recommendations, cross-project consolidations that create new authoritative files | Full CHANGE DECISION CHECK per edit |
**Safety floor stays active regardless of manifest declaration:** (a) edits to protected paths (`CLAUDE.md`, `working-rules.md`, knowledge folder itself, user critical paths) always get full Rule 22; (b) structural signals (`auth/`, `migrations/`, `models.py`, `routes.ts`, external services like `stripe`) on a declared-low op escalate to full Rule 22; (c) any edit to a file not matched by the manifest triggers full Rule 22 as scope-drift detection.
**When in doubt about an op's impact, declare `high`** — full Rule 22 is always the safe choice.
**Write the manifest** via Bash before executing promotions:
```bash
. scripts/aria/config.sh
kt_batch_begin "audit-knowledge" "Audit promotion: N items per approved plan" '[
{"file_path_pattern": "/abs/path/to/knowledge/approaches/*.md", "operation_type": "create", "impact": "low", "justification": "New approach files per approved Step 7 plan"},
{"file_path_pattern": "/abs/path/to/knowledge/decisions/*.md", "operation_type": "create", "impact": "high", "justification": "New ADR — architectural commitment requires full scrutiny"},
{"file_path_pattern": "/abs/path/to/knowledge/intake/*-backlog.md", "operation_type": "update", "impact": "low", "justification": "Clear promoted entries per approved plan"},
{"file_path_pattern": "/abs/path/to/knowledge/projects/*/patterns/*.md", "operation_type": "update", "impact": "low", "justification": "Stub-and-reference after cross-project promotion"}
]'
```
Substitute `/abs/path/to/knowledge/` with the actual `knowledge_folder` from Step 0 and adjust patterns to match the specific approved items (only include patterns for op types actually approved — don't list phantom patterns).
**If `kt_batch_begin` fails** (jq missing, validation error, permission issue) — the command prints a diagnostic to stderr and returns non-zero. Proceed with the audit regardless: full Rule 22 fires on every edit as before. The manifest is a ceremony-reduction optimization, not a requirement. Don't block the audit on batch-manifest failure.
Then execute approved promotions below:
- Approved insights → move to the appropriate knowledge file, clear from backlog
- Approved decisions → create full ADR in `{knowledge_folder}/decisions/`, clear from backlog
- Approved rules → for each entry, prompt the user to pick the promotion target: (a) **user memory** — write a `feedback_*.md` file under the active project's Claude Code memory directory (typically `~/.claude/projects/{cwd-encoded}/memory/`, the same location existing `feedback_*.md` files live in) and add a one-line index entry to `MEMORY.md` in that same directory. Mirrors how feedback memories are written manually today; (b) **cross-project knowledge rule** — append to `{knowledge_folder}/rules/user-rules.md` (the user-owned rules file that ARIA never overwrites). Use this when the rule is for ARIA's own behavior across projects rather than personal/working-style; (c) **project-tier working rule** — only available when `projects_enabled: true` AND the idea has a `project` tag matching `projects_list`. Append to `{knowledge_folder}/projects/{tag}/rules/working-rules.md`; if the file or its parent `rules/` directory doesn't exist, create them from the template (see Step 7c of `/setup` for the scaffolding contract). Clear the entry from `intake/rules-backlog.md` after writing. **Never** write to paths outside `{knowledge_folder}` or the user memory directory — destinations like `{project_path}/working-rules.md` (the codebase itself) are out of scope for ARIA promotion since ARIA does not modify project source.
- Approved project-tier promotions (only if `projects_enabled: true`) → before writing, validate the target project subfolder exists. If `projects/{tag}/` is not in the user's knowledge folder, prompt: *"Project '{tag}' is not in your config (`projects_list`). Add it now? (yes adds the tag to projects_list, creates `projects/{tag}/{decisions,patterns}/` with a per-project README, then writes the file)."* If the user says yes, edit `.cursor/aria-knowledge.local.md` to append the tag to `projects_list` (preserving existing entries), create the directory structure (mirror `/setup` Step 3's project tier scaffolding), then write the promoted file. If the user says no, fall back to the cross-project location (`approaches/` or `decisions/`) and warn that the project context is being lost.
- Approved cross-project promotion candidates from Step 5e → already handled inline in Step 5e (synthesis + `originally_at` + source disposition). No additional action here.
- Approved synthesis drafts → create the new file in the appropriate category, clear source entries from backlogs
- Approved integrity fixes → apply the fix (edit existing file, add cross-reference, archive superseded content)
- **Update existing** → for items with Step 5c cross-reference matches, merge the new content into the matched file instead of creating a new one. Read the existing file, identify where the new content fits (new section, addition to existing section, or replacement of outdated content), make the edit, update the `Last updated` date, and add/update tags if needed. Clear from backlog after updating.
- **Stale codemaps** → if the user wants to refresh a stale codemap, do NOT run it inline. Instead tell them: *"Run `/codemap update` in the {project} directory in a separate session or after this audit completes. Codemap updates scan many files and are best run as a focused task."* This avoids blowing the context window mid-audit.
- Rejected items → clear from their respective backlogs
### Cross-References on Promotion
When writing any new knowledge file during promotion, add a `## Related` section at the bottom linking to existing knowledge files that share concepts, context, or dependencies. To find related files:
1. Check which rules the new content implements, extends, or is an example of
2. Check which approaches or decisions discuss the same system, component, or pattern
3. Check if any existing file's `## Related` section should be updated to link back to the new file
Format:
```markdown
## Related
- [enforcement-mechanisms.md](../rules/enforcement-mechanisms.md) — this approach uses hook-based enforcement (mechanism tier 2-3)
- [001-compact-output-format.md](../decisions/001-compact-output-format.md) — decision that shaped the output format used here
```
Use relative paths. Each link should include a brief note explaining the relationship, not just the filename. Only link files with a genuine conceptual connection — don't link everything to everything.
If there are no Category C items, pending insights, or pending decisions, say so clearly:
> "Nothing new to extract. All knowledge-worthy items are already captured."
## Step 7b: Rebuild Knowledge Index
After all approved promotions and edits are complete, rebuild the knowledge index to capture the current state.
Run the full `/index` logic:
1. Scan all promoted folders for files and tags
2. Normalize tags (present conflicts for approval)
3. Suggest freeform-to-known tag promotions
4. Flag untagged files and offer to add tags
5. Update project-to-tag mappings
6. Detect stale files
7. Suggest cross-references between files with 2+ shared tags
8. Write `{knowledge_folder}/index.md`
**Batch the interactive prompts** — present all index health findings together rather than interrupting one at a time:
```
## Index Health
- N similar tags found: [list normalizations]
- N freeform tags eligible for promotion: [list]
- N untagged files: [list]
- N cross-reference suggestions: [list]
- Project mappings: [changes or "unchanged"]
[Approve normalizations? Promote tags? Tag files? Add cross-references?]
```
Apply approved changes, then write the final `index.md`.
**After writing, count tag sections** (`grep -c '^### ' index.md`). If **zero**, note:
> "Index rebuilt with no tag sections. Active knowledge surfacing stays off until at least
> one promoted file carries a tag — the SessionStart hook gates on tag content, not on the
> index file existing."
This matters because a tagless index used to be merely unhelpful; since the gate was
tightened it silently keeps a whole capability switched off, and a rebuild that reports
success is exactly where that would go unnoticed.
If this is the first audit (no index exists yet), note: "Building knowledge index for the first time."
## Step 8: Update the Audit Log (always, even if nothing extracted)
After presenting findings (and completing any approved extractions), update `{knowledge_folder}/logs/knowledge-audit-log.md`.
Use the **structured format** below — it keeps audit logs scannable over many passes, and fields like "Counts" and "New files" are grep-able for trend analysis across audits. Previous entries in free-form paragraphs remain valid; apply this template to new entries going forward.
**If items were promoted:**
```markdown
## Last Audit
- **Date:** YYYY-MM-DD (Nth pass — short label: "routine check", "v2.8.0 continuation", "post-restructure", etc.)
- **Trigger:** count=N threshold=T days=D cadence=C — (which fired: count-tier|days|user-invoked)
- **Counts:** X insights, Y decisions, Z extractions, R rules reviewed
- **Ideas disposition:** W reviewed — accepted: A1 tracker / A2 roadmap / A3 todo / A4 adr / A5 backlog / A6 bundle / A7 rule (sum = A); B rejected; C deferred; D reclassified (omit field entirely if no ideas were in the audit; omit any zero-valued sub-counts)
- **New files:** N total — [breakdown: K approaches, L ADRs (split by tier), M patterns, etc.]
- **Extended files:** P total — [list filename: brief change, e.g. "css-gotchas.md +2 gotchas"]
- **Memory:** A new feedback, B new project, C new reference, D updates
- **Integrity fixes:** E total — [one-line each, e.g. "decisions/README.md naming convention per ADR 014"]
- **Themes:** [1-3 phrases naming the pattern clusters that drove promotions, e.g. "audit methodology synthesis", "ARIA v2.8.0 patterns"]
- **Notes:** [free text — deferred items, cross-references, notable decisions, 1-3 sentences max]
```
**If nothing promoted (empty-audit case):**
```markdown
## Last Audit
- **Date:** YYYY-MM-DD (Nth pass — "no new items" or short label)
- **Trigger:** count=N threshold=T days=D cadence=C — (which fired: count-tier|days|user-invoked)
- **Result:** No new items — [X memory files all Category A, Y plan files Category B, backlogs empty OR K entries all cleared as already-captured/stale]
- **Ideas disposition:** [optional — omit if no ideas were in the audit, else: W reviewed — accepted: A1 tracker / A2 roadmap / A3 todo / A4 adr / A5 backlog / A6 bundle / A7 rule (sum = A); B rejected; C deferred; D reclassified — omit any zero-valued sub-counts]
- **Notes:** [optional — anything worth flagging even though nothing was promoted, e.g. "clusters forming around theme X but below threshold"]
```
**Formatting rules:**
- Every field on its own line (no paragraph mashing)
- Counts are numeric; lists are comma- or newline-separated but bounded (don't dump 30 filenames into one bullet — use "27 total — [3-5 highlights]" plus "See [file] for full list" if needed)
- Notes is the escape hatch for things that don't fit — but cap at a few sentences. If the Notes section balloons past that, the audit produced enough content to deserve a dedicated summary doc, not a bloated log entry.
Also demote the previous "Last Audit" entry to the "## Previous Audits" section. If multiple audits happened in a single day (continuation passes like Pass 2 or tenth-pass), nest them under a single date header rather than creating sibling "Date: YYYY-MM-DD" entries.
## Step 8b: Clear Batch Manifest (v2.10.0+)
After the audit log is written, clear the batch manifest to unblock default Rule 22 behavior for any edits later in the session:
```bash
. scripts/aria/config.sh
kt_batch_end
```
Safe to call even if Step 7a's `kt_batch_begin` didn't succeed (e.g., jq missing) — the function just removes the manifest file if it exists. If the audit errors out before reaching Step 8b, `session-start-check.sh`'s stale-manifest auto-clear (30-minute threshold) recovers on the next session start so stale manifests don't silently suppress Rule 22 on unrelated edits.
## Rules
- **Never auto-extract** — always present findings for user review first
- **Be conservative with Category C** — if it's borderline, it's probably Category A or B
- **Check project docs thoroughly** — knowledge is often already captured in project-level CLAUDE.md, PROGRESS.md, or docs/ folders
- **Convert relative dates** — if a memory or plan references "last Thursday", convert to the actual date
- **Stale memories are not Category C** — outdated project status doesn't need extraction, it needs cleanup
- **Prioritize approaches and rules** — these are the highest-value extractions. Debug recipes, implementation plans, and one-time fixes are Category B
- **Watch for clusters** — individual backlog entries may not justify a knowledge file, but patterns of related entries do. The backlogs are signal generators, not just staging areas
- **A capture is a snapshot of a moment, not of current state** — any finding mined from a transcript (pre-compact or subagent) that asserts a present-tense defect MUST be re-verified against HEAD before it is filed, ticketed, or promoted. See Step 2d item 4. This applies with or without a standing grant to file findings; a grant makes the check *more* necessary, not less
- **Before any disposition that deletes, verify the targets' git-tracking state** — "recoverable via git history" is false for a file that was never committed. Per ADR 084, checkpoint first. In a shared working tree with live parallel sessions, checkpoint **by named path**, never `git add <dir>` — a directory pathspec limits which files, not whose
---
## /audit-config
- # /audit-config — Configuration & Documentation Health Check
+ # /audit config — Configuration & Documentation Health Check
+ Canonical invocation: **`/audit config`**. The direct `/audit-config` form is retained for compatibility and is not advertised.
+
Scan all AGENTS.md files, `.claude/settings.local.json` configs, plugin manifests, and knowledge files for drift, broken references, and staleness.
## Step 0: Resolve Config
Read `.cursor/aria-knowledge.local.md` and extract `knowledge_folder` and `audit_cadence_config`. If the file doesn't exist, stop: "aria-knowledge is not configured. Run /setup to get started."
Use `{knowledge_folder}` as the base path for all knowledge file operations in subsequent steps.
## Step 1: Read the Audit Log and Determine Mode
Read `{knowledge_folder}/logs/config-audit-log.md`.
Note the "Last Audit" date and calculate days since.
**Determine how this skill was invoked:**
- - **User-requested** (user said `/audit-config`, "audit configs", "check setup", etc.): **Always run the full audit**, regardless of how recently the last audit was. Skip directly to Step 2.
+ - **User-requested** (user said `/audit config`, "audit configs", "check setup", etc.): **Always run the full audit**, regardless of how recently the last audit was. Skip directly to Step 2.
- **Session-start check** (triggered by the SessionStart hook): Check if the configured cadence has been exceeded.
- If **cadence exceeded**: Prompt the user — *"It's been N days since the last config & docs audit. Want me to check for drift?"* If they agree, proceed to Step 2. If not, stop.
- If **within cadence**: Report the last audit date and stop. *"Last config & docs audit was N day(s) ago (YYYY-MM-DD). Next check due in M days."*
## Step 2: Scan Configuration Files
Use agents in parallel to scan these areas:
### 2a: Settings Files
Find all `.claude/settings.local.json` files in the current working directory. For each:
- Validate JSON structure
- Check all `Bash(...)` permission paths exist on disk
- Check all `mcp__*` references against currently available MCP tools
- Flag stale or redundant permissions
- Check for ghost configs in unexpected locations (e.g., `node_modules/`)
### 2b: Plugin Manifests
For each plugin referenced in settings files:
- Compare manifest version against any version claims in AGENTS.md files
- Verify plugin paths referenced in settings files
### 2c: Plugin Configs
Check `.claude/*.local.md` files:
- Verify referenced IDs and paths are properly formatted
- Note configuration settings
## Step 3: Scan CLAUDE.md Files
Find all AGENTS.md files recursively in the current working directory.
Expand via Glob first, then issue Read calls for all found AGENTS.md files in a single parallel tool-use block. Validation checks run in the main thread after reads complete.
For each file, check:
- **File references** — do referenced files/paths actually exist?
- **Cross-references** — do pointers to other AGENTS.md files resolve?
- **Version claims** — do stated versions match actual manifests/package.json?
- **Version-stamp ripple** — when a version appears in one CLAUDE.md, does the same version appear consistently across sibling AGENTS.md files and memory files that reference the same project? Mismatched versions across surfaces (e.g., root says v2.14.2, sub-project says v2.14.3) signal a post-release update that didn't propagate. See Step 3a for the detection pattern.
- **Adoption-state phrases** — does language like "NOT YET BUILT", "(placeholder)", "spec drafted, not yet built", "currently disabled", "still has older prototype", "pipeline built but not yet adopted" contradict the actual state of a referenced artifact (plugin.json exists with non-zero version, config flag is enabled, build output is present)? See Step 3a.
- **Team roster** — is it consistent across AGENTS.md files?
- **Stale content** — are there line numbers, dates, or status claims that look outdated?
- **Missing references** — are there significant docs/files in the project that aren't referenced?
## Step 3a: Release-State Cascade Patterns
Two specific cascade shapes are common enough to warrant dedicated detection. Both follow the same structural pattern: one source-of-truth surface changes (a version bump, an enabled flag), and N downstream surfaces fail to update.
### 3a.1: Version-stamp ripple
After a plugin/package release, version references typically touch 5+ surfaces: the manifest itself, the project's CLAUDE.md status header, any parent container CLAUDE.md table row, the project memory file's description + body + version-row, and the MEMORY.md index entry. Each is small; skipping any creates documentation drift.
**Detection:**
1. For each plugin manifest (`plugin.json`) or `package.json` found, extract the canonical version string (e.g., `v2.14.4`).
2. Glob AGENTS.md files in the project + ancestor directories + `~/.claude/projects/.../memory/project_*.md` files referencing the project's slug.
3. For each surface, grep for version strings matching the pattern `v?\d+\.\d+\.\d+` near a mention of the project name.
4. Flag any surface where the stated version is **older than** the manifest version. Treat "older" by semver comparison, not string comparison.
5. Do NOT flag surfaces where the version is absent entirely — those are not drift, just under-documentation (out of scope for this check).
Report shape:
```
Version-stamp drift for {project-slug}:
Canonical: v{manifest-version} (from {manifest-path})
Stale surfaces:
- {surface-path} — stated v{stale-version}
- {surface-path} — stated v{stale-version}
```
### 3a.2: Adoption-state cascade
When a binary config value flips (e.g., `enabled=0` → `enabled=1` in a deploy script, or a placeholder folder becomes a built artifact), N referenced docs may still describe the prior state.
**Detection patterns to grep against CLAUDE.md / README.md / memory files:**
| Phrase pattern (case-insensitive) | Inverse-state check |
|-----------------------------------|---------------------|
| "currently disabled in {flag-name}" | Read the named flag/script; flag drift if value is now enabled |
| "NOT YET BUILT" / "(placeholder)" / "spec drafted, not yet built" | Check for plugin.json / package.json with non-zero version, or built artifact (e.g., `*.plugin` package) in the referenced folder |
| "pipeline built but not yet adopted" | Check whether the pipeline is enabled in the canonical config |
| "still has older prototype" / "render-broken `dist/` not regenerated" | Check `git status` / file mtimes of the referenced folder |
| "deferred to v{X.Y.Z}+" where X.Y.Z is now in the past | Check current manifest version against X.Y.Z |
Surfaces to scan are the same as 3a.1: AGENTS.md files in the working tree, README.md files, and project memory files in `~/.claude/projects/.../memory/`.
**Conservative reporting:** Both 3a.1 and 3a.2 are pattern-based heuristics, so false positives are possible. Report under **Should Fix** (not **Critical**) and present the specific surface + the specific contradicting phrase + the underlying state — let the user judge whether each is real drift or intentional historical note.
## Step 3b: Missing-Known-Fields Cascade (v2.15.2+)
After 3a's pattern-based drift checks, run a structural check for config-schema gaps: any user-facing field documented in `scripts/aria/config.sh` but missing from `.cursor/aria-knowledge.local.md`. This catches `/setup` discipline failures retroactively — if the wizard ever silently skipped surfacing a new field (e.g., the `active_knowledge_surfacing` gap that bit v2.15.1's first users), this audit cadence picks it up at the configured `audit_cadence_config` cadence (default 14 days).
**Algorithm:**
1. Enumerate known user-facing field names by parsing `scripts/aria/config.sh`. Each known field is encoded as:
```bash
KT_FIELDNAME=$(sed -n '/^---$/,/^---$/p' "$KT_CONFIG" | grep '^fieldname:' | sed 's/^fieldname: *//')
```
Extract `fieldname` from each `grep '^FIELDNAME:'` literal. These are the canonical fields the user's config should contain. This enumeration is derived from `config.sh` at audit time, not a hardcoded list here — so it self-updates as new fields are added. For example, `style_lookback_days`, `style_max_sessions`, and `style_audit_log` (the `/audit style` sub-audit's tuning keys — default 90 days / 50 sessions / `{knowledge_folder}/logs/style-audit-log.md`) are already parsed in this shape, so a config missing any of them is flagged by this cascade without any change to this file.
2. For each known field, grep `.cursor/aria-knowledge.local.md` for `^{fieldname}:`. Zero hits → missing.
3. **Report:** under a new **Missing config fields** subsection in Step 6's findings, list each missing field with:
- Field name
- Default value (from the matching `KT_FIELDNAME=${KT_FIELDNAME:-default}` line in config.sh; "empty" if no default)
- Recommended action: *"Run `/setup` to re-surface this field with `[NEW]` marker, OR hand-add `{fieldname}: {default}` to the config's frontmatter between hook-parsed entries."*
4. **Classification:** report under **Should Fix** (consistent with 3a.1/3a.2 conservative reporting). Missing-field detection has effectively zero false-positive rate (deterministic grep) but the FIX is user judgment — a missing field might be intentional (e.g., user removed it to fall back to default behavior).
**Why this check exists (v2.15.2 Origin):** the `/setup` wizard's Step 6 Advanced Options bundle is a *soft instruction* to Claude — it's not hook-enforced, so a fast/quiet `/setup` run can silently skip surfacing new fields. Step 3b runs against the canonical `scripts/aria/config.sh` source-of-truth at audit cadence, surfacing gaps regardless of how the wizard got there. Pairs with `/setup` Step 7e (Self-Validation Audit) as the setup-time safety net.
**Presence-only check:** the field can be present with an empty value (e.g., `critical_paths:` with no value is valid). Step 3b checks for *key presence*, not non-empty value — empty fields are intentional in this schema (per CONFIG.md "Empty values: bare `key:` only").
## Step 4: Scan Knowledge Repository
Read the `{knowledge_folder}` directory structure and verify:
- `{knowledge_folder}/README.md` tree matches actual file structure
- All files referenced in README exist
- No orphaned files (files that exist but aren't in README)
- Knowledge files cross-reference correctly
- `{knowledge_folder}/decisions/` — check if pending decisions in backlog have been waiting more than 2 audit cycles
- `{knowledge_folder}/guides/` — verify subdirectory READMEs exist if subdirectories are present
Resolve the knowledge-folder glob patterns via Glob first, then issue Read calls for all resolved files in a single parallel tool-use block. Structural verification runs in the main thread after reads complete.
## Step 5: Check PROGRESS.md Files
Glob for PROGRESS.md files first, then Read all found files in a single parallel tool-use block.
For each PROGRESS.md file found in the current working directory:
- Note the date of the last session entry
- Flag if no updates in 7+ days (for active projects)
- Check if IDEAS-BACKLOG.md exists and has dated entries (if present)
## Step 5a: Check Tracked Artifact Staleness (added v2.16.1)
For each configured project in `KT_PROJECTS_LIST` (from config), stat `{project_root}/CODEMAP.md` and `{project_root}/STITCH.md`. Compute `age = (today - mtime).days`. Classify per the v2.16.0 thresholds:
- **Critical** (will block aria-knowledge from loading as reference): CODEMAP age > `2 × codemap_staleness_threshold_days` (default 14, so refusal zone = 28d). STITCH age > `2 × stitch_staleness_threshold_days` (default 30, so refusal zone = 60d). Flag with "REFUSAL ZONE: {N} days; trigger-based loading (T-1/T-2/T-3/T-5/T-6) refuses this artifact until updated. Run /codemap update / /stitch verify {tag}."
- **Should Fix:** CODEMAP age > threshold but ≤ 2×. STITCH age > threshold but ≤ 2×. Flag with "STALE: {N} days old; run /codemap update / /stitch verify {tag}."
- **Low Priority:** project in `projects_list` but no CODEMAP.md found. Flag with "no CODEMAP for {tag} — consider /codemap create."
- **Healthy:** all tracked artifacts within thresholds.
Skip projects whose `project_root` directory doesn't exist (stale `projects_list` entries — surface as a separate config-drift finding under "Should Fix").
## Step 6: Present Findings
Present results organized by severity:
**Output policy:** emit every severity section defined in the format below, even when all sections resolve to "None". Zero-finding audits are informational signals that the audit actually ran the checks — do not collapse the structured report into a one-line "no issues" summary. "Healthy (no issues)" should always list the areas that passed cleanly, not be omitted even when all four severity sections are empty.
```
## Config & Docs Audit Results (YYYY-MM-DD)
**Last audit:** YYYY-MM-DD (N days ago)
**Files scanned:** X config files, Y AGENTS.md files, Z knowledge files
### Critical (blocks work or causes errors)
- [list items or "None"]
### Should Fix (drift that will cause confusion)
- [list items or "None"]
### Low Priority (cleanup, nice-to-have)
- [list items or "None"]
### Healthy (no issues)
- [list areas that passed cleanly]
```
## Step 7: Wait for User Review
**STOP here.** Do NOT fix anything automatically.
Present findings and ask the user which items to fix. Only proceed with fixes after explicit approval. For each approved fix, apply the change and confirm.
If there are no issues, say so clearly:
> "All configs and docs are healthy. No drift detected."
## Step 8: Update the Audit Log and Knowledge Files
After completing any approved fixes:
1. Update `{knowledge_folder}/logs/config-audit-log.md`:
```markdown
## Last Audit
- **Date:** YYYY-MM-DD
- **Result:** [describe outcome — e.g., "No issues found" or "Fixed N items — brief description"]
```
Move the previous "Last Audit" entry to "Previous Audits".
2. If the audit revealed changes to the knowledge system setup, update relevant files in `{knowledge_folder}/`.
## What This Audit Catches
| Category | Examples |
|----------|----------|
| **Config drift** | Broken paths, stale permissions, ghost configs, outdated MCP refs |
| **Doc staleness** | Version mismatches, missing file references, line number rot |
| **Context drift** | Team roster changes, project status gaps, PROGRESS.md staleness |
| **Structure issues** | README not matching actual files, orphaned docs, missing cross-refs |
| **Release-state cascade** | Version-stamp ripple (one surface bumped, siblings stale); adoption-state phrases that contradict the underlying flag/manifest/artifact state |
## Rules
- **Never auto-fix** — always present findings for user review first
- **Use agents for parallel scanning** — config, CLAUDE.md, and knowledge checks are independent
- **Verify paths on disk** — don't trust that documented paths exist, check them
- **Compare, don't assume** — cross-reference versions, names, and structures against actual files
- **Focus on actionable items** — don't flag cosmetic issues or preferences, focus on things that will cause errors or confusion
---
## /audit-style
# /audit style — Working-Style Sub-Audit
**Cursor port — corpus path:** Session logs live at `~/.cursor/projects/<cwd-encoded>/agent-transcripts/*.jsonl` (cwd with `/` replaced by `-`). This is **not** Claude Code's `~/.claude/projects/<cwd-encoded>/*.jsonl`. The extractor (`scripts/aria/extract-user-prose.py`) was written for Claude Code transcript shape — if Cursor JSONL fails to parse, **fail loud** (do not silently mine zero). Skip files whose names begin with `agent-` the same way.
+ Canonical invocation: **`/audit style`** (args ride the umbrella: `/audit style recent`). The direct `/audit-style` form is retained for compatibility and is not advertised.
+
Mine your own past session-log corpus for working-style rules you have already revealed through action — not rules you're asked to invent, rules extracted from what you actually said and did across real sessions. Evidence-gated at every step: a candidate that cannot show its receipts does not ship, no matter how plausible it sounds.
## Step 0: Config + Corpus Locate
Read `.cursor/aria-knowledge.local.md` and extract the three style-audit config keys (parsed by `config.sh` as `KT_STYLE_LOOKBACK_DAYS`, `KT_STYLE_MAX_SESSIONS`, `KT_STYLE_AUDIT_LOG`). These keys are **bare-assigned** — the config file may have no value at all for any of them, in which case the shell variable is an empty string. Apply these defaults yourself in the skill body whenever the corresponding value is empty:
- `KT_STYLE_LOOKBACK_DAYS` empty → default to **90** days.
- `KT_STYLE_MAX_SESSIONS` empty → default to **50** sessions.
- `KT_STYLE_AUDIT_LOG` empty → default to `{knowledge_folder}/logs/style-audit-log.md`.
If `.cursor/aria-knowledge.local.md` doesn't exist, stop: "aria-knowledge is not configured. Run /setup to get started."
**Locate the corpus.** The session-log corpus for the current project lives at `~/.cursor/projects/<cwd-encoded>/agent-transcripts/*.jsonl`, where `<cwd-encoded>` is the current working directory with `/` replaced by `-` (Claude Code's standard transcript-directory encoding). Glob that directory for `*.jsonl` files — each file is one session transcript.
**Skip subagent sessions (hard pre-filter).** Exclude any transcript whose filename begins with `agent-` (e.g. `agent-a1b2c3….jsonl`). These are subagent worker transcripts spawned by the parent session (Task/Agent dispatches, workflow workers, review agents) — they are the *agent's* execution logs, not the user's authored prose, and mining them would (a) attribute agent-authored dispatch text to the user and (b) massively inflate the corpus on any session that fanned out workers. The `agent-` filename prefix is a clean, unambiguous discriminator (Claude Code names all subagent transcripts this way). This filter runs BEFORE the count in Step 1b, so the over-cap gate sees only genuine user sessions. (Validated on a live run: a 43-file delta was 29 subagent transcripts + 14 user sessions — skipping the `agent-*` set is what made the delta tractable.)
**Read the style-audit log for incremental scope.** Read `KT_STYLE_AUDIT_LOG` (resolved path per the default above). If it exists, its most recent timestamp entry marks the boundary of the last mining pass — this run only needs to consider sessions modified/created after that timestamp (incremental scope, keeps repeat runs cheap). **If the log doesn't exist yet (first run)**, there is no prior boundary: window the initial scan to the last `KT_STYLE_LOOKBACK_DAYS` (default 90) days of session files, by file mtime or the transcript's own embedded timestamps.
**Reuse a prior external mine as a first-run boundary (avoid re-mining what's already mined).** If there is no audit-log yet BUT a prior full mine of this same corpus exists on disk — most notably a ditto run archived under `{knowledge_folder}/references/` (its `you-corpus.txt` mtime marks when it ran, and its `stats.json` records the session count/date-range it covered) — treat that prior mine's timestamp as the incremental boundary instead of doing a full-lookback re-scan. Then only the **delta** (sessions newer than that mine, after the `agent-*` skip above) needs fresh extraction; fold the delta's evidence in with the prior mine's already-reduced result rather than re-processing the whole corpus. This turns an all-time first run from a multi-million-token re-scan into a small delta mine. State clearly in the report which portion was reused vs freshly mined. (Validated on a live run: reused 1,697 prior-mined sessions + freshly mined a 10-session user delta, instead of re-scanning ~8.5M tokens.) If no such prior mine exists, fall back to the lookback window as above.
## Step 1: Extract User Prose (multi-stage filter)
The reference implementation of this filter is `extract-user-prose.py`, which lives alongside this SKILL.md at `scripts/aria/extract-user-prose.py`. **That script is the canonical algorithm** — this section documents the same stages in prose so the mining logic is auditable without reading Python, but the script is the executable source of truth; when in doubt about an edge case, defer to what the script actually does, or invoke it directly (`python3 .../extract-user-prose.py <session.jsonl>`) rather than re-deriving the filter by hand.
Each `.jsonl` line is one JSON object (a transcript event). The filter applies, in order:
1. **Stage 1 — role + block-type gate.** Keep only objects where `type == "user"` AND the nested `message.role == "user"`, and only the **text** content (a plain string, or list blocks with `type == "text"`). This is the load-bearing exclusion: it drops every `tool_result` block outright — tool outputs are not the user's voice, no matter how much prose they contain.
2. **Stage 2 — strip command/tool wrapper noise.** Even after Stage 1, some `role: user` events are Claude Code's own wrapper markup rather than something the user typed — local-command invocations and their echoed output/errors. Drop any text block containing `<local-command-*>`, `<command-name>`, `<command-args>`, `<local-command-stdout>`, `<local-command-caveat>`, or similar `<command-*>` tags.
3. **Stage 3 — drop skill-injection preambles and resume scaffolds.** Some `role: user` text is machine-injected context rather than something the user composed: skill-injection preambles (e.g. text beginning `Base directory for this skill:`, `Caveat:`), `<system-reminder>` blocks, and resume-scaffold text (lines beginning `Resume `). Drop any block matching these prefixes.
4. **Stage 4 — drop bare slash-commands.** A line that is just `/command` or `/command args` with no surrounding prose (starts with `/`) carries no working-style signal — it's an invocation, not a statement about how the user thinks or works. Drop it.
**Format-drift-fails-loud.** If a `.jsonl` line fails to parse as JSON, or if the transcript directory's schema no longer matches the shapes above (e.g. `message.role`/`message.content` fields renamed or restructured, `type` values changed), the skill must **surface this loudly** — report the parse/shape failure explicitly to the user with the offending file and line — and must NOT silently fall back to mining zero signal or guessing at a best-effort reinterpretation. A silent empty result set on schema drift is indistinguishable from "genuinely no signal this window," which would corrupt the receipts gate downstream (Step 3 could wrongly conclude "no evidence" when the real cause is "the extractor broke"). Report the drift, do not extract from the affected file, and continue with files that still parse.
## Step 1b: Over-Cap Gate
Before extracting from every session in scope, count how many session files fall in scope per Step 0 (incremental boundary, or the lookback window on first run).
**If sessions-to-scan > `KT_STYLE_MAX_SESSIONS`** (default 50), **STOP** — do not silently scan only the first N (that would silently bias toward whichever sessions happen to sort first, not the most relevant ones). Show the user an estimate (session count, earliest/latest date in range) and prompt:
> "Found N sessions in scope (exceeds the {max_sessions} cap). Options:"
> - **`recent`** — scan only the most recent `KT_STYLE_MAX_SESSIONS` sessions (drops the oldest ones from this pass; they remain queued for a future pass via the audit-log timestamp boundary)
> - **`all`** — scan every session in scope regardless of the cap (slower, higher token cost — shown estimate helps the user judge)
> - **`window <D>`** — narrow the scope to the last `D` days instead of the full lookback/incremental range, then re-count
> - **`cancel`** — abort this run without scanning or writing anything
Older sessions that are excluded by a `recent` or `window` choice are **not lost** — they stay queued for a later pass because the incremental boundary in `KT_STYLE_AUDIT_LOG` only advances to cover what was actually mined this run (see Step 5).
**If sessions-to-scan ≤ the cap**, proceed directly to Step 2 without prompting.
## Step 2: Infer Per Layer
For each session in scope, run the Step 1 filter to produce genuine user-prose lines (tagged with session id + date). Then cluster this prose across **all 5 mining layers** — every layer runs on every audit pass, none deferred:
1. **Definition of done** — what the user says "done" actually means in practice (e.g. what has to be true, verified, or observed before they accept a task as complete).
2. **Rejection criteria** — what the user pushes back on, redoes, or explicitly refuses, and why (the shape of "no, not like that").
3. **Debugging approach** — how the user directs root-causing versus patching, what evidence they ask to see before accepting a diagnosis, how they sequence investigation.
4. **Design taste** — recurring preferences about structure, simplicity, abstraction depth, naming, or architecture that the user states or enforces across sessions.
5. **Writing voice** — recurring stylistic instructions or corrections about tone, format, verbosity, or phrasing in written output.
For each layer, look for **recurring** patterns — the same shape of statement or correction appearing across more than one session — and draft each as a candidate one-line rule, paired with the specific prose lines that support it (the candidate's supporting quotes). A pattern seen in only one session is not yet a candidate; carry it forward as a note but do not draft a rule from single-session evidence (the receipts gate in Step 3 would reject it anyway — this just avoids wasted drafting effort).
## Step 3: RECEIPTS GATE (fail-closed)
This is the load-bearing gate of the entire skill. A candidate rule drafted in Step 2 **survives only if all three conditions hold**:
(a) **≥2 distinct sessions** — the supporting quotes must come from at least two different session transcripts (different `session` ids from the extraction), not two quotes from the same session repeated or rephrased. A pattern that only shows up once, however clearly stated, does not survive.
(b) **Dated verbatim quotes** — every supporting quote must be the literal, unparaphrased text the user typed (post-redaction, see Step 4), each tagged with the date it was said (from the transcript's timestamp). A paraphrase or a summary of "what the user seemed to mean" is not a receipt — only the actual words, dated, count as evidence.
(c) **No fabrication** — the candidate rule's stated generalization must be directly supported by the quotes attached to it, not extrapolated beyond what they say. If the rule statement claims more than the quotes demonstrate, either narrow the rule statement to match the evidence or drop it.
**If any of (a), (b), (c) fails, the candidate is DROPPED — not softened, not hedged, not staged with a caveat.** There is no partial-credit tier ("probably true but only 1 session" does not become a low-confidence entry). This is a fail-closed gate: absence of sufficient evidence means the candidate does not get written anywhere, full stop.
**Rule 36 note (this gate must be able to fail for the right reason):** the receipts gate is only meaningful if it can actually reject a candidate — a version of this step that always finds "enough" evidence, or that silently treats a single session as sufficient, would produce false passes that look identical to real ones from the outside. When implementing or later modifying this step, verify the negative case directly: deliberately test with a candidate whose only evidence is single-session, and confirm it gets dropped, not waved through. A candidate that survives only because the ≥2-session check was skipped, weakened, or never actually evaluated is a false pass, indistinguishable on the surface from a genuine one — the gate's value depends entirely on it being able to fail, and failing for the correct reason (insufficient distinct-session evidence), not an unrelated one.
## Step 3b: Source Rejection
Before treating any prose as evidence, exclude content whose origin is aria's own machinery rather than the user's independent working style — otherwise the audit would mine its own prior output back into "discovered" rules, closing a feedback loop that fabricates false corroboration.
**Never treat the following as evidence, even if they pass the Step 1 filter:**
- A message whose content is (or is dominated by) a `/command` invocation and its arguments — this is dispatch, not a statement of working style.
- Content sourced from **CLAUDE.md** (any project or workspace CLAUDE.md) — these are already-synthesized instructions, not raw user prose revealing style; mining them back "confirms" what was already written, not what was independently observed.
- Content sourced from **MEMORY.md** or any user-memory index file — same reasoning: already-synthesized, not primary evidence.
- Content sourced from an existing **`feedback_*.md`** file — this is the exact promotion output of a prior `/audit style` (or manual) pass; treating it as new evidence for a new candidate would let the skill cite its own prior conclusions as independent corroboration, silently inflating confidence without new information.
If a candidate's only supporting quotes turn out to trace back to one of these sources on closer inspection, that quote does not count toward the Step 3 receipts gate — re-evaluate whether the remaining quotes (from genuine session prose) still clear the ≥2-distinct-session bar on their own.
## Step 4: Redact + Stage
For every candidate that survives Step 3's gate, redact each surviving quote before it is written anywhere. **Mirror `extract-user-prose.py`'s `REDACTIONS` list** — the same categories (API keys, JWTs, GitHub/Slack/AWS tokens, password/secret/api-key key-value pairs, email addresses, IP addresses) must be scrubbed from the quote text, using the same patterns the reference script applies, not a looser ad hoc pass.
**If a quote cannot be safely redacted** (e.g. the secret-shaped content is structurally entangled with the sentence such that redaction would either leave a recoverable fragment or destroy the quote's meaning entirely), **drop that quote** rather than writing it in a partially-redacted or risky state. If dropping the unsafe quote causes the candidate to fall below the Step 3 receipts bar, the candidate is dropped too (redaction failure cascades through the same fail-closed logic as an evidence failure).
Redaction happens here so the report, the card, and any write all use the redacted quotes. **No file is written in this step** — where the survivors go (staged to `rules-backlog.md`, promoted to `feedback_*.md`, or nothing) is the user's choice at the Step 6 disposition gate, made against the full report + card. The redacted survivors are simply held for Steps 5–6.
- **The write surface is fixed regardless of disposition:** staged survivors go to `{knowledge_folder}/intake/rules-backlog.md` (the `### YYYY-MM-DD — {title}` block below the `---` separator, rule statement + inline dated redacted receipts — the shape `/audit-knowledge` already expects). Promotion to `feedback_*.md` (or `rules/user-rules.md`) happens ONLY on the explicit promote-now disposition, and even then follows `/audit-knowledge`'s three-target logic. **The default disposition never writes `feedback_*.md`** — that stays a human-gated decision.
+ **The write surface is fixed regardless of disposition:** staged survivors go to `{knowledge_folder}/intake/rules-backlog.md` (the `### YYYY-MM-DD — {title}` block below the `---` separator, rule statement + inline dated redacted receipts — the shape `/audit knowledge` already expects). Promotion to `feedback_*.md` (or `rules/user-rules.md`) happens ONLY on the explicit promote-now disposition, and even then follows `/audit knowledge`'s three-target logic. **The default disposition never writes `feedback_*.md`** — that stays a human-gated decision.
## Step 5: Report (the report IS the preview — nothing is written yet)
Render the full report below to the user. **No file has been written at this point** — this report, together with the Working Style card, is what the Step 6 disposition decision is made against. This replaces the old separate preview gate: the report shows exactly what *would* be staged/promoted, so the user decides against the real content.
**Output policy (emit-all — this is a fixed-structure report):** `/audit style` is a fixed-structure skill, not a one-liner — a zero count carries information, and the zero-states below are *distinct signals the user must be able to tell apart*. Emit every subsection defined below on every run, including its explicit zero-state line when it has no content. Do NOT collapse or omit an empty subsection; a silent omission is indistinguishable from "the skill didn't run that check."
### Part A — Every rule, stated individually with reasoning
Both passed and dropped candidates are stated in full — never collapse the dropped set into per-reason counts alone. Each dropped rule gets its own line with its specific reason.
```
## /audit style — <window>
### ✅ Passed the receipts gate (M)
- **<rule statement>** [<D> distinct sessions · confidence: <high|medium>]
- why it passed: <one line — the recurring pattern the ≥2 sessions share>
- [<session-8> <date>] "<redacted verbatim quote>"
- [<session-8> <date>] "<redacted verbatim quote>"
(repeat per passing candidate — NOT capped at 3; state all M)
— zero-state: "0 passed — nothing eligible to stage this run."
### ✗ Dropped (K) — each rule + why
- **<candidate rule statement>** — dropped: <specific reason: single-session (only session X) | no verbatim quote | unredactable secret in only receipt | source-rejected (its evidence traced to a /command|CLAUDE.md|MEMORY|feedback_*)>
(repeat per dropped candidate — state the RULE and its REASON, not just a count bucket)
— zero-state: "0 dropped."
### Scan health
- Sessions scanned: <J> of <total-eligible> (over-cap choice, if any: <recent|all|window N>)
- Extractor: <clean | schema-drift on P file(s): list them> ← if P>0 this is NOT "no signal"; the extractor broke (Step 1 fail-loud) and those files were skipped
- Candidates drafted (Step 2): <N> · Mined prose messages: <total>
- In-session-only (NOT in the shareable card): contradictions surfaced (#11), project-weighting of the evidence (#14) — render these here if present, but they never go into the card file.
```
**The three distinguishable zero-states** (never conflate — each has a different user action):
1. **`0 passed`, candidates drafted, extractor clean** → the gate did its job; evidence was genuinely too thin. Action: none, or widen with `/audit style all`.
2. **`0 passed` because extractor hit schema-drift** → the tool broke, NOT "no signal." Surface the drifted files (Step 1); the log boundary must NOT advance for them. Action: fix the extractor/filter.
3. **`0 mined` / very few sessions scanned** → window too thin. Action: re-run wider.
### Part B — "Your Working Style" (the shareable card)
After the rules, render a **Your Working Style** section — an ARIA-native working profile. (It occupies the same role as ditto's profile card, but is derived independently from ARIA's own knowledge — rules, memory, decision artifacts — and must not copy ditto's labels, framing, or naming shapes; see the anti-copy ban in element #1.) It is made richer by what ARIA knows that raw logs can't. Render it inline in the report AND (per Step 5b) write it as a self-contained shareable card file. Include these elements — every one that has content; omit #10 entirely if no evolution is found:
1. **Reasoning Type** — a short label (2-3 words) summarizing how the user reasons/decides. **Derive it independently every run — do NOT reuse a stock label or ditto's naming shape.** Procedure: (a) take the **top 2-3 highest-corroboration rules** (by distinct-session count) plus the through-line; (b) name what *those specific rules* add up to, using ARIA's own vocabulary of working-role nouns — e.g. **Operator, Reasoner, Reviewer, Lead, Builder, Maintainer** — paired with an adjective drawn from the user's actual dominant discipline (proof / gate / ground-truth / root-cause / long-term / etc.). The label is a **summary of the user's own top rules**, not a personality archetype. **Hard ban (anti-copy):** never emit ditto's default framing or its shape — do NOT use "Evidence-First …", do NOT use the "`<Adjective>-First <Noun>`" pattern, and do NOT carry any label forward from a prior run or example. If the top rules are all about acting only on verified proof, a label like "Proof-Based Operator" fits; if they're about a fixed pre-mortem→execute ceremony, "Gate-Driven Lead" fits — but derive from *this run's* top rules, don't pick from a menu. (Call it **Reasoning Type**, never "archetype" — "archetype" is ditto's frame.)
2. **Through-line** — one sentence capturing the pattern under all the rules, worded in ARIA's own framing (e.g. "The discipline that earns autonomy: nothing is trusted — a prior decision, a metric, a 'done' claim — until re-verified against ground truth"), NOT ditto's "the uncomfortable one" label.
3. **Your Rules — Work** — ALL passed work-domain rules, ranked by corroboration (session count), not capped.
4. **Your Rules — Design Taste** — the passed design-domain rules.
5. **Your Rules — Writing Voice** — the passed write-domain rules, register-split (casual input vs professional deliverable).
6. **Coverage stats — every stat LABELED with what it means**, not bare numbers. E.g.: "Sessions mined: J (distinct Claude Code conversations) · Your messages: M (only your typed prose — tool output and skill injections were filtered out) · Text volume: ≈T tokens ≈ roughly P pages of your writing · Date range: <first>→<last> · Secrets auto-redacted before analysis: R." Never emit a raw token count without saying what it represents.
7. **Corroboration vs. existing memory** — for each passed rule, mark whether it **CONFIRMS** an existing `feedback_*.md`/`user-rules.md` entry (name it) or is **NEW** (not yet in memory). This is ARIA-unique — a raw-log tool cannot see the user's memory.
8. **Blind spots** — two kinds: (a) working-style dimensions ARIA HAS memory for but this mine found NO fresh evidence of (a discipline going quiet); and (b) **inferred blind spots the user may not be aware of** — asymmetries in the evidence itself (e.g. "every mined rule is about verification/correctness; none about when-to-stop-polishing or delegation-trust — that absence is itself a signal"). State (b) as a careful, falsifiable observation, not a diagnosis.
9. **Decision-discipline fingerprint** — derived from the user's *artifacts* (ADRs, `/prospect`+`/retrospect` logs, the change-decision-framework usage), not messages: how they structure decisions (e.g. gate-chain ceremony, 7-step framework, ADR-with-alternatives). ARIA-unique.
10. **Evolution / drift** — ONLY if the dated evidence + memory history actually show a rule changing over the range (e.g. "commit-vs-push tightened after a mid-June incident"). If no evolution is found, OMIT this element entirely — do not emit an empty "no evolution" line in the card.
12. **Consistency/confidence** — per rule, a high/medium confidence from session-spread (already on each rule in #3–#5).
13. **How to work with me** — a short, directive block an agent could load ("Before calling done, show it running live. Commit locally; never push unasked. On a fork you can verify, decide and show your work.").
15. **Anti-patterns I reject** — the rejection-criteria rules restated as "don'ts" (e.g. "Don't fake a green/screenshot. Don't expand a scoped fix. Don't push without asking.").
**Card is a strict subset of the report:** elements #11 (contradictions) and #14 (project-weighting) appear in Part A's Scan-health / in-session view ONLY — they must NOT be written into the shareable card file (a screenshot-safe artifact shouldn't name unresolved tensions or reveal what the user is working on). There is NO letter grade / seal (#16 excluded).
## Step 5b: Write the shareable card file
Write the Working Style card as a self-contained artifact to **`{knowledge_folder}/references/working-style/`**:
- `card-<YYYY-MM-DD>.html` — a standalone, styled, theme-aware HTML page (inline CSS, no external assets), containing elements #1–#9, #12, #13, #15 (NOT #11/#14). Dated filename so successive runs archive rather than clobber.
- `card-<YYYY-MM-DD>.md` — a markdown mirror of the same content, for diffing/grep.
Create `references/working-style/` if absent. This is the only file this skill writes unconditionally (it's a report artifact, not captured knowledge — it stages nothing and promotes nothing). If the user later declines all dispositions, the card still stands as a record of the run.
**Stamp `{knowledge_folder}/logs/style-audit-log.md`** (or `KT_STYLE_AUDIT_LOG`) with this run's timestamp + session-id range ONLY after a disposition that consumes the sessions (keep-staged or promote). On cancel, do NOT advance the boundary (the sessions stay eligible next run).
## Step 6: Disposition (single merged gate — default-first)
Present ONE decision. This is the only write-authorizing prompt (it absorbs the old preview gate — the report above already showed the exact content). Default is keep-as-recommended.
```
Disposition for the M passed rules:
[keep] Keep as recommended (default) — stage to rules-backlog.md for review
- at the next /audit-knowledge. Nothing written to feedback_*.md.
+ at the next /audit knowledge. Nothing written to feedback_*.md.
[promote] Promote the passed rules to user memory (feedback_*.md / user-rules.md)
- NOW, via /audit-knowledge's three-target logic.
+ NOW, via /audit knowledge's three-target logic.
[specify] Decide per-rule, or something else (tell me).
[cancel] Write nothing (the card file already saved; sessions stay eligible next run).
Press Enter / "keep" for the default.
```
- - **`keep` (default, incl. bare Enter / any non-committal reply):** append the M passed rules to `rules-backlog.md` (Step 4's shape); they flow through `/audit-knowledge`'s existing `rule` disposition on the user's normal cadence. **Nothing is written to `feedback_*.md`.** Advance the audit-log boundary.
- - **`promote`:** the user has explicitly authorized direct promotion — write the passed rules to `feedback_*.md` (or `rules/user-rules.md` for cross-project ARIA-behavior rules, or a project-tier `working-rules.md`) per `/audit-knowledge`'s three-target logic. This is the ONLY path that writes user memory, and only on this explicit choice. Advance the boundary.
+ - **`keep` (default, incl. bare Enter / any non-committal reply):** append the M passed rules to `rules-backlog.md` (Step 4's shape); they flow through `/audit knowledge`'s existing `rule` disposition on the user's normal cadence. **Nothing is written to `feedback_*.md`.** Advance the audit-log boundary.
+ - **`promote`:** the user has explicitly authorized direct promotion — write the passed rules to `feedback_*.md` (or `rules/user-rules.md` for cross-project ARIA-behavior rules, or a project-tier `working-rules.md`) per `/audit knowledge`'s three-target logic. This is the ONLY path that writes user memory, and only on this explicit choice. Advance the boundary.
- **`specify`:** surface the passed rules and take per-rule instructions (stage some, promote some, drop some) or any freeform direction. Follow it exactly; never invent a disposition the user didn't give.
- **`cancel`:** write nothing to backlog or memory; the card file from Step 5b remains. Do NOT advance the audit-log boundary.
- **Restate the invariants:** `/audit style` is **opt-in only** (no cadence/SessionStart/threshold trigger — explicit invocation only), and its **default never writes `feedback_*.md`** — direct promotion happens only on the explicit `promote`/`specify` choice; otherwise memory is reached only through the human-gated `/audit-knowledge` review, same as any other rule-backlog entry.
+ **Restate the invariants:** `/audit style` is **opt-in only** (no cadence/SessionStart/threshold trigger — explicit invocation only), and its **default never writes `feedback_*.md`** — direct promotion happens only on the explicit `promote`/`specify` choice; otherwise memory is reached only through the human-gated `/audit knowledge` review, same as any other rule-backlog entry.
---
## /audit-usage
# /audit usage — Value/ROI Self-Analysis
+ Canonical invocation: **`/audit usage`**. The direct `/audit-usage` form is retained for compatibility and is not advertised.
+
Generate a value-analysis report computed against the user's OWN knowledge corpus — the user-facing counterpart to the plugin's published `docs/value-analysis.md` (which is the author's N=1 digest). Deterministic metrics come from `bin/usage-metrics.sh`; the interpretive narrative is written here, gated on sample size.
## Step 0: Resolve Config
Read `.cursor/aria-knowledge.local.md`; extract `knowledge_folder`. If missing: stop with "aria-knowledge is not configured. Run /setup to get started."
## Step 1: Gather Metrics
Run the deterministic emitter once:
bash scripts/aria/usage-metrics.sh
Parse the labeled block (each line is `KEY value`, or `KEY subkey value` for month buckets). If the output contains `USAGE_METRICS_ERROR`, stop and tell the user their knowledge_folder is unset or missing.
If `PROSPECT_TOTAL` and `RETRO_TOTAL` are both 0: stop with "No prospect/retrospect history yet — run some /prospect and /retrospect cycles, then check back. (Cost-surface metrics are still available; say 'cost only' to see them.)" Do not fabricate a report.
## Step 2: Write the Analysis (sample-size honest)
Compose the report over the user's numbers. Sections:
1. **TL;DR** — one-line verdicts (needs-changes rate = `PROSPECT_PWC`/`PROSPECT_TOTAL`, clean rate, per-fix-verdict rate = `RETRO_VERDICT_FILES`/`RETRO_TOTAL`, fixed cost = `SKILL_DISCOVERY_BYTES`÷4 tokens).
2. **Cost surface** — `SKILL_DISCOVERY_BYTES` (÷4 ≈ tokens), `SKILL_COUNT`, per-session floor note; state it's the universal fixed cost every session pays (mostly cache-eligible if the session stays warm).
3. **Quality — plan rigor** — prospect distribution table with `n = PROSPECT_TOTAL`. Interpret the PWC/clean/hold split (PWC = plans that needed pre-execution correction).
4. **Quality — validation discipline** — retrospect outcome table (`RETRO_CLOSED`/`PARTIAL`/`MIXED`/`UNRESOLVED`) + per-fix-verdict rate.
5. **Trends** — month tables from `PROSPECT_MONTH` / `RETRO_MONTH` **only for months whose total ≥ 10 logs**. Any month below 10: omit from the table and note "insufficient sample — directional only." If NO month clears 10, print "Not enough history for a trend yet (need ≥10 logs in a month)." — no table.
6. **Confounds + limits** — always include the standing caveats: author-learning, the tool trains its own user, work-mix shift; and the N=1 limit (this is the user's own corpus, not a controlled study — no counterfactual proof that uncorrected plans would have shipped wrong).
Never assert "improving over time" unless at least two months each clear the ≥10 threshold AND the direction is monotonic. Otherwise say "directional only."
## Step 3: Persist
Write `{knowledge_folder}/references/usage-analysis.md` (full rewrite each run) with frontmatter — get the timestamp via `date -u +%Y-%m-%dT%H:%M:%SZ`:
---
synthesized_at: <UTC now>
measured_at_corpus: <PROSPECT_TOTAL>/<RETRO_TOTAL>
plugin_version: <from plugin.json if resolvable, else "unknown">
---
followed by the Step 2 report body. This is the one file the skill creates. Create the `references/` directory if absent.
## Step 4: Report
Print a 3-4 line inline summary (needs-changes rate, clean rate, per-fix-verdict rate, fixed-token cost) and "Full report written to {knowledge_folder}/references/usage-analysis.md".
## Rules
- - **Opt-in only** — never fired by a cadence nudge; only explicit `/audit usage`, `/audit all`, or menu pick.
+ - **Opt-in only** — never fired by a cadence nudge; only explicit `/audit usage` or a menu pick.
- **Honest on small samples** — print every `n`; gate trends on ≥10/month; never fabricate on a zero corpus.
- **Metrics are the script's job** — do not re-derive counts inline; `bin/usage-metrics.sh` is the single source of truth. The skill only interprets and persists.
- **The user's corpus, not the author's** — the report reflects THIS user's logs; do not import the published doc's numbers.