docs: make the box narrative agent-agnostic, not Claude-specific #58

Merged
dan-claude-bot merged 3 commits from docs/agnostic-readme into main 2026-07-15 00:24:44 +00:00
4 changed files with 63 additions and 51 deletions

View file

@ -1,12 +1,13 @@
# box # box
**Headless, trust-less, throwaway dev VMs.** One command mints a fresh, **Headless, trust-less, throwaway dev VMs.** One command mints a fresh,
network-isolated Incus box from a **template**; the flagship template is network-isolated Incus box from a **template**; the coding-agent templates
`claude` — Debian 13 with Claude Code installed. The box is the product — ship a CLI agent on Debian 13 — `claude` (Claude Code), `codex` (OpenAI
you log in and work; destroying it loses nothing you didn't push. Codex), `grok` (xAI Grok). The box is the product — you log in and work;
destroying it loses nothing you didn't push.
**Strictly creds-free.** A box ships with everything installed and **no** **Strictly creds-free.** A box ships with everything installed and **no**
credentials — no Claude token, no git PAT, nothing. You authenticate credentials — no agent token, no git PAT, nothing. You authenticate
interactively *inside* the box. The tool never stores or injects a secret. That interactively *inside* the box. The tool never stores or injects a secret. That
means there's nothing shared or committed, so it's safe for multiple operators means there's nothing shared or committed, so it's safe for multiple operators
out of the box. out of the box.
@ -18,8 +19,8 @@ nobody home — not a box with the safety off.
**The tool knows nothing about your projects.** You just `git clone` inside a **The tool knows nothing about your projects.** You just `git clone` inside a
box. A repo can ship an optional [`.box/`](docs/box-recipe.md) box. A repo can ship an optional [`.box/`](docs/box-recipe.md)
runbook that Claude Code reads and acts on — there is no `install` step and no runbook that the box's coding agent reads and acts on — there is no `install`
host-run setup. See [docs/box-design.md](docs/box-design.md) for the step and no host-run setup. See [docs/box-design.md](docs/box-design.md) for the
design rationale. design rationale.
> **0.5.0**: two new templates (`codex`, `grok`), `box expose` — a > **0.5.0**: two new templates (`codex`, `grok`), `box expose` — a
@ -66,23 +67,26 @@ legacy box remains.
## Quick start ## Quick start
```sh ```sh
box new --name work --template claude # a creds-free Claude box (~10 min cold) box new --name work --template claude # a creds-free coding-agent box (~10 min cold)
box shell work # enter as the template's user box shell work # enter as the template's user
``` ```
Inside the box, authenticate as needed: Pick whichever coding-agent template you like — `claude`, `codex`, `grok` — or
`blank` for none. Inside the box, authenticate as needed. The `claude` template
looks like this; the others follow the same shape with their own login step:
```sh ```sh
claude # then run /login — copy the URL (press c), open it claude # then run /login — copy the URL (press c), open it
# in YOUR browser, paste the code back. No host CLI needed. # in YOUR browser, paste the code back. No host CLI needed.
gh auth login # or drop a PAT in — your git credentials, your call gh auth login # or drop a PAT in — your git credentials, your call
git clone https://github.com/you/project && cd project git clone https://github.com/you/project && cd project
claude # if the repo has .box/, Claude reads it and sets up claude # if the repo has .box/, the agent reads it and sets up
``` ```
## Templates ## Templates
The claude box is one template among several. What ships today: No coding agent is special — each is one template among several, and adding
another is just another directory. What ships today:
| Template | What's in it | | Template | What's in it |
| --- | --- | | --- | --- |
@ -122,7 +126,7 @@ box snapshot work authed # checkpoint after you've logged in
box new --name feature --from work/authed # clone the authed state into a new box box new --name feature --from work/authed # clone the authed state into a new box
``` ```
`--from` copies the whole box (Claude login, git creds, clones and all) while `--from` copies the whole box (agent login, git creds, clones and all) while
preserving isolation. You can also `box new --name x --from work` to clone preserving isolation. You can also `box new --name x --from work` to clone
a box's live state, or roll a box back with `box restore work authed`. a box's live state, or roll a box back with `box restore work authed`.
@ -233,8 +237,9 @@ enforces it, layer by layer:
that door only ever opens onto the host's own loopback (`127.0.0.1`), never that door only ever opens onto the host's own loopback (`127.0.0.1`), never
the network. the network.
The VM is the trust boundary: whatever runs inside — Claude, or anything a The VM is the trust boundary: whatever runs inside — the coding agent, or
template ships — can run arbitrary code and touch nothing you care about. anything a template ships — can run arbitrary code and touch nothing you care
about.
### Measured, not claimed ### Measured, not claimed
@ -265,9 +270,10 @@ inherit.
## Recipes: the `.box/` convention ## Recipes: the `.box/` convention
A repo that wants to be easy to stand up in a box ships an optional `.box/` A repo that wants to be easy to stand up in a box ships an optional `.box/`
folder — a runbook Claude reads and follows (install deps, start services, folder — a runbook the box's coding agent reads and follows (install deps,
template env, seed data, smoke-test). It is agent-facing documentation, not a start services, template env, seed data, smoke-test). It is agent-facing
host-executed script. See [docs/box-recipe.md](docs/box-recipe.md). documentation, not a host-executed script. See
[docs/box-recipe.md](docs/box-recipe.md).
## Uninstall ## Uninstall
@ -280,6 +286,6 @@ rm -rf ~/.local/share/box ~/.local/bin/box # the CLI itself
## Non-goals ## Non-goals
- **No unattended/CI bring-up.** The flow is interactive (log in, clone, ask - **No unattended/CI bring-up.** The flow is interactive (log in, clone, ask
Claude). Reproducible-by-construction provisioning is out of scope. the agent). Reproducible-by-construction provisioning is out of scope.
- **No credential storage or injection by the tool.** Boxes are creds-free; - **No credential storage or injection by the tool.** Boxes are creds-free;
snapshots are the reuse mechanism, not a secrets store. snapshots are the reuse mechanism, not a secrets store.

