Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Quality Pipeline

A multi-round automated code quality tool for Claude Code. Runs sequential quality rounds (testing, maintainability, refactoring, concurrency, fault tolerance, error handling, security, type safety, dead code elimination, dependency hygiene, simplification) with test verification and clean git commits.

Installation

# Install as a CLI tool
uv tool install /path/to/quality-pipeline

# Or run directly from the repo
uv run quality-pipeline --help

Usage

From any git project directory:

# Run all rounds
quality-pipeline

# Preview the plan
quality-pipeline --dry-run

# Cherry-pick rounds
quality-pipeline --rounds "audit-tests maintainability dead-code simplify"

# Resume from round 3
quality-pipeline --start-from 3

# Safe with uncommitted changes
quality-pipeline --worktree

Or without installing, using uv run from the quality-pipeline repo:

uv run quality-pipeline --project-dir /path/to/your/project

Important: uv run changes the working directory to the quality-pipeline repo, so --project-dir is required when targeting another project. Without it, the pipeline runs on itself rather than your intended target.

When invoked from within a Claude Code session, the pipeline automatically unsets CLAUDECODE and CLAUDE_CODE_ENTRYPOINT before spawning claude -p subprocesses, so they don't fail with a recursive-run detection error.

Options

Option Description
--project-dir DIR Run in DIR instead of current directory
--rounds "r1 r2 ..." Which rounds to run (default: all)
--config FILE Path to pipeline.yaml config
--start-from N Resume from round N (1-indexed)
--dry-run Show plan without executing
--worktree Run in an isolated git worktree (safe with uncommitted changes)
--worktree-symlinks "d1 d2" Space-separated dirs to symlink into worktree
--test-command "CMD" Override auto-detected test command
--review Enable reviewer pass for all rounds
--no-review Disable reviewer pass for all rounds
--log-dir DIR Directory for log files

Built-in Rounds

Round Prefix Turns Time Gate Retries Review Description
audit-tests test: 40 20m hard 2 Audit test quality and fill coverage gaps with substantial, independent tests
maintainability refactor: 40 20m soft 1 yes Fix duplicate implementations, leaky interfaces, module-boundary drift, and brittle tests
refactor refactor: 40 20m soft 1 Improve naming, structure, and clarity
concurrency fix: 30 25m hard 0 yes Fix races, lost updates, and find parallelization opportunities
fault-tolerance fix: 30 25m hard 0 yes Fix non-atomic writes, lost updates, missing fsync, and idempotency bugs
error-handling fix: 30 15m hard 1 Fix swallowed errors, missing error paths, and inconsistent patterns
security fix: 40 20m hard 0 yes Fix hardcoded secrets, injection vectors, and insecure defaults
type-safety refactor: 30 15m soft 1 Add missing type annotations and tighten overly broad types
dead-code chore: 20 10m soft 1 Remove unused imports, functions, and variables
dependency-hygiene chore: 20 10m soft 1 Remove unused dependencies and flag deprecated API usage
simplify style: 20 10m soft 1 Reduce unnecessary abstractions and complexity

How It Works

  1. Creates a branch quality/YYYY-MM-DD-<hash> (optionally in an isolated worktree with --worktree)
  2. For each round: a. Runs static analysis tools (if configured) and injects results into the prompt b. Invokes claude -p with a focused prompt c. Runs your test suite to verify nothing broke d. On test failure: retries with test output (if max_retries > 0) e. On final failure: rolls back and applies gate logic (hard=stop, soft=continue) f. On success: commits and optionally runs a reviewer pass
  3. Moves to the next round

Rounds interact exclusively through git state — each round starts a fresh Claude session that sees the updated codebase.

Gate Types

Each round has a gate setting that controls what happens when tests fail:

  • hard (default): Pipeline stops. Use for correctness-critical rounds (tests, concurrency, security).
  • soft: Pipeline continues to the next round. Use for best-effort rounds (refactoring, dead code, simplify).
  • none: Tests are skipped entirely. Use for rounds that don't affect behavior.

Unrecognized gate values (e.g., a typo like hardd) produce a warning and default to hard.

Retry Loop

When tests fail after a round, the pipeline can retry by re-invoking Claude with the test output. Set max_retries in the round frontmatter (default: 0). Each retry uses half the round's budget/time and shows Claude the last 100 lines of test output.

Static Analysis

