All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 5s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.7 KiB
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 |
|
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)- passthrough —
return 0without 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
- Fork
St0nefish/agent-toolkiton GitHub - Branch from
master(notmain) - Add classifier, wire it, update tests
- Run full test suite — zero regressions required
- PR via
gh pr create --repo St0nefish/agent-toolkit --base master
Reference PR
- PR #38: feat: add uv/uvx classifier — full uv/uvx classifier with 102 tests, submitted 2026-03-18