Skip to content

Latest commit

 

History

History
148 lines (103 loc) · 8.02 KB

File metadata and controls

148 lines (103 loc) · 8.02 KB

harness-python-react

CI Security License: MIT Python 3.14 Node 24 LTS React 19.2 Coverage 98%

Production-grade SDLC harness for human–LLM coding collaborations — keeping quality consistent regardless of who shipped the code. Python (FastAPI) + Vite/React/TypeScript, with every gate (lint, types, architecture, security, eval) enforced mechanically in CI, not by discipline.

What ships

  • Backend: Python 3.14, FastAPI, Pydantic v2 (StrictModel base), uv deps, OpenTelemetry SDK + OTLP exporter, structured JSON logs, generic tool-registry pattern.
  • Frontend: Node 24 LTS, React 19.2, Vite 8, TypeScript strict, ESLint 10 flat config, Prettier, Vitest + jsdom + Testing Library.
  • Eval harness: provider-agnostic runner + LLM-judge Protocol, three tolerance modes (exact / numeric / semantic), one example golden case, nightly workflow (disabled by default).
  • CI: 21 required status checks across ci.yml (lint/format, mypy strict, unit tests, coverage, import-linter architecture, pre-commit, frontend build, frontend quality, branch-protection sync, commit-type sync, version/action/tests/docs audits) + security.yml (gitleaks, pip-audit, npm audit, trivy) + PR-title lint.
  • Release: tag-triggered workflow that builds the image, pushes to ghcr.io, generates a CycloneDX SBOM, and publishes the GitHub Release.
  • Agent integration: .claude/hooks/ (forbidden-flag blocker, secret scan, formatter dispatch, SessionStart context) + six auto-activating skills (architect / code-reviewer / devops / frontend / qa-engineer / technical-writer).
  • Issue execution: GitHub Issues remain the external source of truth; optional Beads guidance adds a local dependency-aware execution queue without changing issue closure authority.
  • Docker: multi-stage Dockerfile (non-root, healthcheck), docker compose up boots app + frontend + Jaeger.

Quickstart

git clone https://github.com/constk/harness-python-react.git
cd harness-python-react

uv sync --extra dev
uv run pre-commit install --hook-type pre-commit --hook-type commit-msg
(cd frontend && npm ci)

docker compose up   # backend :8000, frontend :5173, Jaeger :16686

The pre-push gate is just check (= ruff + mypy + import-linter + pytest). For frontend changes add just frontend-check.

Screenshots

just check — local pre-push gate

What every contributor sees before pushing:

$ uv run --frozen ruff check .
All checks passed!

$ uv run --frozen ruff format --check .
37 files already formatted

$ uv run --frozen mypy --strict src/ tests/
Success: no issues found in 31 source files

$ uv run --frozen lint-imports
Analyzed 24 files, 15 dependencies.

src layers flow one-way (api/eval -> agent -> tools -> data -> observability ->
models) KEPT
src.models depends on nothing in src/ KEPT

Contracts: 2 kept, 0 broken.

$ uv run --frozen pytest tests/ --cov=src --cov-report=term
============================= 40 passed in 0.75s ==============================
TOTAL                             221      3    99%
Required test coverage of 75.0% reached. Total coverage: 98.64%

CI on a sample PR

Ten jobs across ci.yml (eight backend + two frontend) — all green:

CI status

The four security-workflow jobs (gitleaks, pip-audit, npm audit, trivy) gate every PR alongside this set; see the Security workflow runs.

Hello page (npm run dev / docker compose up)

The scaffold's React page hits /api/v1/health on load and renders the version + status badge. The Vite dev server proxies /api/* to the FastAPI backend (target overridable via VITE_API_PROXY_TARGET):

Hello page

Jaeger trace (docker compose up + /api/v1/health)

The full stack — backend, frontend, Jaeger collector — boots with docker compose up. Hitting /api/v1/health once produces an OpenTelemetry trace exported via OTLP/gRPC; the span hierarchy is visible at http://localhost:16686 under the harness-python-react service, with agent_span(...) attributes attached using only the keys constant-defined at the top of src/observability/spans.py.

Why a harness

The differentiator isn't the scaffold — it's that every layer of the pipeline catches a different failure class without relying on the human or LLM coder remembering to run anything. The same posture protects code regardless of who wrote it.

Example. An agent added from src.tools import ... inside src.models for type reuse. lint-imports failed CI — the src.models depends on nothing in src/ contract broke — and pointed the next iteration at docs/BOUNDARIES.md. The type moved into src.models instead. Never shipped.

See docs/HARNESS.md for the full umbrella. Highlights:

  • Pydantic StrictModel everywhere a contract crosses a seam (rejects unknown keys at construction).
  • import-linter enforces one-way layer flow (api | eval → agent → tools → data → observability → models).
  • Three independent secret scans (PreToolUse hook → pre-commit gitleaks → CI gitleaks).
  • Two meta-gates that catch drift in the gates themselves: Branch-protection contexts sync (workflow jobs vs branch-protection JSON) and Commit-type sync (commitizen schema vs PR-title allowlist).
  • CycloneDX SBOM attached to every release for supply-chain attestation.

Documentation

File Purpose
docs/HARNESS.md Umbrella: every control + where it lives
docs/INVARIANTS.md The numbered load-bearing rules
docs/BOUNDARIES.md Module layering + the import-linter contracts
docs/DEVELOPMENT.md Local setup, branching, justfile, CI
docs/EVAL_HARNESS.md Eval flywheel + opt-in for the nightly workflow
docs/BEADS.md Optional local Beads queue layered under GitHub Issues
docs/SECURITY.md Threat model + defence-in-depth map
docs/ARCHITECTURE.md Scaffold-level component view
CONTRIBUTING.md Branching, commit format, PR flow
CLAUDE.md Agent-facing project instructions

Versions

Verified April 2026 (endoflife.date):

Layer Version Sunset
Python 3.14.4 active feature release
Node LTS 24.15.0 through 2028-04-30
React 19.2.5 current stable
Vite 8.x current stable
TypeScript 6.x current stable

Bump together (Python in pyproject.toml, Node in frontend/package.json, both in Dockerfile + the CI matrix). Document the bump in docs/DEVELOPMENT.md.

License

MIT.