# Lazaret Specification This document is the normative product specification for Lazaret. It defines the problem, stable vocabulary, architecture, and requirements. The [TLA+ application protocol model](protocol/Lazaret.tla) defines lifecycle and communication semantics. Current implementation strategy, experimental results, and historical rationale live in the development journal (local checkout: [journal index](journal/00_INDEX.md), including the [implementation plan](journal/implementation-plan.md)). ## 1. Problem Statement AI coding agents need broad local capabilities: they run arbitrary tools, modify a project, use Git, install dependencies, and access selected network services. Code produced or invoked by an agent is not trusted to run directly on the developer's host. A conventional container reduces risk, but poor terminal behavior, transient tool state, restricted Git access, and manual setup can make the safe path too inconvenient for routine work. Lazaret's north star is: > Make isolated agent execution the easiest way to work, while ensuring that every > transition from the sandbox to host authority is explicit, attributable, and > controlled by the developer. Lazaret therefore provides a rootless gVisor sandbox with a bidirectionally shared workspace, persistent sandbox-local tooling, controlled network egress, and a human-in-the-loop host escalation path. ### 1.1 Trust Model The following components are trusted: - The developer and host operating system. - The Lazaret CLI and the domain's Session Coordinator. - Host configuration selected by the developer. - The Network Sidecar and the policy given to it by Lazaret. The following components are untrusted: - The agent and every process it launches. - Code, tools, and package installation scripts executed inside the Agent Sandbox. - Data received from the network by sandboxed processes. All Client Sessions in the same Domain intentionally share an Agent Sandbox and are one sandbox trust domain. Session identity distinguishes ownership and routes terminal interactions; it is not an isolation boundary between processes in that sandbox. The Agent Workspace is intentionally writable. Lazaret protects the host outside the explicitly mounted workspace and volumes. Tracked and ordinary untracked workspace paths remain writable, while Git-ignored paths are isolated into Domain-scoped sandbox state by default. The developer may explicitly disable that isolation in trusted host configuration. Host configuration is read only by host Lazaret processes. A configuration file must not be mounted into, or located beneath a host path mounted into, the Agent Sandbox. ## 2. Glossary These terms and identifiers are stable across the specification, protocol model, implementation plan, logs, and user interfaces. | Term | Definition | | :--- | :--- | | **Agent Profile** | A developer-selected host configuration describing an agent image and its granted storage, network, environment, and escalation capabilities. | | **Agent Workspace** | The canonical host project directory mounted read-write at `/workspace` in the Agent Sandbox. | | **Agent Sandbox** | The rootless gVisor container in which an agent and its child processes execute. One sandbox is shared by all Client Sessions in a Domain. | | **Agent Sandbox ID** | A runtime-unique identifier assigned to one Agent Sandbox instance and bound to its Domain protocol identity. | | **Client CLI ID** | A runtime-unique identifier assigned to one host Lazaret CLI process. It is authenticated as a protocol identity and bound to one Client Session. | | **Client Session** | One active host Lazaret CLI process and the interactive or non-interactive command it attaches to the Agent Sandbox. | | **Session ID** | A cryptographically random identifier unique to one Client Session. | | **Session Anchor** | Ephemeral session credentials that bind protocol messages to a registered Session ID and route them to the owning host CLI. | | **Session Coordinator** | The ephemeral host process that exclusively owns and coordinates a Domain's runtime resources and Client Sessions. | | **Session Coordinator ID** | A runtime-unique identifier assigned to one Session Coordinator instance and bound to its Domain protocol identity. | | **Domain** | The shared runtime and persistent-state scope for one `(Agent Profile, canonical Agent Workspace)` pair. | | **Domain ID** | A deterministic identifier derived from the Agent Profile name and canonical Agent Workspace path. It namespaces Domain resources but is not an authentication credential. | | **Domain Root** | The host-only directory containing persistent state and metadata for one Domain. | | **Network Sidecar** | The trusted, shell-less gateway container that establishes the Domain's network policy before the Agent Sandbox starts. | | **Network Sidecar ID** | A runtime-unique identifier assigned to the Network Sidecar instance owned by a Domain. | | **Git Sentry** | The protective mount layout that preserves bidirectional workspace and Git access while preventing writes to the host's default Git hooks and repository configuration. | | **Ignored Workspace State** | Domain-scoped sandbox-local storage presented at Git-ignored Agent Workspace paths instead of exposing the corresponding host content. | | **State Anchor** | The Domain-scoped persistent writable filesystem layer merged over selected paths from the sandbox base image. | | **Trust Anchor** | The ephemeral Domain-scoped certificate authority used to authenticate role-bound Lazaret protocol identities. | | **Protocol Identity** | An authenticated binding of a component role, Agent Profile, Domain ID, and runtime component ID. Identifiers name components but do not authenticate them by themselves. | | **Escalation Client** | The Lazaret-provided executable through which a sandboxed process requests a host action. | | **Escalation Mailbox** | Host-private, Domain-scoped regular-file message paths mounted into the Agent Sandbox for signed escalation requests and correlated results. | | **Escalation Request ID** | A cryptographically random identifier used to correlate one host escalation request and response. | | **Escalation Result** | The terminal response to an accepted Host Escalation, correlated by Escalation Request ID and carrying its outcome plus command exit status and output when execution occurred. | | **Host Escalation** | A request by a sandboxed process for Lazaret to execute a developer-approved or auto-approved action with host authority. | | **Configuration Fingerprint** | A cryptographic digest of the validated host configuration that created or joined a running Domain. | | **Storage Root** | The trusted host directory beneath which Lazaret stores Domain Roots and profile-scoped state. | ## 3. Architecture ### 3.1 System Boundaries ```mermaid flowchart LR subgraph Host[Trusted host] CLI[Client CLI] Config[Host configuration] HostWorkspace[Agent Workspace] Coordinator[Session Coordinator] State[State Anchor] Gateway[Network Sidecar] Mailbox[Escalation Mailbox] HostExec[Approved host process] end subgraph Sandbox[Untrusted Agent Sandbox - rootless runsc] Agent[Agent and child processes] Workspace[/workspace mount] Escalate[Escalation Client] end Config --> CLI HostWorkspace <--> Workspace CLI <--> Coordinator Coordinator --> State Coordinator --> Gateway Coordinator <--> Mailbox Agent <--> Workspace Agent --> Escalate Escalate <--> Mailbox Coordinator --> HostExec Agent --> Gateway Gateway --> Network[Permitted destinations] ``` The Agent Sandbox uses gVisor's application-kernel isolation under rootless Podman. Rootless operation limits the host authority of the runtime, while gVisor interposes a separate userspace kernel between untrusted processes and the host kernel. The Network Sidecar is a separate trusted component and is not part of the untrusted agent environment. ### 3.2 Domain and Session Lifecycle The Session Coordinator is the single owner of a Domain's Agent Sandbox, Network Sidecar, State Anchor, host-only sockets, Escalation Mailbox, and active-session registry. Concurrent CLI processes for the same Domain join the existing coordinator and attach separate Client Sessions to the shared sandbox. Different Domains never share these resources. The first Client Session starts the Domain. The coordinator prepares persistent state, establishes network policy, starts the Agent Sandbox, and then accepts the session. When no Client Sessions remain, it tears down transient resources while retaining Domain-scoped persistent state. Startup, registration, cancellation, recovery, and teardown transitions are defined by the [TLA+ application protocol model](protocol/Lazaret.tla). A Domain failure first withdraws publication, invalidates active trust material, disconnects sessions, and terminates associated host processes. It does not assume that already-created sandbox, sidecar, or mount resources disappeared. Recovery stops the sandbox, then the sidecar, then unmounts the State Anchor before the Domain may return to the absent state and accept a new startup leader. The Trust Anchor authenticates distinct Protocol Identities for the Session Coordinator, Client CLI, Network Sidecar, and Agent Sandbox. Certificates bind a peer's role, Agent Profile, Domain ID, and runtime component ID; a certificate for one role or Domain cannot authorize another. Session registration additionally binds the authenticated Client CLI ID to its Session ID and Session Anchor. Authorization uses the relevant current identity tuple rather than any identifier alone. Network attachment binds the `(Domain ID, Network Sidecar ID, Agent Sandbox ID)` tuple. Session control binds the `(Domain ID, Session Coordinator ID, Client CLI ID, Session ID)` tuple. Host Escalation binds the authenticated Agent Sandbox ID to the registered `(Client CLI ID, Session ID, Session Anchor)` tuple in that Domain. ### 3.3 Filesystem and Git Model The Agent Workspace is mounted read-write. Tracked paths and untracked paths that are not ignored propagate in both directions. The Git index, `HEAD`, references, and objects are shared with the host in real time. Lazaret does not create a separate worktree or branch and does not promise that the host working tree remains unchanged. By default, paths matched by the repository's effective Git ignore rules are redirected to Ignored Workspace State. Existing host content at those paths is not exposed to the Agent Sandbox, and sandbox writes remain Domain-scoped and persist across restarts. This prevents agent-modified dependency trees, virtual environments, generated executables, caches, and other ignored artifacts from later being executed by host tools. Trusted host configuration may disable this behavior when fully bidirectional ignored paths are required. Ignored-path isolation is defense in depth and does not replace the mandatory Git Sentry protections below. Lazaret applies narrow protective mounts over host integration files that must not be modified by the agent: - The host repository's `.git/config` is exposed read-only. - The host repository's `.git/hooks` is hidden behind sandbox-local transient storage. - Supported host editor configuration directories may be hidden behind sandbox-local transient storage. These protections do not make the workspace immutable. Their purpose is to stop the sandbox from writing the protected host Git configuration and default hook directory while preserving normal Git operations and bidirectional source edits. ### 3.4 Persistent Sandbox State The State Anchor preserves developer tooling and selected sandbox system paths for one Domain. It combines a read-only lower directory from the selected base image with a Domain-scoped writable upper directory. Files not represented in the upper layer follow the selected base image. Files, directories, and whiteouts recorded in the upper layer remain authoritative when the lower image changes. This permits installed tools to survive restarts while allowing unmodified base-image content to follow the selected image. Persistent state is sandbox state, not host configuration. It must not contain or override Lazaret's host control plane. ### 3.5 Network Isolation The Network Sidecar establishes the Domain's egress routes before the Agent Sandbox starts. The sidecar alone receives the network-administration capability needed to install policy; the Agent Sandbox does not receive that capability. The Agent Sandbox may join only the sidecar's prepared network namespace, not the host network namespace. IPv4 destinations are permitted by default except for the RFC 1918 private address ranges, which are denied by default. Explicit, more-specific allow rules may grant access within those ranges. Lazaret also installs the reachability needed for the Domain's selected DNS resolvers. Other permitted and denied destination prefixes come from trusted host configuration. Normal Linux longest-prefix routing determines the most specific matching route; an equal-prefix conflict must be rejected or resolved in favor of denial. IPv4 and IPv6 must either receive equivalent policy or an address family must be disabled. The topology and policy-installation sequence must ensure that all external Agent Sandbox traffic traverses the configured enforcement path. Dynamic policy changes are not a requirement unless the implementation can apply them without weakening that property. ### 3.6 Host Escalation The Escalation Client exchanges request and result records through the Escalation Mailbox. Records are regular files written by atomic rename beneath host-private, Domain-scoped paths. The sandbox-writable request path and sandbox-readable result path may have different mount modes. The mailbox is not trusted as an authentication boundary: each request carries authenticated Domain credentials and a Session Anchor signature binding it to a registered Client Session and to the exact request content. A verified request is routed only to that session's host CLI. Host-only CLI/coordinator control may use host-private Unix sockets that are never mounted into the Agent Sandbox. A host command may run only when the developer approves it interactively or when it matches an auto-approval rule in trusted host configuration. Auto-approved commands are launched directly as an argument vector without a shell. Rules match the complete vector by default; permission for arbitrary trailing arguments is an explicit property of an individual rule. Interactive approval may allow the developer to approve, deny, or edit a request. Every accepted request must produce an Escalation Result for its Escalation Client while its Client Session remains connected. The result reports completion, denial, timeout, cancellation, or failure and, when a host command ran, its exit status and standard-output and standard-error data. Approval is an authorization decision, not a terminal result. A request reaches its terminal state only after this result is delivered or its Client Session disconnects. Terminal ownership must return to the sandbox session after resolution. Authentication, message correlation, approval, execution, cancellation, and terminal-routing transitions are defined by the [TLA+ application protocol model](protocol/Lazaret.tla). ### 3.7 State Inspection and Reset The host CLI provides read-only discovery, inspection, structural verification, and explicit reset operations for Domain State Anchors. These operations resolve a Domain through trusted host metadata and never accept an arbitrary host filesystem path as an upper-layer target. Inspection reports metadata and overlay changes without printing file contents by default. Structural verification requires an inactive Domain and exclusive lifecycle ownership so its result is not invalidated by concurrent writes. A reset may target one configured persistent container path or all State Anchors in the Domain. It discards the selected upper-layer state so the next launch follows the current base-image lower layer; it does not modify the base image, Agent Workspace, Ignored Workspace State, or unselected State Anchors. Reset is permitted only after Lazaret holds the Domain's exclusive lifecycle lock and has established that no Client Session, coordinator, sandbox, sidecar, host process, or overlay mount is using the selected state. Confirmation flags may suppress the human prompt but may not bypass these safety conditions. Reset must be crash-consistent and must never follow a symlink outside the Domain Root. ## 4. Requirements ### 4.1 Security Requirements | ID | Requirement | | :--- | :--- | | **SR-1** | Agent processes shall execute in a rootless gVisor sandbox and shall not receive host root authority. | | **SR-2** | Host configuration shall never be mounted into the Agent Sandbox or located beneath a host path mounted into it. | | **SR-3** | Host paths outside the Agent Workspace, developer-configured volumes, and Lazaret-owned fixed control mounts shall not be accessible to the Agent Sandbox. | | **SR-4** | The sandbox shall be unable to modify the host repository's `.git/config` or default `.git/hooks` directory through the workspace mount. | | **SR-5** | The Network Sidecar shall establish network policy before the Agent Sandbox starts, and the Agent Sandbox shall not receive network-administration capability. | | **SR-6** | Network policy shall cover every enabled address family and shall deny equal-specificity policy conflicts. | | **SR-7** | A host action shall execute only after interactive developer approval or a match against a trusted host auto-approval rule. | | **SR-8** | Auto-approved host commands shall execute without a shell and shall permit trailing arguments only when the matched rule explicitly grants them. | | **SR-9** | Every protocol peer shall be authenticated to its component role, Agent Profile, Domain ID, and runtime component ID. Authorization shall require the relevant current identity tuple; an identifier or certificate for another role, Domain, component instance, or Client Session shall not be accepted. | | **SR-10** | Domain sockets, mailboxes, and coordination files shall reside in a host-private directory owned by the developer. | | **SR-11** | Runtime and persistent resources belonging to different Domain IDs shall remain isolated. | | **SR-12** | The Agent Sandbox shall not join host user, PID, IPC, UTS, cgroup, or network namespaces; the only shared network namespace permitted is the Domain's Network Sidecar enforcement namespace. | | **SR-13** | Git-ignored Agent Workspace paths shall use Ignored Workspace State by default, preventing the sandbox from reading or modifying corresponding host content; only trusted host configuration may disable this behavior. | | **SR-14** | State Anchor maintenance shall remain confined to the resolved Domain Root. Destructive maintenance shall require exclusive lifecycle ownership and an inactive, unmounted target. | ### 4.2 Functional Requirements | ID | Requirement | | :--- | :--- | | **FR-1** | Lazaret shall derive a stable Domain ID from the selected Agent Profile and canonical Agent Workspace. | | **FR-2** | Concurrent Client Sessions in one Domain shall share one coordinator, Agent Sandbox, Network Sidecar, and State Anchor. | | **FR-3** | Tracked and non-ignored workspace edits and supported Git operations shall propagate bidirectionally between host and sandbox. | | **FR-4** | Selected sandbox paths and Ignored Workspace State shall persist across Domain restarts without copying Lazaret host configuration into the sandbox. | | **FR-5** | The coordinator shall route each escalation prompt to the Client Session identified by the verified Session ID and deliver the correlated Escalation Result to the requesting Escalation Client. | | **FR-6** | The final Client Session leaving a Domain shall trigger teardown of transient Domain resources. | | **FR-7** | Startup and teardown shall recover safely from interrupted or stale prior executions without assuming that external runtime resources disappeared with their owner process. | | **FR-8** | Lazaret shall support interactive terminal sessions without degrading supported host terminal capabilities. | | **FR-9** | Trusted host configuration shall allow the developer to disable Git-ignored path isolation for an Agent Profile. | | **FR-10** | Session registration shall bind one authenticated Client CLI ID, Session ID, and Session Anchor, and escalation routing and approval shall preserve that binding. | | **FR-11** | The host CLI shall list, inspect, structurally verify, and reset all or selected State Anchors without requiring direct manipulation of Lazaret's storage layout. | ### 4.3 Developer-Experience Requirements | ID | Requirement | | :--- | :--- | | **DX-1** | A developer shall be able to launch an Agent Profile in the current workspace with one command. | | **DX-2** | Tools installed in configured persistent sandbox paths and dependencies stored in Ignored Workspace State shall remain available on later launches of the same Domain. | | **DX-3** | Normal source editing, `git status`, staging, committing, and reference updates shall work from inside the Agent Sandbox. | | **DX-4** | Escalation prompts shall identify the requesting profile, session, command, and justification without mixing terminal input or output between sessions. | | **DX-5** | Failures shall report actionable diagnostics and shall not leave the developer's terminal in a corrupted mode. | | **DX-6** | State inspection shall provide human-readable and machine-readable output without exposing persisted file contents by default, and reset shall show its resolved Domain and exact scope before confirmation. | ### 4.4 Operational Requirements | ID | Requirement | | :--- | :--- | | **OR-1** | The coordinator shall maintain exclusive runtime ownership of Domain resources. | | **OR-2** | Every accepted protocol request shall resolve to a delivered completed, denied, timed-out, cancelled, or failed result, unless its Client Session disconnects first. | | **OR-3** | Cancellation and process termination shall not strand an active host command or permanently block another Client Session. | | **OR-4** | Security-sensitive behavior shall be covered by integration tests on supported Podman, runsc, filesystem, and network configurations. Test evidence belongs in the journal. | | **OR-5** | An interrupted State Anchor reset shall recover to either the prior generation or a new empty generation; it shall not leave a partially reset active upper layer. |