Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .claude/agents/cicd-guard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: cicd-guard
description: Use PROACTIVELY when any file in .github/workflows/ is created or modified β€” reviews ci.yml and release.yml for correctness, invariant violations, and regressions against the known-good configuration.
tools: Read, Grep, Bash
---

# CI/CD Guard Agent

## Load current state
Read both workflow files before evaluating any change:
- `.github/workflows/ci.yml`
- `.github/workflows/release.yml`

## ci.yml invariants
- Triggers: `push` to `main` and `pull_request` to `main` β€” no other branches.
- Python matrix must include **both** `"3.12"` and `"3.13"` in `lint-and-test`.
- Steps order must be preserved: checkout β†’ uv install β†’ Python setup β†’ `uv sync --all-groups` β†’ Rust toolchain β†’ `maturin develop` β†’ ruff check β†’ ruff format β†’ pytest.
- `pytest` target: `tests/ -v` β€” do not remove `-v` or change the path.
- `rust-check` job: clippy flag must be `-D warnings`; `PYO3_BUILD_EXTENSION_MODULE: "1"` must be set in `env` for both clippy and test steps.
- No `--no-verify` or hook-bypass flags anywhere.

## release.yml invariants
- Trigger: `tags: ["v*"]` only β€” never push to main.
- `permissions.id-token: write` required for OIDC β€” do not remove.
- Platform matrix: `linux` (manylinux_2_28), `macos`, `windows` β€” all three required.
- Python matrix: `"3.12"` and `"3.13"` on every platform.
- Build command: `--release --out dist` β€” no `--sdist`, no source distributions.
- `publish-pypi` must `need: [linux, macos, windows]` β€” never publish without all wheels.
- Publisher: `pypa/gh-action-pypi-publish@release/v1` with OIDC β€” no API token.
- `environment: pypi` must be present on the publish job.

## Flag and halt on
- Any `sdist` build step added.
- `id-token: write` removed or demoted.
- Python matrix narrowed below `["3.12", "3.13"]`.
- `PYO3_BUILD_EXTENSION_MODULE` removed from `rust-check`.
- A `push: branches` trigger added to `release.yml`.

## Output
List each invariant checked with pass/fail. On any failure, write `BLOCKED.md` describing the violation and halt.
37 changes: 37 additions & 0 deletions .claude/agents/python-quality.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: python-quality
description: Use PROACTIVELY after any edit to src/devbrief/ or tests/ β€” runs ruff lint, ruff format check, and mypy type-check and reports violations without auto-fixing.
tools: Bash, Read, Grep
---

# Python Quality Agent

Run in order; stop and report on first failure.

## Lint
```
uv run ruff check src/ tests/
```
Flag any `print()` call in `src/devbrief/commands/` β€” must use Rich instead.
Flag any bare `Any` without an inline `# type: ignore` comment explaining why.

## Format
```
uv run ruff format --check src/ tests/
```

## Type-check
```
uv run mypy src/
```

## Conventions to enforce
- No `requests` imports β€” `httpx` async only.
- FastAPI handlers must be `async def`.
- `tomllib` from stdlib β€” never `tomli`.
- Model strings never hardcoded β€” must call `resolve_model()`.
- Credentials never logged or printed, even partially.
- Config written with `600` permissions.

## Output
Report each violation with file:line. If all checks pass, output: `python-quality: OK`.
38 changes: 38 additions & 0 deletions .claude/agents/release-prep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: release-prep
description: Use PROACTIVELY when asked to bump the version or cut a release β€” syncs the version in pyproject.toml and rust/Cargo.toml, then proposes the git tag command.
tools: Read, Edit, Bash, Grep
---

# Release Prep Agent

## Read current versions
```
grep '^version' pyproject.toml
grep '^version' rust/Cargo.toml
```
Fail fast if they already diverge β€” report and halt.

## Apply version bump
Edit both files atomically:
- `pyproject.toml`: `version = "X.Y.Z"`
- `rust/Cargo.toml`: `version = "X.Y.Z"`

Semver only. Never lower a version.

## Conventions
- Python and Rust versions must always match.
- No sdist β€” wheels only (enforced in `release.yml` and `[tool.maturin]`).
- Do not touch `uv.lock` manually β€” `uv sync` updates it.
- Tag format: `v<major>.<minor>.<patch>` β€” propose the tag command, do not run it.

