Welcome! This project is designed to be easy to contribute to. Whether you're adding a rule pack, building an adapter, or improving the engine — here's how to get started.
git clone https://github.com/nimser/guiderails.git
cd guiderails
npm installnpm test # Run all tests
npm test:watch # Watch mode
npm run build # Compile to dist/
npm run typecheck # TypeScript check only
npm run lint # Run oxlint (type-aware)
npm run format # Format code with oxfmt
npm run check # Full gate: lint + format + typecheckA pre-commit hook (installed via the code-style skill) runs format then check before every commit. Bypass with git commit --no-verify if needed — but the CI workflow will still enforce the gate.
The easiest way to contribute is writing a YAML rule pack. No TypeScript required. Define matchers and actions in a .yaml file and submit it.
- Format & schema: Rule Pack Guide
- Examples: Built-in packs in
src/packs/ - How matching works: How Matching Works — understand the three detection layers before writing patterns
Ideas for new packs: AWS SSM/Secrets Manager, Terraform, HashiCorp Vault, database CLIs, Azure CLI, GCP CLI. Pick whichever your team uses most — likelihood of encounter matters more than completeness.
Sharing your rule packs: Once accepted, community rule packs are curated in the companion repo awesome-guiderails. We'll feature useful packs there for others to discover.
Want to add support for another AI coding harness? Adapters are thin shims:
- Normalize the harness event →
ToolCallContext - Call
engine.evaluate()from the public API - Translate the result back to the harness's native mechanism
The first-party Pi and Claude Code adapters show the pattern. Adapters for other harnesses (OpenCode, Codex, Aider, …) are community-owned and live outside this repo, built against the stable interface (ADR-009).
Changes to the matcher registry, resolver, action fallback chain, or type system require more context. Start with the Architecture Decisions (read in order), then open an issue to discuss your approach before diving in.
- TypeScript strict mode, no
any, no!non-null assertions - Named exports only — no default exports
- JSDoc on public package exports
- Format with oxfmt (single quotes, no semicolons, 100 char print width)
- Colocate tests:
file.test.tsnext tofile.ts
The linter and formatter will catch most issues automatically.
- Keep PRs focused — one feature or fix per PR
- Tests required for new logic
- Reference the relevant spec in
openspec/changes/if applicable - Mention whether you used an AI coding assistant (see PR template)
For architectural reasoning, see the docs in this repo:
- Getting Started — contributor gateway, key vocabulary, architecture at a glance
- Architecture Decisions (ADRs) — the why behind core design choices (read in order 1–5)
- How Matching Works — layer-by-layer matching with real command examples
- Rule Pack Guide — complete YAML format spec and action types
The source of truth is the code and tests. If a doc and the code disagree, trust the code — and please open an issue so we can fix the doc.
Releases are cut from main and published by .github/workflows/release.yml whenever a v* tag is pushed. The process is deterministic — every step is either a required file edit or a CI gate that fails the release if skipped.
- Move the relevant entries from
## [Unreleased]inCHANGELOG.mdunder a new## [X.Y.Z] - YYYY-MM-DDheading. Leave## [Unreleased]in place, empty, for the next round of changes. - Add the compare link for the new version at the bottom of
CHANGELOG.mdand update the[Unreleased]link to diff from the new tag. - Bump
versioninpackage.jsontoX.Y.Z. - Commit, then tag:
git tag vX.Y.Zand push both the commit and the tag. - CI takes over: it verifies the tag matches
package.json, verifiesCHANGELOG.mdhas a matching entry (failing closed if either is missing), publishes to npm with provenance, and creates the GitHub Release with notes extracted straight from thatCHANGELOG.mdentry.
A missing or mismatched changelog entry fails the release before anything is published — there is no path to a tagged release without changelog notes.
See SECURITY.md.