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

# Concepts

> The core mental model for Declaw: sandbox microVMs, the envd daemon, the edge proxy security proxy, network namespaces, SecurityPolicy, and templates.

## System overview

When your code calls `Sandbox.create()`, the following sequence happens:

```mermaid theme={null}
sequenceDiagram
    participant SDK as Python / TS SDK
    participant API as API Server
    participant Orch as Orchestrator
    participant FC as sandbox VM
    participant Proxy as Security Proxy

    SDK->>API: POST /sandboxes (SecurityPolicy)
    API->>Orch: Create sandbox (policy)
    Orch->>Orch: Create network namespace
    Orch->>Orch: Set up veth pair + TAP device
    Orch->>Orch: Configure iptables REDIRECT rule
    Orch->>Proxy: Register policy for this sandbox
    Orch->>FC: Boot sandbox
    FC-->>Orch: envd ready on :49983
    Orch-->>API: Sandbox ID + envd endpoint
    API-->>SDK: SandboxInfo
```

Every subsequent SDK call — running commands, reading files, writing files — goes through the API server to envd running inside the VM. All outbound network traffic from the VM passes through the security proxy before reaching the internet.

***

## Sandboxes

A **sandbox** is a sandbox. It is the unit of isolation in Declaw.

Each sandbox has:

* An **independent rootfs** — a full copy of the base filesystem image. Changes made inside one sandbox are never visible in another.
* An **independent process tree** — there is no shared PID namespace between sandboxes or between a sandbox and the host.
* An **independent network namespace** — the sandbox has its own network stack, IP address, routing table, and iptables rules.
* A **configurable timeout** — the server destroys the sandbox when the timeout expires, even if the client process has crashed.

Sandboxes are ephemeral by design. When you call `sbx.kill()`, the VM is immediately destroyed and all data inside it is gone. If you need to persist state, write files out via `sbx.files.read()` before killing, or use [snapshots](/features/snapshots).

### Sandbox lifecycle

```
create() -> running -> (timeout or kill()) -> destroyed
                    -> pause() -> paused -> (resume) -> running
                    -> create_snapshot() -> snapshot stored
```

### SandboxInfo fields

| Field         | Type           | Description                                       |
| ------------- | -------------- | ------------------------------------------------- |
| `sandbox_id`  | `str`          | Unique identifier for the sandbox                 |
| `template_id` | `str`          | The base image used to boot this sandbox          |
| `name`        | `str`          | Human-readable sandbox name                       |
| `metadata`    | `dict`         | Arbitrary key-value pairs attached at creation    |
| `started_at`  | `datetime`     | When the sandbox started                          |
| `end_at`      | `datetime`     | When the sandbox is scheduled to end              |
| `state`       | `SandboxState` | `live`, `running`, `paused`, `creating`, `killed` |

***

## envd

**envd** is a lightweight HTTP daemon that runs inside every sandbox VM on port `49983`. It exposes three API groups:

* **Filesystem API** — read, write, list, watch files inside the VM
* **Process API** — run commands, stream stdout/stderr, send stdin, kill processes
* **PTY API** — open interactive terminal sessions

The SDK communicates with envd through the Declaw API server. You never talk to envd directly — the API server proxies requests and handles authentication and routing.

envd starts automatically as part of the VM boot process. The orchestrator waits for envd to become healthy before marking the sandbox as `running` and returning the sandbox ID to the SDK.

<Note>
  envd traffic between the API server and the VM travels over the private veth pair connecting the host to the network namespace. This traffic is never routed through the security proxy, so envd API calls are not subject to PII scanning or network policies.
</Note>

***

## Network namespaces

Every sandbox runs inside a dedicated Linux **network namespace**. This is the mechanism that provides network isolation between sandboxes and between sandboxes and the host.

The structure for a single sandbox looks like this:

```
Host network stack
  |
  |- veth0 (host side) <----> veth1 (namespace side)
                                    |
                                    |- TAP device
                                          |
                                          |- sandbox VM (eth0)
                                               |- Your code
```

The veth pair bridges the host network stack and the namespace. The TAP device connects the namespace to the VM's virtual NIC. The VM sees a normal network interface (`eth0`) and has no awareness that it is inside a namespace.

### Traffic routing

Outbound packets from the VM travel: VM eth0 -> TAP -> veth1 -> veth0 -> host. Before they reach the host's default route, an `iptables REDIRECT` rule intercepts them and sends them to the security proxy's listening port. The proxy inspects the packet, applies the sandbox's policy, and either forwards or drops the connection.

This REDIRECT rule is scoped to the sandbox's network namespace, so it only affects traffic from that specific sandbox.

***

## Security Proxy

The **security proxy** is a transparent TLS interceptor. It sits on the network path between every sandbox and the internet.

For **HTTP** traffic, the proxy reads the `Host` header to identify the destination.

For **HTTPS** traffic, the proxy reads the TLS SNI field during the handshake to identify the destination, then terminates the TLS connection, inspects the plaintext request body, applies security policies, and re-encrypts the traffic to forward it. The VM must trust the proxy's dynamically-generated certificate authority for this to work — the CA is installed in the VM rootfs at build time.

The proxy only activates full TLS interception when a `SecurityPolicy` that requires it is attached to the sandbox. Specifically, if `pii.enabled`, `injection_defense.enabled`, or any `transformations` are configured, TLS interception is active. Network-only policies (domain allowlists/denylists) are enforced at the TCP layer without decryption.

### Security pipeline

When TLS interception is active, each intercepted request passes through this pipeline:

