Metadata-Version: 2.1
Name: cadence-runner
Version: 0.19.2
Summary: CLI tool for autonomous task execution via Claude Code
Keywords: claude,claude-code,cli,automation,agent
Author-Email: Mikhail Drozdetskiy <m.drozdetskiy@gmail.com>
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
Project-URL: Homepage, https://github.com/Drozdetskiy/cadence
Project-URL: Repository, https://github.com/Drozdetskiy/cadence
Project-URL: Issues, https://github.com/Drozdetskiy/cadence/issues
Requires-Python: >=3.14
Requires-Dist: typer>=0.9
Requires-Dist: rich>=13.0
Requires-Dist: PyYAML>=6.0
Description-Content-Type: text/markdown

# cadence

Autonomous task-execution pipeline on top of [Claude Code](https://docs.anthropic.com/en/docs/claude-code).

`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 |

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

```bash
# from source, editable
pip install -e .

# or with pdm
pdm install
```

Requires:
- Python **3.14+**
- [Claude Code](https://docs.anthropic.com/en/docs/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 `preprompt`; the generated plan is written next to it as `plan` (the `preprompt` → `plan` mapping is built into `--plan`). A per-task `config.yaml` next to the prompt is auto-discovered.

```
cdc-tasks/
  0001-my-feature/
    preprompt          # free-form task description (input)
    plan               # generated by --plan, consumed by --task
    config.yaml        # optional per-task overrides (auto-discovered)
```

```bash
# 1. Create a plan from a free-form task description
cadence --plan cdc-tasks/0001-my-feature/preprompt
#   → writes cdc-tasks/0001-my-feature/plan

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

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

# 4. 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` are mutually exclusive.
- `--impl` requires `--plan` (and is incompatible with `--review`).
- `--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:

```markdown
# 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.

```yaml
# 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 (preprompt/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: <branch-name>. Added: <what>. Changed: <what>. Deleted: <what>. ...

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

See [`docs/config.md`](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:

```yaml
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.
```

Pattern: `<branch-name>. Added: <what>. Changed: <what>. Deleted: <what>.` — sections are included only when they apply, one short clause each, English, single line.

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):

```yaml
commit_format: |
  Format: <branch-name>. Added: <what>. Changed: <what>. Deleted: <what>.
  Include only the sections that apply. English, single line.
  Each section 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:

```yaml
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/`](docs/): `config.md`, `processor.md`, `executor.md`, `git-and-plans.md`, `progress-and-input.md`.

## Development

```bash
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`](LICENSE).