Quick Start

Get crag running in under 60 seconds. Zero dependencies, zero config.

Install

npm install -g @whitehatd/crag

Or run without installing:

npx @whitehatd/crag

1. Analyze your project

cd your-project
crag analyze

Reads your package.json, CI workflows, Makefiles, and 25+ stack signals. Writes .claude/governance.md with your real gates.

2. Compile to every AI tool

crag compile --target all

Emits 12 files: AGENTS.md, .cursor/rules/governance.mdc, GEMINI.md, .github/copilot-instructions.md, GitHub Actions workflow, Husky hook, and more.

3. Check for drift

crag audit

Compares governance against reality: stale configs, phantom gates, CI extras. Fix drift before your agents inherit it.

One-shot mode

crag

Running crag with no arguments auto-detects the project and runs analyze + compile in one shot.

Demo

crag demo

Self-contained proof-of-value that creates a synthetic project, analyzes it, compiles all 12 targets, checks for drift, and verifies SHA determinism. Takes ~3 seconds, no config required.

Zero dependencies. crag ships with nothing but Node built-ins. No supply chain risk. Works on Node 18+. Installs in under a second.

Commands

Every subcommand, every flag. Unknown flags are rejected with exit code 1 and a typo suggestion.

Core

CommandDescription
cragAuto-detect project, run analyze + compile in one shot
crag analyzeGenerate .claude/governance.md from the filesystem
crag compile --target <t>Compile governance to a specific target (or all)
crag auditDrift report: stale configs, outdated rules, missing targets
crag diffCompare governance against codebase reality
crag doctorDeep diagnostic: governance integrity, drift, hook validity
crag demoSelf-contained proof-of-value run (~3s)

Infrastructure

CommandDescription
crag initInteractive interview (requires Claude Code CLI)
crag checkVerify infrastructure file presence
crag hook installInstall pre-commit hook (auto-recompile on governance change)
crag hook uninstallRemove crag-installed hook
crag hook statusCheck hook installation status
crag upgradeUpdate universal skills to latest version
crag workspaceInspect detected workspace
crag installInstall agent globally for /crag-project

Cloud

CommandDescription
crag loginAuthenticate via GitHub OAuth
crag login --statusCheck auth state
crag login --logoutClear saved credentials
crag sync --pushPush governance to cloud
crag sync --pullPull governance from cloud
crag sync --statusShow sync status

Flags

FlagCommandsDescription
--dry-runanalyze, compile, autoPreview without writing files
--jsonaudit, demo, doctor, check, workspaceMachine-readable JSON output
--workspaceanalyze, upgrade, doctorOperate on all workspace members
--forceupgrade, hook install, syncForce overwrite
--fixauditAuto-recompile stale targets
--verbosecompilePrint byte sizes of each target
--mergeanalyzeMerge with existing governance
--drift-gatehook installBlock commits if drift detected
--target <t>compileSpecify compile target

Exit codes

CodeMeaning
0Success
1User error (missing governance, invalid flag, drift)
2Internal error (permission denied, disk full)

Governance Format

The one file you maintain. Everything else is generated. Target length: 20–30 lines.

Minimal example

# Governance — example-app

## Identity
- Project: example-app

## Gates (run in order, stop on failure)
### Lint
- npx eslint . --max-warnings 0
- npx tsc --noEmit

### Test
- npm run test

### Build
- cargo build --release

## Branch Strategy
- Trunk-based, conventional commits

## Security
- No hardcoded secrets or API keys

Path-scoped sections

### Frontend (path: web/)
- npx biome check .
- npm run build

Gates in this section run with cwd = web/. Used for monorepos where different directories have different build systems.

Conditional sections

### TypeScript (if: tsconfig.json)
- npx tsc --noEmit

Section is skipped if the condition file doesn’t exist. Makes governance portable across configurations.

Gate classifications

ClassificationBehavior on failure
[MANDATORY] (default)Stop execution
[OPTIONAL]Print warning, continue
[ADVISORY]Log result, always proceed
### Test
- npm run test                  # [MANDATORY]
- npm run test:slow             # [OPTIONAL]
- npm run test:experimental     # [ADVISORY]

Inheritance (monorepo)

## Gates (inherit: root)
### Backend
- cargo test
- cargo clippy -- -D warnings

