- Python 3.14 (see
pyproject.tomlrequires-python) - Node 24 LTS (see
frontend/package.jsonengines.node) uvfor Python deps + venvjustfor the task runner (optional but recommended)- Docker (for the local stack: app + frontend + Jaeger)
git clone https://github.com/constk/harness-python-react.git
cd harness-python-react
# Backend deps + venv
uv sync --extra dev
# Pre-commit hooks (commit-msg + pre-commit stages)
uv run pre-commit install --hook-type pre-commit --hook-type commit-msg
# Frontend deps
cd frontend && npm ci && cd ..docker compose up- Backend: http://localhost:8000/api/v1/health
- Frontend (Vite dev server with HMR): http://localhost:5173
- Jaeger UI: http://localhost:16686
For backend-only iteration without Docker:
uv run uvicorn src.api.main:app --reload --port 8000For frontend-only iteration:
cd frontend && npm run devjust (no args) lists every recipe. The most-used:
| Recipe | What it runs |
|---|---|
just lint |
ruff check . + ruff format --check . |
just typecheck |
mypy --strict src/ tests/ |
just test |
pytest tests/ -m "not integration" |
just architecture |
lint-imports |
just check |
lint typecheck architecture test (the pre-push gate) |
just frontend-check |
npm run lint && format:check && check && test |
just docker-build |
Builds harness-python-react:dev for sanity checks |
Every recipe uses uv run --frozen — bare uv run silently re-resolves when pyproject.toml drifts from uv.lock; --frozen aborts loudly instead.
main ◄── release PR ◄── develop ◄── feat/123-short-name
◄── fix/124-bug-name
◄── chore/125-config-change
mainis protected: every required CI context must pass + 1 review + commit-type sync + branch-protection sync.developis the integration branch; same gates asmainminus a strictness flag (strict: falseso PRs don't need rebases).- Feature branches are short-lived and named
<type>/<issue-number>-<kebab-title>.
Seven allowed prefixes (enforced in three places — [tool.commitizen], pr-title.yml, check_commit_types.py):
feat:— new capabilityfix:— bug fixdocs:— documentation onlytest:— tests / eval-harness changesrefactor:— internal change with no behaviour deltachore:— tooling, deps, infrarelease:—develop → mainrelease PRs only
Subject is lowercase after the colon (Title Case is rejected unless it's an all-caps initialism).
| Workflow | Triggers | Required? |
|---|---|---|
ci.yml |
push/PR to develop+main | Yes — 8 backend + 2 frontend jobs |
security.yml |
push/PR + weekly schedule | Yes — 4 jobs (gitleaks, pip-audit, npm audit, trivy) |
pr-title.yml |
PR open/edit/sync | Yes — conventional-commit lint |
release.yml |
tag v*.*.* |
No — tag-triggered |
release-drafter.yml |
push to main + PR label events | No |
branch-protection.yml |
weekly + push to .github/branch-protection/** | No |
artifact-cleanup.yml |
weekly | No |
eval-nightly.yml |
workflow_dispatch only by default |
No |
codeql.yml |
workflow_dispatch only (placeholder) |
No |
The .claude/hooks/ scripts enforce the harness from the LLM-coder side: blocking --no-verify, scanning staged diffs for secrets, formatting after every Write/Edit. Opt in by copying the example settings file:
cp .claude/settings.local.json.example .claude/settings.local.jsonThe example wires:
PreToolUse:Bash→pretooluse_bash.py(forbidden-flag blocker + secret scan + audit log)PostToolUse:Write|Edit→posttooluse_writeedit.py(ruff / prettier on touched files)SessionStart:startup|resume→sessionstart.py(injects current branch +git status --shortas session context)
.claude/settings.local.json and .claude/bash-log.txt are gitignored — your local config never ships.
uv run pre-commit install --hook-type pre-commit --hook-type commit-msg wires both stages. The hooks:
- Ruff (lint + format auto-fix)
- Generic hygiene (YAML/TOML/JSON parse, merge conflicts, large files >500 KB, trailing whitespace, EOF, line endings)
- Gitleaks (secret scan)
- Commitizen (conventional-commit lint at
commit-msg) - Local mypy
--strictagainst the project's uv env
pre-commit run --all-files runs the full suite against every file — the same job CI runs.
The branch-protection.yml workflow needs a BRANCH_PROTECTION_TOKEN secret with admin:repo scope on this repo. The default GITHUB_TOKEN cannot edit branch protection on the repo it runs in. Create a fine-grained PAT scoped to this repo only.