Architecture
A launcher plus a small set of single-purpose components. Any process (sgit, a shell command, an agent loop) runs inside, each component under its own Process Behaviour Policy, talking to the others only over allowed, mutually authenticated edges. Theme: one role, one noun, one uid, one policy, one certificate.
The picture
person: supplies manifest hash sha256:M, carries sealed QR codes
│
┌──────────────────────────── sharness.launcher (outside every domain) ──────────────────────────────┐
│ │
│ harnessed app / orchestrator (no keys, no tools of its own, Landlock exec allowlist) │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ sharness.fs sharness.net sharness.bash sharness.llm ──────► model API │
│ (writes) (network) ──┐ (sandboxes) │ │
│ │ │ │
│ └──────► sharness.kms ◄──────┘ (vault keys, API keys, sealed secrets) │
│ │
│ every edge: mutual TLS, roles in certificates, schemas on the payload, both sides check │
│ every component: own uid, own policy, kernel-enforced │
└──────────────────────────────────────────────────────────────────────────────────────────────────────┘
The app-specific orchestrator (sgit's CLI, or an agent loop such as Claude Code) sits on top and routes. It holds nothing and runs nothing itself. What each component does is on Components.
Edges (deny by default)
caller ↓ callee → fs net bash llm kms app/orchestrator ✔ ✔ ✔ ✔ ✗ net ✗ — ✗ ✗ ✔ llm ✗ ✗ ✗ — ✔ bash (sandbox) ✗ ✔* — ✗ ✗ * only if the profile allows network fs, kms ✗ ✗ ✗ ✗ —
The orchestrator never talks to the KMS. Only sharness.net and sharness.llm do, and the KMS never returns a clear key to either: it returns derived keys sealed to a one-time key (see Keys and the KMS).
The original four, for sgit
The design began with four components for sgit. The early documents use sgit-specific names; the mapping is: sgit-kms → sharness.kms, sgit-net → sharness.net, sgit-fs → sharness.fs, sgit-cli → the harnessed app.
┌───────────────────────────────── session (ephemeral VM / pod / host) ──────────────────────────────┐ │ agent (LLM) ── runs ──► sgit command (the harnessed app) │ │ ▲ transcript sees only: commands, k1, m1, status output — never a clear key │ │ ┌─────┴──────────────┐ mTLS ┌────────────────────┐ │ │ │ sgit (app) │─────────►│ sharness.fs │──► clone folder + .sg_vault/ (only writer) │ │ │ orchestrates │ edge 1 │ no keys, no net │ paths, sealed formats only, no symlinks │ │ │ NO keys │ └────────────────────┘ out, no exec bits │ │ │ NO network │ mTLS ┌────────────────────┐ TLS client, ┌──────────────────┐ │ │ │ NO disk writes │─────────►│ sharness.net │─ allowlisted ─►│ platform egress │──► vault │ │ │ no fork │ edge 2 │ DERIVED keys for │ host names │ proxy │ server │ │ └────────────────────┘ │ one command │ └──────────────────┘ │ │ └─────────┬──────────┘ │ │ │ mTLS edge 3 │ │ ┌─────────▼──────────┐ private key in a memfd_secret page │ │ │ sharness.kms │ frozen between calls (cgroup freezer) │ │ │ no net, no disk │ only op: open sealed → re-seal to E.pub │ │ └────────────────────┘ (or remote: Lambda / KMS / HSM / platform)│ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘
Measured with a session CA and role certificates: app→fs, app→net and net→kms accepted; fs→kms, app→kms and fs→net refused, exactly per the matrix.
Mutual TLS with a session CA
launcher each component
──────── ──────────────
1. make CA key (P-256), CA cert (2h, pathlen 0)
2. for each role:
make key, issue cert
SAN URI spiffe://<session-id>/<role>
SAN DNS localhost
validity = session
3. DESTROY CA private key ───────────────► set of identities is now closed
4. CA cert hash → into policy manifest 5. on connect, BOTH sides:
- verify chain to session CA
- read peer role from SAN URI
- check (caller, callee) ∈ edges
- reject otherwise
Rules (proposed):
- TLS 1.3 only, P-256 keys. Making the CA plus four role certificates took 24 ms (measured).
- Both sides check roles. The callee checks the caller and the caller checks the callee, so a compromised component cannot pose as
sharness.netto the app. - SPIFFE IDs (
spiffe://<trust-domain>/<role>): the SPIFFE/SPIRE and service-mesh pattern, so on Kubernetes SPIRE or a mesh can issue the identities instead of the launcher. - A component's TLS key is not its sealing identity.
sharness.kms's TLS key and its RSA identity are separate keys. - Set
TCP_NODELAYon both ends. Without it on the server the handshake measured 46 ms (a delayed-ACK stall) instead of 3.2 ms. - Same protocol on any transport: Unix sockets locally, TCP across machines. On Unix sockets, add
SO_PEERCREDuid checks as an independent third layer. - Wire format: a small HTTP/1.1 (or length-prefixed JSON) API over the TLS connection; one connection per command; TLS session resumption between commands.
What it costs (measured)
Python ssl, TLS 1.3, P-256, server as a thread in the benchmark process, as of 24 Oct 2026.
| Transport | Connect + handshake | 600 B round trip | Bulk |
|---|---|---|---|
| TCP plain | 0.10 ms | 15 µs | ~300 MB/s |
| TCP mutual TLS | 3.2 ms | 67 µs | ~320 MB/s |
| Unix plain | 0.09 ms | 56 µs | ~320 MB/s |
| Unix mutual TLS | 3.4 ms | 74 µs | ~420 MB/s |
Per sgit command: three handshakes ≈ 10 ms, against 146 ms of sgit imports and ~108 ms of key derivation already paid today. Round-trip and bulk figures varied by up to ~25% between runs; handshake times were stable. Method and caveats on Evidence.
Deployment topologies
Same components, same protocol, same policies. Only the launcher changes. Only A was measured.
A. one VM, separate uids (what was measured)
┌──────────────────────── VM ────────────────────────┐
│ app fs net kms (one uid each) │
│ └─ Unix sockets + mTLS + SO_PEERCRED + iptables │
└────────────────────────────────────────────────────┘
B. Docker / compose: one container per component
┌─app─┐ ┌─fs──┐ ┌─net─┐ ┌─kms─┐ network: internal only, except net
│ │──│ │ │ │──│ │ volumes: clone folder rw in fs, ro in app
└─────┘ └─────┘ └──┬──┘ └─────┘ kms: internal network only, read-only rootfs
└──► egress
C. Kubernetes: one pod, one container per component (or kms as its own Deployment)
identities from SPIRE / mesh (spiffe://<td>/<role>); NetworkPolicy mirrors the edge matrix;
seccomp + readOnlyRootFilesystem + runAsNonRoot per container from the policy
D. remote KMS
net ──mTLS/HTTPS──► Lambda / Cloud Function ──► cloud KMS asymmetric key (HSM)
caller bound to the session's auth key; nonce store e.g. DynamoDB conditional put
E. platform-provided (proposed end state)
net ──► local platform endpoint (vsock / proxy) ──► platform KMS; session identity
= the platform's own knowledge of the session; no auth key in the container
Topology E is a proposal for what agent platforms should offer. No such service is known to exist today.
Glossary
| Term | Meaning |
|---|---|
| vault key | the secret that opens an sgit vault; the read key, write key, vault id and file ids are derived from it (PBKDF2, 600,000 iterations, ~108 ms) |
| derived keys | the read key and the write key. Almost all of sgit runs on these, not on the vault key |
k1 / pki.sgit.ai/qr/key/v1 | a public key bundle, as a QR or JSON |
m1 / pki.sgit.ai/qr/sealed/v1 | a sealed message: RSA-OAEP 4096 wraps an AES-256-GCM key; the sender signs with ECDSA P-256 over recipient, time and expiry |
| session identity | the key pair (RSA-4096 encryption + ECDSA P-256 signing) the KMS makes for this session; its public half is what the person carries to the sender |
| record fingerprint | the signing key's fingerprint; what --to names |
| E | a one-time key pair made by the caller for a single KMS request; the response is sealed to E.pub |
| session CA | a throwaway certificate authority that issues one TLS certificate per component, then has its private key destroyed |
| edge | an allowed caller → callee connection between components |
| PBP | Process Behaviour Policy: the ABP model (grant, mandate, delta, barrier) applied to a process |
| launcher / runtime | whatever creates the users, CA, certificates and policies and starts the components; ideally the agent platform, not the agent |
| harnessed app | a program running inside the harness (sgit, a shell command, an agent) |
| harness-aware / transparent | an app that speaks the harness protocol directly, or an unmodified app that works because the harness presents ordinary interfaces (a proxy, a mount) |
Sources: 05-sharness §1–2, 01-architecture §1, §3 and §5, and the glossary in 00-README §4.