@elie-laloum/outpost 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.fr.md +251 -0
- package/README.md +226 -0
- package/ROADMAP.md +34 -0
- package/SECURITY.md +15 -0
- package/dist/application/campaign.d.ts +33 -0
- package/dist/application/campaign.js +195 -0
- package/dist/application/campaign.js.map +1 -0
- package/dist/application/execution.d.ts +48 -0
- package/dist/application/execution.js +322 -0
- package/dist/application/execution.js.map +1 -0
- package/dist/application/interactive-brief.d.ts +3 -0
- package/dist/application/interactive-brief.js +35 -0
- package/dist/application/interactive-brief.js.map +1 -0
- package/dist/application/outpost.d.ts +91 -0
- package/dist/application/outpost.js +629 -0
- package/dist/application/outpost.js.map +1 -0
- package/dist/application/remote-workspace.d.ts +11 -0
- package/dist/application/remote-workspace.js +264 -0
- package/dist/application/remote-workspace.js.map +1 -0
- package/dist/application/tasks.d.ts +17 -0
- package/dist/application/tasks.js +36 -0
- package/dist/application/tasks.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +94 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/scaffold.d.ts +28 -0
- package/dist/cli/scaffold.js +169 -0
- package/dist/cli/scaffold.js.map +1 -0
- package/dist/cli/starters.d.ts +3 -0
- package/dist/cli/starters.js +34 -0
- package/dist/cli/starters.js.map +1 -0
- package/dist/domain/backlog.d.ts +16 -0
- package/dist/domain/backlog.js +23 -0
- package/dist/domain/backlog.js.map +1 -0
- package/dist/domain/errors.d.ts +11 -0
- package/dist/domain/errors.js +37 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/ports.d.ts +183 -0
- package/dist/domain/ports.js +2 -0
- package/dist/domain/ports.js.map +1 -0
- package/dist/domain/prompts.d.ts +22 -0
- package/dist/domain/prompts.js +45 -0
- package/dist/domain/prompts.js.map +1 -0
- package/dist/domain/response.d.ts +37 -0
- package/dist/domain/response.js +50 -0
- package/dist/domain/response.js.map +1 -0
- package/dist/domain/workflow.d.ts +68 -0
- package/dist/domain/workflow.js +246 -0
- package/dist/domain/workflow.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/abort.d.ts +1 -0
- package/dist/infrastructure/abort.js +16 -0
- package/dist/infrastructure/abort.js.map +1 -0
- package/dist/infrastructure/conversations.d.ts +30 -0
- package/dist/infrastructure/conversations.js +222 -0
- package/dist/infrastructure/conversations.js.map +1 -0
- package/dist/infrastructure/files.d.ts +5 -0
- package/dist/infrastructure/files.js +85 -0
- package/dist/infrastructure/files.js.map +1 -0
- package/dist/infrastructure/git.d.ts +14 -0
- package/dist/infrastructure/git.js +304 -0
- package/dist/infrastructure/git.js.map +1 -0
- package/dist/infrastructure/journal.d.ts +10 -0
- package/dist/infrastructure/journal.js +53 -0
- package/dist/infrastructure/journal.js.map +1 -0
- package/dist/infrastructure/process.d.ts +6 -0
- package/dist/infrastructure/process.js +133 -0
- package/dist/infrastructure/process.js.map +1 -0
- package/dist/infrastructure/reporter.d.ts +10 -0
- package/dist/infrastructure/reporter.js +47 -0
- package/dist/infrastructure/reporter.js.map +1 -0
- package/dist/infrastructure/settings.d.ts +3 -0
- package/dist/infrastructure/settings.js +41 -0
- package/dist/infrastructure/settings.js.map +1 -0
- package/dist/infrastructure/shutdown.d.ts +1 -0
- package/dist/infrastructure/shutdown.js +67 -0
- package/dist/infrastructure/shutdown.js.map +1 -0
- package/dist/infrastructure/terminal.d.ts +11 -0
- package/dist/infrastructure/terminal.js +19 -0
- package/dist/infrastructure/terminal.js.map +1 -0
- package/dist/infrastructure/transfer.d.ts +3 -0
- package/dist/infrastructure/transfer.js +29 -0
- package/dist/infrastructure/transfer.js.map +1 -0
- package/dist/providers/agents.d.ts +17 -0
- package/dist/providers/agents.js +204 -0
- package/dist/providers/agents.js.map +1 -0
- package/dist/providers/backlogs.d.ts +9 -0
- package/dist/providers/backlogs.js +82 -0
- package/dist/providers/backlogs.js.map +1 -0
- package/dist/providers/cloud-files.d.ts +4 -0
- package/dist/providers/cloud-files.js +66 -0
- package/dist/providers/cloud-files.js.map +1 -0
- package/dist/providers/container.d.ts +21 -0
- package/dist/providers/container.js +310 -0
- package/dist/providers/container.js.map +1 -0
- package/dist/providers/daytona.d.ts +10 -0
- package/dist/providers/daytona.js +153 -0
- package/dist/providers/daytona.js.map +1 -0
- package/dist/providers/docker.d.ts +3 -0
- package/dist/providers/docker.js +3 -0
- package/dist/providers/docker.js.map +1 -0
- package/dist/providers/factories.d.ts +9 -0
- package/dist/providers/factories.js +12 -0
- package/dist/providers/factories.js.map +1 -0
- package/dist/providers/local.d.ts +4 -0
- package/dist/providers/local.js +64 -0
- package/dist/providers/local.js.map +1 -0
- package/dist/providers/podman.d.ts +3 -0
- package/dist/providers/podman.js +3 -0
- package/dist/providers/podman.js.map +1 -0
- package/dist/providers/vercel.d.ts +9 -0
- package/dist/providers/vercel.js +158 -0
- package/dist/providers/vercel.js.map +1 -0
- package/dist/providers/versions.d.ts +4 -0
- package/dist/providers/versions.js +5 -0
- package/dist/providers/versions.js.map +1 -0
- package/docs/api.md +147 -0
- package/docs/architecture.md +21 -0
- package/docs/migration-1.1.fr.md +44 -0
- package/docs/migration-1.1.md +38 -0
- package/docs/operations.md +101 -0
- package/docs/providers.md +119 -0
- package/docs/workflows.md +101 -0
- package/package.json +95 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
- Add typed issue campaigns with dynamic planning, bounded concurrency, per-issue branches, warm review, verified integration and tracker closure.
|
|
6
|
+
- Add complete GitHub and Beads backlog connectors and executable campaign starters.
|
|
7
|
+
- Isolate cold passes, validate cancellation and structured responses before allocation, and preserve raw/final agent output.
|
|
8
|
+
- Expose per-turn transcripts, custom conversation stores, selective path rewriting and separate Claude cache counters.
|
|
9
|
+
- Align environment allowlists, caller-relative prompts, interactive variable collection and lifecycle hook ordering.
|
|
10
|
+
- Recover managed workspaces, refresh reusable branches and preserve host edits during committed-only remote synchronization.
|
|
11
|
+
- Complete Podman namespace options, macOS preflight, file-mount preparation and bounded transfers.
|
|
12
|
+
- Add human progress reporting, appendable journals, recovery metadata and terminal cleanup.
|
|
13
|
+
- Expand functional, provider and package tests; document migration in English and French.
|
|
14
|
+
|
|
15
|
+
## 1.0.0
|
|
16
|
+
|
|
17
|
+
Initial Outpost release.
|
|
18
|
+
|
|
19
|
+
- Separate workspace and sandbox ownership, reusable environments and asynchronous disposal.
|
|
20
|
+
- Codex and Claude Code adapters with native conversations, resume and fork.
|
|
21
|
+
- Docker, Podman, host, Vercel and Daytona providers; extensible provider contracts.
|
|
22
|
+
- Managed Git worktrees, named branches, automatic integration and recovery files.
|
|
23
|
+
- Remote synchronization retaining commit identity and protecting concurrent host changes.
|
|
24
|
+
- Prompt files, typed variables, command expansion, completion loops and inactivity deadlines.
|
|
25
|
+
- Tagged text/JSON responses, Standard Schema validation and resumable repair attempts.
|
|
26
|
+
- Typed workflow graphs with conditions, retries, cancellation, concurrency and diagrams.
|
|
27
|
+
- Interactive/headless initialization, five starter templates and issue-tracker connectors.
|
|
28
|
+
- English/French documentation, cross-platform tests, coverage gates and package release automation.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elie Laloum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.fr.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Outpost
|
|
2
|
+
|
|
3
|
+
[English](README.md) · [API](docs/api.md) · [Fournisseurs](docs/providers.md) · [Workflows](docs/workflows.md) · [Exploitation](docs/operations.md) · [Roadmap](ROADMAP.md)
|
|
4
|
+
|
|
5
|
+
Outpost est une bibliothèque TypeScript pour exécuter des agents de développement dans des sandbox réutilisables, gérer leurs espaces de travail Git et composer des workflows typés. La v1 fournit les adaptateurs **Codex** et **Claude Code**, ainsi que les environnements Docker, Podman, Vercel, Daytona et une exécution locale explicite. Les adaptateurs d’agents et les fournisseurs de sandbox sont deux points d’extension distincts.
|
|
6
|
+
|
|
7
|
+
[GitLab](https://gitlab.elielaloum.com/elielaloum/outpost) est le dépôt principal. [GitHub](https://github.com/elie-laloum/outpost) reçoit le miroir et exécute la CI ainsi que les publications de packages.
|
|
8
|
+
|
|
9
|
+
## Prérequis
|
|
10
|
+
|
|
11
|
+
- Node.js **24 ou supérieur**, Git et un dépôt possédant au moins un commit.
|
|
12
|
+
- Docker ou Podman pour l’isolation locale ; un compte et le SDK optionnel correspondant pour une sandbox cloud.
|
|
13
|
+
- Une authentification native de l’agent ou sa clé API. Un jeton GitHub/GitLab ne remplace pas une clé de modèle.
|
|
14
|
+
- Des imports ESM. Les déclarations TypeScript sont livrées ; Node exécute directement les scripts générés en `.ts`/`.mts`.
|
|
15
|
+
|
|
16
|
+
## Installation et premier lancement
|
|
17
|
+
|
|
18
|
+
Depuis les sources :
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm ci
|
|
22
|
+
npm run build
|
|
23
|
+
npm pack
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Installez l’archive obtenue dans votre dépôt cible, ou utilisez [GitHub Packages](https://github.com/elie-laloum/outpost/packages). La configuration du registre figure dans le [guide d’exploitation](docs/operations.md).
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install --save-dev /chemin/elie-laloum-outpost-1.1.0.tgz
|
|
30
|
+
npx outpost init --yes --agent codex --provider docker --template blank --build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Copiez `.outpost/.env.example` vers `.outpost/.env`. Renseignez `OPENAI_API_KEY`, ou laissez cette déclaration vide pour reprendre sa valeur dans le processus. Pour Claude, choisissez `--agent claude` et déclarez `ANTHROPIC_API_KEY` ou `CLAUDE_CODE_OAUTH_TOKEN`. Seules les clés déclarées sont importées dans les sandbox isolés.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
node .outpost/run.mts "Ajouter la validation de configuration et ses tests"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Le script s’appelle `run.ts` si le projet déclare `"type": "module"`, sinon `run.mts`. L’initialisation refuse d’écraser des fichiers existants. `--install` installe la bibliothèque et le SDK optionnel avec le gestionnaire détecté : npm, pnpm, yarn ou bun. Sans `--build`, construisez ensuite l’image avec `npx outpost image build`.
|
|
40
|
+
|
|
41
|
+
## Exécution ponctuelle
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { dispatch, codex } from "@elie-laloum/outpost";
|
|
45
|
+
import { docker } from "@elie-laloum/outpost/providers/docker";
|
|
46
|
+
|
|
47
|
+
const result = await dispatch({
|
|
48
|
+
agent: codex(),
|
|
49
|
+
provider: docker(),
|
|
50
|
+
branch: { mode: "integrate" },
|
|
51
|
+
brief: { text: "Corriger les tests en échec, vérifier et créer un commit." },
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(result.branch, result.commits, result.conversation);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`dispatch` crée l’environnement, lance l’agent, récupère les modifications et la conversation native, intègre les commits si demandé, puis ferme les ressources dont il est propriétaire. Le travail non commité est conservé. En cas d’échec, les worktrees séparés restent disponibles pour inspection.
|
|
58
|
+
|
|
59
|
+
| Politique Git | Comportement |
|
|
60
|
+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
61
|
+
| `{ mode: "current" }` | Utilise le checkout actuel ; défaut des fournisseurs montés et locaux. |
|
|
62
|
+
| `{ mode: "named", name: "feature/validation", from: "main" }` | Crée ou réutilise un worktree géré pour cette branche. |
|
|
63
|
+
| `{ mode: "integrate", from: "main" }` | Crée une branche temporaire puis fusionne ses commits dans la branche hôte d’origine. |
|
|
64
|
+
|
|
65
|
+
Les fournisseurs distants exigent `named` ou `integrate`. `from` est optionnel. Une branche déjà utilisée ailleurs produit une erreur explicite. L’intégration refuse un changement de branche hôte et conserve le worktree en cas de conflit.
|
|
66
|
+
|
|
67
|
+
## Sandbox réutilisable
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createSandbox, claude } from "@elie-laloum/outpost";
|
|
71
|
+
|
|
72
|
+
await using sandbox = await createSandbox({
|
|
73
|
+
agent: claude({ model: "sonnet", reasoning: "high" }),
|
|
74
|
+
branch: { mode: "named", name: "feature/settings" },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const first = await sandbox.dispatch({
|
|
78
|
+
brief: { text: "Implémenter la validation." },
|
|
79
|
+
});
|
|
80
|
+
const tests = await sandbox.command({ executable: "npm", arguments: ["test"] });
|
|
81
|
+
if (tests.status !== 0)
|
|
82
|
+
await first.resume({ brief: { text: "Corriger les tests." } });
|
|
83
|
+
await sandbox.attach();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Une commande retourne son statut, même non nul. Une exécution d’agent en échec lève une erreur. L’annulation par `AbortSignal`, le délai maximal et la surveillance d’inactivité arrêtent l’opération courante sans détruire la sandbox réutilisable. Une sandbox accepte une opération active à la fois. Le parallélisme utilise plusieurs sandbox.
|
|
87
|
+
|
|
88
|
+
L’agent par défaut est optionnel pour une sandbox chaude. Fournissez `agent` à chaque appel de `sandbox.dispatch` ou `sandbox.attach` pour changer d’agent ou de modèle sans recréer l’environnement. Chaque exécution reçoit uniquement les variables de l’adaptateur choisi.
|
|
89
|
+
|
|
90
|
+
`await using` ferme automatiquement le handle. `close()` est également disponible et idempotent. `attach()` ouvre le terminal natif avec Docker, Podman ou le fournisseur local. Les fournisseurs cloud rejettent explicitement cette opération.
|
|
91
|
+
|
|
92
|
+
## Espace de travail indépendant
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { openWorkspace, codex, claude } from "@elie-laloum/outpost";
|
|
96
|
+
|
|
97
|
+
await using workspace = await openWorkspace({
|
|
98
|
+
branch: { mode: "named", name: "feature/shared-work" },
|
|
99
|
+
copies: [".env.test"],
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await workspace.dispatch({
|
|
103
|
+
agent: codex(),
|
|
104
|
+
brief: { text: "Implémenter et commiter." },
|
|
105
|
+
});
|
|
106
|
+
await workspace.dispatch({
|
|
107
|
+
agent: claude(),
|
|
108
|
+
brief: { text: "Relire, tester et commiter les corrections." },
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
L’espace de travail fourni survit aux sandbox successives. Son propriétaire doit le fermer après elles. Un worktree contenant des modifications reste sur disque ; `close()` retourne alors `retainedDirectory`. Un worktree propre est supprimé, mais une branche nommée reste disponible. `close({ preserve: true })` conserve aussi un worktree propre.
|
|
113
|
+
|
|
114
|
+
`workspace.sandbox()` et `workspace.attach()` donnent accès aux autres cycles de vie. Avec une sandbox chaude en mode `integrate`, utilisez explicitement `sandbox.workspace.integrate()` au moment voulu. Les exécutions ponctuelles intègrent avant de retourner leur résultat.
|
|
115
|
+
|
|
116
|
+
## Prompts et boucles
|
|
117
|
+
|
|
118
|
+
Un `brief` contient exactement une source : `text` littéral, ou `file` avec des `values` primitives optionnelles. Les fichiers sont relus à chaque passage ; le texte littéral n’est jamais interprété.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
const result = await dispatch({
|
|
122
|
+
agent: codex(),
|
|
123
|
+
brief: {
|
|
124
|
+
file: ".outpost/brief.md",
|
|
125
|
+
values: { OBJECTIVE: "Corriger la validation" },
|
|
126
|
+
},
|
|
127
|
+
passes: 5,
|
|
128
|
+
until: ["<outpost>done</outpost>"],
|
|
129
|
+
idleMs: 600_000,
|
|
130
|
+
settleMs: 60_000,
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Les fichiers acceptent `{{OBJECTIVE}}`, les variables réservées `{{WORK_BRANCH}}` et `{{BASE_BRANCH}}`, ainsi que des commandes comme `` !`git status --short` ``. Les commandes présentes dans le fichier d’origine s’exécutent en parallèle dans la sandbox après les hooks. Une valeur substituée ne peut pas introduire une nouvelle commande d’expansion. Une valeur insérée dans une commande existante conserve toutefois sa sémantique shell : utilisez des valeurs fiables ou correctement échappées.
|
|
135
|
+
|
|
136
|
+
Les variables absentes déclenchent une erreur ; les variables inutilisées passent par `warn`. Un marqueur de fin interrompt la boucle. Si l’agent reste actif après ce marqueur, le délai de grâce se renouvelle à chaque sortie, puis arrête sa commande. Un budget épuisé sans marqueur retourne `completed: false`.
|
|
137
|
+
|
|
138
|
+
Chaque tour fournit sa durée, son statut, son texte, sa conversation éventuelle et les tokens bruts. Chaque tour expose aussi son chemin `transcript` lorsqu’il est capturé. Le résultat regroupe `input`, `cached` (lecture du cache), `cacheCreated` (création du cache), `output`, les commits et le marqueur observé. Aucun coût monétaire n’est extrapolé.
|
|
139
|
+
|
|
140
|
+
## Réponses structurées
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { response } from "@elie-laloum/outpost";
|
|
144
|
+
|
|
145
|
+
const result = await dispatch({
|
|
146
|
+
agent: codex(),
|
|
147
|
+
brief: {
|
|
148
|
+
text: "Analyser le dépôt et répondre avec <report>un JSON contenant ok</report>.",
|
|
149
|
+
},
|
|
150
|
+
response: response.json({
|
|
151
|
+
tag: "report",
|
|
152
|
+
repairs: 2,
|
|
153
|
+
schema(input) {
|
|
154
|
+
if (
|
|
155
|
+
!input ||
|
|
156
|
+
typeof input !== "object" ||
|
|
157
|
+
!("ok" in input) ||
|
|
158
|
+
typeof input.ok !== "boolean"
|
|
159
|
+
) {
|
|
160
|
+
throw new Error("Un booléen ok est requis");
|
|
161
|
+
}
|
|
162
|
+
return { ok: input.ok };
|
|
163
|
+
},
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
console.log(result.value.ok);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`response.text` extrait du texte balisé. `response.json` accepte une fonction ou un validateur Standard Schema, y compris asynchrone. La balise d’ouverture doit être demandée dans le prompt. Les réponses structurées exigent un seul passage ; les tentatives de correction reprennent la même conversation. En cas d’échec, `ResponseError.recovery` contient les informations de reprise disponibles.
|
|
171
|
+
|
|
172
|
+
## Conversations natives
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
await result.resume({ brief: { text: "Expliquer le résultat." } });
|
|
176
|
+
await result.fork({ brief: { text: "Explorer une autre solution." } });
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
La capture est active par défaut. Outpost enregistre les transcriptions dans le stockage natif de l’agent sur l’hôte et réécrit les champs de répertoire de travail. Le contenu des messages n’est pas remplacé globalement. Les transcriptions des sous-agents Claude sont récupérées au mieux, avec avertissement en cas d’échec. Un échec de capture de la transcription principale fait échouer l’exécution.
|
|
180
|
+
|
|
181
|
+
`saveConversations: false` désactive la capture sur l’adaptateur. Une reprise ponctuelle vérifie d’abord l’existence de la transcription hôte. `fork` crée une nouvelle conversation ; il faut aussi choisir un autre workspace pour isoler les fichiers. `conversationHome` permet de choisir un autre répertoire de stockage hôte.
|
|
182
|
+
|
|
183
|
+
## Workflows typés
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { task, workflow } from "@elie-laloum/outpost";
|
|
187
|
+
|
|
188
|
+
const inspect = task({
|
|
189
|
+
key: "inspect",
|
|
190
|
+
perform: async () => ({ ready: true }),
|
|
191
|
+
});
|
|
192
|
+
const implement = task({
|
|
193
|
+
key: "implement",
|
|
194
|
+
after: [inspect],
|
|
195
|
+
retry: { attempts: 2, delayMs: 500 },
|
|
196
|
+
perform: async (context) => context.value(inspect).ready,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const result = await workflow("delivery", [inspect, implement]).start({
|
|
200
|
+
concurrency: 2,
|
|
201
|
+
});
|
|
202
|
+
result.unwrap();
|
|
203
|
+
console.log(result.value(implement));
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Les dépendances absentes, doublons et cycles sont rejetés avant exécution. Les valeurs sont typées et propres à chaque lancement. Conditions, tentatives supplémentaires, limites de concurrence, événements d’observation et diagrammes Mermaid sont disponibles. `agentTask`, `commandTask` et `isolatedTask` relient le graphe aux opérations de sandbox.
|
|
207
|
+
|
|
208
|
+
L’annulation et le délai maximal des tâches sont coopératifs : le code d’une tâche doit respecter `context.signal`. Le planificateur attend le nettoyage des tâches actives avant de retourner. Les opérations Outpost respectent ce signal. Une fonction JavaScript arbitraire qui l’ignore ne peut pas être arrêtée de force.
|
|
209
|
+
|
|
210
|
+
Les cinq modèles CLI sont `blank`, `iterate`, `review`, `plan` et `plan-review`. Les deux derniers font travailler plusieurs analyses indépendantes avant l’implémentation. Les connecteurs GitHub Issues, Beads et personnalisés sont générés avec `--tracker`. Consultez le [guide des workflows](docs/workflows.md).
|
|
211
|
+
|
|
212
|
+
Un `dispatch({ passes })` ponctuel acquiert une nouvelle sandbox à chaque passe ; `sandbox.dispatch({ passes })` conserve son environnement. Les fichiers de prompt relatifs sont résolus depuis le répertoire de l’appelant. Les méthodes `resume`/`fork` d’un résultat ponctuel acceptent une nouvelle branche, un autre fournisseur et des hooks ; celles d’un résultat chaud restent liées à leur sandbox.
|
|
213
|
+
|
|
214
|
+
## Campagnes par issue
|
|
215
|
+
|
|
216
|
+
`campaign` relit le backlog à chaque cycle, valide un plan typé et attribue une branche par issue. Le parallélisme est borné ; la revue partage la sandbox d’implémentation. Une phase de fusion et de vérification intervient même pour une seule branche. La fermeture d’une issue a lieu uniquement après intégration des commits dans la branche hôte. GitHub et Beads fournissent les opérations de liste, détail et fermeture. Un connecteur personnalisé implémente `Backlog`.
|
|
217
|
+
|
|
218
|
+
Les starters exposent `cycles`, `concurrency`, `implementationPasses`, `reviewPasses`, les agents de chaque rôle et les règles de `.outpost/STANDARDS.md`. Une issue sans commit n’est ni revue ni fermée. Un cycle sans progression s’arrête. `recoveryDetails(error)` fournit les chemins disponibles en cas d’erreur, sans remplacer la raison d’annulation. [Guide de migration 1.1 en français](docs/migration-1.1.fr.md).
|
|
219
|
+
|
|
220
|
+
## Configuration et fournisseurs
|
|
221
|
+
|
|
222
|
+
Les fournisseurs prennent en charge les variables d’environnement, montages de fichiers/répertoires, réseaux, ressources, groupes supplémentaires, périphériques et labels SELinux selon le backend. Les SDK cloud sont des dépendances optionnelles, chargées uniquement à l’utilisation du fournisseur concerné. [Référence des fournisseurs](docs/providers.md).
|
|
223
|
+
|
|
224
|
+
Les hooks s’exécutent après la copie des entrées puis après la création de la sandbox. Les groupes `hostReady` et `sandboxReady` tournent en parallèle ; les commandes hôte restent séquentielles, tandis que les commandes du groupe sandbox démarrent ensemble et annulent leurs voisines en cas d’échec.
|
|
225
|
+
|
|
226
|
+
Seul `.outpost/.env` est lu. Une valeur non vide du fichier est prioritaire ; une déclaration vide reprend la valeur du processus. Le `.env` à la racine du dépôt n’est pas importé. Les variables explicites du fournisseur et de l’adaptateur restent prioritaires. Une clé déclarée simultanément par le fournisseur et l’adaptateur provoque une erreur. Les journaux sont écrits dans `.outpost/logs` par défaut ; `false`, `"stdout"`, un chemin personnalisé et le mode verbeux sont disponibles.
|
|
227
|
+
|
|
228
|
+
`AgentAdapter` permet d’ajouter un agent. `SandboxProvider`, `mountedProvider` et `remoteProvider` permettent d’ajouter un backend. Le domaine ne dépend pas d’un SDK cloud. [Architecture](docs/architecture.md) et [API complète](docs/api.md).
|
|
229
|
+
|
|
230
|
+
## Vérification et publication
|
|
231
|
+
|
|
232
|
+
```sh
|
|
233
|
+
npm ci
|
|
234
|
+
npm run check
|
|
235
|
+
npm run coverage
|
|
236
|
+
npm run test:package
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
La CI GitHub exécute les tests unitaires et fonctionnels sous Linux, Windows et macOS, impose 80 % de couverture des lignes, fonctions et branches, installe le package réellement produit et teste Docker/Podman. Les tests de contrats cloud utilisent des doubles contrôlés ; les essais avec de vrais modèles et comptes cloud nécessitent leurs identifiants.
|
|
240
|
+
|
|
241
|
+
Les tags de version sont créés dans GitLab puis répliqués. Le workflow de release valide le tag et la CI, publie GitHub Packages et joint l’archive installable à une release GitHub. La publication npm est optionnelle, via trusted publishing une fois configuré. [Procédure d’exploitation](docs/operations.md).
|
|
242
|
+
|
|
243
|
+
## Limites d’isolation et récupération
|
|
244
|
+
|
|
245
|
+
Docker et Podman montent le worktree sélectionné et les métadonnées Git. L’agent peut modifier ce dépôt et son état Git. Les autres chemins hôte ne sont pas exposés par défaut, mais ce montage ne constitue pas une protection contre un agent hostile visant le dépôt partagé. `local()` s’exécute directement sur votre machine, sans isolation.
|
|
246
|
+
|
|
247
|
+
Les fournisseurs cloud synchronisent l’historique, les changements suivis et les fichiers nouveaux. Les identifiants et auteurs des commits sont conservés. Une modification hôte concurrente déclenche une erreur de récupération plutôt qu’un écrasement. Les bundles, patches et fichiers de secours sont conservés sous `.outpost/recovery`.
|
|
248
|
+
|
|
249
|
+
Les logs, transcriptions et fichiers de récupération peuvent contenir des données privées. Les dossiers d’exécution et `.env` sont exclus du versionnement. [Détails de sécurité](SECURITY.md).
|
|
250
|
+
|
|
251
|
+
Licence MIT : [LICENSE](LICENSE).
|
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Outpost
|
|
2
|
+
|
|
3
|
+
[Français](README.fr.md) · [API](docs/api.md) · [Providers](docs/providers.md) · [Workflows](docs/workflows.md) · [Operations](docs/operations.md) · [Roadmap](ROADMAP.md)
|
|
4
|
+
|
|
5
|
+
Outpost is a TypeScript library for running coding agents in reusable sandboxes, managing their Git workspaces and composing typed workflows. V1 supports **Codex** and **Claude Code**, with Docker, Podman, Vercel, Daytona and explicit host execution. Agent adapters and sandbox providers are separate extension points.
|
|
6
|
+
|
|
7
|
+
The source repository is [GitLab](https://gitlab.elielaloum.com/elielaloum/outpost). [GitHub](https://github.com/elie-laloum/outpost) is its push mirror and runs all CI and package releases.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Node.js **24 or later**, Git, and an existing repository with at least one commit.
|
|
12
|
+
- Docker or Podman for local isolation; the appropriate account and optional SDK for a cloud sandbox.
|
|
13
|
+
- An authenticated coding agent or its API key. Git hosting credentials are not model credentials.
|
|
14
|
+
- ESM imports. TypeScript declarations ship with the package; Node can execute the generated `.ts`/`.mts` scripts directly.
|
|
15
|
+
|
|
16
|
+
## Install and run
|
|
17
|
+
|
|
18
|
+
Build from the source checkout:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm ci
|
|
22
|
+
npm run build
|
|
23
|
+
npm pack
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Install the resulting tarball in your target repository, or use the package from [GitHub Packages](https://github.com/elie-laloum/outpost/packages). Registry configuration is documented in [Operations](docs/operations.md).
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install --save-dev /path/to/elie-laloum-outpost-1.1.0.tgz
|
|
30
|
+
npx outpost init --yes --agent codex --provider docker --template blank --build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Copy `.outpost/.env.example` to `.outpost/.env`. Set `OPENAI_API_KEY` there, or leave its declaration empty to inherit the process value. For Claude, select `--agent claude` and declare `ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN`. Only declared process variables are imported into isolated sandboxes. Run the generated script:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
node .outpost/run.mts "Add validation and tests for the configuration loader"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Initialization uses `run.ts` when the host package declares `"type": "module"`, and `run.mts` otherwise. It never overwrites an existing scaffold. `--install` installs the library and optional provider SDK with the detected package manager. Omit `--build` to build the image later with `npx outpost image build`.
|
|
40
|
+
|
|
41
|
+
## One dispatch
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { dispatch, codex } from "@elie-laloum/outpost";
|
|
45
|
+
import { docker } from "@elie-laloum/outpost/providers/docker";
|
|
46
|
+
|
|
47
|
+
const result = await dispatch({
|
|
48
|
+
agent: codex(),
|
|
49
|
+
provider: docker(),
|
|
50
|
+
branch: { mode: "integrate" },
|
|
51
|
+
brief: { text: "Fix the failing tests, verify the result and commit it." },
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(result.branch, result.commits, result.conversation);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`dispatch` provisions a sandbox, executes the agent, collects changes and native conversation files, integrates commits when requested, and closes owned resources. Uncommitted work is retained. Failure paths preserve separate workspaces for inspection.
|
|
58
|
+
|
|
59
|
+
| Branch policy | Behavior |
|
|
60
|
+
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
61
|
+
| `{ mode: "current" }` | Uses the current checkout. This is the mounted/host default. |
|
|
62
|
+
| `{ mode: "named", name: "feature/validation", from: "main" }` | Creates or reuses a managed worktree for that branch. |
|
|
63
|
+
| `{ mode: "integrate", from: "main" }` | Creates a temporary branch and merges its commits into the original host branch. |
|
|
64
|
+
|
|
65
|
+
Remote providers require `named` or `integrate`. `from` is optional. Integration refuses a changed host branch and retains the workspace on conflict. A branch checked out elsewhere produces an actionable error.
|
|
66
|
+
|
|
67
|
+
## Keep a sandbox warm
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createSandbox, claude } from "@elie-laloum/outpost";
|
|
71
|
+
|
|
72
|
+
await using sandbox = await createSandbox({
|
|
73
|
+
agent: claude({ model: "sonnet", reasoning: "high" }),
|
|
74
|
+
branch: { mode: "named", name: "feature/settings" },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const first = await sandbox.dispatch({
|
|
78
|
+
brief: { text: "Implement settings validation." },
|
|
79
|
+
});
|
|
80
|
+
const tests = await sandbox.command({ executable: "npm", arguments: ["test"] });
|
|
81
|
+
if (tests.status !== 0)
|
|
82
|
+
await first.resume({ brief: { text: "Fix the failing tests." } });
|
|
83
|
+
await sandbox.attach();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Commands return nonzero statuses; agent dispatches throw on agent failure. `AbortSignal`, command deadlines and idle watchdogs stop the current operation while leaving a warm sandbox usable. A sandbox accepts one active operation at a time. Use separate sandboxes for parallel work.
|
|
87
|
+
|
|
88
|
+
The default agent is optional for a warm sandbox. Pass `agent` to individual `sandbox.dispatch` or `sandbox.attach` calls to switch between Codex and Claude, or change models, without recreating the environment. Each job receives only its selected adapter's variables.
|
|
89
|
+
|
|
90
|
+
## Own the workspace separately
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { openWorkspace, codex, claude } from "@elie-laloum/outpost";
|
|
94
|
+
|
|
95
|
+
await using workspace = await openWorkspace({
|
|
96
|
+
branch: { mode: "named", name: "feature/shared-work" },
|
|
97
|
+
copies: [".env.test"],
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await workspace.dispatch({
|
|
101
|
+
agent: codex(),
|
|
102
|
+
brief: { text: "Implement the feature and commit." },
|
|
103
|
+
});
|
|
104
|
+
await workspace.dispatch({
|
|
105
|
+
agent: claude(),
|
|
106
|
+
brief: { text: "Review the implementation, test and commit fixes." },
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A supplied workspace outlives each sandbox. Its owner closes it. Closing a dirty workspace returns `retainedDirectory`; closing a clean managed workspace removes the worktree. Named branches remain. `workspace.sandbox()` and `workspace.attach()` provide the other lifecycles. Warm integration workspaces can call `sandbox.workspace.integrate()` explicitly.
|
|
111
|
+
|
|
112
|
+
## Prompts and iteration
|
|
113
|
+
|
|
114
|
+
Provide exactly one `brief`: literal `text`, or a `file` with optional primitive `values`. Files are reread each pass; inline text is never expanded.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const result = await dispatch({
|
|
118
|
+
agent: codex(),
|
|
119
|
+
brief: { file: ".outpost/brief.md", values: { OBJECTIVE: "Fix validation" } },
|
|
120
|
+
passes: 5,
|
|
121
|
+
until: ["<outpost>done</outpost>"],
|
|
122
|
+
idleMs: 600_000,
|
|
123
|
+
settleMs: 60_000,
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Files support `{{OBJECTIVE}}`, reserved `{{WORK_BRANCH}}` and `{{BASE_BRANCH}}`, and shell expansion such as `` !`git status --short` ``. Original file commands run concurrently inside the sandbox after setup hooks. Substituted text cannot introduce additional commands. Values inserted into an existing command are shell input: only interpolate trusted values there. Missing variables fail; unused variables warn through `warn`.
|
|
128
|
+
|
|
129
|
+
Completion markers stop the loop. If the process hangs after a marker, the completion grace period resets on subsequent output and then stops that command. Every turn includes its duration, native transcript path when available and raw token counts (input, cache read, cache creation, output); the result includes aggregate usage and the matched completion marker.
|
|
130
|
+
|
|
131
|
+
## Structured responses and conversations
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { response } from "@elie-laloum/outpost";
|
|
135
|
+
|
|
136
|
+
const result = await dispatch({
|
|
137
|
+
agent: codex(),
|
|
138
|
+
brief: {
|
|
139
|
+
text: "Analyze the repository. Return <report>JSON with an ok boolean</report>.",
|
|
140
|
+
},
|
|
141
|
+
response: response.json({
|
|
142
|
+
tag: "report",
|
|
143
|
+
repairs: 2,
|
|
144
|
+
schema(input) {
|
|
145
|
+
if (
|
|
146
|
+
!input ||
|
|
147
|
+
typeof input !== "object" ||
|
|
148
|
+
!("ok" in input) ||
|
|
149
|
+
typeof input.ok !== "boolean"
|
|
150
|
+
) {
|
|
151
|
+
throw new Error("Expected an ok boolean");
|
|
152
|
+
}
|
|
153
|
+
return { ok: input.ok };
|
|
154
|
+
},
|
|
155
|
+
}),
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
console.log(result.value.ok);
|
|
159
|
+
await result.resume({ brief: { text: "Explain the result." } });
|
|
160
|
+
await result.fork({ brief: { text: "Explore a different solution." } });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`response.text` extracts tagged text. `response.json` accepts a function or a Standard Schema validator, including asynchronous validation. Structured responses and conversation continuations require one pass. Repairs resume the same conversation. `ResponseError.recovery` exposes the conversation, commits and recovery paths. `recoveryDetails(error)` also retrieves recovery metadata for other failures without replacing cancellation reasons.
|
|
164
|
+
|
|
165
|
+
Native conversation capture is enabled by default. Transcripts are saved to the host agent's own storage and working-directory fields are rewritten for host resumption. Claude child transcripts are copied on a best-effort basis. Set `saveConversations: false` on an adapter to opt out. Forks create a new conversation; use a separate workspace when filesystem isolation is also required.
|
|
166
|
+
|
|
167
|
+
Each cold `dispatch({ passes })` provisions a fresh sandbox per pass. `sandbox.dispatch({ passes })` deliberately reuses its environment. Relative brief filenames resolve from the caller’s working directory. Cold result `resume`/`fork` accepts new branch/provider/hook settings; warm result methods retain the sandbox’s settings. See [1.1 migration notes](docs/migration-1.1.md).
|
|
168
|
+
|
|
169
|
+
## Typed workflows
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { task, workflow } from "@elie-laloum/outpost";
|
|
173
|
+
|
|
174
|
+
const inspect = task({
|
|
175
|
+
key: "inspect",
|
|
176
|
+
perform: async () => ({ ready: true }),
|
|
177
|
+
});
|
|
178
|
+
const implement = task({
|
|
179
|
+
key: "implement",
|
|
180
|
+
after: [inspect],
|
|
181
|
+
retry: { attempts: 2, delayMs: 500 },
|
|
182
|
+
perform: async (context) => context.value(inspect).ready,
|
|
183
|
+
});
|
|
184
|
+
const result = await workflow("delivery", [inspect, implement]).start({
|
|
185
|
+
concurrency: 2,
|
|
186
|
+
});
|
|
187
|
+
result.unwrap();
|
|
188
|
+
console.log(result.value(implement));
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The graph validates dependencies and cycles before running. Results are typed and scoped to one execution. Conditions, cooperative cancellation, retries, concurrency limits, observer events and Mermaid diagrams are built in. `agentTask`, `commandTask` and `isolatedTask` connect workflows to sandbox operations. [Workflow guide](docs/workflows.md).
|
|
192
|
+
|
|
193
|
+
## Issue campaigns
|
|
194
|
+
|
|
195
|
+
`campaign({ agent, provider, backlog })` loads a backlog, validates a typed plan, allocates a branch per issue and bounds parallel implementation. Review shares each issue sandbox. A merge phase validates the combined work; issue closure occurs only after integration into the host branch. The backlog is refreshed for the next cycle. GitHub and Beads connectors expose list, detail and close operations; custom trackers implement `Backlog`.
|
|
196
|
+
|
|
197
|
+
[Campaign configuration and starter examples](docs/workflows.md#issue-campaigns).
|
|
198
|
+
|
|
199
|
+
## Configuration and extension
|
|
200
|
+
|
|
201
|
+
Provider settings cover environment variables, file/directory mounts, networks, resource limits, devices, extra groups and SELinux labels. Hooks run at workspace readiness and after sandbox creation. The two post-creation hook groups run concurrently. Host commands run in order; sandbox commands run concurrently and cancel their siblings on failure. [Complete API](docs/api.md) and [provider reference](docs/providers.md).
|
|
202
|
+
|
|
203
|
+
Outpost reads only `.outpost/.env`. Nonempty file values win; empty declarations inherit matching process values. The repository-root `.env` is not imported. Explicit provider and adapter variables override those values. The same variable cannot be declared by both provider and adapter. Logs default to `.outpost/logs`, with `false`, `"stdout"`, custom files and verbose modes available.
|
|
204
|
+
|
|
205
|
+
Implement `AgentAdapter` to add an agent. Implement `SandboxProvider` directly or use `mountedProvider`/`remoteProvider` to add an execution backend. Domain contracts do not depend on a specific cloud SDK. [Architecture](docs/architecture.md).
|
|
206
|
+
|
|
207
|
+
## Verification and releases
|
|
208
|
+
|
|
209
|
+
```sh
|
|
210
|
+
npm ci
|
|
211
|
+
npm run check
|
|
212
|
+
npm run coverage
|
|
213
|
+
npm run test:package
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
GitHub Actions runs unit and functional tests on Linux, Windows and macOS, enforces 80% line/function/branch coverage, installs the packed package, and runs real Docker and Podman tests. Cloud contract tests use controlled SDK doubles; live cloud/model checks require the corresponding credentials. No GitLab CI pipeline is required.
|
|
217
|
+
|
|
218
|
+
Version tags are created on GitLab and mirrored. The release workflow validates the tag, runs CI, publishes GitHub Packages and attaches the installable tarball to a GitHub release. Optional npm publication uses trusted publishing when enabled. [Release procedure and registry setup](docs/operations.md).
|
|
219
|
+
|
|
220
|
+
## Execution boundary
|
|
221
|
+
|
|
222
|
+
Docker and Podman mount the selected worktree and Git metadata. Agents can edit that repository and its Git state. This protects unrelated host paths but is not a boundary against a hostile agent attacking the shared repository. Mount only what the task needs. `local()` runs directly on your machine without isolation. Cloud providers synchronize via Git bundles and file transfers; concurrent host changes cause a recovery error instead of being overwritten.
|
|
223
|
+
|
|
224
|
+
Logs, conversation files and recovery files can contain private prompts or source. Runtime folders and `.env` are excluded from version control. See [Security](SECURITY.md) for the precise boundaries.
|
|
225
|
+
|
|
226
|
+
MIT licensed. See [LICENSE](LICENSE).
|
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
## V1 contract
|
|
4
|
+
|
|
5
|
+
Reusable sandboxes; independent workspaces; current/named/integration branch policies; Claude Code and Codex adapters; native session capture, resume and fork; Docker, Podman, host, Vercel and Daytona providers; command streaming and cancellation; file prompts, expansion, loops and structured responses; setup hooks; typed workflows; CLI initialization; EN/FR documentation; cross-platform tests and package release automation.
|
|
6
|
+
|
|
7
|
+
## V1.x: efficiency and diagnostics
|
|
8
|
+
|
|
9
|
+
- Durable campaign closure receipts to reconcile tracker outages without reimplementing merged issues.
|
|
10
|
+
- Configurable planner policies, merge validation commands and per-role token budgets.
|
|
11
|
+
|
|
12
|
+
- Incremental remote file manifests and compressed transfer batches while preserving recovery guarantees.
|
|
13
|
+
- Content-addressed dependency caches and prebuilt agent images with signed provenance.
|
|
14
|
+
- Configurable recovery retention with an inspect/prune CLI and storage quotas.
|
|
15
|
+
- Structured metrics, OpenTelemetry integration and per-workflow usage budgets.
|
|
16
|
+
- Richer diagnostic reports for provider capabilities and agent CLI compatibility.
|
|
17
|
+
- More hosted-provider contract fixtures and scheduled live compatibility checks.
|
|
18
|
+
|
|
19
|
+
## V2: durable orchestration
|
|
20
|
+
|
|
21
|
+
- Persisted workflow checkpoints and recovery after host restarts.
|
|
22
|
+
- Distributed task queues and worker leases with fencing tokens.
|
|
23
|
+
- Explicit approvals and pause/resume nodes in workflows.
|
|
24
|
+
- Artifact contracts between isolated tasks, with typed validation and lineage.
|
|
25
|
+
- Native terminal transport for cloud backends where reliable PTY APIs are available.
|
|
26
|
+
- Additional agent adapters through the existing domain ports.
|
|
27
|
+
|
|
28
|
+
## Research
|
|
29
|
+
|
|
30
|
+
- Stronger Git metadata isolation for adversarial agents.
|
|
31
|
+
- MicroVM backends and fine-grained outbound network policies.
|
|
32
|
+
- Speculative execution with conflict-aware integration and cost limits.
|
|
33
|
+
|
|
34
|
+
Roadmap items are additions to the v1 contract. They are not prerequisites for running the current library.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Security boundaries
|
|
2
|
+
|
|
3
|
+
Outpost runs coding agents that execute arbitrary project commands. Use it with repositories and credentials appropriate for that task.
|
|
4
|
+
|
|
5
|
+
Docker/Podman expose only the selected checkout, Git metadata and explicit volumes. The Docker socket is not mounted by default. Containers use a chosen UID/GID, dropped capabilities, no-new-privileges and a private home. Extra devices, writable mounts and elevated hooks expand the boundary deliberately.
|
|
6
|
+
|
|
7
|
+
Shared Git metadata is writable by the agent. A mounted sandbox is not an adversarial boundary protecting the host repository or its configuration. Outpost disables host Git hooks for its own Git commands, but a malicious repository can contain other executable configuration or project tooling. Do not run untrusted repositories with valuable host credentials. Host `local()` provides no isolation.
|
|
8
|
+
|
|
9
|
+
Remote providers upload repository history and inputs to the selected cloud account. Explicit credentials and environment files are sent to that environment. Review the cloud provider's own storage/network policy. Concurrent host changes stop synchronization; recovery files preserve prior and incoming state when available.
|
|
10
|
+
|
|
11
|
+
Prompt command expansion only recognizes commands present in the original prompt file. Substitution cannot introduce new expansion fragments. Values substituted inside an original shell command still have shell semantics and must be trusted or quoted by the prompt author.
|
|
12
|
+
|
|
13
|
+
Conversation transcripts, logs, bundles and patches may contain secrets. Runtime files are ignored by Git and sensitive files are created with restrictive permissions where supported. Keep API keys in environment variables or ignored `.env` files. Never embed tokens in tracked configuration, remote URLs or examples.
|
|
14
|
+
|
|
15
|
+
Report vulnerabilities privately using the repository's security reporting channel when enabled, or contact the maintainer through the hosting profile. Do not include live credentials in reports. V1 receives fixes for reproducible security defects.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentAdapter } from "../domain/ports.ts";
|
|
2
|
+
import type { Backlog } from "../domain/backlog.ts";
|
|
3
|
+
import { type SandboxOptions } from "./outpost.ts";
|
|
4
|
+
export interface CampaignEvent {
|
|
5
|
+
readonly phase: "backlog" | "plan" | "implement" | "review" | "merge" | "close";
|
|
6
|
+
readonly cycle: number;
|
|
7
|
+
readonly issue?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CampaignOptions extends Omit<SandboxOptions, "workspace" | "branch" | "agent"> {
|
|
10
|
+
readonly agent: AgentAdapter;
|
|
11
|
+
readonly backlog: Backlog;
|
|
12
|
+
readonly planner?: AgentAdapter | false;
|
|
13
|
+
readonly reviewer?: AgentAdapter | false;
|
|
14
|
+
readonly merger?: AgentAdapter;
|
|
15
|
+
readonly cycles?: number;
|
|
16
|
+
readonly concurrency?: number;
|
|
17
|
+
readonly implementationPasses?: number;
|
|
18
|
+
readonly reviewPasses?: number;
|
|
19
|
+
readonly standards?: string;
|
|
20
|
+
readonly observe?: (event: CampaignEvent) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface IssueOutcome {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly branch: string;
|
|
25
|
+
readonly state: "empty" | "failed" | "merged";
|
|
26
|
+
readonly error?: unknown;
|
|
27
|
+
}
|
|
28
|
+
export interface CampaignResult {
|
|
29
|
+
readonly cycles: number;
|
|
30
|
+
readonly reason: "empty" | "blocked" | "no-progress" | "limit";
|
|
31
|
+
readonly issues: readonly IssueOutcome[];
|
|
32
|
+
}
|
|
33
|
+
export declare function campaign(options: CampaignOptions): Promise<CampaignResult>;
|