@dotbabel/dotbabelMaintained by @kaiohenricunha · Changelog · Security
Make an AI coding agent show its work.
Agents produce plausible output fast. The expensive failures come from the plausible-but-unverified kind: a fix for a bug nobody reproduced, an analysis citing a file that was never opened, a “done” that no test covers. dotbabel is the verification layer — a library of skills that force an agent to ground every claim, plus gates that check the result before it merges.
The skills encode the discipline. /ground-first refuses to propose an edit
until the relevant source has actually been read. /fix-with-evidence demands
a failing reproduction before a fix and a passing run after it.
/veracity-audit and /plan-grader grade work against what the code really
says. /security-review, /detect-flaky, and /validate-spec gate the
output. Cloud and IaC specialists (aws, gcp, azure, kubernetes,
terraform, crossplane) bring the same evidence-first posture to
infrastructure work.
How serious is that verification? Serious enough to replace your CI gate.
dotbabel local-attest runs your GitHub Actions matrix on your machine and,
on a clean pass, posts a SHA-pinned attestation that makes the remote
workflows skip themselves for that commit — one repo cut ~27 minutes of runner
time per push to zero. It is deliberately hard to fool: pinned to the exact
head SHA so the next push invalidates it, owner-authored comments only, a
refusal to attest when any leg was skipped or never launched, an audit log
that records failures as well as passes, and toolchain pins that fail the run
closed when your local Node or Go differs from CI’s. That is the standard the
rest of the toolkit is built to.
And it holds a floor under the code an agent writes. dotbabel quality
resolves one policy — complexity, changed-line coverage, duplication, dead code,
high-confidence security findings — and measures it with the tools your repo
already has: your Makefile targets, your package.json scripts, your
pyproject.toml config. It installs nothing, runs nothing outside an explicit
trust allowlist, and when it cannot measure something it says unsupported,
not_configured, or unavailable rather than quietly passing.
It also runs everywhere you work: one rule floor, fanned out to Claude Code, Codex, Gemini CLI, Antigravity CLI, OpenCode CLI, and Copilot CLI, with drift detection so the copies cannot silently disagree.
Who is this for?
| I am… | I want… | Start here |
|---|---|---|
| Agent user | Skills that make Claude ground, verify, and cite its work | Install as a plugin |
| Dotfile user | The toolkit — skills, commands, and CLAUDE.md in every Claude session | Clone & bootstrap |
| CI payer | To stop re-running checks I already verified locally | Local attestation |
| Quality owner | One enforceable quality floor across a mixed-language repo | Language-aware quality |
| Consumer | The CLI in my repo — bootstrap, doctor, drift detection, optional spec-gov gates | Install the CLI |
| Library user | Node API in my own tooling | docs/api-reference.md |
| Contributor | Dev workflow, local gates | CONTRIBUTING.md |
| What you want | How |
|---|---|
| Skills & subagents inside Claude Code, no clone | Install as a plugin — two slash commands |
Skills & commands library wired into ~/.claude/ |
Clone & bootstrap — 30 seconds, no npm required |
| Skip remote CI for commits you verified locally | Local attestation — npx dotbabel-local-attest --init |
| Governance CLI for your own repos (bootstrap + doctor + optional spec gates) | Install the CLI — see install section (Node ≥ 20 required) |
| One quality floor across every language in the repo | Language-aware quality — npx dotbabel-quality detect |
All five paths are independent. You can use one, some, or all of them.
Verification you can substitute for the remote run. local-attest needs one
file: a matrix of the checks CI runs. --init drafts it from your existing
workflows, so adoption is a command rather than an afternoon:
npx dotbabel-local-attest --init
It reads .github/workflows/*.yml, turns every run: step in a
pull-request-triggered job into a leg, groups legs into one lane per job (lanes
run concurrently, legs within a lane run in order), mirrors any paths: filter
as a when.changedPaths rule, and copies setup-node / setup-go versions
into toolchain pins. Anything it cannot translate — a marketplace action, a
service container, a job-level if: — becomes a TODO: comment inside the
generated file rather than a silent omission.
The draft is a starting point, not a gate. Read it against your workflows before you attest anything: a green attestation switches remote CI off, so a check missing from the matrix is enforced nowhere. Then:
npx dotbabel-local-attest --dry-run # run the matrix, print the comment, post nothing
npx dotbabel-local-attest # run it, post the attestation, push
Wire the gate into a workflow by skipping when a trusted attestation matches
the head SHA. The full contract — comment format, trust model, audit log, and
the branch-protection caveat — is in
skills/local-attest/references/operator-guide.md;
the config schema is in
skills/local-attest/references/config.md.
Once attestations are trustworthy, /merge-pr can reuse them instead of running
the suite a second time. That is opt-in (attestation.enforce in .dotbabel.json),
and dotbabel doctor checks it is configured coherently. See
docs/attestation.md.
One quality policy across a mixed-language repository, measured with the tools
the repo already has. Dotbabel discovers your Makefile targets, package.json
scripts, and pyproject.toml config — it never installs a checker.
dotbabel quality detect # what would run; executes nothing
dotbabel quality explain # resolved rules and provenance
dotbabel quality check --profile pr --base origin/main # the PR floor
dotbabel quality check --all --path src/api # one package, entirely
| Profile | Use | Default work |
|---|---|---|
fast |
Agent iteration | Changed format, syntax, types, lint, size, and available complexity |
pr |
Pull requests | fast, tests, coverage, security, duplication, and dead-code tools |
deep |
Scheduled audit | pr, configured mutation, race, and repository analyzers |
25 stable rule ids with shipped defaults — complexity 15, changed-line coverage
90%, mutation 85%, duplication 5%. Every one is overridable per repo, and
dotbabel quality explain shows whether a value came from the shipped policy,
your user file, or the project.
Exit 0 means no error verdict, 1 a policy failure, 2 a missing tool,
report, base, or trust. Exit 2 is not a pass — an unavailable measurement
is reported as unsupported, not_configured, or unavailable rather than
silently succeeding.
Local runs execute project-owned commands only for a repository in the exact-path
trust allowlist; CI passes --allow-project-commands for a single run, and it
never persists. Trust is not a sandbox — it is an explicit choice to run the
repository’s own commands.
Details: docs/quality.md · flags and JSON envelope: docs/cli-reference.md · copy-paste config and workflow: examples/quality/
The fastest path if you just want the skills and subagents inside Claude Code — no clone, no npm:
/plugin marketplace add kaiohenricunha/dotbabel
/plugin install dotbabel@dotbabel
That installs the skills library and the specialist subagents. The
local-attest CLI is a separate install (npx dotbabel-local-attest, above),
because it runs your test suite and pushes commits — that belongs behind an
explicit install, not a plugin that arrives with everything else.
Just want the skills library, commands, and a global CLAUDE.md? Three lines:
git clone https://github.com/kaiohenricunha/dotbabel.git ~/projects/dotbabel
cd ~/projects/dotbabel
./bootstrap.sh # symlinks commands/ + skills/ + CLAUDE.md into ~/.claude/
That’s it — the full skills and commands library is now available in every Claude Code session. To stay current:
./sync.sh pull # pull + re-bootstrap
./sync.sh push # secret-scan + commit + push
If you have the CLI installed, you can use it instead of the shell scripts:
dotbabel bootstrap # same as ./bootstrap.sh
dotbabel sync pull # same as ./sync.sh pull
dotbabel sync push # same as ./sync.sh push
dotbabel sync status # show installed vs latest version
Both bootstrap and sync support --source <path> (clone mode) or default
to the npm package installation (npm mode). Run dotbabel bootstrap --help
or dotbabel sync --help for full options.
The bootstrap wires the authored library into every Claude Code session:
skills/ provides reusable workflows and specialists. Skills can be invoked
directly with /skill-name and can also activate from natural-language
requests when their metadata matches.commands/ keeps the existing explicit slash-command prompt templates for
workflows such as /ground-first, /fix-with-evidence, and /pre-pr.agents/ provides specialized Claude Code subagents copied during bootstrap.CLAUDE.md provides the global rule floor for every session.Do not treat this README as the catalog. The source-of-truth inventory is
generated from artifact frontmatter under index/, checked in CI
with dotbabel index --check, and explained in
docs/taxonomy.md.
dotbabel list --type skill
dotbabel list --type command
dotbabel search handoff
dotbabel show handoff --type skill
dotbabel index --check
See CLAUDE.md for the global rules this installs.
After ./bootstrap.sh, open any repo in Claude Code and try:
# Understand existing code before touching it
/ground-first auth token refresh race condition
# → grounded analysis with file:line citations, no edits proposed
# Fix a reported bug with a full evidence loop
/fix-with-evidence 140
# → reproduces the issue, fixes it, verifies, opens a PR
# Check changed code against the resolved quality policy
/quality-review pr origin/main
# → explain + detect + check, then reviews the semantic risks tools cannot judge
# Get a deep AWS IAM review of this repo
/aws-specialist review IAM policies in the production account
# → structured review: least-privilege gaps, trust-policy findings, remediations
# Batch-triage all open Dependabot PRs
/dependabot-sweep
# → parallel subagents annotate each PR with risk level; safe bumps merged automatically
# Hand off mid-task context across CLIs or machines
/handoff <query> # local cross-agent: emit <handoff> block
/handoff push [<query>] [--tag] # upload to transport (scrubs secrets)
/handoff pull [<query>] # fetch and render on the other end
# <query> = short UUID, full UUID, 'latest', Claude customTitle, or Codex thread_name
These workflows are context-aware: they read your repo’s files, history, and CI state.
Want the governance CLI in your own repos — bootstrap, doctor, drift detection, programmatic validation, and optional spec-governance gates? Install it:
# One-liner (requires Node ≥ 20)
curl -fsSL https://raw.githubusercontent.com/kaiohenricunha/dotbabel/main/install.sh | bash
Or install manually:
# Global — use dotbabel anywhere
npm install -g @dotbabel/dotbabel
# Per-project — pin it to a repo (useful for CI)
npm install -D @dotbabel/dotbabel
The one-liner installs the package globally and runs dotbabel bootstrap to
wire ~/.claude/ automatically. To pin a version or skip the bootstrap step:
curl -fsSL https://raw.githubusercontent.com/kaiohenricunha/dotbabel/main/install.sh | DOTBABEL_VERSION=0.4.0 bash
curl -fsSL https://raw.githubusercontent.com/kaiohenricunha/dotbabel/main/install.sh | DOTBABEL_SKIP_BOOTSTRAP=1 bash
Then use the umbrella dispatcher or standalone bins interchangeably:
dotbabel bootstrap # set up (or refresh) ~/.claude/ — symlinks commands, skills, CLAUDE.md
dotbabel bootstrap --all # also force Copilot/Codex/Gemini instruction symlinks
dotbabel sync pull # pull latest dotbabel version and re-bootstrap
dotbabel sync push # secret-scan staged files, commit, and push (clone mode)
dotbabel sync status # show installed vs latest version / git status
dotbabel doctor # self-diagnostic: env, facts, manifest, specs, bootstrap
dotbabel doctor --install-hooks # install pre-commit freshness check for generated instructions
dotbabel validate-skills # verify skills manifest checksums + DAG
dotbabel validate-specs # audit spec contracts + dependency cycles
dotbabel check-spec-coverage # PR gate: protected paths must be spec-backed
dotbabel check-instruction-drift # detect stale CLAUDE.md / README entries
dotbabel check-instructions-fresh # verify generated cross-CLI instruction files are fresh
dotbabel check-instruction-parity # verify applicable headings are preserved per CLI
dotbabel detect-drift # flag commands diverged from origin/main 14+ days
dotbabel init # scaffold specs, hooks, manifest into a repo
dotbabel quality explain # show the resolved quality policy and provenance
dotbabel quality detect # inspect languages and tools without execution
dotbabel quality check --profile pr --base origin/main # run the PR quality floor
dotbabel quality check --all --path src/api # scope a run to one package
dotbabel quality baseline --profile pr --base origin/main # candidate legacy baseline
Every subcommand also works as a standalone bin — npx dotbabel-doctor,
npx dotbabel-validate-specs, etc. All support --help, --version,
--json, --verbose, --no-color.
Five-minute walkthrough: docs/quickstart.md. Quality policy and adapter guide: docs/quality.md. Flags and the JSON envelope: docs/cli-reference.md.
npx dotbabel-init --project-name my-project --project-type node
npx dotbabel-doctor # verify everything wired up
npx dotbabel-validate-specs # run first governance check
~/.config/dotbabel/local-rules.md)dotbabel bootstrap (npm CLI, 2.7.0+) generates ~/.claude/CLAUDE.md as a
real file containing the canonical dotbabel rule floor followed by a
marker-delimited overlay block. To layer your own personal rules on top
without forking dotbabel’s source, drop them into
~/.config/dotbabel/local-rules.md:
mkdir -p ~/.config/dotbabel
cat > ~/.config/dotbabel/local-rules.md <<'EOF'
## My personal rules
- Default to drafts when opening PRs.
- Always link the Linear ticket in the PR body.
EOF
dotbabel bootstrap # regenerates ~/.claude/CLAUDE.md with your overlay merged in
The overlay sits AFTER the canonical content (Claude Code’s top-to-bottom
read order means your rules trump dotbabel defaults). Future dotbabel
bootstrap and dotbabel sync runs preserve the overlay, regenerating the
merged file on every invocation. Direct edits to ~/.claude/CLAUDE.md are
backed up to ~/.claude/CLAUDE.md.bak-<timestamp> before regen — always
edit local-rules.md, not the generated file.
The shell-only ./bootstrap.sh quickstart still uses the legacy symlink
shape and does not support overlays. Install the npm package for overlay
support.
dotbabel bootstrap covers your user scope (~/.claude/, ~/.codex/,
~/.gemini/, ~/.config/opencode/). For per-repo artifacts — a project’s own CLAUDE.md,
.claude/commands/*.md, and .claude/skills/* — use project-sync to fan
them out to Codex (.codex/skills/), Gemini (.gemini/skills/), Antigravity
(.agents/skills/), OpenCode (.opencode/skills/), and Copilot (.github/prompts/*.prompt.md +
.github/instructions/*.instructions.md):
cd ~/projects/my-app
dotbabel project-init # one-time: writes .dotbabel.json and a starter CLAUDE.md
dotbabel project-sync --dry-run # preview planned actions
dotbabel project-sync # symlink everything in place
dotbabel check-project-sync # CI-safe drift check (read-only)
dotbabel check-project-sync --all # ...including CLIs you have not installed
The fan-out uses symlinks — your .claude/ tree stays the single source of
truth. A .dotbabel.json is optional; without one, project-sync uses
sensible defaults and treats the entire CLAUDE.md as the project rule
floor (or the slice between <!-- dotbabel:rule-floor:begin --> /
<!-- dotbabel:rule-floor:end --> markers when present).
gate_on_cli_presence (default true) skips a CLI’s symlink fan-out when its
binary is absent from PATH. check-project-sync honors the same setting, so
a machine without gemini installed does not report the un-synced Gemini tree
as drift; pass --all to either command to ignore the gate for one run.
Instruction files (AGENTS.md, GEMINI.md, .github/copilot-instructions.md)
are always written, never gated.
fan_out_layout (default per-cli) controls whether Codex and Gemini get
their own trees. Both read <dir>/SKILL.md, so shared writes one canonical
tree and points both at it, halving the entries git has to track:
per-cli shared
.codex/skills/<name>/SKILL.md .cli/skills/<name>/SKILL.md
.gemini/skills/<name>/SKILL.md .codex/skills -> ../.cli/skills
.gemini/skills -> ../.cli/skills
Switching an existing repo to shared backs the old trees up to
.codex/skills.bak-<timestamp> before replacing them, so nothing is lost —
delete the backups once you are satisfied. Copilot keeps its own
.github/prompts/ and .github/instructions/ shapes either way. If a CLI
turns out not to follow the redirect, set fan_out_layout back to per-cli.
cli_excluded keeps a command or skill off a CLI it cannot serve. Some
commands describe a Claude-only flow (headless Claude workers, Claude-specific
flags); list them per CLI and the fan-out skips them there, removing a link it
wrote earlier. Names are command basenames without .md or skill ids. Under
fan_out_layout: "shared" an exclusion for codex or gemini applies to
both, since they read one tree, and the sync warns when the two lists differ.
Point your editor at the config schema for autocomplete and validation:
{
"$schema": "https://dotbabel.dev/schemas/dotbabel.config.schema.json",
"fan_out": ["codex", "gemini", "antigravity", "opencode", "copilot"],
"fan_out_layout": "per-cli",
"gate_on_cli_presence": true,
"cli_excluded": { "codex": ["review-prs-parallel"], "gemini": ["review-prs-parallel"] }
}
An unknown name in fan_out or a key in cli_excluded fails with
CONFIG_UNKNOWN_CLI rather than being skipped, so a typo cannot silently cost
you a CLI’s wiring; an unknown fan_out_layout fails with
CONFIG_UNKNOWN_LAYOUT, and a malformed cli_excluded with
CONFIG_INVALID_EXCLUSION.
import {
createHarnessContext,
validateSpecs,
validateManifest,
checkSpecCoverage,
checkInstructionDrift,
scaffoldHarness,
ValidationError,
ERROR_CODES,
EXIT_CODES,
} from "@dotbabel/dotbabel";
const ctx = createHarnessContext(); // resolves repo root via git
const { ok, errors } = validateSpecs(ctx); // errors are ValidationError instances
if (!ok) {
for (const err of errors) {
if (err.code === ERROR_CODES.SPEC_STATUS_INVALID) {
// programmatic reaction to a specific failure class
}
}
process.exit(EXIT_CODES.VALIDATION);
}
Full contract: docs/api-reference.md.
Every bin honors --help, --version, --json, --verbose, --no-color and exits with:
| Code | Name | Meaning |
|---|---|---|
| 0 | OK | Success |
| 1 | VALIDATION | Rule failure (expected failure mode) |
| 2 | ENV | Misconfigured environment |
| 64 | USAGE | Bad CLI invocation (matches BSD sysexits.h EX_USAGE) |
Per-bin details: docs/cli-reference.md.
Each row links to its ADR (see docs/adr/):
| Decision | ADR |
|---|---|
| Monorepo dual-persona layout | 0001 |
| No TypeScript; JSDoc + zero runtime deps | 0002 |
Structured ValidationError contract |
0012 |
Exit-code convention {0,1,2,64} |
0013 |
| CLI ✓/✗/⚠ output format | 0014 |
Shell-level hardening (SEC-1..4, OPS-1..2) is enforced at
plugins/dotbabel/scripts/validate-settings.sh;
its 12-case behavioral suite at
plugins/dotbabel/tests/test_validate_settings.sh
pins every contract.
| docs/index.md | Nav map with persona-tailored entry points |
| docs/quickstart.md | Install → scaffold → first green validator |
| docs/cli-reference.md | Every bin, flag, exit code, --json schema |
| docs/api-reference.md | Node API surface |
| docs/architecture.md | Layer diagram + PR-time sequence |
| docs/quality.md | Rule catalog, adapters, baselines, trust, CI |
| docs/troubleshooting.md | Error-code → remediation index |
| docs/upgrade-guide.md | 0.1 → 0.2 migration, forking |
| docs/personas.md | Who reads which file |
| CONTRIBUTING.md | Dev workflow + local gates |
| SECURITY.md | Private vulnerability disclosure |
| CHANGELOG.md | Keep-a-Changelog history |
MIT — see LICENSE.