Rounds can be augmented with static analysis results. The pipeline runs configured analyzers before Claude and injects their output into the prompt. Default mappings:

  • maintainability → ruff-refactor, ruff-simplify
  • refactor → ruff-refactor
  • security → bandit, semgrep
  • type-safety → mypy, pyright, tsc
  • dead-code → vulture, ruff-dead-code, codegraph-unused
  • simplify → ruff-simplify

Override per-round with the analyzers frontmatter field or via overrides in pipeline.yaml.

Behavior Contracts

Correctness-critical rounds (concurrency, fault-tolerance, error-handling, security) and the maintainability round include Behavior Contract sections that specify what MUST change and what MUST NOT change. These constrain Claude's changes and give the reviewer something concrete to check against.

Reviewer Pass

After a round commits, an optional reviewer pass invokes a fresh Claude session to review the diff. The reviewer checks for correctness, contract compliance, scope creep, test quality, and subtle regressions. Enable per-round with review: true in frontmatter, or globally with --review.

Per-Project Configuration

Drop a .claude/pipeline.yaml in your project:

test_command: "pytest tests/"
rounds: [audit-tests, maintainability, refactor, concurrency, fault-tolerance, error-handling, security, type-safety, dead-code, dependency-hygiene, simplify]
branch_prefix: "quality/"
max_budget_usd: 20.00
max_time_minutes: 20
overrides:
  audit-tests:
    max_budget_usd: 8.00
    max_time_minutes: 30
    append_prompt: "Use pytest with fixtures"
  dead-code:
    gate: none
    max_retries: 0
  security:
    review: true
    analyzers: "bandit semgrep"

Configuration priority

For numeric fields like max_budget_usd and max_time_minutes, the priority order is:

  1. Per-round override (from the overrides section in pipeline.yaml) — highest
  2. Frontmatter (explicitly set in the round's .md file)
  3. Global config (top-level max_budget_usd / max_time_minutes in pipeline.yaml)
  4. Default ($5.00 budget, 30 turns, 15 minutes) — lowest

This means a round that explicitly sets max_budget_usd: 3.00 in its frontmatter won't be silently overwritten by a global max_budget_usd: 20.00 — the frontmatter value is preserved unless a per-round override is also present.

Custom Rounds

Add a markdown file to quality_pipeline/rounds/ with YAML frontmatter:

---
name: my-round
commit_message_prefix: "feat: "
max_budget_usd: 5.00
max_turns: 30
max_time_minutes: 15
gate: hard
max_retries: 1
review: false
analyzers: "mypy pyright"
---

# My Custom Round

Your prompt here...

Frontmatter fields (all optional, with backward-compatible defaults):

Field Default Description
name "" Round identifier (used for config overrides and display)
commit_message_prefix "chore: " Git commit message prefix
max_budget_usd 5.00 Claude API budget cap (for pay-per-token users)
max_turns 30 Maximum Claude conversation turns
max_time_minutes 15 Wall-clock timeout for the Claude invocation
gate "hard" hard, soft, or none (see Gate Types)
max_retries 0 Retry attempts on test failure
review false Run a reviewer pass after commit
analyzers "" Space-separated static analysis tools to run

Test Command Detection

The pipeline auto-detects your test runner by checking (in order):

  1. CLAUDE.md for test command mentions
  2. Makefile test target
  3. package.json test script (respects bun/pnpm/yarn lockfiles)
  4. pyproject.toml / pytest configuration (uses uv run pytest if uv.lock present)
  5. go.mod → go test ./...
  6. Cargo.toml → cargo test

Override with --test-command or test_command in pipeline.yaml.

Self-Testing

The pipeline can be run on its own codebase. Use --worktree so the orchestrator isn't modified mid-run:

# Preview
uv run quality-pipeline --worktree --dry-run

# Run all rounds
uv run quality-pipeline --worktree

# Cherry-pick rounds
uv run quality-pipeline --worktree --rounds "audit-tests maintainability simplify"

Test auto-detection works because the repo now has a pyproject.toml with pytest configured.

Failure Recovery

  • If a round fails, previous rounds' commits are preserved on the branch
  • Resume with --start-from N to skip completed rounds
  • Hard gate rounds: test failure rolls back changes and stops the pipeline
  • Soft gate rounds: test failure rolls back changes but continues to the next round
  • Retry loop (if configured) re-invokes Claude with test output before giving up

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages