smol-symphony 0.3.2 → 0.4.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/AGENTS.md +6 -3
- package/PRODUCT.md +2 -2
- package/README.md +99 -85
- package/WORKFLOW.template.yaml +55 -11
- package/WORKFLOW.yaml +9 -3
- package/assets/symphony-mise.system.toml +6 -0
- package/dist/core/credential/adapter-config.js +28 -0
- package/dist/core/credential/adapter-config.js.map +1 -1
- package/dist/core/credential/availability.js +44 -1
- package/dist/core/credential/availability.js.map +1 -1
- package/dist/core/credential/extract.js +34 -0
- package/dist/core/credential/extract.js.map +1 -1
- package/dist/core/credential/fake-creds.js +39 -2
- package/dist/core/credential/fake-creds.js.map +1 -1
- package/dist/core/credential/shape.js +19 -0
- package/dist/core/credential/shape.js.map +1 -1
- package/dist/core/image/managed-image.js +3 -12
- package/dist/core/image/managed-image.js.map +1 -1
- package/dist/core/mcp/pi-extension.js +124 -0
- package/dist/core/mcp/pi-extension.js.map +1 -0
- package/dist/core/schedule/sleep-cycle.js +11 -6
- package/dist/core/schedule/sleep-cycle.js.map +1 -1
- package/dist/core/schedule/tick.js +1 -0
- package/dist/core/schedule/tick.js.map +1 -1
- package/dist/core/workflow/derive.js +2 -0
- package/dist/core/workflow/derive.js.map +1 -1
- package/dist/core/workflow/parse.js +6 -1
- package/dist/core/workflow/parse.js.map +1 -1
- package/dist/core/workflow/validate.js +2 -2
- package/dist/core/workflow/validate.js.map +1 -1
- package/dist/shell/adapter/adapter-registry.js +23 -1
- package/dist/shell/adapter/adapter-registry.js.map +1 -1
- package/dist/shell/{cli → adapter}/doctor.js +8 -2
- package/dist/shell/adapter/doctor.js.map +1 -0
- package/dist/shell/adapter/gondolin-image-fetch.js +17 -6
- package/dist/shell/adapter/gondolin-image-fetch.js.map +1 -1
- package/dist/shell/{main-scaffold.js → adapter/scaffold.js} +4 -4
- package/dist/shell/adapter/scaffold.js.map +1 -0
- package/dist/shell/adapter/workflow-loader.js +20 -1
- package/dist/shell/adapter/workflow-loader.js.map +1 -1
- package/dist/shell/interp/credential-defaults.js +83 -1
- package/dist/shell/interp/credential-defaults.js.map +1 -1
- package/dist/shell/interp/credential.js +10 -1
- package/dist/shell/interp/credential.js.map +1 -1
- package/dist/shell/interp/ensure-tracker-root.js +30 -0
- package/dist/shell/interp/ensure-tracker-root.js.map +1 -0
- package/dist/shell/interp/tracker-disk.js +19 -0
- package/dist/shell/interp/tracker-disk.js.map +1 -1
- package/dist/shell/interp/vm.js +15 -1
- package/dist/shell/interp/vm.js.map +1 -1
- package/dist/shell/main-credential.js +1 -1
- package/dist/shell/main-credential.js.map +1 -1
- package/dist/shell/main-doctor.js +1 -1
- package/dist/shell/main-doctor.js.map +1 -1
- package/dist/shell/main-http-handler.js +4 -4
- package/dist/shell/main-http-handler.js.map +1 -1
- package/dist/shell/main-http-views.js +0 -19
- package/dist/shell/main-http-views.js.map +1 -1
- package/dist/shell/main-preflight.js +1 -1
- package/dist/shell/main-preflight.js.map +1 -1
- package/dist/shell/main-runner.js +28 -22
- package/dist/shell/main-runner.js.map +1 -1
- package/dist/shell/main.js +14 -6
- package/dist/shell/main.js.map +1 -1
- package/package.json +2 -3
- package/dist/shell/cli/doctor.js.map +0 -1
- package/dist/shell/main-scaffold.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -94,11 +94,14 @@ re-express, not a directive.
|
|
|
94
94
|
|
|
95
95
|
## Build, test, and check before declaring done
|
|
96
96
|
|
|
97
|
-
- `npm run
|
|
98
|
-
|
|
97
|
+
- `npm run verify` — must pass (typecheck + eslint purity/budgets + depcruise
|
|
98
|
+
walls + the three ratcheted arch gates against `arch-baseline.json` + tests).
|
|
99
|
+
CI runs the same gates, so a red gate here is a red PR.
|
|
99
100
|
- `npm run build` — must pass.
|
|
100
101
|
|
|
101
|
-
Run
|
|
102
|
+
Run both before calling `symphony.transition` into a terminal state. If a gate
|
|
103
|
+
fails "good news" (the count FELL), lower the matching `arch-baseline.json`
|
|
104
|
+
number in the same commit — that is the ratchet locking in the win.
|
|
102
105
|
|
|
103
106
|
## Filing tracker issues
|
|
104
107
|
|
package/PRODUCT.md
CHANGED
|
@@ -23,7 +23,7 @@ process is logging.
|
|
|
23
23
|
|
|
24
24
|
smol-symphony is a small TypeScript orchestrator that takes Markdown issues off a
|
|
25
25
|
local tracker, prepares per-issue workspaces, and runs coding agents
|
|
26
|
-
(Claude Code, Codex
|
|
26
|
+
(Claude Code, Codex) inside isolated per-issue Gondolin microVMs over
|
|
27
27
|
ACP. The
|
|
28
28
|
HTTP dashboard exists to do two things well:
|
|
29
29
|
|
|
@@ -83,7 +83,7 @@ Three patterns this must never resemble:
|
|
|
83
83
|
stuck?" and "is anything running?" Density beats whitespace luxury for
|
|
84
84
|
the running / retry / issue tables.
|
|
85
85
|
|
|
86
|
-
4. **Agents are not the brand.** This tool dispatches Claude, Codex
|
|
86
|
+
4. **Agents are not the brand.** This tool dispatches Claude, Codex —
|
|
87
87
|
it does not perform AI-ness. The product narrative is "small orchestrator
|
|
88
88
|
with isolated VM execution", not "AI-powered work runner". Visual language
|
|
89
89
|
should reflect that.
|
package/README.md
CHANGED
|
@@ -5,15 +5,18 @@
|
|
|
5
5
|
> repository was authored by those agents under human review.
|
|
6
6
|
|
|
7
7
|
A small TypeScript orchestrator that reads issues off a local Markdown tracker,
|
|
8
|
-
prepares per-issue workspaces, and runs coding agents (Claude Code, Codex
|
|
9
|
-
|
|
8
|
+
prepares per-issue workspaces, and runs coding agents (Claude Code, Codex)
|
|
9
|
+
inside isolated per-issue [Gondolin](https://github.com/earendil-works/gondolin)
|
|
10
10
|
microVMs over the [Agent Client Protocol](https://agentclientprotocol.com).
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
a GitHub remote
|
|
16
|
-
workspace for review.
|
|
12
|
+
You file issues; symphony dispatches one agent per issue and handles state,
|
|
13
|
+
retry, and concurrency. The agent signals progress through an injected MCP
|
|
14
|
+
server (`transition`, `request_human_steering`, `propose_issue`). When you point
|
|
15
|
+
it at a GitHub remote it opens a pull request per issue; in local-only mode the
|
|
16
|
+
per-issue `agent/<id>` branch is left in the workspace for review.
|
|
17
|
+
|
|
18
|
+
**New here? Jump to [Quick start](#quick-start)** — install, scaffold, run, with
|
|
19
|
+
no repo checkout and no image to build.
|
|
17
20
|
|
|
18
21
|
```
|
|
19
22
|
┌──────────────────────────────────────────────────────────────────────────┐
|
|
@@ -45,96 +48,103 @@ original architectural narrative, see
|
|
|
45
48
|
|
|
46
49
|
## Quick start
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
From zero to your first dispatched issue. **No repo checkout, no image to build** —
|
|
52
|
+
the agent image is a prebuilt asset symphony fetches from a published release the
|
|
53
|
+
first time it runs.
|
|
51
54
|
|
|
52
55
|
```bash
|
|
53
|
-
# 1.
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
# WORKFLOW.yaml pins, so a first run needs no edit.
|
|
57
|
-
git clone https://github.com/dizk/smol-symphony.git
|
|
58
|
-
cd smol-symphony && npm install && npm run build:image
|
|
56
|
+
# 1. Install symphony. (Or skip this and prefix each command below with `npx`,
|
|
57
|
+
# e.g. `npx smol-symphony doctor WORKFLOW.yaml`.)
|
|
58
|
+
npm i -g smol-symphony
|
|
59
59
|
|
|
60
|
-
# 2. In your project, scaffold
|
|
61
|
-
#
|
|
62
|
-
#
|
|
60
|
+
# 2. In your project, scaffold a starter workflow. With no WORKFLOW.yaml present,
|
|
61
|
+
# symphony offers to write a ~30-line starter (plus a prompts/Todo.md and an
|
|
62
|
+
# issue-filing skill), then exits so you can glance at it. It runs as-is.
|
|
63
63
|
cd /path/to/your/project
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# 3.
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# 5. Run symphony and watch it dispatch.
|
|
80
|
-
npx smol-symphony WORKFLOW.yaml --port 8787
|
|
81
|
-
# Open http://127.0.0.1:8787/ — issue 1 moves from "on disk" into a running
|
|
82
|
-
# session as symphony boots a per-issue microVM and dispatches the agent.
|
|
64
|
+
symphony WORKFLOW.yaml
|
|
65
|
+
|
|
66
|
+
# 3. Check the host is ready before the first dispatch. `doctor` runs every
|
|
67
|
+
# prerequisite probe — Node version, the agent image, your adapter credential,
|
|
68
|
+
# a writable tracker, a bindable dashboard port — and prints a PASS/FAIL line
|
|
69
|
+
# with a one-line fix for each failure, exiting 0 only if every check passes.
|
|
70
|
+
symphony doctor WORKFLOW.yaml
|
|
71
|
+
|
|
72
|
+
# 4. Run symphony. The first run downloads the prebuilt agent image (one-time,
|
|
73
|
+
# surfaced on the dashboard); then it serves the dashboard and starts dispatching.
|
|
74
|
+
symphony WORKFLOW.yaml --port 8787
|
|
75
|
+
|
|
76
|
+
# 5. Open http://127.0.0.1:8787/ and add your first issue from the "new issue"
|
|
77
|
+
# form. symphony picks it up, boots a per-issue microVM, and dispatches the
|
|
78
|
+
# agent — watch the issue move from "on disk" into a running session.
|
|
83
79
|
```
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
That's the whole path. Two host prerequisites symphony can't install for you,
|
|
82
|
+
both checked by `doctor` in step 3:
|
|
83
|
+
|
|
84
|
+
- **Node.js ≥ 23.6** (the `engines.node` floor; `doctor` reports your version).
|
|
85
|
+
- **One adapter credential.** For the default `claude` adapter, a
|
|
86
|
+
`~/.claude/.credentials.json` on the host — run `claude login` once. (For
|
|
87
|
+
`codex`, see [WORKFLOW.template.yaml](./WORKFLOW.template.yaml).) The credential
|
|
88
|
+
never enters the VM — see [Trust posture](#trust-posture).
|
|
90
89
|
|
|
91
|
-
The scaffolded
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
the
|
|
90
|
+
The scaffolded [WORKFLOW.minimal.yaml](./WORKFLOW.minimal.yaml) runs as-is on the
|
|
91
|
+
managed image; the only edits a different setup needs are that adapter credential
|
|
92
|
+
and — if you'd rather pin your own image than fetch the managed one —
|
|
93
|
+
`gondolin.image`. The first-run scaffold also drops an issue-filing skill at
|
|
94
|
+
`.claude/skills/symphony-issues/SKILL.md` (best-effort — it never blocks the
|
|
95
|
+
scaffold), so a coding agent in the freshly-onboarded repo can file well-formed
|
|
96
|
+
tracker issues and decompose a large task into a `blocked_by` DAG from day one.
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
When you want a power feature the starter omits — typed action DAGs, PR autopilot,
|
|
99
|
+
per-state adapters, egress allowlists, sleep-cycle reflection — graduate to the
|
|
100
|
+
annotated [WORKFLOW.template.yaml](./WORKFLOW.template.yaml). Full detail behind
|
|
101
|
+
each step is in [Prerequisites in detail](#prerequisites-in-detail) — you should
|
|
102
|
+
not need it to get here.
|
|
101
103
|
|
|
102
104
|
### Prerequisites in detail
|
|
103
105
|
|
|
104
|
-
- **Node.js ≥
|
|
105
|
-
|
|
106
|
+
- **Node.js ≥ 23.6.** The `engines.node` floor; `symphony doctor` reports your
|
|
107
|
+
running version against it.
|
|
108
|
+
- **The agent image — fetched, not built.** Gondolin is the in-process microVM
|
|
106
109
|
substrate (`@earendil-works/gondolin`), so there is no separate VM daemon to
|
|
107
|
-
run. The
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
adds project toolchains (rust, go, kotlin+gradle, …) on
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
`
|
|
119
|
-
[images/agents/README.md](./images/agents/README.md)
|
|
120
|
-
|
|
121
|
-
|
|
110
|
+
run. The scaffolded workflow sets `gondolin.image: managed`, which fetches a
|
|
111
|
+
**prebuilt** agent rootfs from a published smol-symphony release on first run —
|
|
112
|
+
one asset per host arch (`x86_64`, `aarch64`), keyed to the symphony version.
|
|
113
|
+
No docker, no `npm run build:image`, no local OCI convert. The image ships only
|
|
114
|
+
the `mise` (jdx/mise) binary; node + every ACP-capable coding agent CLI
|
|
115
|
+
(`claude-agent-acp`, `codex-acp`) come from a mise SYSTEM config symphony stages
|
|
116
|
+
into the guest at dispatch (`assets/symphony-mise.system.toml`), and a consuming
|
|
117
|
+
repo's own `mise.toml` adds project toolchains (rust, go, kotlin+gradle, …) on
|
|
118
|
+
top. So bumping an agent CLI is a one-line edit to the staged mise config + a
|
|
119
|
+
restart — no image rebuild. On an unsupported arch (no published asset), or when
|
|
120
|
+
you'd rather build/pin your own, set `gondolin.image` to a local build id /
|
|
121
|
+
`name:tag` (`npm run build:image` from a checkout prints one — see
|
|
122
|
+
[images/agents/README.md](./images/agents/README.md)) or `gondolin.oci_image` to
|
|
123
|
+
an OCI ref symphony auto-converts on first reconcile. Tune the managed fetch and
|
|
124
|
+
the mise data dir via the `gondolin` keys in
|
|
125
|
+
[WORKFLOW.template.yaml](./WORKFLOW.template.yaml).
|
|
122
126
|
- **An adapter credential.** For the default `acp.adapter: claude`: a
|
|
123
|
-
credentials file at `~/.claude/.credentials.json` on the host
|
|
124
|
-
it only on the host side: the guest holds
|
|
125
|
-
the host substitutes the real OAuth access
|
|
126
|
-
Gondolin egress (TLS-MITM). The credential
|
|
127
|
-
the VM. (For `acp.adapter: codex`, see
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
credentials file at `~/.claude/.credentials.json` on the host (run
|
|
128
|
+
`claude login` once). Symphony reads it only on the host side: the guest holds
|
|
129
|
+
only a token-shaped placeholder, and the host substitutes the real OAuth access
|
|
130
|
+
token into the outbound request at Gondolin egress (TLS-MITM). The credential
|
|
131
|
+
file itself is never staged into the VM. (For `acp.adapter: codex`, see
|
|
132
|
+
[WORKFLOW.template.yaml](./WORKFLOW.template.yaml).)
|
|
133
|
+
- **Where state lives.** The tracker, run logs, and per-issue workspaces default
|
|
134
|
+
to `~/.symphony/{trackers,logs,workspaces}/<project>` — outside your repo, so a
|
|
135
|
+
delete / re-clone doesn't wipe them. `<project>` is derived from
|
|
136
|
+
`workspace.github_repo` (or the workflow-file directory name). The startup
|
|
137
|
+
banner prints the resolved tracker root, workspace root, dashboard URL, and log
|
|
138
|
+
file; override any with the matching `*.root` key (e.g. `tracker.root: ./issues`
|
|
139
|
+
to keep issues inside the repo).
|
|
131
140
|
- **Console output.** With the default log file configured, symphony prints a
|
|
132
141
|
one-line-per-field startup banner (workflow, tracker root, dashboard URL,
|
|
133
|
-
log-file path) and routes the structured `key=value` stream to
|
|
134
|
-
|
|
135
|
-
Pass `--verbose` (alias `--foreground`) to mirror the
|
|
136
|
-
to the console for interactive debugging. With no log
|
|
137
|
-
`SYMPHONY_LOG_FILE=""` override), the structured stream
|
|
142
|
+
log-file path) and routes the structured `key=value` stream to the log file only
|
|
143
|
+
(`~/.symphony/logs/<project>/symphony.log` by default). `tail -f` that file to
|
|
144
|
+
follow the detail. Pass `--verbose` (alias `--foreground`) to mirror the
|
|
145
|
+
structured stream back to the console for interactive debugging. With no log
|
|
146
|
+
file configured (the `SYMPHONY_LOG_FILE=""` override), the structured stream
|
|
147
|
+
stays on stderr.
|
|
138
148
|
|
|
139
149
|
### From a checkout
|
|
140
150
|
|
|
@@ -365,12 +375,16 @@ posture:
|
|
|
365
375
|
|
|
366
376
|
```bash
|
|
367
377
|
npm run typecheck # tsc --noEmit
|
|
368
|
-
npm test #
|
|
369
|
-
#
|
|
370
|
-
#
|
|
378
|
+
npm test # ~1400 tests across the core deciders + shell adapters:
|
|
379
|
+
# workflow, tracker, prompt, workspace, adapters, http, mcp,
|
|
380
|
+
# acp-bridge, orchestrator, run log, and runner state resolution
|
|
371
381
|
npm run build # tsc emit to dist/
|
|
372
382
|
```
|
|
373
383
|
|
|
384
|
+
`npm run verify` runs the full gate set CI enforces: typecheck, the eslint
|
|
385
|
+
purity/budget rules, the dependency-cruiser layering walls, the ratcheted
|
|
386
|
+
architecture gates, and the tests.
|
|
387
|
+
|
|
374
388
|
An end-to-end smoke run needs the built agent image (see `images/agents/`).
|
|
375
389
|
|
|
376
390
|
See [CHANGELOG.md](./CHANGELOG.md) for operator-visible changes between
|
package/WORKFLOW.template.yaml
CHANGED
|
@@ -54,13 +54,16 @@ tracker:
|
|
|
54
54
|
# and the landing directory for `symphony.propose_issue`.
|
|
55
55
|
# adapter (string, optional): override the workflow-level `acp.adapter` for
|
|
56
56
|
# agents dispatched in this state. Must be a known profile (claude,
|
|
57
|
-
# codex).
|
|
57
|
+
# codex, pi). All use host-side credential substitution at Gondolin
|
|
58
58
|
# egress and are startup-probed so a missing credential fails fast.
|
|
59
59
|
# claude has a single host credential file
|
|
60
60
|
# (~/.claude/.credentials.json) that is probed for readability; codex
|
|
61
61
|
# passes when either ~/.codex/auth.json holds a token (ChatGPT-OAuth
|
|
62
62
|
# tokens.access_token or a top-level OPENAI_API_KEY) or the host
|
|
63
|
-
# OPENAI_API_KEY env var is set.
|
|
63
|
+
# OPENAI_API_KEY env var is set; pi passes when ~/.pi/agent/auth.json
|
|
64
|
+
# holds a `github-copilot` entry (access or refresh token — log in
|
|
65
|
+
# once with `pi` /login on the host) or the host COPILOT_GITHUB_TOKEN
|
|
66
|
+
# env var is set.
|
|
64
67
|
# prompt_file (path): this state's prompt template, in its own file. The shell
|
|
65
68
|
# loader reads it and assembles `prompt.preamble_file` + this file +
|
|
66
69
|
# `prompt.footer_file` (see the top-level `prompt:` block below) into
|
|
@@ -189,11 +192,20 @@ tracker:
|
|
|
189
192
|
# a trigger fires the orchestrator MINTS a FRESH ephemeral issue into
|
|
190
193
|
# this state (it runs once and terminates in a dedicated terminal),
|
|
191
194
|
# instead of re-arming one immortal parked ticket. Fields:
|
|
192
|
-
# • on_idle (bool): spawn when the orchestrator is idle AND
|
|
193
|
-
#
|
|
194
|
-
# since last cycle" gate is load-bearing —
|
|
195
|
-
# orchestrator re-spawns in a tight loop with
|
|
196
|
-
# mine). Default false.
|
|
195
|
+
# • on_idle (bool): spawn when the orchestrator is idle AND at
|
|
196
|
+
# least `idle_min_terminal` issues reached a terminal state since
|
|
197
|
+
# the last cycle (the "since last cycle" gate is load-bearing —
|
|
198
|
+
# without it an idle orchestrator re-spawns in a tight loop with
|
|
199
|
+
# nothing new to mine). Default false.
|
|
200
|
+
# • idle_min_terminal (int): the idle trigger's signal floor — the
|
|
201
|
+
# minimum terminal transitions since the last cycle that on_idle
|
|
202
|
+
# requires before it fires. Default 1 (fire on any single finish,
|
|
203
|
+
# the historic behavior). Raise it to reflect only once enough new
|
|
204
|
+
# signal has accumulated, collapsing strings of single-finish idle
|
|
205
|
+
# cycles into one; the after_terminal backstop still covers busy
|
|
206
|
+
# stretches, so reflection never starves. Keep it >= 1 — a floor of
|
|
207
|
+
# 0 lets the idle trigger fire with nothing finished, reintroducing
|
|
208
|
+
# the tight re-spawn loop. Has no effect when on_idle is false.
|
|
197
209
|
# • after_terminal (int): a backstop for busy stretches that never
|
|
198
210
|
# go idle — spawn once this many issues have reached a terminal
|
|
199
211
|
# state (Done/Cancelled/the spawn's terminal) since the last
|
|
@@ -371,9 +383,10 @@ states:
|
|
|
371
383
|
# checks the lesson against the evidence rather than the reflector's summary.
|
|
372
384
|
#
|
|
373
385
|
# CADENCE: the orchestrator auto-spawns a fresh reflection issue from the
|
|
374
|
-
# Reflect state's `spawn:` block — `on_idle` (idle with
|
|
375
|
-
# the last cycle) or `after_terminal` (a backstop
|
|
376
|
-
# terminal state since the last cycle). The counter
|
|
386
|
+
# Reflect state's `spawn:` block — `on_idle` (idle with >=`idle_min_terminal`
|
|
387
|
+
# issues finished since the last cycle; default 1) or `after_terminal` (a backstop
|
|
388
|
+
# once N issues have reached a terminal state since the last cycle). The counter
|
|
389
|
+
# resets on a successful mint;
|
|
377
390
|
# `max_in_flight: 1` prevents a second cycle while one is live. An operator can
|
|
378
391
|
# also mint a cycle by hand by creating a Reflect issue (a real dashboard
|
|
379
392
|
# "reflect now" button or a `symphony reflect` verb is a natural fit) — a clean
|
|
@@ -392,6 +405,7 @@ states:
|
|
|
392
405
|
# allowed_transitions: [Reflected]
|
|
393
406
|
# spawn:
|
|
394
407
|
# on_idle: true
|
|
408
|
+
# idle_min_terminal: 3 # idle signal floor (default 1); >=N finished since last cycle
|
|
395
409
|
# after_terminal: 10 # backstop for busy stretches (0 disables)
|
|
396
410
|
# title: "Reflection {{ stamp }}"
|
|
397
411
|
# max_in_flight: 1 # never two reflections live at once
|
|
@@ -470,7 +484,8 @@ pr:
|
|
|
470
484
|
# role: active
|
|
471
485
|
# allowed_transitions: [Reflected]
|
|
472
486
|
# spawn:
|
|
473
|
-
# on_idle: true # spawn when idle with >=
|
|
487
|
+
# on_idle: true # spawn when idle with >=idle_min_terminal finished since last cycle
|
|
488
|
+
# idle_min_terminal: 3 # idle signal floor (default 1)
|
|
474
489
|
# after_terminal: 10 # spawn after N terminal transitions (0 disables)
|
|
475
490
|
# title: "Reflection {{ stamp }}"
|
|
476
491
|
# max_in_flight: 1 # never two reflections live at once
|
|
@@ -734,6 +749,11 @@ acp:
|
|
|
734
749
|
# bearer (in a fake ~/.codex/auth.json); the host substitutes the
|
|
735
750
|
# real OpenAI/ChatGPT token at egress. No real credential — and no
|
|
736
751
|
# real OPENAI_API_KEY — enters the VM.
|
|
752
|
+
# pi — pi-acp wrapping `pi --mode rpc` (the pi coding agent), backed by a
|
|
753
|
+
# GitHub Copilot subscription. Same model: the guest holds a
|
|
754
|
+
# placeholder COPILOT_GITHUB_TOKEN env bearer; the host substitutes
|
|
755
|
+
# the real short-lived Copilot token at egress. No real credential
|
|
756
|
+
# enters the VM.
|
|
737
757
|
adapter: claude
|
|
738
758
|
|
|
739
759
|
# Credentials never enter the VM (issue 113; codex generalized in 116). The
|
|
@@ -756,6 +776,23 @@ acp:
|
|
|
756
776
|
# so codex-acp runs in its native mode without an in-VM OAuth handshake or
|
|
757
777
|
# refresh (both stay host-side). Every credential-bearing var is stripped from
|
|
758
778
|
# the forwarded VM boot env.
|
|
779
|
+
#
|
|
780
|
+
# For pi: the host credential is the `github-copilot` entry in
|
|
781
|
+
# ~/.pi/agent/auth.json — run `pi` once on the host and `/login` with GitHub
|
|
782
|
+
# Copilot to create it (or export COPILOT_GITHUB_TOKEN with a ready Copilot
|
|
783
|
+
# bearer). The host reads the short-lived `access` Copilot token (NEVER the
|
|
784
|
+
# durable `refresh` GitHub-OAuth token) and substitutes it at egress to
|
|
785
|
+
# api.individual.githubcopilot.com; when it nears expiry the host re-exchanges
|
|
786
|
+
# the refresh token against api.github.com/copilot_internal/v2/token directly
|
|
787
|
+
# (no model call) and rewrites auth.json. In the guest, pi resolves its bearer
|
|
788
|
+
# from the COPILOT_GITHUB_TOKEN placeholder env var (used verbatim — pi's env
|
|
789
|
+
# path performs no exchange/refresh), and `defaultProvider: github-copilot` is
|
|
790
|
+
# pinned via a staged ~/.pi/agent/settings.json. Because pi has no built-in MCP
|
|
791
|
+
# client (and pi-acp ignores the ACP mcpServers descriptor), symphony also
|
|
792
|
+
# stages a per-dispatch extension at ~/.pi/agent/extensions/symphony-mcp.ts
|
|
793
|
+
# that bridges the symphony tools (transition / request_human_steering /
|
|
794
|
+
# propose_issue) to the MCP endpoint. Business/enterprise Copilot endpoints
|
|
795
|
+
# (api.business.githubcopilot.com etc.) are not wired — individual only.
|
|
759
796
|
|
|
760
797
|
# model (string | null): optional model selector forwarded to the chosen adapter.
|
|
761
798
|
# Each adapter profile knows how to surface it natively:
|
|
@@ -763,6 +800,10 @@ acp:
|
|
|
763
800
|
# claude-agent-acp would (aliases like "opus", "sonnet", or full IDs
|
|
764
801
|
# like "claude-opus-4-7").
|
|
765
802
|
# codex — passed as `-c model="<value>"` argv to codex-acp (parsed as TOML).
|
|
803
|
+
# pi — written as `defaultModel` into the staged ~/.pi/agent/settings.json
|
|
804
|
+
# (pi-acp forwards no argv and pi has no model env var). Accepts a
|
|
805
|
+
# Copilot model id (e.g. "gpt-5", "claude-sonnet-4-6") or pi's
|
|
806
|
+
# provider/id + fuzzy forms; unset ⇒ pi's own Copilot default.
|
|
766
807
|
# Leave unset / null to use the adapter's own default model. Default: null.
|
|
767
808
|
# model: claude-opus-4-7
|
|
768
809
|
|
|
@@ -777,6 +818,9 @@ acp:
|
|
|
777
818
|
# from drifting from the adapter's own supported list.
|
|
778
819
|
# codex — not wired (codex-acp has no first-class effort knob on the wrapper);
|
|
779
820
|
# setting `acp.effort` for a codex-backed state is a no-op.
|
|
821
|
+
# pi — not wired (pi's thinking level shares the same settings.json the
|
|
822
|
+
# model pin is staged into, and the injection channels have no merge
|
|
823
|
+
# semantics); setting `acp.effort` for a pi-backed state is a no-op.
|
|
780
824
|
# Leave unset / null for the adapter's own default. Default: null.
|
|
781
825
|
# effort: xhigh
|
|
782
826
|
|
package/WORKFLOW.yaml
CHANGED
|
@@ -101,9 +101,14 @@ states:
|
|
|
101
101
|
allowed_transitions: [Reflected]
|
|
102
102
|
# Recurring spawn trigger. This active state mints a FRESH ephemeral
|
|
103
103
|
# reflection issue into itself: `on_idle` when the orchestrator is idle and
|
|
104
|
-
#
|
|
105
|
-
# as a backstop once that many issues have reached
|
|
106
|
-
# last cycle. The terminal-transition counter resets
|
|
104
|
+
# `idle_min_terminal` issues have reached a terminal state since the last
|
|
105
|
+
# cycle, and `after_terminal` as a backstop once that many issues have reached
|
|
106
|
+
# a terminal state since the last cycle. The terminal-transition counter resets
|
|
107
|
+
# to 0 on a successful mint. `idle_min_terminal: 3` raises the idle signal floor
|
|
108
|
+
# (was a hardcoded >=1): a quiet period reflects once >=3 issues have finished,
|
|
109
|
+
# collapsing strings of single-finish idle cycles into one and skipping cycles
|
|
110
|
+
# with too little new signal. The `after_terminal: 10` backstop still covers
|
|
111
|
+
# busy stretches, so reflection never starves.
|
|
107
112
|
# `max_in_flight: 1` is load-bearing — it replaces the immortal ticket's
|
|
108
113
|
# built-in "one location = one reflection" mutex, so a busy stretch never mints
|
|
109
114
|
# a second cycle while one is still live. `title` stamps the mint time
|
|
@@ -113,6 +118,7 @@ states:
|
|
|
113
118
|
# approve/discard, so this does not bypass the human gate.
|
|
114
119
|
spawn:
|
|
115
120
|
on_idle: true
|
|
121
|
+
idle_min_terminal: 3
|
|
116
122
|
after_terminal: 10
|
|
117
123
|
title: "Reflection {{ stamp }}"
|
|
118
124
|
max_in_flight: 1
|
|
@@ -66,3 +66,9 @@ node = "24"
|
|
|
66
66
|
"npm:@agentclientprotocol/claude-agent-acp" = "0.39.0"
|
|
67
67
|
"npm:@zed-industries/codex-acp" = { version = "0.15.0", npm_args = "--ignore-scripts=false" }
|
|
68
68
|
"npm:opencode-ai" = { version = "1.15.12", npm_args = "--ignore-scripts=false" }
|
|
69
|
+
# pi (adapter: pi) — the pi coding agent + the pi-acp ACP wrapper that spawns
|
|
70
|
+
# `pi --mode rpc` (pi has no native ACP mode). Both are pure JS with NO install
|
|
71
|
+
# scripts (pi's own docs install with --ignore-scripts), so plain pins suffice.
|
|
72
|
+
# pi-coding-agent needs node >= 22.19 — satisfied by the node pin above.
|
|
73
|
+
"npm:@earendil-works/pi-coding-agent" = "0.79.1"
|
|
74
|
+
"npm:pi-acp" = "0.0.27"
|
|
@@ -102,6 +102,27 @@ export function codexPlaceholderAuthSpec() {
|
|
|
102
102
|
guestPath: CODEX_AUTH_GUEST_PATH,
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
// ── pi settings.json (provider + model) ────────────────────────────────────
|
|
106
|
+
/** Absolute guest path pi's global settings.json lands at. */
|
|
107
|
+
export const PI_SETTINGS_GUEST_PATH = '/root/.pi/agent/settings.json';
|
|
108
|
+
/**
|
|
109
|
+
* The pi `~/.pi/agent/settings.json` spec. pi-acp spawns `pi --mode rpc` with
|
|
110
|
+
* NO passthrough argv and pi has no model env var, so provider/model selection
|
|
111
|
+
* rides pi's own global settings file. `defaultProvider` is always pinned to
|
|
112
|
+
* `github-copilot` (the only provider symphony stages a credential for);
|
|
113
|
+
* `defaultModel` is included only when a model was chosen (omitted ⇒ pi's own
|
|
114
|
+
* Copilot default).
|
|
115
|
+
*/
|
|
116
|
+
export function piSettingsSpec(model) {
|
|
117
|
+
return {
|
|
118
|
+
stagedName: 'pi-settings.json',
|
|
119
|
+
content: JSON.stringify({
|
|
120
|
+
defaultProvider: 'github-copilot',
|
|
121
|
+
...(model !== null && model.length > 0 ? { defaultModel: model } : {}),
|
|
122
|
+
}),
|
|
123
|
+
guestPath: PI_SETTINGS_GUEST_PATH,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
105
126
|
/**
|
|
106
127
|
* Aggregate every staged-file spec one adapter dispatch needs into a single
|
|
107
128
|
* `StagedFileSpec[]`, in a stable order (identity/config first, then the
|
|
@@ -113,6 +134,9 @@ export function codexPlaceholderAuthSpec() {
|
|
|
113
134
|
* • claude — optional non-secret identity (when extracted) + optional
|
|
114
135
|
* effortLevel settings.json (when effort is set).
|
|
115
136
|
* • codex — the fake placeholder auth.json (always; the init check needs it).
|
|
137
|
+
* • pi — the settings.json provider/model pin (always; `effort` is not
|
|
138
|
+
* wired for pi — there is no collision-free channel for pi's
|
|
139
|
+
* thinking level alongside the model file).
|
|
116
140
|
*/
|
|
117
141
|
export function buildStagedConfigs(input) {
|
|
118
142
|
const specs = [];
|
|
@@ -130,6 +154,10 @@ export function buildStagedConfigs(input) {
|
|
|
130
154
|
specs.push(codexPlaceholderAuthSpec());
|
|
131
155
|
break;
|
|
132
156
|
}
|
|
157
|
+
case 'pi': {
|
|
158
|
+
specs.push(piSettingsSpec(input.model));
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
133
161
|
}
|
|
134
162
|
return specs;
|
|
135
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter-config.js","sourceRoot":"","sources":["../../../src/core/credential/adapter-config.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,gEAAgE;AAChE,mFAAmF;AACnF,qEAAqE;AACrE,+EAA+E;AAC/E,EAAE;AACF,0EAA0E;AAC1E,gFAAgF;AAChF,+EAA+E;AAC/E,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAC/E,gFAAgF;AAChF,6EAA6E;AAC7E,gFAAgF;AAChF,gFAAgF;AAChF,EAAE;AACF,sFAAsF;AACtF,gFAAgF;AAChF,iFAAiF;AACjF,qFAAqF;AACrF,mDAAmD;AACnD,mFAAmF;AACnF,EAAE;AACF,mDAAmD;AACnD,gFAAgF;AAChF,8EAA8E;AAC9E,kFAAkF;AAClF,0EAA0E;AAC1E,uEAAuE;AACvE,gFAAgF;AAChF,8DAA8D;AAS9D,8EAA8E;AAE9E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,0BAA0B,GAAG,6BAA6B,CAAC;AAExE,wEAAwE;AACxE,MAAM,CAAC,MAAM,0BAA0B,GAAG,oBAAoB,CAAC;AAE/D;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO;QACL,UAAU,EAAE,sBAAsB;QAClC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;QAChD,SAAS,EAAE,0BAA0B;KACtC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAA+B;IAChE,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO;QACL,UAAU,EAAE,aAAa;QACzB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;YACtB,YAAY,EAAE;gBACZ,WAAW,EAAE,QAAQ,CAAC,WAAW;gBACjC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;aAC5C;SACF,CAAC;QACF,SAAS,EAAE,0BAA0B;KACtC,CAAC;AACJ,CAAC;AAED,8EAA8E;AAE9E,6DAA6D;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,wBAAwB,CAAC;AAE9D,kFAAkF;AAClF,MAAM,CAAC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,UAAU,EAAE,WAAW;QACvB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;YACtB,cAAc,EAAE,yBAAyB;YACzC,SAAS,EAAE,QAAQ;SACpB,CAAC;QACF,SAAS,EAAE,qBAAqB;KACjC,CAAC;AACJ,CAAC;AAeD
|
|
1
|
+
{"version":3,"file":"adapter-config.js","sourceRoot":"","sources":["../../../src/core/credential/adapter-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ import { nonEmptyString } from './strings.js';
|
|
|
31
31
|
// The seam between the config layer and the IO adapter layer: both sides agree
|
|
32
32
|
// on which adapter ids exist. The full adapter *profile* lives elsewhere
|
|
33
33
|
// (AdapterProfile / the shell's adapter registry); this is only the id set.
|
|
34
|
-
export const KNOWN_ADAPTER_IDS = ['claude', 'codex'];
|
|
34
|
+
export const KNOWN_ADAPTER_IDS = ['claude', 'codex', 'pi'];
|
|
35
35
|
export function isKnownAdapter(id) {
|
|
36
36
|
return KNOWN_ADAPTER_IDS.includes(id);
|
|
37
37
|
}
|
|
@@ -53,6 +53,10 @@ export function hostClaudeCredentialPath(homeDir) {
|
|
|
53
53
|
export function hostCodexCredentialPath(homeDir) {
|
|
54
54
|
return joinPath(homeDir, '.codex', 'auth.json');
|
|
55
55
|
}
|
|
56
|
+
/** Absolute path to the host's pi credential file (`~/.pi/agent/auth.json`). */
|
|
57
|
+
export function hostPiCredentialPath(homeDir) {
|
|
58
|
+
return joinPath(homeDir, '.pi', 'agent', 'auth.json');
|
|
59
|
+
}
|
|
56
60
|
// ─── codex credential resolution ─────────────────────────────────────────────
|
|
57
61
|
/**
|
|
58
62
|
* Pure: does codex have a resolvable credential from either valid source? The
|
|
@@ -80,6 +84,45 @@ export function codexCredentialAvailable(authFileText, env) {
|
|
|
80
84
|
export function codexMissingCredentialMessage(homeDir) {
|
|
81
85
|
return `adapter "codex" requires a host credential, but none is available: neither a token in ${hostCodexCredentialPath(homeDir)} (ChatGPT-OAuth tokens.access_token or OPENAI_API_KEY) nor an OPENAI_API_KEY environment variable is present`;
|
|
82
86
|
}
|
|
87
|
+
// ─── pi (GitHub Copilot) credential resolution ───────────────────────────────
|
|
88
|
+
/**
|
|
89
|
+
* Pure: does pi have a resolvable GitHub-Copilot credential from either valid
|
|
90
|
+
* source? The host reads two — the `github-copilot` entry in `~/.pi/agent/auth.json`
|
|
91
|
+
* (either a live short-lived `access` Copilot token or the durable `refresh`
|
|
92
|
+
* GitHub-OAuth token the host refresher can mint one from) or a
|
|
93
|
+
* `COPILOT_GITHUB_TOKEN` env var (used verbatim as the Copilot bearer, no
|
|
94
|
+
* refresh). The shell reads the file (passing `null` when absent/unreadable)
|
|
95
|
+
* and its env in, mirroring the dispatch-time resolution.
|
|
96
|
+
*/
|
|
97
|
+
export function piCredentialAvailable(authFileText, env) {
|
|
98
|
+
if (nonEmptyString(env['COPILOT_GITHUB_TOKEN']))
|
|
99
|
+
return true;
|
|
100
|
+
if (authFileText === null)
|
|
101
|
+
return false;
|
|
102
|
+
let parsed;
|
|
103
|
+
try {
|
|
104
|
+
parsed = JSON.parse(authFileText);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return piAuthFileHasCredential(parsed);
|
|
110
|
+
}
|
|
111
|
+
/** Human-readable explanation of which pi credential sources were checked. */
|
|
112
|
+
export function piMissingCredentialMessage(homeDir) {
|
|
113
|
+
return `adapter "pi" requires a host credential, but none is available: neither a github-copilot entry in ${hostPiCredentialPath(homeDir)} (run \`pi\` on the host and /login with GitHub Copilot) nor a COPILOT_GITHUB_TOKEN environment variable is present`;
|
|
114
|
+
}
|
|
115
|
+
function piAuthFileHasCredential(parsed) {
|
|
116
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
117
|
+
return false;
|
|
118
|
+
const entry = parsed['github-copilot'];
|
|
119
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
120
|
+
return false;
|
|
121
|
+
const rec = entry;
|
|
122
|
+
// Either a live access token (substitutable now) or the durable refresh token
|
|
123
|
+
// (the host refresher mints a fresh access token before dispatch needs it).
|
|
124
|
+
return nonEmptyString(rec['access']) !== null || nonEmptyString(rec['refresh']) !== null;
|
|
125
|
+
}
|
|
83
126
|
function codexAuthFileHasToken(parsed) {
|
|
84
127
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
85
128
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"availability.js","sourceRoot":"","sources":["../../../src/core/credential/availability.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,oEAAoE;AACpE,6DAA6D;AAC7D,0EAA0E;AAC1E,EAAE;AACF,4EAA4E;AAC5E,iFAAiF;AACjF,yDAAyD;AACzD,EAAE;AACF,0DAA0D;AAC1D,EAAE;AACF,6DAA6D;AAC7D,2EAA2E;AAC3E,iFAAiF;AACjF,8EAA8E;AAC9E,0EAA0E;AAC1E,6EAA6E;AAC7E,+EAA+E;AAC/E,oFAAoF;AACpF,uEAAuE;AACvE,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,iFAAiF;AACjF,qEAAqE;AAIrE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,yEAAyE;AACzE,4EAA4E;AAE5E,MAAM,CAAC,MAAM,iBAAiB,GAA4B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"availability.js","sourceRoot":"","sources":["../../../src/core/credential/availability.ts"],"names":[],"mappings":"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"}
|