Agent SDK

The alineo package runs Pi coding agents inside sandbox containers — start an agent from a spec, prompt it, steer it mid-turn, spawn children from it, and pick it back up after your process dies or its container is gone.

alineo runs an AI coding agent inside a sandbox container. An agent is a spec and a prompt:

import { Alineo, textOnly } from "alineo";
import { SQLiteAdapter } from "@alineo-labs/sqlite";

const agent = await Alineo.start(
  {
    name: "hello",
    harness: "pi",
    provider: "nvidia",
    model: "nvidia/nemotron-3-super-120b-a12b",
    env: { NVIDIA_API_KEY: "${NVIDIA_API_KEY}" },
  },
  { adapter: new SQLiteAdapter("./.alineo/ledger.db") },
);

for await (const chunk of textOnly(agent.prompt("Write and run a Python hello world."))) {
  process.stdout.write(chunk);
}

The agent installs packages, clones repositories and runs what it writes — inside the container, never on your machine. Quickstart →

It starts in seconds

The first start() installs the Pi CLI into a node:22 sandbox and snapshots it. Every start after that restores the snapshot instead: ~3 seconds rather than ~90. The cache key is the spec's harness version, packages and setup steps, so it invalidates itself when it should — setup snapshots.

Your process is not the agent

The agent lives in the container, not in your Node process. Kill the process, come back tomorrow, pick the same agent back up:

const agent = await Alineo.reattach(sandboxId, { adapter });

The bridge inside the container is never restarted, so a turn that was running when your process died is still running. If the container itself is gone — deleted, or left Exited by a reboot — reattach() restores the agent onto a fresh one from its last turn checkpoint instead of failing — reconnecting and restoring.

Steer it mid-turn

await agent.steer("Focus only on the auth path — drop the unrelated findings.");

The message lands after the current tool call finishes and before the next model call. The agent does not restart and does not lose its context. followUp() queues the next turn instead, and abort() stops this one now — steering.

Gate what it can do

Every tool call the agent wants to make can be held for a decision — yours, or a policy's:

agent.prompt(task, {
  onPermission: (req) =>
    req.tool === "bash" && req.target.startsWith("rm ")
      ? { kind: "reject", feedback: "Deleting files is out of scope." }
      : { kind: "once" },
});

reject hands the feedback back to the model as the reason. Leave onPermission off and the requests surface on the stream instead, for a human to resolve with agent.resolvePermission() — the permission gate.

Spawn a child from a live agent

const reviewer = await agent.spawn("./agents/reviewer.json");

spawn() forks the parent's live sandbox, so the checkout, the installed packages and the files the parent wrote are already on the child's disk. Clone a repository once and review it three ways at the same time.

For more than a couple of children — budgets, waitFor gathering, one event stream for the whole tree, recovery when the host dies — that's alineod, which drives this SDK in-process and exposes it over HTTP.

Everything is on the record

The adapter on start() isn't bookkeeping you can skip. Every exec, tool call and state transition is appended to a SQLite or Postgres ledger before anything derived from it is updated, and that is what makes the rest work: reattach() finds the agent again, a restore finds its latest checkpoint, and an auditor gets the whole session rather than a summary of it.

Where this sits

The Agent SDK runs one agent on top of the Core SDK's sandboxes — agent.sandbox is a live SandboxHandle for anything Pi doesn't cover. alineod runs trees of these agents, and the alineo CLI drives them from a shell.