Skip to content
Français

Extend Outpost

Find the contract to implement when adding an agent, sandbox, model service, store or queue.

An agent adapter describes the command and decodes its output. A sandbox provider executes that command. Keeping these responsibilities separate lets the same adapter work with different providers.

import { createAgent, dispatch, type AgentAdapter } from "@elie-laloum/outpost";
import { repository, sandboxProvider } from "./outpost.config.ts";

const mycli: AgentAdapter = {
  name: "mycli",
  request: ({ text }) => ({
    executable: "mycli",
    arguments: ["--json"],
    stdin: text ?? "",
  }),
  events: (line) => [{ kind: "text", text: line }],
};

await dispatch({
  agent: createAgent({ harness: { kind: "cli", bind: () => mycli } }),
  sandboxProvider,
  repository,
  brief: { text: "Summarize the README." },
});

Moving this agent to your own sandbox changes only sandboxProvider. Storing checkpoints in your own backend changes only the transporter of the stores.

Outpost continues to manage the lifecycle around your integration. Your adapter or provider implements its own contract while the application handles the following operations.

  • Process supervisionWaits for the exit status, bounds the output and stops idle agents.
  • CancellationPasses signals and deadlines to commands, transfers and model requests.
  • Retries and repairsTask retries, typed-response repairs, quota pauses and fallback.
  • ObservationForwards decoded events to observers and journals, and adds up token usage.
  • Workspace and GitWorktrees, branch locks, integration and synchronization back to the host.
  • Agent homeInstalls the adapter’s credential and configuration plans in the sandbox’s private home.

Test what a user observes when things go wrong: a nonzero exit status, output that closes before the process, a cancelled or timed-out run, a release called twice. Check who owns each resource and that temporary files disappear on success, failure and cancellation.

For a sandbox provider, diagnose() runs a bounded probe against a real sandbox: Node.js, Git, separate output streams, a nonzero exit status, the home directory and, with transfers, binary file transfers.

import { reportValue } from "./reporter.ts";
import { createSandbox } from "@elie-laloum/outpost";
import { repository, sandboxProvider } from "./outpost.config.ts";

await using sandbox = await createSandbox({ sandboxProvider, repository });
const report = await sandbox.diagnose({ transfers: true });
reportValue(report.hasFailures, report.checks);
// Example output: false [ { id: "sandbox.node", status: "pass", … }, … ]

Load a vendor SDK only from your integration’s own entry point, and declare it as an optional peer dependency. Outpost does the same: @elie-laloum/outpost/providers/vercel, /transports/s3 and /queues/bullmq load their SDKs, the core import does not.

To contribute a built-in agent or provider to Outpost itself, follow AGENTS.md in the repository.

API: CliHarness · AgentAdapter · ConversationStore · SandboxProvider · SandboxLease · ModelProvider · Transport · TaskQueue · diagnoseSandbox.

DecisionProvider evaluates typed questions over lossless JSON state. It is independent of ModelProvider and allocates no sandbox. Use the common System One HTTP adapter for Jev and compatible Laya endpoints, or implement one cancellable request returning native answers and available usage. See typed decisions and per-step routing.