Configuration Overview¶
nah works out of the box with zero config. When you want to tune it, configuration lives in two places.
File locations¶
| Scope | Path | Purpose |
|---|---|---|
| Global | ~/.config/nah/config.yaml |
Your personal preferences, trusted paths, LLM setup |
| Project | .nah.yaml (in git root) |
Per-project tightening, custom classifications |
nah config path # show both paths
nah config show # display effective merged config
Global vs project scope¶
Global config can do everything -- override policies, add trusted paths, configure LLM, modify safety lists.
Project config can only tighten security. It can:
- Add classify entries (commands → action types)
- Escalate action policies (e.g.,
git_write: ask) - Tighten content pattern policies (ask → block)
It cannot:
- Relax any policy (lowering strictness is rejected)
- Modify safety lists (
known_registries,exec_sinks, etc.) - Set
trusted_paths,allow_paths, ordb_targets - Configure the LLM layer
- Change the taxonomy profile
This is the supply-chain safety model: a malicious repo's .nah.yaml can't weaken your protections.
Merge rules¶
When both configs exist, nah merges them with these rules:
| Field | Merge behavior |
|---|---|
profile |
Global only |
actions |
Tighten-only (project can only escalate strictness) |
classify |
Kept separate (global = Phase 1, project = Phase 3 lookup) |
sensitive_paths |
Tighten-only |
sensitive_basenames |
Global only |
content_patterns |
Project can tighten policies only (add/suppress global-only) |
credential_patterns |
Global only |
known_registries |
Global only |
exec_sinks |
Global only |
decode_commands |
Global only |
trusted_paths |
Global only |
allow_paths |
Global only |
db_targets |
Global only |
llm |
Global only |
log |
Global only |
Quick reference — all config keys¶
| Key | Type | Scope | Docs |
|---|---|---|---|
profile |
full / minimal / none |
global | Profiles |
classify |
dict of type → prefix list | both* | Custom taxonomy |
actions |
dict of type → policy | both | Action types |
sensitive_paths_default |
ask / block |
both* | Sensitive paths |
sensitive_paths |
dict of path → policy | both | Sensitive paths |
allow_paths |
dict of path → project list | global | Sensitive paths |
trusted_paths |
list of paths | global | Sensitive paths |
known_registries |
list or dict (add/remove) | global | Safety lists |
exec_sinks |
list or dict (add/remove) | global | Safety lists |
sensitive_basenames |
dict of name → policy | global | Safety lists |
decode_commands |
list or dict (add/remove) | global | Safety lists |
content_patterns |
dict (add/suppress) | both | Content inspection |
credential_patterns |
dict (add/suppress) | global | Content inspection |
llm |
dict (providers, max_decision, eligible, context_chars) |
global | LLM layer |
db_targets |
list of database/schema dicts | global | Database targets |
log |
dict (verbosity, etc.) | global | CLI reference |
* classify entries in global config are Phase 1 (checked first, can override built-in). Project entries are Phase 3 (checked after built-in, can only add new commands). sensitive_paths_default in project config can only tighten (ask → block).
YAML format¶
Both config files use standard YAML. If nah detects comments in a file before a CLI write operation (nah allow, nah classify, etc.), it warns you that comments will be removed and asks for confirmation.
Optional dependency: pip install nah[config] installs pyyaml. Without it, config files are ignored (a stderr warning is printed).