diff --git a/plugins/dev-team/agents/software-engineer.md b/plugins/dev-team/agents/software-engineer.md index 385ae8c19..462dc0e11 100644 --- a/plugins/dev-team/agents/software-engineer.md +++ b/plugins/dev-team/agents/software-engineer.md @@ -9,11 +9,6 @@ skills: - quality-gate-pipeline - test-driven-development - systematic-debugging - - hexagonal-architecture - - domain-driven-design - - api-design - - legacy-code - - mutation-testing - code-review memory: project --- @@ -59,15 +54,20 @@ Three reflexes that fire at the moment code is written — not just at review ti ## Skills +Preloaded on every dispatch (`skills:` frontmatter, ADR 0028): + - [Quality Gate Pipeline](../skills/quality-gate-pipeline/SKILL.md) - invoke before delivery (Phase 1: self-validation), before completion claims (Phase 2: verification evidence), and during rework (Phase 3: review-correction loop) - [Test-Driven Development](../skills/test-driven-development/SKILL.md) - advisory RED-GREEN-REFACTOR methodology reference; invoke only on explicit request or for after-the-fact discipline audits. `/build`'s single cadence is Code-First Small Batches — implement one behavior, write its test, refactor on every green (`docs/experiments/RECOMMENDATIONS.md` Rec 3); the refactor step is mandatory - [Systematic Debugging](../skills/systematic-debugging/SKILL.md) - invoke when any test fails or unexpected behavior occurs; no guess-and-fix. Its Phase 4 is a hard gate for every defect fix — reproduce the bug with a failing test before writing fix code — regardless of the advisory-only status of Test-Driven Development above +- [Code Review](../skills/code-review/SKILL.md) - invoked by orchestrator after each discrete unit of work and before committing; do not invoke independently. Preloaded so review feedback (Review Feedback Protocol above) reads against context this agent already has, not context it has to fetch mid-correction + +On-demand — invoke explicitly when the condition applies; **not** in `skills:` frontmatter, so a step that never touches one of these pays nothing for it (#2109: these five, unconditionally preloaded, were ~17K tokens of per-dispatch baseline that a `/build` step touching none of them still paid for on every turn): + - [Hexagonal Architecture](../skills/hexagonal-architecture/SKILL.md) - invoke when structuring new services or modules with port/adapter separation - [Domain-Driven Design](../skills/domain-driven-design/SKILL.md) - invoke when modeling business domains, defining aggregates, or mapping bounded contexts - [API Design](../skills/api-design/SKILL.md) - invoke when implementing APIs to verify contract compliance - [Legacy Code](../skills/legacy-code/SKILL.md) - invoke when modifying or extending code that lacks test coverage or has poor structure - [Mutation Testing](../skills/mutation-testing/SKILL.md) - invoke when assessing whether tests for new or modified code are catching meaningful faults -- [Code Review](../skills/code-review/SKILL.md) - invoked by orchestrator after each discrete unit of work and before committing; do not invoke independently ## Knowledge Files @@ -87,6 +87,7 @@ When the orchestrator sends review findings as correction context: ## Constraints - When running Bash `git` commands outside a wave-isolated worktree (e.g. the no-plan fast path or any inline-review fix loop that operates directly in the orchestrator's shared working tree), stage and commit **only** the specific files your current unit of work touched — never `git add -A`, `git add .`, or `git commit -a`. Repo-wide staging in the shared tree can sweep in a sibling agent's or the operator's unrelated changes. Inside a wave-isolated worktree the tree is already isolated (see `agents/orchestrator.md` § Wave-Aware Build Dispatch), so this constraint targets the in-session, non-worktree path. +- **Self-verification before signaling any step or task done, mandatory (#2107).** Run the project's own tests, lint, and type-check tools — whichever apply to its stack, when the project has them — and confirm fresh, current-session output shows them passing before reporting completion. This is [Quality Gate Pipeline](../skills/quality-gate-pipeline/SKILL.md) Phase 2's "Required Evidence" made a hard constraint rather than an invocable skill you might defer: a "should work now" / "should be fixed" / "probably" is never a substitute for pasted, current-run evidence, and a claim resting on output from earlier in the conversation is not verification. [`/build`](../skills/build/SKILL.md)'s own cadence (sub-steps 3 and 5) enforces the same bar mechanically at each step boundary — this constraint holds even when dispatched outside that cadence (e.g. a standalone fix, an inline review-fix iteration). ## Behavioral Guidelines diff --git a/plugins/dev-team/docs/skills.md b/plugins/dev-team/docs/skills.md index 8ca25b2d5..79e693ef0 100644 --- a/plugins/dev-team/docs/skills.md +++ b/plugins/dev-team/docs/skills.md @@ -15,172 +15,172 @@ Most skills are **user-invocable** as slash commands — shown as `/name`; run t | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/api-design` | no flags — run directly | [`api-design/SKILL.md`](../skills/api-design/SKILL.md) | Contract-first API design for stable, evolvable interfaces. Use whenever defining a new API endpoint, inter-service boundary, or modifying an existing contract. Includes backward compatibility checklist and error contract specification. | -| `/design-doc` | no flags — run directly | [`design-doc/SKILL.md`](../skills/design-doc/SKILL.md) | Produce a written design document in docs/specs/ with user approval before planning begins. Use this skill during the Research phase when a feature request, architectural change, or non-trivial task enters the pipeline. Ensures misunderstandings are caught before any planning or implementation work starts. Also use when the user says "brainstorm", "design", "spec", or "let's think through this". | -| `/design-interrogation` | no flags — run directly | [`design-interrogation/SKILL.md`](../skills/design-interrogation/SKILL.md) | Relentlessly interview the user about a plan, design, or feature spec to surface unresolved decisions, hidden assumptions, and edge cases. Use when the user says "grill me", "stress-test this plan", "poke holes in my design", "what am I missing", or before committing to a plan that feels under-examined. Unlike /specs (which produces artifacts) this skill produces clarity — it's a thinking tool. Also use proactively in the Research phase when a design doc has implicit decisions that need to be made explicit. | -| `/design-it-twice` | no flags — run directly | [`design-it-twice/SKILL.md`](../skills/design-it-twice/SKILL.md) | Generate multiple radically different interface designs for a module using parallel sub-agents, then compare and synthesize. Based on Ousterhout's "Design It Twice" principle. Use when the user wants to explore interface options, design an API, compare module shapes, or says "design it twice", "what are my options", or "show me alternatives". Also use when the Architect agent is designing a new module boundary or public interface. | -| `/feature-file-validation` | no flags — run directly | [`feature-file-validation/SKILL.md`](../skills/feature-file-validation/SKILL.md) | Validate Gherkin feature files for structural quality, determinism, and implementation independence, then verify each scenario has matching test automation. Use this skill whenever reviewing test files, feature files, or BDD scenarios — including during /code-review when .feature files or step definition files appear in the changeset. Also use when a user asks to "check my feature files", "validate my Gherkin", "are my scenarios testable", or "do my feature files have tests". | -| `/gherkin-derive` | [--mode none\|xunit-with-annotations\|bdd-runner] [--repo-slug ] | [`gherkin-derive/SKILL.md`](../skills/gherkin-derive/SKILL.md) | Derive Gherkin scenarios directly from a codebase — standalone, with no prior legacy-modernization analysis. Discovers the public surface (OpenAPI, routes, existing tests, exported signatures, plus message-queue, cron, and websocket/GraphQL surfaces), recommends a BDD binding mode via the bdd-value-guide rubric, and merges scenarios into `.feature` files (preserving prior enrichment, never overwriting) plus (in bdd-runner mode) pending step-definition stubs. Use it on its own to capture intended behavior before changing tests, or as Phase 3 of `/test-improve`. Creates no tracker Stories. | -| `/gherkin-public` | [--repo-slug ] [--parent ] [--create-stories] | [`gherkin-public/SKILL.md`](../skills/gherkin-public/SKILL.md) | Author Gherkin scenarios for the entire public interface of a repository — every API endpoint, UI screen, batch-job entry point, library export, and event type — at the observable boundary, not internal steps. The scenarios become the executable specification of intended behavior before any test or production-code change lands. After the operator approves the scenarios at the Phase-2 gate, this skill also creates the Phase-4 and Phase-5 `[Component tests]` Stories that will bind their test code to specific scenario names — so the component tests are written from the approved Gherkin, not from the assessment. | -| `/issues-from-assessment` | [--parent ] [--repo-slug ] [--workflow ] [--refactor-mode ] [--dry-run] | [`issues-from-assessment/SKILL.md`](../skills/issues-from-assessment/SKILL.md) | Convert a `/cd-test-architecture` assessment into a parent + Phase-tagged child issues on the tracker the operator points at (ADO, GitHub, GitLab, Jira). Dispatches by parent URL host to the tracker's own CLI (`az boards`, `gh`, `glab`, `acli`). When no parent URL is given, or when the required CLI is not installed, falls back to local plan files under `.claude/plans//` after informing the operator. Multi-workflow: called by `/test-improve` (Phase 4), via its own `--workflow` namespace so memory paths and tracker labels never collide. | -| `/issues-from-plan` | [plan file path] | [`issues-from-plan/SKILL.md`](../skills/issues-from-plan/SKILL.md) | Break a plan into independently-grabbable GitHub issues. Use when the user says "create issues from this plan", "break this into tickets", "file issues", or wants to distribute plan steps across a team. | -| `/plan` | [--output ] [--yes] [--spec-issue ] | [`plan/SKILL.md`](../skills/plan/SKILL.md) | Create a structured implementation plan with goal, acceptance criteria, incremental Code-First Small Batches steps, and a pre-PR quality gate. Use this for tasks that need a plan but not the full three-phase orchestration, or when the user says "plan this", "make a plan", "break this down", or "how should I implement this". | -| `/specs` | no flags — run directly | [`specs/SKILL.md`](../skills/specs/SKILL.md) | Collaborative workflow for producing the three specification artifacts (intent, architecture notes, acceptance criteria) that describe a change and its goals before any implementation begins. Its value is resolving ambiguity with a human before build starts — not synthesizing edge cases. Use when starting any new feature or behavior change — do not write code until artifacts pass the consistency gate. BDD/Gherkin scenarios are authored later, per slice, in /plan. | +| `/api-design` | no flags — run directly | [`api-design/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/api-design/SKILL.md) | Contract-first API design for stable, evolvable interfaces. Use whenever defining a new API endpoint, inter-service boundary, or modifying an existing contract. Includes backward compatibility checklist and error contract specification. | +| `/design-doc` | no flags — run directly | [`design-doc/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/design-doc/SKILL.md) | Produce a written design document in docs/specs/ with user approval before planning begins. Use this skill during the Research phase when a feature request, architectural change, or non-trivial task enters the pipeline. Ensures misunderstandings are caught before any planning or implementation work starts. Also use when the user says "brainstorm", "design", "spec", or "let's think through this". | +| `/design-interrogation` | no flags — run directly | [`design-interrogation/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/design-interrogation/SKILL.md) | Relentlessly interview the user about a plan, design, or feature spec to surface unresolved decisions, hidden assumptions, and edge cases. Use when the user says "grill me", "stress-test this plan", "poke holes in my design", "what am I missing", or before committing to a plan that feels under-examined. Unlike /specs (which produces artifacts) this skill produces clarity — it's a thinking tool. Also use proactively in the Research phase when a design doc has implicit decisions that need to be made explicit. | +| `/design-it-twice` | no flags — run directly | [`design-it-twice/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/design-it-twice/SKILL.md) | Generate multiple radically different interface designs for a module using parallel sub-agents, then compare and synthesize. Based on Ousterhout's "Design It Twice" principle. Use when the user wants to explore interface options, design an API, compare module shapes, or says "design it twice", "what are my options", or "show me alternatives". Also use when the Architect agent is designing a new module boundary or public interface. | +| `/feature-file-validation` | no flags — run directly | [`feature-file-validation/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/feature-file-validation/SKILL.md) | Validate Gherkin feature files for structural quality, determinism, and implementation independence, then verify each scenario has matching test automation. Use this skill whenever reviewing test files, feature files, or BDD scenarios — including during /code-review when .feature files or step definition files appear in the changeset. Also use when a user asks to "check my feature files", "validate my Gherkin", "are my scenarios testable", or "do my feature files have tests". | +| `/gherkin-derive` | [--mode none\|xunit-with-annotations\|bdd-runner] [--repo-slug ] | [`gherkin-derive/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/gherkin-derive/SKILL.md) | Derive Gherkin scenarios directly from a codebase — standalone, with no prior legacy-modernization analysis. Discovers the public surface (OpenAPI, routes, existing tests, exported signatures, plus message-queue, cron, and websocket/GraphQL surfaces), recommends a BDD binding mode via the bdd-value-guide rubric, and merges scenarios into `.feature` files (preserving prior enrichment, never overwriting) plus (in bdd-runner mode) pending step-definition stubs. Use it on its own to capture intended behavior before changing tests, or as Phase 3 of `/test-improve`. Creates no tracker Stories. | +| `/gherkin-public` | [--repo-slug ] [--parent ] [--create-stories] | [`gherkin-public/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/gherkin-public/SKILL.md) | Author Gherkin scenarios for the entire public interface of a repository — every API endpoint, UI screen, batch-job entry point, library export, and event type — at the observable boundary, not internal steps. The scenarios become the executable specification of intended behavior before any test or production-code change lands. After the operator approves the scenarios at the Phase-2 gate, this skill also creates the Phase-4 and Phase-5 `[Component tests]` Stories that will bind their test code to specific scenario names — so the component tests are written from the approved Gherkin, not from the assessment. | +| `/issues-from-assessment` | [--parent ] [--repo-slug ] [--workflow ] [--refactor-mode ] [--dry-run] | [`issues-from-assessment/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/issues-from-assessment/SKILL.md) | Convert a `/cd-test-architecture` assessment into a parent + Phase-tagged child issues on the tracker the operator points at (ADO, GitHub, GitLab, Jira). Dispatches by parent URL host to the tracker's own CLI (`az boards`, `gh`, `glab`, `acli`). When no parent URL is given, or when the required CLI is not installed, falls back to local plan files under `.claude/plans//` after informing the operator. Multi-workflow: called by `/test-improve` (Phase 4), via its own `--workflow` namespace so memory paths and tracker labels never collide. | +| `/issues-from-plan` | [plan file path] | [`issues-from-plan/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/issues-from-plan/SKILL.md) | Break a plan into independently-grabbable GitHub issues. Use when the user says "create issues from this plan", "break this into tickets", "file issues", or wants to distribute plan steps across a team. | +| `/plan` | [--output ] [--yes] [--spec-issue ] | [`plan/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/plan/SKILL.md) | Create a structured implementation plan with goal, acceptance criteria, incremental Code-First Small Batches steps, and a pre-PR quality gate. Use this for tasks that need a plan but not the full three-phase orchestration, or when the user says "plan this", "make a plan", "break this down", or "how should I implement this". | +| `/specs` | no flags — run directly | [`specs/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/specs/SKILL.md) | Collaborative workflow for producing the three specification artifacts (intent, architecture notes, acceptance criteria) that describe a change and its goals before any implementation begins. Its value is resolving ambiguity with a human before build starts — not synthesizing edge cases. Use when starting any new feature or behavior change — do not write code until artifacts pass the consistency gate. BDD/Gherkin scenarios are authored later, per slice, in /plan. | ## Build & Ship | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/autoship` | --max-issues N --max-cost-usd N [--dry-run] [--label LABEL] [--max-batch-size N] | [`autoship/SKILL.md`](../skills/autoship/SKILL.md) | Orchestrate a bounded round of automated issue processing: reclaim orphaned in-progress issues, discover eligible `autoship:ready` issues, and invoke `/ship` sequentially for each — stopping at cost or count caps and surfacing blocked items without halting the round. Requires `--max-issues` and `--max-cost-usd`. Use when you want a self-contained automated delivery round driven from the issue tracker. | -| `/branch-workflow` | no flags — run directly | [`branch-workflow/SKILL.md`](../skills/branch-workflow/SKILL.md) | Clean branch completion workflow — PR creation, merge strategy, and cleanup. Use this skill when implementation is complete and it's time to ship — after Phase 3 human gate passes. Also use when the user says "create a PR", "merge this", "ship it", "finish this branch", or asks about merge strategy. | -| `/build` | [--plan ] [--yes] [--backstop-review=skip] | [`build/SKILL.md`](../skills/build/SKILL.md) | Execute an approved implementation plan in small per-behavior batches. Reads the plan, implements each step one behavior at a time in the Code-First Small Batches cadence with a refactor on every green, runs inline review checkpoints, and produces verification evidence. Use when the user says "build this", "implement the plan", "start building", or after /plan has been approved. | -| `/continue` | no flags — run directly | [`continue/SKILL.md`](../skills/continue/SKILL.md) | Resume work from a prior session by reading phase progress files in .claude/memory/ and active plans. Use this when starting a new session on in-progress work, or when the user says "continue", "pick up where I left off", "resume", or "what was I working on". | -| `/pr` | [--skip-review] [--draft] [--base ] | [`pr/SKILL.md`](../skills/pr/SKILL.md) | Run a pre-PR quality gate (tests, typecheck, lint, code review) and then create a pull request with a structured summary. Use when the user says "create a PR", "open a PR", "submit for review", or "I'm done with this feature". | -| `/ship` | [--skip-spec] [--no-auto-merge] [--force-restart] [--issues ] | [`ship/SKILL.md`](../skills/ship/SKILL.md) | Run the full spec-to-merge pipeline as one command: spec, plan, small-batch build, code review, and a PR with auto-merge — pausing at the existing human gates. Idempotent per issue — a re-invocation for work already shipped or in-flight resumes/monitors instead of re-running the pipeline. Use when the user says "ship this", "take this feature end to end", "implement this issue", "we need to build", or wants the spec->plan->build->PR flow without re-assembling it each time. | -| `/test-driven-development` | no flags — run directly | [`test-driven-development/SKILL.md`](../skills/test-driven-development/SKILL.md) | Advisory reference for the Classic RED-GREEN-REFACTOR TDD discipline with hard gates — not a build cadence toggle. The plugin's single build cadence is Code-First Small Batches (docs/experiments/RECOMMENDATIONS.md Rec 3); /build does not dispatch into this skill. Use on explicit user request when someone wants test-first discipline for the code being written, or when reviewing code to verify TDD discipline was followed by hand. | +| `/autoship` | --max-issues N --max-cost-usd N [--dry-run] [--label LABEL] [--max-batch-size N] | [`autoship/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/autoship/SKILL.md) | Orchestrate a bounded round of automated issue processing: reclaim orphaned in-progress issues, discover eligible `autoship:ready` issues, and invoke `/ship` sequentially for each — stopping at cost or count caps and surfacing blocked items without halting the round. Requires `--max-issues` and `--max-cost-usd`. Use when you want a self-contained automated delivery round driven from the issue tracker. | +| `/branch-workflow` | no flags — run directly | [`branch-workflow/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/branch-workflow/SKILL.md) | Clean branch completion workflow — PR creation, merge strategy, and cleanup. Use this skill when implementation is complete and it's time to ship — after Phase 3 human gate passes. Also use when the user says "create a PR", "merge this", "ship it", "finish this branch", or asks about merge strategy. | +| `/build` | [--plan ] [--yes] [--backstop-review=skip] | [`build/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/build/SKILL.md) | Execute an approved implementation plan in small per-behavior batches. Reads the plan, implements each step one behavior at a time in the Code-First Small Batches cadence with a refactor on every green, runs inline review checkpoints, and produces verification evidence. Use when the user says "build this", "implement the plan", "start building", or after /plan has been approved. | +| `/continue` | no flags — run directly | [`continue/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/continue/SKILL.md) | Resume work from a prior session by reading phase progress files in .claude/memory/ and active plans. Use this when starting a new session on in-progress work, or when the user says "continue", "pick up where I left off", "resume", or "what was I working on". | +| `/pr` | [--skip-review] [--draft] [--base ] | [`pr/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/pr/SKILL.md) | Run a pre-PR quality gate (tests, typecheck, lint, code review) and then create a pull request with a structured summary. Use when the user says "create a PR", "open a PR", "submit for review", or "I'm done with this feature". | +| `/ship` | [--skip-spec] [--no-auto-merge] [--force-restart] [--issues ] | [`ship/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/ship/SKILL.md) | Run the full spec-to-merge pipeline as one command: spec, plan, small-batch build, code review, and a PR with auto-merge — pausing at the existing human gates. Idempotent per issue — a re-invocation for work already shipped or in-flight resumes/monitors instead of re-running the pipeline. Use when the user says "ship this", "take this feature end to end", "implement this issue", "we need to build", or wants the spec->plan->build->PR flow without re-assembling it each time. | +| `/test-driven-development` | no flags — run directly | [`test-driven-development/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/test-driven-development/SKILL.md) | Advisory reference for the Classic RED-GREEN-REFACTOR TDD discipline with hard gates — not a build cadence toggle. The plugin's single build cadence is Code-First Small Batches (docs/experiments/RECOMMENDATIONS.md Rec 3); /build does not dispatch into this skill. Use on explicit user request when someone wants test-first discipline for the code being written, or when reviewing code to verify TDD discipline was followed by hand. | ## Code Review & Static Analysis | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/apply-fixes` | [--dry] [--skip-tests] [--skip-build] [--skip-lint] | [`apply-fixes/SKILL.md`](../skills/apply-fixes/SKILL.md) | Apply correction prompts generated by /code-review. Use this whenever the user wants to apply, fix, or action the results of a code review — phrases like "apply the fixes", "fix the issues", "apply corrections", or after /code-review has run and produced a corrections/ directory. | -| `/code-review` | [--agent ] [--since ] [--path ] [--all] [--json] [--internal] [--force --reason ""] [--static-analysis\|--no-static-analysis] [--init-risks] [--background] [--pdf] | [`code-review/SKILL.md`](../skills/code-review/SKILL.md) | Run all enabled review agents against target files. Use this whenever the user asks for a code review, wants feedback on their code, says "review my code", "check this before I PR", "what's wrong with this", "run the agents", or has just finished implementing a feature. Use proactively before commits and pull requests. | -| `/frontend-architecture` | [--path ] [--since ] [--all] [--json] | [`frontend-architecture/SKILL.md`](../skills/frontend-architecture/SKILL.md) | Frontend component architecture review — dispatch the component-architecture-review agent over the frontend component files to catch reusable components that should be extracted, duplicated UI patterns, prop drilling, component-granularity problems, and inconsistent component APIs as a frontend evolves. Use when the user says "review the frontend architecture", "are my components reusable", "is this UI duplicated", "should this be a shared component", "check for prop drilling", or before extracting a component library. Advisory — it recommends, it does not edit. | -| `/review` | [--agent ] [--since ] [--path ] [--all] [--json] [--internal] [--force --reason ""] [--static-analysis\|--no-static-analysis] [--init-risks] [--background] | [`review/SKILL.md`](../skills/review/SKILL.md) | Alias for /code-review. Run all enabled review agents against target files. Use this whenever the user asks for a code review, wants feedback on their code, says "review my code", "check this before I PR", "what's wrong with this", "run the agents", or has just finished implementing a feature. | -| `/review-agent` | [--since ] [--path ] [--internal] [--json] | [`review-agent/SKILL.md`](../skills/review-agent/SKILL.md) | Run a single named review agent against target files. Use this when the user names a specific agent (e.g. "run security-review", "check for test issues", "run js-fp-review on this file") rather than wanting the full suite. Prefer this over /code-review when only one concern is relevant or speed matters. Also used by the orchestrator for inline review checkpoints during Phase 3 implementation. | -| `/review-summary` | [--from ] | [`review-summary/SKILL.md`](../skills/review-summary/SKILL.md) | Generate a compact summary of the most recent code review results and save it for future sessions. Use this at the end of a coding session after /code-review has run, or when the user says "summarize the review", "save the results", "generate a summary", or wants to preserve review context before closing a session. | -| `/semantic-duplication-scan` | no flags — run directly | [`semantic-duplication-scan/SKILL.md`](../skills/semantic-duplication-scan/SKILL.md) | Detect business logic reimplemented in multiple architectural layers. Builds a persistent computation-register.json by annotating non-trivial computation functions with structured semantic descriptions, then clusters entries to surface duplicate domain concepts. Runs in full-scan mode on first use, incremental (git-diff-based) mode on subsequent runs. Use when the user wants to find logical duplication that linters and diff-scoped review agents miss — the same domain calculation independently reimplemented across layers. | -| `/semantic-scan` | [path] [--full] [--no-opus] | [`semantic-scan/SKILL.md`](../skills/semantic-scan/SKILL.md) | Build a computation register and detect semantic duplicates across architectural layers. Finds business logic reimplemented multiple times in different layers — the same domain calculation independently appearing in domain services, client adapters, and presentation components. Runs incrementally (git-diff-based) after the first scan. Produces a structured duplicate report with file:line references and canonical location suggestions. | -| `/semgrep-analyze` | [path] [--rules ] | [`semgrep-analyze/SKILL.md`](../skills/semgrep-analyze/SKILL.md) | Run Semgrep static analysis on target files and return structured findings. Use this when the user wants static analysis, SAST scanning, or security scanning — phrases like "run semgrep", "scan for vulnerabilities", "static analysis on this code", or as a pre-review gate when security findings are needed before AI agents run. | -| static-analysis-integration | agent-loaded — not directly invocable | [`static-analysis-integration/SKILL.md`](../skills/static-analysis-integration/SKILL.md) | SARIF-first pre-pass stage for /code-review that runs available static analysis tools and normalizes their output to the unified finding envelope defined in security-primitives-contract v1.0.0. Deduplicates findings across tools and passes confirmed issues to AI agents so they can focus on semantic concerns. | +| `/apply-fixes` | [--dry] [--skip-tests] [--skip-build] [--skip-lint] | [`apply-fixes/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/apply-fixes/SKILL.md) | Apply correction prompts generated by /code-review. Use this whenever the user wants to apply, fix, or action the results of a code review — phrases like "apply the fixes", "fix the issues", "apply corrections", or after /code-review has run and produced a corrections/ directory. | +| `/code-review` | [--agent ] [--since ] [--path ] [--all] [--json] [--internal] [--force --reason ""] [--static-analysis\|--no-static-analysis] [--init-risks] [--background] [--pdf] | [`code-review/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/code-review/SKILL.md) | Run all enabled review agents against target files. Use this whenever the user asks for a code review, wants feedback on their code, says "review my code", "check this before I PR", "what's wrong with this", "run the agents", or has just finished implementing a feature. Use proactively before commits and pull requests. | +| `/frontend-architecture` | [--path ] [--since ] [--all] [--json] | [`frontend-architecture/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/frontend-architecture/SKILL.md) | Frontend component architecture review — dispatch the component-architecture-review agent over the frontend component files to catch reusable components that should be extracted, duplicated UI patterns, prop drilling, component-granularity problems, and inconsistent component APIs as a frontend evolves. Use when the user says "review the frontend architecture", "are my components reusable", "is this UI duplicated", "should this be a shared component", "check for prop drilling", or before extracting a component library. Advisory — it recommends, it does not edit. | +| `/review` | [--agent ] [--since ] [--path ] [--all] [--json] [--internal] [--force --reason ""] [--static-analysis\|--no-static-analysis] [--init-risks] [--background] | [`review/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/review/SKILL.md) | Alias for /code-review. Run all enabled review agents against target files. Use this whenever the user asks for a code review, wants feedback on their code, says "review my code", "check this before I PR", "what's wrong with this", "run the agents", or has just finished implementing a feature. | +| `/review-agent` | [--since ] [--path ] [--internal] [--json] | [`review-agent/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/review-agent/SKILL.md) | Run a single named review agent against target files. Use this when the user names a specific agent (e.g. "run security-review", "check for test issues", "run js-fp-review on this file") rather than wanting the full suite. Prefer this over /code-review when only one concern is relevant or speed matters. Also used by the orchestrator for inline review checkpoints during Phase 3 implementation. | +| `/review-summary` | [--from ] | [`review-summary/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/review-summary/SKILL.md) | Generate a compact summary of the most recent code review results and save it for future sessions. Use this at the end of a coding session after /code-review has run, or when the user says "summarize the review", "save the results", "generate a summary", or wants to preserve review context before closing a session. | +| `/semantic-duplication-scan` | no flags — run directly | [`semantic-duplication-scan/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/semantic-duplication-scan/SKILL.md) | Detect business logic reimplemented in multiple architectural layers. Builds a persistent computation-register.json by annotating non-trivial computation functions with structured semantic descriptions, then clusters entries to surface duplicate domain concepts. Runs in full-scan mode on first use, incremental (git-diff-based) mode on subsequent runs. Use when the user wants to find logical duplication that linters and diff-scoped review agents miss — the same domain calculation independently reimplemented across layers. | +| `/semantic-scan` | [path] [--full] [--no-opus] | [`semantic-scan/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/semantic-scan/SKILL.md) | Build a computation register and detect semantic duplicates across architectural layers. Finds business logic reimplemented multiple times in different layers — the same domain calculation independently appearing in domain services, client adapters, and presentation components. Runs incrementally (git-diff-based) after the first scan. Produces a structured duplicate report with file:line references and canonical location suggestions. | +| `/semgrep-analyze` | [path] [--rules ] | [`semgrep-analyze/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/semgrep-analyze/SKILL.md) | Run Semgrep static analysis on target files and return structured findings. Use this when the user wants static analysis, SAST scanning, or security scanning — phrases like "run semgrep", "scan for vulnerabilities", "static analysis on this code", or as a pre-review gate when security findings are needed before AI agents run. | +| static-analysis-integration | agent-loaded — not directly invocable | [`static-analysis-integration/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/static-analysis-integration/SKILL.md) | SARIF-first pre-pass stage for /code-review that runs available static analysis tools and normalizes their output to the unified finding envelope defined in security-primitives-contract v1.0.0. Deduplicates findings across tools and passes confirmed issues to AI agents so they can focus on semantic concerns. | ## Testing & Coverage | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/apply-test-doubles` | [] [--component ] [--yes] | [`apply-test-doubles/SKILL.md`](../skills/apply-test-doubles/SKILL.md) | Apply `/cd-test-architecture`'s Step 4b build-vs-document decision logic against an existing, saved assessment report — or, when no valid report path is given, against a target to assess first — without re-running the full Steps 0-6 assessment each time. Use when the user wants to revisit or change a component's Build/Document choice from a saved cd-test-architecture report, says "apply the test doubles", "re-run Step 4b", "change the build-vs-document decision", or cites the `/apply-test-doubles ` command from a test-double setup guide. | -| `/cd-test-architecture` | [--component ] [--ci ] [--external-tests ] [--stack ] [--pdf] [--yes] | [`cd-test-architecture/SKILL.md`](../skills/cd-test-architecture/SKILL.md) | Evaluate an existing application's tests and recommend a CD-pipeline-aligned test architecture — fast, deterministic tests with minimal tooling that fully validate behavior (including cross-service interaction) and run in CI without configuring the rest of the system. Use when the user says "evaluate how this app is tested", "design a test architecture", "align our tests for CD", "make our CI tests deterministic", "our tests need the whole system configured", "our tests live in another repo / Postman / manual scripts", or asks for UI/service/batch test patterns. | -| `/coverage-baseline` | [--parent ] [--repo-slug ] [--workflow ] | [`coverage-baseline/SKILL.md`](../skills/coverage-baseline/SKILL.md) | Multi-workflow coverage baseline worker. Detects the repo's coverage tool from its build manifest, runs it, records the resulting line+branch percentages as the baseline, and posts the number to the parent issue (or local `FEATURE.md`). This number is the floor every later phase must improve on. Called by `/test-improve` (Phase 2) via `--workflow test-improve`. | -| `/coverage-delta` | [--parent ] [--repo-slug ] [--workflow ] [--story ] [--story-files ] | [`coverage-delta/SKILL.md`](../skills/coverage-delta/SKILL.md) | Multi-workflow coverage delta worker. Reads the baseline coverage, re-runs the same coverage tool against the current suite, computes the delta on line+branch percentages, and posts it to the parent issue (or local `FEATURE.md`). Called after each Story so the operator sees coverage move with every test added. Called by `/test-improve` (Phase 5) via `--workflow test-improve`. | -| `/exploratory-testing` | no flags — run directly | [`exploratory-testing/SKILL.md`](../skills/exploratory-testing/SKILL.md) | Charter-driven exploratory testing — probe a running feature/endpoint with structured heuristics, evaluate charter quality, run adversarial expansion, classify defects, and auto-triage critical findings into an incremental report. Use when the user runs /explore, says "explore this endpoint", "poke at this feature", "find bugs in the running app", or wants hands-off exploratory testing of a live target. | -| `/explore` | --charter '' [target] [--probe-budget ] [--invariants ''] [--no-adversarial] [--force] | [`explore/SKILL.md`](../skills/explore/SKILL.md) | Charter-driven exploratory testing of a running feature or endpoint. Dispatches the QA Engineer in "Chaos Specialist" mode to probe with structured heuristics (Goldilocks, Happy-Path Divergence, Telemetry Deepening, Invariant Probing, CRUD Sweep), run adversarial expansion, and auto-triage critical defects into an incremental report. Use when the user says "explore this endpoint", "poke at this feature", or wants hands-off exploratory testing of a live target. | -| `/farley-score` | no flags — run directly | [`farley-score/SKILL.md`](../skills/farley-score/SKILL.md) | Evaluate test quality using Dave Farley's 8 properties with a weighted Farley Score. Use when reviewing test suites, after writing tests, or when the user says "score my tests", "test quality", "Farley score", or "how good are my tests". | -| `/legacy-code` | no flags — run directly | [`legacy-code/SKILL.md`](../skills/legacy-code/SKILL.md) | Safely modify code that lacks tests. Use whenever tasked with changing code without test coverage — apply characterization tests and dependency-breaking techniques before making any behavioral changes. | -| `/mutation-testing` | no flags — run directly | [`mutation-testing/SKILL.md`](../skills/mutation-testing/SKILL.md) | Validate test suite quality by running a real mutation testing tool and triaging surviving mutants. Use after writing tests to verify assertions catch behavioral changes, when evaluating test coverage quality, or as a CI quality gate on critical modules. The AI value here is triage — classifying survivors, writing fix tests — not generating or estimating mutations. | -| `/quality-targets-converge` | [--parent ] [--repo-slug ] [--workflow ] [--max-iterations ] [--refactor-mode ] | [`quality-targets-converge/SKILL.md`](../skills/quality-targets-converge/SKILL.md) | Multi-workflow convergence worker. Closes the gap between the current test suite and the four quality targets (line+branch coverage ≥ 90%, zero surviving mutants, 100% deterministic, fastest pre-merge wall-clock achievable on-machine). Each iteration reads the latest measurements, picks the largest gap, and dispatches the smallest action that moves it. Stops only when all four targets are green or each gap is explicitly waived by the operator with a recorded reason. Called by `/test-improve` (Phase 8) via `--workflow test-improve`. | -| `/test-audit-disable` | [--repo-slug ] [--dry-run] | [`test-audit-disable/SKILL.md`](../skills/test-audit-disable/SKILL.md) | Standalone worker. Audits the existing test suite for tests that cannot fail — no assertions, assertions on constants, expect-true, swallowed exceptions, self-equality — and disables each one by skip-and-tag (never deletes). Records each disabled test plus its reason in a JSON log under `.claude/memory///` so a later phase can repair them. Pairs with `/coverage-baseline` to produce a true baseline coverage number. | -| `/test-design` | [--path ] [--since ] [--advise] | [`test-design/SKILL.md`](../skills/test-design/SKILL.md) | Deep test-design review and forward-design advisor. Dispatches test-review (tactical quality) and test-smell-review (xUnit smells, double selection, pyramid placement) in parallel, and runs the test-design-advisor worker to recommend how to test hard-to-test code. Use when the user says "review my tests", "how should I test this", "is this testable", "design tests for this", "what's the right test for X", "test design review", or before writing a suite for an untested module. For a single unit, pass --advise --path . Advisory — it recommends, it does not edit. | -| test-design-advisor | agent-loaded — not directly invocable | [`test-design-advisor/SKILL.md`](../skills/test-design-advisor/SKILL.md) | Worker skill — assess testability, recommend the right test-pyramid layer and test-double strategy, and propose a behavior-preserving refactor sequence to make hard-to-test code testable. Invoked by /test-design and /test-health; not user-invocable. For a user-facing entry point use /test-design (add --advise --path for forward-design on a single unit). | -| `/test-health` | [--path ] [--pdf] [--no-mutation] | [`test-health/SKILL.md`](../skills/test-health/SKILL.md) | Project-wide test-strategy audit — derive the suite's shape and shape-vs-architecture fit, map coverage to the Agile Testing Quadrants, roll up coverage + mutation health, flag flaky tests and automation maturity, and produce an ordered improvement plan. Delegates CD-determinism + pipeline assessment to cd-test-architecture. Use when the user says "audit our tests", "how healthy is our test suite", "test strategy review", or runs /test-health. Advisory — writes a report, does not edit. | +| `/apply-test-doubles` | [] [--component ] [--yes] | [`apply-test-doubles/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/apply-test-doubles/SKILL.md) | Apply `/cd-test-architecture`'s Step 4b build-vs-document decision logic against an existing, saved assessment report — or, when no valid report path is given, against a target to assess first — without re-running the full Steps 0-6 assessment each time. Use when the user wants to revisit or change a component's Build/Document choice from a saved cd-test-architecture report, says "apply the test doubles", "re-run Step 4b", "change the build-vs-document decision", or cites the `/apply-test-doubles ` command from a test-double setup guide. | +| `/cd-test-architecture` | [--component ] [--ci ] [--external-tests ] [--stack ] [--pdf] [--yes] | [`cd-test-architecture/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/cd-test-architecture/SKILL.md) | Evaluate an existing application's tests and recommend a CD-pipeline-aligned test architecture — fast, deterministic tests with minimal tooling that fully validate behavior (including cross-service interaction) and run in CI without configuring the rest of the system. Use when the user says "evaluate how this app is tested", "design a test architecture", "align our tests for CD", "make our CI tests deterministic", "our tests need the whole system configured", "our tests live in another repo / Postman / manual scripts", or asks for UI/service/batch test patterns. | +| `/coverage-baseline` | [--parent ] [--repo-slug ] [--workflow ] | [`coverage-baseline/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/coverage-baseline/SKILL.md) | Multi-workflow coverage baseline worker. Detects the repo's coverage tool from its build manifest, runs it, records the resulting line+branch percentages as the baseline, and posts the number to the parent issue (or local `FEATURE.md`). This number is the floor every later phase must improve on. Called by `/test-improve` (Phase 2) via `--workflow test-improve`. | +| `/coverage-delta` | [--parent ] [--repo-slug ] [--workflow ] [--story ] [--story-files ] | [`coverage-delta/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/coverage-delta/SKILL.md) | Multi-workflow coverage delta worker. Reads the baseline coverage, re-runs the same coverage tool against the current suite, computes the delta on line+branch percentages, and posts it to the parent issue (or local `FEATURE.md`). Called after each Story so the operator sees coverage move with every test added. Called by `/test-improve` (Phase 5) via `--workflow test-improve`. | +| `/exploratory-testing` | no flags — run directly | [`exploratory-testing/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/exploratory-testing/SKILL.md) | Charter-driven exploratory testing — probe a running feature/endpoint with structured heuristics, evaluate charter quality, run adversarial expansion, classify defects, and auto-triage critical findings into an incremental report. Use when the user runs /explore, says "explore this endpoint", "poke at this feature", "find bugs in the running app", or wants hands-off exploratory testing of a live target. | +| `/explore` | --charter '' [target] [--probe-budget ] [--invariants ''] [--no-adversarial] [--force] | [`explore/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/explore/SKILL.md) | Charter-driven exploratory testing of a running feature or endpoint. Dispatches the QA Engineer in "Chaos Specialist" mode to probe with structured heuristics (Goldilocks, Happy-Path Divergence, Telemetry Deepening, Invariant Probing, CRUD Sweep), run adversarial expansion, and auto-triage critical defects into an incremental report. Use when the user says "explore this endpoint", "poke at this feature", or wants hands-off exploratory testing of a live target. | +| `/farley-score` | no flags — run directly | [`farley-score/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/farley-score/SKILL.md) | Evaluate test quality using Dave Farley's 8 properties with a weighted Farley Score. Use when reviewing test suites, after writing tests, or when the user says "score my tests", "test quality", "Farley score", or "how good are my tests". | +| `/legacy-code` | no flags — run directly | [`legacy-code/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/legacy-code/SKILL.md) | Safely modify code that lacks tests. Use whenever tasked with changing code without test coverage — apply characterization tests and dependency-breaking techniques before making any behavioral changes. | +| `/mutation-testing` | no flags — run directly | [`mutation-testing/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/mutation-testing/SKILL.md) | Validate test suite quality by running a real mutation testing tool and triaging surviving mutants. Use after writing tests to verify assertions catch behavioral changes, when evaluating test coverage quality, or as a CI quality gate on critical modules. The AI value here is triage — classifying survivors, writing fix tests — not generating or estimating mutations. | +| `/quality-targets-converge` | [--parent ] [--repo-slug ] [--workflow ] [--max-iterations ] [--refactor-mode ] | [`quality-targets-converge/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/quality-targets-converge/SKILL.md) | Multi-workflow convergence worker. Closes the gap between the current test suite and the four quality targets (line+branch coverage ≥ 90%, zero surviving mutants, 100% deterministic, fastest pre-merge wall-clock achievable on-machine). Each iteration reads the latest measurements, picks the largest gap, and dispatches the smallest action that moves it. Stops only when all four targets are green or each gap is explicitly waived by the operator with a recorded reason. Called by `/test-improve` (Phase 8) via `--workflow test-improve`. | +| `/test-audit-disable` | [--repo-slug ] [--dry-run] | [`test-audit-disable/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/test-audit-disable/SKILL.md) | Standalone worker. Audits the existing test suite for tests that cannot fail — no assertions, assertions on constants, expect-true, swallowed exceptions, self-equality — and disables each one by skip-and-tag (never deletes). Records each disabled test plus its reason in a JSON log under `.claude/memory///` so a later phase can repair them. Pairs with `/coverage-baseline` to produce a true baseline coverage number. | +| `/test-design` | [--path ] [--since ] [--advise] | [`test-design/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/test-design/SKILL.md) | Deep test-design review and forward-design advisor. Dispatches test-review (tactical quality) and test-smell-review (xUnit smells, double selection, pyramid placement) in parallel, and runs the test-design-advisor worker to recommend how to test hard-to-test code. Use when the user says "review my tests", "how should I test this", "is this testable", "design tests for this", "what's the right test for X", "test design review", or before writing a suite for an untested module. For a single unit, pass --advise --path . Advisory — it recommends, it does not edit. | +| test-design-advisor | agent-loaded — not directly invocable | [`test-design-advisor/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/test-design-advisor/SKILL.md) | Worker skill — assess testability, recommend the right test-pyramid layer and test-double strategy, and propose a behavior-preserving refactor sequence to make hard-to-test code testable. Invoked by /test-design and /test-health; not user-invocable. For a user-facing entry point use /test-design (add --advise --path for forward-design on a single unit). | +| `/test-health` | [--path ] [--pdf] [--no-mutation] | [`test-health/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/test-health/SKILL.md) | Project-wide test-strategy audit — derive the suite's shape and shape-vs-architecture fit, map coverage to the Agile Testing Quadrants, roll up coverage + mutation health, flag flaky tests and automation maturity, and produce an ordered improvement plan. Delegates CD-determinism + pipeline assessment to cd-test-architecture. Use when the user says "audit our tests", "how healthy is our test suite", "test strategy review", or runs /test-health. Advisory — writes a report, does not edit. | ## Security | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/docker-image-audit` | no flags — run directly | [`docker-image-audit/SKILL.md`](../skills/docker-image-audit/SKILL.md) | Audit Docker images and Dockerfiles for security vulnerabilities, bloat, and best-practice violations using hadolint, Trivy, and Grype. Produces a structured severity report with actionable fixes. Use this skill whenever the user wants to check a Docker image for security issues, scan a container for vulnerabilities, audit a Dockerfile, harden a Docker image, reduce image size, minimize attack surface, check for CVEs in a container, or says things like "is this Dockerfile secure?", "scan my image", "check my container for vulnerabilities", "how can I make this image smaller?", "audit my Docker setup", or "harden this container". Also trigger when the user has just created or modified a Dockerfile and wants validation before shipping it. | -| `/governance-compliance` | no flags — run directly | [`governance-compliance/SKILL.md`](../skills/governance-compliance/SKILL.md) | Audit logging, quality gates, and ethics procedures for the agent team. Use for periodic compliance reviews, when logging task completion events, or when an ethical concern arises that requires human escalation. | -| `/threat-modeling` | no flags — run directly | [`threat-modeling/SKILL.md`](../skills/threat-modeling/SKILL.md) | Structured STRIDE security analysis for identifying threats, attack surfaces, and mitigations. Use before implementing any new API, service, authentication change, or data flow crossing trust boundaries — security analysis belongs in the design phase, not after. | +| `/docker-image-audit` | no flags — run directly | [`docker-image-audit/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/docker-image-audit/SKILL.md) | Audit Docker images and Dockerfiles for security vulnerabilities, bloat, and best-practice violations using hadolint, Trivy, and Grype. Produces a structured severity report with actionable fixes. Use this skill whenever the user wants to check a Docker image for security issues, scan a container for vulnerabilities, audit a Dockerfile, harden a Docker image, reduce image size, minimize attack surface, check for CVEs in a container, or says things like "is this Dockerfile secure?", "scan my image", "check my container for vulnerabilities", "how can I make this image smaller?", "audit my Docker setup", or "harden this container". Also trigger when the user has just created or modified a Dockerfile and wants validation before shipping it. | +| `/governance-compliance` | no flags — run directly | [`governance-compliance/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/governance-compliance/SKILL.md) | Audit logging, quality gates, and ethics procedures for the agent team. Use for periodic compliance reviews, when logging task completion events, or when an ethical concern arises that requires human escalation. | +| `/threat-modeling` | no flags — run directly | [`threat-modeling/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/threat-modeling/SKILL.md) | Structured STRIDE security analysis for identifying threats, attack surfaces, and mitigations. Use before implementing any new API, service, authentication change, or data flow crossing trust boundaries — security analysis belongs in the design phase, not after. | ## Architecture & Domain Modeling | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/adr-tools` | no flags — run directly | [`adr-tools/SKILL.md`](../skills/adr-tools/SKILL.md) | Create and manage Architecture Decision Records using the npryce adr-tools CLI. Use when the user asks to "add an ADR", "record this decision", "create an ADR", "supersede ADR N", "link ADRs", "generate the ADR table of contents", or any request involving the `adr` command. Pairs with the adr-author agent — this skill is the mechanics (commands, files, links); adr-author is the decision framework (when an ADR is warranted) and the prose authoring. | -| `/domain-analysis` | no flags — run directly | [`domain-analysis/SKILL.md`](../skills/domain-analysis/SKILL.md) | Strategic DDD health assessment of an existing system. Use whenever someone asks to analyze their architecture, assess domain health, find coupling problems, map bounded contexts, trace event flows across services, or understand what is slowing down delivery. Trigger on phrases like "what's wrong with our architecture", "where is the coupling", "assess our domain", "event storming", "value stream", "friction report", "bounded contexts", or "why is everything so tangled". Apply to existing codebases — use domain-driven-design skill for greenfield modeling. | -| `/domain-driven-design` | no flags — run directly | [`domain-driven-design/SKILL.md`](../skills/domain-driven-design/SKILL.md) | Model software around the business domain. Use when designing bounded contexts, defining aggregates and value objects, mapping context relationships, or working with complex business logic. Apply before implementation to prevent model drift. | -| `/hexagonal-architecture` | no flags — run directly | [`hexagonal-architecture/SKILL.md`](../skills/hexagonal-architecture/SKILL.md) | Design with ports and adapters to separate business logic from infrastructure. Use when designing a new service, reviewing structural compliance, or deciding how to introduce a new external dependency without coupling the domain. | -| `/mermaid-diagramming` | no flags — run directly | [`mermaid-diagramming/SKILL.md`](../skills/mermaid-diagramming/SKILL.md) | Create Mermaid diagrams using the project's blue-gray theme. Use whenever the user asks to draw a diagram, create a flowchart, visualize a process, document architecture, or add any Mermaid diagram to a markdown file. Trigger on phrases like "draw a diagram", "create a flowchart", "visualize this", "add a mermaid diagram", "document the flow", "sequence diagram", "architecture diagram", or any request to diagram a process or system. | -| `/ubiquitous-language` | [path-to-source-root] | [`ubiquitous-language/SKILL.md`](../skills/ubiquitous-language/SKILL.md) | Build or refresh the project's ubiquitous language glossary — one markdown file per business concept at `.plans/domain/.md` plus a `_index.md`. Mines grep-based signals (class names, enum values, interface names, domain-event names, BDD scenario names, validator rules) and applies a four-gate filter to keep only genuine business concepts. Optional interactive interview phase to refine definitions and capture behavior (state transitions, invariants, synonyms to avoid). Language-agnostic — works for JS/TS, C#, Java, Python, Go, or any mix. Use whenever the user says "build the glossary", "extract domain terms", "document the ubiquitous language", "what are the domain concepts", or when domain-review surfaces pervasive terminology inconsistency (3+ names for the same concept). | +| `/adr-tools` | no flags — run directly | [`adr-tools/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/adr-tools/SKILL.md) | Create and manage Architecture Decision Records using the npryce adr-tools CLI. Use when the user asks to "add an ADR", "record this decision", "create an ADR", "supersede ADR N", "link ADRs", "generate the ADR table of contents", or any request involving the `adr` command. Pairs with the adr-author agent — this skill is the mechanics (commands, files, links); adr-author is the decision framework (when an ADR is warranted) and the prose authoring. | +| `/domain-analysis` | no flags — run directly | [`domain-analysis/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/domain-analysis/SKILL.md) | Strategic DDD health assessment of an existing system. Use whenever someone asks to analyze their architecture, assess domain health, find coupling problems, map bounded contexts, trace event flows across services, or understand what is slowing down delivery. Trigger on phrases like "what's wrong with our architecture", "where is the coupling", "assess our domain", "event storming", "value stream", "friction report", "bounded contexts", or "why is everything so tangled". Apply to existing codebases — use domain-driven-design skill for greenfield modeling. | +| `/domain-driven-design` | no flags — run directly | [`domain-driven-design/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/domain-driven-design/SKILL.md) | Model software around the business domain. Use when designing bounded contexts, defining aggregates and value objects, mapping context relationships, or working with complex business logic. Apply before implementation to prevent model drift. | +| `/hexagonal-architecture` | no flags — run directly | [`hexagonal-architecture/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/hexagonal-architecture/SKILL.md) | Design with ports and adapters to separate business logic from infrastructure. Use when designing a new service, reviewing structural compliance, or deciding how to introduce a new external dependency without coupling the domain. | +| `/mermaid-diagramming` | no flags — run directly | [`mermaid-diagramming/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/mermaid-diagramming/SKILL.md) | Create Mermaid diagrams using the project's blue-gray theme. Use whenever the user asks to draw a diagram, create a flowchart, visualize a process, document architecture, or add any Mermaid diagram to a markdown file. Trigger on phrases like "draw a diagram", "create a flowchart", "visualize this", "add a mermaid diagram", "document the flow", "sequence diagram", "architecture diagram", or any request to diagram a process or system. | +| `/ubiquitous-language` | [path-to-source-root] | [`ubiquitous-language/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/ubiquitous-language/SKILL.md) | Build or refresh the project's ubiquitous language glossary — one markdown file per business concept at `.plans/domain/.md` plus a `_index.md`. Mines grep-based signals (class names, enum values, interface names, domain-event names, BDD scenario names, validator rules) and applies a four-gate filter to keep only genuine business concepts. Optional interactive interview phase to refine definitions and capture behavior (state transitions, invariants, synonyms to avoid). Language-agnostic — works for JS/TS, C#, Java, Python, Go, or any mix. Use whenever the user says "build the glossary", "extract domain terms", "document the ubiquitous language", "what are the domain concepts", or when domain-review surfaces pervasive terminology inconsistency (3+ names for the same concept). | ## Performance, Containers & Browser | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/benchmark` | [--baseline] [--budget] [--trend] [--mobile] [--3g] [--runs ] | [`benchmark/SKILL.md`](../skills/benchmark/SKILL.md) | Capture runtime performance metrics (Core Web Vitals, resource sizes, load times) for web pages. Compare against baselines and performance budgets. Use when the user says "benchmark", "check performance", "page speed", "web vitals", "performance regression", or "how fast is this page". | -| `/browse` | [--screenshot ] [--click ] [--fill ] [--wait ] [--viewport ] | [`browse/SKILL.md`](../skills/browse/SKILL.md) | Launch a browser to navigate URLs, take screenshots, click elements, and fill forms. Use for visual verification, e2e testing, and interactive debugging. | -| browser-testing | agent-loaded — not directly invocable | [`browser-testing/SKILL.md`](../skills/browser-testing/SKILL.md) | Patterns and templates for browser-based QA using Playwright. Covers navigation, form interaction, screenshot capture, visual verification, and CAPTCHA/auth handoff. | -| `/docker-image-create` | no flags — run directly | [`docker-image-create/SKILL.md`](../skills/docker-image-create/SKILL.md) | Generate production-ready Dockerfiles from project source code. Detects language/framework automatically and produces multi-stage builds with minimal, distroless, or slim base images. Use this skill whenever the user wants to containerize an application, create a Dockerfile, dockerize a project, build a Docker image, or says things like "make this run in Docker", "create a container for this app", "I need a Dockerfile", "package this for deployment", or "containerize this service". Also trigger when the user has an existing Dockerfile and wants it rewritten for production use, or when they ask about Docker best practices for their project. | -| performance-benchmark | agent-loaded — not directly invocable | [`performance-benchmark/SKILL.md`](../skills/performance-benchmark/SKILL.md) | Capture runtime performance metrics (Core Web Vitals, resource sizes, load times) against defined budgets. Compare to baselines, flag regressions, and maintain trend history. Complements the code-level performance-review agent with actual runtime measurement. | +| `/benchmark` | [--baseline] [--budget] [--trend] [--mobile] [--3g] [--runs ] | [`benchmark/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/benchmark/SKILL.md) | Capture runtime performance metrics (Core Web Vitals, resource sizes, load times) for web pages. Compare against baselines and performance budgets. Use when the user says "benchmark", "check performance", "page speed", "web vitals", "performance regression", or "how fast is this page". | +| `/browse` | [--screenshot ] [--click ] [--fill ] [--wait ] [--viewport ] | [`browse/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/browse/SKILL.md) | Launch a browser to navigate URLs, take screenshots, click elements, and fill forms. Use for visual verification, e2e testing, and interactive debugging. | +| browser-testing | agent-loaded — not directly invocable | [`browser-testing/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/browser-testing/SKILL.md) | Patterns and templates for browser-based QA using Playwright. Covers navigation, form interaction, screenshot capture, visual verification, and CAPTCHA/auth handoff. | +| `/docker-image-create` | no flags — run directly | [`docker-image-create/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/docker-image-create/SKILL.md) | Generate production-ready Dockerfiles from project source code. Detects language/framework automatically and produces multi-stage builds with minimal, distroless, or slim base images. Use this skill whenever the user wants to containerize an application, create a Dockerfile, dockerize a project, build a Docker image, or says things like "make this run in Docker", "create a container for this app", "I need a Dockerfile", "package this for deployment", or "containerize this service". Also trigger when the user has an existing Dockerfile and wants it rewritten for production use, or when they ask about Docker best practices for their project. | +| performance-benchmark | agent-loaded — not directly invocable | [`performance-benchmark/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/performance-benchmark/SKILL.md) | Capture runtime performance metrics (Core Web Vitals, resource sizes, load times) against defined budgets. Compare to baselines, flag regressions, and maintain trend history. Complements the code-level performance-review agent with actual runtime measurement. | ## Debugging & Diagnostics | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/ci-debugging` | no flags — run directly | [`ci-debugging/SKILL.md`](../skills/ci-debugging/SKILL.md) | Systematic CI/CD failure diagnosis with hypothesis-first approach, environment delta analysis, and anti-patterns. Use when CI fails, pipelines break, or the user says "CI is failing", "build broke", "pipeline error", or "tests pass locally but fail in CI". | -| `/fix` | [--triage-record ] | [`fix/SKILL.md`](../skills/fix/SKILL.md) | Investigate a bug via /triage (or reuse an existing triage record), prove the defect reproduces, then implement the record's TDD Fix Plan one RED/GREEN cycle at a time with a regression check after each cycle, close the record, and delegate to /pr for a reviewed pull request. Use when the user reports a bug and wants it fixed end-to-end, says "fix this bug", or wants a hands-off defect fix that closes the loop /triage leaves open. | -| `/systematic-debugging` | no flags — run directly | [`systematic-debugging/SKILL.md`](../skills/systematic-debugging/SKILL.md) | Four-phase debugging protocol (reproduce, investigate, root-cause, fix) that prevents guess-and-fix thrashing. Use this skill whenever a test fails, a bug is reported, an error occurs during implementation, or any unexpected behavior is encountered. Prevents the common LLM failure mode of guessing at fixes without understanding the problem. | -| `/triage` | [--pdf] | [`triage/SKILL.md`](../skills/triage/SKILL.md) | Investigate a bug, find its root cause, and write a portable triage record to .dev-team-reports/triage/.md with a TDD fix plan. Use when the user reports a bug and wants it triaged, says "triage this", "investigate and write it up", or wants a hands-off bug investigation that produces an actionable record. | +| `/ci-debugging` | no flags — run directly | [`ci-debugging/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/ci-debugging/SKILL.md) | Systematic CI/CD failure diagnosis with hypothesis-first approach, environment delta analysis, and anti-patterns. Use when CI fails, pipelines break, or the user says "CI is failing", "build broke", "pipeline error", or "tests pass locally but fail in CI". | +| `/fix` | [--triage-record ] | [`fix/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/fix/SKILL.md) | Investigate a bug via /triage (or reuse an existing triage record), prove the defect reproduces, then implement the record's TDD Fix Plan one RED/GREEN cycle at a time with a regression check after each cycle, close the record, and delegate to /pr for a reviewed pull request. Use when the user reports a bug and wants it fixed end-to-end, says "fix this bug", or wants a hands-off defect fix that closes the loop /triage leaves open. | +| `/systematic-debugging` | no flags — run directly | [`systematic-debugging/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/systematic-debugging/SKILL.md) | Four-phase debugging protocol (reproduce, investigate, root-cause, fix) that prevents guess-and-fix thrashing. Use this skill whenever a test fails, a bug is reported, an error occurs during implementation, or any unexpected behavior is encountered. Prevents the common LLM failure mode of guessing at fixes without understanding the problem. | +| `/triage` | [--pdf] | [`triage/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/triage/SKILL.md) | Investigate a bug, find its root cause, and write a portable triage record to .dev-team-reports/triage/.md with a TDD fix plan. Use when the user reports a bug and wants it triaged, says "triage this", "investigate and write it up", or wants a hands-off bug investigation that produces an actionable record. | ## Setup, Config & Plugin Management | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/help` | [--all] | [`help/SKILL.md`](../skills/help/SKILL.md) | List the main dev-team workflows, with an option to show every user-invocable slash command. | -| `/project-init` | [--yes] [--force] | [`project-init/SKILL.md`](../skills/project-init/SKILL.md) | Get a repository ready for the dev-team toolchain in one command — detect the tech stack (JS/TS, Python, C#, Java), inventory the static-analysis tools the project already has, confirm a plan, and install only what's missing, repo-level. This is the canonical source of truth for tech-stack detection and toolchain installation — NOT dev-team-specific config (CLAUDE.md generation, agent template activation, PostToolUse hooks, the generated `/pr` command all live in `/setup`, which invokes this skill first for the stack signal). Also installs the detection-gated capability tools other skills depend on — semgrep, Playwright + Chromium, adr, gh, and the docker scanners (hadolint/trivy/grype). For JavaScript it scaffolds a new project with ES modules, functional style, prettier, oxlint, editorconfig, vitest, and gitignore. Use this skill whenever the user wants to start a new JS project, scaffold a Node.js app, create a new package, bootstrap a JavaScript repo, or says things like "init a new project", "set up a JS project", "create a new node app", "start a new frontend project", or "bootstrap a new package". Also trigger when the user says "set up my project's toolchain", "install the linters for this repo", "get this repo ready for the plugin", or asks to add standard tooling (linting, formatting, testing) to a new or existing project in any supported language. | -| `/setup` | [--yes] [--dry-run] | [`setup/SKILL.md`](../skills/setup/SKILL.md) | Provision a repo for the dev-team plugin end to end — install the plugin's own prerequisites (jq, python3, per-language mutation tooling — Stryker, pitest, Stryker.NET), then generate dev-team-specific project configuration — project-level CLAUDE.md, the PostToolUse formatting hook, language-specific agent template activation, and a generated `/pr` command — from the stack signal `/dev-team:project-init` establishes. This is NOT where toolchain detection/installation itself lives (that's `/project-init`); `/setup` only consumes it. Use this when onboarding a new project to the dev-team plugin, when the mutation gate reports a missing tool, or when the user says "setup", "bootstrap", "configure this project for dev-team", "install required tools for the dev-team plugin", or "activate agent templates". | -| `/upgrade` | no flags — run directly | [`upgrade/SKILL.md`](../skills/upgrade/SKILL.md) | Check for and apply plugin updates using the official Claude Code plugin update mechanism. | -| `/version` | no flags — run directly | [`version/SKILL.md`](../skills/version/SKILL.md) | Report the installed version of the dev-team plugin. | +| `/help` | [--all] | [`help/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/help/SKILL.md) | List the main dev-team workflows, with an option to show every user-invocable slash command. | +| `/project-init` | [--yes] [--force] | [`project-init/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/project-init/SKILL.md) | Get a repository ready for the dev-team toolchain in one command — detect the tech stack (JS/TS, Python, C#, Java), inventory the static-analysis tools the project already has, confirm a plan, and install only what's missing, repo-level. This is the canonical source of truth for tech-stack detection and toolchain installation — NOT dev-team-specific config (CLAUDE.md generation, agent template activation, PostToolUse hooks, the generated `/pr` command all live in `/setup`, which invokes this skill first for the stack signal). Also installs the detection-gated capability tools other skills depend on — semgrep, Playwright + Chromium, adr, gh, and the docker scanners (hadolint/trivy/grype). For JavaScript it scaffolds a new project with ES modules, functional style, prettier, oxlint, editorconfig, vitest, and gitignore. Use this skill whenever the user wants to start a new JS project, scaffold a Node.js app, create a new package, bootstrap a JavaScript repo, or says things like "init a new project", "set up a JS project", "create a new node app", "start a new frontend project", or "bootstrap a new package". Also trigger when the user says "set up my project's toolchain", "install the linters for this repo", "get this repo ready for the plugin", or asks to add standard tooling (linting, formatting, testing) to a new or existing project in any supported language. | +| `/setup` | [--yes] [--dry-run] | [`setup/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/setup/SKILL.md) | Provision a repo for the dev-team plugin end to end — install the plugin's own prerequisites (jq, python3, per-language mutation tooling — Stryker, pitest, Stryker.NET), then generate dev-team-specific project configuration — project-level CLAUDE.md, the PostToolUse formatting hook, language-specific agent template activation, and a generated `/pr` command — from the stack signal `/dev-team:project-init` establishes. This is NOT where toolchain detection/installation itself lives (that's `/project-init`); `/setup` only consumes it. Use this when onboarding a new project to the dev-team plugin, when the mutation gate reports a missing tool, or when the user says "setup", "bootstrap", "configure this project for dev-team", "install required tools for the dev-team plugin", or "activate agent templates". | +| `/upgrade` | no flags — run directly | [`upgrade/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/upgrade/SKILL.md) | Check for and apply plugin updates using the official Claude Code plugin update mechanism. | +| `/version` | no flags — run directly | [`version/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/version/SKILL.md) | Report the installed version of the dev-team plugin. | ## Session, Context & Telemetry | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/artifact-lifecycle` | no flags — run directly | [`artifact-lifecycle/SKILL.md`](../skills/artifact-lifecycle/SKILL.md) | Report on skill and agent usage data from ~/.claude/metrics/artifact-usage.json, classifying each artifact as active, stale (>= 30 days unused), or an archive candidate (>= 90 days unused). Proposes CLAUDE.md overrides for stale artifacts and exclusions for archive candidates. Pinned skills are always exempt. Use when the user asks to "review artifact lifecycle", "find stale skills", or "/artifact-lifecycle". | -| `/context-loading-protocol` | no flags — run directly | [`context-loading-protocol/SKILL.md`](../skills/context-loading-protocol/SKILL.md) | Decide which agents and skills to load for a given task. Use at the start of every task to select the minimum viable context load, calculate the token budget, and stay below the 40% utilization ceiling. | -| `/cost-report` | [--transcript ] [--tolerance ] | [`cost-report/SKILL.md`](../skills/cost-report/SKILL.md) | Report actual token spend and dollar cost of dispatched work — per agent and total — and flag cost regressions. Use when the user asks "how much did that cost", "token spend", "cost of this run", "cost report", or wants to check for a cost regression after /code-review or an orchestration run. | -| `/handoff` | no flags — run directly | [`handoff/SKILL.md`](../skills/handoff/SKILL.md) | Compress or split off context for another session to pick up. Use to compress conversation history when context utilization approaches 40% (continue mode), or to split off a distinguishable out-of-scope side-task to an independent session (fork mode) — write a structured artifact for the other session and free the current one. | -| `/performance-metrics` | no flags — run directly | [`performance-metrics/SKILL.md`](../skills/performance-metrics/SKILL.md) | Log task completion data to .claude/metrics/. Use at the end of every task to record tokens, cost, agents used, rework cycles, and hallucination events. Also use for periodic reporting to identify efficiency and quality trends. | -| `/session-review` | [--cwd ] [--transcript ] [--out ] [--cross-machine] | [`session-review/SKILL.md`](../skills/session-review/SKILL.md) | Mine real Claude Code session transcripts to suggest plugin improvements that cut token spend, reduce re-work, and improve accuracy. Use when the user asks to "review my sessions", "where am I wasting tokens", "why does this keep re-doing work", or "/session-review". | -| `/telemetry` | [on\|off\|status\|report] | [`telemetry/SKILL.md`](../skills/telemetry/SKILL.md) | Manage and report the opt-in, privacy-clean usage telemetry beacon. Use when the user asks to "enable/disable telemetry", "show telemetry", "usage stats", "which commands do I use", or "how often is the commit gate bypassed". | +| `/artifact-lifecycle` | no flags — run directly | [`artifact-lifecycle/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/artifact-lifecycle/SKILL.md) | Report on skill and agent usage data from ~/.claude/metrics/artifact-usage.json, classifying each artifact as active, stale (>= 30 days unused), or an archive candidate (>= 90 days unused). Proposes CLAUDE.md overrides for stale artifacts and exclusions for archive candidates. Pinned skills are always exempt. Use when the user asks to "review artifact lifecycle", "find stale skills", or "/artifact-lifecycle". | +| `/context-loading-protocol` | no flags — run directly | [`context-loading-protocol/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/context-loading-protocol/SKILL.md) | Decide which agents and skills to load for a given task. Use at the start of every task to select the minimum viable context load, calculate the token budget, and stay below the 40% utilization ceiling. | +| `/cost-report` | [--transcript ] [--tolerance ] | [`cost-report/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/cost-report/SKILL.md) | Report actual token spend and dollar cost of dispatched work — per agent and total — and flag cost regressions. Use when the user asks "how much did that cost", "token spend", "cost of this run", "cost report", or wants to check for a cost regression after /code-review or an orchestration run. | +| `/handoff` | no flags — run directly | [`handoff/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/handoff/SKILL.md) | Compress or split off context for another session to pick up. Use to compress conversation history when context utilization approaches 40% (continue mode), or to split off a distinguishable out-of-scope side-task to an independent session (fork mode) — write a structured artifact for the other session and free the current one. | +| `/performance-metrics` | no flags — run directly | [`performance-metrics/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/performance-metrics/SKILL.md) | Log task completion data to .claude/metrics/. Use at the end of every task to record tokens, cost, agents used, rework cycles, and hallucination events. Also use for periodic reporting to identify efficiency and quality trends. | +| `/session-review` | [--cwd ] [--transcript ] [--out ] [--cross-machine] | [`session-review/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/session-review/SKILL.md) | Mine real Claude Code session transcripts to suggest plugin improvements that cut token spend, reduce re-work, and improve accuracy. Use when the user asks to "review my sessions", "where am I wasting tokens", "why does this keep re-doing work", or "/session-review". | +| `/telemetry` | [on\|off\|status\|report] | [`telemetry/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/telemetry/SKILL.md) | Manage and report the opt-in, privacy-clean usage telemetry beacon. Use when the user asks to "enable/disable telemetry", "show telemetry", "usage stats", "which commands do I use", or "how often is the commit gate bypassed". | ## Safety Modes | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/careful` | [off] | [`careful/SKILL.md`](../skills/careful/SKILL.md) | Toggle careful mode. When active, destructive commands (rm -rf, force-push, DROP TABLE, etc.) are blocked instead of just warned about. | -| `/freeze` | | [`freeze/SKILL.md`](../skills/freeze/SKILL.md) | Scope-lock file editing to a specific glob pattern. Only files matching the pattern can be edited until /unfreeze is called. | -| `/guard` | | [`guard/SKILL.md`](../skills/guard/SKILL.md) | Activate both careful mode and freeze mode together. Blocks destructive commands and scope-locks editing to the specified pattern. Use for production-critical debugging sessions. | -| `/unfreeze` | no flags — run directly | [`unfreeze/SKILL.md`](../skills/unfreeze/SKILL.md) | Lift the scope lock set by /freeze. All files become editable again. | +| `/careful` | [off] | [`careful/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/careful/SKILL.md) | Toggle careful mode. When active, destructive commands (rm -rf, force-push, DROP TABLE, etc.) are blocked instead of just warned about. | +| `/freeze` | | [`freeze/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/freeze/SKILL.md) | Scope-lock file editing to a specific glob pattern. Only files matching the pattern can be edited until /unfreeze is called. | +| `/guard` | | [`guard/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/guard/SKILL.md) | Activate both careful mode and freeze mode together. Blocks destructive commands and scope-locks editing to the specified pattern. Use for production-critical debugging sessions. | +| `/unfreeze` | no flags — run directly | [`unfreeze/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/unfreeze/SKILL.md) | Lift the scope lock set by /freeze. All files become editable again. | ## Harness Governance & Tuning | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/agent-audit` | [file-path \| --all] [--fix] | [`agent-audit/SKILL.md`](../skills/agent-audit/SKILL.md) | Audit code-review agents, skills, and hooks for structural compliance. Use this when adding or modifying any agent, skill, or hook file, or for a periodic health check of the toolkit. Trigger phrases: "audit the agents", "check compliance", "validate the skills", "are the agents correct", or any time agent/skill files change. | -| `/agent-eval` | [--agent ] [--skill ] [--fixture ] [--trials ] [--in-session] [--integration] [--ablation ] [--no-cache] [--verbose] | [`agent-eval/SKILL.md`](../skills/agent-eval/SKILL.md) | Run eval fixtures against review agents and grade results. Use this after adding or modifying a review agent, to validate detection accuracy, or when the user says "run the evals", "test the agents", "check for regressions", or "how accurate is the agent". | -| `/agent-readiness` | [repo-path] [--json ] [--markdown ] | [`agent-readiness/SKILL.md`](../skills/agent-readiness/SKILL.md) | Score how ready the current repository is for AI-assisted development against the Agent-Readiness Scorecard. Use when the user asks "how agent-ready is this repo", "score this repo for agents", "agent readiness", or wants a tiered readiness report. Scores YOUR project repo's readiness — not the dev-team plugin's own review agents and routing (for that, use /harness-audit). | -| `/competitive-analysis` | no flags — run directly | [`competitive-analysis/SKILL.md`](../skills/competitive-analysis/SKILL.md) | Compare this plugin against external plugins, tools, feature sets, or ideas to find gaps and weaknesses. Produces a structured gap analysis report with rough specs for closing each gap. Use this skill whenever the user references capabilities from OUTSIDE the plugin — another plugin they found, a competitor's tool, a feature list from a different project, a repo URL, or a hypothetical concept for capabilities we lack. Trigger phrases include "how do we compare to X", "what does Y have that we don't", "what are we missing", "gap analysis", "competitive analysis", "weaknesses compared to", "stack up against", "where do we fall short", and "should we add X — I saw it in another tool". Also trigger when the user pastes a feature list or describes capabilities they saw elsewhere and asks whether we should have them. Do NOT trigger for internal operations like running reviews, auditing our own agents, adding skills, threat modeling, domain analysis, or debugging — those use other skills. | -| `/feedback-learning` | no flags — run directly | [`feedback-learning/SKILL.md`](../skills/feedback-learning/SKILL.md) | Capture amend/learn/remember/forget keywords from the user and update agent or skill configurations. Invoke immediately when the user issues any of these trigger words — parse the change, preview a diff, apply it, and log it to the audit trail. | -| `/harness-audit` | [--output ] [--pdf] | [`harness-audit/SKILL.md`](../skills/harness-audit/SKILL.md) | Analyze review agent effectiveness, model routing, and orchestration complexity against actual usage data. Produces a report of harness components that may be candidates for simplification or removal. Use periodically to prevent harness staleness as model capabilities improve. Audits the dev-team plugin's OWN harness from runtime metrics — not your project repo's readiness (for that, use /agent-readiness). | -| `/human-oversight-protocol` | no flags — run directly | [`human-oversight-protocol/SKILL.md`](../skills/human-oversight-protocol/SKILL.md) | Approval gates, intervention commands, and transparency requirements. Use to classify any agent action as autonomous/notify/approve, respond to override/pause/stop commands, or structure a plan review before the implementation phase begins. | -| `/quality-gate-pipeline` | no flags — run directly | [`quality-gate-pipeline/SKILL.md`](../skills/quality-gate-pipeline/SKILL.md) | Unified quality gate for agent output — self-validation, verification evidence, and review-correction loops. Consolidates accuracy-validation, verification-before-completion, and task-review-correction into a single three-phase pipeline. Use before delivery, at completion, and during rework. | +| `/agent-audit` | [file-path \| --all] [--fix] | [`agent-audit/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/agent-audit/SKILL.md) | Audit code-review agents, skills, and hooks for structural compliance. Use this when adding or modifying any agent, skill, or hook file, or for a periodic health check of the toolkit. Trigger phrases: "audit the agents", "check compliance", "validate the skills", "are the agents correct", or any time agent/skill files change. | +| `/agent-eval` | [--agent ] [--skill ] [--fixture ] [--trials ] [--in-session] [--integration] [--ablation ] [--no-cache] [--verbose] | [`agent-eval/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/agent-eval/SKILL.md) | Run eval fixtures against review agents and grade results. Use this after adding or modifying a review agent, to validate detection accuracy, or when the user says "run the evals", "test the agents", "check for regressions", or "how accurate is the agent". | +| `/agent-readiness` | [repo-path] [--json ] [--markdown ] | [`agent-readiness/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/agent-readiness/SKILL.md) | Score how ready the current repository is for AI-assisted development against the Agent-Readiness Scorecard. Use when the user asks "how agent-ready is this repo", "score this repo for agents", "agent readiness", or wants a tiered readiness report. Scores YOUR project repo's readiness — not the dev-team plugin's own review agents and routing (for that, use /harness-audit). | +| `/competitive-analysis` | no flags — run directly | [`competitive-analysis/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/competitive-analysis/SKILL.md) | Compare this plugin against external plugins, tools, feature sets, or ideas to find gaps and weaknesses. Produces a structured gap analysis report with rough specs for closing each gap. Use this skill whenever the user references capabilities from OUTSIDE the plugin — another plugin they found, a competitor's tool, a feature list from a different project, a repo URL, or a hypothetical concept for capabilities we lack. Trigger phrases include "how do we compare to X", "what does Y have that we don't", "what are we missing", "gap analysis", "competitive analysis", "weaknesses compared to", "stack up against", "where do we fall short", and "should we add X — I saw it in another tool". Also trigger when the user pastes a feature list or describes capabilities they saw elsewhere and asks whether we should have them. Do NOT trigger for internal operations like running reviews, auditing our own agents, adding skills, threat modeling, domain analysis, or debugging — those use other skills. | +| `/feedback-learning` | no flags — run directly | [`feedback-learning/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/feedback-learning/SKILL.md) | Capture amend/learn/remember/forget keywords from the user and update agent or skill configurations. Invoke immediately when the user issues any of these trigger words — parse the change, preview a diff, apply it, and log it to the audit trail. | +| `/harness-audit` | [--output ] [--pdf] | [`harness-audit/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/harness-audit/SKILL.md) | Analyze review agent effectiveness, model routing, and orchestration complexity against actual usage data. Produces a report of harness components that may be candidates for simplification or removal. Use periodically to prevent harness staleness as model capabilities improve. Audits the dev-team plugin's OWN harness from runtime metrics — not your project repo's readiness (for that, use /agent-readiness). | +| `/human-oversight-protocol` | no flags — run directly | [`human-oversight-protocol/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/human-oversight-protocol/SKILL.md) | Approval gates, intervention commands, and transparency requirements. Use to classify any agent action as autonomous/notify/approve, respond to override/pause/stop commands, or structure a plan review before the implementation phase begins. | +| `/quality-gate-pipeline` | no flags — run directly | [`quality-gate-pipeline/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/quality-gate-pipeline/SKILL.md) | Unified quality gate for agent output — self-validation, verification evidence, and review-correction loops. Consolidates accuracy-validation, verification-before-completion, and task-review-correction into a single three-phase pipeline. Use before delivery, at completion, and during rework. | ## Other | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/claude-setup-review` | [--path ] [--json] | [`claude-setup-review/SKILL.md`](../skills/claude-setup-review/SKILL.md) | Audit this project's Claude Code harness — CLAUDE.md completeness, rule clarity, skill and agent wiring, path accuracy, and agent frontmatter schema compliance. Use when the user says "review my CLAUDE.md", "audit my Claude setup", "is my Claude config right", "check my agent frontmatter", "are my skill paths correct", or after adding or restructuring CLAUDE.md, agents, or skills. Advisory — it recommends, it does not edit. | -| `/co-evolution-audit` | [--since ] [--max-commits ] [--min-churn ] [--max-test-churn ] | [`co-evolution-audit/SKILL.md`](../skills/co-evolution-audit/SKILL.md) | Flag production files that churn repeatedly while their paired test files do not change — the "Red Queen" co-evolution gap. Uses git log --stat to compute per-file change frequency over a configurable window, applies language-aware pairing heuristics (Python, JS/TS, Go, Java, C#), and produces a ranked table of stale-coverage pairs. Feeds test-health and test-improve as prioritization input, not a standalone gate. Use when you want to find high-churn files whose tests have gone stale, or before running /test-improve to identify the highest- leverage targets first. | -| `/harness-e2e-check` | [--item N] [--output ] | [`harness-e2e-check/SKILL.md`](../skills/harness-e2e-check/SKILL.md) | On-demand end-to-end integration check of the dev-team plugin's own harness mechanisms — failure-class routing, dead-end detection, evidence bundles, invariants/rollback, the REFACTOR-phase test-freeze guard family, lesson-validation weighting, and the handoff rename — running each live rather than trusting a per-PR test result. Originated as issue #907's post-merge integration test plan; this is that plan made repeatable. Use when the user says "run the harness e2e check", "re-run 907", "smoke-test the harness", or after any batch of harness-mechanism changes lands on main. | -| `/headless-run` | [--cwd DIR] [--model MODEL] [--timeout SECS] | [`headless-run/SKILL.md`](../skills/headless-run/SKILL.md) | Run a Claude Code skill or command headlessly in an isolated subprocess — fresh session id, clean HOME and config dir, scrubbed env, JSON result, timeout. Use for scripted one-shot invocations and benchmark-harness cases (e.g. running /code-review once per case), to run an isolated claude -p, or to avoid a nested run reusing the parent Remote session identity or tool surface. Trigger phrases include "run a skill headlessly", "isolated claude -p", "benchmark harness invocation", "run /code-review headlessly", "run it once per case", and "avoid nested session reuse". | -| `/long-eval` | [status\|ensure-alive] --module --out | [`long-eval/SKILL.md`](../skills/long-eval/SKILL.md) | Run an eval that takes longer than one cloud-session container lifetime — agent calibration, prompt A/B sweeps, judge-panel scoring — so it survives the frequent container recycles that kill in-process work. Use when the user says "run this long eval", "the eval keeps dying on restart", "make the eval survive restarts", "resume the eval", "keep the eval alive", or when a full-corpus calibration/benchmark will clearly outlast a single session. Ships a restart-durable engine + CLI so nothing is re-invented per eval. | -| `/mutation-night-watch` | no flags — run directly | [`mutation-night-watch/SKILL.md`](../skills/mutation-night-watch/SKILL.md) | Launch, schedule, and hand off an unattended, LLM-free overnight mutation night-watch run. Use when the user wants a mutation-score baseline waiting each morning without paying LLM cost or blocking a session overnight, says "run mutation testing overnight", "schedule a nightly mutation scan", "set up a mutation night watch", or asks how to get an unattended mutation baseline. Wraps mutation_nightwatch.py — report-only measurement, never generation. | -| `/orchestration-benchmark` | [--task-class ] [--runs ] [--dry-run] | [`orchestration-benchmark/SKILL.md`](../skills/orchestration-benchmark/SKILL.md) | Run the pre-registered solo-vs-coordinated A/B benchmark: three arms (solo session, current orchestration, delegation-only sweep) over the same task matrix at matched verification rigor, measuring dollar cost, token band shift, quality, rework, and wall-clock. Use when the user asks "is orchestration worth it", "benchmark the pipeline against a solo run", "measure delegation value", "orchestration benchmark", or wants the crossover threshold below which a solo session beats delegation. | -| `/proxy-resilience` | no flags — run directly | [`proxy-resilience/SKILL.md`](../skills/proxy-resilience/SKILL.md) | Bounded backoff, retry ceiling, and escalation convention for repeated failures against a corporate Anthropic proxy. Use when you observe repeated HTTP 429 rate-limit responses or connection-refused errors that reference a proxy host, or the user says "proxy is rate-limiting", "429 from the proxy", "proxy connection refused", or "corporate proxy is flaky". | -| `/repo-review` | [--path ] [--json] [--pdf] | [`repo-review/SKILL.md`](../skills/repo-review/SKILL.md) | Whole-repository drift review for the review agents that a per-diff /code-review pass cannot meaningfully evaluate — accumulated file/CLAUDE.md size drift, AI-provenance verification debt, harness-config completeness, and cross-file frontend component duplication. Use when the user asks for a "repo review", "drift review", "whole-tree review", wants to check accumulated size/token drift, verification debt, or duplicated frontend components across the WHOLE codebase rather than a single diff, or periodically (e.g. every N merged PRs) to catch drift no single diff-scoped review would surface. Report-only — never gates a commit. | -| `/report-pdf` | [--out ] | [`report-pdf/SKILL.md`](../skills/report-pdf/SKILL.md) | Render a dev-team Markdown report to a polished, shareable PDF. Use when the user says "make a PDF of the report", "export the code-review report as PDF", "turn .dev-team-reports/code-review.md into a PDF", or wants any .dev-team-reports or reports Markdown file as a styled document to attach to a ticket or hand to a non-terminal stakeholder. | -| `/run-report` | [--session ] | [`run-report/SKILL.md`](../skills/run-report/SKILL.md) | Report one orchestrated run's timeline — per-state dwell time, rejection count, hook denials/bypasses grouped by cause, and cost — joined from boundary-events.jsonl, cost-metering.jsonl, and workflow-states.jsonl for a given session_id (default: most recent). Use when the user asks "how did that run go", "show the run report", "/run-report", or wants a single view of a `/ship`/`/autoship`/`/build` run instead of cross-referencing streams by hand. | -| `/stryker-xunit-v2-shim` | no flags — run directly | [`stryker-xunit-v2-shim/SKILL.md`](../skills/stryker-xunit-v2-shim/SKILL.md) | Build a xunit.v2 Stryker shim so Stryker.NET produces a valid mutation score for a xunit.v3 test project. Stryker.NET cannot observe mutant kills through xunit.v3 (it runs on the Microsoft Testing Platform), so a normal run reports a false near-zero score with almost every mutant reported Survived. Use this BEFORE running Stryker whenever the target .NET test project references xunit.v3 — including when mutation is enabled via /test-improve or /mutation-testing, or you are about to run dotnet-stryker — and as a rescue when a run already reported ~0% or everything Survived or the user says the score looks suspiciously low. When Stryker and xunit.v3 both appear, build the shim first. | -| `/test-improve` | [--parent ] [--analyze-only] [--from-phase []] [--stack ] | [`test-improve/SKILL.md`](../skills/test-improve/SKILL.md) | Consolidated analyze-then-improve test orchestrator. Defaults to lightweight ceremony; opts into heavier capabilities (Gherkin extraction, mutation testing, refactor-for-testability) only when the operator asks. Always baselines coverage (and mutation, when enabled) before any test change, runs the end-of-phase review loop after Phases 5 and 7, and produces a stable 10-section executive-summary report. Use when the user says "improve our tests", "modernize the test suite", "upgrade our tests", or runs /test-improve. | +| `/claude-setup-review` | [--path ] [--json] | [`claude-setup-review/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/claude-setup-review/SKILL.md) | Audit this project's Claude Code harness — CLAUDE.md completeness, rule clarity, skill and agent wiring, path accuracy, and agent frontmatter schema compliance. Use when the user says "review my CLAUDE.md", "audit my Claude setup", "is my Claude config right", "check my agent frontmatter", "are my skill paths correct", or after adding or restructuring CLAUDE.md, agents, or skills. Advisory — it recommends, it does not edit. | +| `/co-evolution-audit` | [--since ] [--max-commits ] [--min-churn ] [--max-test-churn ] | [`co-evolution-audit/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/co-evolution-audit/SKILL.md) | Flag production files that churn repeatedly while their paired test files do not change — the "Red Queen" co-evolution gap. Uses git log --stat to compute per-file change frequency over a configurable window, applies language-aware pairing heuristics (Python, JS/TS, Go, Java, C#), and produces a ranked table of stale-coverage pairs. Feeds test-health and test-improve as prioritization input, not a standalone gate. Use when you want to find high-churn files whose tests have gone stale, or before running /test-improve to identify the highest- leverage targets first. | +| `/harness-e2e-check` | [--item N] [--output ] | [`harness-e2e-check/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/harness-e2e-check/SKILL.md) | On-demand end-to-end integration check of the dev-team plugin's own harness mechanisms — failure-class routing, dead-end detection, evidence bundles, invariants/rollback, the REFACTOR-phase test-freeze guard family, lesson-validation weighting, and the handoff rename — running each live rather than trusting a per-PR test result. Originated as issue #907's post-merge integration test plan; this is that plan made repeatable. Use when the user says "run the harness e2e check", "re-run 907", "smoke-test the harness", or after any batch of harness-mechanism changes lands on main. | +| `/headless-run` | [--cwd DIR] [--model MODEL] [--timeout SECS] | [`headless-run/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/headless-run/SKILL.md) | Run a Claude Code skill or command headlessly in an isolated subprocess — fresh session id, clean HOME and config dir, scrubbed env, JSON result, timeout. Use for scripted one-shot invocations and benchmark-harness cases (e.g. running /code-review once per case), to run an isolated claude -p, or to avoid a nested run reusing the parent Remote session identity or tool surface. Trigger phrases include "run a skill headlessly", "isolated claude -p", "benchmark harness invocation", "run /code-review headlessly", "run it once per case", and "avoid nested session reuse". | +| `/long-eval` | [status\|ensure-alive] --module --out | [`long-eval/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/long-eval/SKILL.md) | Run an eval that takes longer than one cloud-session container lifetime — agent calibration, prompt A/B sweeps, judge-panel scoring — so it survives the frequent container recycles that kill in-process work. Use when the user says "run this long eval", "the eval keeps dying on restart", "make the eval survive restarts", "resume the eval", "keep the eval alive", or when a full-corpus calibration/benchmark will clearly outlast a single session. Ships a restart-durable engine + CLI so nothing is re-invented per eval. | +| `/mutation-night-watch` | no flags — run directly | [`mutation-night-watch/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/mutation-night-watch/SKILL.md) | Launch, schedule, and hand off an unattended, LLM-free overnight mutation night-watch run. Use when the user wants a mutation-score baseline waiting each morning without paying LLM cost or blocking a session overnight, says "run mutation testing overnight", "schedule a nightly mutation scan", "set up a mutation night watch", or asks how to get an unattended mutation baseline. Wraps mutation_nightwatch.py — report-only measurement, never generation. | +| `/orchestration-benchmark` | [--task-class ] [--runs ] [--dry-run] | [`orchestration-benchmark/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/orchestration-benchmark/SKILL.md) | Run the pre-registered solo-vs-coordinated A/B benchmark: three arms (solo session, current orchestration, delegation-only sweep) over the same task matrix at matched verification rigor, measuring dollar cost, token band shift, quality, rework, and wall-clock. Use when the user asks "is orchestration worth it", "benchmark the pipeline against a solo run", "measure delegation value", "orchestration benchmark", or wants the crossover threshold below which a solo session beats delegation. | +| `/proxy-resilience` | no flags — run directly | [`proxy-resilience/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/proxy-resilience/SKILL.md) | Bounded backoff, retry ceiling, and escalation convention for repeated failures against a corporate Anthropic proxy. Use when you observe repeated HTTP 429 rate-limit responses or connection-refused errors that reference a proxy host, or the user says "proxy is rate-limiting", "429 from the proxy", "proxy connection refused", or "corporate proxy is flaky". | +| `/repo-review` | [--path ] [--json] [--pdf] | [`repo-review/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/repo-review/SKILL.md) | Whole-repository drift review for the review agents that a per-diff /code-review pass cannot meaningfully evaluate — accumulated file/CLAUDE.md size drift, AI-provenance verification debt, harness-config completeness, and cross-file frontend component duplication. Use when the user asks for a "repo review", "drift review", "whole-tree review", wants to check accumulated size/token drift, verification debt, or duplicated frontend components across the WHOLE codebase rather than a single diff, or periodically (e.g. every N merged PRs) to catch drift no single diff-scoped review would surface. Report-only — never gates a commit. | +| `/report-pdf` | [--out ] | [`report-pdf/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/report-pdf/SKILL.md) | Render a dev-team Markdown report to a polished, shareable PDF. Use when the user says "make a PDF of the report", "export the code-review report as PDF", "turn .dev-team-reports/code-review.md into a PDF", or wants any .dev-team-reports or reports Markdown file as a styled document to attach to a ticket or hand to a non-terminal stakeholder. | +| `/run-report` | [--session ] | [`run-report/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/run-report/SKILL.md) | Report one orchestrated run's timeline — per-state dwell time, rejection count, hook denials/bypasses grouped by cause, and cost — joined from boundary-events.jsonl, cost-metering.jsonl, and workflow-states.jsonl for a given session_id (default: most recent). Use when the user asks "how did that run go", "show the run report", "/run-report", or wants a single view of a `/ship`/`/autoship`/`/build` run instead of cross-referencing streams by hand. | +| `/stryker-xunit-v2-shim` | no flags — run directly | [`stryker-xunit-v2-shim/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/stryker-xunit-v2-shim/SKILL.md) | Build a xunit.v2 Stryker shim so Stryker.NET produces a valid mutation score for a xunit.v3 test project. Stryker.NET cannot observe mutant kills through xunit.v3 (it runs on the Microsoft Testing Platform), so a normal run reports a false near-zero score with almost every mutant reported Survived. Use this BEFORE running Stryker whenever the target .NET test project references xunit.v3 — including when mutation is enabled via /test-improve or /mutation-testing, or you are about to run dotnet-stryker — and as a rescue when a run already reported ~0% or everything Survived or the user says the score looks suspiciously low. When Stryker and xunit.v3 both appear, build the shim first. | +| `/test-improve` | [--parent ] [--analyze-only] [--from-phase []] [--stack ] | [`test-improve/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/dev-team/skills/test-improve/SKILL.md) | Consolidated analyze-then-improve test orchestrator. Defaults to lightweight ceremony; opts into heavier capabilities (Gherkin extraction, mutation testing, refactor-for-testability) only when the operator asks. Always baselines coverage (and mutation, when enabled) before any test change, runs the end-of-phase review loop after Phases 5 and 7, and produces a stable 10-section executive-summary report. Use when the user says "improve our tests", "modernize the test suite", "upgrade our tests", or runs /test-improve. | diff --git a/plugins/dev-team/hooks/lib/build_skills_index.py b/plugins/dev-team/hooks/lib/build_skills_index.py index 1ad0a1091..cc9a944a0 100755 --- a/plugins/dev-team/hooks/lib/build_skills_index.py +++ b/plugins/dev-team/hooks/lib/build_skills_index.py @@ -42,6 +42,8 @@ _SCRIPT_DIR = Path(__file__).resolve().parent _DEFAULT_PLUGIN_DIR = _SCRIPT_DIR.parents[1] # lib -> hooks -> dev-team +_REPO_ROOT = _DEFAULT_PLUGIN_DIR.parents[1] # dev-team -> plugins -> repo root +_BLOB_BASE = "https://github.com/bdfinst/agentic-dev-team/blob/main" # Options-column sentinel values _OPT_NO_FLAGS = "no flags — run directly" @@ -152,6 +154,24 @@ def _cell(text: str) -> str: return " ".join(str(text).split()).replace("|", "\\|") +def _source_link(label: str, target: Path, fallback_rel: str) -> str: + """Link `label` to `target`'s source. + + The rendered catalog (docs/skills.md) is published on the MkDocs site, + whose assembled tree (scripts/assemble-docs.sh) copies only each plugin's + docs/ directory — not skills/ or commands/. A relative `../skills/...` + link resolves in a repo checkout but 404s on the deployed page (#2103), + so link to the file's permanent GitHub source instead. `target` outside + the repo tree (synthetic paths used by tests) keeps the old repo-relative + form, which is never published. + """ + try: + rel = target.resolve().relative_to(_REPO_ROOT) + except ValueError: + return f"[`{label}`]({fallback_rel})" + return f"[`{label}`]({_BLOB_BASE}/{rel.as_posix()})" + + def _options_value(fm: dict) -> str: """Return the Options column value for a skill/command's frontmatter.""" if fm.get("user-invocable") is True: @@ -211,7 +231,9 @@ def _add_entry(key: str, fm: dict, link: str) -> None: for skill_md in sorted(skills_dir.glob("*/SKILL.md")): folder = skill_md.parent.name fm = _frontmatter(skill_md) - link = f"[`{folder}/SKILL.md`](../skills/{folder}/SKILL.md)" + link = _source_link( + f"{folder}/SKILL.md", skill_md, f"../skills/{folder}/SKILL.md" + ) _add_entry(folder, fm, link) # commands/.md — keyed by frontmatter `name` @@ -220,7 +242,9 @@ def _add_entry(key: str, fm: dict, link: str) -> None: for cmd_md in sorted(commands_dir.glob("*.md")): fm = _frontmatter(cmd_md) key = str(fm.get("name") or cmd_md.stem) - link = f"[`commands/{cmd_md.name}`](../commands/{cmd_md.name})" + link = _source_link( + f"commands/{cmd_md.name}", cmd_md, f"../commands/{cmd_md.name}" + ) _add_entry(key, fm, link) display = [(name, buckets[name]) for name in order if buckets.get(name)] diff --git a/plugins/dev-team/knowledge/agent-registry.md b/plugins/dev-team/knowledge/agent-registry.md index a8bd2d686..d102f5408 100644 --- a/plugins/dev-team/knowledge/agent-registry.md +++ b/plugins/dev-team/knowledge/agent-registry.md @@ -21,7 +21,7 @@ This file contains the complete registry tables. CLAUDE.md references this file | Product Manager | `agents/product-manager.md` | 1,221 | Requirements, prioritization | | QA/SQA Engineer | `agents/qa-engineer.md` | 4,188 | Testing, quality assurance | | Security Engineer | `agents/security-engineer.md` | 1,115 | Security analysis, threat modeling | -| Software Engineer | `agents/software-engineer.md` | 2,122 | Code generation, implementation | +| Software Engineer | `agents/software-engineer.md` | 2,458 | Code generation, implementation | | Technical Writer | `agents/tech-writer.md` | 939 | Documentation, style consistency | | UI/UX Designer | `agents/ui-ux-designer.md` | 583 | Interface design, UX | | **All team agents** | | **~30,233** | | diff --git a/plugins/dev-team/knowledge/telemetry-schema.md b/plugins/dev-team/knowledge/telemetry-schema.md index 2f3148d4a..323d05dba 100644 --- a/plugins/dev-team/knowledge/telemetry-schema.md +++ b/plugins/dev-team/knowledge/telemetry-schema.md @@ -248,7 +248,7 @@ aggregate counts only, no file names, prompts, command strings, or code. | `sessions`, `transcripts` | integer | How many sessions/transcripts the digest covered | | `tokens` | object | Input/output/cache token totals | | `cost_usd`, `cache_hit_ratio` | number | Session cost and cache-read efficiency | -| `rework` | object | `failed_edits`, `repeated_file_edits`, `retried_bash_commands`, `repeated_verify_runs`, `permission_denials`, `compaction_events` | +| `rework` | object | `failed_edits`, `repeated_file_edits`, `retried_bash_commands`, `retried_bash_commands_by_skill`/`retried_bash_commands_by_agent` (#2110 — each retry attributed, at the moment it's detected, to whichever skill/agent is sticky-active; `retried_bash_commands` is the derived sum, never a second independent count), `repeated_verify_runs`, `permission_denials`, `compaction_events` | | `accuracy` | object | `tool_calls`, `tool_error_rate`, `user_correction_turns`, `by_skill`/`by_agent` (correction counts, double-bucketed against whichever skill/agent is sticky-active), `correction_rate_by_skill`/`correction_rate_by_agent` (corrections per skill invocation / agent dispatch — absent for a never-invoked name, never a misleading `0.0`), `correction_causes` (#2013, below) | | `utilization` | object | `skills_invoked`, `agents_invoked` (agent RUNS), `agent_dispatches` (Agent/Task tool calls), `never_observed_skills`, `never_observed_agents` | diff --git a/plugins/dev-team/scripts/lib/session_log/signals.py b/plugins/dev-team/scripts/lib/session_log/signals.py index efb4af265..3cb5aaf50 100644 --- a/plugins/dev-team/scripts/lib/session_log/signals.py +++ b/plugins/dev-team/scripts/lib/session_log/signals.py @@ -297,7 +297,15 @@ def track_edit(block: dict, edits_per_file: Counter, thread: dict) -> None: thread["edited_since_verify"] = True -def track_bash(block: dict, bash_signal_counts: Counter, thread: dict) -> None: +def track_bash( + block: dict, + bash_signal_counts: Counter, + thread: dict, + *, + active: dict | None = None, + retried_by_skill: Counter | None = None, + retried_by_agent: Counter | None = None, +) -> None: """Bash-retry / commit-bypass / stuck-verify-loop concern (#111, #708): normalize the command for near-identical retry detection, detect a stuck-verify-loop repeat (the same normalized verify command run again @@ -308,7 +316,16 @@ def track_bash(block: dict, bash_signal_counts: Counter, thread: dict) -> None: per-transcript-file dict). Retries and repeated verify runs are only meaningful within a thread: a review panel's sibling agents share their parent's sessionId, so a session-keyed tally would score fifteen agents - each running `git diff --cached` once as fourteen retries.""" + each running `git diff --cached` once as fourteen retries. + + `active`/`retried_by_skill`/`retried_by_agent` (#2110) attribute each + retry, at the moment it's detected, to whichever skill/agent is the + thread's current sticky pointer (`active["skill"]`/`active["agent"]`, + the same pointer `accumulate_skill_agent_signals` maintains and the + correction-turn signal already attributes against) — "unattributed" + when neither is set. All three are optional and default to no + attribution, so a caller with no `active` pointer to offer (there is + none today) gets the prior behavior unchanged.""" name = block.get("name", "?") inp = block.get("input", {}) if isinstance(block.get("input"), dict) else {} if name != "Bash" or not isinstance(inp.get("command"), str): @@ -316,6 +333,14 @@ def track_bash(block: dict, bash_signal_counts: Counter, thread: dict) -> None: cmd = inp["command"].strip() # near-identical retry detection: normalize whitespace norm = re.sub(r"\s+", " ", cmd) + if active is not None and thread["bash_commands"][norm] >= 1: + # This exact normalized command already ran once in this thread — + # this call is a retry, attributed to whichever skill/agent is + # active right now. + if retried_by_skill is not None: + retried_by_skill[active.get("skill") or "unattributed"] += 1 + if retried_by_agent is not None: + retried_by_agent[active.get("agent") or "unattributed"] += 1 thread["bash_commands"][norm] += 1 if classify.VERIFY_RE.search(cmd): if thread["last_verify_norm"] == norm and not thread["edited_since_verify"]: diff --git a/plugins/dev-team/scripts/lib/session_report_downstream.py b/plugins/dev-team/scripts/lib/session_report_downstream.py index 96ccd57e2..296869387 100644 --- a/plugins/dev-team/scripts/lib/session_report_downstream.py +++ b/plugins/dev-team/scripts/lib/session_report_downstream.py @@ -91,18 +91,25 @@ def _accumulate_skill_agent_signals_downstream(content, skills_invoked, agent_di def _shape_rework( failed_edits: int, repeated_file_edits: dict, - retried_bash_commands: int, + retried_bash_by_skill: Counter, + retried_bash_by_agent: Counter, repeated_verify_runs: int, permission_denials: int, compaction_events: int, ) -> dict: """The `rework` sub-object's shape -- identical between `extract_downstream()`'s per-transcript accumulation and `combine()`'s - cross-project merge, previously duplicated verbatim in both.""" + cross-project merge, previously duplicated verbatim in both. + + `retried_bash_commands` (#2110) is derived from `retried_bash_by_skill` + rather than passed separately -- a single source of truth, matching + #2108's own lesson about a scalar and its breakdown drifting apart.""" return { "failed_edits": failed_edits, "repeated_file_edits": dict(sorted(repeated_file_edits.items())), - "retried_bash_commands": retried_bash_commands, + "retried_bash_commands": sum(retried_bash_by_skill.values()), + "retried_bash_commands_by_skill": dict(sorted(retried_bash_by_skill.items())), + "retried_bash_commands_by_agent": dict(sorted(retried_bash_by_agent.items())), "repeated_verify_runs": repeated_verify_runs, "permission_denials": permission_denials, "compaction_events": compaction_events, @@ -204,7 +211,8 @@ def extract_downstream( correction_by_skill = Counter() correction_by_agent = Counter() correction_causes = _new_correction_causes_state() - retried_bash = 0 + retried_bash_by_skill = Counter() + retried_bash_by_agent = Counter() skills_invoked = Counter() agent_dispatches = Counter() @@ -281,7 +289,14 @@ def extract_downstream( if btype == "tool_use": _track_tool_call(block, pending_tool, tool_calls) _track_edit(block, edits_per_file, thread) - _track_bash(block, bash_signal_counts, thread) + _track_bash( + block, + bash_signal_counts, + thread, + active=active, + retried_by_skill=retried_bash_by_skill, + retried_by_agent=retried_bash_by_agent, + ) elif btype == "tool_result": _classify_tool_result(block, pending_tool, tool_errors, error_counts) @@ -306,7 +321,6 @@ def extract_downstream( agent_runs[label] += 1 elif records_in_window: main_transcripts += 1 - retried_bash += sum(n - 1 for n in thread["bash_commands"].values() if n > 1) repeated_file_edits = {f: n for f, n in edits_per_file.items() if n > 1} agents_invoked = agent_runs if subagent_layout_present else agent_dispatches @@ -331,7 +345,8 @@ def extract_downstream( "rework": _shape_rework( error_counts["failed_edits"], repeated_file_edits, - retried_bash, + retried_bash_by_skill, + retried_bash_by_agent, bash_signal_counts["repeated_verify_runs"], error_counts["permission_denials"], compaction_events, @@ -385,6 +400,8 @@ def combine(digests: dict[str, dict], registry: dict) -> dict: skills_invoked = Counter() agents_invoked = Counter() agent_dispatches = Counter() + retried_bash_by_skill = Counter() + retried_bash_by_agent = Counter() for d in digests.values(): sessions += d["sessions"] @@ -399,7 +416,8 @@ def combine(digests: dict[str, dict], registry: dict) -> dict: rework["failed_edits"] += rw["failed_edits"] for f, n in rw["repeated_file_edits"].items(): repeated_file_edits[f] += n - rework["retried_bash_commands"] += rw["retried_bash_commands"] + _merge_counters(retried_bash_by_skill, rw.get("retried_bash_commands_by_skill", {})) + _merge_counters(retried_bash_by_agent, rw.get("retried_bash_commands_by_agent", {})) rework["repeated_verify_runs"] += rw["repeated_verify_runs"] rework["permission_denials"] += rw["permission_denials"] rework["compaction_events"] += rw["compaction_events"] @@ -438,7 +456,8 @@ def combine(digests: dict[str, dict], registry: dict) -> dict: "rework": _shape_rework( rework["failed_edits"], repeated_file_edits, - rework["retried_bash_commands"], + retried_bash_by_skill, + retried_bash_by_agent, rework["repeated_verify_runs"], rework["permission_denials"], rework["compaction_events"], diff --git a/plugins/dev-team/scripts/lib/session_report_maintainer.py b/plugins/dev-team/scripts/lib/session_report_maintainer.py index 9eb47c504..f3ff235d9 100644 --- a/plugins/dev-team/scripts/lib/session_report_maintainer.py +++ b/plugins/dev-team/scripts/lib/session_report_maintainer.py @@ -206,7 +206,8 @@ def extract_maintainer( subagent_layout_present = False sessions: set[str] = set() edits_per_file = Counter() - retried_bash_total = 0 + retried_bash_by_skill = Counter() + retried_bash_by_agent = Counter() bash_signal_counts = Counter() commit_attempt_events: list[tuple[str | None, bool]] = [] error_counts = Counter() @@ -323,7 +324,14 @@ def extract_maintainer( if btype == "tool_use": _track_tool_call(block, pending_tool, tool_calls) _track_edit(block, edits_per_file, thread) - _track_bash(block, bash_signal_counts, thread) + _track_bash( + block, + bash_signal_counts, + thread, + active=active, + retried_by_skill=retried_bash_by_skill, + retried_by_agent=retried_bash_by_agent, + ) bblock_input = ( block.get("input", {}) if isinstance(block.get("input"), dict) @@ -367,10 +375,13 @@ def extract_maintainer( agent_runs[label] += 1 elif records_seen: main_transcripts += 1 - retried_bash_total += sum(n - 1 for n in thread["bash_commands"].values() if n > 1) repeated_file_edits = {f: n for f, n in edits_per_file.items() if n > 1} - retried_bash = retried_bash_total + # Single source of truth (#2110): the scalar is the sum of the live, + # per-event attribution below, not a second independent computation — + # the two could otherwise drift the way the churn-report window key did + # (#2108). + retried_bash = sum(retried_bash_by_skill.values()) failed_edits = error_counts["failed_edits"] permission_denials = error_counts["permission_denials"] repeated_verify_runs = bash_signal_counts["repeated_verify_runs"] @@ -421,6 +432,8 @@ def extract_maintainer( "failed_edits": failed_edits, "repeated_file_edits": dict(sorted(repeated_file_edits.items())), "retried_bash_commands": retried_bash, + "retried_bash_commands_by_skill": dict(sorted(retried_bash_by_skill.items())), + "retried_bash_commands_by_agent": dict(sorted(retried_bash_by_agent.items())), "repeated_verify_runs": repeated_verify_runs, "permission_denials": permission_denials, "compaction_events": compaction_events, @@ -543,6 +556,7 @@ def sync_record( """One per-session, metrics-only record for cross-machine aggregation (#178).""" base = slim_record(digest) tok = digest.get("token", {}) + rew = digest.get("rework", {}) acc = digest.get("accuracy", {}) util = digest.get("utilization", {}) by_model = { @@ -562,7 +576,15 @@ def sync_record( "cache_hit_ratio": base["cache_hit_ratio"], "by_model": by_model, "by_thread": tok.get("by_agent_type", tok.get("by_subagent", {})), - "rework": base["rework"], + "rework": { + **base["rework"], + "retried_bash_commands_by_skill": dict( + sorted(rew.get("retried_bash_commands_by_skill", {}).items()) + ), + "retried_bash_commands_by_agent": dict( + sorted(rew.get("retried_bash_commands_by_agent", {}).items()) + ), + }, "accuracy": { **base["accuracy"], "by_skill": dict(sorted(acc.get("by_skill", {}).items())), @@ -638,8 +660,28 @@ def cmd_sync( session_paths[0], ) project, ts = _project_and_ts(main) + # The session's own .claude/metrics/boundary-events.jsonl -- used + # below both to correlate `gate_ran` events against this + # session's commit attempts (#2106: omitting this argument here + # left EVERY synced session's gate_ran_events read as `None` -> + # `[]`, so every non-bypassed commit attempt classified + # "absent" regardless of whether the git-native pre-commit hook + # actually ran -- the digest's "100% gate_ran_absent" reflected + # this sync path never looking, not the gate never firing) and + # to resolve the session's own plugin_version below (#2018). + raw_cwd = _first_cwd(main) + boundary_events_path = ( + Path(raw_cwd) / ".claude" / "metrics" / "boundary-events.jsonl" + if raw_cwd + else None + ) digest = extract_maintainer( - session_paths, pricing, registry, plugin_version, projects_root=root + session_paths, + pricing, + registry, + plugin_version, + projects_root=root, + boundary_events_path=boundary_events_path, ) # #2018: this per-session sync record is what durably archives # onto .claude/metrics/session-digest.jsonl at every @@ -652,12 +694,8 @@ def cmd_sync( # keyed by this loop's raw session_id -- before building the # sync record; falls back to "unknown" when the session's real # cwd can't be determined or has no matching boundary event. - raw_cwd = _first_cwd(main) digest["plugin_version"] = ( - resolve_session_plugin_version( - session_id, - Path(raw_cwd) / ".claude" / "metrics" / "boundary-events.jsonl", - ) + resolve_session_plugin_version(session_id, boundary_events_path) if raw_cwd else "unknown" ) @@ -742,6 +780,10 @@ def _read_synced_records(digests_root: Path) -> list[dict]: utilization, ("skills_invoked", "agents_invoked", "agent_dispatches") ) _normalize_name_dicts(accuracy, ("by_skill", "by_agent")) + _normalize_name_dicts( + rework, + ("retried_bash_commands_by_skill", "retried_bash_commands_by_agent"), + ) _normalize_numeric_fields( tokens, ( @@ -751,7 +793,16 @@ def _read_synced_records(digests_root: Path) -> list[dict]: "cache_read_input_tokens", ), ) + # The two dict-valued fields just sanitized above are captured + # before the numeric-only comprehension below, which would + # otherwise drop them (`_REWORK_KEYS` is numeric-scalar-only, + # like `repeated_file_edits`'s already-summarized length) or + # crash `_safe_number` on a dict value. + retried_by_skill = rework["retried_bash_commands_by_skill"] + retried_by_agent = rework["retried_bash_commands_by_agent"] rework = {k: _safe_number(v) for k, v in rework.items() if k in _REWORK_KEYS} + rework["retried_bash_commands_by_skill"] = retried_by_skill + rework["retried_bash_commands_by_agent"] = retried_by_agent _normalize_numeric_fields( accuracy, ("tool_calls", "tool_error_rate", "user_correction_turns") ) @@ -822,6 +873,8 @@ def rollup( cost = 0.0 cr = cc = 0 rew = Counter() + retried_bash_by_skill = Counter() + retried_bash_by_agent = Counter() tool_calls = 0 err_weighted = 0.0 corrections = 0 @@ -859,6 +912,10 @@ def rollup( for k, v in rwk.items(): if isinstance(v, (int, float)): rew[k] += v + for name, k in (rwk.get("retried_bash_commands_by_skill", {}) or {}).items(): + retried_bash_by_skill[name] += k + for name, k in (rwk.get("retried_bash_commands_by_agent", {}) or {}).items(): + retried_bash_by_agent[name] += k acc = r.get("accuracy", {}) if isinstance(r.get("accuracy"), dict) else {} n = acc.get("tool_calls", 0) or 0 tool_calls += n @@ -898,7 +955,11 @@ def _hostmap(d: dict) -> dict: "cache_hit_ratio": round(cr / (cr + cc), 4) if (cr + cc) else 0.0, "by_host": _hostmap(by_host), "by_project": _hostmap(by_project), - "rework": dict(sorted(rew.items())), + "rework": { + **dict(sorted(rew.items())), + "retried_bash_commands_by_skill": dict(sorted(retried_bash_by_skill.items())), + "retried_bash_commands_by_agent": dict(sorted(retried_bash_by_agent.items())), + }, "accuracy": { "tool_calls": tool_calls, "tool_error_rate": round(err_weighted / tool_calls, 4) diff --git a/plugins/dev-team/skills/build/SKILL.md b/plugins/dev-team/skills/build/SKILL.md index 6bd786e2d..b367f928d 100644 --- a/plugins/dev-team/skills/build/SKILL.md +++ b/plugins/dev-team/skills/build/SKILL.md @@ -188,6 +188,8 @@ Work each step **one behavior at a time** — never all the code then all the te - **Out of scope / unchanged**: `hooks/verify_guard.py` is not modified and continues to own the separate, syntactic case — the same verify command re-run with zero intervening edits. This repair loop fires only when edits *do* happen but the failure signature doesn't change. 3. **REFACTOR (every green, never skipped).** Clean up structure, naming, duplication without changing behavior. Runs in **every** per-behavior cycle: never deferred to an end-of-build pass, never made conditional on task size or complexity (`docs/experiments/RECOMMENDATIONS.md` Rec 4 — deleting just this step erased the cadence's changeability advantage entirely). **Tests are frozen for the phase** — a refactor must never change a test (enforced by the freeze/revert guards; recovery: return to the TEST phase, change the test there, re-verify green, re-enter REFACTOR). Run tests again — they must still pass. If tests break, undo and try a smaller change. A no-op refactor (nothing worth changing, stated in one line) satisfies the phase — the mandate is the check on every green, not a diff — and any refactor made stays within the code the step touched; adjacent-file cleanups are follow-ups, not refactors. + + **Self-verification, mandatory (#2107).** Before this step may be marked done (sub-step 5), also run the project's lint and type-check tools — whichever apply to its stack (`ruff`/ESLint/`tsc`/`pmd`/`dotnet build`, etc.) — when the project has them, and confirm they pass; paste the output alongside the test run. This closes a real gap the TEST phase's test-only hard gate leaves open: a green suite proves behavior, not that the REFACTOR pass above left no unused import, type error, or style violation behind — those otherwise surface only downstream, in Step 6's backstop review, after the step already reads `[x]`. Same bar `quality-gate-pipeline`'s Phase 2 ("Required Evidence") already states for every completion claim; this is that bar made explicit and mandatory at the one moment in this cadence it was previously only implied. Skip only what the project genuinely has none of (state which, in one line) — never skip because it "should still be clean." 4. **Inline review checkpoint — granularity scales with complexity.** *Where* the checkpoint runs depends on the step's **Complexity** classification (review *depth* still scales too): - **trivial**: Skip inline review. The final `/code-review` (step 6) covers all modified files. - **standard**: **Defer** review to the slice boundary (sub-step 6) — do not review now. Track the step's changed files so the slice checkpoint reviews them in one batch. Per-step review on standard steps is N near-identical passes where one at slice end largely does the same work, and the final `/code-review` (step 6) remains the backstop. This is the batching win — fewer review dispatches per multi-step slice at bounded quality risk. @@ -195,6 +197,7 @@ Work each step **one behavior at a time** — never all the code then all the te - If no complexity is specified, default to **standard**. - **UI changes (any complexity)**: After the relevant review passes (per-step for complex, at the slice checkpoint for standard), run browser verification via `/browse` in automated smoke test mode. Skip with warning if the dev server is not running. See `${CLAUDE_PLUGIN_ROOT}/knowledge/three-phase-workflow.md#phase-3-implement` Stage 3. 5. **Mark step done** — Use the Edit tool to update the plan file's `## Build Progress` section on disk: + - **Do not flip a checkbox on a "should work"/"should be fixed" impression.** The self-verification evidence required in sub-step 3 above (tests, and lint/type-check where the project has them) must be fresh from this session — not recalled from earlier in the conversation, not assumed — before this bullet may fire. This is the same completion-claim bar `quality-gate-pipeline`'s Phase 2 states generally, made mandatory at this specific step-completion moment (#2107). - Change `- [ ] Step N.M: ` to `- [x] Step N.M: <title>` for the completed step. - When every step under a slice is `[x]`, that is not the same as the slice being done — check off the parent `- [ ] Slice N: <title>` only after sub-steps 4.9 (runtime verification) and 4.10 (invariants) both pass, if applicable; a slice with no runtime surface and no declared invariants has nothing further to wait on and may be checked off once its steps and review checkpoint(s) are done. - After all slices are `[x]`, change `**Status**: approved` to `**Status**: in-progress`. diff --git a/plugins/dev-team/skills/code-review/SKILL.md b/plugins/dev-team/skills/code-review/SKILL.md index 6a4c0a9d4..b2a4f5c91 100644 --- a/plugins/dev-team/skills/code-review/SKILL.md +++ b/plugins/dev-team/skills/code-review/SKILL.md @@ -292,9 +292,34 @@ deterministically with the shared helper (not by eyeballing the file list): python3 "$CLAUDE_PLUGIN_ROOT/skills/code-review/scripts/change_shape.py" --files <target files> ``` -It prints `{"hasRuntimeSurface": <bool>, "isTestOnly": <bool>, "skipLenses": -[...]}`. When `skipLenses` is non-empty, exclude those agents from this run and -note the skip in the report (they were gated by change shape, not by `Scope:`). +It prints `{"hasRuntimeSurface": <bool>, "isTestOnly": <bool>, "isProseOnly": +<bool>, "skipLenses": [...]}`. When `skipLenses` is non-empty, exclude those +agents from this run and note the skip in the report (they were gated by +change shape, not by `Scope:`). + +`isProseOnly` (#2104) reports a third, independent property: every changed +file is `.md`/`.mdx`. Unlike `hasRuntimeSurface`, this makes **no** exception +for functional Claude-config markdown (`agents/`, `skills/`, `knowledge/`, +`.claude/`, …) — that markdown drives agent behavior, so `performance-review` +and `correctness-review` still apply to it, but a `.md` file cannot exhibit an +injection/auth/data-exposure vulnerability, a domain-boundary leak, a +test-coverage gap, or a resource leak/N+1 query regardless of whether it also +happens to be functional config. When `isProseOnly` is true, `skipLenses` +additionally drops `security-review`, `domain-review`, `test-review`, and +`performance-review` — each of those four agents' own `## Skip` clause +already self-reports skip on a documentation-only target, so keeping them in +the roster either pays for a self-reported skip or, worse, produces an +ungrounded finding stretched to fit the lens (the motivating case: a 9-agent +panel dispatched against a single-file skill-markdown diff produced +elaborate security/domain/test/performance framing for what were really +prose nits). `correctness-review`, `spec-compliance-review`, `doc-review`, +`structure-review`, `naming-review`, and `arch-review` stay in the roster — +they meaningfully review markdown-as-instructions. This is narrower than +`select_lenses.py`'s own `NON_EXECUTABLE_SKIP_ELIGIBLE` allowlist, which +considered and rejected filtering `security-review`/`domain-review` for its +broader "non-executable" category (docs **and** config/lockfiles/assets) — +see that module's comment. This gate never widens to config, so that +rejection does not apply here. `isTestOnly` (#1964) reports a second, independent property: every changed file is *provably* a test file (`knowledge/test-file-indicators.md`). It currently diff --git a/plugins/dev-team/skills/code-review/scripts/change_shape.py b/plugins/dev-team/skills/code-review/scripts/change_shape.py index a91b2182f..499beffdd 100755 --- a/plugins/dev-team/skills/code-review/scripts/change_shape.py +++ b/plugins/dev-team/skills/code-review/scripts/change_shape.py @@ -134,6 +134,46 @@ def _require_shared(module: str) -> ImportError: LOW_YIELD_LENSES = ["performance-review", "correctness-review"] +# Lenses to skip when EVERY changed file is provably prose (`.md`/`.mdx`), +# including functional Claude-config markdown (#2104). `has_runtime_surface` +# correctly treats agents/skills/knowledge/.claude markdown as runtime +# surface — it drives agent behavior, so `performance-review` and +# `correctness-review` still run against it above. But a handful of lenses +# review a *code-level* property no markdown file, functional or not, can +# exhibit: an injection/auth/data-exposure vulnerability, a domain-boundary +# leak, a test-coverage gap, or a resource leak/N+1 query. Dispatching a +# 9-agent panel (including these four) against a single-file skill-markdown +# diff produced elaborate findings framed as security/domain/test/performance +# issues that were really prose/spec-consistency nitpicks belonging to +# doc-review/spec-compliance-review/correctness-review instead. Each of these +# four agents' own `## Skip` clause already self-reports skip on a +# documentation-only target (security-review: "static assets, images, or +# documentation"; domain-review: "no business logic or domain entities +# present"; test-review: "no test files in target"; performance-review: +# "configuration, documentation, or type definitions") — dispatching them +# anyway just pays for a self-reported skip, or worse, an ungrounded finding +# stretched to fit the lens. +# +# Deliberately NARROWER than `select_lenses.py`'s own +# `NON_EXECUTABLE_SKIP_ELIGIBLE` allowlist, which considered and REJECTED +# adding security-review/domain-review/arch-review for its broader +# "non-executable" category (docs **and** config/lockfiles/assets): that +# module's own comment documents why — security-review's Skip clause does not +# cover config/lockfiles (its Scope mandates scanning them for hardcoded +# credentials) and domain-review's is a content judgment a config file's type +# alone can't answer. This module's prose-only signal is strictly `.md`/ +# `.mdx` — it never widens to config, so neither rejection applies here. +# `arch-review` and `correctness-review` are deliberately absent from this +# list for the same reason `select_lenses.py` keeps `arch-review` unfiltered: +# a pure-markdown ADR update, or a functional-config skill/agent file, is +# exactly the content their own `## Detect` sections exist to review. +PROSE_ONLY_SKIP_LENSES = [ + "security-review", "domain-review", "test-review", "performance-review", +] + +# Extensions provably incapable of holding anything but prose (lower-cased). +_PROSE_EXTENSIONS = {".md", ".mdx"} + # Lenses to skip when EVERY changed file is provably a test file (#1964). # Deliberately EMPTY until per-lens `diff_shape` outcome data justifies each # entry — see this module's docstring. Adding a name here without citing that @@ -237,24 +277,63 @@ def is_test_only(files: Iterable[str]) -> bool: return all(_is_provably_test_file(f) for f in file_list) +def _is_prose_file(file: str) -> bool: + return PurePosixPath(str(file).strip()).suffix.lower() in _PROSE_EXTENSIONS + + +def is_prose_only(files: Iterable[str]) -> bool: + """True when *every* changed file is `.md`/`.mdx` prose (#2104). + + Unlike `has_runtime_surface`, this makes no exception for functional + Claude-config markdown: a `.md` file cannot exhibit an injection + vulnerability, a domain-boundary leak, a test-coverage gap, or an N+1 + query regardless of whether it also drives agent behavior. An empty + changeset is not prose-only, matching the other predicates' empty-case + convention. + """ + file_list = [f for f in files if str(f).strip()] + if not file_list: + return False + return all(_is_prose_file(f) for f in file_list) + + def lenses_to_skip(files: Iterable[str]) -> list[str]: """Return the low-yield lenses to skip for this changeset. - Empty when the changeset has any runtime surface (run every lens). Otherwise - the doc/config-only changeset skips `performance-review` and - `correctness-review`. + Empty when the changeset has any runtime surface and is not prose-only. + A doc/config-only changeset (no runtime surface) skips `performance-review` + and `correctness-review`; a prose-only changeset (every file `.md`/`.mdx`, + including functional Claude-config markdown) additionally skips + `security-review`, `domain-review`, and `test-review` (#2104) — the two + sets are independent and union together, since a prose-only diff is + always also a no-runtime-surface diff unless it is functional config. """ file_list = [f for f in files if str(f).strip()] if not file_list: return [] # nothing to review — the caller handles empty scope + + # Ordered, deduplicated union — preserves each source list's own order and + # never lists a lens twice (e.g. `performance-review` is in both + # LOW_YIELD_LENSES and PROSE_ONLY_SKIP_LENSES for a plain-docs-only diff). + skip: list[str] = [] + seen: set[str] = set() + + def _extend(names: Iterable[str]) -> None: + for name in names: + if name not in seen: + seen.add(name) + skip.append(name) + if not has_runtime_surface(file_list): - return list(LOW_YIELD_LENSES) + _extend(LOW_YIELD_LENSES) # Runtime surface present. A test-only changeset may still narrow the # roster once TEST_ONLY_SKIP_LENSES is populated from measured data; it is - # empty today, so this returns [] and the full panel runs (#1964). - if is_test_only(file_list): - return list(TEST_ONLY_SKIP_LENSES) - return [] + # empty today, so this contributes nothing (#1964). + elif is_test_only(file_list): + _extend(TEST_ONLY_SKIP_LENSES) + if is_prose_only(file_list): + _extend(PROSE_ONLY_SKIP_LENSES) + return skip def main(argv=None) -> int: @@ -282,6 +361,7 @@ def main(argv=None) -> int: result = { "hasRuntimeSurface": has_runtime_surface(files), "isTestOnly": is_test_only(files), + "isProseOnly": is_prose_only(files), "skipLenses": skip, } print(json.dumps(result, sort_keys=True)) diff --git a/plugins/dev-team/skills/code-review/scripts/repo_invariants.py b/plugins/dev-team/skills/code-review/scripts/repo_invariants.py index 7de097ed0..3d5c6a0c5 100755 --- a/plugins/dev-team/skills/code-review/scripts/repo_invariants.py +++ b/plugins/dev-team/skills/code-review/scripts/repo_invariants.py @@ -670,6 +670,72 @@ def check_transcript_parsing_confined_to_session_log(changed_files=None) -> list return findings +# --- #2108: churn_recurrence.py / churn_coupling_report.py render_text() +# `report["window"]` access must stay safe ----------------------------------- +# +# Session-digest churn analysis (issue #2108) traced repeated review-round +# rework on the #2085 PR (bash-failure taxonomy + churn baselines slice) to +# the SAME bug recurring in two structurally-parallel renderers. Round 2's +# review fixed churn_recurrence.py's render_text(): it unconditionally read +# report["window"], a key only churn_coupling_report.py's CLI caller +# injects, so a caller rendering rank_all_files()'s own output directly hit +# a raw KeyError; fixed via report.get("window", "unknown"). Round 3's very +# next review pass found the IDENTICAL bug in churn_coupling_report.py's own +# render_text() -- same key, same failure mode, in the sibling file -- +# because nothing pinned "these two report shapes agree on how this +# caller-optional key is read." A second occurrence of the same +# mechanically-checkable fact is this repo's own trigger to ratchet it into +# a check, applied one round late. + +_CHURN_REPORT_WINDOW_KEY_FILES = ( + "scripts/lib/churn_recurrence.py", + "scripts/churn_coupling_report.py", +) +_WINDOW_KEY_RE = re.compile(r"""report\s*\[\s*['"]window['"]\s*\]""") +_WINDOW_KEY_ASSIGNMENT_RE = re.compile( + r"""report\s*\[\s*['"]window['"]\s*\]\s*=(?!=)""" +) + + +def check_churn_report_window_key_safe_access(changed_files=None) -> list[dict]: + """`churn_recurrence.py` and `churn_coupling_report.py`'s `render_text()` + must read `report["window"]` via `.get("window", "unknown")`, never a + bare index — see the section comment above for the twice-recurring bug + this pins (#2108). Assignment (`report["window"] = ...`, the CLI + caller's own injection site) is a different operation and is not + flagged. Corpus-wide by design, like the checks above: a regression on + either file is a standing gap whether or not this changeset touched it. + """ + findings = [] + for rel in _CHURN_REPORT_WINDOW_KEY_FILES: + text = _read_text(_REPO_ROOT / rel) + if not text: + continue + for lineno, line in enumerate(text.splitlines(), start=1): + if not _WINDOW_KEY_RE.search(line): + continue + if _WINDOW_KEY_ASSIGNMENT_RE.search(line): + continue # a write (the CLI's own injection site), not a read + if ".get(" in line: + continue # already safe + findings.append( + { + "invariant": "churn-report-window-key-safe-access", + "file": rel, + "message": ( + f"{rel}:{lineno} reads report['window'] via a bare " + "index. A caller rendering a report shape that never " + "sets this key (e.g. rank_all_files()'s own output) " + "raises KeyError — this exact bug already recurred " + "once, in the sibling renderer (#2085 round 2, then " + "round 3). Use report.get('window', 'unknown') " + "instead." + ), + } + ) + return findings + + # Registered checks. Each entry takes an optional `changed_files` list and # returns findings. See the module docstring for why that argument exists. CHECKS = [ @@ -679,6 +745,7 @@ def check_transcript_parsing_confined_to_session_log(changed_files=None) -> list check_scope_glob_matches_skip_prose, check_contract_failure_shapes_documented, check_transcript_parsing_confined_to_session_log, + check_churn_report_window_key_safe_access, ] diff --git a/plugins/dev-team/tests/scripts/test_change_shape.py b/plugins/dev-team/tests/scripts/test_change_shape.py index 1fe0fda6b..8c1867769 100644 --- a/plugins/dev-team/tests/scripts/test_change_shape.py +++ b/plugins/dev-team/tests/scripts/test_change_shape.py @@ -175,13 +175,78 @@ def test_the_two_never_on_intuition_lenses_are_absent(self, lens): def test_doc_only_precedence_is_unchanged_by_the_new_branch(self): """A doc/config-only changeset still yields the low-yield pair — the - test-only branch is reached only when runtime surface is present.""" + test-only branch is reached only when runtime surface is present. + `README.md` is also prose-only (#2104), which additionally unions in + `PROSE_ONLY_SKIP_LENSES`; mixed doc+config changesets (not prose-only) + are unaffected — see TestLensesToSkip.test_docs_only_skips_low_yield_lenses.""" assert change_shape.lenses_to_skip(["README.md"]) == [ "performance-review", "correctness-review", + "security-review", + "domain-review", + "test-review", ] +class TestProseOnlyClassification: + """#2104: a third, independent question — is EVERY changed file provably + prose (`.md`/`.mdx`)? Unlike `has_runtime_surface`, this makes no + exception for functional Claude-config markdown — a `.md` file cannot + exhibit a security/domain/test/performance defect regardless of whether + it drives agent behavior.""" + + @pytest.mark.parametrize( + "files", + [ + pytest.param(["README.md"], id="plain-doc"), + pytest.param(["docs/guide.md", "CHANGELOG.md"], id="multiple-docs"), + pytest.param(["notes.mdx"], id="mdx"), + pytest.param( + ["skills/setup/SKILL.md"], id="functional-config-skill-markdown" + ), + pytest.param(["agents/security-review.md"], id="functional-config-agent"), + pytest.param(["CLAUDE.md"], id="functional-config-claude-md"), + ], + ) + def test_provably_prose_only_changesets(self, files): + assert change_shape.is_prose_only(files) is True + + @pytest.mark.parametrize( + "files,why", + [ + pytest.param(["README.md", "src/app.py"], "a source file present", id="mixed-source"), + pytest.param(["README.md", "config.json"], "config is not prose", id="mixed-config"), + pytest.param([".claude/settings.json"], "json, not markdown", id="json-config"), + pytest.param([], "nothing to prove", id="empty"), + ], + ) + def test_not_prose_only_is_the_fail_safe_answer(self, files, why): + assert change_shape.is_prose_only(files) is False, why + + def test_functional_config_markdown_only_skips_the_four_code_focused_lenses(self): + """The motivating case (#2104): a single-file skill-markdown diff + currently runs the full panel because `has_runtime_surface` correctly + treats it as runtime surface. The new prose-only signal drops the four + lenses whose lens cannot apply to prose, while leaving + `correctness-review` (still meaningful on functional-config content) + untouched — it is absent from both source lists for this changeset.""" + skip = change_shape.lenses_to_skip(["skills/setup/SKILL.md"]) + assert skip == ["security-review", "domain-review", "test-review", "performance-review"] + assert "correctness-review" not in skip + assert "arch-review" not in skip + assert "doc-review" not in skip + assert "spec-compliance-review" not in skip + assert "structure-review" not in skip + assert "naming-review" not in skip + + def test_mixed_functional_and_plain_markdown_is_still_prose_only(self): + skip = change_shape.lenses_to_skip(["agents/security-review.md", "README.md"]) + assert skip == ["security-review", "domain-review", "test-review", "performance-review"] + + def test_source_file_present_keeps_the_four_lenses(self): + assert change_shape.lenses_to_skip(["skills/setup/SKILL.md", "src/app.py"]) == [] + + class TestTestOnlyCli: def test_cli_reports_is_test_only(self, capsys): rc = change_shape.main(["--files", "tests/a.test.js"]) @@ -202,3 +267,22 @@ def test_cli_always_emits_the_key(self, capsys): rc = change_shape.main(["--files", "README.md"]) assert rc == 0 assert "isTestOnly" in json.loads(capsys.readouterr().out) + + +class TestProseOnlyCli: + def test_cli_reports_is_prose_only_for_functional_config_markdown(self, capsys): + rc = change_shape.main(["--files", "skills/setup/SKILL.md"]) + assert rc == 0 + out = json.loads(capsys.readouterr().out) + assert out["isProseOnly"] is True + assert out["hasRuntimeSurface"] is True + assert out["skipLenses"] == [ + "security-review", "domain-review", "test-review", "performance-review", + ] + + def test_cli_reports_not_prose_only_for_mixed(self, capsys): + rc = change_shape.main(["--files", "README.md", "src/app.py"]) + assert rc == 0 + out = json.loads(capsys.readouterr().out) + assert out["isProseOnly"] is False + assert out["skipLenses"] == [] diff --git a/plugins/dev-team/tests/scripts/test_change_size.py b/plugins/dev-team/tests/scripts/test_change_size.py index d08667708..0962af40a 100644 --- a/plugins/dev-team/tests/scripts/test_change_size.py +++ b/plugins/dev-team/tests/scripts/test_change_size.py @@ -188,11 +188,16 @@ def test_never_readds_agent_shape_gate_already_dropped(self): skipped_by_shape = set(change_shape.lenses_to_skip(files)) assert "correctness-review" in skipped_by_shape # sanity: shape drops it + # README.md is also prose-only (#2104), so the shape gate drops + # security-review too — its own `## Skip` clause already self-reports + # skip on a documentation-only target. + assert "security-review" in skipped_by_shape size_result = change_size.parse_numstat(["1\t0\tREADME.md"]) assert change_size.qualifies_for_fast_path(size_result) is True kept_by_size = set(change_size.FAST_PATH_AGENTS) assert "correctness-review" in kept_by_size # size alone would keep it + assert "security-review" in kept_by_size # Composition order (SKILL.md Step 3): apply shape-skip first, then # size's keep-list only narrows what's left — it never re-adds. @@ -206,4 +211,6 @@ def test_never_readds_agent_shape_gate_already_dropped(self): assert "correctness-review" not in final_roster assert "performance-review" not in final_roster assert "structure-review" not in final_roster - assert final_roster == {"security-review", "spec-compliance-review", "doc-review"} + # security-review was dropped by shape above, never re-added by size. + assert "security-review" not in final_roster + assert final_roster == {"spec-compliance-review", "doc-review"} diff --git a/plugins/dev-team/tests/scripts/test_repo_invariants.py b/plugins/dev-team/tests/scripts/test_repo_invariants.py index 4b1954bc5..8055dee15 100644 --- a/plugins/dev-team/tests/scripts/test_repo_invariants.py +++ b/plugins/dev-team/tests/scripts/test_repo_invariants.py @@ -467,3 +467,77 @@ def test_allowlist_is_ignored_regardless_of_changed_files(self): repo_invariants.check_transcript_parsing_confined_to_session_log(["some/file.py"]) == repo_invariants.check_transcript_parsing_confined_to_session_log(None) ) + + +class TestChurnReportWindowKeySafeAccess: + """#2108: the same report["window"] bare-index bug recurred twice across + two structurally-parallel renderers (#2085 review round 2, then round + 3) -- the ratchet rule's textbook "reported twice" trigger.""" + + def test_clean_against_the_real_repo(self): + """The real repo, post-#2085, already fixed both occurrences. A + finding here means a regression back to a bare index.""" + assert repo_invariants.check_churn_report_window_key_safe_access() == [] + + def test_flags_a_bare_index_regression(self, tmp_path, monkeypatch): + """Proves the check can actually fail (CLAUDE.md: 'make it fail on + purpose once before you trust it').""" + repo_root = tmp_path / "repo" + (repo_root / "scripts" / "lib").mkdir(parents=True) + (repo_root / "scripts" / "lib" / "churn_recurrence.py").write_text( + 'def render_text(report, top):\n' + ' window = report["window"]\n' + ' return window\n', + encoding="utf-8", + ) + monkeypatch.setattr(repo_invariants, "_REPO_ROOT", repo_root) + + findings = repo_invariants.check_churn_report_window_key_safe_access() + + assert len(findings) == 1 + assert findings[0]["invariant"] == "churn-report-window-key-safe-access" + assert findings[0]["file"] == "scripts/lib/churn_recurrence.py" + + def test_ignores_the_assignment_site(self, tmp_path, monkeypatch): + """report["window"] = ... (the CLI caller's own injection site) is a + write, not the read bug this check targets.""" + repo_root = tmp_path / "repo" + (repo_root / "scripts").mkdir(parents=True) + (repo_root / "scripts" / "churn_coupling_report.py").write_text( + 'report["window"] = f"{args.since} days"\n', + encoding="utf-8", + ) + monkeypatch.setattr(repo_invariants, "_REPO_ROOT", repo_root) + + assert repo_invariants.check_churn_report_window_key_safe_access() == [] + + def test_ignores_an_already_safe_get_access(self, tmp_path, monkeypatch): + repo_root = tmp_path / "repo" + (repo_root / "scripts" / "lib").mkdir(parents=True) + (repo_root / "scripts" / "lib" / "churn_recurrence.py").write_text( + 'def render_text(report, top):\n' + ' window = report.get("window", "unknown")\n' + ' return window\n', + encoding="utf-8", + ) + monkeypatch.setattr(repo_invariants, "_REPO_ROOT", repo_root) + + assert repo_invariants.check_churn_report_window_key_safe_access() == [] + + def test_ignores_files_outside_the_two_named_paths(self, tmp_path, monkeypatch): + repo_root = tmp_path / "repo" + (repo_root / "scripts").mkdir(parents=True) + (repo_root / "scripts" / "unrelated.py").write_text( + 'window = report["window"]\n', encoding="utf-8" + ) + monkeypatch.setattr(repo_invariants, "_REPO_ROOT", repo_root) + + assert repo_invariants.check_churn_report_window_key_safe_access() == [] + + def test_corpus_wide_regardless_of_changed_files(self): + """Corpus-wide by design: a regression on either file is a standing + gap whether or not this changeset touched it.""" + assert ( + repo_invariants.check_churn_report_window_key_safe_access(["some/file.py"]) + == repo_invariants.check_churn_report_window_key_safe_access(None) + ) diff --git a/plugins/dev-team/tests/scripts/test_session_log_signals.py b/plugins/dev-team/tests/scripts/test_session_log_signals.py index 803537055..e9d3e1333 100644 --- a/plugins/dev-team/tests/scripts/test_session_log_signals.py +++ b/plugins/dev-team/tests/scripts/test_session_log_signals.py @@ -296,6 +296,84 @@ def test_track_bash_detects_commit_and_bypass(): assert bash_signal_counts["commit_bypasses"] == 1 +# --------------------------------------------------------------------------- +# track_bash retry attribution (#2110) +# --------------------------------------------------------------------------- + + +def test_track_bash_attributes_a_retry_to_the_active_skill(): + thread = signals.new_thread() + bash_signal_counts = Counter() + retried_by_skill = Counter() + retried_by_agent = Counter() + active = {"skill": "build", "agent": None} + block = {"name": "Bash", "input": {"command": "python3 -m pytest -q"}} + signals.track_bash( + block, bash_signal_counts, thread, + active=active, retried_by_skill=retried_by_skill, retried_by_agent=retried_by_agent, + ) + # First occurrence is not a retry. + assert retried_by_skill == {} + signals.track_bash( + block, bash_signal_counts, thread, + active=active, retried_by_skill=retried_by_skill, retried_by_agent=retried_by_agent, + ) + assert retried_by_skill == {"build": 1} + assert retried_by_agent == {"unattributed": 1} + + +def test_track_bash_attributes_a_retry_to_the_active_agent(): + thread = signals.new_thread() + bash_signal_counts = Counter() + retried_by_skill = Counter() + retried_by_agent = Counter() + active = {"skill": None, "agent": "software-engineer"} + block = {"name": "Bash", "input": {"command": "npm run lint"}} + for _ in range(3): + signals.track_bash( + block, bash_signal_counts, thread, + active=active, retried_by_skill=retried_by_skill, retried_by_agent=retried_by_agent, + ) + # 3 occurrences of the same command -> 2 retries. + assert retried_by_agent == {"software-engineer": 2} + assert retried_by_skill == {"unattributed": 2} + + +def test_track_bash_retry_attribution_follows_active_pointer_changes(): + """A thread's active skill/agent can change between retries of the SAME + command (e.g. a long-running main thread) -- each retry is attributed + to whichever pointer was active at that moment, not a single thread-wide + label.""" + thread = signals.new_thread() + bash_signal_counts = Counter() + retried_by_skill = Counter() + retried_by_agent = Counter() + active = {"skill": "fix", "agent": None} + block = {"name": "Bash", "input": {"command": "go test ./..."}} + signals.track_bash( + block, bash_signal_counts, thread, + active=active, retried_by_skill=retried_by_skill, retried_by_agent=retried_by_agent, + ) + active["skill"] = "triage" + signals.track_bash( + block, bash_signal_counts, thread, + active=active, retried_by_skill=retried_by_skill, retried_by_agent=retried_by_agent, + ) + assert retried_by_skill == {"triage": 1} + + +def test_track_bash_no_attribution_without_active_pointer(): + """The prior behavior is unchanged for a caller with no `active` to + offer: no attribution, no crash, and the underlying retry-detection + bookkeeping (`thread["bash_commands"]`) is untouched by the omission.""" + thread = signals.new_thread() + bash_signal_counts = Counter() + block = {"name": "Bash", "input": {"command": "make build"}} + signals.track_bash(block, bash_signal_counts, thread) + signals.track_bash(block, bash_signal_counts, thread) + assert thread["bash_commands"]["make build"] == 2 + + def test_sibling_agents_sharing_a_thread_do_not_cross_contaminate(): """The #1991 regression the old sid-keying existed to prevent: two 'sibling' threads (each freshly created via new_thread(), as extract() diff --git a/plugins/marketplace-dev/docs/skills.md b/plugins/marketplace-dev/docs/skills.md index cfdd9cadc..80f3e9fd4 100644 --- a/plugins/marketplace-dev/docs/skills.md +++ b/plugins/marketplace-dev/docs/skills.md @@ -15,13 +15,13 @@ Most skills are **user-invocable** as slash commands — shown as `/name`; run t | Skill | Options | File | Description | | --- | --- | --- | --- | -| `/add-plugin` | <name@marketplace> [--repo <owner/repo>] | [`add-plugin/SKILL.md`](../skills/add-plugin/SKILL.md) | Install a Claude Code plugin and register it in settings.json so the full team can replicate the install. Use this whenever adding a new plugin to the project — it keeps settings.json in sync with what is actually installed. | -| `/agent-add` | <description-or-url> [--plugin <dir>] [--name <name>] [--type review\|team] [--model sonnet\|opus\|haiku\|fable\|inherit] [--effort low\|medium\|high\|xhigh\|max] [--memory user\|project\|local] [--isolation worktree] [--color <color>] [--max-turns <int>] [--background true\|false] [--skills <name1,name2,...>] [--context diff-only\|full-file\|project-structure] [--lang <exts>] [--dry] | [`agent-add/SKILL.md`](../skills/agent-add/SKILL.md) | Create a new Claude Code agent file (review or team type) following the official sub-agent schema and token-efficiency budgets. Use when the user wants to add a new review agent, detect a new category of code issue, create a team agent persona, or says things like "add an agent for X", "create a reviewer for Y", "new team agent for Z". Also use when given a URL to a coding standard that should become a review agent. | -| `/agent-create` | no flags — run directly | [`agent-create/SKILL.md`](../skills/agent-create/SKILL.md) | Create new Claude Code sub-agent files following the official schema and token-efficiency budgets. Handles both review agents (JSON output, read-only tools, ≤ 40-line body) and team agents (prose output, action tools, ≤ 75-line body). Use when the user says "add an agent", "create a reviewer for X", "new team agent for Y", or when /agent-add is invoked. Validates against /plugin-audit before writing. Updates the agent registry and plugin CLAUDE.md after success. | -| `/agent-remove` | <agent-name> [--plugin <dir>] [--dry] | [`agent-remove/SKILL.md`](../skills/agent-remove/SKILL.md) | Remove an agent from the system — deletes the agent file, cleans up all registry entries, removes cross-references, and updates documentation. Use when the user says "remove the X agent", "delete X-review", "retire the X role", or "we no longer need X". Handles both team agents and review agents. Always confirms before deleting. | -| `/agent-skill-authoring` | no flags — run directly | [`agent-skill-authoring/SKILL.md`](../skills/agent-skill-authoring/SKILL.md) | Conventions, anti-patterns, and meta-patterns for writing skills (and the shared agent/skill philosophy). Use when creating or editing a SKILL.md file, or when reviewing the agent-vs-skill separation. For the procedural workflow that generates a new agent file, use the agent-create skill (invoked by /agent-add). | -| `/agent-type-advisor` | <prose use-case \| path/to/agent-or-skill.md> | [`agent-type-advisor/SKILL.md`](../skills/agent-type-advisor/SKILL.md) | Recommend whether a plugin capability should be a markdown (LLM-interpreted) unit or a deterministic script. Use when designing a new agent/skill ("should this be markdown or a script?"), or when auditing an existing agent/skill file for a type mismatch. Accepts either a prose use-case description (forward- looking, new unit) or a path to an existing agent/skill file (retrospective). | -| init-plugin-eval | agent-loaded — not directly invocable | [`init-plugin-eval/SKILL.md`](../skills/init-plugin-eval/SKILL.md) | Scaffold the eval directory structure for a plugin's review agents and advisory skills. Use after creating a plugin or adding its first review agent, or when the user says "set up evals for this plugin", "init plugin evals", "scaffold eval fixtures", or "create the eval harness for <plugin>". Creates the fixtures/ and expected/ dirs plus a README describing the grading contract. | -| plugin-audit | agent-loaded — not directly invocable | [`plugin-audit/SKILL.md`](../skills/plugin-audit/SKILL.md) | Generalized structural compliance check for any Claude Code plugin. Audits architectural decisions only — agent type appropriateness (markdown vs script), frontmatter compliance, eval coverage, and body line-count budgets. Use when adding or modifying any agent or skill in a plugin, after scaffolding a new plugin, before a migration PR lands, or for a periodic health check. Accepts any plugin directory path; not hardcoded to one plugin's internal structure. | -| scaffold-marketplace | agent-loaded — not directly invocable | [`scaffold-marketplace/SKILL.md`](../skills/scaffold-marketplace/SKILL.md) | Create a Claude Code plugin-marketplace root with a valid catalog, release automation, and at least one plugin slot. Use when starting a new marketplace monorepo, or when the user says "scaffold a marketplace", "set up a plugin marketplace", "create a marketplace catalog", or "bootstrap a marketplace repo". | -| scaffold-plugin | agent-loaded — not directly invocable | [`scaffold-plugin/SKILL.md`](../skills/scaffold-plugin/SKILL.md) | Create a new Claude Code plugin directory with the correct, audit-clean structure. Use when starting a new plugin in a marketplace monorepo, or when the user says "scaffold a plugin", "create a new plugin", "add a plugin to this marketplace", or "new plugin skeleton". Produces a directory that passes /plugin-audit with zero findings on a clean install. | +| `/add-plugin` | <name@marketplace> [--repo <owner/repo>] | [`add-plugin/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/add-plugin/SKILL.md) | Install a Claude Code plugin and register it in settings.json so the full team can replicate the install. Use this whenever adding a new plugin to the project — it keeps settings.json in sync with what is actually installed. | +| `/agent-add` | <description-or-url> [--plugin <dir>] [--name <name>] [--type review\|team] [--model sonnet\|opus\|haiku\|fable\|inherit] [--effort low\|medium\|high\|xhigh\|max] [--memory user\|project\|local] [--isolation worktree] [--color <color>] [--max-turns <int>] [--background true\|false] [--skills <name1,name2,...>] [--context diff-only\|full-file\|project-structure] [--lang <exts>] [--dry] | [`agent-add/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/agent-add/SKILL.md) | Create a new Claude Code agent file (review or team type) following the official sub-agent schema and token-efficiency budgets. Use when the user wants to add a new review agent, detect a new category of code issue, create a team agent persona, or says things like "add an agent for X", "create a reviewer for Y", "new team agent for Z". Also use when given a URL to a coding standard that should become a review agent. | +| `/agent-create` | no flags — run directly | [`agent-create/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/agent-create/SKILL.md) | Create new Claude Code sub-agent files following the official schema and token-efficiency budgets. Handles both review agents (JSON output, read-only tools, ≤ 40-line body) and team agents (prose output, action tools, ≤ 75-line body). Use when the user says "add an agent", "create a reviewer for X", "new team agent for Y", or when /agent-add is invoked. Validates against /plugin-audit before writing. Updates the agent registry and plugin CLAUDE.md after success. | +| `/agent-remove` | <agent-name> [--plugin <dir>] [--dry] | [`agent-remove/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/agent-remove/SKILL.md) | Remove an agent from the system — deletes the agent file, cleans up all registry entries, removes cross-references, and updates documentation. Use when the user says "remove the X agent", "delete X-review", "retire the X role", or "we no longer need X". Handles both team agents and review agents. Always confirms before deleting. | +| `/agent-skill-authoring` | no flags — run directly | [`agent-skill-authoring/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/agent-skill-authoring/SKILL.md) | Conventions, anti-patterns, and meta-patterns for writing skills (and the shared agent/skill philosophy). Use when creating or editing a SKILL.md file, or when reviewing the agent-vs-skill separation. For the procedural workflow that generates a new agent file, use the agent-create skill (invoked by /agent-add). | +| `/agent-type-advisor` | <prose use-case \| path/to/agent-or-skill.md> | [`agent-type-advisor/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/agent-type-advisor/SKILL.md) | Recommend whether a plugin capability should be a markdown (LLM-interpreted) unit or a deterministic script. Use when designing a new agent/skill ("should this be markdown or a script?"), or when auditing an existing agent/skill file for a type mismatch. Accepts either a prose use-case description (forward- looking, new unit) or a path to an existing agent/skill file (retrospective). | +| init-plugin-eval | agent-loaded — not directly invocable | [`init-plugin-eval/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/init-plugin-eval/SKILL.md) | Scaffold the eval directory structure for a plugin's review agents and advisory skills. Use after creating a plugin or adding its first review agent, or when the user says "set up evals for this plugin", "init plugin evals", "scaffold eval fixtures", or "create the eval harness for <plugin>". Creates the fixtures/ and expected/ dirs plus a README describing the grading contract. | +| plugin-audit | agent-loaded — not directly invocable | [`plugin-audit/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/plugin-audit/SKILL.md) | Generalized structural compliance check for any Claude Code plugin. Audits architectural decisions only — agent type appropriateness (markdown vs script), frontmatter compliance, eval coverage, and body line-count budgets. Use when adding or modifying any agent or skill in a plugin, after scaffolding a new plugin, before a migration PR lands, or for a periodic health check. Accepts any plugin directory path; not hardcoded to one plugin's internal structure. | +| scaffold-marketplace | agent-loaded — not directly invocable | [`scaffold-marketplace/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/scaffold-marketplace/SKILL.md) | Create a Claude Code plugin-marketplace root with a valid catalog, release automation, and at least one plugin slot. Use when starting a new marketplace monorepo, or when the user says "scaffold a marketplace", "set up a plugin marketplace", "create a marketplace catalog", or "bootstrap a marketplace repo". | +| scaffold-plugin | agent-loaded — not directly invocable | [`scaffold-plugin/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/marketplace-dev/skills/scaffold-plugin/SKILL.md) | Create a new Claude Code plugin directory with the correct, audit-clean structure. Use when starting a new plugin in a marketplace monorepo, or when the user says "scaffold a plugin", "create a new plugin", "add a plugin to this marketplace", or "new plugin skeleton". Produces a directory that passes /plugin-audit with zero findings on a clean install. | diff --git a/plugins/security-assessment/docs/skills.md b/plugins/security-assessment/docs/skills.md index 5ab9547f8..4e7484be9 100644 --- a/plugins/security-assessment/docs/skills.md +++ b/plugins/security-assessment/docs/skills.md @@ -15,11 +15,11 @@ Most skills are **user-invocable** as slash commands — shown as `/name`; run t | Skill | Options | File | Description | | --- | --- | --- | --- | -| compliance-mapping | agent-loaded — not directly invocable | [`compliance-mapping/SKILL.md`](../skills/compliance-mapping/SKILL.md) | Pattern-table mapping from unified findings to regulatory citations (PCI-DSS, GDPR, HIPAA, SOC2). LLM edge annotator invoked only for llm_review_trigger=true rows. | -| `/cross-repo-analysis` | <path1> <path2> [<path3> ...] | [`commands/cross-repo-analysis.md`](../commands/cross-repo-analysis.md) | Run cross-repo security analysis across two or more target paths. Composes service-comm-parser + shared-cred-hash-match + cross-repo-synthesizer to produce a named-attack-chain report. | -| `/export-pdf` | <report.md> [--output <report.pdf>] [--css <path>] | [`commands/export-pdf.md`](../commands/export-pdf.md) | Convert a Markdown report to PDF via pandoc (preferred) or weasyprint (fallback). Skips gracefully if neither is installed. | -| false-positive-reduction | agent-loaded — not directly invocable | [`false-positive-reduction/SKILL.md`](../skills/false-positive-reduction/SKILL.md) | Hybrid FP-reduction — joern when present, LLM fallback when absent. Six-stage rubric (Stage 0 + Stages 1-5) applied to every finding; emits the disposition register. | -| `/redteam-model` | <target-url> [--self-certify-owned <path>] [--dry-run] [--agents <id> ...] [--start <id>] | [`commands/redteam-model.md`](../commands/redteam-model.md) | Adversarial ML red-team harness against a self-owned model endpoint. 7 probes + report. Rate-limited, budget-bounded, audit-logged. | -| `/security-assessment` | <path> [<path> ...] [--start <phase>] [--agents <phase> ...] [--fp-reduce=yes\|no] | [`commands/security-assessment.md`](../commands/security-assessment.md) | Full security assessment pipeline — recon, SARIF-first tool detection, judgment review, FP-reduction, narrative + compliance, service-comm diagram, exec report. Single-repo or multi-repo. | -| security-assessment-pipeline | agent-loaded — not directly invocable | [`security-assessment-pipeline/SKILL.md`](../skills/security-assessment-pipeline/SKILL.md) | Declarative phase graph for /security-assessment. Phases run in fixed order with dependency enforcement; per-phase artifacts land in memory/ and feed the next phase. | -| `/upgrade` | no flags — run directly | [`commands/upgrade.md`](../commands/upgrade.md) | Check for and apply security-assessment plugin updates using the official Claude Code plugin update mechanism. | +| compliance-mapping | agent-loaded — not directly invocable | [`compliance-mapping/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/skills/compliance-mapping/SKILL.md) | Pattern-table mapping from unified findings to regulatory citations (PCI-DSS, GDPR, HIPAA, SOC2). LLM edge annotator invoked only for llm_review_trigger=true rows. | +| `/cross-repo-analysis` | <path1> <path2> [<path3> ...] | [`commands/cross-repo-analysis.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/commands/cross-repo-analysis.md) | Run cross-repo security analysis across two or more target paths. Composes service-comm-parser + shared-cred-hash-match + cross-repo-synthesizer to produce a named-attack-chain report. | +| `/export-pdf` | <report.md> [--output <report.pdf>] [--css <path>] | [`commands/export-pdf.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/commands/export-pdf.md) | Convert a Markdown report to PDF via pandoc (preferred) or weasyprint (fallback). Skips gracefully if neither is installed. | +| false-positive-reduction | agent-loaded — not directly invocable | [`false-positive-reduction/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/skills/false-positive-reduction/SKILL.md) | Hybrid FP-reduction — joern when present, LLM fallback when absent. Six-stage rubric (Stage 0 + Stages 1-5) applied to every finding; emits the disposition register. | +| `/redteam-model` | <target-url> [--self-certify-owned <path>] [--dry-run] [--agents <id> ...] [--start <id>] | [`commands/redteam-model.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/commands/redteam-model.md) | Adversarial ML red-team harness against a self-owned model endpoint. 7 probes + report. Rate-limited, budget-bounded, audit-logged. | +| `/security-assessment` | <path> [<path> ...] [--start <phase>] [--agents <phase> ...] [--fp-reduce=yes\|no] | [`commands/security-assessment.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/commands/security-assessment.md) | Full security assessment pipeline — recon, SARIF-first tool detection, judgment review, FP-reduction, narrative + compliance, service-comm diagram, exec report. Single-repo or multi-repo. | +| security-assessment-pipeline | agent-loaded — not directly invocable | [`security-assessment-pipeline/SKILL.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/skills/security-assessment-pipeline/SKILL.md) | Declarative phase graph for /security-assessment. Phases run in fixed order with dependency enforcement; per-phase artifacts land in memory/ and feed the next phase. | +| `/upgrade` | no flags — run directly | [`commands/upgrade.md`](https://github.com/bdfinst/agentic-dev-team/blob/main/plugins/security-assessment/commands/upgrade.md) | Check for and apply security-assessment plugin updates using the official Claude Code plugin update mechanism. | diff --git a/tests/fixtures/session_log/extract_session_report.golden.json b/tests/fixtures/session_log/extract_session_report.golden.json index 0588706db..f9e125664 100644 --- a/tests/fixtures/session_log/extract_session_report.golden.json +++ b/tests/fixtures/session_log/extract_session_report.golden.json @@ -54,7 +54,9 @@ "file.py": 2 }, "repeated_verify_runs": 0, - "retried_bash_commands": 0 + "retried_bash_commands": 0, + "retried_bash_commands_by_agent": {}, + "retried_bash_commands_by_skill": {} }, "sessions": 1, "subagent_transcripts": 3, diff --git a/tests/fixtures/session_log/session_extract.golden.json b/tests/fixtures/session_log/session_extract.golden.json index dfbc9bbc3..c77682657 100644 --- a/tests/fixtures/session_log/session_extract.golden.json +++ b/tests/fixtures/session_log/session_extract.golden.json @@ -58,7 +58,9 @@ "file.py": 2 }, "repeated_verify_runs": 0, - "retried_bash_commands": 0 + "retried_bash_commands": 0, + "retried_bash_commands_by_agent": {}, + "retried_bash_commands_by_skill": {} }, "schema": "session-digest/v4", "sessions": 1, diff --git a/tests/repo/test_gate_ran_correlation.py b/tests/repo/test_gate_ran_correlation.py index 11ca8638b..a0fb31b36 100644 --- a/tests/repo/test_gate_ran_correlation.py +++ b/tests/repo/test_gate_ran_correlation.py @@ -160,6 +160,129 @@ def test_deliberate_bypass_is_never_counted_toward_absent_or_errored( assert data["gate"]["gate_ran_clean"] == 0 +def test_sync_out_correlates_gate_ran_events_from_the_sessions_own_cwd( + tmp_path: Path, +) -> None: + """#2106: `cmd_sync` (`--sync-out`, the path that durably archives onto + `.claude/metrics/session-digest.jsonl` at every SessionStart and feeds + `/session-review`'s cross-session digest) used to call `extract_maintainer` + without a `boundary_events_path` at all, so `_read_gate_ran_events(None)` + always returned `[]` — every synced session's non-bypassed commit + attempts classified `gate_ran_absent`, regardless of whether the + git-native `.husky/pre-commit` gate actually ran. This is what a + 100%-absent digest finding actually reflected: this sync path never + looking at the session's own boundary-events.jsonl, not the gate never + firing (see test_gate_ran_husky.py — the emitter side is unaffected). + Must resolve the SAME session-cwd-derived boundary-events.jsonl already + used for plugin_version resolution (#2018) and correlate against it.""" + projects = tmp_path / "projects" / "projA" + projects.mkdir(parents=True) + work = tmp_path / "work-alpha" + (work / ".claude" / "metrics").mkdir(parents=True) + (projects / "sess-a.jsonl").write_text( + json.dumps( + { + "type": "assistant", + "cwd": str(work), + "sessionId": "s-a", + "timestamp": "2026-06-07T10:00:00Z", + "message": { + "model": "claude-opus-4-8", + "usage": {"input_tokens": 10, "output_tokens": 1}, + "content": [ + { + "type": "tool_use", + "name": "Bash", + "input": {"command": "git commit -m x"}, + } + ], + }, + } + ) + + "\n" + ) + (work / ".claude" / "metrics" / "boundary-events.jsonl").write_text( + _gate_ran_line("2026-06-07T10:00:01Z", "allow") + ) + out = tmp_path / "digests" / "testhost" / "session-digest.jsonl" + watermark = tmp_path / "watermark.json" + res = subprocess.run( + [ + sys.executable, + str(EXTRACT), "--profile", "maintainer", + "--sync-out", str(out), + "--watermark", str(watermark), + "--projects-root", str(tmp_path / "projects"), + "--host", "testhost", + "--plugin-root", str(PLUGIN), + ], + capture_output=True, + text=True, + check=False, + ) + assert res.returncode == 0, res.stdout + res.stderr + record = json.loads(out.read_text().splitlines()[0]) + assert record["gate"]["commit_attempts"] == 1 + assert record["gate"]["gate_ran_clean"] == 1 + assert record["gate"]["gate_ran_absent"] == 0 + + +def test_sync_out_still_reports_absent_with_no_matching_boundary_event( + tmp_path: Path, +) -> None: + """Sanity converse of the test above: a session whose cwd genuinely has + no boundary-events.jsonl still reports absent — the fix must not paper + over a real gate_ran_absent population, only stop manufacturing a false + one for every synced session unconditionally.""" + projects = tmp_path / "projects" / "projA" + projects.mkdir(parents=True) + work = tmp_path / "work-beta" + work.mkdir(parents=True) + (projects / "sess-b.jsonl").write_text( + json.dumps( + { + "type": "assistant", + "cwd": str(work), + "sessionId": "s-b", + "timestamp": "2026-06-07T10:00:00Z", + "message": { + "model": "claude-opus-4-8", + "usage": {"input_tokens": 10, "output_tokens": 1}, + "content": [ + { + "type": "tool_use", + "name": "Bash", + "input": {"command": "git commit -m x"}, + } + ], + }, + } + ) + + "\n" + ) + out = tmp_path / "digests" / "testhost" / "session-digest.jsonl" + watermark = tmp_path / "watermark.json" + res = subprocess.run( + [ + sys.executable, + str(EXTRACT), "--profile", "maintainer", + "--sync-out", str(out), + "--watermark", str(watermark), + "--projects-root", str(tmp_path / "projects"), + "--host", "testhost", + "--plugin-root", str(PLUGIN), + ], + capture_output=True, + text=True, + check=False, + ) + assert res.returncode == 0, res.stdout + res.stderr + record = json.loads(out.read_text().splitlines()[0]) + assert record["gate"]["commit_attempts"] == 1 + assert record["gate"]["gate_ran_absent"] == 1 + assert record["gate"]["gate_ran_clean"] == 0 + + def test_default_boundary_events_path_resolves_under_cwd(tmp_path: Path) -> None: """With no --boundary-events override, the default resolves to <cwd>/.claude/metrics/boundary-events.jsonl (#2037) — the same diff --git a/tests/repo/test_retried_bash_attribution.py b/tests/repo/test_retried_bash_attribution.py new file mode 100644 index 000000000..40303df62 --- /dev/null +++ b/tests/repo/test_retried_bash_attribution.py @@ -0,0 +1,174 @@ +"""#2110 — retried_bash_commands gains skill/agent attribution. + +Session digest analysis found a large gap between two rework counters +(`rework.retried_bash_commands: 3947` vs. `rework.repeated_verify_runs: 1`) +with no per-skill/per-agent breakdown to trace the volume to a cause. This +file end-to-ends the fix through the `--profile maintainer` pipeline: +extract -> --sync-out -> --rollup, proving the breakdown survives each hop +and the scalar total stays derived from it (single source of truth, #2108's +own lesson applied here). + +Unit-level coverage of the underlying `track_bash` attribution primitive +lives in `plugins/dev-team/tests/scripts/test_session_log_signals.py`. +""" + +from __future__ import annotations + +import json +import subprocess +import sys +from pathlib import Path + +from _repo_root import REPO_ROOT + +EXTRACT = REPO_ROOT / "plugins" / "dev-team" / "scripts" / "session_report.py" +PLUGIN = REPO_ROOT / "plugins" / "dev-team" + + +def _rec(ts: str, content: list) -> str: + return ( + json.dumps( + { + "type": "assistant", + "cwd": "/p", + "sessionId": "s", + "timestamp": ts, + "message": { + "model": "claude-opus-4-8", + "usage": {"input_tokens": 10, "output_tokens": 1}, + "content": content, + }, + } + ) + + "\n" + ) + + +def _bash(command: str) -> dict: + return {"type": "tool_use", "name": "Bash", "input": {"command": command}} + + +def _skill(name: str) -> dict: + return {"type": "tool_use", "name": "Skill", "input": {"skill": name}} + + +def _run(*args: str) -> dict: + res = subprocess.run( + [sys.executable, str(EXTRACT), "--profile", "maintainer", *args], + capture_output=True, text=True, check=False, + ) + assert res.returncode == 0, res.stdout + res.stderr + return json.loads(res.stdout) + + +def test_extract_maintainer_attributes_a_retry_to_the_active_skill(tmp_path: Path) -> None: + transcript = tmp_path / "t.jsonl" + transcript.write_text( + _rec("2026-06-07T10:00:00Z", [_skill("build")]) + + _rec("2026-06-07T10:00:01Z", [_bash("python3 -m pytest -q")]) + + _rec("2026-06-07T10:00:02Z", [_bash("python3 -m pytest -q")]), + encoding="utf-8", + ) + data = _run("--transcript", str(transcript), "--plugin-root", str(PLUGIN)) + rew = data["rework"] + assert rew["retried_bash_commands"] == 1 + assert rew["retried_bash_commands_by_skill"] == {"build": 1} + assert rew["retried_bash_commands_by_agent"] == {"unattributed": 1} + + +def test_extract_maintainer_reports_unattributed_with_no_active_skill_or_agent( + tmp_path: Path, +) -> None: + transcript = tmp_path / "t.jsonl" + transcript.write_text( + _rec("2026-06-07T10:00:00Z", [_bash("npm run lint")]) + + _rec("2026-06-07T10:00:01Z", [_bash("npm run lint")]), + encoding="utf-8", + ) + data = _run("--transcript", str(transcript), "--plugin-root", str(PLUGIN)) + rew = data["rework"] + assert rew["retried_bash_commands"] == 1 + assert rew["retried_bash_commands_by_skill"] == {"unattributed": 1} + assert rew["retried_bash_commands_by_agent"] == {"unattributed": 1} + + +def test_sync_out_carries_the_breakdown_through(tmp_path: Path) -> None: + projects = tmp_path / "projects" / "projA" + projects.mkdir(parents=True) + (projects / "sess-a.jsonl").write_text( + _rec("2026-06-07T10:00:00Z", [_skill("triage")]) + + _rec("2026-06-07T10:00:01Z", [_bash("go test ./...")]) + + _rec("2026-06-07T10:00:02Z", [_bash("go test ./...")]), + encoding="utf-8", + ) + out = tmp_path / "digests" / "testhost" / "session-digest.jsonl" + watermark = tmp_path / "watermark.json" + res = subprocess.run( + [ + sys.executable, str(EXTRACT), "--profile", "maintainer", + "--sync-out", str(out), + "--watermark", str(watermark), + "--projects-root", str(tmp_path / "projects"), + "--host", "testhost", + "--plugin-root", str(PLUGIN), + ], + capture_output=True, text=True, check=False, + ) + assert res.returncode == 0, res.stdout + res.stderr + record = json.loads(out.read_text().splitlines()[0]) + rew = record["rework"] + assert rew["retried_bash_commands"] == 1 + assert rew["retried_bash_commands_by_skill"] == {"triage": 1} + + +def test_rollup_aggregates_the_breakdown_across_sessions(tmp_path: Path) -> None: + manifest_dir = tmp_path / "fake-plugin" / ".claude-plugin" + manifest_dir.mkdir(parents=True) + (manifest_dir / "plugin.json").write_text(json.dumps({"version": "1.0.0"})) + + digests = tmp_path / "digests" / "box" + digests.mkdir(parents=True) + digests.joinpath("session-digest.jsonl").write_text( + "\n".join( + json.dumps(rec) + for rec in ( + { + "schema": "session-sync/v3", + "plugin_version": "1.0.0", + "session_id": "s1", + "rework": { + "retried_bash_commands": 2, + "retried_bash_commands_by_skill": {"build": 2}, + "retried_bash_commands_by_agent": {"unattributed": 2}, + }, + }, + { + "schema": "session-sync/v3", + "plugin_version": "1.0.0", + "session_id": "s2", + "rework": { + "retried_bash_commands": 1, + "retried_bash_commands_by_skill": {"fix": 1}, + "retried_bash_commands_by_agent": {"software-engineer": 1}, + }, + }, + ) + ) + + "\n" + ) + res = subprocess.run( + [ + sys.executable, str(EXTRACT), "--profile", "maintainer", + "--rollup", str(tmp_path / "digests"), + "--plugin-root", str(tmp_path / "fake-plugin"), + ], + capture_output=True, text=True, check=False, + ) + assert res.returncode == 0, res.stdout + res.stderr + data = json.loads(res.stdout) + rew = data["rework"] + assert rew["retried_bash_commands"] == 3 + assert rew["retried_bash_commands_by_skill"] == {"build": 2, "fix": 1} + assert rew["retried_bash_commands_by_agent"] == { + "software-engineer": 1, "unattributed": 2, + } diff --git a/tests/repo/test_session_extract_plugin_version.py b/tests/repo/test_session_extract_plugin_version.py index 6883e423e..db60b6f92 100644 --- a/tests/repo/test_session_extract_plugin_version.py +++ b/tests/repo/test_session_extract_plugin_version.py @@ -689,16 +689,21 @@ def test_rollup_sanitizes_hostile_project_path_to_safe_name_sentinel( "utilization.agent_dispatches", "accuracy.by_skill", "accuracy.by_agent", + "rework.retried_bash_commands_by_skill", + "rework.retried_bash_commands_by_agent", ], ) def test_rollup_sanitizes_unsafe_keys_in_each_name_bearing_dict( tmp_path: Path, field: str ) -> None: - """An unsafe key (one `_safe_name` would reject) in any of the five + """An unsafe key (one `_safe_name` would reject) in any of these name-bearing dicts `rollup()` reads must not crash ingestion, and a well-formed sibling record from a different host must still survive in - the output — proving the normalization is wired at each of the five - field paths independently, not inferred from one exemplar.""" + the output — proving the normalization is wired at each field path + independently, not inferred from one exemplar. The two `rework. + retried_bash_commands_by_*` paths (#2110) get the same treatment as + `accuracy.by_skill`/`by_agent` — the identical threat model applies to + a peer-supplied skill/agent name in either sub-object.""" plugin_root = _fake_plugin_root(tmp_path, "10.23.0") digests = tmp_path / "digests" diff --git a/tests/repo/test_skills_index_current.py b/tests/repo/test_skills_index_current.py index ff5a97e29..00c918523 100644 --- a/tests/repo/test_skills_index_current.py +++ b/tests/repo/test_skills_index_current.py @@ -270,11 +270,34 @@ def test_plugin_dir_flag_points_to_security_assessment(tmp_path: Path) -> None: res = _run_builder(["--plugin-dir", str(sa_dir)], env=env) assert res.returncode == 0, res.stderr rendered = out.read_text() - # 3 skills + 5 commands = 8 entries; count SKILL.md and .md links - skill_links = re.findall(r"\[`[^`]+`\]\(\.\./(?:skills|commands)/", rendered) + # 3 skills + 5 commands = 8 entries; count SKILL.md and .md links, which + # point at the file's GitHub source (#2103) since skills/ and commands/ + # aren't part of the published docs site. + skill_links = re.findall( + r"\[`[^`]+`\]\(https://github\.com/bdfinst/agentic-dev-team/blob/main/" + r"plugins/security-assessment/(?:skills|commands)/", + rendered, + ) assert len(skill_links) == 8, f"Expected 8 entries, got {len(skill_links)}: {skill_links}" +def test_generated_links_point_to_github_source_not_the_unpublished_skills_dir() -> ( + None +): + """#2103: scripts/assemble-docs.sh only copies each plugin's docs/ dir into + the published MkDocs site, never skills/ or commands/, so a relative + `../skills/...` link 404s once deployed. Every generated link must point + at the file's GitHub source instead, which resolves both in a checkout + and on the live site.""" + catalog = (REPO_ROOT / "plugins" / "dev-team" / "docs" / "skills.md").read_text() + links = re.findall(r"\[`[^`]+`\]\(([^)]+)\)", catalog) + assert links, "expected at least one skill/command link in the catalog" + for link in links: + assert link.startswith( + "https://github.com/bdfinst/agentic-dev-team/blob/main/" + ), f"non-GitHub-source link would 404 on the published docs site: {link}" + + def test_a_skill_outside_the_taxonomy_lands_in_a_trailing_other_section( tmp_path: Path, ) -> None: diff --git a/tests/skills/test_setup_yes_flag.py b/tests/skills/test_setup_yes_flag.py index 63be01595..3489a3fc8 100644 --- a/tests/skills/test_setup_yes_flag.py +++ b/tests/skills/test_setup_yes_flag.py @@ -37,6 +37,35 @@ def _project_init() -> str: return PROJECT_INIT.read_text(encoding="utf-8") +def _setup_conservative_ambiguous_stack_bullet() -> str: + """Bound to /setup's Conservative-bucket "Unrecognized / ambiguous stack" + bullet only — not the whole document — so a match here can't be + satisfied by the unrelated Step 6 mutation-tooling clause, which also + contains the phrase "never guess a stack" (#2105). Mirrors + `_yes_semantics_conservative_repowise_bullet` below.""" + return section_outside_code( + _setup(), + r"^- \*\*Unrecognized / ambiguous stack", + boundary_pattern=r"^\*\*Precedence\.\*\*", + include_start_line=True, + ) + + +def _project_init_affirmative_three_column_plan_bullet() -> str: + """Bound to /project-init's Affirmative-bucket "Step 3 three-column plan" + bullet only — not the whole document. Before this, `.*` in the OR-regex's + first branch (`three-column plan.*proceed`), applied against the whole + document collapsed to one line, could span from this bullet all the way + to any later, unrelated "proceed" occurrence — several exist — making + that branch nearly always true regardless of doc content (#2105).""" + return section_outside_code( + _project_init(), + r"^- \*\*Step 3 three-column plan", + boundary_pattern=r"^- \*\*Step 4b capability tools", + include_start_line=True, + ) + + def _yes_semantics_conservative_repowise_bullet() -> str: """Bound to just the Conservative bucket's `Step 4c Repowise` bullet — not the whole document — so a match here can't be satisfied by an @@ -102,8 +131,8 @@ def test_setup_coverage_config_edits_stay_advisory_under_yes(): def test_setup_never_guesses_stack_under_yes(): - body = collapsed(_setup()) - assert grep(r"never guess a stack", body) + bullet = collapsed(_setup_conservative_ambiguous_stack_bullet()) + assert grep(r"never guesses a toolchain", bullet) def test_setup_never_guesses_communication_style_under_yes(): @@ -127,7 +156,8 @@ def test_project_init_has_arguments_section(): def test_project_init_yes_auto_confirms_plan_and_keyless_pair(): body = collapsed(_project_init()) - assert grep(r"three-column plan.*proceed|print the\s*plan and proceed", body) + plan_bullet = collapsed(_project_init_affirmative_three_column_plan_bullet()) + assert grep(r"three-column plan.*proceed|print the\s*plan and proceed", plan_bullet) assert grep(r"keyless[- ]pair prompt as yes|keyless pair \(CodeGraph \+ Repowise\)", body)