Non-negotiable structural rules that apply to every Claude Code session in
this repo and to every commit, enforced via three defense-in-depth layers:
1. PreToolUse hook in .claude/settings.json blocks any Write/Edit that
would push a file past the 500-line hard cap. Auto-loads for any
Claude session in this repo regardless of who launched it.
2. scripts/githooks/pre-commit (installed via scripts/install-hooks.sh)
enforces the LOC cap, freezes migrations/ unless [migration-approved],
and protects guardrail files unless [guardrail-change] is present.
3. .gitea/workflows/ci.yaml gets loc-budget + guardrail-integrity jobs,
plus mypy --strict on new Python packages, tsc --noEmit on Node
services, and a syft+grype SBOM scan.
Per-language conventions are documented in AGENTS.python.md / AGENTS.go.md /
AGENTS.typescript.md at the repo root — layering (router->service->repo for
Python, hexagonal for Go, colocation for Next.js), tooling baseline, and
explicit "what you may NOT do" lists.
Adds scripts/check-loc.sh (soft 300 / hard 500, reports 205 hard and 161
soft violations in the current codebase) plus .claude/rules/loc-exceptions.txt
(initially empty — the list is designed to shrink over time).
Per-service READMEs for all 10 services + PHASE1_RUNBOOK.md for the
backend-compliance refactor. Skeleton packages (compliance/{domain,
repositories,schemas}) are the landing zone for the clean-arch rewrite that
begins in Phase 1.
CLAUDE.md is prepended with the six non-negotiable rules.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2.5 KiB
2.5 KiB
Architecture Rules (auto-loaded)
These rules apply to every Claude Code session in this repository, regardless of who launched it. They are non-negotiable.
File-size budget
- Soft target: 300 lines per non-test, non-generated source file.
- Hard cap: 500 lines. The PreToolUse hook in
.claude/settings.jsonblocks Write/Edit operations that would create or push a file past 500. The git pre-commit hook re-checks. CI is the final gate. - Exceptions live in
.claude/rules/loc-exceptions.txtand require a written rationale plus[guardrail-change]in the commit message. The exceptions list should shrink over time, not grow.
Clean architecture
- Python (FastAPI): see
AGENTS.python.md. Layering:api → services → repositories → db.models. Routers ≤30 LOC per handler. Schemas split per domain. - Go (Gin): see
AGENTS.go.md. Standard Go Project Layout + hexagonal.cmd/thin, wiring ininternal/app. - TypeScript (Next.js): see
AGENTS.typescript.md. Server-by-default, push the client boundary deep, colocate_components/and_hooks/per route.
Database is frozen
- No new Alembic migrations. No
ALTER TABLE. No__tablename__or column renames. - The pre-commit hook blocks any change under
migrations/oralembic/versions/unless the commit message contains[migration-approved].
Public endpoints are a contract
- Any change to a path/method/status/request schema/response schema in a backend service must update every consumer in the same change set.
- Each backend service has an OpenAPI baseline at
tests/contracts/openapi.baseline.json. Contract tests fail on drift.
Tests
- New code without tests fails CI.
- Refactors must preserve coverage. Before splitting an oversized file, add a characterization test that pins current behavior.
- Layout:
tests/unit/,tests/integration/,tests/contracts/,tests/e2e/.
Guardrails are themselves protected
- Edits to
.claude/settings.json,scripts/check-loc.sh,scripts/githooks/pre-commit,.claude/rules/loc-exceptions.txt, or anyAGENTS.*.mdrequire[guardrail-change]in the commit message. The pre-commit hook enforces this. - If you (Claude) think a rule is wrong, surface it to the user. Do not silently weaken it.
Tooling baseline
- Python:
ruff,mypy --stricton new modules,pytest --cov. - Go:
golangci-lintstrict config,go vet, table-driven tests. - TS:
tsc --noEmitstrict, ESLint type-aware, Vitest, Playwright. - All three: dependency caching in CI, license/SBOM scan via
syft+grype.