Verification Skills: Make Claude Prove the Work Is Done

0
Verification Skills: Make Claude Prove the Work Is Done

As a project grows, the same instructions start appearing again and again:

  • Run the tests.
  • Check the formatter and linter.
  • Read the final diff.
  • Make sure no test was weakened merely to get a green build.
  • Tell me exactly what passed, failed, or could not be run.

That repetition is a signal. The procedure should stop living in chat history and become a reusable skill.

If there is one Claude Code skill worth building first, make it a verification skill. Code generation saves time, but verification protects the result. It turns "Claude says it is done" into "the project gates were executed, the change was inspected, and the evidence was reported."

Why Verification Is the Best First Skill

Without a defined verification procedure, quality depends on memory. Claude finishes a refactor, and you must remember to ask for tests. It fixes a bug, and you must remember to inspect the changed assertions. It updates configuration, and you must remember to check the generated files or run a build.

That works until the one time it does not.

A verification skill makes the expected finishing procedure repeatable. For an implementation, refactor, bug fix, migration, or configuration change, it can instruct Claude to:

  1. Identify what changed and what behavior the change was meant to preserve or introduce.
  2. Run the relevant automated gates.
  3. Inspect the final diff, not only the files Claude remembers editing.
  4. Review test changes for suspicious weakening.
  5. Report a clear PASS, FAIL, or BLOCKED result with command output and limitations.

The important shift is that completion becomes evidence-based. A clean-looking diff is not enough. A green test suite is not enough if the tests were made meaningless. A verification result should connect the requested behavior, the changed code, and the observed checks.

A Skill Is Not a Guaranteed Completion Event

There is an important distinction to get right.

Claude Code uses a skill's description to decide whether the skill is relevant to the current task. A well-described verification skill may be loaded automatically when Claude is implementing or reviewing code, and you can always invoke it directly with a command such as /verify-change.

However, a skill is still model-invoked guidance. It is not a deterministic lifecycle event that is guaranteed to run after every file edit or before every response.

Use the layers deliberately:

Requirement Best instruction surface
Naming conventions, architecture facts, standard project commands CLAUDE.md
A reusable multi-step verification procedure A skill
A check that must execute at a lifecycle point A hook
A merge requirement that must be independent of the coding agent CI and branch protection

This separation matters. Put the procedure in a skill because Claude needs reasoning: it must choose the relevant checks, interpret failures, inspect the diff, and detect suspicious test changes. Add a hook when forgetting the procedure is unacceptable. Keep CI as the independent final authority before merge or deployment.

What a Verification Skill Should Actually Verify

A useful verification skill checks more than whether one command exited successfully.

1. The requested behavior

Claude should restate the intended outcome in concrete terms. For a bug fix, that means identifying the failing case. For a refactor, it means naming the behavior that must remain unchanged. For a migration, it means identifying compatibility and rollback concerns.

This gives the later checks a target. Otherwise, Claude may prove that the code compiles without proving that it solves the requested problem.

2. Automated quality gates

The exact commands depend on the repository, but a typical set includes:

  • Formatting checks
  • Static analysis or linting
  • Type checking
  • Unit tests
  • Integration tests
  • Build or packaging checks
  • Schema or migration validation
  • Generated-file consistency checks

The skill should run the project's real commands rather than inventing generic substitutes. When the repository already exposes make verify, task check, npm run validate, or a similar command, use that as the primary entry point.

3. The complete diff

Claude should inspect the final repository diff after the checks run. This catches accidental changes, debugging output, generated artifacts, unrelated formatting, and modifications made indirectly by tools.

At minimum, inspect:

git status --short
git diff --check
git diff --stat
git diff -- .

If staged changes are part of the workflow, inspect git diff --cached as well.

4. Test integrity

A green test suite can still be bad evidence. Tests may have been weakened to accept broken behavior.

The verification pass should look for changes such as:

  • Deleted or relaxed assertions
  • New skip, xfail, disabled, or ignored markers
  • Broader exception handling that hides failures
  • Reduced coverage thresholds
  • Snapshots updated without checking whether the new output is correct
  • Mocks replacing the code path that the test was supposed to exercise
  • Fixtures changed to avoid the edge case that exposed the bug
  • Timing thresholds widened without a documented reason
  • Expected values changed to match the implementation rather than the requirement

