Aller au contenu
English

Réutiliser une sandbox

Gardez un environnement ouvert pour les échanges avec l’agent, les commandes et les tests sur les mêmes fichiers.

Ouvrez une sandbox avec createSandbox() lorsque plusieurs opérations doivent partager les mêmes fichiers et dépendances. await using la ferme à la sortie du bloc, y compris si une opération lève une erreur.

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

await using sandbox = await createSandbox({
  repository,
  sandboxProvider,
  agent: coder,
});
await sandbox.dispatch({ brief: { text: "Fix the failing date tests." } });
const tests = await sandbox.command({
  executable: "npm",
  arguments: ["test"],
});
reportValue(tests.status === 0 ? "Tests pass" : tests.stderr);
// Example output: Tests pass

L’agent modifie le worktree, puis npm test s’exécute dans la même sandbox, sur ses modifications. La page Fonctionnement explique la différence avec un dispatch() ponctuel, et qui ferme quoi.

sandbox.dispatch() accepte le même brief et les mêmes options de tour que dispatch(), sans les réglages de dépôt et de sandbox. Chaque appel démarre une nouvelle conversation : poursuivez-en une avec sandbox.resume(id, options) ou sandbox.fork(id, options) (Conversations).

Un agent passé à sandbox.dispatch() remplace celui donné à createSandbox().

sandbox.command() lance un exécutable avec un tableau d’arguments. Aucun shell ne les interprète : *, | et $HOME arrivent au programme tels quels. Appelez vous-même un shell quand il vous en faut un.

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

await using sandbox = await createSandbox({ repository, sandboxProvider });
const result = await sandbox.command({
  executable: "sh",
  arguments: ["-c", "node --version | tail -n 1"],
  variables: { CI: "1" },
});
reportValue(result.stdout.trim());
// Example output: v24.15.0

sandbox.root est le chemin du dépôt dans la sandbox et le répertoire de travail par défaut.

Référence API : Command.

Une commande qui se termine résout avec status, stdout et stderr, quel que soit son code de sortie. Une commande qu’Outpost a dû arrêter rejette.

IssueRésultat
Le processus sort, même avec le statut 1Résout ; testez result.status.
deadlineMs expireRejette avec une OutpostError de code timeout ; sur Vercel et Daytona, avec une TimeoutError.
signal est déclenchéRejette avec la raison du signal.
La sandbox se ferme pendant la commandeRejette ; le processus est arrêté.

Le résultat attend la sortie du processus, pas la fermeture de ses flux. Lisez status plutôt que de déduire la réussite de stdout. Les codes d’erreur sont listés dans Erreurs.

observe affiche la sortie pendant l’exécution. retain borne seulement ce que garde le résultat, pas ce que reçoit observe.

import type { Command } from "@elie-laloum/outpost";

const build: Command = {
  executable: "npm",
  arguments: ["run", "build"],
  deadlineMs: 120_000,
  observe(channel, text) {
    (channel === "stderr" ? process.stderr : process.stdout).write(text);
  },
};

Passez-le à sandbox.command(build). Arrêter une commande termine son groupe de processus et ses descendants. La sandbox reste ouverte pour l’opération suivante.

sandbox.attach() lance la CLI de l’agent dans votre terminal, à l’intérieur de la sandbox. Vous travaillez avec elle à la main ; l’appel résout quand vous quittez, avec status et les commits créés pendant la session.

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

await using sandbox = await createSandbox({
  repository,
  sandboxProvider,
  agent: coder,
});
const session = await sandbox.attach({
  brief: { text: "Walk me through the payment module." },
});
reportValue(session.status, session.commits);
// Example output: 0 []

Lancez-le depuis un vrai terminal. continuation rouvre une conversation capturée. La fonction attach() de premier niveau ouvre et ferme sa propre sandbox, et applique la politique de branche quand la session sort avec le statut 0.

Fournisseurattach()
Docker, Podman, hôtePris en charge
DaytonaPris en charge
Vercel, FirecrackerRejeté

attach() exige un agent CLI comme Codex ou Claude Code. Le harness intégré, les agents de secours et les agents de rejeu sont rejetés.

Une sandbox que vous créez ne fusionne jamais sa branche d’elle-même. Avec branch: { mode: "integrate" }, appelez sandbox.workspace.integrate() avant la fermeture pour fusionner la branche de travail dans sa base.

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

await using sandbox = await createSandbox({
  repository,
  sandboxProvider,
  agent: coder,
  branch: { mode: "integrate" },
});
await sandbox.dispatch({
  brief: { text: "Fix the failing tests and commit." },
});
const tests = await sandbox.command({ executable: "npm", arguments: ["test"] });
if (tests.status === 0) await sandbox.workspace.integrate();

Avec les autres modes de branche, integrate() ne fait rien. Un conflit de fusion, ou une branche de l’hôte changée pendant l’exécution, rejette avec le code conflict et conserve le worktree. close({ preserve: true }) le conserve aussi pour inspection (Récupérer du travail).

  • Une sandbox exécute une opération à la fois : un second appel lancé pendant qu’une opération tourne est rejeté, pas mis en file. Utilisez des sandboxes distinctes pour le travail parallèle.
  • La sortie est capturée sous forme de texte. Déplacez les fichiers binaires avec les méthodes de transfert du fournisseur (Sandboxes cloud).

API : createSandbox · Sandbox · Command · CommandResult · AttachOptions · attach.