An execution substrate for autonomous AI agents, by Platten Industries. Agents don't get trust — they get a lease: a time-boxed, resource-clamped, kernel-enforced capability grant, with every action written to a hash-chained ledger that is unkeyed by default, and that says so on every host it runs on.
New here, or allergic to jargon? Start with The SPLAT Field Guide — the whole system explained in plain English.
Platten Industries is a one-person company, and this repository is that person's work. No second engineer has reviewed it, no auditor has assessed it, and most commits name an AI assistant as co-author because that is how they were written. None of that is load-bearing either way: what holds the claims up is machine-checked evidence — probe files, recorded runs pinned to the SHA-256 of the source that produced them, and tests that fail the build when prose and evidence disagree. Run the probes rather than trusting the voice. Every section below also names what it does not establish, and SUPPORTED_POLICY.md enumerates what a lease does not enforce at all.
The three answers that matter, before the long version below.
- A container's unit is a machine; a lease's unit is one task.
docker runand gVisor both hand the workload a box and let it do what it likes inside that box. A lease names this binary, this destination, this many seconds — and an exec or aconnect()outside it dies with-EPERMin the kernel, not in a wrapper the agent shares privilege with. Seccomp has the granularity but filters syscall numbers and arguments; it cannot say "this path, for this mission." - It runs on the machine the agent is already on, on a kernel you did not build. No cloud round trip, no shipping private source to someone else's infrastructure, no custom kernel and no fork — stock WSL2 with native BTF and
CONFIG_BPF_LSM=y. That is the deployment story hosted sandboxes structurally cannot tell. - Every claim here is bound to a probe you can run on your own host, and the build fails when the documentation oversells or undersells what the evidence shows. Claims in this README have been withdrawn after passing once — the status table names each one and why.
If a per-machine perimeter is what you need, use a container: it is simpler, older and better understood. The case for this project starts where "the machine" is too coarse a boundary.
Every mainstream approach to "safe" AI agent execution filters in user space — regex guards, prompt rules, wrapper APIs. All of it runs beside the agent, at the same privilege, where a hijacked agent can route around it. SPLAT's position is that containment belongs below the agent:
- On Windows, tool processes execute inside suspended-spawn Job Objects under a restricted token whose privileges are stripped, whose Administrators SID is marked deny-only, and whose integrity level is dropped to Medium — inside NTFS ACL jails with inheritance severed. The OS object manager enforces the boundary.
- On Linux, a BPF-LSM program is written to enforce a per-cgroup capability lease inside the kernel itself, so that an exec, file-open, or connect outside the lease dies with
-EPERMbefore it happens. This half is proven in operation on a stock WSL2 kernel — a recorded canary run shows all three hooks returning-EPERMwhile a permitted action succeeds (evidence) — and proven through the daemon: a tool executed bysplat-agentrunning as uid 0 was refused/etc/shadowby the kernel, and an allow-listed shell was refused its exec of an unleased binary. The last hop is Demonstrated end to end, as of 2026-11-05 and against the kernel program that ships (d5bb4cad), in the shipped SPLAT Guest (Debian 13, archivef238c13a): arun_commandsent tosplat-mcpby an MCP client travelled the C# bridge into that kernel and was refused there, while the command the lease permitted ran asuid=200000(evidence). See the status table and the substrate section below for what each run does and does not establish.
This is blast-radius containment, not detection. SPLAT does not claim to know when an agent has been prompt-injected; it guarantees that whatever the agent has become, it cannot act outside the lease it was granted. Prompt injection is not a bug with a patch; it is a structural property of putting untrusted text into the same channel as instructions. Every mitigation running at the agent's own privilege fails at the moment the agent is compromised. The only defenses that survive are the ones the agent cannot reach.
Technical evaluations of agent sandboxes tend to blur together into generic "isolation." In reality, three concrete architectural choices separate SPLAT from anything else on the market, in descending order of defensibility:
- The unit of containment is a task, not a box. Sandboxes-for-agents (E2B, Modal, Daytona, Fly) hand an agent an entire microVM where it can do whatever it wants inside the machine perimeter. Isolation is real, but the granularity is "the machine." Runtime security tools (Falco, Tetragon) do eBPF enforcement, but their unit is a long-lived cluster workload and their operator is a security team writing deployment-wide policy. SPLAT's unit is one mission: this model, this binary, this destination, for this many seconds. That is a capability grant, not a perimeter. Enforcing at that granularity requires a policy compiler, a dynamic lease lifecycle, and an in-kernel hook—most sandboxing efforts stop at the container.
- It runs on the box the agent is already on, on an unmodified kernel. This is SPLAT's sharpest commercial wedge. Every cloud sandbox requires shipping workloads and private corporate data to someone else's infrastructure—an absolute non-starter for the exact buyers who most need containment: health systems, defense, finance, and anyone with data that cannot leave the host. SPLAT contains an agent locally on stock WSL2 (
6.18.33.2-microsoft-standard-WSL2), native BTF, with no custom kernel build and no proprietary kernel fork. That is a deployment story cloud sandboxes structurally cannot tell. - The evidence discipline is itself the differentiator. In an early security category where 90% of claims are aspirational, SPLAT makes every claim load-bearing:
- Automated tests (
DocumentationDriftTests) fail the build in both directions: if the documentation undersells proven capability and if it oversells unproven capability. - Proof records are cryptographically pinned to the SHA-256 digest of the exact BPF source that generated them; a proof cannot outlive its code.
- When
src/splat-benchbenchmarked real containment overhead and retired the inherited<1msmarketing figure by recording 4.12 ms p50 / 9.88 ms p95, the project published the worse measured numbers rather than preserving marketing optics. Evaluators reading this codebase can trust that claims represent verified reality.
- Automated tests (
What is NOT differentiated: The Windows half. Win32 Job Objects, restricted tokens with USE_FOR_DENY_ONLY on the Administrators SID, Medium integrity drops, and NTFS ACL jails are essentially the Chromium sandbox architecture, well-trodden and proven in production browsers since 2008. It is competently implemented and asserted against whoami running inside the sandbox, but it is standard defense-in-depth, not the defensible moat. The moat is the Linux capability lease enforced by BPF-LSM on an unmodified kernel.
| Component | State |
|---|---|
| Windows containment substrate (Job Objects, restricted tokens, ACL jails) | Shipped — in the tested control plane |
| Governance plane (1:1:1 templates, DLP, egress firewall, audit ledger, semantic memory) | Built, unproven beyond the reviewed corpus — 1193 automated tests; current-definition live corpus coverage is incomplete after template changes (see verification below) |
| Zero-warning build gate | Enforced — src and tests compile with TreatWarningsAsErrors, so a cold solution build reports 0 warnings and 0 errors. No project is exempt: the console joined on 2026-09-18, when it moved to Windows App SDK 2.5.1 on .NET 10 and built without a warning, and WarningGateTests fails if an exemption appears |
splat-mcp — MCP server exposing governed execution to agent clients |
Implemented; the hop is Demonstrated end to end against the program that ships — stdio JSON-RPC, 12 tools. Re-recorded PASS on 2026-11-05 in the shipped SPLAT Guest (Debian 13, archive f238c13a) against kernel program d5bb4cad, which is the source in this tree (evidence): a client's command travelled to the kernel and was refused there, the permitted one ran as uid=200000, an undeclared exec and a connect outside the lease each returned -EPERM, and a destination outside the host's egress policy was refused before any lease was requested. This claim was withdrawn twice before, on 2026-09-20 and again on 2026-09-25, each time because the kernel program changed hours after a passing run - once by our own edit. A proof cannot outlive the program it tested, including when the change is ours and the same day; what is new is that the hash comparison now runs on a schedule instead of waiting to be noticed. packaging\reprove-substrate.ps1 restores it. run_command / run_code route to the Linux lease daemon and are therefore gated on the substrate below; the remaining ten run on the Windows control plane today |
| Linux kernel substrate (BPF-LSM lease enforcement) | Proven in isolation — canary recorded all three hooks returning -EPERM on stock WSL2 6.18.33.2, machine-checked, evidence committed |
Linux lease daemon (splat-agent) |
Enforcing, proven under root on 2026-11-05 — 90 checks against a root daemon on kernel 6.18.33.2, every one of them passing (docs/GUIDE-operator.md). This claim was withdrawn from 2026-09-20, when the kernel program gained a per-record clock, sequence number and drop counter and the recorded run stopped naming the program that ships; it was restored on 2026-10-01 against 496cc634, re-recorded on 2026-10-24 against 4d16bf66, and re-recorded on 2026-11-05 against d5bb4cad, which is the source in this tree, inside the shipped SPLAT Guest (Debian 13, archive f238c13a) rather than a development distro. Twelve of those checks are the lease's in-kernel deadline and reaper: with the daemon SIGKILLed and none running, the last permitted open began 3.0 µs before the deadline the kernel itself held, the kernel stamped its first refusal 10.0 µs after it, socket connect and datagram send past the deadline were likewise refused without a daemon, a restarted daemon drained the orphan cgroup, a live daemon's reaper ended an expired cgroup's processes within a tick, and every denial the kernel counted for the lease was drained, none dropped. Eleven of those checks are the pinned hooks surviving a kill -9: with no daemon listening, a process in the still-leased cgroup was refused an exec and a file it had been refused before, was allowed the one it had been allowed, and the same kernel objects were still there after a restart - with a foreign source hash, a partial pin set and a substituted map each refusing startup as controls. Eight more are the copy-on-write scratch layer: private writes, an unchanged host lowerdir, concurrent isolation and teardown. That run: recorded in evidence/daemon-probe.json and bound to the SHA-256 of the BPF source it exercised, so the proof cannot outlive the program it tested. All three hooks: a protected file the workload could read (/etc/hostname, 644 — a control run reads it, the leased run is denied, so only the lease accounts for the difference), an unleased second exec refused mid-sh, and egress held to one address and one port. Two concurrent leases proven not to lend each other permissions. The tool reports its lease's own uid (200000), not the daemon's root. IPv6 denied outright. An overrunning workload killed by the reaper 5.5s into a 60s sleep rather than merely unpoliced. A lease dimension the caller did not declare refused rather than defaulted. It proves it holds its token before a caller sends anything, and refuses the token sent in the clear. The daemon refuses to start at all unless enforcement is live |
| Host↔guest caller identity | Built for the managed service, gate passed 2026-10-21 — run as a separate Windows account, the managed service owns the distro, the daemon's token and the keyed ledger, and names each caller from that caller's own Windows token over a pipe that admits only the listed accounts. The gate run passed every step on one build. An admitted standard account ran a lease as nobody and met a live kernel connect denial. An account that is not admitted was refused. The ledger audit found every admission under the pipe caller, never the principal the request claimed. The service passed again after a restart and after a reinstall. It does not exclude an administrator. The stdio bridge on the operator's own distro still runs protocol 3 alone: a root-owned shared secret that never crosses the wire, proven by both ends on every frame, which does not stop another process running as the same Windows user. See the roadmap |
Launch-overhead benchmark (src/splat-bench) |
Recorded — the governed Windows path adds 4.12 ms p50 / 9.88 ms p95 over the same tool run bare, on Windows 10.0.26200, 50 alternating iterations (evidence). The locks account for ~2.4 ms; the rest is process creation both arms pay. This retired the inherited <1ms marketing figure, which the measurement missed by about 4× |
That table is the contract: nothing above it is aspirational, and nothing below it is hidden.
The 2026-10-20 bounded stress run kept unauthorized operations denied and restored the installed service, but lost 92.01% of native flood event details. Its containment checks passed; lossless telemetry under those loads did not.
flowchart TD
subgraph CP["Control plane — Windows (.NET 10)"]
UI["WinUI 3 operator console"] --> ENG["MissionExecutionEngine<br/>1:1:1 governed templates"]
MCP["splat-mcp (MCP server)<br/>12 governed tools"] --> ENG
ENG --> DLP["In-memory DLP sanitizer"]
DLP --> FW["Egress firewall<br/>strict FQDN allow-list"]
FW --> AI["Streaming reasoning cores<br/>Claude / Gemini, key-routed"]
ENG --> LED["SHA-256 chained audit ledger<br/>Merkle root verification"]
end
subgraph WIN["Windows substrate — shipped"]
JO["Win32 Job Objects<br/>hard CPU / RAM clamps, no breakaway"]
RT["Restricted token<br/>privileges stripped · admin SID deny-only<br/>Medium integrity"]
JAIL["NTFS ACL jails<br/>inheritance severed"]
JO --> RT --> JAIL
end
subgraph LNX["Linux substrate — proven under root (WSL2)"]
AGENT["splat-agent<br/>Rust / libbpf-rs / tokio"]
LSM["lease_lsm.bpf.c (BPF-LSM)<br/>bprm_check_security · file_open · socket_connect"]
EPERM["out-of-lease operation<br/>blocked with -EPERM, in-kernel"]
AGENT --> LSM --> EPERM
end
ENG --> JO
MCP -.->|run_command / run_code<br/>via WslLeasedExecutor| AGENT
The code-level map — which assembly owns each box, how a mission moves between them, and which boundaries a kernel enforces rather than SPLAT's own process — is docs/ARCHITECTURE.md.
Sensor tools never run as trusted children of the app. Each execution passes through:
| Stage | Implementation |
|---|---|
| Suspended spawn | SuspendedProcessLauncher.cs — native CreateProcessW with CREATE_SUSPENDED, so clamps attach before the first instruction runs |
| Resource clamps | Win32JobSandbox.cs — Job Object hard RAM/CPU limits |
| Privilege strip | RestrictedTokenProvider.cs — DISABLE_MAX_PRIVILEGE leaves only SeChangeNotifyPrivilege; Administrators (S-1-5-32-544) is marked USE_FOR_DENY_ONLY, so the SID can no longer grant access; integrity is lowered to Medium (S-1-16-8192) via SetTokenInformation. Asserted end-to-end against whoami /priv and /groups running inside the sandbox |
| Filesystem jail | NtAclJailManager.cs — per-mission NTFS ACL jail with SetAccessRuleProtection inheritance severed |
| Network denial | SensorAppContainer.cs — the tool is launched into an AppContainer holding zero capability SIDs, so it has no network stack rather than a filtered one. A job object clamps CPU, memory and PIDs but has no concept of a socket, so until this landed a tool that declared it only reads the local machine could still open any connection it liked. Proven differentially in SensorNetworkContainmentTests.cs: the same command that reaches a listener (and 1.1.1.1:443 by raw IP, so DNS cannot explain it) when unconfined is refused inside the container. Coverage is partial, and measured. The container is an RPC wall as well as a network one: Get-WinEvent, Get-CimInstance and Get-MpComputerStatus all fail inside it, so templates built on WMI, the Event Log service, Defender or the SCM keep their network stack rather than being silently broken — a live test asserts that WMI really is blocked, so the exemption cannot become folklore. Roughly half the catalog is contained today; closing the rest needs per-template verification or an egress control that is not also an RPC wall |
| Governed remediation | SandboxedRemediationEngine.cs — a template's fix, and its rollback, run in their own sandbox only when each declares a postcondition, and the verdict is that measurement, not the exit code. The shipped catalog defines no fixes yet |
| Secrets at rest | DpapiCredentialVault.cs — Windows DPAPI CurrentUser vault |
The Linux side is a per-cgroup capability lease enforced by a BPF-LSM program (native/splat-agent/src/bpf/lease_lsm.bpf.c), loaded by a resident Rust daemon (native/splat-agent, libbpf-rs 0.24 + tokio, CO-RE via vmlinux.h):
| Hook | Policy for a leased cgroup | Out-of-lease result |
|---|---|---|
lsm/bprm_check_security |
exec only allow-listed inodes | -EPERM |
lsm/file_open |
protected inodes never open | -EPERM |
lsm/socket_connect |
egress only to allow-listed IPv4 | -EPERM |
Policy matches on inode identity, not path strings — full-path resolution in BPF is racy (TOCTOU) and slow. Only cgroups present in the lease map are policed; the host and every other workload are untouched. Violations stream to user space over a BPF ring buffer.
The key defect the first canary run exposed. struct inode_key is a (dev, ino) pair, but the two sides built it from different device encodings: userspace seeded the maps with glibc's st_dev from stat(), while the BPF program keys on the kernel's inode->i_sb->s_dev, which packs (major << 20) | minor. Measured here, /bin/sh is st_dev 2096 and s_dev 8388656 — so every lookup missed. The failure was asymmetric and that is the part worth remembering: a miss in allowed_exec_inodes denies (loud — the first run denied an allow-listed /bin/sh and the canary script never started), while a miss in protected_inodes reads as "not protected" and allows (silent — /etc/shadow was unprotected in that run and nothing said so). Fixed on both sides with unit tests pinning the conversion. A related user-space gap has closed since: splat-mcp used to send placeholder inode numbers and an empty exec allow-list, which the BPF program treats as deny-everything. It now sends paths, which the daemon stats inside the guest, and an exec allow-list pinned to the one command being run.
Execution proof is recorded. The kernel gate was confirmed GREEN on the live stock WSL2 kernel: 6.18.33.2-microsoft-standard-WSL2, native BTF at /sys/kernel/btf/vmlinux, unified cgroup v2, and CONFIG_BPF_LSM=y — no custom kernel, no fork. The recorded run reads active_lsms as unavailable, because securityfs has to be mounted by hand and does not survive a WSL restart; that list would only have corroborated the result, never established it. What establishes it is that the program attached at all — the kernel refuses to load a BPF-LSM program when bpf is absent from the list — and then denied three operations from inside it. On 2026-09-03 the native/splat-canary harness produced the observable proof: a permitted connect() to the leased address succeeded while open() on /etc/shadow, connect() to an unleased address, and exec() of an unleased binary each returned -EPERM from the kernel. The run is machine-checked — the harness computes its own verdict and exits non-zero on a bad run — and its evidence file records the kernel release, the violations, and the SHA-256 of the BPF source that produced them. DocumentationDriftTests holds this README to that evidence in both directions, and stops accepting it if the BPF source changes without a fresh run. The daemon path is proven too, as of 2026-09-03: run under root, splat-agent spawned a tool as uid 0 that was refused /etc/shadow by file_open, and an allow-listed /bin/sh whose exec of dpkg was refused by bprm_check_security — root privilege did not defeat the lease. Reaching that took two fixes the first root run exposed: the tool now joins its leased cgroup in pre_exec, between fork and exec, because attaching after spawn() returned left its own exec unpoliced; and the lease now allow-lists the tool it was asked to run, which it previously did not. The last hop is Demonstrated end to end, as of 2026-09-26, against the kernel program this tree builds. probe-last-hop.ps1 drives splat-mcp.exe over stdio exactly as an MCP client does, and scores controls as well as refusals: the permitted command ran as nobody, the operator-approved endpoint stayed reachable, sh's undeclared exec of dpkg and a connect() to an address outside the lease both returned -EPERM from the kernel, and a request for an endpoint outside the operator's --egress policy was refused inside the MCP host before any lease existed (evidence). That run also found the defect which had made the hop unusable in practice and which no unit test could see: the bridge's wsl.exe children inherited splat-mcp's standard input — the JSON-RPC channel itself — and consumed the client's own bytes, so the sixth request of a session arrived truncated. The Windows-side bridge (WslLeasedExecutor.cs, TemplatePolicyCompiler.cs, WslSubstrateHealthChecker.cs) compiles governed templates into leases and health-checks the substrate. Since 2026-09-24 that compiler is on a live path: four catalog templates name the Linux lease as their substrate, and the console and splat-mcp alike hand such a mission whole to the daemon, which makes the mission's workspace, runs the tool as nobody in a policed cgroup, and reports in a LEASE frame what it installed. The kernel's part of that path was covered by withdrawn claims from 2026-09-20 until 2026-10-01, when the root probe returned PASS over sixty-five checks against that revision. The current run records PASS over 90 checks against d5bb4cad, including the scratch execution controls and the twelve in-kernel lease-deadline and reaper checks, at 2026-11-05T05:47:26Z, inside the shipped SPLAT Guest (Debian 13, archive f238c13a); the last-hop record was refreshed in the same run.
src/splat-mcp is a Model Context Protocol server that exposes SPLAT's governance to any MCP-speaking agent (Claude Code, IDE agents, orchestrators). Thirteen tools, and they do not all sit at the same depth — the distinction matters, because an agent decides what is safe to attempt from the description it is given:
| Tool | Enforced by |
|---|---|
run_command, run_code |
The Linux lease daemon. Demonstrated end to end on 2026-09-26, against the kernel program that ships — a recorded run drove splat-mcp over stdio as a client does, and the kernel refused both an undeclared exec and a connect outside the lease while the permitted command ran as nobody (evidence) |
fs_read, fs_write |
Windows control plane. Confined by canonical-path containment to a governed workspace root — a user-space boundary, not a kernel one |
diagnose_system, investigate_system, run_agent_brain, run_governed_crew |
The full 1:1:1 mission pipeline: validated argument binding, Job Object clamps, restricted token, ACL jail, DLP, audit ledger, Layer-2 cognitive planning, and multi-agent crew execution |
get_substrate_health, list_diagnostic_templates, search_incident_memory, list_governed_crews |
Read-only queries against the local host, catalog, memory, and crew registry |
export_run_record |
Reads one finished mission out of the ledger: the facts the engine sealed when it ended, the mission's entries with a Merkle proof for each, and scripts that check them. Signed when the host was given a run record key, and the bundle says so either way |
verify_run_record |
Holds a bundle up against this host's ledger. Everything inside a bundle agrees with itself however many of the mission's rows were left out of it, so this reports, row by row, whether the live chain still holds exactly those entries at those positions and nothing more for that mission |
Run it as splat-mcp --workspace <dir>. fs_read and fs_write are confined to that directory, which must already exist — it is never created for you. Without the flag they fall back to a private folder under %LOCALAPPDATA%\SPLAT\mcp-workspace, and the server names it on stderr at startup; stdout carries nothing but JSON-RPC. A bad option exits with status 2 before anything is built. --ledger-key <file> keys the audit ledger with a file you keep; an MCP client may start the server without your environment variables, so give it in the stanza's args. --run-record-key <file> signs exported run records with a key you keep, which splat-mcp new-run-record-key <file> will make for you, printing the fingerprint to publish; without it bundles export unsigned and say so. splat-mcp --help prints the rest. On a fresh host, splat-mcp provision --apply does the Linux setup that splat-mcp doctor reports missing: it installs the lease daemon it carries at /opt/splat/splat-agent, starts it under systemd so it survives a restart, and succeeds only when the daemon is enforcing. Without --apply it changes nothing and lists what it would do.
Installing it. One self-contained file; the target machine needs no .NET, and its WSL guest needs no Rust toolchain, because the Linux daemon travels inside it:
powershell -ExecutionPolicy Bypass -File packaging\publish-splat-mcp.ps1That builds the daemon in WSL first — so the build machine needs a Rust toolchain in WSL, and only the build machine — then produces dist\splat-mcp.exe (~77 MB, with its native SQLite and the daemon packed inside) and
dist\splat-mcp.exe.sha256, which names the daemon's build ID and the oldest glibc it accepts (2.39). It refuses to report success if the publish returns non-zero, produces
nothing, leaves a file beside the executable, yields something that cannot print its own usage, links the daemon against libelf, zlib or zstd, or ships an executable that does not carry the daemon it built.
Point an MCP client at the file:
{
"mcpServers": {
"splat": {
"command": "C:\\tools\\splat-mcp.exe",
"args": ["--workspace", "C:\\path\\to\\your\\project"]
}
}
}There is no dotnet tool package: PackAsTool rejects a platform target framework (NETSDK1146), and
this server targets net10.0-windows because its containment primitives are Win32.
splat-mcp doctor answers the question that comes before trusting it with an agent: what will this host actually enforce? It reports the kernel, whether bpf is on its boot command line, whether the daemon is reachable and holding live BPF maps, and whether its token is in place — then what a lease enforces, refuses and does not police, copied from SUPPORTED_POLICY.md and held to it by a test. It exits 0 only when a lease on this host would reach the kernel, so a setup script can gate on it. It serves nothing and creates nothing.
splat-mcp provision gets a host from "WSL2 is installed" to "a lease reaches the kernel". It checks WSL, systemd and bpf on the boot line, installs the daemon it carries at /opt/splat/splat-agent — a build from this repository carries none, and builds it in the guest with cargo instead — writes and enables a systemd unit, and passes only when the authenticated health check says a lease reaches the kernel. It changes nothing without --apply, and even then leaves two steps to you and names them: wsl --install, which needs administrator rights and a reboot, and wsl --shutdown, which ends every WSL session you have open.
--egress a.b.c.d:port,... names the only endpoints a run_command or run_code lease may connect to. A calling agent may ask for some of them and never for others, and without the flag both tools get no network: the agent's own request used to write the network half of its lease, so the kernel would faithfully enforce whatever an injected prompt had talked it into asking for.
Every call lands in the audit ledger attributed to a resolved principal — the Windows logon session, or a validated credential where SPLAT_MCP_CLIENT_CREDENTIAL is configured. A credential that fails to validate refuses the call rather than falling back to an anonymous row.
-
Tamper-evident ledger —
SqliteChainedAuditLedger.cs: every action, argument, token, and fix is committed to a SHA-256 chained hash ledger (WAL-mode SQLite) with Merkle-root verification. The chain commits to a salted digest of the payload rather than the plaintext, which is what makes retention erasure possible without forging a tamper signal — a purged row still recomputes. Each row is attributed to a resolved principal (the Windows logon session, or a validated credential) with its provenance recorded inline, never to a caller-supplied name.What this detects, and what it does not. Editing any historical row in place breaks the chain verifiably. Unkeyed — the default — it does not detect a rewrite:
ComputeEntryHashV2is public, so anyone who can write the database file can recompute the whole chain from genesis undetectably, andsplat-mcp doctorsays so on every unkeyed host. Since 2026-09-18 the operator can key it with a file they keep (--ledger-key <file>onsplat-mcp, orSPLAT_LEDGER_KEY_FILEfor either host). Each keyed entry is HMAC-SHA256 under that key, and each row records which chain it is on. The first keyed entry records the switch and commits to the unkeyed history before it. A keyed ledger refuses to be extended without its key or with another. Keyed, nobody without the key file can rewrite it unnoticed. Two things a key does not change: deleting the newest entries is caught only by a saved audit anchor, and whoever can read the key file — the operator's own account included — can rewrite it as freely as SPLAT can write it. -
SIEM export and local EDR observations —
SiemForwarder.cssends Microsoft Sentinel (HMAC), CEF, and RFC 5424 syslog. Connection checks distinguish local UDP send, TCP connect, validated TLS and ingestion-API acceptance; none establishes retention. Sends have a timeout but no durable retry queue.EdrIngestionBridge.csreads local process/registry indicators and Defender events; it does not implement provider isolation commands or verify live protection state. Transport and unsupported-action assertions are inSiemTransportInvariantTests.csandSiemAndEdrIntegrationTests.cs; current validation limits are recorded in the SOC invariant audit. -
Pre-egress DLP —
RegexDataLossPreventionSanitizer.csmasks private-key blocks, NTLM hash pairs, passwords/API keys/bearer tokens, CLI password parameters, emails, card and SSN patterns — in memory, before anything reaches a model provider. -
Local semantic memory —
SqliteSemanticMemoryIndex.cs: in-process 128-dim embeddings with sub-second cosine similarity over incident history; no cloud embedding calls.
-
The 1:1:1 invariant. Every governed template binds 1 template → 1 model → 1 dedicated native tool. The model gateway has one approved FQDN, enforced by strict validation and an in-memory egress firewall (
EgressFirewallHandler.cs). A Linux tool may declare up to eight exact destination hosts;TemplatePolicyCompiler.csresolves and pins their IPv4 addresses for each lease. A 40+ template catalog covers network, identity, endpoint, SysOps, and compliance runbooks.Which leg that FQDN governs. Two different processes can reach a destination. The AI gateway is called by SPLAT's own process and governed by its provider client and firewall handler. A sensor destination uses
EgressScope.ToolProcess; the public discovery and RARE sensors now run under Linux leases. The kernel enforces their pinned address/port set, while the RARE sensor connects using those exact pins and verifies the requested hostname through TLS. A gateway-scoped template does not earn a sensor network lease. Windows still cannot pin a network-capable child's destinations; its local-subsystem exemptions remain documented in the Windows boundary. -
Bounded composition, not swarms. Project Studio chains at most six ordered agent stages with a bounded, DLP-filtered evidence hand-off between them. No recursive routing, no parallel swarm, no open-ended loops — multi-step autonomy is earned as the kernel substrate lands, not assumed.
-
Reasoning cores are pluggable — streaming Anthropic Claude and Google Gemini clients behind
ModelClientRouter.cs, routed by available key.
$ dotnet test tests/MissionController.Tests/MissionController.Tests.csproj
The 2026-10-05 recordings remain historical evidence, including the four original Linux templates
run through the guest lease. On 2026-10-14, the eight public probes moved into Linux and
sysops-time-sync were recorded against live Anthropic models, reviewed and promoted. The
coverage, privacy and replay gates passed for those recorded definitions (MissionCorpusTests,
MissionCorpusPrivacyTests, MissionReplayTests); their fixture notes retain known model
errors rather than treating acceptance as factual correctness. Replaying an old answer cannot
validate a changed template. The Field Guide's separate publication
record is checked by DocumentationDriftTests.ThePublishedFieldGuide_IsTheSourceAsItStandsToday.
The recording guide describes promotion
and the adversarial checks. These recordings hold observed pipeline behaviour; diagnosis accuracy
beyond this reviewed corpus remains built, unproven. The test count below is an inventory.
On 2026-10-17 the published A2A authority proof passed 114/114 checks, including all three RARE sensors against public Apple sources, signed delegation narrowing, cancellation drain and revocation. No model API was called in that proof. On 2026-10-18, a separately authorized Anthropic run recorded the three RARE Linux templates; their reviewed fixtures passed coverage, privacy, replay and adversarial checks (9/9). Review found counting, citation and unsupported-inference errors in the accepted answers. Those answers and verdicts are preserved, with explicit limitations in each fixture's note. A personal name and school in one review title were redacted; no answer or verdict was rewritten. The Windows DNS observation and updated Field Guide publication remain release gates. See the current A2A verification.
1193 xUnit unit, integration, and security tests. Coverage spans the sandbox clamps (HardeningSubsystemTests), the Job Object containment flags read back out of the live kernel object, the restricted token asserted against whoami running inside the sandbox, governed argument binding, DLP masking, ledger tamper-detection, egress-firewall enforcement, operator attribution, token lifecycle and circuit breakers, the remediation/rollback engine, the MCP server, and end-to-end multi-layer verification.
On the warning count. The 2026-10-01 cold solution build (--no-incremental) completed with zero warnings and errors, including the WinUI project. This verifies compilation; live corpus and runtime containment require their separate evidence.
SPLAT/
├── src/
│ ├── MissionController.Core/ # Domain contracts, mission & project execution engines
│ ├── MissionController.Infrastructure.Windows/# Job Objects, restricted tokens, ACL jails, remediation, DPAPI vault
│ ├── MissionController.Infrastructure.Linux/ # WSL substrate bridge: leased executor, policy compiler, health checks
│ ├── MissionController.Infrastructure.Network/# DLP, egress firewall, identity/JWT, AI clients, SIEM/EDR
│ ├── MissionController.Infrastructure.Data/ # SQLite storage, chained audit ledger, Merkle engine, vector memory
│ ├── MissionController.UI/ # WinUI 3 operator console (MVVM)
│ ├── splat-mcp/ # MCP server — governed execution for agent clients
│ └── splat-alert-sidecar/ # Decoupled EDR/Falcon alert consumer for lease containment
├── native/
│ ├── splat-agent/ # Rust eBPF daemon: lease_lsm.bpf.c + libbpf-rs loader
│ └── splat-canary/ # Minimal -EPERM proof harness (preflight → canary)
├── tests/MissionController.Tests/ # 1193 xUnit unit / integration / security tests
├── packaging/ # Signed MSIX build + Intune/SCCM silent install scripts
└── docs/ # Architecture, context and module maps; briefs, plans, audits - index in docs/README.md
| Framework | Mapping |
|---|---|
| SOC 2 Type II | CC6.1 restricted tokens & privilege separation · CC6.6 / CC6.7 per-lease egress allow-listing · CC6.8 per-lease executable allow-listing · CC7.2 chained audit of governed runs |
| HIPAA Security Rule | § 164.312(b) cryptographic chained audit controls · § 164.312(e)(1) transmission security & DLP masking |
| NIST SP 800-171 / CMMC 2.0 | AU.2.041–042 attributed, chained audit logs · SC.3.177 strict egress isolation |
These are the controls the architecture is built against; they are not an attestation, and SPLAT has not been assessed by an auditor. One qualification worth stating rather than burying: AU.2.041 non-repudiation has two halves, and only one is complete. Actions are now attributed to a principal the OS or a validator established, but the chain protecting that attribution is unkeyed unless the operator supplies a key (see the ledger note above). Unkeyed, a local administrator can still rewrite history including their own name in it; keyed, so can anyone who can read the key file, which an administrator can. Read the mapping as design intent with a known gap, not as a passed control.
Every open item — who can do it, what "done" means, and the evidence for its current state — is in docs/ROADMAP.md, checked against the tree rather than carried forward from older plans. In order:
- Installable and provable by a stranger (done 2026-09-18, on a second machine) — a
splat-mcpcommand line with an explicit workspace, adoctorcommand that prints what this host will and will not enforce, first-run WSL provisioning, single-file distribution, and one recorded end-to-end run of an MCP client's command being refused by the kernel. - The workload's own mount namespace — the root run
records PASS for the full leased-scratch execution criterion: a generated executable runs in
its explicitly authorized overlay, identical bytes outside it are denied, and its layer and
grant disappear after teardown. Nine new checks also cover descriptor execution, another
lease, the default refusal and the operator ceiling. The complete run covers 74 checks,
including the existing mount and pinned-hook controls, against BPF source
6fc637d8. - Caller identity on the bridge (done 2026-10-21, for the managed service) — a separate Windows account owns the distro and the daemon, and the service names each caller from that caller's Windows token. The gate run recorded every step. It does not exclude an administrator, and the stdio bridge still identifies no caller.
- The per-mission run record — a bundle from which someone who did not run a mission can verify what it was permitted to do and what it did. It needs a keyed ledger, which the operator can now supply; unkeyed is still the default, as the compliance note above says.
- A kit you mount — SPLAT on a flash drive or from one downloaded script. It mounts onto a host only after showing what that host can enforce and what mounting will change, and it unmounts cleanly. None of it is built yet; its design document moved out of the repository on 2026-10-14.
GNU AGPL-3.0 — © 2026 Platten Industries.
Commercial use is permitted. When conveying covered binaries, modified or unmodified, provide Corresponding Source through a method allowed by section 6 and preserve the required notices. Modified network-interactive versions must prominently offer their Corresponding Source to their remote users under section 13. Ordinary execution alone does not require disclosure or a commercial license. The license does not automatically cover independent workloads or their outputs.
The full LICENSE controls. COMMERCIAL.md explains the distinction between distribution, modified network use and ordinary execution. Alternative permissions for code Platten Industries can relicense require a separate commercial agreement; third-party obligations remain. The Community notices and privacy information do not add restrictions to the AGPL grant.
Third-party components (.NET Runtime, Windows App SDK, Win2D, Microsoft.Data.Sqlite, CommunityToolkit, SQLite, the libbpf ecosystem) remain under their own licences.
"SPLAT" and "Platten Industries", and their logos, are marks of Platten Industries. The AGPL grants copyright and patent permissions, not trademark permissions, and none are granted here. Say your build is derived from SPLAT; do not call it SPLAT.
- A containment failure, or anything that gets out of a lease — SECURITY.md. Not a public issue. Read the already known section first: several weaknesses here are measured, published and open, so rediscovering one is a confirmation rather than a finding.
- A document that claims more than the code does — the most valuable report this project takes, and it has its own issue form. A measurement that contradicts a document gets merged over the document.
- A patch — CONTRIBUTING.md for the build commands, the rules the suite enforces, and what is worth working on. Code needs a signed CLA, because the same work is offered commercially and both offers have to cover all of it.
- Conduct — CODE_OF_CONDUCT.md.
Built by Sean Platten (GitHub · LinkedIn) — systems engineer applying a decade of high-throughput line discipline to kernel-level agent containment: mise en place before execution, no black boxes, zero wasted motion, and boundaries the hardware enforces.