/ia-verify
Run pre-PR verification chain: build, types, lint, tests, security scan, diff review
> /plugin marketplace add iliaal/whetstone> /plugin install whetstone@iliaal-marketplace
Command definition
ia-verify.mdname: ia-verify
description: "Run pre-PR verification chain: build, types, lint, tests, security scan, diff review"
argument-hint: "[mode: quick|full|pre-commit|pre-pr]"
Verify
Run a structured verification pipeline and produce a single READY / NOT READY report.
**Boundary vs `/ia-review`:** `/ia-verify` is the pre-PR static gate (pass/fail on build/types/lint/tests/security). `/ia-review` is the multi-agent code review with findings synthesis. Use `/ia-verify` first to confirm shippable; use `/ia-review` for design-level assessment.
Mode
`$ARGUMENTS`: defaults to `full` if omitted.
| Mode | What runs | |------|-----------| | `quick` | Build + type check only | | `full` | Build + types + lint + tests | | `pre-commit` | Build + types + lint + tests + console.log audit | | `pre-pr` | Project-declared gates + build + types + lint + tests + console.log audit + security scan + performance + accessibility + infrastructure + documentation + diff review |
Project-declared gates (phase 0) also run before any push, regardless of mode.
Applicability Detection
Resolve one verification scope before classifying or scanning changes:
1. In `pre-pr` mode, resolve the PR base (`gh pr view --json baseRefName -q .baseRefName`) or the repository's verified default branch, and freeze the current HEAD SHA. Resolve the merge-base against the available base ref, then use `git diff --no-textconv --no-ext-diff <merge-base-sha> <head-sha>` for content and its `--name-only` form for file lists in every diff-based phase below (metadata-only forms such as `--name-only` and `--stat` render no content and need no such flags). If the base cannot be resolved, report NOT READY with that missing input; do not silently substitute an empty working-tree diff. For a dirty checkout, either verify the committed head in isolation or explicitly include and identify local changes; do not claim tests of a different tree verify the frozen PR head. 2. In `pre-commit` mode, freeze the complete index tree and its staged diff (`git diff --no-textconv --no-ext-diff --cached`). Run every applicable phase in an isolated checkout of that complete index tree, including unchanged tracked inputs. Preserve the caller's index and unstaged work when preparing verification. Do not copy unstaged source, configuration, or fixtures into the isolated checkout. Report NOT READY if the staged tree cannot be verified in isolation. Before issuing READY, confirm the caller's index still matches the tested snapshot; otherwise repeat verification or report NOT READY. In `quick`/`full` mode, use the caller's selected scope, defaulting to tracked staged and unstaged changes (`git diff --no-textconv --no-ext-diff HEAD`) plus explicitly enumerated untracked files. Record the selected scope and tested tree in the report. An empty selected diff is not evidence that a feature branch is unchanged. 3. Classify the selected files:
- **frontend**: files under `src/components/`, `src/pages/`, `app/`, `*.tsx`, `*.jsx`, `*.vue`, `*.svelte`, `*.css`, `*.scss`, templates
- **backend**: files under `src/api/`, `routes/`, `controllers/`, `services/`, `*.php`, `*.py` (non-frontend), `*.go`, server-side TS
- **infrastructure**: migration files, Dockerfiles, terraform/ansible, CI configs, env templates, k8s manifests
- **docs-only**: passive prose only; agent instructions, executable snippets, and configuration embedded in Markdown must be classified by the behavior they drive
4. Apply phase filters (pre-pr mode only):
- **Performance**: skip for docs-only changes
- **Accessibility**: skip for backend-only or docs-only changes
- **Infrastructure**: skip for pure frontend changes (no migrations, no env changes, no CI changes)
- **Documentation**: always run when user-facing files changed; skip for internal refactors with no API/behavior change
Log which phases were skipped and why in the report. A checker that failed to run (missing tool, errored invocation, unparseable output) is `ERROR`, never `SKIP` or `CLEAN`; `SKIP` is reserved for a phase deliberately not run. An `ERROR` row blocks a READY result.
Pipeline
Run each phase in order. Stop on the first failure unless the mode skips that phase.
0. Project-Declared Gates (runs in pre-pr mode and before any push in every mode)
Run the project-declared gates check from the `ia-verification-before-completion` skill's Gate Function. Stop and report NOT READY if any gate is unmet, naming it.
1. Build
Detect and run the project's build command:
- `package.json` → `npm run build` (or pnpm/yarn/bun equivalent)
- `Makefile` → `make build`
- `pyproject.toml` → `python -m build` or framework-specific
- `mix.exs` → `mix compile --warnings-as-errors`
- `go.mod` → `go build ./...`
- `composer.json` → `composer install`
After the build, run any generation command the project itself declares (a CLAUDE.md/AGENTS.md instruction, Makefile target, or `package.json`/`composer.json` script for codegen, arginfo or OpenAPI client regeneration, autoload maps, or lockfile refresh); do not invent one. Snapshot the tree's content, not just its status, before the build and compare after this phase: `(set -o pipefail; idx=$(mktemp) && cp "$(git rev-parse --git-path index)" "$idx" && GIT_INDEX_FILE="$idx" git add -A -N -- :/ && { git status --porcelain --untracked-files=all && GIT_INDEX_FILE="$idx" git diff --no-textconv --no-ext-diff --binary HEAD; } | git hash-object --stdin; rc=$?; rm -f "$idx"; exit $rc)`. Status codes alone miss a rewrite of an already-modified tracked file, and `git diff` omits untracked content, so a throwaway index marks every untracked path intent-to-add; the real index is untouched. Read the exit status of each snapshot, not just its printed hash: a nonzero exit (for example an untracked nested repository with no commit) is Build `FAIL (snapshot failed: <first error: or fatal: line>)`. A changed hash means the build or generator rewrote tracked or untracked files, so
Read more
name: ia-verify description: "Run pre-PR verification chain: build, types, lint, tests, security scan, diff review" argument-hint: "[mode: quick|full|pre-commit|pre-pr]"
Verify
Run a structured verification pipeline and produce a single READY / NOT READY report.
**Boundary vs `/ia-review`:** `/ia-verify` is the pre-PR static gate (pass/fail on build/types/lint/tests/security). `/ia-review` is the multi-agent code review with findings synthesis. Use `/ia-verify` first to confirm shippable; use `/ia-review` for design-level assessment.
Mode
`$ARGUMENTS`: defaults to `full` if omitted.
| Mode | What runs | |------|-----------| | `quick` | Build + type check only | | `full` | Build + types + lint + tests | | `pre-commit` | Build + types + lint + tests + console.log audit | | `pre-pr` | Project-declared gates + build + types + lint + tests + console.log audit + security scan + performance + accessibility + infrastructure + documentation + diff review |
Project-declared gates (phase 0) also run before any push, regardless of mode.
Applicability Detection
Resolve one verification scope before classifying or scanning changes:
1. In `pre-pr` mode, resolve the PR base (`gh pr view --json baseRefName -q .baseRefName`) or the repository's verified default branch, and freeze the current HEAD SHA. Resolve the merge-base against the available base ref, then use `git diff --no-textconv --no-ext-diff <merge-base-sha> <head-sha>` for content and its `--name-only` form for file lists in every diff-based phase below (metadata-only forms such as `--name-only` and `--stat` render no content and need no such flags). If the base cannot be resolved, report NOT READY with that missing input; do not silently substitute an empty working-tree diff. For a dirty checkout, either verify the committed head in isolation or explicitly include and identify local changes; do not claim tests of a different tree verify the frozen PR head. 2. In `pre-commit` mode, freeze the complete index tree and its staged diff (`git diff --no-textconv --no-ext-diff --cached`). Run every applicable phase in an isolated checkout of that complete index tree, including unchanged tracked inputs. Preserve the caller's index and unstaged work when preparing verification. Do not copy unstaged source, configuration, or fixtures into the isolated checkout. Report NOT READY if the staged tree cannot be verified in isolation. Before issuing READY, confirm the caller's index still matches the tested snapshot; otherwise repeat verification or report NOT READY. In `quick`/`full` mode, use the caller's selected scope, defaulting to tracked staged and unstaged changes (`git diff --no-textconv --no-ext-diff HEAD`) plus explicitly enumerated untracked files. Record the selected scope and tested tree in the report. An empty selected diff is not evidence that a feature branch is unchanged. 3. Classify the selected files:
- **frontend**: files under `src/components/`, `src/pages/`, `app/`, `*.tsx`, `*.jsx`, `*.vue`, `*.svelte`, `*.css`, `*.scss`, templates
- **backend**: files under `src/api/`, `routes/`, `controllers/`, `services/`, `*.php`, `*.py` (non-frontend), `*.go`, server-side TS
- **infrastructure**: migration files, Dockerfiles, terraform/ansible, CI configs, env templates, k8s manifests
- **docs-only**: passive prose only; agent instructions, executable snippets, and configuration embedded in Markdown must be classified by the behavior they drive
4. Apply phase filters (pre-pr mode only):
- **Performance**: skip for docs-only changes
- **Accessibility**: skip for backend-only or docs-only changes
- **Infrastructure**: skip for pure frontend changes (no migrations, no env changes, no CI changes)
- **Documentation**: always run when user-facing files changed; skip for internal refactors with no API/behavior change
Log which phases were skipped and why in the report. A checker that failed to run (missing tool, errored invocation, unparseable output) is `ERROR`, never `SKIP` or `CLEAN`; `SKIP` is reserved for a phase deliberately not run. An `ERROR` row blocks a READY result.
Pipeline
Run each phase in order. Stop on the first failure unless the mode skips that phase.
0. Project-Declared Gates (runs in pre-pr mode and before any push in every mode)
Run the project-declared gates check from the `ia-verification-before-completion` skill's Gate Function. Stop and report NOT READY if any gate is unmet, naming it.
1. Build
Detect and run the project's build command:
- `package.json` → `npm run build` (or pnpm/yarn/bun equivalent)
- `Makefile` → `make build`
- `pyproject.toml` → `python -m build` or framework-specific
- `mix.exs` → `mix compile --warnings-as-errors`
- `go.mod` → `go build ./...`
- `composer.json` → `composer install`
After the build, run any generation command the project itself declares (a CLAUDE.md/AGENTS.md instruction, Makefile target, or `package.json`/`composer.json` script for codegen, arginfo or OpenAPI client regeneration, autoload maps, or lockfile refresh); do not invent one. Snapshot the tree's content, not just its status, before the build and compare after this phase: `(set -o pipefail; idx=$(mktemp) && cp "$(git rev-parse --git-path index)" "$idx" && GIT_INDEX_FILE="$idx" git add -A -N -- :/ && { git status --porcelain --untracked-files=all && GIT_INDEX_FILE="$idx" git diff --no-textconv --no-ext-diff --binary HEAD; } | git hash-object --stdin; rc=$?; rm -f "$idx"; exit $rc)`. Status codes alone miss a rewrite of an already-modified tracked file, and `git diff` omits untracked content, so a throwaway index marks every untracked path intent-to-add; the real index is untouched. Read the exit status of each snapshot, not just its printed hash: a nonzero exit (for example an untracked nested repository with no commit) is Build `FAIL (snapshot failed: <first error: or fatal: line>)`. A changed hash means the build or generator rewrote tracked or untracked files, so
A Claude Code plugin that makes AI coding agents follow engineering discipline. Plan before coding. Verify before claiming done. Find root cause before patching. Review before merge. Skills activate based on file type and task signals, not manual toggling.
Other commands on whetstone.
More commands from other plugins.
build
CommandImplement tasks incrementally — build, test, verify, commit. Add "auto" to run the whole plan in one approved pass.

