@guardsmith/cli
v0.6.1
Published
GuardSmith CLI — the guard binary (init / lint / sync / new / explain)
Downloads
686
Readme
GuardSmith treats AI development standards (CLAUDE.md, agents, skills) the way ESLint
treats code style: a distributable config plus a linter. This package provides the CLI.
Requires Node.js 20+.
Install
npx @guardsmith/cli <command> # one-off
# or
pnpm add -D @guardsmith/cli # per project, then: pnpm guard <command>Quick start
# New project — scaffold from the standards master
# (CLAUDE.md, agents, skills, docs, Docker-based local CI, design spec)
npx @guardsmith/cli new my-project
# Existing project — generate the policy file only
npx @guardsmith/cli init
# Verify (exit 1 = violations found: uninitialized templates,
# broken contract headings, leaked credentials, drift, ...)
npx @guardsmith/cli lint
# Show what a standards update would change, then take it in
npx @guardsmith/cli bump v0.7.1 --dry-run # dry-run for the new tag (exit 1 = something conflicts)
npx @guardsmith/cli bump v0.7.1 # apply + move the extends tags and the vars file
# Dry-run at the tag the policy currently pins (does not predict a bump)
npx @guardsmith/cli sync
# Existing project with no guardsmith.vars.yaml yet — generate it first
npx @guardsmith/cli sync --init-vars
# Explain a rule / show versions
npx @guardsmith/cli explain claude-md/thin-diff
npx @guardsmith/cli version| Command | Key flags |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| guard new <dir> | — |
| guard init | — |
| guard lint | --root, --policy, --format console\|sarif\|json, --out, --no-cache, --no-gitignore |
| guard sync | --root, --policy, --write, --no-cache, --no-gitignore, --conflict-markers, --init-vars |
| guard bump <tag> | --root, --policy, --repo <owner>/<repo>, --dry-run, --no-cache, --no-gitignore, --conflict-markers |
| guard explain <rule-id> | — |
| guard version | — |
guard sync and guard bump take a standards release in as a three-way merge: the
master at the tag the project sits on is the base, the master at the new tag is theirs, and
your repository is ours, so project-specific wording survives. A file where your edits and
the standards change overlap is reported as a conflict and left untouched
(--conflict-markers writes it out with <<<<<<< / ||||||| / ======= / >>>>>>>
markers instead). Both exit 0 with no conflicts, 1 when anything conflicts — guard bump
then writes nothing at all, not even the policy — and 2 on a run-time error.
guard bump <tag> --dry-run prints the same plan, the predicted conflicts and the policy
lines it would rewrite, writes nothing, and returns the exit code the real run would. It is
the only way to see a new tag's diff up front: guard sync without --write is a
dry-run against the tag the policy currently pins. --dry-run cannot be combined with
--conflict-markers.
The merge reads the project's placeholder substitutions from guardsmith.vars.yaml
(project root, committed, no secrets). guard new writes the skeleton; an existing project
generates one with guard sync --init-vars. A policy with no drift3 rule keeps the old
section-level guard sync --write behaviour.
Checks operate on files that could be committed: .gitignore (nested files included)
is honoured by default and .git/ is always excluded, so secret-scan never reports a
value inside .claude/settings.local.json, and file-exists treats a .gitignore'd path
as missing. The policy's ignore globs are excluded on top of that, and excluded trees are
pruned during traversal rather than filtered afterwards. --no-gitignore restores the full
scan when you want to audit ignored files.
guard lint also measures how much context a CLAUDE.md keeps resident: import-budget
adds up the entry file plus every file reached through its @path imports and always
reports one info (resident context: N files, X chars (≈Y tokens, rough estimate) plus a
per-file breakdown; the token figure is a rough chars / 4 estimate). Nothing outside the
scan root is read. Write package names as `@scope/pkg` — @ is an import anywhere in
the file, so a bare @scope/pkg is read as one and reported as unresolved import.
The policy schema is strict: unknown keys under with or on a rule are parse errors
naming the offending path, not silently dropped fields.
After guard new, open the project with Claude Code — the bundled init-project skill
interviews you and concretizes the templates. guard lint passes once initialization
is genuinely complete.
Policy in a nutshell
# guard.policy.yaml
version: 1
target: claude-code
extends:
- github:novexar/guardsmith//presets/[email protected] # tag pinning is mandatory
# Projects with a frontend also add:
# - github:novexar/guardsmith//presets/[email protected]
ignore: [] # globs excluded from every scan (concatenated across extends layers)
rules: [] # add or override (redefining an id overrides it)
exemptions: [] # time-boxed waivers: reason + approved_by + expires requiredextends composes OSS baseline → private organization overlay → per-project policy.
Private repositories are fetched with the GITHUB_TOKEN environment variable, so
organization-specific rules never leave your GitHub. Expired exemptions surface as
errors — nothing is waived silently forever.
CI enforcement
Add one line to your workflow using the GuardSmith Lint Action:
- uses: novexar/[email protected]Violating PRs fail with a summary comment and a SARIF report. Air-gapped environments can
run entirely from the self-contained bundle attached to
GitHub Releases (source: release /
node guard.mjs) — no npm registry access required.
Documentation
- Getting started & concepts: https://github.com/novexar/Guardsmith
- 3-layer policy design: https://github.com/novexar/Guardsmith/blob/main/docs/LAYERING.md
- Upgrading standards (per-release checklist): https://github.com/novexar/Guardsmith/tree/main/docs/migration
License
Apache-2.0
Third-party licenses: dependencies carry their own licenses via npm; the offline release
bundle ships with a THIRD-PARTY-NOTICES.md.