Changing a test is not automatically suspicious. A legitimate behavior change often requires new expectations. The skill's job is to verify that the change is explained by the requirement and still tests meaningful behavior.

5. Honest reporting

The skill must not convert missing evidence into a pass.

If Docker is unavailable, an external service cannot be reached, credentials are missing, or a test suite is too expensive to run locally, the result is BLOCKED or PARTIAL, not PASS.

A reliable report states:

  • Which commands ran
  • Their exit status
  • Which checks were skipped and why
  • What the diff review found
  • Whether tests changed
  • Whether those test changes preserved test strength
  • Remaining risks

Build the Skill as a Small Folder

An Agent Skill is a directory with a required SKILL.md entry point and optional supporting resources. A verification skill benefits from separating reasoning from deterministic commands:

.claude/skills/verify-change/
├── SKILL.md
├── references/
│   └── test-integrity.md
└── scripts/
    └── check.sh

This structure uses progressive disclosure:

  • The skill metadata is available for discovery.
  • The SKILL.md body loads when the skill is activated.
  • Detailed references are read only when needed.
  • Scripts can be executed as tools instead of copying their entire implementation into the conversation context.

Keep SKILL.md focused on the decision process. Put long checklists in references/ and deterministic project commands in scripts/.

Example SKILL.md

Create .claude/skills/verify-change/SKILL.md:

---
name: verify-change
description: Verifies code changes after implementations, refactors, bug fixes, migrations, and configuration updates. Use when source code, tests, build files, schemas, or runtime configuration changed and the work must be proven complete with executed checks and diff evidence.
allowed-tools: Read Grep Glob Bash(${CLAUDE_SKILL_DIR}/scripts/check.sh)
---

# Verify Change

Verify the completed change before describing it as done.

## Procedure

1. Restate the requested behavior and identify the files that changed.
2. Run `${CLAUDE_SKILL_DIR}/scripts/check.sh` from the project root.
3. Run `git status --short`, `git diff --check`, and `git diff --stat`.
4. Read the complete relevant diff, including changed tests and configuration.
5. If tests changed, read [the test integrity checklist](references/test-integrity.md).
6. Confirm that test changes validate intended behavior and were not weakened merely to pass.
7. Report `PASS`, `FAIL`, or `BLOCKED` using the format below.

Do not claim a check passed unless its command was executed and its result was observed.
Do not hide failing commands, skipped checks, warnings, or environmental limitations.
Do not modify code during verification unless fixing a discovered problem, then rerun every affected gate.

## Result Format

### Verification: PASS | FAIL | BLOCKED

- **Scope:** What was verified
- **Automated gates:** Command and result for each gate
- **Diff review:** Relevant findings
- **Test integrity:** Unchanged, strengthened, justified change, or concern found
- **Limitations:** Checks not run and why
- **Remaining risks:** Any behavior not covered by available evidence

The description contains both what the skill does and when it applies. That description is the discovery surface Claude uses when deciding whether to load the skill.

The allowed-tools rule is deliberately narrow: it pre-approves only the bundled verification script. Claude can still request permission for other shell commands when needed.

Example Verification Script

The script should contain the canonical commands for your project. Do not make Claude rediscover them on every task.

For a Python project using uv, Ruff, ty, and pytest, create .claude/skills/verify-change/scripts/check.sh:

#!/usr/bin/env bash
set -uo pipefail

failures=0

run_gate() {
  local name="$1"
  shift

  printf '\n==> %s\n' "$name"

  if "$@"; then
    printf 'PASS: %s\n' "$name"
  else
    local exit_code=$?
    printf 'FAIL: %s (exit %s)\n' "$name" "$exit_code" >&2
    failures=$((failures + 1))
  fi
}

run_gate "format" uv run ruff format --check .
run_gate "lint" uv run ruff check .
run_gate "types" uv run ty check
run_gate "tests" uv run pytest

if ((failures > 0)); then
  printf '\nVerification failed: %s gate(s) failed.\n' "$failures" >&2
  exit 1
fi

printf '\nAll automated gates passed.\n'

Make it executable:

chmod +x .claude/skills/verify-change/scripts/check.sh

For another stack, keep the same reporting shape and replace the commands:

