diff --git a/CHANGELOG.md b/CHANGELOG.md index 47c930c..4de7b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ which records not just what changed but what each drill run proved. ## Unreleased +### Added + +- `kimi-box` template — the Moonshot Kimi CLI agent seed (#158; rig#109's tenant) + ## 0.9.0 — 2026-07-21 ### Added diff --git a/README.md b/README.md index a8b89d4..8960b0c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **Headless, trust-less, throwaway dev VMs.** One command mints a fresh, network-isolated Incus box from a **template**; the coding-agent templates hand you a CLI agent on Debian 13 — `claude-box` (Claude Code), `codex-box` -(OpenAI Codex), `grok-box` (xAI Grok) — **box mints, [rig](https://github.com/heavy-duty/rig) +(OpenAI Codex), `grok-box` (xAI Grok), `kimi-box` (Moonshot Kimi) — **box mints, [rig](https://github.com/heavy-duty/rig) converges**: the template is a thin seed, and the agent tooling lands via a creds-free `rig bootstrap` role auto-run at mint ([#81](https://github.com/heavy-duty/box/issues/81)). The box is the product @@ -222,7 +222,7 @@ box shell work # enter as the template's user ``` Pick whichever coding-agent template you like — `claude-box`, `codex-box`, -`grok-box` — or `blank` for none. Inside the box, authenticate as needed. The +`grok-box`, `kimi-box` — or `blank` for none. Inside the box, authenticate as needed. The `claude-box` template looks like this; the others follow the same shape with their own login step: @@ -245,6 +245,7 @@ another is just another directory. What ships today: | `claude-box` | Claude Code, creds-free — where this project started | | `codex-box` | OpenAI Codex CLI, creds-free | | `grok-box` | xAI Grok CLI, creds-free | +| `kimi-box` | Moonshot Kimi CLI, creds-free | | `staging-box` | Server-class: docker + sshd hardening via rig; VM-only, autostarts | **Templates are thin seeds; rig does the becoming** @@ -256,7 +257,7 @@ pin tokens below). The seed is deliberately small — the tenant user, tmux, and [rig](https://github.com/heavy-duty/rig) preinstalled, nothing that joins a tailnet or admits credentials — and after cloud-init settles, box auto-runs the template's **creds-free** tenant role inside the guest -(`rig bootstrap claude-box` / `codex-box` / `grok-box` / `staging-box`, +(`rig bootstrap claude-box` / `codex-box` / `grok-box` / `kimi-box` / `staging-box`, [rig#31](https://github.com/heavy-duty/rig/issues/31); the roles carry a family suffix — `-box` for box tenants, `-server` for fleet machines — and a template is named for the role it converges, diff --git a/bin/box b/bin/box index f5ec84e..d4811f7 100755 --- a/bin/box +++ b/bin/box @@ -265,7 +265,7 @@ one of its snapshots — login state, git creds and clones carry over, isolation is preserved, and the clone knows its template's user without being told. -A tenant template (claude-box, codex-box, grok-box, staging-box) is a THIN seed — the user, +A tenant template (claude-box, codex-box, grok-box, kimi-box, staging-box) is a THIN seed — the user, tmux, rig (#81) — and after cloud-init box auto-runs the creds-free tenant role inside it ('rig bootstrap ', rig#31): that role installs the agent CLI / server posture and the agent-context file. rig is preinstalled diff --git a/docs/box-design.md b/docs/box-design.md index d4de7a9..46e7150 100644 --- a/docs/box-design.md +++ b/docs/box-design.md @@ -1,8 +1,8 @@ # box design `box` is a CLI that mints and manages **trust-less, network-isolated VMs -with a coding agent installed** (`claude-box`, `codex-box`, `grok-box`, or -`blank` for none). It is infrastructure, not a project provisioner. +with a coding agent installed** (`claude-box`, `codex-box`, `grok-box`, +`kimi-box`, 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 design decisions. @@ -94,7 +94,7 @@ A template is a **thin, creds-free seed** — base image, the tenant user, tmux, and [rig](https://github.com/heavy-duty/rig) preinstalled — and what the box *becomes* lives in rig's bootstrap roles (rig#31): box auto-runs the template's creds-free tenant role after cloud-init (`rig bootstrap claude-box` -/ `codex-box` / `grok-box` / `staging-box` — the roles carry a family suffix, +/ `codex-box` / `grok-box` / `kimi-box` / `staging-box` — the roles carry a family suffix, `-box` for box tenants and `-server` for fleet machines, and the templates are named for the roles they converge, rig#76), which installs the agent CLI or server posture. The split is deliberate: cloud-init is a first-boot one-shot — diff --git a/templates/kimi-box/box.env b/templates/kimi-box/box.env new file mode 100644 index 0000000..1af6657 --- /dev/null +++ b/templates/kimi-box/box.env @@ -0,0 +1,22 @@ +# The kimi-box template — a thin, creds-free seed (#81): Debian 13, the +# 'kimi' user, tmux and rig. What the box BECOMES — the Moonshot Kimi CLI, +# docker, the agent-context file with its #80 guard — is rig's job: +# box auto-runs 'rig bootstrap kimi-box' after mint (heavy-duty/rig#31, +# the role itself: heavy-duty/rig#109). +# The template is named for the role it converges, suffix and all +# (heavy-duty/rig#76): rig's roles carry a family suffix — '-server' for +# fleet machines, '-box' for box tenants — and a seed that named the bare +# 'kimi' would ask a post-rename rig for a role that no longer exists. +# KEY="value" only. Parsed against an allowlist, never sourced; there is no +# key for a network or a security flag, on purpose — the shared box-net +# profile is the placement contract and no template can weaken it. +# BOX_USER must match the user user-data.yaml creates (the duplication is +# deliberate and by hand) — and it is the tenant user the rig role converges +# (rig dies loudly if the seed did not create it). +BOX_DESCRIPTION="Moonshot Kimi CLI on Debian 13, creds-free — box mints, rig converges" +BOX_IMAGE="images:debian/13/cloud" +BOX_USER="kimi" +BOX_CPU="4" +BOX_MEMORY="8GiB" +BOX_DISK="60GiB" +BOX_BOOTSTRAP_ROLE="kimi-box" diff --git a/templates/kimi-box/user-data.yaml b/templates/kimi-box/user-data.yaml new file mode 100644 index 0000000..e86ba31 --- /dev/null +++ b/templates/kimi-box/user-data.yaml @@ -0,0 +1,33 @@ +#cloud-config +# A thin, creds-free seed (#81): the tenant user, tmux (#65), and rig — +# nothing that joins a tailnet or admits credentials, no agent CLI, no +# docker, no context-file heredoc. Everything this box becomes comes from +# 'rig bootstrap kimi-box' (heavy-duty/rig#31), which box auto-runs after +# mint; the agent-context file — including the #80 guard (never run +# 'box setup-host' or the drill inside a box) — is rendered by that role, +# once, instead of being copy-pasted per template. +users: + - name: kimi + shell: /bin/bash + sudo: "ALL=(ALL) NOPASSWD:ALL" + lock_passwd: true +package_update: true +# tmux: 'box tmux' runs 'tmux new-session' INSIDE the box (#65). +# curl + ca-certificates: the rig installer below rides them, and a bare +# cloud image is not guaranteed to ship either. +packages: + - tmux + - curl + - ca-certificates +runcmd: + # Preinstall rig so the box can converge — and re-converge — via + # 'rig bootstrap kimi-box'. @RIG_REPO@/@RIG_REF@ are the pin point (#81): + # box substitutes them at mint from the RIG_REPO/RIG_REF environment + # (default heavy-duty/rig @ main — unpinned, tracking main, the same + # honest edge as rig's own unpinned box install, until rig#32 ships a + # release flow). The pin covers both the installer fetched AND the tree + # it installs, so a branch under review is testable end to end. + # HOME=/root: cloud-init runs runcmd as root but with NO $HOME in the + # environment, and the rig installer (set -u) reads $HOME for its DEST — + # measured live: the mint died with "HOME: unbound variable" without it. + - curl -fsSL https://raw.githubusercontent.com/@RIG_REPO@/@RIG_REF@/install.sh | HOME=/root RIG_REPO="@RIG_REPO@" RIG_REF="@RIG_REF@" bash