@amenophis1er/foreman 0.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/DESIGN.md +408 -0
- package/LICENSE +15 -0
- package/README.md +133 -0
- package/bin/foreman.mjs +58 -0
- package/package.json +68 -0
- package/scripts/prepare.mjs +48 -0
- package/skills/director/SKILL.md +65 -0
- package/src/anthropic-models.ts +54 -0
- package/src/ask.test.ts +88 -0
- package/src/ask.ts +95 -0
- package/src/attachments.test.ts +33 -0
- package/src/attachments.ts +60 -0
- package/src/cli.test.ts +27 -0
- package/src/cli.ts +297 -0
- package/src/codex.test.ts +328 -0
- package/src/codex.ts +196 -0
- package/src/cost-basis.test.ts +76 -0
- package/src/deck.test.ts +402 -0
- package/src/deck.ts +892 -0
- package/src/fork.test.ts +31 -0
- package/src/gateway/ledger.cjs +326 -0
- package/src/gateway/ledger.test.ts +255 -0
- package/src/gateway/llm-gateway.cjs +1411 -0
- package/src/gateway/llm-gateway.test.ts +478 -0
- package/src/gateway.test.ts +226 -0
- package/src/gateway.ts +309 -0
- package/src/instance.ts +124 -0
- package/src/models.test.ts +147 -0
- package/src/models.ts +158 -0
- package/src/notify/commands.test.ts +28 -0
- package/src/notify/commands.ts +73 -0
- package/src/notify/telegram.ts +259 -0
- package/src/notify.test.ts +343 -0
- package/src/notify.ts +495 -0
- package/src/ollama.test.ts +49 -0
- package/src/ollama.ts +49 -0
- package/src/openai-prices.test.ts +58 -0
- package/src/openai-prices.ts +106 -0
- package/src/orchestrator.test.ts +1147 -0
- package/src/orchestrator.ts +2325 -0
- package/src/planner.test.ts +60 -0
- package/src/planner.ts +505 -0
- package/src/policy.test.ts +411 -0
- package/src/policy.ts +599 -0
- package/src/preflight.ts +348 -0
- package/src/prices.test.ts +69 -0
- package/src/prices.ts +90 -0
- package/src/provider.test.ts +366 -0
- package/src/provider.ts +502 -0
- package/src/secrets.test.ts +143 -0
- package/src/secrets.ts +66 -0
- package/src/server.ts +1992 -0
- package/src/services.test.ts +53 -0
- package/src/services.ts +102 -0
- package/src/sse-events.test.ts +83 -0
- package/src/store.test.ts +119 -0
- package/src/store.ts +346 -0
- package/src/tailscale.test.ts +32 -0
- package/src/tailscale.ts +79 -0
- package/src/title.ts +138 -0
- package/src/types.ts +442 -0
- package/ui/dist/assets/index-LAj0Dy9p.css +1 -0
- package/ui/dist/assets/index-lcBy-uRZ.js +65 -0
- package/ui/dist/favicon.svg +8 -0
- package/ui/dist/index.html +14 -0
package/DESIGN.md
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# Foreman — design concept
|
|
2
|
+
|
|
3
|
+
> **Working name: Foreman.** A foreman runs a crew on a job site. Here the job
|
|
4
|
+
> site is a folder on your machine, the crew is Claude agents, and you hand it
|
|
5
|
+
> a mission instead of a checklist. Rename freely (alternates: Overseer, Helm,
|
|
6
|
+
> Conductor, Steward, Skipper).
|
|
7
|
+
|
|
8
|
+
**One line:** an autonomous mission runner. You pick a project folder, type a
|
|
9
|
+
mission, and Foreman plans it, spawns Claude agents to do the work in that
|
|
10
|
+
folder, steers them, answers their questions, approves their tools, verifies
|
|
11
|
+
the result, and reports back — from a single UI, with no terminal.
|
|
12
|
+
|
|
13
|
+
Status: **concept only.** No code yet. This document captures the idea and the
|
|
14
|
+
architecture while the lessons from `claude-golden-eye`'s director mode are
|
|
15
|
+
fresh.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Where this comes from
|
|
20
|
+
|
|
21
|
+
Foreman is the standalone, terminal-free evolution of **director mode**, which
|
|
22
|
+
we built and proved inside the `claude-golden-eye` plugin. There, one Claude
|
|
23
|
+
Code *session* (the director) autonomously ran a mission across other Claude
|
|
24
|
+
Code *sessions* (workers), observed and steered through golden-eye's hooks,
|
|
25
|
+
channel, and MCP tools. It works: in a soak test, a single mission prompt
|
|
26
|
+
produced a correct, tested CLI with the human touching nothing.
|
|
27
|
+
|
|
28
|
+
But director mode is bound to Claude Code **running in terminals**. That forces
|
|
29
|
+
two panes (director + worker), a channels research-preview flag on every
|
|
30
|
+
session, and manual session lifecycle. The friction is structural, not a bug.
|
|
31
|
+
|
|
32
|
+
**The pivot:** stop driving terminals. Use the **Claude Agent SDK** — the same
|
|
33
|
+
Claude Code engine, embeddable in an application — so Foreman *is* the program
|
|
34
|
+
that spawns and drives agents, with the UI as the only surface. Everything we
|
|
35
|
+
learned about director↔worker orchestration carries over; only the substrate
|
|
36
|
+
changes (SDK processes instead of terminal sessions).
|
|
37
|
+
|
|
38
|
+
### What carries over from director mode (hard-won, keep it)
|
|
39
|
+
|
|
40
|
+
- **Plan-first into a tracking doc.** The director always wrote `MISSION.md`
|
|
41
|
+
(mission, DONE-when, budget, checklist, log, decisions) and re-read it every
|
|
42
|
+
wake. The doc — not the context window — is the mission's source of truth, so
|
|
43
|
+
it survives compaction/restart. Keep this verbatim.
|
|
44
|
+
- **The blocked-question protocol.** Terminal question dialogs can't be answered
|
|
45
|
+
remotely, so workers were told: never ask interactively; when you need a
|
|
46
|
+
decision, report "blocked" with the question and end your turn. Foreman keeps
|
|
47
|
+
this shape (the SDK equivalent is a worker signalling the orchestrator), and
|
|
48
|
+
it's cleaner here because the SDK has real permission callbacks.
|
|
49
|
+
- **Verify DONE independently.** The director never trusted a worker's "done" —
|
|
50
|
+
it read the files and ran the tests itself. Non-negotiable.
|
|
51
|
+
- **The escalation contract.** Anything irreversible, out of scope, over
|
|
52
|
+
budget, or looping → escalate to the human, don't power through.
|
|
53
|
+
- **Never let an agent modify its own oversight infrastructure.** A director
|
|
54
|
+
once tried to patch and restart golden-eye's server to unblock itself. Hard
|
|
55
|
+
rule: tooling failure is always an escalation, never a self-repair.
|
|
56
|
+
- **Deterministic loop guards.** The director's own events never woke it;
|
|
57
|
+
action echoes weren't wake events. Any event-driven design needs the same.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Core concept
|
|
62
|
+
|
|
63
|
+
- **Folder-linked.** A Foreman run is bound to one directory on the system. That
|
|
64
|
+
path becomes the `cwd` of every agent it spawns; all work happens there and in
|
|
65
|
+
its subtree. Picking the folder in the UI is the entire "setup."
|
|
66
|
+
- **UI is the I/O surface.** Not a terminal. The UI: pick folder → state mission
|
|
67
|
+
→ watch live → answer the few things only a human should → get the result. The
|
|
68
|
+
dashboard we already designed for golden-eye (agent tree, live transcripts,
|
|
69
|
+
plan board, approve/deny cards) is the right starting shape.
|
|
70
|
+
- **Real agents, not headless one-shots.** Each worker is a full Agent-SDK
|
|
71
|
+
agentic loop (tools, edits, bash, MCP, subagents) — the same Claude Code
|
|
72
|
+
behavior, just embedded and streamed to the UI instead of a TTY.
|
|
73
|
+
- **A director drives workers.** The director role from golden-eye becomes an
|
|
74
|
+
orchestration layer (see §4 for the key open decision on where its
|
|
75
|
+
intelligence lives).
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 3. How it differs from golden-eye (and why it's a separate product)
|
|
80
|
+
|
|
81
|
+
| | golden-eye (keep as is) | Foreman (new) |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| What it is | Claude Code **plugin**: observes real terminal sessions | Standalone **app** that runs agents |
|
|
84
|
+
| Substrate | Claude Code CLI in terminals | Claude Agent SDK, embedded |
|
|
85
|
+
| Dependencies | zero runtime deps (a point of pride) | depends on the Agent SDK + tree |
|
|
86
|
+
| Spends tokens? | never — pure observer | yes — it *is* the agent runtime |
|
|
87
|
+
| Auth | none needed | Anthropic **API key** (see §9) |
|
|
88
|
+
| Surface | dashboard observes; terminals drive | dashboard **is** the driver |
|
|
89
|
+
| Lifecycle | humans open/close sessions | Foreman starts/kills/resumes agents |
|
|
90
|
+
|
|
91
|
+
These are different enough to be **two products sharing UI DNA**, not one. The
|
|
92
|
+
recommendation is to keep golden-eye exactly as it is (clean, zero-dep, ships
|
|
93
|
+
as v0.1.0) and grow Foreman independently, reusing dashboard patterns and the
|
|
94
|
+
director's charter wisdom. Do not rewrite golden-eye into this.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 4. Architecture (draft)
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
┌─────────────────────────── UI (control plane) ───────────────────────────┐
|
|
102
|
+
│ pick folder · state mission · live transcripts · plan board · │
|
|
103
|
+
│ approve/deny cards · pause/kill · cost meter │
|
|
104
|
+
└───────────────▲───────────────────────────────────┬──────────────────────┘
|
|
105
|
+
│ SSE/ws (stream out) │ HTTP (commands in)
|
|
106
|
+
┌───────────────┴───────────────────────────────────▼──────────────────────┐
|
|
107
|
+
│ Orchestrator (Node service) │
|
|
108
|
+
│ • owns runs: {folder, mission, budget, status} │
|
|
109
|
+
│ • spawns/streams/kills SDK agents; routes canUseTool → UI cards │
|
|
110
|
+
│ • persists MISSION.md + run state; enforces budgets & guardrails │
|
|
111
|
+
└───────────────┬───────────────────────────────────────────────────────────┘
|
|
112
|
+
│ Agent SDK (query() / ClaudeSDKClient), cwd = the folder
|
|
113
|
+
┌────────────▼───────────┐ ┌──────────────────────────────┐
|
|
114
|
+
│ Director agent │ ───▶ │ Worker agent(s) │
|
|
115
|
+
│ (strong model, thinking)│ │ (build/edit/test in cwd) │
|
|
116
|
+
│ plans, steers, verifies │ │ report blocked → director │
|
|
117
|
+
└─────────────────────────┘ └──────────────────────────────┘
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**SDK grounding (verified against current docs):**
|
|
121
|
+
|
|
122
|
+
- Package `@anthropic-ai/claude-agent-sdk` (TS) / `claude-agent-sdk` (Py);
|
|
123
|
+
entry `query()` returns an async iterator of messages. Multi-turn
|
|
124
|
+
continuity: Python has `ClaudeSDKClient`; TS has **no client class** — it
|
|
125
|
+
uses streaming input (`AsyncIterable<SDKUserMessage>`) plus the
|
|
126
|
+
`resume`/`continue` options. We stream `AssistantMessage` / `UserMessage` /
|
|
127
|
+
`ResultMessage` to the UI.
|
|
128
|
+
- `cwd` option pins the agent to the chosen folder.
|
|
129
|
+
- `canUseTool(toolName, input, ctx)` callback → `Allow(updated_input?)` or
|
|
130
|
+
`Deny(message)` — note deny takes **no `interrupt` flag**; mid-run
|
|
131
|
+
interruption is done via the query/client's own `interrupt()` method.
|
|
132
|
+
This is how UI approve/deny cards work —
|
|
133
|
+
natively, no channels relay. Precedence: hooks → deny rules → ask rules →
|
|
134
|
+
permission mode → allow rules → canUseTool.
|
|
135
|
+
- Permission modes: `default`, `acceptEdits`, `plan`, `dontAsk`, `auto`,
|
|
136
|
+
`bypassPermissions`. Foreman would run workers in `default`/`acceptEdits`
|
|
137
|
+
with a `canUseTool` gate, never blanket `bypassPermissions`.
|
|
138
|
+
- Hooks (`PreToolUse`/`PostToolUse`/`Stop`/`SubagentStop`/…) run **in the
|
|
139
|
+
orchestrator process, no context cost** — perfect for feeding the same
|
|
140
|
+
observability the golden-eye dashboard renders.
|
|
141
|
+
- `mcpServers` option → agents can use MCP tools (`mcp__<server>__<tool>`).
|
|
142
|
+
- Subagents via the `Agent`/`Task` tool; `agents={...}` defines them with
|
|
143
|
+
per-agent model + tool restrictions + `max_turns`.
|
|
144
|
+
- Sessions: capture `session_id` from `ResultMessage`; `resume` / `continue` /
|
|
145
|
+
`fork_session`; persisted under `~/.claude/projects/<cwd>/<id>.jsonl`, or a
|
|
146
|
+
custom `session_store` for our own backend.
|
|
147
|
+
|
|
148
|
+
### The one decision that shapes everything: where does the director live?
|
|
149
|
+
|
|
150
|
+
- **Option A — Director is an SDK agent too.** Orchestrator spawns a director
|
|
151
|
+
agent (strong model + extended thinking) whose *tools* are "spawn worker",
|
|
152
|
+
"message worker", "answer worker", "read MISSION.md". Workers are separate SDK
|
|
153
|
+
agents (or its subagents). Keeps intelligence in a model, mirrors what we
|
|
154
|
+
proved. Most faithful to director mode.
|
|
155
|
+
- **Option B — Director is orchestrator code calling a model.** The Node
|
|
156
|
+
service holds the loop and calls the model for judgment at each decision
|
|
157
|
+
point. Simpler infra, but drifts back toward "intelligence in the server,"
|
|
158
|
+
which we deliberately rejected in golden-eye.
|
|
159
|
+
- **Option C — No separate director; one agent with subagents.** A single SDK
|
|
160
|
+
agent runs the mission and uses the SDK's own subagents as its crew. Simplest,
|
|
161
|
+
but loses the cross-agent supervision that makes this distinctive — it's
|
|
162
|
+
really just normal delegation with a tracking doc.
|
|
163
|
+
|
|
164
|
+
**Leaning: A.** It preserves the director/worker separation and the
|
|
165
|
+
observability story; the orchestrator stays "dumb pipes + guardrails."
|
|
166
|
+
Workers as separate SDK sessions (not subagents) keep them independently
|
|
167
|
+
observable and resumable, matching golden-eye's model.
|
|
168
|
+
|
|
169
|
+
### The director's wake loop (the hardest part of Option A — design before spike 2)
|
|
170
|
+
|
|
171
|
+
In golden-eye, the channel and hooks defined *when* the director woke and
|
|
172
|
+
*what* it saw. In Foreman that becomes: how does the director learn a worker
|
|
173
|
+
finished, blocked, or went quiet? Under Option A the orchestrator must inject
|
|
174
|
+
events into the director's streaming input, and every director-mode question
|
|
175
|
+
returns:
|
|
176
|
+
|
|
177
|
+
- **Which events wake it.** Wake granularity drives cost: a strong-model
|
|
178
|
+
director woken on every worker turn burns tokens fast. Default should be
|
|
179
|
+
coarse — worker *blocked*, worker *done*, milestone reached, budget
|
|
180
|
+
threshold, silence timeout — not per-turn.
|
|
181
|
+
- **Echo filtering.** The director's own actions (messages it sent, workers it
|
|
182
|
+
spawned) must never wake it. Same deterministic loop guards as golden-eye.
|
|
183
|
+
- **Turn coalescing.** Events arriving while the director is mid-turn queue
|
|
184
|
+
and coalesce into one wake, never interleave.
|
|
185
|
+
|
|
186
|
+
Also worth naming: the director's tools ("spawn worker", "message worker",
|
|
187
|
+
"answer worker", "read mission doc") are **custom in-process MCP tools** the
|
|
188
|
+
orchestrator implements via `createSdkMcpServer` — a real chunk of the
|
|
189
|
+
phase-2 work.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 5. Mission model
|
|
194
|
+
|
|
195
|
+
Unchanged from director mode. On start, the director writes the mission doc at
|
|
196
|
+
`.foreman/MISSION.md` inside the target folder (gitignored by default —
|
|
197
|
+
polluting a real repo's root with an agent artifact is the wrong default):
|
|
198
|
+
|
|
199
|
+
```markdown
|
|
200
|
+
# MISSION: <one line>
|
|
201
|
+
DONE WHEN: <verifiable criteria>
|
|
202
|
+
BUDGET: max <N> turns · <$X> · escalate at <T>
|
|
203
|
+
## Plan
|
|
204
|
+
- [ ] 1. <verifiable milestone>
|
|
205
|
+
## Log
|
|
206
|
+
## Decisions
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The UI renders this as the plan board and reads it as run state. It is the
|
|
210
|
+
durable record; a Foreman run can be killed and resumed from it. That includes
|
|
211
|
+
**orchestrator crash recovery**: if the Node service dies mid-run, the mission
|
|
212
|
+
doc plus persisted SDK sessions (`sessionStore` + `resume`) are enough to
|
|
213
|
+
reconstruct and continue the run.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 6. Safety & guardrails (first-class, not bolted on)
|
|
218
|
+
|
|
219
|
+
An autonomous agent runtime with shell access and a wallet is a different risk
|
|
220
|
+
class than an observer. Non-negotiables:
|
|
221
|
+
|
|
222
|
+
- **Bounded runs.** `max_turns` and `max_budget_usd` per run (the SDK enforces
|
|
223
|
+
both; `error_max_budget_usd` stops subagents and refuses new spawns). Surface
|
|
224
|
+
a live cost meter (`ResultMessage.total_cost_usd`) and a hard cap in the UI.
|
|
225
|
+
- **`canUseTool` gate, deny-by-default for danger.** Auto-allow in-folder,
|
|
226
|
+
reversible operations; route anything irreversible or out-of-scope to a UI
|
|
227
|
+
approve/deny card; hard-deny known-destructive patterns.
|
|
228
|
+
- **Folder confinement — policy-enforced, not sandboxed.** `cwd` pins where
|
|
229
|
+
the agent works; it does **not** sandbox anything — Bash can write anywhere,
|
|
230
|
+
and `canUseTool` path-inspection of shell commands is best-effort (paths
|
|
231
|
+
hide inside scripts, redirects, `cd`). Policy: auto-allow only clearly
|
|
232
|
+
in-folder writes, route the rest to approval. OS-level sandboxing (or
|
|
233
|
+
containerized workers, see open questions) is the hardening path if
|
|
234
|
+
policy-only proves too leaky.
|
|
235
|
+
- **Escalation contract** (from director mode): irreversible / out-of-scope /
|
|
236
|
+
over-budget / looping → stop and ask the human.
|
|
237
|
+
- **No self-modification of Foreman itself.** The infra rule, carried over.
|
|
238
|
+
- **Pause / kill switch** always available in the UI; the orchestrator
|
|
239
|
+
interrupts a running agent via the SDK's `interrupt()` on the query/client
|
|
240
|
+
(deny responses carry no interrupt flag).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 7. Observability
|
|
245
|
+
|
|
246
|
+
Reuse golden-eye's dashboard patterns wholesale: agent tree, full-height live
|
|
247
|
+
transcripts, plan board, timeline, cost/token meters. Because SDK hooks run in
|
|
248
|
+
the orchestrator process, we get the event stream for free without tailing
|
|
249
|
+
JSONL. This is where Foreman and golden-eye visibly share DNA.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 8. Worker senses: browser tooling & visual verification
|
|
254
|
+
|
|
255
|
+
Workers (and the director) shouldn't have to trust "tests pass" — they should
|
|
256
|
+
be able to *look at* the running app. This is mostly free via `mcpServers`,
|
|
257
|
+
but the choice of tool matters:
|
|
258
|
+
|
|
259
|
+
- **Playwright MCP (`@playwright/mcp`) is the default.** Given to workers via
|
|
260
|
+
`mcpServers`, it launches a **headless, disposable** browser: navigate,
|
|
261
|
+
click, fill forms, read console errors, take screenshots. Agents genuinely
|
|
262
|
+
*see* — the Read tool renders images, so a worker screenshots the page and
|
|
263
|
+
visually inspects the result. The director uses the same to verify DONE
|
|
264
|
+
against the real app, not just the test suite.
|
|
265
|
+
- **Ruled out as defaults:** tools that drive the human's real Chrome
|
|
266
|
+
(claude-in-chrome style — your logged-in sessions and cookies under an
|
|
267
|
+
unattended agent) and full **computer use** (desktop control — hands the
|
|
268
|
+
whole machine to an agent whose story is "confined to a folder"). Keep the
|
|
269
|
+
browser headless and disposable.
|
|
270
|
+
- **Guardrails compose.** Browser MCP tools flow through the same
|
|
271
|
+
`canUseTool` gate as everything else: auto-allow navigation to
|
|
272
|
+
`localhost`, route external URLs to an approval card.
|
|
273
|
+
- **Docker synergy:** a Playwright-enabled base image gives the browser
|
|
274
|
+
story and the isolation story in one artifact (see §12 on containerized
|
|
275
|
+
workers).
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## 9. Auth & billing (the real gate)
|
|
280
|
+
|
|
281
|
+
> **Superseded in part.** This section predates instance pinning. Foreman now
|
|
282
|
+
> points at an *installed* Claude Code and uses whatever that install is logged
|
|
283
|
+
> into, which is how a personal Foreman rides a subscription without any third
|
|
284
|
+
> party minting tokens. The generalisation of that idea — Codex installs, local
|
|
285
|
+
> Ollama, OpenAI-compatible endpoints — is designed in
|
|
286
|
+
> [docs/provider-model.md](docs/provider-model.md). The last bullet below still
|
|
287
|
+
> governs everything.
|
|
288
|
+
|
|
289
|
+
- **API key only.** SDK apps authenticate via `ANTHROPIC_API_KEY` (or a cloud
|
|
290
|
+
provider: Bedrock/Vertex/Foundry). Anthropic does **not** permit third-party
|
|
291
|
+
SDK apps to offer claude.ai login to end users — so a distributed Foreman
|
|
292
|
+
can't ride users' subscriptions; each install brings its own key. For
|
|
293
|
+
**personal use this is fine** (your key, your machine).
|
|
294
|
+
- **Foreman spends money autonomously.** Every run bills the key. Budgets and
|
|
295
|
+
the cost meter aren't nice-to-haves; they're the safety floor.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 10. Phased build (when we start)
|
|
300
|
+
|
|
301
|
+
> **Status (2026-09-03).** Phases 1–3 are built and verified, plus several
|
|
302
|
+
> items beyond the original plan:
|
|
303
|
+
> phase 1 spike (one worker, SSE transcript, approve/deny) ✅ ·
|
|
304
|
+
> phase 2 director (MISSION.md, spawn/message workers, ask_human, budgets,
|
|
305
|
+
> independent verification) ✅ · phase 3 dashboard (React + design system,
|
|
306
|
+
> agent tree, transcript, plan board) ✅ · persistence (append-only event
|
|
307
|
+
> logs, atomic meta, orphan sweep, history replay) ✅ · **fleet** (multi-
|
|
308
|
+
> project home, zoomable project views, composer, concurrent missions —
|
|
309
|
+
> one per project) ✅ · per-mission model selection (director/workers) ✅ ·
|
|
310
|
+
> resume of interrupted runs via director session restore ✅.
|
|
311
|
+
> Parallel workers already occur naturally (the director issues parallel
|
|
312
|
+
> spawn_worker tool calls); phase 4 below remains for the *management*
|
|
313
|
+
> around them (wake loop, steering, conflict policy).
|
|
314
|
+
|
|
315
|
+
1. **Spike:** orchestrator spawns ONE SDK worker in a chosen folder, streams its
|
|
316
|
+
transcript to a minimal UI, `canUseTool` → an approve/deny card. Prove the
|
|
317
|
+
substrate end to end.
|
|
318
|
+
2. **Mission + director (Option A):** director agent plans `MISSION.md`, spawns
|
|
319
|
+
one worker, steers via tools, verifies DONE, respects budgets. This is
|
|
320
|
+
director-mode reborn without terminals.
|
|
321
|
+
3. **Dashboard parity:** port golden-eye's tree/transcript/plan/timeline views.
|
|
322
|
+
4. **Multi-worker:** director runs N workers for one mission. N workers
|
|
323
|
+
sharing one `cwd` will trample each other's edits — per-worker git
|
|
324
|
+
worktrees (or serialized write access) is the likely answer.
|
|
325
|
+
5. **Polish:** pause/resume/kill, run history, cost caps, guardrail tuning.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## 11. Non-goals
|
|
330
|
+
|
|
331
|
+
**What Foreman is:** a governance layer — goal doc + budget + policy +
|
|
332
|
+
escalation — around autonomous work, on your own machine, in your own folders.
|
|
333
|
+
Coding was the first capability plugged in; the browser was the second.
|
|
334
|
+
|
|
335
|
+
The boundaries below exist because the alternative to each is a real, working
|
|
336
|
+
product that already occupies that ground. Every one of them is a bet, and
|
|
337
|
+
crossing it does not make Foreman more capable — it makes Foreman a lesser
|
|
338
|
+
copy of something else. They are permanent, not "at least at first".
|
|
339
|
+
|
|
340
|
+
### The mission is the unit of work
|
|
341
|
+
|
|
342
|
+
- **Conversation produces missions; it never does the work.** The planner is
|
|
343
|
+
read-only — Read, Grep, Glob, and nothing else — permanently. Not "read-only
|
|
344
|
+
until a small edit would be convenient". If it needs doing, it becomes a
|
|
345
|
+
mission the human starts, with a budget and DONE WHEN criteria. The day the
|
|
346
|
+
planner writes a file, Foreman is a chat client with a cost meter.
|
|
347
|
+
- **Not chat-first.** The project view's centre of gravity is the mission and
|
|
348
|
+
its verification, not the transcript. Talking is the cheap step before
|
|
349
|
+
committing, not the product.
|
|
350
|
+
- **No unverified completion.** The director reads the files and runs the
|
|
351
|
+
checks itself. A worker's "done" is evidence, never a result.
|
|
352
|
+
|
|
353
|
+
### The desk shows the work; it is not a workstation
|
|
354
|
+
|
|
355
|
+
- **No terminal in the UI.** Foreman runs on your machine and you already have
|
|
356
|
+
one. An unrestricted shell in the panel is a hole straight through
|
|
357
|
+
`canUseTool`, which is the entire safety floor.
|
|
358
|
+
- **The deck is diff and artifacts**, not a file manager and not an editor.
|
|
359
|
+
Its job is to show what this mission changed, which is something your editor
|
|
360
|
+
cannot tell you and Foreman can.
|
|
361
|
+
|
|
362
|
+
### It runs in your real folders, as you
|
|
363
|
+
|
|
364
|
+
- **No containers, no isolation layer.** The agent edits the actual repository.
|
|
365
|
+
That is the bet: policy plus budgets plus an audit trail, rather than a
|
|
366
|
+
sandbox you then have to sync back.
|
|
367
|
+
- **Never mint credentials.** Foreman reads what a first-party CLI already put
|
|
368
|
+
there (`~/.claude`, `~/.codex`); it does not reimplement anyone's OAuth flow
|
|
369
|
+
to obtain tokens itself. See [docs/provider-model.md](docs/provider-model.md).
|
|
370
|
+
- **Not blanket `bypassPermissions`.** Autonomy comes from good `canUseTool`
|
|
371
|
+
policy + budgets, never from removing the floor.
|
|
372
|
+
|
|
373
|
+
### Single-user, single-purpose
|
|
374
|
+
|
|
375
|
+
- Not a hosted or multi-tenant service.
|
|
376
|
+
- No embeddable widget, no plugin marketplace, no agent-as-a-product surface.
|
|
377
|
+
- Not a replacement for golden-eye — the observer plugin stays its own thing.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## 12. Open questions
|
|
382
|
+
|
|
383
|
+
- Director substrate: confirm Option A vs C after the spike.
|
|
384
|
+
- Workers as separate SDK sessions vs subagents (observability & resume vs
|
|
385
|
+
simplicity).
|
|
386
|
+
- How much of golden-eye's server/UI can be literally reused vs forked.
|
|
387
|
+
- Do we ever need a human-in-the-loop "review before commit/push" stage as a
|
|
388
|
+
built-in mission phase?
|
|
389
|
+
- Containerized workers (Docker): worth it for isolation/"full unleash" runs,
|
|
390
|
+
or is policy + budgets enough for personal use?
|
|
391
|
+
- Mission shapes (the super-agent direction): keep the MISSION.md *invariant*
|
|
392
|
+
(goal, success criteria, decisions, log — externalized outside the context
|
|
393
|
+
window; it is what makes runs resumable, auditable, steerable) but free the
|
|
394
|
+
*format*. Proportionality is now in the charter (a 3-line doc is valid for
|
|
395
|
+
a small task); next is shape-awareness — **build** (deliverable, DONE WHEN:
|
|
396
|
+
today's checklist), **research/decide** (deliverable is an answer + a
|
|
397
|
+
recommendation), **assist/monitor** (ongoing goal, "until told to stop",
|
|
398
|
+
per-period budgets, Notifier as heartbeat). The doc skeleton should follow
|
|
399
|
+
the declared shape. Foreman's long-term identity: a governance layer
|
|
400
|
+
(goal doc + budget + policy + escalation) around any capable agent — coding
|
|
401
|
+
was just the first capability plugged in; the browser (below) is the second.
|
|
402
|
+
- Unattended operation: a "Trust this run" pre-grant toggle, plus human
|
|
403
|
+
notification channels (Telegram/Slack/webhook behind a Notifier interface)
|
|
404
|
+
with an availability policy (quiet hours, severity threshold) and an
|
|
405
|
+
escalation ladder — question unanswered for N minutes → notify; still
|
|
406
|
+
unanswered → director takes the conservative path and records it in
|
|
407
|
+
Decisions, or parks the milestone. Cards never expire today; missions
|
|
408
|
+
stall politely until answered.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amen AMOUZOU
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Foreman
|
|
2
|
+
|
|
3
|
+
An autonomous mission runner on the [Claude Agent SDK]. You link project
|
|
4
|
+
folders, write a mission, and Foreman's **director** agent plans it into
|
|
5
|
+
`.foreman/MISSION.md`, delegates implementation to **worker** sessions,
|
|
6
|
+
answers or escalates their questions, verifies the result independently, and
|
|
7
|
+
reports back — all from one browser dashboard, no terminal.
|
|
8
|
+
|
|
9
|
+
Foreman is the standalone evolution of [claude-golden-eye]'s director mode:
|
|
10
|
+
same director/worker doctrine, but the agents are embedded SDK sessions
|
|
11
|
+
driven by this app instead of terminal sessions observed by a plugin.
|
|
12
|
+
(Golden-eye still observes Foreman's agents for free — they are real Claude
|
|
13
|
+
Code sessions.)
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
Foreman needs Node 20 or newer and a Claude Code login (or an API key) on the
|
|
18
|
+
machine it runs on. Then:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npx @amenophis1er/foreman # try it — starts the server, serves http://localhost:4177
|
|
22
|
+
npm install -g @amenophis1er/foreman # keep it — then `foreman` from any shell
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
foreman doctor # what this machine can run, what is missing, how to fix it
|
|
27
|
+
foreman # start in this terminal (Ctrl+C stops it)
|
|
28
|
+
foreman up # …or in the background; foreman down stops it, foreman status asks
|
|
29
|
+
foreman open # the dashboard, in your browser
|
|
30
|
+
foreman service install # keep it running for good: start at login, restart if it dies
|
|
31
|
+
foreman --help # the rest, and the environment variables
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`foreman doctor` prints the same checklist the server prints on start —
|
|
35
|
+
credentials and which account pays, the Claude Code install, Ollama and Codex
|
|
36
|
+
if present, the browser missions will use, the port, Tailscale, the data
|
|
37
|
+
directory — and exits. Nothing blocks unless it says so.
|
|
38
|
+
|
|
39
|
+
**On the move.** If the machine is on a [Tailscale] tailnet, Foreman listens
|
|
40
|
+
on the tailnet address too (never on every interface — there is no login),
|
|
41
|
+
and the links it sends to your phone use the tailnet name. Link the Telegram
|
|
42
|
+
bot in Settings → Notifications and the phone can answer asks, plan and start
|
|
43
|
+
missions, and open what the crew built. `foreman service install` is what
|
|
44
|
+
keeps the server up while the lid is closed.
|
|
45
|
+
|
|
46
|
+
**Platforms.** macOS is where Foreman is developed and tested. Linux is
|
|
47
|
+
verified on Debian with Node 22: install, `foreman doctor`, `foreman up` /
|
|
48
|
+
`status` / `down` and the dashboard all work; `foreman service install` needs
|
|
49
|
+
a systemd user session (a desktop, or `loginctl enable-linger`), and browser
|
|
50
|
+
missions need Google Chrome or `npx playwright install chromium` with
|
|
51
|
+
`FOREMAN_BROWSER=chromium`. Windows is not yet tested natively — use WSL2 for
|
|
52
|
+
now; `foreman service` has no Windows implementation, `foreman up` works.
|
|
53
|
+
|
|
54
|
+
**From a checkout** (contributing):
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
npm ci && npm run setup # dependencies, then the dashboard build
|
|
58
|
+
npm start # serves http://localhost:4177
|
|
59
|
+
npm test · npm run typecheck · npm run dev # tests · both tsconfigs · API + Vite together
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
[Tailscale]: https://tailscale.com
|
|
63
|
+
|
|
64
|
+
### Which account pays
|
|
65
|
+
|
|
66
|
+
The SDK spawns your local Claude Code engine, so missions run on whatever that
|
|
67
|
+
install is logged in with — a Claude subscription or an `ANTHROPIC_API_KEY`.
|
|
68
|
+
Both report real per-run cost, so budgets bind either way.
|
|
69
|
+
|
|
70
|
+
A machine can hold more than one login, and `CLAUDE_CONFIG_DIR` inherited from
|
|
71
|
+
the launching shell silently decides which one is used. So startup prints the
|
|
72
|
+
account it resolved to, and the dashboard shows it beside every place a mission
|
|
73
|
+
can be started:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
✓ Credentials Claude subscription — you@example.com · Your Org
|
|
77
|
+
✓ Claude Code /Users/you/.claude · bundled executable
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Pin it explicitly with `FOREMAN_CLAUDE_CONFIG_DIR`, and assert the mode you
|
|
81
|
+
intend with `FOREMAN_AUTH_MODE=api-key|subscription` so an unset key fails at
|
|
82
|
+
startup instead of quietly billing the other account. A project can pin its own
|
|
83
|
+
install, and choose whether it inherits the server's billing or uses that
|
|
84
|
+
install's own login — which is what makes personal and work projects coexist on
|
|
85
|
+
one server.
|
|
86
|
+
|
|
87
|
+
Dev loop: `npm run dev` (API + Vite, proxied to :4177) · `npm test` ·
|
|
88
|
+
`npm run typecheck` · `scripts/dev-restart.sh` (restarts the server only when
|
|
89
|
+
no run, ask or planner turn would be lost).
|
|
90
|
+
|
|
91
|
+
## Using it
|
|
92
|
+
|
|
93
|
+
1. **Fleet** (`/`): link a folder as a project. Cards show status, live
|
|
94
|
+
mission cost, and a pulsing **needs you** strip when approvals or
|
|
95
|
+
questions wait.
|
|
96
|
+
2. **Project view**: write the mission in the composer (say what DONE looks
|
|
97
|
+
like; flag decisions the director must ask you about), set a budget cap
|
|
98
|
+
and optional director/worker models, Start.
|
|
99
|
+
3. While running: approve/deny tool cards (or **Always** per tool per run),
|
|
100
|
+
answer director questions, watch the plan board tick as MISSION.md
|
|
101
|
+
updates. Interrupt anytime.
|
|
102
|
+
4. Every run persists (`~/.foreman/`): refresh-proof, browsable history with
|
|
103
|
+
full replay, and a **⟳ Resume** button on interrupted runs that restores
|
|
104
|
+
the director's session and re-verifies state before continuing.
|
|
105
|
+
|
|
106
|
+
Missions in real repositories are fine: `.foreman/` git-ignores itself, the
|
|
107
|
+
repo's `CLAUDE.md` loads into workers, and git operations go through your
|
|
108
|
+
approval cards.
|
|
109
|
+
|
|
110
|
+
## Architecture
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
ui/ React 19 + Vite dashboard (design tokens in src/design/)
|
|
114
|
+
src/server.ts HTTP + SSE wiring only
|
|
115
|
+
src/orchestrator.ts MissionRun: director + workers + budget + escalation
|
|
116
|
+
src/policy.ts permission policy (what auto-allows vs. asks you)
|
|
117
|
+
src/store.ts ~/.foreman persistence: append-only event logs, atomic meta
|
|
118
|
+
src/types.ts shared contracts
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- **One active mission per project; many across projects.** SSE frames carry
|
|
122
|
+
`{runId, projectId}` envelopes; persisted logs are replayed through the
|
|
123
|
+
same reducer that renders live events.
|
|
124
|
+
- The director's tools (`spawn_worker`, `message_worker`, `ask_human`) are
|
|
125
|
+
in-process MCP tools; worker calls block inside the director's tool call,
|
|
126
|
+
so reports land in its context as ordinary tool results.
|
|
127
|
+
- Budgets are enforced before any new worker work; guarded asks (e.g. writes
|
|
128
|
+
outside the folder) always prompt, even after "Always".
|
|
129
|
+
|
|
130
|
+
Design history and roadmap: [DESIGN.md](DESIGN.md).
|
|
131
|
+
|
|
132
|
+
[Claude Agent SDK]: https://code.claude.com/docs/en/agent-sdk
|
|
133
|
+
[claude-golden-eye]: ../claude-golden-eye
|
package/bin/foreman.mjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `foreman` command.
|
|
4
|
+
*
|
|
5
|
+
* Everything resolves from this file's own location rather than the working
|
|
6
|
+
* directory, so the server can be started from anywhere — which is the whole
|
|
7
|
+
* point of having a bin. `src/` ships as TypeScript, so tsx is registered as a
|
|
8
|
+
* loader here rather than requiring a build step before first run.
|
|
9
|
+
*
|
|
10
|
+
* npx @amenophis1er/foreman start, right now, from nothing
|
|
11
|
+
* npm i -g @amenophis1er/foreman then `foreman` from any shell
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import { register } from 'tsx/esm/api';
|
|
15
|
+
|
|
16
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
17
|
+
|
|
18
|
+
const USAGE = `foreman ${pkg.version}
|
|
19
|
+
|
|
20
|
+
foreman Start in this terminal (same as "start"); Ctrl+C stops it
|
|
21
|
+
foreman up Start in the background; logs to ~/.foreman/logs/server.log
|
|
22
|
+
foreman down Stop a background server started with "up"
|
|
23
|
+
foreman status Is a server up? Which port, which pid?
|
|
24
|
+
foreman doctor Check credentials, providers, browser, port, Tailscale — and exit
|
|
25
|
+
foreman open Open the dashboard in your browser
|
|
26
|
+
foreman service install Keep Foreman running: start at login, restart if it dies
|
|
27
|
+
foreman service uninstall Remove that
|
|
28
|
+
foreman service status Is the service registered and running?
|
|
29
|
+
foreman service logs Tail the service's log
|
|
30
|
+
foreman --version | --help
|
|
31
|
+
|
|
32
|
+
Environment:
|
|
33
|
+
PORT Listen port (default 4177)
|
|
34
|
+
FOREMAN_HOME State directory (default ~/.foreman)
|
|
35
|
+
FOREMAN_BIND auto (loopback + Tailscale, default) | local | all
|
|
36
|
+
FOREMAN_BROWSER Browser for missions: chrome (default), chromium, msedge, firefox
|
|
37
|
+
FOREMAN_CLAUDE_CONFIG_DIR Claude Code install missions run under
|
|
38
|
+
FOREMAN_CLAUDE_EXECUTABLE Claude Code executable (default: bundled)
|
|
39
|
+
FOREMAN_AUTH_MODE Assert 'api-key' or 'subscription'; fail on mismatch
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const [command = 'start', ...rest] = process.argv.slice(2);
|
|
43
|
+
|
|
44
|
+
if (command === '--help' || command === '-h' || command === 'help') {
|
|
45
|
+
process.stdout.write(USAGE);
|
|
46
|
+
} else if (command === '--version' || command === '-v' || command === 'version') {
|
|
47
|
+
process.stdout.write(`${pkg.version}\n`);
|
|
48
|
+
} else if (command === 'start') {
|
|
49
|
+
register();
|
|
50
|
+
await import(new URL('../src/server.ts', import.meta.url).href);
|
|
51
|
+
} else if (['doctor', 'open', 'service', 'up', 'down', 'status'].includes(command)) {
|
|
52
|
+
register();
|
|
53
|
+
const { runCli } = await import(new URL('../src/cli.ts', import.meta.url).href);
|
|
54
|
+
process.exitCode = await runCli(command, rest, { version: pkg.version, bin: new URL(import.meta.url) });
|
|
55
|
+
} else {
|
|
56
|
+
process.stderr.write(`foreman: unknown command "${command}"\n\n${USAGE}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|