This document defines the workflow for all contributors — human and AI agents alike (Claude Code, Cursor, Copilot, etc.). Read it before making any changes.
mainis the development branch. Never commit directly tomain.- All work happens on feature branches cut from
main:git checkout main && git pull git checkout -b <type>/<short-description> - Branch naming convention:
feat/<description>— new featurefix/<description>— bug fixrefactor/<description>— restructuring without behavior changedocs/<description>— documentation onlychore/<description>— tooling, config, deps
We prefer git worktree over swapping branches in a single checkout. Worktrees give every branch its own working directory backed by the same .git store, which means:
- Multiple agents (or you + an agent) can edit different branches in parallel without stepping on each other.
- Long-running tooling (dev servers, test watchers, GPU jobs, indexers) stays untouched when you switch tasks — no
git stash, no rebuilds. - The main checkout stays clean for reviewing PRs or running
main.
Layout convention. Keep worktrees as sibling directories of the main checkout, named after the branch:
~/Projects/
cascade-devkit/ # main checkout, tracks `main`
cascade-devkit-feat-loader/ # worktree on `feat/loader`
cascade-devkit-fix-nan-ts/ # worktree on `fix/nan-timestamps`
Create a worktree for a new branch. From the main checkout:
git fetch origin
# Create a new branch off origin/main AND a worktree for it in one step
git worktree add -b feat/loader ../cascade-devkit-feat-loader origin/main
cd ../cascade-devkit-feat-loaderCreate a worktree for an existing branch (e.g. to review someone else's PR locally):
git fetch origin
git worktree add ../cascade-devkit-pr-42 origin/their-branchList and inspect worktrees:
git worktree list # show all worktrees + their HEADs
git worktree list --porcelainRemove a worktree once the branch is merged or abandoned:
# From any worktree (typically the main checkout):
git worktree remove ../cascade-devkit-feat-loader
git branch -d feat/loader # delete the branch if merged (use -D to force)
# If the directory was deleted manually, prune stale metadata:
git worktree pruneRules and gotchas:
- One branch per worktree — git refuses to check the same branch out in two worktrees. That is the feature, not a bug.
- Don't nest worktrees inside the main checkout (
./worktrees/...) — tooling that walks the tree (linters, formatters, IDE indexers) will double-process files. - Each worktree has its own untracked files, build artifacts, and
node_modules/venv. Re-install deps aftergit worktree addif needed. git worktree removerefuses if the worktree has uncommitted changes; resolve those first rather than passing--force.
Each commit must:
-
Represent a single logical change — do not bundle unrelated changes.
-
Have a clear message structured as:
<type>(<scope>): <short summary> <body — what changed and why. Mention any trade-offs or alternatives considered.>Example:
feat(auth): add JWT refresh token rotation Access tokens now expire in 15 min. Refresh tokens are single-use and rotated on each use to limit the blast radius of a stolen token. Chose rotation over sliding window to meet the security requirements in docs/ARCHITECTURE.md#authentication. -
Types:
feat,fix,refactor,docs,test,chore
-
We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license.
- Any contribution which contains commits that are not Signed-Off will not be accepted.
-
To sign off on a commit you simply use the
--signoff(or-s) option when committing your changes:$ git commit -s -m "Add cool feature."This will append the following to your commit message:
Signed-off-by: Your Name <your@email.com> -
Full text of the DCO (https://developercertificate.org/):
Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
- PRs are opened from a feature branch into
main. - Keep PRs small and focused. A good PR can be reviewed in under 30 minutes. If a branch grows large, split it.
- PR title follows the same
<type>(<scope>): <summary>format as commits. - PR description must include:
- What the change does
- Why it is being made
- How to test or verify it
- Any open questions or follow-up issues
- Link related GitHub issues when applicable.
- Update
docs/dev/changelog.mdin the same PR with a one-line entry describing the change. The PR number is not known untilgh pr createreturns it — either predict the next number withgh pr list --state all --limit 1 --json number, or commit with a placeholder, open the PR, amend the commit with the real(#<N>), and force-push the feature branch (force-push is forbidden onmainbut permitted on your own feature branch). - At least one approval is required before merging.
The docs/dev directory is the project's living memory. All contributors must keep it up to date.
| File | Purpose |
|---|---|
docs/dev/architecture.md |
Design decisions, system design, rationale. Check this before starting any non-trivial work. |
docs/dev/changelog.md |
One-line entry per merged PR (newest first). Update in the same PR that makes the change — see Pull Requests. |
docs/dev/schema-history.md |
Per-version table for the CASCADE annotation schema. Mirrors SCHEMA_HISTORY in cascade_av.spec.versions; update in the same PR that changes the registry. |
The contributor workflow itself (this document) lives at the repo root in CONTRIBUTING.md so GitHub surfaces it on issue / PR pages.
- Read
docs/dev/architecture.mdfirst before proposing or implementing any structural change. - Record newly discovered issues as GitHub issues using
ghrather than silently working around them (see GitHub Issues below). - Look for open GitHub issues since they could reveal existing problems.
- Add a one-line entry to
docs/dev/changelog.mdas part of the same PR that makes the change (not a follow-up). See Pull Requests for how to handle the PR-number reference.
We track work and surface defects through GitHub Issues, managed from the terminal with the gh CLI. Authenticate once with gh auth login (or rely on GH_TOKEN if it is set in your environment).
Before opening a new issue or starting a non-trivial change, scan what is already tracked — your bug or idea may already be known.
# List open issues in this repo (default: open, no filter)
gh issue list
# Filter by label, assignee, or author
gh issue list --label bug
gh issue list --label "good first issue"
gh issue list --assignee @me
gh issue list --author @me
# Full-text search across titles and bodies
gh issue list --search "dataset loader"
gh issue list --search "panic in:title"
# Include closed issues when researching prior decisions
gh issue list --state all --search "schema"
# View a specific issue in the terminal
gh issue view 42
gh issue view 42 --comments # include the discussion thread
gh issue view 42 --web # open in the browser insteadKeep one issue per problem. A good issue is reproducible, scoped, and actionable.
# Interactive: prompts for title, body (in $EDITOR), labels, assignees
gh issue create
# Non-interactive: fully specified on the command line
gh issue create \
--title "fix(loader): NaN timestamps crash CSV ingest" \
--body "Reproduce by running ./scripts/ingest.py on fixtures/bad_ts.csv. Expected: row skipped with a warning. Actual: ValueError on line 42." \
--label bug
# Body from a file (useful for longer reports or templates)
gh issue create --title "feat(api): paginated dataset listing" --body-file .github/ISSUE_TEMPLATE/feature.md
# Assign and label at creation time
gh issue create --title "..." --body "..." --label bug --label "needs-triage" --assignee @meRecommended title format mirrors our commit style: <type>(<scope>): <short summary>.
A useful issue body includes:
- Context — what you were doing and why.
- Steps to reproduce — exact commands, inputs, or files.
- Expected vs. actual — what should happen, what does happen.
- Environment — branch/commit (
git rev-parse --short HEAD), OS, relevant tool versions. - Workaround (if any) — so others hitting it aren't blocked.
# Comment on an existing issue (e.g. to link a PR or add findings)
gh issue comment 42 --body "Reproduced on main@$(git rev-parse --short HEAD); root cause looks like timestamp parsing."
# Add or remove labels after triage
gh issue edit 42 --add-label "priority:high" --remove-label "needs-triage"
# Close manually (PR merges that mention "Closes #42" will close it automatically)
gh issue close 42 --reason completed
gh issue close 42 --reason "not planned" --comment "Superseded by #57."To auto-close an issue when a PR merges, include Closes #<n> (or Fixes #<n>) in the PR description.
The following rules apply to all AI coding agents (Claude Code, Cursor, GitHub Copilot, etc.):
- Use git worktree so multiple agents can work on the repository in parallel without stepping on each other. See Worktrees for the layout convention and commands.
- Branch first. Never modify source files on
main. Always create a branch. - Commit atomically. One logical change per commit with a clear message explaining what and why.
- No large PRs. If a task requires many changes, split into sequential PRs.
- Architecture first. Read
docs/dev/architecture.mdbefore making structural decisions. - Surface issues. Add discovered problems to GitHub issues — don't silently patch around them.
- No force-push to
main. Ever. - Do not commit secrets, credentials, or environment files (
.env, key files, etc.). - Do not auto-merge your own PRs without a human or designated reviewer approval.
First time on the project:
git clone <repo-url>
cd cascade-devkitStarting a new piece of work (preferred — uses a worktree so your main checkout stays free):
git fetch origin
git worktree add -b feat/your-feature ../cascade-devkit-feat-your-feature origin/main
cd ../cascade-devkit-feat-your-feature
# Install deps into this worktree (fresh worktrees have no .venv or
# node_modules). Cheap if everything is already cached.
make install
# make changes
git commit -m "feat(scope): what and why"
git push -u origin feat/your-feature
gh pr create # open a PR from the terminalWhen the PR is merged, clean up:
cd ../cascade-devkit
git worktree remove ../cascade-devkit-feat-your-feature
git branch -d feat/your-featureFor questions or process issues, file a GitHub issue.