Core concepts
Effects and coverage
nah lowers calls into typed invocation, filesystem, Git, network, and system-state effects. Observation resolves cwd, roots, paths, and environment.
full coverage preserves every guard-relevant visible input, without claiming
to understand opaque programs. Unresolved arguments, code, or fields are partial.
Bash pipelines, control flow, subshells, and redirects become stages and data-flow edges. Unresolved shell state makes coverage partial.
Visible source stays a code-execution effect. Python and JavaScript/TypeScript
use owned HIRs and bounded interpreters without execution. PowerShell and cmd
use static tokenizers; IPython handles magics. TypeScript/TSX ignore
reviewed type-only syntax, following JavaScript semantics without type-checking
or the TypeScript compiler. Other languages use narrow detectors.
Profiles own only proven Node, Deno, Bun, OpenClaw QuickJS, or Prime current-cell APIs. Rebinding or visible mutation removes ownership; hidden state is unknown. Generic JavaScript owns none.
Exact child argv/cwd are nested; missing or non-directory cwd prevents the child.
Unawaited JavaScript applies state only through its first await.
Deno.Command reads options and cwd when consumed.
Only proven Bash lowers fully. sh is a portable subset;
dialect-sensitive state and redirects stay partial. powershell, pwsh, and
cmd share reviewed typed effects. Other syntax, custom shells, Bun's $,
and bun exec stay partial; sinks vanish only after a proven throw.
Per source, the public ActionStream (custom guards, dry-run JSON, records) admits
64 modeled language calls; overflow makes coverage partial. Built-ins retain a
separate 256-call, 4,096-flow projection to block later danger.
Fail-closed records these bounds as language-call-limit or
language-safety-limit analysis refusals.
Command-like arguments to unknown programs trigger analysis refusal; reviewed
subcommand programs are exempt if their first argument is a static verb that
cannot run a command (no leading options).
Verdicts and failures
block— an active guard or structural self-protection found definite danger.delegate— nothing blocked; the runtime keeps control.
Evaluation failure is diagnostic, not a third verdict. By default it adds no
finding. --fail-closed blocks explicit failures/refusals, not ordinary
uncertainty. See nah docs security.
nah never approves. Delegation returns control to the runtime's permission or execution behavior; nah is neither an approval UI nor a sandbox.
Guards
A guard blocks a narrow danger such as remote content flowing into execution, destructive Git, or sensitive-path access. Guards compose by union: any may block, and none may approve.
An activated custom guard answers block or abstain. Abstain is no finding,
not approval. Failure or invalid output adds a typed failure only.
Definite evidence may block a partial stream; uncertainty alone never blocks.
Run nah docs guards for the catalog and tested examples.
Trust and activation
User guards require activation. Project guards require trust plus activation; nah does not read manifests before trust. Activation pins the manifest, executable, and data. Changed or missing bytes do not run and add a failure.
Before trust, .nah/project.toml may enable built-ins but cannot disable guards
or execute code. Agents may edit inert proposals; a human performs trust and
activation out of band. nah blocks understood intercepted attempts to cross
that boundary or disable active wiring.
nah nap starts a 10-minute, user-global maintenance window: plain nap pauses
self-protection; --all pauses every non-permanent layer. Nap-state protection
remains. See nah docs configuration and nah docs security.
Audit records
Live decisions attempt a redacted audit append; failure does not change the
verdict. Records name the runtime (unknown for nah decide). nah why <id>
explains one; nah log lists recent decisions, --blocked lists blocks, and
--json emits JSON Lines.