Custom Taxonomy¶
nah's classification is fully customizable. You can add commands to existing types, create new types, and control how the three-phase lookup works.
Adding commands to existing types¶
Use the classify config key to map command prefixes to action types:
# ~/.config/nah/config.yaml
classify:
container_destructive:
- "docker rm"
- "docker system prune"
- "kubectl delete"
filesystem_delete:
- "terraform destroy"
db_write:
- "psql -c DROP"
- "mysql -e DROP"
Each entry is a prefix — "docker rm" matches docker rm my-container, docker rm -f abc, etc.
CLI shortcut:
nah classify "docker rm" container_destructive
nah classify "terraform destroy" filesystem_delete
Creating custom action types¶
You can use any string as an action type — it doesn't have to be one of the 40 built-in types:
nah classify "terraform" infra_modify
nah deny infra_modify
nah will ask for confirmation since infra_modify is not a built-in type. Custom types default to ask policy.
Three-phase lookup¶
Understanding the lookup order is key to effective customization:
Phase 1: Global config (highest priority)¶
Your classify: entries in ~/.config/nah/config.yaml are checked first. They override everything — built-in tables and built-in classifier functions.
# Global config: this overrides the built-in curl flag classifier
classify:
network_outbound:
- curl # all curl commands → network_outbound, even curl -X POST
Warning
A single-token global entry like curl will shadow the built-in flag classifier that distinguishes curl (read) from curl -X POST (write). Use nah status to see shadow warnings.
Phase 2: Built-in classifiers¶
Built-in classifier functions handle commands where the action type depends on flags, wrappers, or inspectable execution context. Examples include find, sed, awk, tar, git, curl/wget/httpie, codex, codex companion, package execution wrappers, make, global installs, and script execution. These run after global config but before the built-in prefix tables.
Skipped entirely when profile: none.
Phase 3: Built-in + Project¶
Built-in prefix tables (from the selected profile) and project .nah.yaml entries are checked independently.
Project entries are Phase 3 — they can add new commands and can tighten overlapping built-in classifications, but cannot weaken a built-in classification unless global config explicitly sets trust_project_config: true.
Global vs project classify¶
| Aspect | Global | Project |
|---|---|---|
| Phase | 1 (first) | 3 (last) |
| Can override built-in | Yes | Only to tighten, unless trust_project_config: true |
| Can override built-in classifier functions | Yes | No |
| Use case | Personal preferences, org standards | Project-specific commands |
| Security | Trusted (your machine) | Untrusted (supply-chain risk) |
Example: project-specific rules¶
# .nah.yaml (in project root)
classify:
db_write:
- "psql -c ALTER"
- "psql -c DROP"
filesystem_delete:
- "make clean"
actions:
db_write: block # tighten: block all DB writes in this project
Project config can tighten actions (for example, escalate ask → block) but cannot relax them unless global config explicitly sets trust_project_config: true.
Checking your rules¶
# See all custom rules with shadow warnings
nah status
# See all types with override annotations
nah types
# Test a specific command
nah test "docker rm my-container"
nah status shows shadow warnings when your global classify entries override finer-grained built-in rules or classifier functions. Use nah forget <prefix> to remove a shadow.