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

# seekrit

> Keep API keys out of boxd machines: resolve them with seekrit per command, at process start, or through a broker machine an isolated agent can reach and nothing else.

![The seekrit keyhole mark and wordmark inside the boxd card.](https://mintcdn.com/azin/2VTt2YrBC5krWL-J/images/boxd-x-seekrit.png?fit=max\&auto=format\&n=2VTt2YrBC5krWL-J\&q=85\&s=95e3ea1fe4752494cb55de017737e87d)

[seekrit](https://seekrit.dev) is a zero-knowledge secrets manager and credential broker for AI agents. It resolves secrets at the moment a process needs them, and its credential broker, `seekrit-proxy`, adds the real key to outgoing requests so an agent only ever holds a placeholder.

A boxd machine keeps its disk and memory across hibernate, fork and snapshot. That is what makes it useful for agents, and it is also why a key should not sit inside one: a `.env` file or a process's environment comes back with every fork and snapshot. seekrit's guide, [Secrets in boxd machines](https://seekrit.dev/docs/guides/sandboxes/boxd), covers three ways to keep it out.

## Pick a shape

| Workload | Where the key lives |
| - | - |
| A short-lived machine you drive yourself | On your side. Resolve with seekrit and pass the values per command. |
| A long-lived machine running your own code | One scoped `skt_` token on the machine. `seekrit-run` resolves at each process start, so a rotation lands on the next command. |
| A machine running an agent or code you don't trust | Nowhere inside it. The agent holds placeholders, and `seekrit-proxy` runs on a separate broker machine. |

## Inject per command

Resolve on your machine and hand the boxd machine only the names one command needs:

```python theme={"theme":"github-dark"}
import os

import seekrit
from boxd import Boxd

secrets = seekrit.Client(token=os.environ["SEEKRIT_TOKEN"]).resolve()
env = {k: secrets[k] for k in ("OPENAI_API_KEY", "TAVILY_API_KEY")}

boxd = Boxd()  # BOXD_API_KEY from the environment
result = boxd.machines.exec(os.environ["MACHINE_ID"], ["python3", "job.py"], env=env, cwd="/home/boxd/app")
print(result.exit_code, result.stdout)
```

The values live in that one process. They are not written to the machine's disk, and the next `exec` without `env` does not see them.

## Keep the key outside the machine

For an agent, run `seekrit-proxy` on a broker machine and let the agent machine reach the broker and nothing else:

```text theme={"theme":"github-dark"}
agent machine (isolated, egress: none)
  OPENAI_BASE_URL=http://seekrit-broker.boxd:7070/openai/v1
  OPENAI_API_KEY={{seekrit:OPENAI_API_KEY}}
        │  private network "seekrit"
        ▼
broker machine: seekrit-proxy, holds SEEKRIT_TOKEN
        │  real key added on the way out, only to api.openai.com /v1/**
        ▼
api.openai.com
```

Two boxd features enforce this, so it doesn't depend on the agent behaving:

* An [egress allowlist](https://docs.boxd.sh/guides/egress-allowlist.md) of `none` cuts the agent machine off from the internet. It is set from outside the machine, so root inside it can't change it.
* A [named network](https://docs.boxd.sh/guides/vm-to-vm.md) decides which machines an [isolated](https://docs.boxd.sh/guides/machine-specs.md) machine can reach. Put the broker and the agents on one, and an agent reaches the broker and none of your other machines.

```python theme={"theme":"github-dark"}
from boxd import Boxd, Machine

boxd = Boxd()

broker = boxd.machines.create("seekrit-broker", networks=["seekrit"])
boxd.machines.set_auto_hibernate_timeout(broker.id, 0)
boxd.machines.set_auto_suspend_timeout(broker.id, 0)

agent = boxd.machines.create(
    "agent-1",
    spec=Machine.spec()
    .isolated()
    .network("seekrit")
    .egress("none")
    .env({
        "OPENAI_BASE_URL": "http://seekrit-broker.boxd:7070/openai/v1",
        "OPENAI_API_KEY": "{{seekrit:OPENAI_API_KEY}}",
    }),
)
```

The agent's spec holds the placeholder, not the key. Keep the broker awake, since traffic from another machine on the private network does not wake a hibernated one.

Inside the agent machine, any client that takes a base URL works unchanged:

```bash theme={"theme":"github-dark"}
curl -s "$OPENAI_BASE_URL/models" -H "Authorization: Bearer $OPENAI_API_KEY"
```

The request reaches OpenAI with the real key. A request straight to `api.openai.com` doesn't resolve, and the agent's disk, environment and every fork or snapshot of it hold only the placeholder.

> [!WARNING]
>
> `seekrit-proxy` has no inbound authentication. Run it on a port the machine's public URL doesn't detect (7070 in the example, not 80, 443, 8080, 8000, 3000, 5000 or 5173), and don't put a [named proxy](https://docs.boxd.sh/guides/proxies.md) in front of it.

seekrit's guide has the full broker setup: `seekrit proxy init`, the token file, a systemd unit, forward mode for harnesses that ignore base URLs, and `seekrit-run` for long-lived machines.

## seekrit or boxd secrets

boxd has its own [env vars and secrets](https://docs.boxd.sh/guides/env-secrets.md), including host-bound secrets that a machine only sees as a `bxds_` placeholder. They suit values you keep in boxd. If your keys already live in seekrit, resolve them from there rather than keeping a second copy to rotate. `BOXD_API_KEY` itself can live in seekrit too:

```bash theme={"theme":"github-dark"}
seekrit run --app platform --env production -- python provision.py
```

## Read more

* [Secrets in boxd machines](https://seekrit.dev/docs/guides/sandboxes/boxd) on seekrit
* [seekrit credential broker](https://seekrit.dev/docs/guides/agent-proxy)
* [Sandboxes on boxd](https://docs.boxd.sh/use-cases/sandboxes.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.