# Use NeuralMind in a CMMC CUI enclave

> Goal: run NeuralMind on source code that is Controlled Unclassified
> Information (CUI), inside an environment assessed against CMMC 2.0 Level 2,
> with each MCP role tied to a real OS account, the index refused on any
> disk that isn't encrypted, and *(v4.16.0+)* the whole posture switched on and
> checked as one setting, `security.profile: cui`.

CMMC assesses a defense contractor's environment, not a tool, so NeuralMind
itself has nothing to be assessed against. What matters is what NeuralMind does inside
your assessment scope and what evidence it leaves. This walkthrough sets up the
controls added in v4.7.0, turns them on together with the CUI profile added in
v4.16.0, and shows what an assessor can check.

**Existing use case it improves:** [offline and regulated
environments](offline-regulated.md) and [air-gapped installs](air-gapped.md),
which keep NeuralMind's own traffic off the network but, before v4.7.0, still
trusted whatever role an MCP call declared.

**New use case it opens:** teams building for the defense industrial base,
such as compliance tooling or contractors' internal apps, can use an AI
coding agent with persistent codebase memory on CUI code. The MCP layer
enforces per-account roles, and the index can't land on an unencrypted laptop
disk.

## 1. Decide whether your code is CUI

Most application source code isn't CUI, even when the application handles CUI.
If yours isn't, NeuralMind is a developer tool outside the enclave and nothing
here is required. If it is, the index, synapse store, decision memory, audit
log and command-output cache that NeuralMind derives from it are CUI too, and
the steps below apply.

## 2. Install without network egress

Follow the [air-gapped walkthrough](air-gapped.md): install from a wheelhouse
and pre-seed the embedding model with `NEURALMIND_ONNX_MODEL_DIR`. Leave
`NEURALMIND_LLM_SEED` unset; it is the only path that sends text (README and
architecture-doc prose, never code) to a third party.

## 3. Write the policy

Have an administrator create `neuralmind-backend.yaml` in the project root,
owned by them and writable only by them:

```yaml
security:
  profile: cui            # v4.16.0+
  users:
    alice: builder
    bob: reader
  roles:
    builder: [neuralmind_wakeup, neuralmind_query, neuralmind_search, neuralmind_skeleton, neuralmind_build]
    reader: [neuralmind_wakeup, neuralmind_query, neuralmind_search, neuralmind_skeleton]
```

```bash
chmod 644 neuralmind-backend.yaml
```

`profile: cui` switches on every setting below as one unit. Each is enforced at
run time, and a refusal is written to the audit log:

- **`identity: os`.** Each MCP caller's identity comes from the OS account the
  server runs as. Over the stdio transport that is the developer who launched
  the agent. The `role` a call declares is ignored and logged as a claim.
  `users` maps OS accounts to roles; an account that isn't listed is refused,
  unless you add `default_role`. `roles` without `admin` means no account can
  reach admin-only tools.
- **`require_encrypted_storage: true`.** NeuralMind refuses to build, query,
  serve MCP tools or run hooks until it has verified FileVault, BitLocker or
  dm-crypt/LUKS on every volume holding the project's state. *(v4.18.0+)* The
  copies it writes under your home directory (Claude Code's synapse export,
  the global query log) are written only where the same check passes.
  `neuralmind data-locations .` lists every place the project's data lives, for
  an assessor or a deletion.
- **Local listeners only.** `neuralmind serve` refuses to start on an address
  other than loopback, or with `--no-auth`. A shared `neuralmind daemon`
  started that way refuses this project's requests, while still serving
  projects without the profile. Reach the graph view from another machine
  through an SSH tunnel.
- **No LLM documentation seeding.** It is refused even with
  `NEURALMIND_LLM_SEED=1` set, so no README or architecture prose goes to a
  model provider.

The profile can't be loosened from the same file. `profile: cui` with
`identity: declared` or `require_encrypted_storage: false` is a contradiction,
and so is a misspelled or blank profile. NeuralMind then refuses every MCP call
and holds the project to the profile until the file is fixed. Before v4.16.0,
set `identity: os` and `require_encrypted_storage: true` yourself; there was no
listener or seeding refusal.

Keep the MCP server on stdio. `identity: os` refuses the HTTP transport,
because over HTTP the server's account isn't the caller's.

