Prepares the repo for parallel agent work. No application code. - CLAUDE.md: conventions, branch naming, and the six non-negotiable invariants from the design (immutable raw bytes, no stored odometers, SI integers, dual-layer user isolation, secret containment, single ingestion path). Also records a model-allocation policy: the orchestrator runs Opus 5, workers default to Sonnet, and Opus is reserved for review plus the areas where a mistake is silent and expensive (ingest, wear SQL, auth/RLS, the Bryton protocol client). And the Gitea Actions gotchas, so nobody rediscovers them: GITEA_TOKEN cannot push to the container registry, jobs.*.environment is ignored, and cron needs a workflow_dispatch pair. - CONTRIBUTING.md: day-to-day flow, worktrees for parallel branches, review expectations. - .gitea/workflows/ci.yml: repo hygiene (branch naming, secret scan, no ride data in git), plus API/web/migration jobs that guard on whether the code exists yet, so CI is meaningful now and grows into the real thing rather than being rewritten. - .gitea/PULL_REQUEST_TEMPLATE.md: forces an honest "how this was verified" and an invariant checklist. - scripts/pr.sh, scripts/review.sh: open and inspect PRs via the Gitea API. - Directory scaffold with placeholder READMEs. Agents open PRs; humans merge them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2.2 KiB
Contributing
Short version: branch, commit, push, open a PR, get it reviewed, squash-merge.
main is never committed to directly.
Conventions live in CLAUDE.md — branch naming, style, the non-negotiable
invariants, and the rules for agents working in parallel. Read that first.
One-time setup
SSH to Gitea should already be pinned in ~/.ssh/config:
Host 192.168.0.3
HostName 192.168.0.3
User git
IdentityFile ~/.ssh/gitea
IdentitiesOnly yes
IdentitiesOnly yes matters: without it, SSH may offer an older deploy key first and Gitea will
authorize against that key's narrower permissions.
For opening PRs from the command line, create a Gitea token at
http://192.168.0.3:3000/user/settings/applications with scopes read:user, write:repository,
write:issue, then:
export GITEA_TOKEN=<token> # add to your shell profile
export GITEA_URL=http://192.168.0.3:3000
Day-to-day
git switch main && git pull
git switch -c feat/ingest-fit-parser
# work, commit in logical steps
git push -u origin feat/ingest-fit-parser
scripts/pr.sh "feat(ingest): parse Bryton FIT activities"
scripts/pr.sh opens the PR against main and prints its URL. Pass --draft if it isn't ready.
Parallel work
Use worktrees so branches don't fight over one checkout:
git worktree add ../bike-app-ingest -b feat/ingest-fit-parser
cd ../bike-app-ingest
# ...
git worktree remove ../bike-app-ingest
Review
- CI must be green before review is requested. A red PR isn't ready.
- Reviewers look for: correctness, the invariants in
CLAUDE.md, whether the tests actually prove what the PR claims, and whether it reuses what already exists. - Address feedback with new commits. Don't force-push over review history unless asked.
- Agents open PRs; humans merge them.
Commits
Conventional prefixes, imperative mood, and a body that explains why:
feat(ingest): discriminate activities from Bryton course files
Bryton writes routes as .fit too, so a naive importer turns saved routes
into phantom rides. Check file_id.type first, falling back to message-shape
inspection since Bryton's encoder omits it on some firmware.