View file

@ -1,28 +1,30 @@
# box design # box design
`box` is a CLI that mints and manages **trust-less, network-isolated VMs `box` is a CLI that mints and manages **trust-less, network-isolated VMs
with Claude Code installed**. It is infrastructure, not a project provisioner. with a coding agent installed** (`claude`, `codex`, `grok`, or `blank` for
none). It is infrastructure, not a project provisioner.
See issue #3 for the full reframe and rationale. This doc captures the durable See issue #3 for the full reframe and rationale. This doc captures the durable
design decisions. design decisions.
## Principle: separate the tool from the agent ## Principle: separate the tool from the agent
- **The tool** mints isolated boxes with Claude installed but **unauthenticated**. - **The tool** mints isolated boxes with the agent installed but **unauthenticated**.
It knows nothing about projects, secrets, recipes, or memory. It knows nothing about projects, secrets, recipes, or memory.
- **The agent** (Claude Code, inside the box) reads an optional `.box/` - **The agent** (Claude Code, Codex, Grok — whichever template, inside the box)
runbook in a cloned repo and acts on it. The recipe's consumer is the reads an optional `.box/` runbook in a cloned repo and acts on it. The recipe's
reasoning agent, not host machinery. consumer is the reasoning agent, not host machinery.
## Boxes are strictly creds-free ## Boxes are strictly creds-free
`box new --name <n>` launches a blank box: everything installed, **no** `box new --name <n>` launches a blank box: everything installed, **no**
git credentials and **no** Claude credentials. The operator authenticates git credentials and **no** agent credentials. The operator authenticates
interactively *inside* the box: interactively *inside* the box:
- **Claude**`claude``/login` (paste-a-code OAuth: copy the URL, open it in - **The coding agent** — e.g. `claude``/login` (paste-a-code OAuth: copy the
your own browser, paste the code back). Works because the box is outbound-only; URL, open it in your own browser, paste the code back); `codex` and `grok`
the tool never handles a token. have their own login step. Works because the box is outbound-only; the tool
never handles a token.
- **Git** — the operator adds their own PAT / `gh auth login` inside the box. - **Git** — the operator adds their own PAT / `gh auth login` inside the box.
The tool stores and injects **no** credentials, ever. This dissolves the The tool stores and injects **no** credentials, ever. This dissolves the
@ -36,15 +38,16 @@ snapshots, not a secrets store:
- `box snapshot <n> [label]` — checkpoint after login + clone. - `box snapshot <n> [label]` — checkpoint after login + clone.
- `box new --name <n2> --from <src>[/<snapshot>]` — clone an existing box - `box new --name <n2> --from <src>[/<snapshot>]` — clone an existing box
or snapshot (authed state and all). Isolation is preserved: the clone keeps or snapshot (authed state and all). Isolation is preserved: the clone keeps
the `claude-dev` profile + `claudenet` + ACL. the `box-net` profile + `boxnet` + ACL.
- `box restore <n> <snapshot>` — roll a box back to a checkpoint. - `box restore <n> <snapshot>` — roll a box back to a checkpoint.
Log in once → snapshot → spin up authed boxes from it. Log in once → snapshot → spin up authed boxes from it.
## The box announces itself to the agent ## The box announces itself to the agent
cloud-init installs a global `~/.claude/CLAUDE.md` in every box telling Claude it cloud-init installs a global agent-context file in every coding-agent box
is running in a box (trust-less, ephemeral, creds-free) and to treat a (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, `~/.grok/AGENTS.md`) telling the
agent it is running in a box (trust-less, ephemeral, creds-free) and to treat a
repo's `.box/` folder as its bootstrap runbook. No "tell it" step, no host repo's `.box/` folder as its bootstrap runbook. No "tell it" step, no host
execution. execution.
@ -62,7 +65,7 @@ forever — and wrapping them one at a time grows a worse `incus`. The rule:
> **box owns a command when it must enforce an invariant Incus cannot see:** > **box owns a command when it must enforce an invariant Incus cannot see:**
> the `user.box=1` boundary (never touch an instance we didn't mint), the > the `user.box=1` boundary (never touch an instance we didn't mint), the
> isolation stack (`claude-dev` profile + `claudenet` + ACL), or the creds-free > isolation stack (`box-net` profile + `boxnet` + ACL), or the creds-free
> snapshot→clone workflow. Everything else is Incus's job. > snapshot→clone workflow. Everything else is Incus's job.
The rule cuts both ways, and that's the point: The rule cuts both ways, and that's the point:
@ -92,7 +95,7 @@ warns and proceeds — from there the trust boundary is yours to keep.
## Isolation ## Isolation
Dedicated NAT bridge `claudenet` + Incus `claude-isolate` ACL dropping all Dedicated NAT bridge `boxnet` + Incus `box-isolate` ACL dropping all
RFC1918/CGNAT/link-local egress, plus host-firewall rules blocking instance → RFC1918/CGNAT/link-local egress, plus host-firewall rules blocking instance →
host. Entry is `incus exec` over the local socket — no inbound path. The VM is host. Entry is `incus exec` over the local socket — no inbound path. The VM is
the trust boundary. the trust boundary.
@ -101,12 +104,12 @@ the trust boundary.
That last clause is the one that was assumed and turned out to be false, so it That last clause is the one that was assumed and turned out to be false, so it
is spelled out here with the mechanism, and `drill/` tests it on every run. is spelled out here with the mechanism, and `drill/` tests it on every run.
- **Box → host, LAN, RFC1918, CGNAT, link-local:** the `claude-isolate` ACL. - **Box → host, LAN, RFC1918, CGNAT, link-local:** the `box-isolate` ACL.
- **Box → box: an nftables *bridge-family* rule** (`host/box-firewall.sh`). - **Box → box: an nftables *bridge-family* rule** (`host/box-firewall.sh`).
It cannot be an ACL rule. Two boxes on one bridge share an L2 segment, so It cannot be an ACL rule. Two boxes on one bridge share an L2 segment, so
their frames are *switched* between bridge ports and never traverse the their frames are *switched* between bridge ports and never traverse the
netfilter path an L3 ACL lives on — the ACL looked airtight (it drops netfilter path an L3 ACL lives on — the ACL looked airtight (it drops
`10.0.0.0/8`, which contains `claudenet`) while box→box was in fact wide open. `10.0.0.0/8`, which contains `boxnet`) while box→box was in fact wide open.
A live probe found box A's SYN arriving at box B. The bridge family's forward A live probe found box A's SYN arriving at box B. The bridge family's forward
hook fires exactly on port-to-port frames, which on this bridge means box→box hook fires exactly on port-to-port frames, which on this bridge means box→box
and nothing else: gateway traffic and routed egress are delivered locally, not and nothing else: gateway traffic and routed egress are delivered locally, not

