Skip to main content

CLI tool for autonomous task execution via Claude Code

Project description

cadence

PyPI version Python versions License CI Code style: ruff

Autonomous task-execution pipeline on top of Claude Code.

Inspired by the ralphex project.

cadence drives Claude through a structured loop: plan → branch → iterative implementation → multi-agent code review → review-loop until clean. It is a thin orchestrator — Claude does the work, cadence keeps it on rails (signals, retries, idle/session timeouts, break/resume, per-phase models, git integration).

What it does

Stage Trigger What happens
plan cadence --plan <file> Interactive Q&A with Claude, draft review (accept / revise / reject), final plan written to <file>-plan.md
task cadence --task <plan> Branch created from plan filename, one ### Task N: section per iteration, each completed and committed
review implicit after --task, or cadence --review First pass launches 4 parallel agents (quality, implementation, testing, simplification); subsequent passes loop on critical/major findings until no commits are produced
run cadence --run Infers the task directory from the current branch and dispatches to plan creation, plan execution (with --impl), or a "already completed" notice — no path argument needed

Phases communicate with the runner via signal markers (e.g. <<<CADENCE:PLAN_READY>>>, <<<CADENCE:ALL_TASKS_DONE>>>, <<<CADENCE:REVIEW_DONE>>>, <<<CADENCE:QUESTION>>>, <<<CADENCE:TASK_FAILED>>>).

Installation

# via Homebrew (macOS)
brew tap Drozdetskiy/cadence
brew install cadence

# via PyPI
pip install cadence-runner

# from source (for development)
pdm install

The PyPI distribution is named cadence-runner; the CLI binary is cadence regardless of how you installed it.

Requires:

  • Python 3.14+ (Homebrew formula pulls this in automatically)
  • Claude Code on PATH
  • a git repository (the --task and --review modes operate on the working tree)

Usage

Tasks live in their own subdirectory under cdc-tasks/<NNNN-slug>/ (configurable via tasks_root). The free-form description goes into a file named init; the generated plan is written next to it as plan (the initplan mapping is built into --plan, and the prompt-file name is configurable via init_prompt_name). A per-task config.yaml next to the prompt is auto-discovered.

cdc-tasks/
  0001-my-feature/
    init               # free-form task description (input)
    plan               # generated by --plan, consumed by --task
    config.yaml        # optional per-task overrides (auto-discovered)
# 1. Scaffold a new task: branch + cdc-tasks/<name>/init (+ config.yaml if not on default_branch)
cadence --task-init 0001-my-feature

# 2. Create a plan from a free-form task description
cadence --plan cdc-tasks/0001-my-feature/init
#   → writes cdc-tasks/0001-my-feature/plan

# 3. Create a plan and chain straight into implementation
cadence --plan cdc-tasks/0001-my-feature/init --impl

# 4. Execute an existing plan: branch + tasks + review
cadence --task cdc-tasks/0001-my-feature/plan

# 5. Run the next step for the current branch (auto-detects init/plan/plan-completed)
cadence --run             # creates a plan if only init exists, prints next step otherwise
cadence --run --impl      # chains init → plan → task end-to-end on the current branch

# 6. Review the current branch only (no plan, no branch creation)
cadence --review
cadence --review --base develop                                 # override base branch
cadence --review --config cdc-tasks/0001-my-feature/config.yaml # per-run overrides

# Misc
cadence --version

Flag rules:

  • --plan, --task, --review, --task-init, --run are mutually exclusive.
  • --impl requires --plan or --run (and is incompatible with --review and --task-init).
  • --run accepts --impl and --config but not --base.
  • --base is only valid with --review. Resolution priority: --base > default_branch in config (defaults to main).

Plan file format

Plans are markdown with a strict structure the runner parses on every iteration:

# Title

## Overview## Context
- Files involved: …

### Task 1: Setup
- [ ] step one
- [ ] step two
- [ ] write tests
- [ ] run test suite

### Task 2: …
- [ ]
  • ### Task N: or ### Iteration N: headers delimit work units.
  • - [ ] / - [x] checkboxes inside Task sections drive progress.
  • Checkboxes outside Task sections (Overview, Context, Success criteria) do not block completion.
  • After a successful --task run the file is renamed in place to <stem>-completed<ext> (no commit — plan files are typically gitignored).

