Aller au contenu
English

Exécuter depuis la CI

Exécutez un script Outpost dans un job de CI et conservez les résultats utiles après son arrêt.

  • Node.js 24+Exécute Outpost et vos scripts.
  • L’historique GitUn clone complet, pour que l’agent lise l’historique et que les sandboxes cloud le téléversent.
  • Une sandboxDocker ou Podman sur le runner, ou le SDK d’une sandbox cloud et ses identifiants d’allocation.
  • L’image de l’agentConstruite dans le job depuis .outpost-image/Dockerfile, préparé pendant l’installation et commité avec vos scripts.
  • Des identifiants pour le jobUne clé d’API ou un jeton de compte dédié, enregistré dans les secrets de votre CI.
  • Vos scripts et leur configurationpackage.json, le lockfile, outpost.config.ts et vos scripts, commités.

Pour utiliser une clé d’API en CI, configurez coder dans outpost.config.ts afin de lire la clé dans l’environnement du job. Déclarez-la dans les secrets de votre CI pour que le runner puisse l’utiliser sans connexion interactive.

import { createAgent, createCodexHarness } from "@elie-laloum/outpost";

export const coder = createAgent({
  harness: createCodexHarness({
    authentication: "usage",
    variables: { OPENAI_API_KEY: process.env.OPENAI_API_KEY ?? "" },
  }),
});

Claude Code et Copilot CLI acceptent aussi un jeton d’abonnement via { account: { variable } }, comme CLAUDE_CODE_OAUTH_TOKEN. La page Authentification présente les identifiants acceptés, leur facturation et l’endroit où Outpost les installe.

Ce job GitHub Actions lance review.ts, tiré de Votre première tâche, sur chaque pull request.

name: Outpost review
on: pull_request

jobs:
  review:
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v5
        with:
          node-version: 24
      - run: npm ci
      - run: npx outpost image build --directory .outpost-image --image outpost:dev
      - run: npx outpost doctor --image outpost:dev --json
      - run: node review.ts
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

Construisez l’image dans le job pour que son identifiant utilisateur corresponde à celui du runner. Le fournisseur Docker refuse une image construite pour un autre identifiant. Si votre Dockerfile se trouve dans un autre dossier, adaptez --directory.

doctor sort avec le statut 1 quand le moteur, l’image ou la CLI de l’agent manque (Diagnostic). Il vérifie Codex sur Docker, sauf si vous passez --agent ou --sandbox-provider, et ne teste pas la clé API.

Réparer une CI en échec est un script complet à lancer de cette façon.

Un job échoue quand le script sort avec un statut non nul. Afficher une erreur ne suffit pas.

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

const signal = AbortSignal.timeout(30 * 60_000);
await using sandbox = await createSandbox({
  repository,
  sandboxProvider,
  agent: coder,
  branch: { mode: "named", name: `outpost/fix-${process.env.GITHUB_RUN_ID}` },
});
await sandbox.dispatch({
  brief: { text: "Fix the failing tests and commit the fix." },
  signal,
});
const tests = await sandbox.command({
  executable: "npm",
  arguments: ["test"],
  signal,
});
if (tests.status !== 0) throw new Error(`npm test failed:\n${tests.stderr}`);
Ce qui échoueCe que fait OutpostCe que vous faites
dispatch(), allocation de sandboxRejette ; Node sort avec le statut 1Rien, ou journaliser puis relancer
Un sandbox.command()Se résout avec son status non nulLever une erreur si status ≠ 0
Un workflow lancé par start()Se résout avec un status autre que "done"Appeler result.unwrap()
outpost doctorSort avec le statut 1Rien

Gardez l’échéance de signal plus courte que le timeout-minutes du job. Outpost arrête alors l’agent et l’étape échoue, au lieu que GitHub annule le job et saute vos étapes if: failure() (Limites et annulation).

Une branche named qui existe déjà est réutilisée, avec les commits de l’exécution précédente. Mettez l’identifiant d’exécution dans le nom, comme dans fix.ts, pour que chaque job parte du commit extrait. C’est important sur les runners auto-hébergés, qui gardent les branches d’un job à l’autre.

Outpost commite sur la branche et s’arrête là. Poussez depuis le job une fois vos contrôles passés, avec un jeton autorisé à écrire.

permissions:
  contents: write
steps:
  # ...les étapes ci-dessus, qui lancent fix.ts
  - run: git push origin "outpost/fix-${GITHUB_RUN_ID}"

Ouvrez la pull request ou fusionnez selon vos règles habituelles de revue et de validation. Pour attendre une personne pendant l’exécution, utilisez les Approbations.

Un runner hébergé est supprimé après le job, avec le répertoire .outpost/ du dépôt. Téléversez ce qu’il faut pour inspecter ou reprendre une exécution en échec.

- if: failure()
  uses: actions/upload-artifact@v4
  with:
    name: outpost-recovery
    include-hidden-files: true
    if-no-files-found: ignore
    retention-days: 7
    path: |
      .outpost/recovery/
      .outpost/storage/objects/checkpoints/
      .outpost/storage/objects/logs/

Ces chemins contiennent les transferts conservés après une synchronisation en échec, les checkpoints de workflow et les journaux (Où vivent les données). Ne téléversez jamais les conversations, .env ni les fichiers d’identifiants : toute personne ayant accès en lecture au dépôt peut télécharger les artefacts de CI.

Les commits de l’agent restent sur sa branche : poussez-la depuis une étape if: failure() pour les garder. Pour reprendre une exécution dans un job ultérieur, gardez ses checkpoints dans S3 ou R2 plutôt que sur le runner.

  • Outpost ne pousse jamais, n’ouvre pas de pull request et ne fusionne rien sur un dépôt distant.
  • doctor ne teste ni la connexion, ni les clés API, ni l’accès au modèle.
  • Les commits utilisent user.name et user.email du dépôt, ou Outpost <outpost@localhost> quand le runner n’en définit aucun.

API : dispatch · createSandbox · WorkflowResult · WorkflowFailure · createCodexHarness.