|
1 | | -# CLAUDE.md — DevBrief Agent Memory |
| 1 | +# CLAUDE.md — DevBrief |
2 | 2 |
|
3 | | -## 1. Project Identity |
| 3 | +## Project |
4 | 4 |
|
5 | | -DevBrief is a developer CLI tool for **project situational awareness**: given a GitHub repository URL (and later: log streams, API endpoints, infra configs, and PRs), it fetches structured data and generates a human-readable brief via Claude AI. The tool is designed for developers who need rapid context on any project without reading every file manually. |
| 5 | +DevBrief: developer CLI for **project situational awareness** — fetches structured data from a GitHub repo and generates a human-readable brief via Claude AI. |
6 | 6 |
|
7 | | -**Tagline:** Project situational awareness |
8 | 7 | **Distribution:** PyPI (`devbrief`) + crates.io (`devbrief-core`) |
| 8 | +**Stack:** Python (uv) + Rust (maturin/PyO3). No React, no Docker, no webpack. |
9 | 9 |
|
10 | 10 | --- |
11 | 11 |
|
12 | | -## 2. Tech Stack |
| 12 | +## Commands |
13 | 13 |
|
14 | | -**Python layer:** |
15 | | -- `typer` — CLI framework (migration target from current `click`) |
16 | | -- `fastapi` + `jinja2` + HTMX — web UI for future `devbrief serve` |
17 | | -- SSE (Server-Sent Events) — streaming output in web UI |
18 | | -- `httpx` (async) — HTTP client (migration target from current `requests`) |
19 | | -- `boto3` — AWS integration for `devbrief logs` |
20 | | -- `anthropic` SDK — Claude AI integration |
21 | | -- `tomllib` (stdlib, Python 3.11+) — config file parsing |
22 | | -- `uv` — package manager and virtual env |
23 | | - |
24 | | -**Rust layer:** |
25 | | -- `maturin` + `PyO3` — Rust extensions callable from Python |
26 | | -- Enters via `devbrief env` subcommand |
27 | | -- Published as `devbrief-core` on crates.io |
28 | | - |
29 | | -**Not used:** React, Node, webpack, Docker (end users install via pip/cargo only) |
30 | | - |
31 | | ---- |
32 | | - |
33 | | -## 3. Project Structure |
34 | | - |
35 | | -``` |
36 | | -devbrief/ |
37 | | -├── src/ |
38 | | -│ └── devbrief/ |
39 | | -│ ├── __init__.py # Package init |
40 | | -│ ├── cli.py # Typer app — registers all subcommands |
41 | | -│ ├── commands/ |
42 | | -│ │ ├── repo.py # devbrief repo (cache-aware) |
43 | | -│ │ ├── auth.py # devbrief auth |
44 | | -│ │ └── logs.py # devbrief logs — FastAPI server, log parser, ring buffer |
45 | | -│ ├── core/ |
46 | | -│ │ ├── credentials.py # API key + model resolution chain |
47 | | -│ │ ├── config.py # Config file read/write (~/.config/devbrief/config.toml) |
48 | | -│ │ └── cache.py # Brief cache keyed by sha256(url+commit_sha) → ~/.cache/devbrief/ |
49 | | -│ ├── github.py # GitHub REST API fetchers (+ fetch_latest_commit_sha) |
50 | | -│ ├── brief.py # Claude prompt builder and generate_brief() |
51 | | -│ └── display.py # Rich terminal display functions |
52 | | -├── tests/ |
53 | | -│ ├── __init__.py |
54 | | -│ ├── test_cache.py # Cache module + repo cache integration tests |
55 | | -│ ├── test_credentials.py # Credential resolution + auth command tests |
56 | | -│ ├── test_logs.py # Log parser, ring buffer, polling endpoints |
57 | | -│ ├── test_github.py # Unit tests for GitHub fetchers |
58 | | -│ └── test_display.py # Unit tests for Rich display functions |
59 | | -├── dist/ # Built distributions (gitignored except .gitignore) |
60 | | -├── .github/ |
61 | | -│ └── workflows/ |
62 | | -│ ├── ci.yml # CI: lint + test on every PR and push to main |
63 | | -│ └── release.yml # Release: build + publish to PyPI on git tag v* |
64 | | -├── pyproject.toml # Project metadata, deps, build config (maturin) |
65 | | -├── uv.lock # Locked dependency tree |
66 | | -├── README.md # PyPI-ready README |
67 | | -├── assets/ |
68 | | -│ ├── devbrief-cache.gif # Demo GIF for devbrief repo (excluded from wheel) |
69 | | -│ ├── devbrief-env.gif # Demo GIF for devbrief env (excluded from wheel) |
70 | | -│ └── vhs/ |
71 | | -│ ├── devbrief-cache.tape # VHS tape source for devbrief-cache.gif |
72 | | -│ └── devbrief-env.tape # VHS tape source for devbrief-env.gif |
73 | | -├── LICENSE # MIT |
74 | | -├── CLAUDE.md # This file — agent persistent memory |
75 | | -└── .gitignore |
76 | | -``` |
77 | | - |
78 | | -**Assets policy:** `assets/` is excluded from the PyPI wheel via `[tool.maturin] exclude`. GIFs and tapes are repo-only. To regenerate: `vhs assets/vhs/devbrief-cache.tape` or `vhs assets/vhs/devbrief-env.tape`. |
| 14 | +| Task | Command | |
| 15 | +|------|---------| |
| 16 | +| Install deps | `uv sync` | |
| 17 | +| Run tests | `uv run pytest` | |
| 18 | +| Lint | `uv run ruff check src/ tests/` | |
| 19 | +| Format | `uv run ruff format src/ tests/` | |
| 20 | +| Type check | `uv run mypy src/` | |
| 21 | +| Rust tests | `PYO3_BUILD_EXTENSION_MODULE=1 cargo test --manifest-path rust/Cargo.toml` | |
| 22 | +| Build wheel | `maturin develop` | |
79 | 23 |
|
80 | 24 | --- |
81 | 25 |
|
82 | | -## 4. Subcommand Status |
83 | | - |
84 | | -| Subcommand | Status | Notes | |
85 | | -|-----------------|-------------|------------------------------------------------| |
86 | | -| devbrief repo | LIVE | v0.3.2, cache layer (SHA-keyed, ~/.cache/devbrief/), --no-cache/--refresh | |
87 | | -| devbrief auth | LIVE | v0.2.0, key validation, config write/read/clear, 600 perms | |
88 | | -| devbrief logs | LIVE | v0.3.0, FastAPI+HTMX polling dashboard, ring buffer, file (1s tail)/stdin | |
89 | | -| devbrief env | LIVE | v0.4.2, Rust active (maturin/PyO3), gitignore audit + .env drift + secret scan | |
90 | | -| devbrief api | PLANNED | | |
91 | | -| devbrief infra | PLANNED | | |
92 | | -| devbrief pr | PLANNED | | |
93 | | - |
| 26 | +## Architecture — Do Not Change Without a Spec Card |
94 | 27 |
|
| 28 | +- **Credential resolution:** env var → `.env` file → `~/.config/devbrief/config.toml` → keychain (future). Implemented in `devbrief.core.credentials`. |
| 29 | +- **Cache key:** `sha256(url + commit_sha)` → `~/.cache/devbrief/` |
| 30 | +- **Config file:** `~/.config/devbrief/config.toml`, permissions `600` on write. |
| 31 | +- **Model:** always resolved via `resolve_model()` — never hardcoded in command files. |
| 32 | +- **Rust extension:** `devbrief env` only. If unavailable at runtime, fall back to Python. |
| 33 | +- **Assets:** `assets/` excluded from PyPI wheel via `[tool.maturin] exclude`. |
95 | 34 |
|
96 | 35 | --- |
97 | 36 |
|
98 | | -## 5. Credential System |
99 | | - |
100 | | -**Layered resolution chain (highest priority first):** |
101 | | -1. Environment variable (e.g. `ANTHROPIC_API_KEY`, `GITHUB_TOKEN`) |
102 | | -2. `.env` file in working directory (loaded via `python-dotenv`) |
103 | | -3. `~/.config/devbrief/config.toml` — user-level config file |
104 | | -4. System keychain (future, not yet implemented) |
| 37 | +## Subcommand Status |
105 | 38 |
|
106 | | -**Config file:** `~/.config/devbrief/config.toml` |
107 | | -**File permissions:** `600` (user read/write only — enforce on write) |
108 | | -**Rules:** |
109 | | -- Never log credentials |
110 | | -- Never print credentials (even partially) in normal output |
111 | | -- Never commit `.env` files or `config.toml` to the repo |
112 | | -- Tests must mock credential reads — never use real keys in tests |
| 39 | +| Subcommand | Status | Notes | |
| 40 | +|-----------------|----------|----------------------------------------------------------------| |
| 41 | +| devbrief repo | LIVE | v0.3.2, SHA-keyed cache, --no-cache/--refresh | |
| 42 | +| devbrief auth | LIVE | v0.2.0, key validation, config write/read/clear, 600 perms | |
| 43 | +| devbrief logs | LIVE | v0.3.0, FastAPI+HTMX polling dashboard, ring buffer, file/stdin| |
| 44 | +| devbrief env | LIVE | v0.4.2, gitignore audit + .env drift + secret scan (Rust) | |
| 45 | +| devbrief api | PLANNED | | |
| 46 | +| devbrief infra | PLANNED | | |
| 47 | +| devbrief pr | PLANNED | | |
113 | 48 |
|
114 | 49 | --- |
115 | 50 |
|
116 | | -## 6. CI/CD Rules |
| 51 | +## Current Sprint |
117 | 52 |
|
118 | | -- **`ci.yml`**: Runs on every PR and push to `main`. Steps: lint (ruff), type-check, test (pytest). |
119 | | -- **`release.yml`**: Runs on git tag push matching `v*`. Steps: build wheels only (no sdist — Rust extension requires Rust to build from source), publish to PyPI via trusted publishing (OIDC). |
120 | | -- **Branch strategy:** `main` is protected. Feature branches: `feat/<subcommand-name>` or `feat/<short-description>`. |
121 | | -- **Conventional commits:** `feat:`, `fix:`, `chore:`, `docs:`, `test:`, `refactor:` |
122 | | -- **Versioning:** semver. Python and Rust share the same version number. Update `pyproject.toml` version and tag simultaneously. |
| 53 | +All subcommands through v0.4.2 are LIVE. **Next action:** await spec card before touching any subcommand. |
123 | 54 |
|
124 | | ---- |
125 | | - |
126 | | -## 7. Coding Rules (Enforce Always) |
127 | | - |
128 | | -- **Python 3.11+ only** — `tomllib` is stdlib, import it directly. (`pyproject.toml` currently sets `>=3.12`.) |
129 | | -- **Async-first:** Use `httpx` async for all HTTP. FastAPI handlers must be `async def`. (Current `requests` usage is tech debt to migrate.) |
130 | | -- **Ruff** for linting and formatting — no other linters, no black, no flake8. |
131 | | -- **Type hints everywhere** — no untyped functions, no `Any` without explanation. |
132 | | -- **Rust:** `clippy` clean, zero warnings allowed. |
133 | | -- **Rust testing:** `cargo test` requires two things: `crate-type = ["cdylib", "rlib"]` (rlib lets |
134 | | - the linker produce a test binary) and `PYO3_BUILD_EXTENSION_MODULE=1` (tells PyO3 not to link |
135 | | - against libpython, which may not be available as a shared lib on the host). Our tests only call |
136 | | - pure Rust functions so they do not need a live Python interpreter. Run as: |
137 | | - `PYO3_BUILD_EXTENSION_MODULE=1 cargo test --manifest-path rust/Cargo.toml`. |
138 | | - The `rust-check` CI job sets this env var automatically. |
139 | | -- **Tests required** for every new command and every credential resolution path. |
140 | | -- **Default model:** `claude-sonnet-4-6`. Never hardcode a model string in any command file. Model is always resolved via `resolve_model()` in `devbrief.core.credentials` (env var `DEVBRIEF_MODEL` → `config.toml [anthropic] default_model` → `"claude-sonnet-4-6"`). |
141 | | -- **Graceful degradation:** If Rust extension is unavailable, fall back to Python implementation. Never hard-crash on missing native extension. |
142 | | -- **Rich** for all terminal output — no raw `print()` in command handlers. |
| 55 | +- **CI:** `ci.yml` runs lint + type-check + test on every PR and push to `main`. |
| 56 | +- **Release:** `release.yml` on git tag `v*` — wheels only (no sdist), PyPI OIDC. |
| 57 | +- **Versioning:** semver. Python and Rust share version. Update `pyproject.toml` + tag simultaneously. |
143 | 58 |
|
144 | 59 | --- |
145 | 60 |
|
146 | | -## 8. Agent Boundaries |
| 61 | +## What NOT to Touch |
147 | 62 |
|
148 | | -- **You implement. You do not decide architecture.** |
149 | | -- If a spec is ambiguous, stop and ask before writing code. |
150 | | -- If a decision would be hard to reverse (schema changes, public API shape, breaking changes), flag it before proceeding. |
151 | | -- When a task is complete, summarize: what was built, what files changed, what tests cover it. |
152 | | -- Read this file at the start of every session. If a subcommand ships or status changes, update the table in section 4. |
| 63 | +- Do not push to `main` or merge PRs — Sebastien reviews. |
| 64 | +- Do not hardcode model strings — always use `resolve_model()`. |
| 65 | +- Do not use `print()` in command handlers — use Rich. |
| 66 | +- Do not commit `.env` or `config.toml`. |
| 67 | +- Do not build `sdist` — Rust extension requires Rust toolchain; wheels only. |
| 68 | +- Do not implement new subcommands without a spec card. |
153 | 69 |
|
154 | 70 | --- |
155 | 71 |
|
156 | | -## 9. Current Task Queue |
157 | | - |
158 | | -1. [x] Create CLAUDE.md |
159 | | -2. [x] Set up CI/CD pipeline (`ci.yml` + `release.yml`) — Rust steps present as commented stubs |
160 | | -3. [x] v0.2.0: CLI restructure (`devbrief repo`), `devbrief auth`, credential + model resolution |
161 | | -4. [x] v0.3.0: `devbrief logs` — FastAPI+HTMX polling dashboard, ring buffer, file/stdin |
162 | | -5. [x] v0.3.1: `devbrief repo` cache layer — SHA-keyed local cache, --no-cache/--refresh flags |
163 | | -6. [x] v0.3.2: `github.py` migrated from `requests` to `httpx` — closes HTTP client tech debt |
164 | | -7. [x] v0.4.0: `devbrief env` — gitignore audit, .env drift (Rust), secret scan (Rust), stub types |
165 | | -8. [x] Rust unit tests: `["cdylib","rlib"]`, `tempfile` dev-dep, 12 `#[cfg(test)]` tests, |
166 | | - `rust-check` CI job active, `PYO3_BUILD_EXTENSION_MODULE=1` for cargo test |
167 | | -9. [ ] Await spec card before touching any subcommand |
| 72 | +## Conventions |
| 73 | + |
| 74 | +See `.claude/rules/` for enforced coding conventions: |
| 75 | +- `python.md` — Python conventions, async, typing, Rich, model resolution |
| 76 | +- `rust.md` — PyO3/maturin, clippy, cargo test setup |
| 77 | +- `testing.md` — pytest structure, cargo test, credential mocking |
| 78 | +- `git.md` — branch naming, conventional commits, PR discipline, hard stops |
0 commit comments