Stack Typical gates
Node.js or TypeScript npm run format:check, npm run lint, npm run typecheck, npm test, npm run build
Go gofmt check, go vet ./..., go test ./..., go build ./...
Rust cargo fmt --check, cargo clippy -- -D warnings, cargo test, cargo build
Java or Kotlin Formatter, static analysis, unit tests, integration tests, package task
Terraform terraform fmt -check -recursive, terraform validate, linting, policy checks, plan review

Prefer one project-owned command such as make verify when possible. It gives developers, Claude, local tooling, and CI the same entry point.

Example Test-Integrity Reference

Create .claude/skills/verify-change/references/test-integrity.md:

# Test Integrity Checklist

Review every changed test and test-related configuration file.

## Blocking concerns

- Assertions were removed without replacement.
- Expected values were broadened only to match the implementation.
- Tests were skipped, disabled, marked flaky, or converted to expected failures.
- Exceptions are swallowed or failures are converted into warnings.
- Coverage thresholds were reduced.
- The implementation under test was replaced by a mock.
- A regression fixture no longer represents the reported failure.

## Changes that require justification

- Snapshot updates
- Timeout or retry increases
- New mocks or stubs
- Large fixture rewrites
- Deleted edge cases
- Changes from exact to partial matching

## Evidence of stronger tests

- A regression test fails before the fix and passes after it.
- Assertions cover externally observable behavior.
- New boundary and failure cases are included.
- The test remains independent of implementation details where practical.
- The changed expectation is traceable to the requested behavior or specification.

Report the exact files and lines that support the conclusion.

The main skill stays lean, while the detailed review criteria remain available when tests actually changed.

Test the Skill, Not Only the Script

A script can pass while the skill still performs poorly. Test both invocation and behavior.

Start with trigger cases that should activate the skill:

  • "Refactor this service and verify the result."
  • "Fix the bug and prove the tests still cover it."
  • "Update the migration, then check everything before finishing."
  • "Review these changes and tell me whether they are safe to merge."

Then test negative cases that should not trigger it unnecessarily:

  • "Explain what this function does."
  • "Find where this environment variable is used."
  • "Summarize the README."

Finally, seed failure scenarios:

  1. Add a lint error and confirm the result is FAIL.
  2. Make a required service unavailable and confirm the result is BLOCKED, not PASS.
  3. Delete an assertion while keeping the tests green and confirm the diff review flags it.
  4. Add an unrelated generated file and confirm the final diff review notices it.
  5. Fix a discovered problem and confirm all affected gates are rerun.

The skill's description is part of the implementation. If it triggers too often or not often enough, revise the description and retest it.

Built-In /verify Versus a Project Verification Skill

Current Claude Code versions include a bundled /verify skill intended to build and run an application so Claude can confirm behavior against the running system, rather than treating tests or type checks as the only proof.

That is useful, but it does not eliminate project-specific verification:

  • The bundled skill focuses on running and observing the application.
  • Your project skill defines repository-specific gates and test-integrity rules.
  • A custom skill can encode migrations, generated files, policy checks, contract tests, security scans, or domain-specific invariants.

Also note that project skills can override bundled skills with the same name. Naming your custom skill verify may intentionally replace the bundled /verify; naming it verify-change keeps both available.

A strong workflow can use both:

/verify-change
/verify

The first proves repository quality gates and diff integrity. The second exercises the running application when runtime verification is relevant.

Add a Hook When Verification Must Not Be Skipped

A skill defines the procedure, but a hook can enforce that something runs at a specific lifecycle point.

For example, a Stop hook runs when the main Claude Code agent is ready to finish. A command hook can block completion by exiting with code 2. The following wrapper skips clean repositories, runs the project verification script when changes exist, and blocks stopping when a gate fails.

Create .claude/hooks/verify-if-dirty.sh:

#!/usr/bin/env bash
set -uo pipefail

if [[ -z "$(git status --porcelain)" ]]; then
  exit 0
fi

if .claude/skills/verify-change/scripts/check.sh; then
  exit 0
fi

echo "Verification failed. Fix the failing gates before finishing." >&2
exit 2

Make it executable:

chmod +x .claude/hooks/verify-if-dirty.sh

Then add the hook to .claude/settings.json:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/verify-if-dirty.sh",
            "timeout": 600
          }
        ]
      }
    ]
  }
}

