Thanks for contributing to flow-comet. This guide covers the branch model, pull-request workflow, merge rules, and code standards — the repository is protected by these rules, so following them keeps the flow smooth.
feat/xxx ──PR(squash)──▶ dev (integration branch — change-level commits)
│
dev ──PR(merge)──▶ main (release branch — one merge commit per release; dev's change-level commits enter main)
| Branch | Role | Merge style | History |
|---|---|---|---|
main |
Release branch | merge | Release PRs merge dev's change-level commits into main (one merge commit per release); every PR's commits stay in main permanently |
dev |
Integration branch | squash | One change-level commit per PR — internal fix detail lives in the PR's Commits list |
feat/* |
Development branch | — | Working history, deleted after merge |
Why this split: dev carries one change-level commit per PR (squash) — a clean, stable sequence where each PR is one unit; the PR's internal commit history (each TDD fix) remains browsable in that PR's Commits list. main receives dev's change-level commits via one merge commit per release — PR history becomes part of main permanently, and after the release merge dev's tip is an ancestor of main, so dev stops leading main (no accumulated release history on dev).
-
Create a feature branch from
dev(prefixfeat/, orfix/for bug fixes) — all changes (including documentation) must go through a feature branch; never commit directly todev:git checkout dev git checkout -b feat/<description>
-
Develop on the feature branch — follow the Development standards below.
-
Open a PR into
dev(basedev, headfeat/<description>). Use the repository PR template (.github/PULL_REQUEST_TEMPLATE.md— scope / verification / self-check checklists). Fill in what changed, why, and verification evidence. Keep the full checklist visible: mark involved items[x]and leave non-involved items[ ]— do not delete unchecked items (the checklist is the reviewer's completeness signal). -
Get the merge gate green — required CI checks must pass (see Review requirements below); the user (maintainer) reviews and approves before merging.
-
Merge into
dev— squash merge: one change-level commit per PR (the PR's internal commits remain browsable in its Commits list).devaccumulates changes — do not release after every change. -
Release PR (batched) — when
devhas accumulated a set of related changes (a feature batch or a maintenance batch), open one release PR intomain(basemain, headdev). Merge with merge — the merge commit brings all of dev's change-level commits into main; dev's tip becomes an ancestor of main, so dev no longer leads main after the release. The release PR title/body carries the public-facing release summary. -
After merge, delete the feature branch.
Maintenance batches: pure-documentation or cleanup changes without behavior impact may accumulate on a single branch (e.g. docs/maintenance-<date>) and ship as one PR into dev — reducing PR count without losing traceability.
| Rule | main |
dev |
|---|---|---|
| Require status checks (CI jobs) | ✅ (regression / pr-policy / quality / installer / docs-links — required for merge; release-consistency runs on the release face only and is not required) | ✅ (same) |
| Block force pushes | ✅ | ✅ |
| Block deletions | ✅ | ✅ |
| Dismiss stale reviews | ✅ | ✅ |
After a release: fast-forward dev to main — the release PR merge makes dev's tip an ancestor of main, so a zero-commit fast-forward syncs dev to main exactly (run it right after the release merge, before the next development PR lands on dev):
git checkout dev
git merge main # fast-forward — dev becomes identical to main
git push origin devDev's tip being an ancestor of main is what makes this a fast-forward: no sync merge commit is created.
After a hotfix (squashed directly into main), sync dev so it does not fall behind main:
git checkout dev
git merge --no-ff main -m "sync: main → dev(hotfix <description>)"
git push origin devHotfix fast path (production emergency fix, independent of the dev release cadence):
git checkout main
git checkout -b hotfix/<description>
# fix → commit (fix: subject) → test
# hotfix merges via squash — one clean commit into main (release PRs merge; hotfixes squash to keep emergency fixes atomic)
git checkout main && git merge --squash hotfix/<description> && git commit -m "fix: hotfix <description>"
git checkout dev && git merge --no-ff main -m "sync: main → dev(hotfix <description>)"
git branch -d hotfix/<description>- Read the README — the quick start walks through a minimal workflow.
- Pick a first issue — issues labeled
good first issueare scoped for newcomers. - Set up your environment — Node.js ≥ 18; clone the repo; run
npm installonce (installs the locked@clack/promptsdependency — the repository's only third-party dependency, used solely by the installer's interactive platform selection); runnode scripts/install-commit-hook.mjsonce (local commit/push message checks). - Verify the baseline — run the regression suite (see Development setup below).
- Not sure whether a change is wanted? Open an issue first — the issue templates ask for the context we need.
- Runtime: Node.js ≥ 18 (ESM); the only third-party dependency is
@clack/prompts(pinned exact version viapackage-lock.json), used only by the installer's interactive TTY multi-select with an automatic readline fallback — runnpm installonce after cloning - Repo: clone, run
npm install, then verify the regression baseline runs:node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/guard-self-test.mjs→ALL 219 SCENARIOS PASSED(two-tier baseline; also runsystem-test.mjs→ALL SYSTEM TESTS PASSED, 73 items) - Authoring environment: Claude Code (skills/hooks run in Claude Code sessions); the hook is installed via
prepare-envinto your project's.claude/(the same installer serves Codex via--platform codexand DeepSeek Harness (dsh) via--platform dsh— project-level skill tree, AGENTS.md managed rules, and a global bridge loader) - For mechanism work: read docs/MECHANISM.md for the mechanism semantics (behavior layer) before touching scripts
CI runs automatically on every PR and push — it enforces the repository conventions server-side (regression suite with scenario-count and public-artifact code self-checks, script syntax, BOM guard, installer reproducibility across all three platforms — Claude Code / Codex / DeepSeek Harness (dsh) — workflow yaml validity, PR template completeness, commit-message conventions, version consistency, CHANGELOG PR links, dead links).
Local hooks (install once after cloning):
node scripts/install-commit-hook.mjs # sets core.hooksPath → .githooks/The hooks reject commits and pushes whose messages carry process codes — project shorthand such as fix numbers, batch codes, or scenario numbers. This word list is this project's own convention (not a universal list); commit messages are public artifacts, so keep them as plain descriptions (see the commit convention below).
Before pushing, run the regression baseline:
node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/guard-self-test.mjs # → ALL 219 SCENARIOS PASSEDCI handles the rest.
Open an issue with a clear description:
- Bug: what happened vs expected, reproduction steps (or the exact BLOCKED/WARN message), environment (Node version, install method)
- Feature proposal: the goal, the workflow you want, any skill combination you have in mind (see PROTOCOL.md for custom protocols)
After the issue is confirmed: bug fixes use a fix/ branch, features use a feat/ branch — both PR into dev per the Pull-request workflow.
- Authoritative source: edit skills/scripts under
.comet/bundle-drafts/flow-comet/skills/(the single source;.claude/copies are install artifacts — update them viaprepare-env, never by hand) - TDD: every mechanism fix starts with a RED scenario in
guard-self-test.mjs(watch it fail for the right reason), then GREEN, then full regression - Regression baseline:
node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/guard-self-test.mjs→ALL 219 SCENARIOS PASSED(two-tier baseline; also runsystem-test.mjs→ALL SYSTEM TESTS PASSED, 73 items) (mandatory after every change) - Documentation sync: behavior-layer docs live in
docs/(bilingual EN/zh — keep both in sync when a doc changes); implementation details stay out of public docs - Bilingual discipline: English docs contain no Chinese (except the language switcher, flow-kit artifact section names, and runtime message quotes); Chinese docs contain no long English sentences (except commands, URLs, and proper terms)
- Backward compatibility: old changes/states keep working — progressive WARN over BLOCK
- Public docs stay jargon-free: no codes, numbers, or process shorthand in README/docs/CHANGELOG/commit messages
Commit messages are public artifacts — they are visible in the git history on GitHub. Write them as plain descriptions: no codes, numbers, or jargon. Use the same public-facing language as CHANGELOG and the docs. Example:
fix: brooks 6-dimension self-check two-tier fallback.
<type>(<scope>): <subject>
feat: new feature / mechanism
fix: bug fix (mechanism, script, hook)
refactor: behavior-preserving restructuring
perf: performance improvement
docs: documentation (README, docs/, CHANGELOG)
test: test-only changes (guard-self-test scenarios)
build: build/tooling changes (scripts, installer)
ci: CI pipeline changes
chore: tooling, release wrap-up
revert: reverts a previous commit
General optional scope: this repository uses <type>(<scope>): <subject> — the scope is a short subsystem or area-of-interest noun from the ecosystem-wide Conventional Commits vocabulary (e.g. docs, usage, installer, guard, handoff, selftest). The scope is recommended and optional: give one for single-subsystem changes (e.g. feat(guard): ..., docs(usage): ..., fix(installer): ...); omit it (<type>: <subject>) for cross-subsystem or global changes. Management codes — change-id, dates, task numbers — must never be used as the scope (administrative metadata does not belong in the subject or the scope). Task/work-item IDs go in the commit body footer as Task: <id> — for example, subject feat(guard): add import pipeline with body Task: T01. The Task: footer is the sanctioned exception to the no-numbers rule.
Workflow artifacts are never committed: .specs/ artifacts (SUMMARY, handoff, TASK, etc.) are gitignored workflow products and never enter the repository. If git add is rejected for them, that rejection is correct behavior — never bypass it with git add -f.
Examples:
fix: init state gains status:'running' + three-tier hook semantics
docs: README restructured into multi-document bilingual layout
test: BOM-tolerance scenarios — state/evidence files with UTF-8 BOM parse normally
Branch prefix alignment: the prefix should match the change type, not a fixed default. Two ways to create a branch — pick by how you develop:
- Pure git development (no flow-comet workflow):
git checkout -b feat/<description>(orfix/) as in the Pull-request workflow - Through the flow-comet workflow:
initcreates the branch for you — specify the matching prefix:
# Authoritative-source path (development); installed copies: Claude Code .claude/skills/ / Codex .agents/skills/
node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/workflow-state.mjs init <change-id> --branch-prefix feat/ # feature work
node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/workflow-state.mjs init <change-id> --branch-prefix fix/ # bug fixes
node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/workflow-state.mjs init <change-id> --branch-prefix docs/ # documentationThe built-in default prefix is change/ (backward-compatible with existing changes); this repository's convention is to specify the type prefix explicitly so the branch matches the change type — same convention as the manual feat//fix/ branches.
- PR description: what changed, why, verification evidence (test output, real-session evidence)
- Scope: code change → accompany tests + regression; doc change → both languages in sync
- Merge gate: required CI checks must pass; the user (maintainer) reviews and approves before merging.
- Advisory only: bot comments are suggestions, not requirements — bots can be wrong. Apply your own judgment (and the maintainer's review) over bot suggestions.
- Actionable vs informational: a bot comment is actionable when it asks for a concrete change (a fix, a clarification, or additional tests); informational comments (summaries, questions, praise) do not need to be resolved.
- Before merging: address every actionable bot comment — fix it, or reply in its thread explaining why you decline it. Resolve the thread when done.
- Keep the PR timeline clean: reply to bot comments in their threads, not as new timeline mentions. For inline comments use the threaded reply; for an overall review (no thread), use a quote reply that cites the review's text.
- Bot checks vs required CI checks: only the CI jobs (regression / pr-policy / quality / installer / docs-links) are required for merge. Bot checks (CodeRabbit / Sourcery) are informational — they may show as pending or rate-limited in the checks panel without blocking the merge.
- Development PRs (→ dev): behavior changes are recorded in the CHANGELOG
Unreleasedsection (Added/Changed/Fixed, bilingual) — the PR updates CHANGELOG itself. - Before a release (on dev): the version number is settled on dev —
Unreleasedis turned into the[X.Y.Z] - datesection linking the batch's merged development PRs. - Release PR (dev → main): does not update CHANGELOG — the version section already exists on dev; the release PR only merges it into main.
- main: never edits CHANGELOG separately — it receives the version section via the release PR merge.
- After a release: dev is automatically tree-identical to main (the release PR merges dev into main's history) and a fresh
Unreleasedsection starts accumulating the next batch.
While a PR is open, keep it up to date with dev:
git fetch origin
git rebase origin/dev # rebase your feature branch onto the latest dev
# resolve conflicts if any, then:
node .comet/bundle-drafts/flow-comet/skills/flow-comet/scripts/guard-self-test.mjs # re-run regression
git push --force-with-lease origin feat/<description> # force push is allowed on feature branchesForce push is allowed on your own feature branch (no protection); a new push invalidates previous approvals (dismiss stale reviews), so request re-review after updating.
Release approval sheet — before every release, present this sheet to the user and get one approval; then execute the full release (merge release PR + distribute + tag) without further per-step prompts:
## Release approval sheet
- Changes: PR list + one-line summary each
- Verification: regression (219 scenarios) / installed-copy checks
- Version: X.Y.Z (doc-only batches may skip the bump)Release steps: the five-step checklist (CHANGELOG → README badge → tag → prepare-env distribution → dev sync) lives in VERSIONS.md.
Release PR specifics:
- The release PR (dev → main) lists dev's change-level commits (by design — each PR = one change); merging it brings those commits into main via one merge commit per release
- Merge with
gh pr merge --merge— the merge commit message is GitHub's default (Merge pull request #N from dev, public-facing language); the release PR title and body carry the release summary, so no internal process detail enters main