Run9 KAOS backend for Kimi Agent SDK: execute Kimi agent filesystem and shell operations inside remote run9 sandboxes.
This repository provides a Run9 backend shaped for the Kimi Agent SDK KAOS examples. It is designed to fit alongside the existing BoxLite, E2B, and Sprites backends without asking Kimi SDK to adopt a new abstraction.
Two layers:
kimi_run9.run9— synchronous lifecycle wrappers around therun9CLI (create_box,exec,exec_bg,stop_box,snapshot,restore,mount_workspace). KAOS does not own box lifecycle; this layer does.kimi_run9.kaos.Run9Kaos— async KAOS Protocol implementation (pathclass,readbytes,writetext,exec, ...). Drop into the standardset_current_kaos(...)flow so Kimi Agent SDK tools route transparently to a running run9 box.
This package is intentionally scoped to box lifecycle plus KAOS routing. It is the M1 quick-demo layer for Kimi Agent SDK + Run9: prove that SDK file and shell operations can run inside a remote Run9 sandbox, and that Run9 snapshot/restore can recover a failed box. Production workspace and evidence-bundle features can be layered later through Drive9; they are not required to use the KAOS backend.
The M1 demo should run from a clean base image. Do not use the earlier OpenClaw+Drive9 image for this package.
Recommended clean base:
public.ecr.aws/docker/library/node:24-bookworm
This image already includes Node.js, npm, Python 3, and git in a small Debian environment, and keeps the Run9 KAOS backend demo independent of OpenClaw and Drive9.
Run9 sits in the same KAOS shape as BoxLite, E2B, and Sprites — the SDK stays
on the host, KAOS routes filesystem and shell calls into a remote sandbox.
Switching from BoxLite/E2B/Sprites to Run9 is a one-line set_current_kaos(...)
swap.
What Run9 adds for longer-running engineering agents:
- Persistent box rootfs. A Run9 box keeps its filesystem across
stopand restart. The agent's repo checkout, package caches, build outputs, and intermediate state survive as long as the box or a derived snap is retained. snapshot+restorefrom stopped checkpoints.run9.snapshot(from_box=...)forks the stopped box's full filesystem into a new snap;run9.restore(...)creates a fresh box from that snap without rebuilding the image or dependency cache from scratch. This is what makes M1 "Kimi agent's sandbox died — keep going" recovery a real CLI flow, not an exercise left to the harness.- Long-running background services.
exec_bg(..., service=("name", port))exposes the box-side process on an org-internal endpoint such asname.svc.run9.internal:30000. Useful for agents that boot a dev server, a Jupyter kernel, or a long evaluator and need to reach it across exec calls. - Org-private service exposure. Service endpoints are reachable within the Run9 org without creating public DNS or public ports. This is a useful default for enterprise-style demos that need private dev servers, evaluators, or notebooks.
- Bring-your-own OCI image. Any image Run9 can pull (Public ECR, GHCR,
Docker Hub) is a valid base. Same
create_box(image=...)shape; no proprietary image format. - Optional Drive9 workspace mount (M2).
run9.mount_workspace(...)mounts a Drive9 workspace at/work/drive9so evidence bundles, patches, and handoff artifacts survive box deletion and can be reviewed outside the sandbox. Run9 persistence is per-sandbox; Drive9 adds cross-sandbox evidence handoff for M2 cases where multiple boxes or outside reviewers need the same artifact set. M1 quick-demo does not require this.
Persistence in 30 seconds:
box = create_box("demo", image="public.ecr.aws/docker/library/node:24-bookworm")
exec_in_box(box.id, ["/bin/sh", "-lc", "echo 'agent did work' > /work/state.txt"])
stop_box(box.id)
snap = snapshot(from_box=box.id)
resumed = restore("demo-resumed", snap.id)
exec_in_box(resumed.id, ["/bin/sh", "-lc", "cat /work/state.txt"])
# -> agent did workWhen to pick which backend:
| Backend | Best for |
|---|---|
| BoxLite | Local development, fast iteration, single laptop. |
| E2B | Remote cloud sandbox workloads and short-lived tool runs. |
| Sprites | Persistent cloud workspace per user. |
| Run9 | Long-running engineering agents that need persistent rootfs, snapshot recovery, and org-private services. M1 box kill/resume + (M2) Drive9 evidence layer. |
The intent is not to replace the existing backends; it is to give Kimi Agent SDK an option for the production-shaped workloads where rootfs persistence and snapshot/restore are the load-bearing primitives.
This is not yet on PyPI; install editable from the source tree:
pip install -e .Run9Kaos itself has no runtime dependencies. The optional [demo] extra
pulls in kimi-agent-sdk for downstream orchestration experiments; [dev]
pulls in test tooling.
import asyncio
from kimi_run9 import create_box, stop_box
from kimi_run9.kaos import Run9Kaos
async def main() -> None:
box = create_box(
"kimi-run9-demo-001",
image="public.ecr.aws/docker/library/node:24-bookworm",
shape="2c4g",
)
try:
kaos = Run9Kaos(box.id, home_dir="/root", cwd="/work/repo")
# Once you `set_current_kaos(kaos)` from `kaos` (the pip package),
# `prompt(...)` / `Session(...)` from kimi-agent-sdk will route tool
# calls to this box.
proc = await kaos.exec("ls", "/work")
out = await proc.stdout.read()
print(out.decode())
finally:
stop_box(box.id)
asyncio.run(main())from kimi_run9 import create_box, exec_in_box, stop_box, snapshot, restore
baseline = create_box(
"kimi-run9-base",
image="public.ecr.aws/docker/library/node:24-bookworm",
)
exec_in_box(baseline.id, ["/bin/sh", "-lc", "git clone https://... /work/repo"])
exec_in_box(
baseline.id,
["/bin/sh", "-lc", "echo 'step 3 of 7' > /work/state.txt"],
)
stop_box(baseline.id)
snap = snapshot(from_box=baseline.id)
resumed = restore("kimi-run9-resume", snap.id)
exec_in_box(resumed.id, ["/bin/sh", "-lc", "pytest"]) # picks up state from Run9 snapshotpython3 -m unittest discover -s tests -vtests/test_run9.py— subprocess mock unit tests for the lifecycle layer.tests/test_kaos.py— KAOS Protocol shape + async behavioural tests for the adapter. Live smoke against a real run9 box is intentionally separate from unit tests and should use a short-lived Run9 credential. Do not commit credentials or box IDs.
run9lifecycle wrappers — doneRun9KaosKAOS Protocol adapter — done- Unit tests for both layers — done (38/38 passing)
- Mock failure-injection demo — done (
examples/failure_inject_demo.py) - Live smoke against a real run9 box — pending
- Kimi Agent SDK end-to-end integration — pending
- Drive9 workspace contract (M2 scope) — separate package