*(v4.17.1+)* The roles apply off the MCP path too. Each route of the shared
`neuralmind daemon` needs the role its matching MCP tool needs, and
`neuralmind build` and `validate --write` need `neuralmind_build`, so the
account the git hooks run as must hold a role that allows it (`builder` above
does). Other CLI commands run with the account's own file permissions.

### Make the profile machine-wide

*(v4.17.1+)* Whoever owns the project directory can delete
`neuralmind-backend.yaml`, even though the administrator owns the file. Before
v4.17.1 that switched every setting above off. Put the profile where a
developer can't reach it:

```bash
sudo mkdir -p /etc/neuralmind
printf 'security:\n  profile: cui\n' | sudo tee /etc/neuralmind/policy.yaml
sudo chmod 755 /etc/neuralmind && sudo chmod 644 /etc/neuralmind/policy.yaml
```

On Windows, write `C:\ProgramData\NeuralMind\policy.yaml` from an
administrator prompt and remove users' write access:
`icacls "C:\ProgramData\NeuralMind" /inheritance:r /grant:r "Administrators:(OI)(CI)F" "SYSTEM:(OI)(CI)F" "Users:(OI)(CI)RX"`.

The machine policy applies to every project on the machine and only tightens:
each setting takes the stricter of its value and the project's. With the
project file deleted, the profile stays on, and with no `users` left every MCP
call is refused. It can hold only `profile`, `identity` and
`require_encrypted_storage`; roles stay in the project file, so it grants
nothing. One that doesn't parse, names another key, holds an invalid value (*v4.17.2+* including a `require_encrypted_storage` that isn't true or false), or on POSIX isn't owned and
writable only by root holds every project to the strictest settings. See
[the security guide](../SECURITY-GUIDE.md#the-machine-policy).

## 4. Check it on each machine

```bash
neuralmind doctor .
```

```
  [ ok ] Security policy: identity: os; account 'alice' gets role 'builder'; machine policy /etc/neuralmind/policy.yaml applies
  [ ok ] Storage encryption: /dev/mapper/luks-root: dm-crypt layer present; OS FIPS mode on
  [ ok ] Security profile: profile: cui (identity: os, encrypted storage required, servers on loopback with their token only, LLM seeding refused); OS FIPS mode on; machine policy /etc/neuralmind/policy.yaml applies
```

The **Security profile** line *(v4.16.0+)* checks what the project file can't
enforce on its own:

- **OS FIPS mode off:** a failure. CMMC SC.L2-3.13.11 asks for FIPS-validated
  cryptography protecting CUI. Without the profile this is only a warning on
  the storage line.
- **FIPS mode that can't be read** (macOS has no FIPS mode switch; FileVault
  uses Apple corecrypto, listed in Apple's CMVP certificates): a warning to
  confirm by hand.
- **`NEURALMIND_LLM_SEED=1` left set:** a warning. The profile refuses it, but
  it shouldn't be in the enclave's environment.
- **Embedding model not on disk** (the default turbovec backend): a warning,
  because the first build would download it. Pre-seed it as in step 2.
- **A running daemon listening beyond loopback or without its token:** a
  warning, because it refuses this project.

`doctor` exits 1 on any failure, so the check can gate a provisioning script. NeuralMind's own hash calls work with the FIPS
mode on *(v4.13.0+; before that, `neuralmind ingest` crashed there)*. A
group-writable policy file is a warning too, since anyone in the group could
change roles.

For the stricter, all-or-nothing check *(v4.19.0+)*, run the
[SP 800-53 hardening baseline](../compliance/SP800-53-HARDENING.md):

```bash
neuralmind hardening . --json > hardening-$(hostname)-$(date +%F).json
```

Its 17 rules check the profile, the machine policy, FIPS mode, encryption and
the daemon as above, and add the checkpoint key, anchor and schedule,
forwarding with nothing waiting, permissions on `neuralmind-backend.yaml` and
`.neuralmind/`, and whether `cryptography`'s OpenSSL runs in FIPS mode. The
embedding-model and `NEURALMIND_LLM_SEED` warnings stay `doctor`'s. It
exits 1 when any rule fails, so the same provisioning script can gate on it,
and the JSON names the SP 800-53 controls each rule supports. SP 800-171
derives from SP 800-53, so it serves as evidence here too.

## 5. What an assessor can look at

Everything lands in `.neuralmind/audit_events.jsonl`, hash-chained:

- a `storage_check` event per process, with the volume, method, FIPS mode and
  verdict;
- an `mcp_call` or `mcp_call_denied` event per tool call, whose actor is the OS
  account, with `claimed_role` / `claimed_actor` whenever a call declared
  something else;
- `mcp_call_denied` with `reason: identity` for any call the server couldn't
  attribute;
- *(v4.16.0+)* a `profile_refused` event, status `denied`, each time the CUI
  profile stops something: `target` names what it stopped (`serve`, `daemon`
  or `llm_seed`) and `details.reason` says why.

- *(v4.16.0+)* an `audit_checkpoint` event each time a checkpoint is taken.

`neuralmind audit verify` walks the hash chain. On its own it detects a changed
or removed record in the middle of the log, but not removal of the newest
records or a rewritten chain. *(v4.16.0+)* Signed, anchored checkpoints close
both gaps (AU.L2-3.3.8). As the administrator:

```bash
neuralmind audit keygen ~/.neuralmind-audit/checkpoint.pem   # admin account only
```

Add the printed key, and an anchor directory only the administrator can
write, to the policy from step 3:

```yaml
security:
  profile: cui
  audit_checkpoint_key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
  audit_anchor_dir: /var/lib/neuralmind-anchor
```

Then take a checkpoint daily from the administrator's crontab:

```bash
neuralmind audit checkpoint /srv/app --key ~/.neuralmind-audit/checkpoint.pem
```

`audit verify` now fails when records a checkpoint covers were removed from the
end, when the chain was recomputed, or when a checkpoint is forged or missing.
The anchored copy survives the developer deleting the local one. Records
written since the newest checkpoint are covered by the chain alone, so keep the
interval short, and keep forwarding the log to your SIEM. `doctor` warns under
the profile when the key or anchor directory isn't set, or the newest
checkpoint is more than a week old.

*(v4.18.0+)* A record that can't be written (a full disk, a permissions error)
fails `doctor`'s *Audit log writes* check under the profile. If the failure
can't be noted either, the call itself is refused, since nothing would show the
gap. Fix the cause, then record the gap in the log itself, so the log and your
SIEM show what's missing:

```bash
neuralmind audit record-gap /srv/app
```

*(v4.19.0+)* Forward the log to your SIEM as it is written, and get an alert
when a record can't be written (AU.L2-3.3.4, 3.3.5). Under the profile the
target must be on this machine, since NeuralMind doesn't encrypt the
connection, so point it at the local syslog daemon and let that forward over
TLS (the [Security Guide](../SECURITY-GUIDE.md#forwarding-to-syslog-v4190)
has an rsyslog example):

```yaml
security:
  profile: cui
  audit_syslog: /dev/log
```

Then send the existing history once; from then on each record goes out as it
is written, and `doctor` warns if any are left waiting:

```bash
neuralmind audit forward /srv/app
```

For the practice-by-practice mapping, with what NeuralMind provides and what
stays yours, see the [CMMC 2.0 table in the Compliance
Summary](../COMPLIANCE-SUMMARY.md).

## 6. What stays outside NeuralMind

- **The encryption itself.** NeuralMind verifies it; FileVault, BitLocker or
  LUKS (with the OS FIPS mode on) provides it.
- **OS accounts and their authentication.** `identity: os` is only as good as
  the logins behind it, and anyone who can run commands as an account can read
  that account's `.neuralmind/` directly.
- **Your agent's model provider.** NeuralMind hands code slices to the coding
  agent, and the agent sends them to its model. If that code is CUI, the
  provider must meet DFARS 252.204-7012 (FedRAMP Moderate or equivalent).
  NeuralMind reduces how much code goes out; it can't make a provider
  eligible.

## Related

- [v4.16.0 release notes](../releases/RELEASE_NOTES_v4.16.0.md): the CUI profile
- [v4.7.0 release notes](../releases/RELEASE_NOTES_v4.7.0.md)
- [NIST: what applies, where it stands, what's next](../compliance/NIST.md)
- [Security Guide — Access Control](../SECURITY-GUIDE.md#access-control)
- [Security settings reference](../wiki/CLI-Reference.md)
