Files
bike-app/CONTRIBUTING.md
BBergleandClaude Opus 5 d5e473959c
CI / Repo hygiene (pull_request) Successful in 24s
CI / API (lint, types, tests) (pull_request) Successful in 55s
CI / Web (lint, typecheck, build) (pull_request) Successful in 25s
CI / Migrations reversible (pull_request) Successful in 3s
chore: set up branching, CI, and PR workflow
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>
2026-09-20 21:12:22 -04:00

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.