Configuration

Local config: .cadence/config.yaml

Project-scoped, no global config. Loaded from cwd (or CADENCE_CONFIG_DIR). All keys are optional — missing keys fall back to defaults.

# Claude executor
claude_command: claude
claude_args: "--dangerously-skip-permissions --verbose"
plan_model:   claude-opus-4-7
task_model:   claude-opus-4-7
review_model: claude-opus-4-7

# Iteration / timing
iteration_delay_ms: 2000
task_retry_count:   1
max_iterations:     50
session_timeout:    "0"   # "30m", "1h30m", … 0 = disabled
idle_timeout:       "0"
wait_on_limit:      "0"   # >0 → retry on rate-limit instead of failing

# VCS / paths
tasks_root:     cdc-tasks # root for per-task subdirectories (init/plan/config.yaml)
default_branch: main      # override per-project in local config
commit_trailer: ""        # appended to all cadence-made commits
commit_format:  |         # appended to task/review prompts (default shown below)
  Format: subject line `<branch-name>.`, then a blank line, then a body
  with one clause per line — `Added: <what>`, `Changed: <what>`,
  `Deleted: <what>`. Include only the lines that apply. ...

# Output
colors:
  task: "#2e8b57"
  review: "#1a9e9e"
  warn: "#d4930d"
  error: "#cc0000"

See docs/config.md for the full key reference (timeouts, error patterns, color palette).

Per-run overrides: --config

--config <path> loads a YAML file that overrides per-phase models and/or default_branch. Each key is optional:

plan:
  model: claude-opus-4-7
task:
  model: claude-opus-4-7
review:
  model: claude-opus-4-7
default_branch: develop

If --config is omitted, cadence auto-discovers config.yaml next to the plan/task file — typically cdc-tasks/<NNNN-slug>/config.yaml (no parent walk). For --review (no plan/task file) auto-discovery is skipped — only an explicit --config is honored. An explicit path that does not exist is a hard error; an auto-discovered missing file is silently ignored. YAML parse errors are always fatal.

Commit message format

commit_format is appended verbatim to every task and review prompt, telling Claude how to write the commit subject. Plan creation does not commit, so the format is not added there.

The built-in default produces messages like:

0014-no-plan-commit-on-start.

Changed: cadence no longer auto-commits the plan file when starting a task.
Deleted: now-unused commit_plan_file / file_has_changes helpers.

Shape: subject line <branch-name>., a blank line, then one short clause per body line — Added: <what>, Changed: <what>, Deleted: <what>. Include only the lines that apply. The subject + blank line + body shape lets GitHub auto-fill the PR title from the subject and the PR description from the body.

Override from .cadence/config.yaml with any free-form text. Example of a tighter restatement (the shipped default also includes Good/Bad examples and guidance about implementation details belonging in the diff — see Config.commit_format in src/cadence/config.py for the verbatim text):

commit_format: |
  Format: subject line `<branch-name>.`, then a blank line, then a body with
  one clause per line — `Added: <what>`, `Changed: <what>`, `Deleted: <what>`.
  Include only the lines that apply. English.
  Each body line is one short clause describing the user-visible outcome.
  Author as the user — no Co-Authored-By trailer (unless `commit_trailer` is configured).

Switch to Conventional Commits:

commit_format: |
  Use Conventional Commits: <type>(<scope>): <subject>
  Types: feat, fix, refactor, docs, test, chore.
  Subject is imperative, lowercase, no trailing period, ≤72 chars.
  Example: feat(executor): add idle-timeout retry

If you need finer control than a free-form block (e.g. different wording per phase), drop a custom task.txt / review_first.txt / review_second.txt under .cadence/prompts/ — the format block is appended to whatever prompt body you supply.

Customizing prompts and agents

cadence ships with embedded defaults under src/cadence/defaults/. To customize, drop replacements into the project:

.cadence/
  config.yaml
  prompts/
    make_plan.txt        # overrides plan-creation prompt
    task.txt             # overrides task-iteration prompt
    review_first.txt     # overrides initial review prompt
    review_second.txt    # overrides review-loop prompt
  agents/
    quality.txt          # custom review agents (referenced as {{agent:quality}})
    implementation.txt
    testing.txt
    simplification.txt
    my-extra-agent.txt   # add new agents — auto-discovered

Per-file fallback: if a local file is empty or contains only # comments, the embedded default is used. Agents support optional YAML frontmatter:

---
model: sonnet         # haiku | sonnet | opus (or full IDs, normalized)
agent: code-reviewer  # subagent type for the Task tool
---
Agent prompt body…

Prompts can reference agents inline with {{agent:name}}; the runner expands these into full Task tool invocations, with base variables ({{PLAN_FILE}}, {{DEFAULT_BRANCH}}, etc.) substituted into the agent body.

Runtime controls

  • Ctrl+C — graceful shutdown (twice within 5s force-exits).
  • Ctrl+\ (SIGQUIT, Unix) — break the current task; the runner kills the active Claude session and prompts to resume or abort. Resume restarts the same task with a fresh session and re-reads the plan file.
  • Rate limits — if wait_on_limit > 0 and Claude output matches claude_limit_patterns, cadence sleeps and retries indefinitely until cancellation.
  • Session / idle timeouts — kill stuck sessions; review-loop iterations skip the no-commit detection if the previous session timed out.

Project layout

src/cadence/
  cli.py            Typer entrypoint, mode dispatch, signal handling
  config.py         Config dataclass, YAML loading, --config overrides
  status.py         Phase / Mode / Signal constants
  input.py          Interactive Q&A collector
  executor/         Claude subprocess + JSON-stream parsing
  git/              Service layer over `git` CLI
  plan/             Markdown plan parser, branch-name extraction
  processor/        Runner — orchestrates plan/task/review phases
  progress/         File+stdout logger with colors and flock
  defaults/
    prompts/        Embedded prompt templates
    agents/         Embedded review agents

Deeper module references live in docs/: config.md, processor.md, executor.md, git-and-plans.md, progress-and-input.md.

Development

make install     # pdm install --dev
make test        # pytest tests/ -v
make test-cov    # with coverage
make lint        # ruff check
make typecheck   # mypy --strict
make check       # lint + typecheck + test

Conventions:

  • Python 3.14+, mypy --strict.
  • Protocol-based interfaces for all Runner dependencies (Executor, Logger, InputCollector, GitChecker) — tests mock these directly, never the real Claude CLI or a real git repo.
  • Signals are literal strings of the form <<<CADENCE:NAME>>> and matched against raw non-JSON CLI output only (so the same literal inside stream-json events does not trigger false positives).

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cadence_runner-0.20.0.tar.gz (93.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cadence_runner-0.20.0-py3-none-any.whl (58.1 kB view details)

Uploaded Python 3

File details

Details for the file cadence_runner-0.20.0.tar.gz.

File metadata

  • Download URL: cadence_runner-0.20.0.tar.gz
  • Upload date:
  • Size: 93.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.26.8 CPython/3.14.4 Darwin/25.4.0

File hashes

Hashes for cadence_runner-0.20.0.tar.gz
Algorithm Hash digest
SHA256 88cae27b0c1684ee6713956e970648b220a609ff889035efe4eeb4dec6d77144
MD5 a2574b3f676179acae21433af72a40d7
BLAKE2b-256 cc826d618fd0faa03724d788f8a76e9cc518fefe93d3dabb1578d512e0c9c840

See more details on using hashes here.

File details

Details for the file cadence_runner-0.20.0-py3-none-any.whl.

File metadata

  • Download URL: cadence_runner-0.20.0-py3-none-any.whl
  • Upload date:
  • Size: 58.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.26.8 CPython/3.14.4 Darwin/25.4.0

File hashes

Hashes for cadence_runner-0.20.0-py3-none-any.whl
Algorithm Hash digest
SHA256 349c85d4e83cc349be0df4d60e57d9d268ceaf8adc126cd971f499518166a557
MD5 ef27ceeda75751216f4788328d7f332c
BLAKE2b-256 eca255ce8bd4097d5ee7be2bd9795aea934247efae46299f8c363ac09e6fd91b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page