# 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`](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: ```bash export GITEA_TOKEN= # add to your shell profile export GITEA_URL=http://192.168.0.3:3000 ``` ## Day-to-day ```bash 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: ```bash 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. ```