> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monolex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Security Model

> NIIA 0.9.50 security boundaries — modes, trust, credentials, MCP failures, skill drift, OS grants, and restricted remote execution.

# 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.50.*

```text theme={null}
read local memory ───────────────────────────────▶ local data boundary
call an MCP tool ────────────────────────────────▶ service + auth boundary
write to a PTY ──────────────────────────────────▶ live-session health boundary
observe sensitive OS content ───────────────────▶ observe grant
change the OS ───────────────────────────────────▶ full control grant
reach another machine ──────────────────────────▶ identity + transport boundary
```

## Built-ins and external packages

Built-in command names do not share a namespace with external packages:

```bash theme={null}
niia search                   # built-in
niia @scope/tool <args>       # external package
```

External packages must use the `@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.

```bash theme={null}
niia trust
```

“Trusted documentation source” and “authorized local executable” are different claims.

## Authentication and secret ownership

```bash theme={null}
niia login
niia auth
niia logout
```

Authentication is owned by the current Monosystem/OpenCLIs credential path. NIIA forwards supported lifecycle operations without putting JWTs or policy tokens into child process arguments or ordinary environment variables.

An authenticated identity does not automatically grant OS control or authorize every remote operation.

## MCP fails closed

```bash theme={null}
niia mcp-run chrome-devtools _help
niia mcp-run chrome-devtools navigate_page url=https://monolex.ai
```

Local stdio MCP accepts scalar `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

With `--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:

```bash theme={null}
niia health --session <ID>
niia ask --session <ID> "run the test"
niia expect-screen --session <ID> "Finished" --max-wait 120
```

Failed health gates, missing guards, and assertion timeouts return non-zero unless the caller explicitly chooses a documented force path.

## Work-entry discipline is advisory

`niia mode auto|manual` owns only the three NIIA hook entries. It preserves
foreign hooks and all unrelated settings. `mode preset` changes the routing
table, not the user's authorization state; a custom table is backed up before
replacement.

`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.

A witness-less baseline audit reads the supplied transcript and working
directory but writes nothing to the witness store. Its report explicitly says
that the rung was assumed, and contract-only checks are skipped rather than
reported as false failures.

`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:

| Scope           | Allows                                                       | Does not imply                        |
| --------------- | ------------------------------------------------------------ | ------------------------------------- |
| Ungated read    | Safe system metadata such as window/process/permission state | Screen-content access or writes       |
| `observe` grant | Sensitive observations that expose user content              | OS mutation                           |
| `full` grant    | Sensitive observation plus authorized writes                 | Permanent access after expiry or lock |

```bash theme={null}
niia observe permissions --json
niia control unlock --scope observe --duration 30m
niia control unlock --scope full --duration 30m
niia control status
niia control lock all
```

Unlock requires human authentication. An AI cannot manufacture the OTP that opens the gate.

NIIA owns the grant. [Kernel CLI](/kernel-cli) owns the underlying OS operation. Passing a write command through `niia observe` is rejected; passing a write through `niia control` still requires the correct grant.

## Target handles and stale-state defense

```bash theme={null}
niia observe targets --app Safari --json
niia control act <target-id> --snapshot <snapshot-id> --dry-run --json
```

`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

```bash theme={null}
niia remote status list
niia remote exec <machine> now
niia remote exec <machine> status
niia remote exec <machine> -- --version
```

The daemon-direct `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

```bash theme={null}
niia daemon gate status --json
niia remote update <machine> niia --dry-run
niia daemon gate enable upgrade
niia remote update <machine> niia
```

The dry-run returns `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.

```bash theme={null}
niia setup --dry-run
niia skills diff --json --orphans
niia skills adopt
niia skills export --into ./niia-skills-export --dry-run
```

* `diff` reports embedded-versus-installed state.
* `adopt` records a baseline without writing installed content.
* `export` stages evolved material for deliberate back-porting.
* destructive replacement requires an explicit force choice.

## Browser ownership

[MonoSurf](/monosurf/index) operates inside the browser page through CDP. [Kernel CLI](/kernel-cli/reference) operates browser chrome, native dialogs, file pickers, Keychain/Face ID prompts, and other apps. NIIA supplies the authorization and orchestration layer when a workflow crosses between them.

See [complete commands](/niia-cli/commands) for every gated entrance.
