Contributing¶
Setup¶
Install pre-commit hooks:
This runs ruff, mypy, and trailing whitespace checks on every commit.
Code quality¶
All checks need to pass. CI runs them on every push.
uv run ruff check src/ tests/ # lint
uv run ruff format src/ tests/ # format
uv run mypy # type check (strict mode)
uv run pytest # test + coverage (minimum enforced by pytest-cov)
uv run bandit -r src/ -q -c pyproject.toml # security
uv run vulture src/ --min-confidence 80 # dead code
uv run complexipy src/ --max-complexity-allowed 15 # cognitive complexity
uv run radon cc src/ -a -nc # cyclomatic complexity
Conventions¶
- Python 3.11+, type annotations on all function signatures
- mypy strict mode. Use
dict[str, Any]not baredict. - Click for the CLI. Each command module exports a Click command or group.
- Config goes in
developer.yaml(copy fromexample.developer.yaml). TheRepoConfigdataclass is the in-code representation. - Architectural decisions go in
DECISIONS.mdwith context, rationale, and revisit triggers.
Adding a new repo¶
Add a block to your developer.yaml (copied from example.developer.yaml). See Configuration.
Adding a new audit type¶
- Create
src/developer/templates/audit/<name>.md.j2-- include_labels.md.j2and_personality.md.j2, use{{ max_findings }}for the limit - Add a Click subcommand in
src/developer/commands/audit.pythat callsrun_audit()with the template name
Adding a new resolve stage¶
- Create
src/developer/templates/resolve/<name>.md.j2 - Add a
Stageentry toSTAGESinsrc/developer/commands/resolve.py - Wire routing by updating an existing stage's
routefunction to point to the new stage
Adding a new pipeline¶
Bigger lift, but the pattern is well-established:
- Create a command file in
src/developer/commands/ - Define a
STAGESdict with your stages - Write route functions for branching logic
- Write pre/post hooks for any Python operations (git, GitHub API)
- Create Pydantic models in
src/developer/models/for structured outputs - Create Jinja2 templates in
src/developer/templates/<pipeline>/ - Register the Click command in
cli.py - Add a
POSTendpoint insrc/developer/api/routes.pywith a_run_*service function and a request model inapi/models.py
API conventions¶
The API lives in src/developer/api/. It mirrors the CLI — same pipelines, same building blocks — but returns structured JSON instead of terminal output.
- Routes go in
api/routes.py. Each pipeline endpoint has a corresponding_run_*service function that replicates the Click command body. - Request/response models go in
api/models.py. - Task execution uses
api/tasks.py. Service functions run in daemon threads viasubmit_task()and log progress withtask.log_message(). - Don't modify existing Click commands to support the API. Write separate service functions that use the same underlying building blocks.