This is a simple backstop, not a universal configuration. A repository with long-running tests, pre-existing local changes, multiple packages, or environment-dependent checks should scope the hook more carefully. You may run a fast subset locally and reserve the complete matrix for CI.

Do not use a model-based hook for a rule that can be checked deterministically by a script. Tests, formatting, generated-file checks, and forbidden-path rules are better expressed as command hooks. Use model reasoning for questions such as whether a changed test still represents the requirement.

Keep CI as the Independent Authority

Claude verifying its own work is valuable, but it is not independent verification. The same agent that made the change is interpreting the result.

CI should rerun the canonical gates in a clean environment and protect the branch from merge when required checks fail. Ideally, local scripts and CI call the same underlying command:

make verify

Then the layers align:

  1. CLAUDE.md tells Claude the project conventions and canonical command.
  2. The verification skill defines how to run checks, inspect the diff, and evaluate test integrity.
  3. A hook prevents Claude from casually finishing with known failures.
  4. CI reruns the gates independently before merge.

Each layer solves a different failure mode. Do not force one instruction surface to do every job.

Common Mistakes

Treating green tests as complete proof

Tests cover only what they assert. Verification must also inspect changed tests, the final diff, build output, and the behavior requested by the user.

Putting the whole procedure in CLAUDE.md

CLAUDE.md loads as persistent context. Long task procedures compete with architecture facts and coding conventions. Move repeated multi-step workflows into skills so their full bodies load only when relevant.

Writing a vague description

description: Checks code is too broad and gives Claude little information about when the skill should activate.

Name the work types and the expected result:

description: Verifies code changes after implementations, refactors, bug fixes, migrations, and configuration updates by running project gates, reviewing the final diff, and checking that tests were not weakened.

Hiding failed or unavailable checks

A verification skill should make uncertainty visible. Missing dependencies, unavailable services, permissions, and timeouts belong in the result.

Running the full suite after every edit

Verification should happen at meaningful boundaries. A PostToolUse hook after every Write can create excessive noise and cost. Prefer targeted fast checks during implementation and a complete verification pass before completion.

Letting verification modify code silently

When verification finds a problem, Claude may fix it, but that starts a new implementation cycle. The affected gates must run again, and the final report must describe the correction.

The Rule of Thumb

If you have typed the same multi-step instruction twice, consider turning it into a skill.

Verification is the best first example because it improves every other task. Once the pattern works, the same structure can capture:

  • Release checklists
  • Database migration procedures
  • Pre-pull-request reviews
  • Dependency upgrade validation
  • Security review steps
  • Incident follow-up checks
  • Deployment and rollback recipes

The folder can carry concise instructions, detailed references, executable tools, templates, and examples. Only the relevant depth needs to enter context.

Recap

A verification skill changes the definition of done.

Done is not:

  • The code looks plausible.
  • Claude says the task is complete.
  • One test command printed green.

Done means:

  • The intended behavior is explicit.
  • The relevant gates were executed and observed.
  • The complete diff was inspected.
  • Changed tests were checked for integrity.
  • Failures and limitations were reported honestly.
  • Independent CI still has the final say.

Build the skill in .claude/skills/verify-change/, commit it with the repository, and give the whole team the same verification procedure. Add a hook when the procedure must not be skipped. Keep CI as the final enforcement boundary.

That is how repeated checking becomes part of the engineering system instead of something everyone has to remember.

References

  • Claude Code: Extend Claude with skills - code[.]claude[.]com/docs/en/skills
  • Claude Code: Hooks reference - code[.]claude[.]com/docs/en/hooks
  • Claude Code: How Claude remembers your project - code[.]claude[.]com/docs/en/memory
  • Agent Skills: Specification - agentskills[.]io/specification
  • Anthropic: Public Agent Skills repository - github[.]com/anthropics/skills
  • Anthropic Claude Code: Skill development guide - github[.]com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/skill-development/SKILL.md

Post a Comment

0 Comments

Post a Comment (0)

#buttons=(Ok, Go it!) #days=(20)

This site uses cookies from Google to deliver its services and analyze traffic. Your IP address and user-agent are shared with Google along with performance and security metrics to ensure quality of service, generate usage statistics, and to detect and address abuse. More Info
Ok, Go it!