View file

@ -1,14 +1,15 @@
# The `.box/` convention # The `.box/` convention
`box` mints trust-less, creds-free, isolated VMs with Claude Code already `box` mints trust-less, creds-free, isolated VMs with a coding agent already
installed (`box new/shell/snapshot/restore/exec/down/start/rm/status`). The installed (`box new/shell/snapshot/restore/exec/down/start/rm/status`) — the
tool knows **nothing** about your project. There is no `install` step and no `claude`, `codex`, and `grok` templates each ship a CLI agent. The tool knows
host-run setup script. **nothing** about your project. There is no `install` step and no host-run
setup script.
A project makes itself easy to stand up inside a box by shipping an optional A project makes itself easy to stand up inside a box by shipping an optional
`.box/` folder. This folder is **agent-facing documentation** — read and `.box/` folder. This folder is **agent-facing documentation** — read and
acted on by Claude Code (the reasoning agent) running inside the box. It is not acted on by the box's coding agent (the reasoning agent) running inside the
shell that the host executes. box, whichever template you minted. It is not shell that the host executes.
> The folder was named `.claudebox/` before the 0.5.0 rename. Repos that still > The folder was named `.claudebox/` before the 0.5.0 rename. Repos that still
> ship `.claudebox/` keep working — the agent is told to read either — but new > ship `.claudebox/` keep working — the agent is told to read either — but new
@ -26,15 +27,17 @@ shell that the host executes.
## How it's consumed ## How it's consumed
Every box ships a global `~/.claude/CLAUDE.md` telling Claude it is inside a Every coding-agent box ships a global agent-context file — `~/.claude/CLAUDE.md`
box and to treat a repo's `.box/` folder as its bootstrap runbook. for `claude`, `~/.codex/AGENTS.md` for `codex`, `~/.grok/AGENTS.md` for `grok`
So the whole flow is: telling the agent it is inside a box and to treat a repo's `.box/` folder as its
bootstrap runbook. So the whole flow is (shown with `claude`; the other agents
follow the same shape):
``` ```
box new # get a box box new # get a box
box shell # get in box shell # get in
git clone <repo> && cd <repo> git clone <repo> && cd <repo>
claude # Claude reads .box/ and brings the project up claude # the agent reads .box/ and brings the project up
``` ```
The operator can also just say: *"set this project up per .box"*. The operator can also just say: *"set this project up per .box"*.
@ -45,9 +48,9 @@ Author everything here for a reasoning agent.
- **`.box/SETUP.md`** — the prose runbook. Prerequisites, how to install - **`.box/SETUP.md`** — the prose runbook. Prerequisites, how to install
deps, how to start services, how to template the env, how to seed data, and deps, how to start services, how to template the env, how to seed data, and
how to smoke-test. Written as instructions to Claude. how to smoke-test. Written as instructions to the agent.
- **Helper scripts** (e.g. `.box/dev-up.sh`) that the runbook tells Claude - **Helper scripts** (e.g. `.box/dev-up.sh`) that the runbook tells the agent
to run. Claude decides to run them; the host never does. to run. The agent decides to run them; the host never does.
- **`.box/env.template`** — example env the runbook explains how to fill. - **`.box/env.template`** — example env the runbook explains how to fill.
Staging values the operator pastes in. **Never commit real secrets.** Staging values the operator pastes in. **Never commit real secrets.**
- **`.box/compose.yml`** — optional services the runbook starts. - **`.box/compose.yml`** — optional services the runbook starts.
@ -70,7 +73,7 @@ This is a Node service backed by Postgres.
6. Smoke-test: `curl -sf localhost:3000/health` should return `{"ok":true}`. 6. Smoke-test: `curl -sf localhost:3000/health` should return `{"ok":true}`.
``` ```
That's it — Claude reads it top to bottom and adapts if reality differs. That's it — the agent reads it top to bottom and adapts if reality differs.
## Guidance ## Guidance
@ -79,4 +82,4 @@ That's it — Claude reads it top to bottom and adapts if reality differs.
- **Never put real credentials in `.box/`.** Templates and staging - **Never put real credentials in `.box/`.** Templates and staging
placeholders only. The operator pastes real values at runtime. placeholders only. The operator pastes real values at runtime.
- **No `.box/` is fine.** The operator can stand the project up by hand, - **No `.box/` is fine.** The operator can stand the project up by hand,
or let Claude infer the steps from the repo's `README` / `CLAUDE.md`. or let the agent infer the steps from the repo's `README` / `CLAUDE.md`.

View file

@ -84,9 +84,9 @@ a **design veto** for #16, caught before the code is written.
## What it does not check ## What it does not check
`claude /login` — it's interactive by design, and the box is creds-free by agent login (e.g. `claude /login`) — it's interactive by design, and the box is
design. The drill confirms Claude Code is installed and runnable; authenticating creds-free by design. The drill confirms each coding-agent template's CLI is
is yours. installed and runnable; authenticating is yours.
If the host has no `/dev/kvm`, box falls back to container mode. The drill If the host has no `/dev/kvm`, box falls back to container mode. The drill
still runs, but it says loudly that **the VM trust boundary was not validated** still runs, but it says loudly that **the VM trust boundary was not validated**