Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kimi-run9-kaos

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:

  1. kimi_run9.run9 — synchronous lifecycle wrappers around the run9 CLI (create_box, exec, exec_bg, stop_box, snapshot, restore, mount_workspace). KAOS does not own box lifecycle; this layer does.
  2. kimi_run9.kaos.Run9Kaos — async KAOS Protocol implementation (pathclass, readbytes, writetext, exec, ...). Drop into the standard set_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.

Why Run9 (vs other KAOS backends)

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 stop and 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 + restore from 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 as name.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/drive9 so 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 work

When 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.

Install

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.

Quick start

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())

Failure injection (M1 run9-only recovery recipe)

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 snapshot

Tests

python3 -m unittest discover -s tests -v
  • tests/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.

Status

  • run9 lifecycle wrappers — done
  • Run9Kaos KAOS 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

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages