Thanks for wanting to make crag better. This document is short on purpose — crag is a small tool, and the contribution process should match.
git clone https://github.com/WhitehatD/crag.git
cd crag
node test/all.js # all tests should pass (539)
node bin/crag.js help # verify CLI worksNo dependencies, no build step, no linter setup. It's just Node.js.
- New compile targets — adding support for another AI coding tool (Tabnine, JetBrains, Void Editor, Kilo, etc.). See
src/compile/for existing targets as templates. - New workspace types — adding detection for another monorepo tool. See
src/workspace/detect.js. - Bug fixes — anything that reduces false positives in
crag diff, handles new edge cases in workspace detection, or fixes Windows/Unix portability issues. - Test coverage — more tests are always welcome, especially for edge cases.
- Documentation — README clarifications, new workflow examples, troubleshooting entries.
- New dependencies. crag is intentionally zero-dependency. Stick to Node.js built-ins.
- Breaking changes to
governance.mdformat. The v2 annotations are additive; the v1 format must keep working. - New runtime requirements. crag should work on Node 18+ without polyfills.
- Vendor-specific features that don't generalize (e.g., "add a flag specific to my company's internal CI").
- Open an issue first for non-trivial changes. A quick discussion prevents wasted work.
- Fork the repo.
- Create a feature branch:
git checkout -b feat/my-improvement - Make your change. Keep the commit focused — one logical change per PR.
- Run the gates: everything in
.claude/governance.mdmust pass.node bin/crag.js check node bin/crag.js diff node test/all.js
- Add tests for any new logic (put them in
test/<module>.test.js). - Commit with a conventional commit message:
feat: add X,fix: Y,docs: Z, etc. - Open a pull request against
master. Explain what and why in the PR description.
- Node.js CommonJS (
require/module.exports) — not ESM. - Zero dependencies in
package.json. - 2-space indentation.
- Semicolons.
- Single quotes for strings, backticks for template literals.
- 'use strict'; at the top of every file.
- Comment why, not what. If the code isn't self-explanatory, refactor rather than comment.
- Error handling at boundaries. Internal modules can assume inputs are valid; public APIs and file I/O must be defensive.
All tests live in test/. Each file exports nothing — it runs assertions directly and updates process.exitCode on failure.
To run just one file:
node test/parse.test.jsTo run everything:
node test/all.jsbin/crag.js— thin dispatcher, requiressrc/cli.js.src/cli.js— command router + auto-update check.src/commands/— one file per command. Keep commands thin; push logic intosrc/governance/,src/workspace/, etc.src/governance/— the v2 parser and gate-to-shell conversion.src/workspace/— workspace detection, member enumeration, hierarchy merge.src/compile/— one file per compile target. UseatomicWrite()fromsrc/compile/atomic-write.jsfor all file writes.src/update/— version check, skill sync, integrity (hash/frontmatter).src/skills/— universal skills shipped as markdown. Read at runtime by the AI agent. Any change requires bumpingversion:in the frontmatter and recomputingsource_hash:.
Releases are fully automated. The maintainer workflow is:
# 1. Make your changes, add to CHANGELOG.md under ## [Unreleased]
# 2. When ready to release, bump the version:
npm run release:patch # 0.2.1 → 0.2.2 (bug fixes)
npm run release:minor # 0.2.1 → 0.3.0 (new features)
npm run release:major # 0.2.1 → 1.0.0 (breaking changes)
# 3. Review the diff (package.json + CHANGELOG.md updated)
git diff
# 4. Commit and push — everything else is automatic:
git add -A
git commit -m "release: v0.2.2"
git pushThat's it. The release.yml workflow will:
- Run all gates + 539 tests + compile-all smoke test
- Detect that the version in
package.jsonis new - Publish to npm with SLSA provenance
- Create the
v0.2.2git tag - Create a GitHub release with notes extracted from
CHANGELOG.md - Verify the package appears on the registry
If the version hasn't changed, the workflow runs tests and exits without publishing. This means every regular commit still goes through CI but only version-bump commits trigger a release.
Requirements for the maintainer:
NPM_TOKENsecret must be set in GitHub repo settings (granular access token with "bypass 2FA" enabled for@whitehatd/crag)GITHUB_TOKENis provided automatically- No manual
npm publishorgh release createcommands needed
Troubleshooting:
- If the workflow fails on the publish step, the package version may already exist. Bump again.
- If the release fails after publish (rare), the npm publish stands — manually create the GitHub release from the CHANGELOG entry.
- To force a re-publish of an existing version (e.g. to fix a corrupt release), use the
workflow_dispatchtrigger withforce_publish=true. Note: npm does not allow overwriting published versions, so you'll need a version bump anyway.
Whenever src/skills/*.md content changes on master, a separate workflow (sync-hashes.yml) automatically recomputes the source_hash frontmatter and commits the update as the github-actions bot with [skip ci]. Contributors don't need to manage hashes manually — just edit the skill content and push.
If you find a security issue, do not open a public issue. Email alexc.forbusiness@gmail.com instead.
By contributing, you agree that your contributions will be licensed under the MIT license.