Merges root governance gates first, then appends member gates. One source of truth for security/branch policy, per-service test commands live with each service.

Parser security

All annotation path values are validated. Rejected patterns:

256 KB content cap prevents ReDoS. Truncation cuts at the last section boundary.

Compile Targets

crag compile --target all writes all 12 files atomically. Partial failures leave prior state intact.

Target reference

TargetOutputConsumer
agents-mdAGENTS.mdCodex, Aider, Factory (60K+ repos)
cursor.cursor/rules/governance.mdcCursor
geminiGEMINI.mdGemini, Gemini CLI
copilot.github/copilot-instructions.mdGitHub Copilot
cline.clinerulesCline (VS Code)
continue.continuerulesContinue.dev
windsurf.windsurf/rules/governance.mdWindsurf Cascade
zed.rulesZed
amazonq.amazonq/rules/governance.mdAmazon Q Developer
github.github/workflows/gates.ymlGitHub Actions
husky.husky/pre-commitHusky
pre-commit.pre-commit-config.yamlpre-commit.com

Refusal behavior

github, husky, and pre-commit targets refuse to emit when governance has zero gates — these produce broken artifacts in that state. Doc-only targets always work.

Atomicity

All compilers write through atomic-write.js: crypto-random temp file, then rename. A crash during compile never leaves a half-written file.

Languages & Runtimes

crag analyze detects 25+ stacks and build systems. Framework detection only fires from runtime dependencies, not devDependencies.

Supported stacks

FamilyDetected fromGates emitted
Node / Deno / Bunpackage.json, deno.json, bunfig.tomlnpm test/lint/build, tsc, eslint, biome
Pythonpyproject.toml, setup.pypytest, ruff, mypy, black (per runner: uv/poetry/pdm/tox/nox)
RustCargo.tomlcargo test, clippy, fmt --check
Gogo.modgo test, go vet, golangci-lint
Java / Kotlinpom.xml, build.gradle(.kts)mvnw/gradlew test build, checkstyle, detekt
RubyGemfile, *.gemspecrspec, rake, rubocop, brakeman
PHPcomposer.jsonphpunit, pest, phpstan, psalm
.NET*.csproj, *.slndotnet test/build/format
SwiftPackage.swiftswift test/build, swiftlint
Elixirmix.exsmix test/format/credo/dialyzer
Haskell*.cabal, stack.yamlcabal/stack test/build, hlint
OCamldune-projectdune runtest/build
Zigbuild.zigzig build test, zig fmt
Crystalshard.ymlcrystal spec, shards build
Nim*.nimblenimble test/build
JuliaProject.toml (uuid)Pkg.test()
Dart / Flutterpubspec.yamlflutter/dart test/analyze
C / C++CMakeLists.txt, meson.buildcmake/meson/configure, ctest
Erlangrebar.configrebar3 eunit/ct/dialyzer
Lua*.rockspec(task-runner mined)
Infrastructure*.tf, Chart.yaml, Dockerfileterraform, tflint, helm lint, hadolint

False-positive guards

CI Systems

crag analyze parses gate commands from 11 CI formats. Output is normalized, deduplicated, and CI-agnostic.

Supported systems

