Thank you for helping improve Comet. This guide explains how to set up the project, prepare a change, keep branches healthy, submit a pull request, and update project-specific assets such as skills and Classic workflow scripts.
Deeper project conventions (Chinese terminology, changelog authoring, bilingual
skill sync, restraint on README updates, etc.) live in CLAUDE.md. This guide
covers only the contribution flow itself and does not repeat those rules.
- First-time contributors can look for issues labeled
good first issue. - For bug fixes, first check whether an issue or recent PR already covers the same problem.
- For larger behavior changes, open an issue or draft PR early so the direction can be discussed before too much code is written.
- Keep each contribution focused on one purpose. Split unrelated changes into separate PRs.
- Include tests or explain why a change does not need tests.
- Update documentation and
CHANGELOG.mdwhen behavior, commands, workflows, or user-facing text changes. - A PR version may only be ahead of
masterby exactly one version. For example, ifmasteris0.3.0, the PR version must be0.3.1.
- Leave a comment under the issue you want to claim, to avoid duplicate work.
- Create a task branch from the latest
master, named after the feature or fix area, for examplefix/dev-resync-docsordocs/contributing-guide. - Implement the change locally, add tests, and run targeted checks.
- Before PR review, run the full verification command:
pnpm build && pnpm lint && pnpm format:check && pnpm test, unless the change is documentation-only. - Open a PR against
masterand follow the template to describe what changed, why it changed, and how it was verified. - After the PR is submitted, three AI reviewers will leave feedback. Their suggestions are not always correct — you need to identify which comments are actionable and which are AI misjudgments, and address everything genuinely related to your PR.
- Once you fix the AI review comments, just push your changes; the PR updates
automatically. You must reply to every AI comment and click
Resolve conversationon the ones you consider resolved. - After everything is resolved, wait for the human maintainer's review feedback.
- Issues labeled
good first issue. - Issues labeled
task. - Issues labeled
bug. - Before claiming, confirm the issue has not already been claimed by or assigned to someone else, to avoid duplicate work.
git clone https://github.com/rpamis/comet
cd comet
pnpm install
pnpm build- Node.js
>=20. The pnpm version is pinned inpackage.json'spackageManagerfield (currentlypnpm@10.18.3). - If dependency installation or build behavior differs locally, mention it in the PR.
| Command | Purpose |
|---|---|
pnpm dev |
Watch mode (TypeScript) |
pnpm build |
Full build (build.js + Classic runtime + dashboard) |
pnpm build:classic-runtime |
Build only the Classic runtime (scripts/build/build-classic-runtime.mjs) |
pnpm build:dashboard |
Build only the comet dashboard frontend (Vite) |
pnpm dev:dashboard |
Dashboard frontend dev mode |
pnpm test |
Run unit tests (Vitest) |
pnpm test:coverage |
Run tests with coverage |
pnpm test:script-smoke |
Run the Classic launcher smoke suite; CI entry point |
pnpm test:watch |
Vitest watch mode |
pnpm lint |
ESLint + architecture linter |
pnpm lint:architecture |
Repository layering linter (scripts/lint/architecture.mjs) |
pnpm lint:fix |
ESLint auto-fix |
pnpm format |
Prettier formatting for app/, domains/, platform/ |
pnpm format:check |
Prettier check (CI-enforced) |
pnpm benchmark:context |
Context compression benchmark |
pnpm benchmark:execution |
Context execution benchmark |
pnpm benchmark:classic |
Classic baseline regression benchmark |
pnpm benchmark:bundle |
Bundle compatibility benchmark (includes build) |
For Classic workflow script work, the most useful targeted check is:
npx vitest run test/domains/comet-classic/comet-scripts.test.tsBefore opening or updating a PR, run the full verification command unless the change is documentation-only:
pnpm build && pnpm lint && pnpm format:check && pnpm testmasteris the canonical development and release base.- Create task branches from the latest
master. - Open PRs against
master. - Merge PRs with Squash and merge.
- Treat squashed PR branches as disposable: delete them after merge, or
recreate/reset them from
masterbefore reuse.
Squash merge creates a new commit on master. If the source branch still keeps
the original commits, Git cannot always recognize that both histories contain
equivalent changes. Because of that, do not keep merging master back into a
branch that has already been squashed.
git fetch origin
git switch master
git pull --ff-only origin master
git switch -c <type>/<short-topic>Use a short branch name that describes the change, for example
fix/dev-resync-docs or docs/contributing-guide.
While working:
- Keep commits small enough to review.
- Prefer adding tests before or with the implementation.
- Run targeted tests during development.
- Re-run formatting before the final diff.
- Avoid broad rewrites, formatting sweeps, or unrelated metadata churn.
If a PR branch falls behind master, prefer rebasing your task branch onto the
latest master:
git fetch origin
git switch <your-branch>
git rebase origin/master
# resolve conflicts, then run the relevant checks
git push --force-with-leaseUse --force-with-lease after a rebase because it protects remote work that you
do not have locally. Avoid plain --force.
If the branch has become tangled with unrelated commits, create a clean branch
from origin/master and cherry-pick only the commits that belong to the PR:
git fetch origin
git switch -c <topic>-take-2 origin/master
git cherry-pick <commit-1> <commit-2>
# run checks
git push --force-with-lease origin <topic>-take-2:<original-branch>This keeps the PR reviewable and prevents accidental merges of unrelated work.
If you keep a shared dev branch, use it only as a temporary working branch.
After a PR from dev is squashed into master, do not merge master back into
dev. Reset dev to origin/master after confirming there is no unsquashed
work that still needs to be preserved:
git fetch origin
git switch dev
git status --short
git branch backup/dev-before-sync-YYYYMMDD
git reset --hard origin/master
git push --force-with-lease origin devIf dev contains work that has not been merged to master, move that work to a
new branch from origin/master before resetting dev.
Follow Conventional Commits:
<type>: <description>
<type>(<scope>): <description>
Types: feat, fix, refactor, docs, test, chore, perf, build, ci
Examples:
feat: add eval report language switch
fix(eval): prevent chart labels from overlapping
docs: update contributor commit rules
The repository ships a Git pre-commit hook (.husky/pre-commit + lint-staged)
that runs prettier --write on every git commit against staged source files
under app/, domains/, and platform/. The scope matches CI format:check,
is editor-independent, and applies to every contributor.
- The hook is installed by
huskyduringpnpm install. - On Windows with
core.autocrlf=true, untouched legacy files may be falsely flagged byprettier --checkdue to CRLF. The hook only processes staged files; legacy files are auto-converted to LF the next time they are edited. - You should still run
pnpm lint,pnpm build, andpnpm testmanually before committing — CI enforces all of them.
- Update
masterand create a feature branch from it. - Implement a focused change with tests.
- Run targeted checks while developing.
- Run
pnpm build && pnpm lint && pnpm format:check && pnpm testbefore PR review, unless the change is documentation-only. - Open a PR against
master. - Describe what changed, why it changed, and how it was verified.
- Respond to review feedback with follow-up commits.
- Use Squash and merge when the PR is approved.
- Delete or recreate the source branch after merge; do not keep merging
masterback into a squashed branch.
For documentation-only changes, run at least the relevant formatter check. Root
README.md and README-zh.md are listed in .prettierignore and are not
checked by Prettier, for example:
npx prettier --check CONTRIBUTING.md CONTRIBUTING-zh.mdSource code is layered by responsibility, with each layer having a clear scope:
app/ # CLI entry and command orchestration. Composes domain/platform capabilities only; holds no domain rules.
├── cli/ # Commander registration
└── commands/ # comet init / status / doctor / update / bundle / publish / skill / creator / eval / dashboard ...
domains/ # Business domain modules
├── bundle/ # Skill bundle compilation, publishing, loading
├── comet-classic/ # Classic workflow (state / guard / handoff / archive / intent / hook-guard)
├── dashboard/ # comet dashboard backend + frontend (web/)
├── engine/ # Generic execution engine (loop / state / guardrails / evals)
├── eval/ # comet eval harness
├── factory/ # Skill creator artifact packaging
├── integrations/ # Third-party integrations (openspec / superpowers / codegraph)
├── skill/ # Skill install, discovery, preferences, snapshot
└── workflow-contract/ # Cross-workflow contracts
platform/ # Platform adaptation; domain code does not leak platform differences
├── fs/ # Filesystem utilities
├── install/ # Platform definitions, detection, install paths
├── paths/ # Repository layout resolution
├── process/ # Subprocesses, error handling, shell quoting
└── version/ # Version comparison
scripts/ # Repository automation (build / release / benchmark / lint / install)
├── benchmark/ # Benchmark suites
├── build/ # build-classic-runtime.mjs, build.js, etc.
├── install/ # postinstall.js
├── lib/ # Cross-script utilities
├── lint/ # architecture.mjs, gitignore-top-level.mjs
└── release/ # prepare.js, prepublish-check.js
assets/ # Release assets: built-in skill content and install manifest
├── skills/ # English skills
├── skills-zh/ # Chinese skills
└── manifest.json # Install entry point
docs/ # Architecture, operations, and design docs (docs/superpowers/ is written by the workflow)
bin/comet.js is the npm bin entry; build.js is the top-level build
script; vitest.config.ts / eslint.config.js / tsconfig.json are tooling
configurations.
pnpm lint:architecture (scripts/lint/architecture.mjs) verifies:
- The top-level directory whitelist
(
config/repository-layout.json'sallowedTopLevelEntries). - Active source roots are restricted to
app/domains/platform(sourceRoots). - Sub-modules of each layer
(
appModules/domainModules/platformModules/scriptModules). - Classic runtime entry/output consistency.
- Built-in skill roots and the install manifest are consistent.
- Test ownership (see the next section).
- Migration-legacy directories (e.g.
src/,test/ts/) are not reintroduced.
If you genuinely need to add a top-level directory, source module, test root,
or exception, you must update config/repository-layout.json, the
architecture linter rules, and the relevant sections of this guide before
opening the PR.
Test directories strictly follow the ownership of the code under test:
| Test directory | Coverage |
|---|---|
test/app/ |
CLI and commands under app/ |
test/domains/<domain>/ |
The matching domains/<domain>/ (each domain has a same-named subdirectory) |
test/platform/ |
The platform/ adaptation layer |
test/scripts/ |
The scripts/ automation scripts |
test/repository/ |
Cross-layer constraints: README, CI workflows, repository layout, package scripts, Classic runtime assets |
test/fixtures/ |
Test data |
test/helpers/ |
Test utilities (comet-test-utils.ts, ensure-cli-built.ts, workflow-plan.ts) |
Do not add horizontal buckets like test/ts/; legacy files should be migrated
to the directories above. The CI smoke entry point is
pnpm test:script-smoke; GitHub Actions and local runs share the same Classic
launcher smoke suite.
- Add an entry to
PLATFORMSinplatform/install/platforms.ts. - Add the mapping to
SKILLS_AGENT_MAPindomains/integrations/superpowers.tsif it differs. - Add or update tests (
test/platform/and the relevant domain tests) that cover detection, installation paths, and generated instructions. - Update
assets/manifest.jsonand the README documentation. - If the platform is user-facing, record it in
CHANGELOG.md.
- Write or update the Chinese version first under
assets/skills-zh/. - Get the wording and behavior confirmed, then sync the English version under
assets/skills/. The two versions must be behaviorally equivalent. - Add new skills to
assets/manifest.json. - Add tests for generated assets or installer behavior when applicable
(
test/domains/skill/,test/repository/classic-runtime-assets.test.ts). - When changing skill boilerplate, sync every copy across all
SKILL.mdandreference/*files. - Never directly modify the original Superpowers or OpenSpec skills.
Skill design guidance:
- Decision Core first: Agent-facing instructions go at the top, including phase detection, dispatch logic, and error handling.
- Reference Appendix: Field reference, script locations, and best practices go at the bottom.
- Keep Chinese and English versions behaviorally equivalent, even when wording
differs naturally. Chinese terminology follows the translation rules in
CLAUDE.md(do not translategateas "门").
Workflow scripts live under assets/skills/comet/scripts/ as thin Node.js
launchers (.mjs). They depend only on Node.js (every Comet user has
Node.js) and never on Bash / Git Bash / WSL, so behavior is identical on
macOS, Linux, and Windows.
- Each launcher (
comet-state.mjs,comet-guard.mjs,comet-handoff.mjs,comet-archive.mjs,comet-yaml-validate.mjs,comet-hook-guard.mjs,comet-intent.mjs) is a thin wrapper:import { main } from './comet-runtime.mjs'and dispatch viamain(['<command>', ...process.argv.slice(2)]). - All real logic lives in
domains/comet-classic/*.ts(TypeScript) and is bundled into a singlecomet-runtime.mjsbyscripts/build/build-classic-runtime.mjs(esbuild). After editing anything indomains/comet-classic/*, runpnpm build(orpnpm build:classic-runtime), otherwise tests exercise a stale bundle and the freshness check inclassic-runtime.test.tswill fail. - Cross-platform concerns are handled by Node: hashing via
node:crypto, YAML via theyamlpackage, subprocesses viachild_process(build/validate commands go throughspawnSync(cmd, { shell: true })). There are nosed -i/sha256sumvsshasum/pipefailportability hazards. comet-env.mjsprints its own directory so skill boilerplate can resolve sibling launcher paths vianode "$COMET_ENV". Commands use the unified formnode "$COMET_STATE" ....- When adding or renaming a launcher, sync:
assets/manifest.json(skills[]and thehooksentry forcomet-hook-guard.mjs);config/repository-layout.json'sclassicRuntime.entries/outputs;- The
beforeEachcopy list intest/domains/comet-classic/comet-scripts.test.ts; - The
.codex/skills/comet/scripts/mirror (gitignored, regenerated by install; just keep it consistent locally).
Runtime dispatch:
comet-runtime.mjs <- every comet-*.mjs launcher imports it
└─ domains/comet-classic/classic-cli.ts dispatches: state / validate / guard / handoff / archive / hook-guard / intent
comet-hook-guard.mjs <- PreToolUse hook (install writes `node <skillsDir>/.../comet-hook-guard.mjs` into each platform's settings)
When changing fields in a .comet.yaml state file, update all three places (all
in TypeScript):
domains/comet-classic/classic-state-command.tsfor thesetwhitelist and enum validation (SETTABLE_FIELDS/MACHINE_OWNED_FIELDS).domains/comet-classic/classic-validate-command.tsfor schema validation and the known field set.test/domains/comet-classic/comet-scripts.test.tsfor YAML examples and assertions.
Then run pnpm build to regenerate comet-runtime.mjs, otherwise the freshness
check in classic-runtime.test.ts will fail.
Comet has grown from a single /comet workflow bundle into a workflow + skill
authoring platform. When working on these commands, note:
comet dashboard: A local read-only browser dashboard. Frontend code lives indomains/dashboard/web/and is built separately viapnpm build:dashboard. The backenddomains/dashboard/server.tsexposes--jsonandGET /api/dashboard.comet eval: Repository-local evaluation, including profiles, manifests, HTML reports, token/cost attribution, pass@k/pass^k. Seedocs/operations/EVAL-USAGE.md.comet creator/comet publish: Main skill-authoring flow. Seedocs/operations/SKILL-CREATION.md.domains/bundle/*is their backend tooling.comet skill add|show|run|continue|check: Local skill package management. Code lives indomains/skill/.
When changing the behavior or output of these commands, update the
corresponding docs/operations/* document and the matching
test/domains/<domain>/ tests.
Detailed rules live in CLAUDE.md. Quick reference:
- Bilingual order: Write the Chinese version of skills / docs first
(
assets/skills-zh/,README-zh.md,CONTRIBUTING-zh.md,docs/operations/*-ZH.md), then sync the English version after user confirmation. For skill content changes, do not write the changelog entry until Chinese and English are fully in sync. - README restraint: After a feature update, do not pile every highlight
into the README. Necessary features should be referenced via
docs/. - Chinese terminology: Do not translate
gateas "门" (e.g. "压缩门" / "调试门" reads unnaturally). Translate by context as "协议" (protocol), "阶段" (phase), "检查" (check), or "阻塞点" (blocker). Modifyingproactive/activetranslates as "主动式". - Skill trigger phrasing: Chinese uses the unified
**立即执行:** 使用 Skill 工具加载 <skill-name> 技能。禁止跳过此步骤。and English uses the unified**Immediately execute:** Use the Skill tool to load the <skill-name> skill. Skipping this step is prohibited.. - Commit / GitHub conventions: Do not comment on or open PRs on GitHub
without explicit approval; do not append a
Co-Authored-Byline to commit messages.
CHANGELOG.md is written in English and records user-visible behavior
changes. See CLAUDE.md for the full categorization and the
"release-perspective check" rules. Quick reference:
- The version number must match
package.json. New version entries go at the top, and a PR may only be one version ahead ofmaster. - If the current branch already has a version entry ahead of
master, append to that same entry instead of adding a new running-tally version. - Group order:
Added → Changed → Fixed → Tests → Removed → Security. Each entry starts with- **Bold keyword**:. - Describe behavior changes and rationale, not implementation trivia.
- Before writing, run
git log <previous-tag>..HEAD --onelineto see the real diff; only write "what a user upgrading from the previous version would notice". - Do not include branch-internal review follow-ups, doc syncs, test refactors, or internal fixes in the changelog.
- For skill content changes, the changelog entry must wait until Chinese and English are fully in sync.
Template:
## What's Changed [x.y.z] - YYYY-MM-DD
### Added
- **Feature name**: Describe what changed and why.
### Changed
### Fixed
### Tests
### Removed
### Security### Tests is only used when the testing/evaluation capability itself is a
user-runnable release feature; ordinary regression tests, coverage backfill,
and test file migrations are not recorded in the changelog.
- Scan for API keys, secrets, tokens, and private keys before publishing.
- Keep
.npmignorealigned so source-only and local configuration files are not published to npm. - Keep
.gitignorecoverage for secrets, credentials, and IDE-specific files. - Validate user-provided change names against path traversal before using them in filesystem paths.
- In symlink install mode, skill installation must not replace a
skills/directory that contains files outside the managed manifest (see issue #159 in the0.4.0-beta.2entry ofCHANGELOG.md).