guard-kit
Permission-friction reduction for coding-agent sessions. A PreToolUse guard
decides at call time — block with a corrective message, steer to a
better form, rewrite to the allowlisted spelling, auto-allow the
provably safe, or log the fall-through — a scanner ranks what the allowlist
failed to cover, a curation tool finds the redundant local overrides, and a
close-stage triage step makes the whole loop a habit.
Why: a command no allowlist entry matches is decided out of band — by interrupting a human, or by a model asked to judge the call — and that decision is invisible to the agent either way, so it cannot notice, count, or fix the friction it causes. The cost is paid per call, out of the operator’s attention or out of latency and tokens, and compounds as the command surface grows. The kit closes the loop by making the fall-through set — exactly the commands nothing granted — the one thing that is recorded. See SPEC.md for the framework, the generic ruleset, what the steering buys, and the triage criterion.
Unlike the other kits, guard-kit registers no gates: its surfaces are
hooks and advisory bin/ tools, so nothing joins gates.list. It follows
gate-sdk’s layout and smoke conventions without depending on its registry.
Install
Vendor the kit beside gate-sdk, then:
-
Copy the guard framework into your gates dir (default
scripts/):cp guard-kit/templates/bash-guard.sh scripts/bash-guard.sh cp guard-kit/templates/wakeup-guard.sh scripts/wakeup-guard.sh # optional cp guard-kit/templates/guard-config.sh scripts/guard-config.shAdd your project’s block/steer/allow rules in
bash-guard.sh’s marked consumer-rules section (before the generic ruleset). The generic ruleset and hook primitives stay in the vendoredlib/guard.sh. -
Wire the hooks — merge
templates/settings-hooks.jsoninto.claude/settings.json(thebash-guardonPreToolUse(Bash); the optionalwakeup-guardonScheduleWakeup|CronCreate; and an optional third block showing the path-shaped shape a consumer kit’s own guard registers under — lifecycle-kit’sworkflow-state-guardis the shipped instance). -
Gitignore the two scratch logs (
.workflow/prompt-friction.log,.workflow/wakeup-attempts.log) — both are per-iteration, cleared at close. -
Splice
templates/close-triage.mdinto your close-stage skill (it fills lifecycle-kit’stooling-friction triageplaceholder).
Configuration follows the established kit pattern — override any knob in
guard-config.sh (log paths, settings paths, GUARD_KIT_RO_SCRIPTS,
GUARD_KIT_RO_BINS, GUARD_KIT_SCRATCH_DIRS, GUARD_KIT_BREADTH_PROBES,
GUARD_KIT_BREADTH_DECLARED); defaults are this repo’s layout, and the probe set
and the declaration map both default to empty because their contents are your
project’s vocabulary, not the kit’s.
Use
bash guard-kit/bin/scan-prompts.sh # rank what nothing granted, filtered by the allowlist
bash guard-kit/bin/scan-prompts.sh --count # <patterns>/<occurrences> token (drift KPI)
bash guard-kit/bin/compare-settings-allow.sh # local-overlay entries a committed glob already grants, and those a probe proves too broad
Test
bash guard-kit/bin/run-guard-tests.sh # decision-table over the generic ruleset