SystemFile(s)
GitHub Actions.github/workflows/*.yml
GitLab CI.gitlab-ci.yml
CircleCI.circleci/config.yml
Travis CI.travis.yml
Azure Pipelinesazure-pipelines.yml
Buildkite.buildkite/pipeline.yml
Drone / Woodpecker.drone.yml, .woodpecker.yml
Bitbucket Pipelinesbitbucket-pipelines.yml
JenkinsJenkinsfile (declarative + scripted)
Cirrus CI.cirrus.yml
Ad-hoc shell CIci/*.sh, scripts/ci-*.sh

Normalization pipeline

  1. Canonicalize matrix tokens (${{ matrix.X }}<matrix>)
  2. Strip YAML-style wrapping quotes iteratively
  3. Decompose compound commands on && and ;
  4. Filter ~40 noise patterns (shell builtins, version probes, curl|bash)
  5. Deduplicate across workflows
  6. Cap at 8 canonical gates per CI system

Task runners

RunnerFile(s)Extraction
MakeMakefile, GNUmakefile.PHONY + column-0 targets matching gate names
TaskTaskfile.ymltasks: sub-keys
justjustfileRecipe names at column 0

Workspaces

crag detects 12 workspace types and supports multi-level governance hierarchies.

Supported types

pnpm · npm/yarn · Cargo · Go multi-module · Gradle · Maven · Nx · Turborepo · Bazel · git submodules · independent nested repos · subservices (polyglot microservices)

Commands

crag workspace              # human-readable
crag workspace --json       # machine-readable
crag analyze --workspace    # per-member governance

Multi-level governance

Root governance sets cross-cutting rules. Member governance adds stack-specific gates via inherit: root. Gates merge: root first, then member.

# Governance — backend/
## Gates (inherit: root)
### Backend
- cargo test
- cargo clippy -- -D warnings

Fixture filtering

crag analyze --workspace filters 40+ directory names (playground/, fixtures/, examples/, vendor/, etc.) so monorepos with fixture packages don’t generate noise.

Claude Code Integration

When crag init sets up a Claude Code project, each session runs a two-phase loop:

/pre-start-context       Discover project, load governance, cache runtimes
   ↓
   (the task)
   ↓
/post-start-validation   Run gates, auto-fix lint/format, commit

Pre-start context

Reads governance.md fresh every session. Classifies task intent (frontend / backend / infra / docs). Uses a content-hashed discovery cache to skip ~80% of redundant scans.

Post-start validation

Runs gates in order, stops on [MANDATORY] failure, retries mechanical errors up to twice with auto-fix.

Auto-fix rules

Error patternAction
Lint errors with auto-fix flagRe-run with --fix
Format errors (prettier, rustfmt, biome)Run formatter
Unused imports/variablesRemove them
Missing semicolons, trailing commasEdit inline
Failing testsNOT auto-fixable — escalate
Build errors from missing depsNOT auto-fixable — escalate

Session state (warm starts)

After a successful session, .claude/.session-state.json is written. If the next session is within 4 hours on the same branch+commit, it skips full discovery for near-zero-latency startup.

Cloud Sync

Back up governance to the cloud, sync across machines, and track drift from the dashboard.

Authentication

crag login           # Opens browser for GitHub OAuth
crag login --status  # Check auth state
crag login --logout  # Clear credentials

Credentials are saved to ~/.crag/credentials.json. The OAuth flow starts a local server, redirects through GitHub, and receives a JWT token.

Sync

crag sync --push     # Upload governance to cloud
crag sync --pull     # Download governance from cloud
crag sync            # Show sync status
crag sync --force    # Force overwrite on conflict

Push sends your governance.md content with a SHA-256 hash. Identical content is deduplicated. Pull writes the cloud version locally (with conflict detection).

Dashboard

The web dashboard at app.crag.sh shows all your synced repos, gate counts, drift status, and audit history. Sign in with the same GitHub account you use for crag login.

Ecosystem

URLPurpose
crag.shLanding page
app.crag.shDashboard
api.crag.shCloud API
crag.sh/statusService status
VS CodeSidebar, CodeLens, auto-recompile, diagnostics
crag.nvimCommands, statusline, diagnostics, auto-compile
npmCLI package

Release Pipeline

Every push to master runs the CI matrix (Ubuntu/macOS/Windows × Node 18/20/22). On green, the patch version auto-bumps and publishes to npm with SLSA provenance.

Workflow

push to master
   ├
   ├─▸ Test workflow
   │     ├─ Syntax check, crag help/version/check
   │     ├─ crag demo --json (determinism SHA)
   │     ├─ node test/all.js (589 tests)
   │     └─ crag compile --target all
   │
   └─▸ Release workflow
         ├─ Detect new version
         ├─ npm publish --provenance
         └─ git tag + GitHub release

Determinism enforcement

The crag demo step runs on all 9 matrix slots and SHA-verifies that two back-to-back crag analyze --dry-run invocations produce byte-identical output. If any runner diverges, the release is blocked.

Skipping a release

Add crag:skip-release on its own line in the commit body. Tests still run, but npm publish is skipped.

Manual release

npm run release:patch    # 0.3.1 → 0.3.2
npm run release:minor    # 0.3.1 → 0.4.0
npm run release:major    # 0.3.1 → 1.0.0
git add -A && git commit -m "release: v0.3.2" && git push