# Containarium

> Open-source agent runtime — SSH-native isolation, eBPF egress policy, Kubernetes + LXC backends, GPU passthrough, MCP-native CLI

- **Type:** MCP server
- **Install:** `agentstack add mcp-footprintai-containarium`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [FootprintAI](https://agentstack.voostack.com/s/footprintai)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [FootprintAI](https://github.com/FootprintAI)
- **Source:** https://github.com/FootprintAI/Containarium
- **Website:** https://containarium.dev

## Install

```sh
agentstack add mcp-footprintai-containarium
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Containarium — Agent Runtime

> **Open-source agent runtime** · SSH-native isolation · eBPF egress policy · Kubernetes + LXC · MCP-native CLI · GPU passthrough

**The open-source, self-hostable agent runtime for AI agents.**
Each agent gets a persistent, SSH-reachable box with per-tenant network isolation — no kube-apiserver token, no host access, no cross-tenant leakage.

Bring your own agent — Cursor, Claude Code, OpenCode, your own MCP client.
We run the box.

```
agent: "create me a sandbox called 'blog'"           → containarium create
agent: "wire up SSH so I can reach it"               → containarium ssh-config sync
agent: "install Caddy on :8080 inside the box"       → shell_exec (via agent-box MCP)
agent: "expose that on blog.example.com"             → containarium expose-port

curl https://blog.example.com → hello world
```

[](LICENSE)
[](go.mod)

[](https://youtu.be/IBDDD_tb8FY)

🌐 **Project site:** [containarium.dev](https://containarium.dev) · 🎬 **55s demo:** [youtu.be/IBDDD_tb8FY](https://youtu.be/IBDDD_tb8FY) · 🚀 **Live app:** [helloworld.demo.containarium.dev](https://helloworld.demo.containarium.dev)

---

## Why an agent runtime?

AI agents are increasingly the primary user of dev infrastructure. They
want to build, install, deploy, and verify — not on the human's laptop
(too noisy, too risky, too local) but on a persistent, isolated runtime that's:

- **Persistent**: state survives between agent runs.
- **Isolated**: a misbehaving install doesn't touch your machine or your cluster.
- **Real**: a full Linux environment with `systemd`, real networking,
  and the ability to host things on the open internet.
- **Driven by structured tools**: not by an agent typing commands into a
  TTY hoping nothing scrolls off-screen, but by MCP — typed,
  bounded, safe.
- **Blast-radius-bounded**: the agent holds an SSH key, not a
  kube-apiserver token. It can't reach the cluster control plane, the
  host OS, or other tenants' boxes.

That's the runtime Containarium gives you. It runs as a self-hosted
platform on LXC or Kubernetes, exposes its admin surface over MCP, and
ships a second MCP server that lives *inside* the box so the agent can
`shell_exec` and edit files directly.

You bring the agent. We run the box.

---

## Quick start

### 1. Self-host on a fresh Ubuntu VM (5 minutes)

```bash
curl -fsSL https://raw.githubusercontent.com/footprintai/containarium/main/hacks/install.sh \
  | sudo bash
```

That installs Containarium + Incus + dependencies, starts the daemon,
and gives you a working API at `http://localhost:8080`.

### 2. Create your first box

```bash
sudo containarium create alice --ssh-key ~/.ssh/id_ed25519.pub
sudo containarium list
```

### 3. Wire up SSH so `ssh alice` just works

```bash
containarium ssh-config sync
# Adds entries to ~/.containarium/ssh_config.
# Then add ONE line to ~/.ssh/config:
#     Include ~/.containarium/ssh_config
ssh alice  # connects through the sentinel
```

### 4. Point your agent at the box

In `~/.cursor/mcp.json` or `~/.claude.json`:

```jsonc
{
  "mcpServers": {
    "containarium-box": {
      "command": "ssh",
      "args": ["alice", "agent-box"]
    }
  }
}
```

Now Claude Code, Cursor, or any MCP-speaking agent can call
`shell_exec`, `read_file`, `write_file`, `list_directory`,
`move_file`, `delete_file` directly inside Alice's container.

### 5. Make it reachable on a public hostname

```bash
containarium expose-port alice \
  --container-port 8080 \
  --domain blog.example.com
```

Caddy on the sentinel terminates TLS for `blog.example.com` and
forwards to `alice-container:8080`. `curl https://blog.example.com`
hits whatever Alice has serving on port 8080.

---

## The four primitives

Every action in Containarium has a CLI verb (canonical) AND an MCP tool
(thin wrapper that delegates to the same Go function). See
[CLAUDE.md](CLAUDE.md) for the convention.

### `agent-box` — in-the-box MCP server

Runs inside every container. Reached over stdio (typically wrapped by
SSH on the client side). Exposes Linux-native operations:

| Tool | What it does |
|---|---|
| `shell_exec` | Run a shell command, capture stdout/stderr/exit, bounded by timeout (default 30s, max 10min) and 256 KiB output cap |
| `read_file` | Byte range OR `head=N` lines OR `tail=N` lines |
| `write_file` | Atomic write with `mkdirp` (temp + rename) |
| `list_directory` | Type/size/mtime, hidden filtering |
| `move_file` | Atomic rename with `mkdirp` on destination |
| `delete_file` | Single-file remove (refuses directories so recursive deletes go via `shell_exec` where blast radius is explicit) |

Resources (read-only data the agent fetches via MCP `resources/read`):

| URI | What it returns |
|---|---|
| `containarium://ci-context` | JSON metadata about the current CI run (PR number, commit SHA, failing test, etc.) when the box was kept alive by the FootprintAI/containarium-run GitHub Action after a failed CI run. Returns `{"available": false}` on non-CI boxes so callers never have to special-case errors. |
| `containarium://ci-prompt` | Static markdown playbook telling agents how to debug a failing CI run inside this box (what to read first, how to iterate, what not to do). Same body on every box; pair with `ci-context` for the per-run data. |

Optional sandbox: when `AGENTBOX_ROOT` is set, every file-ops path is
resolved against that root with a boundary-aware prefix check. Default
unset = no constraint. See
[`internal/agentbox/`](internal/agentbox/) for the Go implementation.

### `mcp-server` — platform MCP server

Runs on the host. Exposes outside-the-box admin operations:
`create_container`, `list_containers`, `delete_container`,
`start_container`, `stop_container`, `expose_port`, `get_metrics`,
`get_system_info`. See [`cmd/mcp-server/`](cmd/mcp-server/).

### `containarium` CLI

Same surface as the platform MCP, plus deeper administration. Top-level
verbs:

```
containarium create        Create a new container
containarium list          List all containers
containarium delete        Delete a container
containarium expose-port   Expose container:port on a public hostname
containarium ssh-config    Generate self-contained ssh_config
containarium route         Manage proxy routes (low-level)
containarium passthrough   Manage TCP/UDP passthrough rules
containarium token         Issue JWT tokens for the API
containarium info          System info
containarium version       Print version
```

Run `containarium  --help` for full options.

### Sentinel — sshpiper + Caddy + PROXY-protocol

The sentinel is a tiny always-on VM (e2-micro on GCP free tier works)
that:

- Receives SSH on port 22 (sshpiper routes to the right backend by
  username).
- Receives HTTPS on 443 (Caddy with TLS-passthrough or
  PROXY-protocol-aware forwarding to backend Caddy).
- Survives spot-VM termination on the backend with a maintenance page.
- Holds the static IP / DNS A-record so backends can be ephemeral.

See [docs/SENTINEL-DESIGN.md](docs/SENTINEL-DESIGN.md) for the full
design.

---

## Architecture

```
        Agent (Cursor / Claude Code / OpenCode)
            │
            │ JWT (access; tt=access, jti, scopes)
            │ MCP over stdio  ──┐
            │                   │ ┌── refresh ──> POST /v1/tokens/refresh
            v                   ▼ │                  (single-use; old jti revoked)
        ssh user@box  → sshpiper → agent-box (in container)
            │
            │ HTTPS  (mTLS upstream; PROXY-protocol v2)
            v
        Sentinel (e2-micro, always-on)
        ├── sshpiper (port 22)            : routes by username; fail2ban per-user
        ├── Caddy + PROXY-protocol (443)  : routes by hostname / SNI suffix
        └── /wake/ source-IP allowlist    : trusted-proxy only
            │
            v
        +-------------------------------------------------+
        | Backend VM (spot or bare-metal GPU node)        |
        |                                                 |
        |  Incus (LXC) ── containers                      |
        |    ├── alice-container    : SSH + agent-box     |
        |    │   └── /run/secrets/* : tmpfs, 0440 alice   |
        |    └── bob-container      : ZFS-backed storage  |
        |                                                 |
        |  Containarium daemon                            |
        |    ├── JWT auth (iss/aud/jti/scopes)            |
        |    ├── Admin RBAC + container-owner authz       |
        |    ├── Image-digest gate (REQUIRE + VERIFY)     |
        |    ├── Secrets ── Postgres (envelope-encrypted) |
        |    │              │                             |
        |    │              v                             |
        |    │           KMS ── Vault Transit / GCP KMS   |
        |    │           (master key retirable post-cutover)
        |    └── Audit log ── Postgres + SHA-256 hash     |
        |                     chain (verify CLI)          |
        +-------------------------------------------------+
```

A single sentinel can front multiple backend VMs — a "pool" — and a
single deployment can run multiple pools (each isolated). See
[docs/MULTI-POOL.md](docs/MULTI-POOL.md).

**Security control surface** (all opt-in via env, default-off for
upgrade safety; see [`docs/security/OPERATOR-SECURITY-RUNBOOK.md`](docs/security/OPERATOR-SECURITY-RUNBOOK.md)):

| Env var | Layer | Effect |
| --- | --- | --- |
| `CONTAINARIUM_REQUIRE_IMAGE_DIGEST=true` | API | refuse images without `@sha256:` |
| `CONTAINARIUM_VERIFY_IMAGE_DIGEST=true` | API | verify digest against the registry index (pre- + post-pull) |
| `CONTAINARIUM_ALLOWED_IMAGE_REGISTRIES` | API | restrict which simplestreams remotes the daemon will pull from |
| `CONTAINARIUM_KMS_BACKEND={none,inproc,vault,gcp}` | Secrets | envelope-encrypt DEKs through an external KMS |
| `CONTAINARIUM_REQUIRE_ENVELOPE=true` | Secrets | refuse legacy master-key-only rows (Phase E retirement gate) |
| `CONTAINARIUM_POSTGRES_URL_FILE` / `_PASSWORD_FILE` | Secrets | DB creds from disk rather than env |
| `CONTAINARIUM_WAKE_TRUSTED_PROXIES` | Sentinel | source-IP allowlist for `/wake/` |
| `OTEL_BEARER_REQUIRED=true` | Telemetry | collector rejects un-bearered OTLP submissions |

---

## How it's different

### vs. SaaS-only sandboxes (e2b, Modal, Replit)

These give you sandboxes for AI agents, but only as hosted SaaS:

- **Self-hostability**: Containarium runs on your own infrastructure
  (a $5 VM, your homelab, your enterprise data center). e2b, Modal,
  and Replit are SaaS-only — your code, your data, and your customers
  go through their compute.
- **License**: Apache 2.0, no CLA. Fork it, sell it, run it.
- **Surface**: full Linux containers with `systemd`, real network
  namespaces, GPU passthrough. Not a process-per-call sandbox.
- **Transport**: MCP-native from day one, not a custom SDK with MCP
  bolted on.

### vs. Docker AI Sandboxes (`sbx`)

Docker's `sbx run claude` and Containarium both call themselves
"AI sandboxes," but they sit on opposite ends of the same spectrum:

- **Locality**: `sbx` runs the sandbox on the developer's laptop
  (microVM, host-isolation). Containarium runs the sandbox on a VM
  you host (LXC, multi-tenant, public-internet reachable via the
  sentinel).
- **Persistence**: `sbx` is session-shaped (workspace mount, no
  documented "give me a box that survives reboot and has a
  hostname"). Containarium containers persist indefinitely, with
  ZFS snapshots and 30-day retention.
- **Public reach**: `containarium expose-port alice --domain
  blog.example.com` is one verb. `sbx` is laptop-local; no
  public-hostname story.
- **Agent surface**: `sbx` is CLI-first (`sbx run `).
  Containarium is MCP-native — two MCP servers (in-the-box
  `agent-box` + platform `mcp-server`) plus the same surface via
  CLI, SSH, REST/gRPC, and a web UI.
- **License**: `sbx` CLI is free; team policy (Docker Admin Console)
  is a paid subscription. Containarium is Apache 2.0 — including
  the audit log, RBAC, KMS integrations, and everything else on
  this page.

If you're stopping an agent from `rm -rf`-ing the laptop it's
running on, `sbx` is the lighter tool. If you're giving your agent
(or your customer's agent) a persistent Linux box on the public
internet, Containarium is the shape.

### vs. OSS Kubernetes agent runtimes (agent-sandbox, OpenShell)

[`kubernetes-sigs/agent-sandbox`](https://github.com/kubernetes-sigs/agent-sandbox)
and [`NVIDIA/OpenShell`](https://github.com/NVIDIA/OpenShell) are the
closest open-source peers on Kubernetes:

- **SSH-native vs. exec-based**: both agent-sandbox and OpenShell reach
  the sandbox via `kubectl exec` or a proprietary client, which requires
  the agent to hold a kube-apiserver token or cluster credentials.
  Containarium reaches the pod over SSH through sshpiper — the agent has
  no path to the cluster control plane at all.
- **MCP-native**: agent-sandbox and OpenShell expose REST APIs or custom
  SDKs. Containarium's `agent-box` MCP server runs *inside* the box,
  reachable over SSH stdio — any MCP-speaking agent (Claude Code, Cursor,
  OpenCode) works with zero client library.
- **LXC + K8s, one CLI**: Containarium runs on either Incus/LXC or
  Kubernetes behind the same `containarium` CLI and `--runtime` flag. You
  switch backends without changing anything for the agent.
- **eBPF egress policy**: Containarium enforces per-tenant egress
  allowlists at the kernel level via TC_INGRESS eBPF programs.
  agent-sandbox has NetworkPolicy; OpenShell has eBPF but is
  NVIDIA-stack-specific. Neither offers a portable, per-tenant eBPF
  allowlist across LXC and K8s backends.

### vs. dev environment platforms (Codespaces, Gitpod, Coder)

Those are persistent IDEs. Containarium is a persistent **box** —
agent-driven, not developer-driven, no IDE assumption, SSH-as-the-API:

- Containarium environments are reached by SSH and MCP. Any IDE works
  (Vim, JetBrains Remote, VS Code Remote, Cursor's remote dev — your
  call).
- Cost: no per-hour billing in the OSS path. Self-host costs are just
  your underlying VM.
- Persistence: containers survive indefinitely; Codespaces auto-delete
  after inactivity.

### vs. application container platforms (Docker, Kubernetes)

LXC is a **system** container, not an application container. Each
container has `systemd`, a real init, real users, real package managers,
real `sudo`. You can run Docker *inside* a Containarium container; the
reverse isn't really a thing.

If your agent is going to `apt install` half a Linux distro, edit
config files in `/etc`, run a database, and reboot — LXC is the right
shape. If your agent runs a single Python process, Docker or Modal is
fine.

It isn't either/or: Containarium can run a box *as a pod* in a
Kubernetes cluster you already operate — same SSH-native agent contract,
no kube-apiserver token in the agent's hands. Switch with
`--runtime=k8s`. See the **Kubernetes backend** section below.

---

## What's in the box

Beyond the agent-native primitives, Containarium ships:

### Multi-OS

- **Ubuntu 24.04 LTS** (default)
- **Rocky Linux 9** (dev/test)
- **RHEL 9** (production)
- **Windows Server VMs** via QEMU/KVM with RDP — see
  [docs/WINDOWS-VM-SETUP.md](docs/WINDOWS-VM-SETUP.md)

### GPU passthrough

For ML/AI agent workflows. Works with NVIDIA RTX 3090, RTX 4090, and
similar. PCI-level passthrough so the container sees the GPU directly.
Tested on bare-metal GPU nodes connected to the sentinel via tunnel.

### Multi-backend

A single sentinel can front:

- **GCP spot VMs**: cost-effective cloud backends with auto-recovery
  on preemption.
- **Bare-metal GPU nodes**: any Linux box you can SSH to; reaches the
  sentinel via outbound tunnel.
- **Windows VMs**: live alongside Linux backends.

All containers from all backends appear in a single unified API.

### Kubernetes backend (experimental)

Beyond the LXC/Incus backend, Containarium can run a box as a **pod in a
Kubernetes cluster you already operate** — reached over SSH exactly l

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [FootprintAI](https://github.com/FootprintAI)
- **Source:** [FootprintAI/Containarium](https://github.com/FootprintAI/Containarium)
- **License:** Apache-2.0
- **Homepage:** https://containarium.dev

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-footprintai-containarium
- Seller: https://agentstack.voostack.com/s/footprintai
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
