claude-home/development/permission-manager-classifier-development.md
Cal Corum b192b3ca47
All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 5s
docs: sync KB — claude-plugins-marketplace, permission-manager-classifier-development
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:23:00 -05:00

4.7 KiB

title description type domain tags
Writing Classifiers for permission-manager (agent-toolkit) Guide to adding new command classifiers to the St0nefish/agent-toolkit permission-manager plugin for Claude Code, covering project structure, conventions, testing, and PR workflow. guide development
claude-code
permissions
agent-toolkit
bash
classifier

Writing Classifiers for permission-manager

Overview

The permission-manager@agent-toolkit plugin (St0nefish/agent-toolkit) provides a cmd-gate PreToolUse hook that classifies Bash commands before execution. Classifiers are bash scripts in plugins-claude/permission-manager/scripts/classifiers/ that decide whether commands should be auto-allowed, require user approval, or be denied.

Project Structure

plugins-claude/permission-manager/
  scripts/
    cmd-gate.sh              # Hook entry point
    lib-classify.sh          # Classification framework + dispatcher
    classifiers/
      cargo.sh               # cargo/rust
      docker.sh              # docker/compose
      find.sh                # find (deny -delete/-exec rm)
      git.sh                 # git (with protected branch logic)
      gh.sh                  # GitHub CLI
      gradle.sh              # gradle/gradlew
      jvm-tools.sh           # java/mvn
      npm.sh                 # npm/node/pnpm/yarn/npx
      pip.sh                 # pip/python/poetry/pyenv
      read-only-tools.sh     # cat, ls, grep, jq, ps, etc.
      tea.sh                 # Gitea CLI
      uv.sh                  # uv/uvx (added 2026-03-18)
tests/permission-manager/
  test-classify.sh           # Main test harness (618+ tests)

Classification Decisions

Three possible outcomes:

  • allow — auto-approve, no prompt (read-only or safe local operations)
  • ask — prompt user for approval (destructive, remote, or elevated operations)
  • deny — block the command (e.g., find -delete)
  • passthroughreturn 0 without calling allow/ask/deny; defers to Claude Code's built-in permission system

Classifier Conventions

File Header

# shellcheck shell=bash
# shellcheck source=../lib-classify.sh

Function Naming

  • Entry point: check_<tool>() (e.g., check_uv, check_docker)
  • Subcommand extractor: extract_<tool>_subcommand() (for tools with global flags)

Entry Guard Pattern

Simple tools (cargo, npm, pip) use awk + case:

local first_token
first_token=$(echo "$command" | awk '{print $1}')
case "$first_token" in
  uv) ;;
  *) return 0 ;;
esac

Complex tools (docker, git) use perl guard:

echo "$command" | perl -ne '$f=1,last if /^\s*docker(\s|$)/; END{exit !$f}' || return 0

Reason Message Style

  • Read-only: "<tool> <subcmd> is read-only"
  • Local ops: "<tool> <subcmd> is a local build/dev operation"
  • Ask: "<tool> <subcmd> modifies <what>"
  • Deny: "<tool> <subcmd> is not allowed"

Classification Philosophy (from existing classifiers)

Category Decision Examples
Read-only inspection allow git status, docker ps, pip list
Local build/install allow npm install, pip install, cargo build
Global tool install ask cargo install, uv tool install
Package uninstall ask pip uninstall, uv pip uninstall
Publish/deploy ask npm publish, cargo publish, uv publish
Execute arbitrary packages passthrough npx, uvx, uv run --with
Destructive operations deny find -delete

Wiring a New Classifier

In lib-classify.sh, add to classify_single_command():

check_<tool>
[[ "$CLASSIFY_MATCHED" -eq 1 ]] && return 0

Place it logically near related classifiers (e.g., check_uv after check_pip).

Testing

Test Format

run_test_both <expected> "<command>" ["label"]

run_test_both runs the test in both Claude and Copilot modes. Expected values: allow, ask, deny, none (passthrough).

Test Section Structure

# ===== ALLOW: <tool> read-only =====
echo "── <tool> read-only ──"
run_test_both allow "<command>"

# ===== ALLOW: <tool> local build/dev =====
echo "── <tool> local build/dev ──"
...

Running Tests

bash tests/permission-manager/test-classify.sh           # Full suite
bash tests/permission-manager/test-classify.sh uv        # Filter by keyword

PR Workflow

  1. Fork St0nefish/agent-toolkit on GitHub
  2. Branch from master (not main)
  3. Add classifier, wire it, update tests
  4. Run full test suite — zero regressions required
  5. PR via gh pr create --repo St0nefish/agent-toolkit --base master

Reference PR