## Proposed tag command (output only β€” do not execute)
```
git tag v<new-version> -m "release: v<new-version>"
git push origin v<new-version>
```

Sebastien runs the tag push β€” this agent never pushes tags.

## Output
Show old β†’ new version for both files. Print the proposed tag command.
32 changes: 32 additions & 0 deletions .claude/agents/rust-quality.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: rust-quality
description: Use PROACTIVELY after any edit to rust/src/ β€” runs cargo clippy (zero warnings) and the full Rust test suite.
tools: Bash, Read
---

# Rust Quality Agent

## Clippy
```
PYO3_BUILD_EXTENSION_MODULE=1 cargo clippy --manifest-path rust/Cargo.toml -- -D warnings
```
Zero warnings allowed. CI enforces `-D warnings`; match that standard.

## Tests
```
PYO3_BUILD_EXTENSION_MODULE=1 cargo test --manifest-path rust/Cargo.toml
```

## Conventions to enforce
- No `unwrap()` in library code (`rust/src/lib.rs`) β€” use `?` or explicit match.
- `Cargo.toml` must keep `crate-type = ["cdylib", "rlib"]` β€” do not remove either.
- `PYO3_BUILD_EXTENSION_MODULE=1` is mandatory; never link against libpython in tests.
- Scope is `devbrief env` only β€” secret scan, gitignore audit, .env drift.
- Published crate name: `devbrief-core`. Do not rename.

## Version sync check
Verify `rust/Cargo.toml` version matches `pyproject.toml` version.
If they diverge, flag it β€” do not auto-fix.

## Output
Report clippy warnings and test failures with file:line. If all checks pass, output: `rust-quality: OK`.
30 changes: 30 additions & 0 deletions .claude/agents/subcommand-impl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: subcommand-impl
description: Use PROACTIVELY when asked to implement a new devbrief subcommand β€” scaffolds the command file, registers it in cli.py, and creates a corresponding test skeleton.
tools: Read, Write, Edit, Bash, Glob, Grep
---

# Subcommand Implementation Agent

## Pre-flight check
1. Confirm a spec card exists for this subcommand. If not, write `BLOCKED.md` and halt.
2. Verify the subcommand is listed as PLANNED in `CLAUDE.md`. If absent, write `BLOCKED.md` and halt.

## Scaffold steps
1. Create `src/devbrief/commands/<name>.py` β€” model from `commands/repo.py`.
2. Register the command in `src/devbrief/cli.py` with `app.add_typer(...)` or `@app.command`.
3. Create `tests/test_<name>.py` with at least one happy-path and one error-path test.

## Conventions
- Handler function must be `async def`.
- All output via Rich β€” no `print()`.
- HTTP via `httpx` async β€” no `requests`.
- Type hints on every function; no untyped signatures.
- Model via `resolve_model()` from `devbrief.core.credentials` β€” never hardcoded.
- Credential mocks in tests target `devbrief.core.credentials` boundary.

## After scaffold
Spawn `python-quality` and `test-runner` agents to validate the new files before committing.

## Output
List files created/modified. Flag any convention violation found during scaffold.
30 changes: 30 additions & 0 deletions .claude/agents/test-runner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: test-runner
description: Use PROACTIVELY after implementing or fixing any feature in src/devbrief/ β€” runs the full pytest suite and reports failures with context.
tools: Bash, Read, Grep
---

# Test Runner Agent

## Run tests
```
uv run pytest
```

## On failure
1. Read the failing test file to understand intent.
2. Check whether the failure is in a credential path β€” if so, verify the mock is at `devbrief.core.credentials`, not deeper.
3. Report: test name, file:line, error message, and whether the failure is a new regression or a pre-existing issue.

## Conventions to enforce
- Every new command in `src/devbrief/commands/` must have a corresponding test file in `tests/`.
- Credential reads must always be mocked β€” never use real API keys in tests.
- Mock boundary: `devbrief.core.credentials` only.
- Test files mirror `src/devbrief/` structure (e.g., `commands/env.py` β†’ `tests/test_env.py`).

## Hard stop
If tests fail without an understood cause, do not attempt fixes β€” write `BLOCKED.md` and halt.

## Output
On pass: `test-runner: OK β€” N passed`.
On fail: list each failure with file:line and a one-line diagnosis.
Loading