```mermaid theme={null}
flowchart LR
    A[Intercepted request] --> B{Network policy\ncheck}
    B -- blocked --> C[Drop connection]
    B -- allowed --> D{PII scan}
    D -- PII found --> E[Redact / block\nper PIIConfig]
    D -- clean --> F{Injection\nscan}
    E --> F
    F -- injection detected --> G[Block / audit\nper InjectionConfig]
    F -- clean --> H[Apply\ntransformations]
    G -- audit mode --> H
    H --> I[Forward to\nexternal server]
    I --> J[Response\nrehydration]
    J --> K[Return to sandbox]
```

***

## SecurityPolicy

`SecurityPolicy` is the single object that configures all security controls for a sandbox. It is passed to `Sandbox.create()` and attached to the sandbox for its entire lifetime.

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from declaw import (
        SecurityPolicy,
        PIIConfig,
        InjectionDefenseConfig,
        NetworkPolicy,
        AuditConfig,
        TransformationRule,
        TransformDirection,
        ALL_TRAFFIC,
    )

    policy = SecurityPolicy(
        # PII scanning and redaction on outbound HTTP bodies
        pii=PIIConfig(
            enabled=True,
            types=["ssn", "credit_card", "email", "phone"],
            action="redact",            # "redact", "block", or "log_only"
            rehydrate_response=True,    # restore original values in responses
        ),

        # Prompt injection detection on LLM API calls
        injection_defense=InjectionDefenseConfig(
            enabled=True,
            action="block",             # "block" or "audit"
            threshold=0.8,              # detection confidence threshold
        ),

        # Domain-level network access control
        network=NetworkPolicy(
            allow_out=["api.openai.com", "pypi.org"],
            deny_out=[ALL_TRAFFIC],     # block everything not in allow_out
        ),

        # Regex-based request/response body transformations
        transformations=[
            TransformationRule(
                pattern=r"sk-[A-Za-z0-9]{32,}",
                replacement="[REDACTED_API_KEY]",
                direction=TransformDirection.REQUEST,
            )
        ],

        # Audit logging for all security events
        audit=AuditConfig(enabled=True),
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import {
      createSecurityPolicy,
      createPIIConfig,
      createInjectionDefenseConfig,
      createNetworkPolicy,
      createAuditConfig,
      createTransformationRule,
      PIIType,
      RedactionAction,
      InjectionAction,
      TransformDirection,
      ALL_TRAFFIC,
    } from "@declaw/sdk";

    const policy = createSecurityPolicy({
      // PII scanning and redaction on outbound HTTP bodies
      pii: createPIIConfig({
        enabled: true,
        types: [PIIType.SSN, PIIType.CreditCard, PIIType.Email, PIIType.Phone],
        action: RedactionAction.Redact,
        rehydrateResponse: true,
      }),

      // Prompt injection detection on LLM API calls
      injectionDefense: createInjectionDefenseConfig({
        enabled: true,
        action: InjectionAction.Block,
        threshold: 0.8,
      }),

      // Domain-level network access control
      network: createNetworkPolicy({
        allowOut: ["api.openai.com", "pypi.org"],
        denyOut: [ALL_TRAFFIC],
      }),

      // Regex-based request/response body transformations
      transformations: [
        createTransformationRule({
          pattern: "sk-[A-Za-z0-9]{32,}",
          replacement: "[REDACTED_API_KEY]",
          direction: TransformDirection.Request,
        }),
      ],

      // Audit logging for all security events
      audit: createAuditConfig({ enabled: true }),
    });
    ```
  </Tab>
</Tabs>

### SecurityPolicy fields

| Field               | Type                             | Default  | Description                                     |
| ------------------- | -------------------------------- | -------- | ----------------------------------------------- |
| `pii`               | `PIIConfig`                      | disabled | PII detection and redaction config              |
| `injection_defense` | `bool \| InjectionDefenseConfig` | `False`  | Prompt injection detection config               |
| `transformations`   | `list[TransformationRule]`       | `[]`     | Regex rewrite rules for request/response bodies |
| `network`           | `NetworkPolicy \| None`          | `None`   | Domain and IP access rules                      |
| `audit`             | `bool \| AuditConfig`            | `False`  | Security event audit logging                    |
| `env_security`      | `EnvSecurityConfig`              | default  | Env var masking and secret handling             |

***

## Templates

A **template** is the base filesystem image used when creating a sandbox. Templates allow you to pre-install dependencies, configure the environment, and avoid reinstalling packages on every sandbox creation.

The built-in `base` template is a minimal Ubuntu environment with Python 3, bash, curl, and common utilities. You can build custom templates from a `TemplateBase` specification that lists packages to install and files to copy.

Custom templates are built once and stored server-side. When a sandbox is created with `template="my-template"`, the orchestrator boots the VM from that template's rootfs snapshot instead of the default image.

See [Templates](/features/templates) for the full build API and `CopyItem` reference.

***

## ALL\_TRAFFIC constant

`ALL_TRAFFIC` is a sentinel value (`"0.0.0.0/0"`) used in network policies to represent all destinations. Use it in `deny_out` to create a default-deny policy:

```python theme={null}
from declaw import ALL_TRAFFIC, SecurityPolicy

policy = SecurityPolicy(
    network={"allow_out": ["api.openai.com"], "deny_out": [ALL_TRAFFIC]}
)
```

This allows connections to `api.openai.com` and blocks everything else. The `allow_out` list is evaluated before `deny_out`, so allowlist entries always take precedence.

***

## Further reading

* [Architecture overview](/architecture/overview) — detailed component diagram and data flow
* [Security Proxy internals](/architecture/security-proxy) — how TLS interception and the scanning pipeline work
* [Network packet flow](/architecture/packet-flow) — detailed trace of a packet from sandbox to internet
* [sandbox internals](/architecture/firecracker) — rootfs isolation, TAP devices, resource limits
