Skip to content

Latest commit

 

History

History
63 lines (45 loc) · 4.54 KB

File metadata and controls

63 lines (45 loc) · 4.54 KB

CLAUDE.md — agent project instructions

You are working in harness-python-react, a template repo whose harness IS the product. Code quality here is enforced mechanically — every gate fails CI, not just tests. Keep that bar as you work.

What this repo is

A production-quality LLM-driven coding harness over a minimal FastAPI + React scaffold. The point isn't the features (one /health, one /echo, one hello page); the point is that every layer of the pipeline — lint, types, architecture, security, eval, agent hooks — catches a different failure class without anyone remembering to run it.

Read first

Workflow

  • One issue per change. Branch name: feat|fix|chore|docs|test|refactor/<issue-number>-<kebab-title>.
  • One PR per branch, base develop. PR title = the conventional-commit subject.
  • develop → main happens via a release: PR.
  • The pre-push gate is just check (lint + typecheck + architecture + tests). Run it before pushing.
  • For frontend changes, also run just frontend-check.

Code conventions

  • Python: 3.14, uv run --frozen everywhere, mypy --strict, ruff with the wide select set (E W F I N UP B SIM TCH S RUF).
  • Type hints: every public function. from __future__ import annotations at module top.
  • Models: anything crossing a module / process seam inherits from StrictModel (src/models/_base.py). extra="forbid". Add strict=True to the class when you want strict type coercion (rejecting "3.14" → float).
  • API: every route under /api/v1/. Typed Pydantic responses, not raw dicts.
  • Layer flow: one-way. Reverse imports are a CI failure. See docs/BOUNDARIES.md.
  • Observability: OTel agent_span(...) for any operation in the request path; semconv-defined attribute keys only (constants at the top of src/observability/spans.py).
  • Frontend: React 19 + TS strict; functional components + hooks; never dangerouslySetInnerHTML on backend output; SSE consumers use the typed primitive at frontend/src/lib/api/client.ts.

What NOT to do

  • Don't bypass gates. --no-verify / --no-hooks / --no-gpg-sign are blocked by pretooluse_bash.py for a reason. If a hook is wrong, fix the hook.
  • Don't introduce a new commit-type prefix without updating both pyproject.toml's commitizen schema AND pr-title.yml (the Commit-type sync meta-gate will fail otherwise).
  • Don't add a CI job without listing it in .github/branch-protection/{develop,main}.json (the Branch-protection contexts sync meta-gate will fail).
  • Don't skip the architecture contract by accident — lint-imports runs in CI and locally via just architecture.
  • Don't write code without tests. Coverage gate is 75% on src/.
  • Don't hand-roll secrets into config. Use env / .env (gitignored) → Settings from src/models/config.py.
  • Don't create files unless they're necessary. The scaffold has no dead modules.

Use the skills

The agent-side skills in .claude/skills/ auto-activate based on context:

  • architect — when designing module boundaries, API contracts, layer-flow decisions.
  • code-reviewer — after writing/editing code; runs the 10-point review checklist.
  • devops — when touching Docker, CI, pyproject.toml, observability config.
  • frontend — when working in frontend/ (React 19 + TS + Vite).
  • qa-engineer — when writing tests or extending the eval harness.
  • technical-writer — when updating docs / READMEs.

Trust their guidance — they encode this project's conventions.

When in doubt

  • If the change touches a gate, update the meta-gate inputs (branch-protection/*.json, pr-title.yml, check_required_contexts.py's exemption list).
  • If the change touches an invariant, decide whether the invariant is wrong (update docs/INVARIANTS.md in the same PR) or the change is wrong (rework).
  • If a CI job is failing for a reason that doesn't match the change, dig — don't reroll. Recent fix patterns: tag-vs-commit SHA in pinned action references, if: hashFiles(...) startup failures (see project-memory), pytest exit-5 on empty test suites.

The harness exists to make sloppy work hard. Lean into it — when a gate trips, it's protecting the next person reading this codebase.