Security Model
NIIA is not one universal permission. Memory reads, MCP calls, terminal writes, OS observations, OS actions, and remote transport cross different gates and keep different owners. Documents NIIA 0.9.41.Built-ins and external packages
Built-in command names do not share a namespace with external packages:@scope/name form and pass NIIA’s package trust check before their executable is launched. Their output is wrapped with a source boundary so an agent can distinguish package text from NIIA’s own response.
Trusting an external package authorizes that package to run with the user’s OS permissions. It is not a sandbox. Do not trust a package from an unknown source.
Signed content trust
niia trust verifies the OpenCLIs trust-domain registry, whose responses are signed with Ed25519. This content-source trust surface is separate from the local external-package allowlist.
Authentication and secret ownership
MCP fails closed
key=value and explicit structured key:=JSON. Remote REST accepts scalar query arguments only.
The following conditions return a non-zero shell exit:
- MCP
isError - JSON-RPC or transport failure
- persistent-session failure
- explicit quota denial
- authentication denial
- remote REST failure
--json, an MCP isError payload remains on stdout before the non-zero exit so automation gets both evidence and failure status.
The supported NIIA server registration is niia mcp. The retired standalone rust-niia-mcp binary is not the current public boundary.
Terminal health and assertions
A rendered terminal frame can outlive the process that produced it. NIIA checks health before treating a session as drivable:Work-entry discipline is advisory
niia gauge, finish, and audit-entry record and report a session contract;
they do not become an authorization system. The user’s explicit rung always
wins. A [CONSENT] overlay on destructive or live-surface language is a
reminder to obtain owner confirmation in the active conversation, not a token
that grants the operation. Fan-out is proposal-only.
finish writes a close witness even when it re-presents unmet work, and
audit-entry never blocks. Hook audit is silent so a SessionEnd/Stop hook does
not inject text into the conversation. Witness files can contain task text,
repository paths, provider brand, transcript path, and event history; they
remain local under .niia/session-order/ or the cwd-hashed home witness path
unless the user explicitly transfers them.
Hook-internal errors also cannot turn the steering layer into a prompt gate.
gauge --hook, gauge --session-start, and audit-entry --hook retain exit
zero, report the error on stderr, and append it to ~/.niia/hook-error.log for
doctor to surface. Only a session id delivered by hook stdin owns the atomic
current pointer; CLI --session and isolated verification runs cannot seize
the live session’s close target.
niia doctor does not walk or rewrite indexed corpora. It reads timestamps and
a bounded log tail. To verify witness-directory writability, it briefly creates
and removes .doctor-probe; that ephemeral probe is its only write.
OS grants
NIIA separates observation and control:niia observe is rejected; passing a write through niia control still requires the correct grant.
Target handles and stale-state defense
targets creates an AX + OCR interaction map. control act can bind the action to the observed snapshot, reject a stale target, reveal an off-screen element, report the planned write with --dry-run, and verify the result after actuation.
This is safer than assuming that coordinates or labels still refer to the same screen state.
Remote execution is deliberately narrow
exec surface accepts exact diagnostics only: now, status, and --version. Arbitrary argv is rejected before alias resolution or child execution.
Use relay operations for terminal work after reachability is proven. File copy uses one exact Headless WebRTC session. Cleanup prints a target-local plan rather than widening gateway execution into a general shell.
Remote updates require scope and a device gate
openclis.update-plan.v1 and does not stop Headless,
install software, or require the mutation gate. Application requires exact tool
names or --all plus the target device’s upgrade gate. openclis and
openclis-vault are rejected because their keychain approval must be renewed
interactively on that machine. The receiver restarts only selected affected
runtime, and plan, child, restart, protocol, or timeout failures return non-zero.
Legacy niia remote upgrade <machine> updates NIIA only.
Skill drift protection
niia setup does not silently overwrite locally evolved skills and agents.
diffreports embedded-versus-installed state.adoptrecords a baseline without writing installed content.exportstages evolved material for deliberate back-porting.- destructive replacement requires an explicit force choice.