Skip to content

guard: /guard:exempt skill to manage exempt_skills interactively #174

Description

@studykit

Description

Add a guard:exempt skill plus an exempt CLI subcommand so the user manages the
exempt_skills list (introduced in #172) interactively, instead of hand-editing
.claude/guard.local.json.

Flow: the skill lists the skills available in the current session, uses
AskUserQuestion for the user to choose which to exempt, and — once the user confirms
— records the selection through the exempt CLI (guard_hook.py exempt set …, run via
Bash). If the user already named skills in their message, it skips the question and
records directly.

Changes (plugins/guard/):

  • New skill skills/exempt/SKILL.md (model-invocable) — drives list →
    AskUserQuestion → record → relay.
  • New exempt CLI subcommand (cmd_exempt): list / set / add / remove /
    clear. Edits ONLY the exempt_skills key — never enabled / mode / state — so
    it can narrow the judge's coverage but cannot disable guard or touch the approval
    gate. Preserves every other config key; normalizes names (leading / stripped,
    lowercased, plugin namespace kept). Project dir from CLAUDE_PROJECT_DIR, else cwd.
  • _CONTROL_CMD_RE now includes exempt, so a typed /guard:exempt turn is skipped
    by the approval classifier (UserPromptSubmit) and by the Stop judge.
  • Version 0.2.0 → 0.3.0; docs updated (AGENTS.md, dev/design.md, README.md).

Context

Follow-up to #172, which added the exempt_skills config but left it to be
hand-edited. The committer is a script (not the Write/Edit tool) on purpose:
guard.local.json stays blocked from the file-editing tools (_is_guard_owned), so
the exempt CLI invoked via Bash is the only supported writer for exempt_skills.
The model can therefore manage that one key, but still cannot self-arm approval or
disable the judge.

Acceptance Criteria

  • CLI verified: list / add (normalizes leading / + case) / dedupe / remove /
    set (replace) / clear behave correctly, and the result is read back by
    _exempt_skills.
  • Other config keys preserved — verified: with a config of model/effort/enabled/
    mode, exempt add kept all four and appended exempt_skills.
  • Live e2e (Claude Code v2.1.197, acceptEdits): /guard:exempt deep-research → the
    skill ran exempt list then exempt set deep-research; .claude/guard.local.json
    updated to exempt_skills: ["deep-research"]. Traces: exempt list, then
    exempt set (n=1, changed=true).
  • python3 -c "import ast; ast.parse(...)" passes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    taskWorkflow implementation task

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions