smol-symphony 0.1.0 → 0.3.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 +125 -39
- package/DESIGN.md +494 -273
- package/PRODUCT.md +2 -1
- package/README.md +259 -110
- package/SPEC.md +565 -1928
- package/WORKFLOW.minimal.yaml +34 -0
- package/WORKFLOW.template.yaml +1100 -0
- package/WORKFLOW.yaml +487 -0
- package/assets/skills/symphony-issues/SKILL.md +136 -0
- package/assets/symphony-mise.system.toml +68 -0
- package/dist/src/bin/symphony.js +30 -0
- package/dist/src/bin/symphony.js.map +1 -0
- package/dist/src/core/actions/context.js +109 -0
- package/dist/src/core/actions/context.js.map +1 -0
- package/dist/src/core/actions/parse.js +192 -0
- package/dist/src/core/actions/parse.js.map +1 -0
- package/dist/src/core/actions/plan.js +197 -0
- package/dist/src/core/actions/plan.js.map +1 -0
- package/dist/src/core/actions/predicates.js +111 -0
- package/dist/src/core/actions/predicates.js.map +1 -0
- package/dist/src/core/actions/run-fold.js +248 -0
- package/dist/src/core/actions/run-fold.js.map +1 -0
- package/dist/src/core/actions/template.js +118 -0
- package/dist/src/core/actions/template.js.map +1 -0
- package/dist/src/core/cli/args.js +116 -0
- package/dist/src/core/cli/args.js.map +1 -0
- package/dist/src/core/coerce.js +75 -0
- package/dist/src/core/coerce.js.map +1 -0
- package/dist/src/core/credential/account-id.js +20 -0
- package/dist/src/core/credential/account-id.js.map +1 -0
- package/dist/src/core/credential/adapter-config.js +136 -0
- package/dist/src/core/credential/adapter-config.js.map +1 -0
- package/dist/src/core/credential/availability.js +98 -0
- package/dist/src/core/credential/availability.js.map +1 -0
- package/dist/src/core/credential/extract.js +228 -0
- package/dist/src/core/credential/extract.js.map +1 -0
- package/dist/src/core/credential/fake-creds.js +171 -0
- package/dist/src/core/credential/fake-creds.js.map +1 -0
- package/dist/src/core/credential/identity.js +125 -0
- package/dist/src/core/credential/identity.js.map +1 -0
- package/dist/src/core/credential/shape.js +230 -0
- package/dist/src/core/credential/shape.js.map +1 -0
- package/dist/src/core/credential/strings.js +15 -0
- package/dist/src/core/credential/strings.js.map +1 -0
- package/dist/src/core/doctor/checks.js +303 -0
- package/dist/src/core/doctor/checks.js.map +1 -0
- package/dist/src/core/git/result.js +107 -0
- package/dist/src/core/git/result.js.map +1 -0
- package/dist/src/core/http/decisions.js +225 -0
- package/dist/src/core/http/decisions.js.map +1 -0
- package/dist/src/core/http/render.js +1635 -0
- package/dist/src/core/http/render.js.map +1 -0
- package/dist/src/core/http/routes.js +145 -0
- package/dist/src/core/http/routes.js.map +1 -0
- package/dist/src/core/http/views.js +181 -0
- package/dist/src/core/http/views.js.map +1 -0
- package/dist/src/core/image/managed-image.js +95 -0
- package/dist/src/core/image/managed-image.js.map +1 -0
- package/dist/src/core/issue/file.js +149 -0
- package/dist/src/core/issue/file.js.map +1 -0
- package/dist/src/core/issue/parse.js +210 -0
- package/dist/src/core/issue/parse.js.map +1 -0
- package/dist/src/core/mcp/dispatch.js +239 -0
- package/dist/src/core/mcp/dispatch.js.map +1 -0
- package/dist/src/core/mcp/post-move.js +92 -0
- package/dist/src/core/mcp/post-move.js.map +1 -0
- package/dist/src/core/mcp/protocol.js +293 -0
- package/dist/src/core/mcp/protocol.js.map +1 -0
- package/dist/src/core/mcp/url.js +162 -0
- package/dist/src/core/mcp/url.js.map +1 -0
- package/dist/src/core/path.js +63 -0
- package/dist/src/core/path.js.map +1 -0
- package/dist/src/core/reconcile/image-decide.js +48 -0
- package/dist/src/core/reconcile/image-decide.js.map +1 -0
- package/dist/src/core/reconcile/ledger.js +142 -0
- package/dist/src/core/reconcile/ledger.js.map +1 -0
- package/dist/src/core/reconcile/pr-classify.js +62 -0
- package/dist/src/core/reconcile/pr-classify.js.map +1 -0
- package/dist/src/core/reconcile/pr-decide.js +180 -0
- package/dist/src/core/reconcile/pr-decide.js.map +1 -0
- package/dist/src/core/reconcile/pr-loop.js +161 -0
- package/dist/src/core/reconcile/pr-loop.js.map +1 -0
- package/dist/src/core/reconcile/pr-notes.js +35 -0
- package/dist/src/core/reconcile/pr-notes.js.map +1 -0
- package/dist/src/core/reconcile/vm-decide.js +70 -0
- package/dist/src/core/reconcile/vm-decide.js.map +1 -0
- package/dist/src/core/reconcile/vm-reap.js +207 -0
- package/dist/src/core/reconcile/vm-reap.js.map +1 -0
- package/dist/src/core/reconcile/workspace-decide.js +162 -0
- package/dist/src/core/reconcile/workspace-decide.js.map +1 -0
- package/dist/src/core/runlog/summary.js +231 -0
- package/dist/src/core/runlog/summary.js.map +1 -0
- package/dist/src/core/runner/dispatch-config.js +95 -0
- package/dist/src/core/runner/dispatch-config.js.map +1 -0
- package/dist/src/core/runner/injection.js +61 -0
- package/dist/src/core/runner/injection.js.map +1 -0
- package/dist/src/core/runner/mise.js +210 -0
- package/dist/src/core/runner/mise.js.map +1 -0
- package/dist/src/core/runner/prompt.js +720 -0
- package/dist/src/core/runner/prompt.js.map +1 -0
- package/dist/src/core/runner/turn.js +242 -0
- package/dist/src/core/runner/turn.js.map +1 -0
- package/dist/src/core/runner/vm-plan.js +390 -0
- package/dist/src/core/runner/vm-plan.js.map +1 -0
- package/dist/src/core/schedule/admission.js +123 -0
- package/dist/src/core/schedule/admission.js.map +1 -0
- package/dist/src/core/schedule/circuit-breaker.js +111 -0
- package/dist/src/core/schedule/circuit-breaker.js.map +1 -0
- package/dist/src/core/schedule/eligibility.js +83 -0
- package/dist/src/core/schedule/eligibility.js.map +1 -0
- package/dist/src/core/schedule/reconcile-issue.js +82 -0
- package/dist/src/core/schedule/reconcile-issue.js.map +1 -0
- package/dist/src/core/schedule/retry.js +96 -0
- package/dist/src/core/schedule/retry.js.map +1 -0
- package/dist/src/core/schedule/sleep-cycle.js +133 -0
- package/dist/src/core/schedule/sleep-cycle.js.map +1 -0
- package/dist/src/core/schedule/slots.js +124 -0
- package/dist/src/core/schedule/slots.js.map +1 -0
- package/dist/src/core/schedule/tick.js +553 -0
- package/dist/src/core/schedule/tick.js.map +1 -0
- package/dist/src/core/schedule/token-fold.js +181 -0
- package/dist/src/core/schedule/token-fold.js.map +1 -0
- package/dist/src/core/state-resolve.js +86 -0
- package/dist/src/core/state-resolve.js.map +1 -0
- package/dist/src/core/vm-guards.js +278 -0
- package/dist/src/core/vm-guards.js.map +1 -0
- package/dist/src/core/workflow/derive.js +107 -0
- package/dist/src/core/workflow/derive.js.map +1 -0
- package/dist/src/core/workflow/parse.js +687 -0
- package/dist/src/core/workflow/parse.js.map +1 -0
- package/dist/src/core/workflow/prompt-probe.js +78 -0
- package/dist/src/core/workflow/prompt-probe.js.map +1 -0
- package/dist/src/core/workflow/validate.js +189 -0
- package/dist/src/core/workflow/validate.js.map +1 -0
- package/dist/src/core/workspace-key.js +19 -0
- package/dist/src/core/workspace-key.js.map +1 -0
- package/dist/src/shell/actions-runner.js +356 -0
- package/dist/src/shell/actions-runner.js.map +1 -0
- package/dist/src/shell/adapter/adapter-registry.js +45 -0
- package/dist/src/shell/adapter/adapter-registry.js.map +1 -0
- package/dist/src/shell/adapter/clock-random.js +96 -0
- package/dist/src/shell/adapter/clock-random.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-dispatch-helpers.js +158 -0
- package/dist/src/shell/adapter/gondolin-dispatch-helpers.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-dispatch.js +385 -0
- package/dist/src/shell/adapter/gondolin-dispatch.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-image-converter.js +233 -0
- package/dist/src/shell/adapter/gondolin-image-converter.js.map +1 -0
- package/dist/src/shell/adapter/gondolin-image-fetch.js +180 -0
- package/dist/src/shell/adapter/gondolin-image-fetch.js.map +1 -0
- package/dist/src/shell/adapter/launcher-asset.js +57 -0
- package/dist/src/shell/adapter/launcher-asset.js.map +1 -0
- package/dist/src/shell/adapter/mise-config-asset.js +65 -0
- package/dist/src/shell/adapter/mise-config-asset.js.map +1 -0
- package/dist/src/shell/adapter/workflow-loader.js +304 -0
- package/dist/src/shell/adapter/workflow-loader.js.map +1 -0
- package/dist/src/shell/cli/doctor.js +268 -0
- package/dist/src/shell/cli/doctor.js.map +1 -0
- package/dist/src/shell/effect-interpreter-families.js +314 -0
- package/dist/src/shell/effect-interpreter-families.js.map +1 -0
- package/dist/src/shell/effect-interpreter.js +29 -0
- package/dist/src/shell/effect-interpreter.js.map +1 -0
- package/dist/src/shell/interp/acp-frame.js +137 -0
- package/dist/src/shell/interp/acp-frame.js.map +1 -0
- package/dist/src/shell/interp/acp-ws-conn.js +320 -0
- package/dist/src/shell/interp/acp-ws-conn.js.map +1 -0
- package/dist/src/shell/interp/acp-ws-frames.js +159 -0
- package/dist/src/shell/interp/acp-ws-frames.js.map +1 -0
- package/dist/src/shell/interp/acp-ws.js +197 -0
- package/dist/src/shell/interp/acp-ws.js.map +1 -0
- package/dist/src/shell/interp/acp.js +319 -0
- package/dist/src/shell/interp/acp.js.map +1 -0
- package/dist/src/shell/interp/credential-defaults.js +128 -0
- package/dist/src/shell/interp/credential-defaults.js.map +1 -0
- package/dist/src/shell/interp/credential-hooks.js +149 -0
- package/dist/src/shell/interp/credential-hooks.js.map +1 -0
- package/dist/src/shell/interp/credential-registry.js +226 -0
- package/dist/src/shell/interp/credential-registry.js.map +1 -0
- package/dist/src/shell/interp/credential.js +103 -0
- package/dist/src/shell/interp/credential.js.map +1 -0
- package/dist/src/shell/interp/gh.js +163 -0
- package/dist/src/shell/interp/gh.js.map +1 -0
- package/dist/src/shell/interp/git.js +28 -0
- package/dist/src/shell/interp/git.js.map +1 -0
- package/dist/src/shell/interp/log.js +213 -0
- package/dist/src/shell/interp/log.js.map +1 -0
- package/dist/src/shell/interp/process.js +178 -0
- package/dist/src/shell/interp/process.js.map +1 -0
- package/dist/src/shell/interp/runlog.js +193 -0
- package/dist/src/shell/interp/runlog.js.map +1 -0
- package/dist/src/shell/interp/timer.js +64 -0
- package/dist/src/shell/interp/timer.js.map +1 -0
- package/dist/src/shell/interp/tracker-disk.js +99 -0
- package/dist/src/shell/interp/tracker-disk.js.map +1 -0
- package/dist/src/shell/interp/tracker-parse.js +71 -0
- package/dist/src/shell/interp/tracker-parse.js.map +1 -0
- package/dist/src/shell/interp/tracker-scan.js +238 -0
- package/dist/src/shell/interp/tracker-scan.js.map +1 -0
- package/dist/src/shell/interp/tracker-write.js +91 -0
- package/dist/src/shell/interp/tracker-write.js.map +1 -0
- package/dist/src/shell/interp/tracker.js +41 -0
- package/dist/src/shell/interp/tracker.js.map +1 -0
- package/dist/src/shell/interp/tty.js +48 -0
- package/dist/src/shell/interp/tty.js.map +1 -0
- package/dist/src/shell/interp/vm.js +199 -0
- package/dist/src/shell/interp/vm.js.map +1 -0
- package/dist/src/shell/interp/workspace.js +310 -0
- package/dist/src/shell/interp/workspace.js.map +1 -0
- package/dist/src/shell/main-acp.js +78 -0
- package/dist/src/shell/main-acp.js.map +1 -0
- package/dist/src/shell/main-adapters.js +222 -0
- package/dist/src/shell/main-adapters.js.map +1 -0
- package/dist/src/shell/main-credential.js +122 -0
- package/dist/src/shell/main-credential.js.map +1 -0
- package/dist/src/shell/main-doctor.js +22 -0
- package/dist/src/shell/main-doctor.js.map +1 -0
- package/dist/src/shell/main-entry.js +46 -0
- package/dist/src/shell/main-entry.js.map +1 -0
- package/dist/src/shell/main-http-csrf.js +45 -0
- package/dist/src/shell/main-http-csrf.js.map +1 -0
- package/dist/src/shell/main-http-handler.js +389 -0
- package/dist/src/shell/main-http-handler.js.map +1 -0
- package/dist/src/shell/main-http-mcp.js +122 -0
- package/dist/src/shell/main-http-mcp.js.map +1 -0
- package/dist/src/shell/main-http-views.js +253 -0
- package/dist/src/shell/main-http-views.js.map +1 -0
- package/dist/src/shell/main-http.js +76 -0
- package/dist/src/shell/main-http.js.map +1 -0
- package/dist/src/shell/main-loops.js +130 -0
- package/dist/src/shell/main-loops.js.map +1 -0
- package/dist/src/shell/main-mcp.js +129 -0
- package/dist/src/shell/main-mcp.js.map +1 -0
- package/dist/src/shell/main-orchestrator.js +120 -0
- package/dist/src/shell/main-orchestrator.js.map +1 -0
- package/dist/src/shell/main-preflight.js +43 -0
- package/dist/src/shell/main-preflight.js.map +1 -0
- package/dist/src/shell/main-reconcilers-helpers.js +244 -0
- package/dist/src/shell/main-reconcilers-helpers.js.map +1 -0
- package/dist/src/shell/main-reconcilers-pr.js +148 -0
- package/dist/src/shell/main-reconcilers-pr.js.map +1 -0
- package/dist/src/shell/main-reconcilers.js +225 -0
- package/dist/src/shell/main-reconcilers.js.map +1 -0
- package/dist/src/shell/main-runner.js +355 -0
- package/dist/src/shell/main-runner.js.map +1 -0
- package/dist/src/shell/main-scaffold.js +116 -0
- package/dist/src/shell/main-scaffold.js.map +1 -0
- package/dist/src/shell/main-shutdown.js +115 -0
- package/dist/src/shell/main-shutdown.js.map +1 -0
- package/dist/src/shell/main-startup.js +48 -0
- package/dist/src/shell/main-startup.js.map +1 -0
- package/dist/src/shell/main-substrates.js +43 -0
- package/dist/src/shell/main-substrates.js.map +1 -0
- package/dist/src/shell/main.js +385 -0
- package/dist/src/shell/main.js.map +1 -0
- package/dist/src/shell/orchestrator-feedback.js +69 -0
- package/dist/src/shell/orchestrator-feedback.js.map +1 -0
- package/dist/src/shell/orchestrator-image.js +167 -0
- package/dist/src/shell/orchestrator-image.js.map +1 -0
- package/dist/src/shell/orchestrator-loop.js +468 -0
- package/dist/src/shell/orchestrator-loop.js.map +1 -0
- package/dist/src/shell/orchestrator-reconcile.js +36 -0
- package/dist/src/shell/orchestrator-reconcile.js.map +1 -0
- package/dist/src/shell/reconciler-loop.js +228 -0
- package/dist/src/shell/reconciler-loop.js.map +1 -0
- package/dist/src/shell/runner-loop-turn.js +301 -0
- package/dist/src/shell/runner-loop-turn.js.map +1 -0
- package/dist/src/shell/runner-loop.js +338 -0
- package/dist/src/shell/runner-loop.js.map +1 -0
- package/dist/src/shell/server/http.js +208 -0
- package/dist/src/shell/server/http.js.map +1 -0
- package/dist/src/shell/server/mcp-runtime-effects.js +237 -0
- package/dist/src/shell/server/mcp-runtime-effects.js.map +1 -0
- package/dist/src/shell/server/mcp-runtime.js +99 -0
- package/dist/src/shell/server/mcp-runtime.js.map +1 -0
- package/dist/src/shell/workspace-key.js +14 -0
- package/dist/src/shell/workspace-key.js.map +1 -0
- package/dist/src/types/acp.js +8 -0
- package/dist/src/types/acp.js.map +1 -0
- package/dist/src/types/actions/plan.js +6 -0
- package/dist/src/types/actions/plan.js.map +1 -0
- package/dist/src/types/actions/predicates.js +6 -0
- package/dist/src/types/actions/predicates.js.map +1 -0
- package/dist/src/types/actions/run-fold.js +8 -0
- package/dist/src/types/actions/run-fold.js.map +1 -0
- package/dist/src/types/actions.js +7 -0
- package/dist/src/types/actions.js.map +1 -0
- package/dist/src/types/adapter/clock-random.js +4 -0
- package/dist/src/types/adapter/clock-random.js.map +1 -0
- package/dist/src/types/adapter/gondolin-image-converter.js +5 -0
- package/dist/src/types/adapter/gondolin-image-converter.js.map +1 -0
- package/dist/src/types/adapter/gondolin-image-fetch.js +5 -0
- package/dist/src/types/adapter/gondolin-image-fetch.js.map +1 -0
- package/dist/src/types/adapter/workflow-loader.js +4 -0
- package/dist/src/types/adapter/workflow-loader.js.map +1 -0
- package/dist/src/types/cli/args.js +8 -0
- package/dist/src/types/cli/args.js.map +1 -0
- package/dist/src/types/config.js +8 -0
- package/dist/src/types/config.js.map +1 -0
- package/dist/src/types/credential-interp.js +6 -0
- package/dist/src/types/credential-interp.js.map +1 -0
- package/dist/src/types/credentials.js +10 -0
- package/dist/src/types/credentials.js.map +1 -0
- package/dist/src/types/doctor.js +7 -0
- package/dist/src/types/doctor.js.map +1 -0
- package/dist/src/types/domain.js +7 -0
- package/dist/src/types/domain.js.map +1 -0
- package/dist/src/types/effect.js +15 -0
- package/dist/src/types/effect.js.map +1 -0
- package/dist/src/types/errors.js +39 -0
- package/dist/src/types/errors.js.map +1 -0
- package/dist/src/types/http/decisions.js +6 -0
- package/dist/src/types/http/decisions.js.map +1 -0
- package/dist/src/types/http/render.js +10 -0
- package/dist/src/types/http/render.js.map +1 -0
- package/dist/src/types/http/views.js +6 -0
- package/dist/src/types/http/views.js.map +1 -0
- package/dist/src/types/http.js +9 -0
- package/dist/src/types/http.js.map +1 -0
- package/dist/src/types/image/managed-image.js +7 -0
- package/dist/src/types/image/managed-image.js.map +1 -0
- package/dist/src/types/interp/effect-interpreter.js +8 -0
- package/dist/src/types/interp/effect-interpreter.js.map +1 -0
- package/dist/src/types/interp/tracker.js +7 -0
- package/dist/src/types/interp/tracker.js.map +1 -0
- package/dist/src/types/issue/file.js +6 -0
- package/dist/src/types/issue/file.js.map +1 -0
- package/dist/src/types/issue/parse.js +8 -0
- package/dist/src/types/issue/parse.js.map +1 -0
- package/dist/src/types/main-acp.js +13 -0
- package/dist/src/types/main-acp.js.map +1 -0
- package/dist/src/types/main-adapters.js +5 -0
- package/dist/src/types/main-adapters.js.map +1 -0
- package/dist/src/types/main-credential.js +21 -0
- package/dist/src/types/main-credential.js.map +1 -0
- package/dist/src/types/main-doctor.js +6 -0
- package/dist/src/types/main-doctor.js.map +1 -0
- package/dist/src/types/main-http-handler.js +12 -0
- package/dist/src/types/main-http-handler.js.map +1 -0
- package/dist/src/types/main-http.js +5 -0
- package/dist/src/types/main-http.js.map +1 -0
- package/dist/src/types/main-loops.js +5 -0
- package/dist/src/types/main-loops.js.map +1 -0
- package/dist/src/types/main-mcp.js +12 -0
- package/dist/src/types/main-mcp.js.map +1 -0
- package/dist/src/types/main-orchestrator.js +5 -0
- package/dist/src/types/main-orchestrator.js.map +1 -0
- package/dist/src/types/main-reconcilers.js +11 -0
- package/dist/src/types/main-reconcilers.js.map +1 -0
- package/dist/src/types/main-runner.js +13 -0
- package/dist/src/types/main-runner.js.map +1 -0
- package/dist/src/types/main-startup.js +5 -0
- package/dist/src/types/main-startup.js.map +1 -0
- package/dist/src/types/main-substrates.js +5 -0
- package/dist/src/types/main-substrates.js.map +1 -0
- package/dist/src/types/mcp/dispatch.js +4 -0
- package/dist/src/types/mcp/dispatch.js.map +1 -0
- package/dist/src/types/mcp/post-move.js +7 -0
- package/dist/src/types/mcp/post-move.js.map +1 -0
- package/dist/src/types/mcp.js +9 -0
- package/dist/src/types/mcp.js.map +1 -0
- package/dist/src/types/ports.js +12 -0
- package/dist/src/types/ports.js.map +1 -0
- package/dist/src/types/reconcile/image-decide.js +5 -0
- package/dist/src/types/reconcile/image-decide.js.map +1 -0
- package/dist/src/types/reconcile/ledger.js +7 -0
- package/dist/src/types/reconcile/ledger.js.map +1 -0
- package/dist/src/types/reconcile/pr-loop.js +8 -0
- package/dist/src/types/reconcile/pr-loop.js.map +1 -0
- package/dist/src/types/reconcile/vm-reap.js +8 -0
- package/dist/src/types/reconcile/vm-reap.js.map +1 -0
- package/dist/src/types/reconcile/workspace-decide.js +7 -0
- package/dist/src/types/reconcile/workspace-decide.js.map +1 -0
- package/dist/src/types/reconcile.js +9 -0
- package/dist/src/types/reconcile.js.map +1 -0
- package/dist/src/types/runlog.js +7 -0
- package/dist/src/types/runlog.js.map +1 -0
- package/dist/src/types/runner/actions-runner.js +12 -0
- package/dist/src/types/runner/actions-runner.js.map +1 -0
- package/dist/src/types/runner/gondolin-dispatch.js +5 -0
- package/dist/src/types/runner/gondolin-dispatch.js.map +1 -0
- package/dist/src/types/runner/injection.js +6 -0
- package/dist/src/types/runner/injection.js.map +1 -0
- package/dist/src/types/runner/runner-loop.js +5 -0
- package/dist/src/types/runner/runner-loop.js.map +1 -0
- package/dist/src/types/runner/turn.js +4 -0
- package/dist/src/types/runner/turn.js.map +1 -0
- package/dist/src/types/runner/vm-plan.js +4 -0
- package/dist/src/types/runner/vm-plan.js.map +1 -0
- package/dist/src/types/runtime.js +9 -0
- package/dist/src/types/runtime.js.map +1 -0
- package/dist/src/types/schedule/admission.js +7 -0
- package/dist/src/types/schedule/admission.js.map +1 -0
- package/dist/src/types/schedule/circuit-breaker.js +2 -0
- package/dist/src/types/schedule/circuit-breaker.js.map +1 -0
- package/dist/src/types/schedule/eligibility.js +9 -0
- package/dist/src/types/schedule/eligibility.js.map +1 -0
- package/dist/src/types/schedule/orchestrator-loop.js +10 -0
- package/dist/src/types/schedule/orchestrator-loop.js.map +1 -0
- package/dist/src/types/schedule/sleep-cycle.js +4 -0
- package/dist/src/types/schedule/sleep-cycle.js.map +1 -0
- package/dist/src/types/schedule/slots.js +8 -0
- package/dist/src/types/schedule/slots.js.map +1 -0
- package/dist/src/types/schedule/tick.js +9 -0
- package/dist/src/types/schedule/tick.js.map +1 -0
- package/dist/src/types/server/mcp-runtime.js +8 -0
- package/dist/src/types/server/mcp-runtime.js.map +1 -0
- package/dist/src/types/workflow/parse.js +4 -0
- package/dist/src/types/workflow/parse.js.map +1 -0
- package/dist/tests/core/account-id.test.js +35 -0
- package/dist/tests/core/account-id.test.js.map +1 -0
- package/dist/tests/core/actions-parse.test.js +176 -0
- package/dist/tests/core/actions-parse.test.js.map +1 -0
- package/dist/tests/core/adapter-config.test.js +133 -0
- package/dist/tests/core/adapter-config.test.js.map +1 -0
- package/dist/tests/core/admission.test.js +215 -0
- package/dist/tests/core/admission.test.js.map +1 -0
- package/dist/tests/core/args.test.js +132 -0
- package/dist/tests/core/args.test.js.map +1 -0
- package/dist/tests/core/availability.test.js +62 -0
- package/dist/tests/core/availability.test.js.map +1 -0
- package/dist/tests/core/checks.test.js +395 -0
- package/dist/tests/core/checks.test.js.map +1 -0
- package/dist/tests/core/circuit-breaker.test.js +172 -0
- package/dist/tests/core/circuit-breaker.test.js.map +1 -0
- package/dist/tests/core/coerce.test.js +87 -0
- package/dist/tests/core/coerce.test.js.map +1 -0
- package/dist/tests/core/context.test.js +228 -0
- package/dist/tests/core/context.test.js.map +1 -0
- package/dist/tests/core/decisions.test.js +310 -0
- package/dist/tests/core/decisions.test.js.map +1 -0
- package/dist/tests/core/derive.test.js +205 -0
- package/dist/tests/core/derive.test.js.map +1 -0
- package/dist/tests/core/dispatch-config.test.js +164 -0
- package/dist/tests/core/dispatch-config.test.js.map +1 -0
- package/dist/tests/core/dispatch.test.js +302 -0
- package/dist/tests/core/dispatch.test.js.map +1 -0
- package/dist/tests/core/eligibility.test.js +163 -0
- package/dist/tests/core/eligibility.test.js.map +1 -0
- package/dist/tests/core/extract.test.js +139 -0
- package/dist/tests/core/extract.test.js.map +1 -0
- package/dist/tests/core/fake-creds.test.js +134 -0
- package/dist/tests/core/fake-creds.test.js.map +1 -0
- package/dist/tests/core/file.test.js +197 -0
- package/dist/tests/core/file.test.js.map +1 -0
- package/dist/tests/core/git-result.test.js +113 -0
- package/dist/tests/core/git-result.test.js.map +1 -0
- package/dist/tests/core/identity.test.js +180 -0
- package/dist/tests/core/identity.test.js.map +1 -0
- package/dist/tests/core/image-decide.test.js +59 -0
- package/dist/tests/core/image-decide.test.js.map +1 -0
- package/dist/tests/core/injection.test.js +163 -0
- package/dist/tests/core/injection.test.js.map +1 -0
- package/dist/tests/core/ledger.test.js +218 -0
- package/dist/tests/core/ledger.test.js.map +1 -0
- package/dist/tests/core/managed-image.test.js +68 -0
- package/dist/tests/core/managed-image.test.js.map +1 -0
- package/dist/tests/core/mise.test.js +138 -0
- package/dist/tests/core/mise.test.js.map +1 -0
- package/dist/tests/core/parse.test.js +174 -0
- package/dist/tests/core/parse.test.js.map +1 -0
- package/dist/tests/core/path.test.js +50 -0
- package/dist/tests/core/path.test.js.map +1 -0
- package/dist/tests/core/plan.test.js +218 -0
- package/dist/tests/core/plan.test.js.map +1 -0
- package/dist/tests/core/post-move.test.js +162 -0
- package/dist/tests/core/post-move.test.js.map +1 -0
- package/dist/tests/core/pr-classify.test.js +117 -0
- package/dist/tests/core/pr-classify.test.js.map +1 -0
- package/dist/tests/core/pr-decide.test.js +298 -0
- package/dist/tests/core/pr-decide.test.js.map +1 -0
- package/dist/tests/core/pr-loop.test.js +301 -0
- package/dist/tests/core/pr-loop.test.js.map +1 -0
- package/dist/tests/core/pr-notes.test.js +165 -0
- package/dist/tests/core/pr-notes.test.js.map +1 -0
- package/dist/tests/core/predicates.test.js +154 -0
- package/dist/tests/core/predicates.test.js.map +1 -0
- package/dist/tests/core/prompt.test.js +189 -0
- package/dist/tests/core/prompt.test.js.map +1 -0
- package/dist/tests/core/protocol.test.js +195 -0
- package/dist/tests/core/protocol.test.js.map +1 -0
- package/dist/tests/core/reconcile-issue.test.js +116 -0
- package/dist/tests/core/reconcile-issue.test.js.map +1 -0
- package/dist/tests/core/render.test.js +549 -0
- package/dist/tests/core/render.test.js.map +1 -0
- package/dist/tests/core/retry.test.js +186 -0
- package/dist/tests/core/retry.test.js.map +1 -0
- package/dist/tests/core/routes.test.js +247 -0
- package/dist/tests/core/routes.test.js.map +1 -0
- package/dist/tests/core/run-fold.test.js +299 -0
- package/dist/tests/core/run-fold.test.js.map +1 -0
- package/dist/tests/core/shape.test.js +185 -0
- package/dist/tests/core/shape.test.js.map +1 -0
- package/dist/tests/core/sleep-cycle.test.js +150 -0
- package/dist/tests/core/sleep-cycle.test.js.map +1 -0
- package/dist/tests/core/slots.test.js +201 -0
- package/dist/tests/core/slots.test.js.map +1 -0
- package/dist/tests/core/state-resolve.test.js +80 -0
- package/dist/tests/core/state-resolve.test.js.map +1 -0
- package/dist/tests/core/summary.test.js +200 -0
- package/dist/tests/core/summary.test.js.map +1 -0
- package/dist/tests/core/template.test.js +116 -0
- package/dist/tests/core/template.test.js.map +1 -0
- package/dist/tests/core/tick.test.js +558 -0
- package/dist/tests/core/tick.test.js.map +1 -0
- package/dist/tests/core/token-fold.test.js +176 -0
- package/dist/tests/core/token-fold.test.js.map +1 -0
- package/dist/tests/core/turn.test.js +388 -0
- package/dist/tests/core/turn.test.js.map +1 -0
- package/dist/tests/core/url.test.js +118 -0
- package/dist/tests/core/url.test.js.map +1 -0
- package/dist/tests/core/validate.test.js +247 -0
- package/dist/tests/core/validate.test.js.map +1 -0
- package/dist/tests/core/views.test.js +252 -0
- package/dist/tests/core/views.test.js.map +1 -0
- package/dist/tests/core/vm-decide.test.js +110 -0
- package/dist/tests/core/vm-decide.test.js.map +1 -0
- package/dist/tests/core/vm-guards.test.js +153 -0
- package/dist/tests/core/vm-guards.test.js.map +1 -0
- package/dist/tests/core/vm-plan.test.js +332 -0
- package/dist/tests/core/vm-plan.test.js.map +1 -0
- package/dist/tests/core/vm-reap.test.js +196 -0
- package/dist/tests/core/vm-reap.test.js.map +1 -0
- package/dist/tests/core/workflow-parse.test.js +493 -0
- package/dist/tests/core/workflow-parse.test.js.map +1 -0
- package/dist/tests/core/workspace-decide.test.js +236 -0
- package/dist/tests/core/workspace-decide.test.js.map +1 -0
- package/dist/tests/helpers/fixtures.js +167 -0
- package/dist/tests/helpers/fixtures.js.map +1 -0
- package/dist/tests/shell/acp-substrate.test.js +101 -0
- package/dist/tests/shell/acp-substrate.test.js.map +1 -0
- package/dist/tests/shell/actions-runner-push.test.js +203 -0
- package/dist/tests/shell/actions-runner-push.test.js.map +1 -0
- package/dist/tests/shell/credential-hooks.test.js +36 -0
- package/dist/tests/shell/credential-hooks.test.js.map +1 -0
- package/dist/tests/shell/credential-registry.test.js +165 -0
- package/dist/tests/shell/credential-registry.test.js.map +1 -0
- package/dist/tests/shell/credential-substrate.test.js +179 -0
- package/dist/tests/shell/credential-substrate.test.js.map +1 -0
- package/dist/tests/shell/dockerfile-mise-pin.test.js +51 -0
- package/dist/tests/shell/dockerfile-mise-pin.test.js.map +1 -0
- package/dist/tests/shell/doctor.test.js +101 -0
- package/dist/tests/shell/doctor.test.js.map +1 -0
- package/dist/tests/shell/effect-vm-create.test.js +52 -0
- package/dist/tests/shell/effect-vm-create.test.js.map +1 -0
- package/dist/tests/shell/gh-port.test.js +63 -0
- package/dist/tests/shell/gh-port.test.js.map +1 -0
- package/dist/tests/shell/gondolin-dispatch-guard.test.js +144 -0
- package/dist/tests/shell/gondolin-dispatch-guard.test.js.map +1 -0
- package/dist/tests/shell/gondolin-dispatch-shquote.test.js +168 -0
- package/dist/tests/shell/gondolin-dispatch-shquote.test.js.map +1 -0
- package/dist/tests/shell/gondolin-image-converter.test.js +208 -0
- package/dist/tests/shell/gondolin-image-converter.test.js.map +1 -0
- package/dist/tests/shell/gondolin-image-fetch.test.js +93 -0
- package/dist/tests/shell/gondolin-image-fetch.test.js.map +1 -0
- package/dist/tests/shell/http-handler.test.js +608 -0
- package/dist/tests/shell/http-handler.test.js.map +1 -0
- package/dist/tests/shell/http-server.test.js +53 -0
- package/dist/tests/shell/http-server.test.js.map +1 -0
- package/dist/tests/shell/mcp-runtime.test.js +366 -0
- package/dist/tests/shell/mcp-runtime.test.js.map +1 -0
- package/dist/tests/shell/mise-config-asset.test.js +87 -0
- package/dist/tests/shell/mise-config-asset.test.js.map +1 -0
- package/dist/tests/shell/orchestrator-loop.test.js +583 -0
- package/dist/tests/shell/orchestrator-loop.test.js.map +1 -0
- package/dist/tests/shell/reconciler-passes.test.js +314 -0
- package/dist/tests/shell/reconciler-passes.test.js.map +1 -0
- package/dist/tests/shell/runner-loop-turn.test.js +97 -0
- package/dist/tests/shell/runner-loop-turn.test.js.map +1 -0
- package/dist/tests/shell/runner-slice.test.js +536 -0
- package/dist/tests/shell/runner-slice.test.js.map +1 -0
- package/dist/tests/shell/scaffold.test.js +65 -0
- package/dist/tests/shell/scaffold.test.js.map +1 -0
- package/dist/tests/shell/tick-config.test.js +83 -0
- package/dist/tests/shell/tick-config.test.js.map +1 -0
- package/dist/tests/shell/tracker-parse-dates.test.js +44 -0
- package/dist/tests/shell/tracker-parse-dates.test.js.map +1 -0
- package/dist/tests/shell/tracker-write-issue.test.js +154 -0
- package/dist/tests/shell/tracker-write-issue.test.js.map +1 -0
- package/dist/tests/shell/workflow-prompt-split.test.js +208 -0
- package/dist/tests/shell/workflow-prompt-split.test.js.map +1 -0
- package/dist/tests/shell/workspace-live-config.test.js +140 -0
- package/dist/tests/shell/workspace-live-config.test.js.map +1 -0
- package/package.json +31 -11
- package/patches/@earendil-works+gondolin+0.12.0.patch +173 -0
- package/prompts/Reflect.md +91 -0
- package/prompts/Review.md +97 -0
- package/prompts/Todo.md +96 -0
- package/prompts/_footer.md +41 -0
- package/prompts/_preamble.md +42 -0
- package/prompts-minimal/Todo.md +26 -0
- package/scripts/postinstall.mjs +63 -0
- package/scripts/vm-agent.mjs +433 -0
- package/WORKFLOW.md +0 -269
- package/WORKFLOW.template.md +0 -307
- package/dist/agent/acp.js +0 -304
- package/dist/agent/acp.js.map +0 -1
- package/dist/agent/adapters.js +0 -275
- package/dist/agent/adapters.js.map +0 -1
- package/dist/agent/codex.js +0 -439
- package/dist/agent/codex.js.map +0 -1
- package/dist/agent/runner.js +0 -394
- package/dist/agent/runner.js.map +0 -1
- package/dist/agent/smolvm.js +0 -174
- package/dist/agent/smolvm.js.map +0 -1
- package/dist/bin/symphony.js +0 -205
- package/dist/bin/symphony.js.map +0 -1
- package/dist/http.js +0 -1189
- package/dist/http.js.map +0 -1
- package/dist/logging.js +0 -45
- package/dist/logging.js.map +0 -1
- package/dist/mcp.js +0 -478
- package/dist/mcp.js.map +0 -1
- package/dist/orchestrator.js +0 -683
- package/dist/orchestrator.js.map +0 -1
- package/dist/prompt.js +0 -65
- package/dist/prompt.js.map +0 -1
- package/dist/trackers/local.js +0 -344
- package/dist/trackers/local.js.map +0 -1
- package/dist/trackers/types.js +0 -10
- package/dist/trackers/types.js.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/workflow.js +0 -385
- package/dist/workflow.js.map +0 -1
- package/dist/workspace.js +0 -196
- package/dist/workspace.js.map +0 -1
- package/scripts/build-vm.sh +0 -67
package/PRODUCT.md
CHANGED
|
@@ -23,7 +23,8 @@ 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, OpenCode) inside isolated
|
|
26
|
+
(Claude Code, Codex, OpenCode) inside isolated per-issue Gondolin microVMs over
|
|
27
|
+
ACP. The
|
|
27
28
|
HTTP dashboard exists to do two things well:
|
|
28
29
|
|
|
29
30
|
1. **Dispatch** — create issues into the tracker without dropping back to the
|
package/README.md
CHANGED
|
@@ -1,77 +1,180 @@
|
|
|
1
1
|
# smol-symphony
|
|
2
2
|
|
|
3
|
+
> **Disclaimer:** this project is written using AI — the orchestrator
|
|
4
|
+
> dispatches AI coding agents at itself, and the bulk of the code in this
|
|
5
|
+
> repository was authored by those agents under human review.
|
|
6
|
+
|
|
3
7
|
A small TypeScript orchestrator that reads issues off a local Markdown tracker,
|
|
4
8
|
prepares per-issue workspaces, and runs coding agents (Claude Code, Codex,
|
|
5
|
-
OpenCode) inside isolated [
|
|
6
|
-
[Agent Client Protocol](https://agentclientprotocol.com).
|
|
9
|
+
OpenCode) inside isolated per-issue [Gondolin](https://github.com/earendil-works/gondolin)
|
|
10
|
+
microVMs over the [Agent Client Protocol](https://agentclientprotocol.com).
|
|
7
11
|
|
|
8
|
-
The agent signals
|
|
9
|
-
`request_human_steering`); the orchestrator handles state,
|
|
10
|
-
and
|
|
12
|
+
The agent signals progress through an injected MCP server (`transition`,
|
|
13
|
+
`request_human_steering`, `propose_issue`); the orchestrator handles state,
|
|
14
|
+
retry, concurrency, and opens a pull request per issue when configured for
|
|
15
|
+
a GitHub remote. In local-only mode the per-issue branch is left in the
|
|
16
|
+
workspace for review.
|
|
11
17
|
|
|
12
18
|
```
|
|
13
19
|
┌──────────────────────────────────────────────────────────────────────────┐
|
|
14
20
|
│ symphony (node host) │
|
|
15
21
|
│ │
|
|
16
|
-
│
|
|
17
|
-
│
|
|
18
|
-
│
|
|
19
|
-
│
|
|
20
|
-
│
|
|
21
|
-
│
|
|
22
|
-
│
|
|
23
|
-
│
|
|
24
|
-
│
|
|
25
|
-
│
|
|
26
|
-
│
|
|
27
|
-
│
|
|
28
|
-
│
|
|
29
|
-
│
|
|
22
|
+
│ ./issues/<state>/*.md ──┐ │
|
|
23
|
+
│ ./WORKFLOW.yaml ├──▶ orchestrator ──▶ agent runner │
|
|
24
|
+
│ ./WORKFLOW.template.yaml ──┘ poll · reconcile · dispatch │
|
|
25
|
+
│ │ │
|
|
26
|
+
│ ▼ ACP/RPC │
|
|
27
|
+
│ ┌───────────────────────────────┐ │
|
|
28
|
+
│ │ Gondolin (per-issue VM) │ │
|
|
29
|
+
│ │ adapter (claude / codex) │ │
|
|
30
|
+
│ │ workspace mount │ │
|
|
31
|
+
│ │ mcp client ────────────────┼─┐│
|
|
32
|
+
│ └───────────────────────────────┘ ││
|
|
33
|
+
│ ││
|
|
34
|
+
│ symphony MCP server ◀─────────────────────────────────────┘│
|
|
35
|
+
│ ( transition · request_human_steering · propose_issue ) │
|
|
36
|
+
│ │
|
|
37
|
+
│ HTTP dashboard (HTMX): / │
|
|
38
|
+
│ attention · sessions · on disk · new issue · totals │
|
|
30
39
|
└──────────────────────────────────────────────────────────────────────────┘
|
|
31
40
|
```
|
|
32
41
|
|
|
42
|
+
`SPEC.md` documents the contracts this repo's code references; for the
|
|
43
|
+
original architectural narrative, see
|
|
44
|
+
[openai/symphony/SPEC.md](https://github.com/openai/symphony/blob/main/SPEC.md).
|
|
45
|
+
|
|
33
46
|
## Quick start
|
|
34
47
|
|
|
35
|
-
|
|
48
|
+
The golden path from zero to your first dispatched issue. The details behind
|
|
49
|
+
each step live in [Prerequisites in detail](#prerequisites-in-detail) below — you
|
|
50
|
+
should not need them to get here.
|
|
36
51
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
```bash
|
|
53
|
+
# 1. Build the agent rootfs image once. This ships only `mise` (jdx/mise) — node +
|
|
54
|
+
# the coding-agent CLIs are mise-installed at dispatch, the launcher is injected —
|
|
55
|
+
# and tags the result `symphony-agents:latest` — the tag the scaffolded
|
|
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
|
|
59
|
+
|
|
60
|
+
# 2. In your project, scaffold the minimal WORKFLOW.yaml. With no workflow file
|
|
61
|
+
# present, symphony offers to write a ~30-line starter (every key required,
|
|
62
|
+
# no power features), then exits so you can glance at it.
|
|
63
|
+
cd /path/to/your/project
|
|
64
|
+
npx smol-symphony WORKFLOW.yaml
|
|
65
|
+
|
|
66
|
+
# 3. Verify the whole setup in one pass before the first dispatch. `symphony
|
|
67
|
+
# doctor` runs every adoption-prerequisite probe — Node version, the
|
|
68
|
+
# `gondolin.image` pin, each configured adapter's host credential, a
|
|
69
|
+
# writable `tracker.root`, and a bindable dashboard port — and prints a
|
|
70
|
+
# PASS/FAIL line per check with a one-line fix for each failure, exiting 0
|
|
71
|
+
# iff every check passes. Unlike startup (which bails on the first failure),
|
|
72
|
+
# it runs all probes so you see the whole picture at once.
|
|
73
|
+
npx smol-symphony doctor WORKFLOW.yaml
|
|
74
|
+
|
|
75
|
+
# 4. Drop one issue into the tracker.
|
|
76
|
+
mkdir -p issues/Todo
|
|
77
|
+
printf -- '---\ntitle: "Say hi"\n---\nAdd a hi() that returns "hi".\n' > issues/Todo/1.md
|
|
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.
|
|
83
|
+
```
|
|
46
84
|
|
|
47
|
-
|
|
85
|
+
The same first-run scaffold also installs an issue-filing skill at
|
|
86
|
+
`.claude/skills/symphony-issues/SKILL.md` (best-effort — it never blocks the
|
|
87
|
+
workflow scaffold), so a coding agent in the freshly-onboarded repo can file
|
|
88
|
+
well-formed tracker issues and decompose a large task into a `blocked_by` DAG
|
|
89
|
+
from day one.
|
|
90
|
+
|
|
91
|
+
The scaffolded file ([WORKFLOW.minimal.yaml](./WORKFLOW.minimal.yaml) is the shipped
|
|
92
|
+
copy) runs as-is once `symphony-agents:latest` exists; the only edits a different
|
|
93
|
+
setup needs are `gondolin.image` (if you pinned a build id) and the adapter
|
|
94
|
+
credential for your chosen agent. When you want a power feature it omits — typed
|
|
95
|
+
action DAGs, PR autopilot, per-state adapters, egress allowlists — graduate to
|
|
96
|
+
the annotated [WORKFLOW.template.yaml](./WORKFLOW.template.yaml).
|
|
97
|
+
|
|
98
|
+
(Or `npm i -g smol-symphony` and then `symphony doctor` / `symphony WORKFLOW.yaml`
|
|
99
|
+
to skip the `npx` fetch — both invoke the `symphony` bin shipped in this
|
|
100
|
+
package.)
|
|
101
|
+
|
|
102
|
+
### Prerequisites in detail
|
|
103
|
+
|
|
104
|
+
- **Node.js ≥ 20.**
|
|
105
|
+
- **The agent rootfs image** (step 1). Gondolin is the in-process microVM
|
|
106
|
+
substrate (`@earendil-works/gondolin`), so there is no separate VM daemon to
|
|
107
|
+
run. The image is built **once** from `images/agents/` via
|
|
108
|
+
`npm run build:image`: it starts from `node:24-bookworm-slim`, installs base
|
|
109
|
+
CLI tooling, and ships only the `mise` (jdx/mise) binary. node + every
|
|
110
|
+
ACP-capable coding agent (`claude-agent-acp`, `codex-acp`, …) are
|
|
111
|
+
NO LONGER baked — they come from a mise SYSTEM config symphony stages into the
|
|
112
|
+
guest at dispatch (`assets/symphony-mise.system.toml`) and installs via
|
|
113
|
+
`mise install` into a warm-cached data dir; a consuming repo's own `mise.toml`
|
|
114
|
+
adds project toolchains (rust, go, kotlin+gradle, …) on top. The in-VM stdio
|
|
115
|
+
launcher is likewise injected at dispatch, not baked. So bumping an agent CLI is
|
|
116
|
+
a one-line edit to the staged mise config + a restart — no image rebuild + repin.
|
|
117
|
+
The build prints a content-addressed build id; pin it (or the
|
|
118
|
+
`symphony-agents:latest` tag) in `WORKFLOW.yaml`'s `gondolin.image`. See
|
|
119
|
+
[images/agents/README.md](./images/agents/README.md) for the build steps and
|
|
120
|
+
requirements, and `gondolin.mise` in
|
|
121
|
+
[WORKFLOW.template.yaml](./WORKFLOW.template.yaml) to tune the data dir or opt out.
|
|
122
|
+
- **An adapter credential.** For the default `acp.adapter: claude`: a
|
|
123
|
+
credentials file at `~/.claude/.credentials.json` on the host. Symphony reads
|
|
124
|
+
it only on the host side: the guest holds only a token-shaped placeholder, and
|
|
125
|
+
the host substitutes the real OAuth access token into the outbound request at
|
|
126
|
+
Gondolin egress (TLS-MITM). The credential file itself is never staged into
|
|
127
|
+
the VM. (For `acp.adapter: codex`, see [WORKFLOW.template.yaml](./WORKFLOW.template.yaml).)
|
|
128
|
+
- **Skipping the `npx` fetch.** `npm i -g smol-symphony` installs the `symphony`
|
|
129
|
+
bin globally so `symphony WORKFLOW.yaml` works without re-fetching; the image
|
|
130
|
+
build still needs a checkout (it lives in `images/agents/`).
|
|
131
|
+
- **Console output.** With the default log file configured, symphony prints a
|
|
132
|
+
one-line-per-field startup banner (workflow, tracker root, dashboard URL,
|
|
133
|
+
log-file path) and routes the structured `key=value` stream to
|
|
134
|
+
`.symphony/logs/symphony.log` only. `tail -f` that file to follow the detail.
|
|
135
|
+
Pass `--verbose` (alias `--foreground`) to mirror the structured stream back
|
|
136
|
+
to the console for interactive debugging. With no log file configured (the
|
|
137
|
+
`SYMPHONY_LOG_FILE=""` override), the structured stream stays on stderr.
|
|
138
|
+
|
|
139
|
+
### From a checkout
|
|
140
|
+
|
|
141
|
+
If you're hacking on symphony itself:
|
|
48
142
|
|
|
49
143
|
```bash
|
|
144
|
+
git clone https://github.com/dizk/smol-symphony.git
|
|
145
|
+
cd smol-symphony
|
|
50
146
|
npm install
|
|
51
147
|
npm run build
|
|
52
|
-
npx symphony WORKFLOW.
|
|
148
|
+
npx symphony WORKFLOW.yaml # the local bin
|
|
53
149
|
```
|
|
54
150
|
|
|
55
|
-
|
|
56
|
-
`issues/Todo/` from the filesystem or the dashboard's `new issue` form;
|
|
57
|
-
symphony dispatches them on the next poll.
|
|
151
|
+
`npm run dev` (via `tsx watch`) reruns on source edits.
|
|
58
152
|
|
|
59
153
|
## Local Markdown tracker
|
|
60
154
|
|
|
61
155
|
Issues live as `.md` files under `tracker.root`. The parent directory is the
|
|
62
|
-
issue state
|
|
156
|
+
issue state; the set of valid state directories comes from the `states:` block
|
|
157
|
+
in `WORKFLOW.yaml` (see below) and is auto-mkdir'd on startup.
|
|
63
158
|
|
|
64
159
|
```
|
|
65
160
|
issues/
|
|
66
161
|
├── Todo/
|
|
67
|
-
│ ├──
|
|
68
|
-
│ └──
|
|
69
|
-
├──
|
|
70
|
-
│ └──
|
|
71
|
-
|
|
72
|
-
|
|
162
|
+
│ ├── 1.md
|
|
163
|
+
│ └── 2.md
|
|
164
|
+
├── Review/
|
|
165
|
+
│ └── 3.md
|
|
166
|
+
├── Done/
|
|
167
|
+
│ └── 4.md
|
|
168
|
+
└── Triage/
|
|
169
|
+
└── 5.md
|
|
73
170
|
```
|
|
74
171
|
|
|
172
|
+
The basename is the issue identifier. When a caller (dashboard form, MCP
|
|
173
|
+
`propose_issue`) omits an explicit identifier, the tracker picks the next free
|
|
174
|
+
positive integer by scanning every state directory under `tracker.root`.
|
|
175
|
+
Operator-supplied identifiers (e.g. `CACHE-7.md`) pass through unchanged and
|
|
176
|
+
coexist with the numeric ones.
|
|
177
|
+
|
|
75
178
|
Each file has YAML front matter and an optional body:
|
|
76
179
|
|
|
77
180
|
```markdown
|
|
@@ -79,28 +182,40 @@ Each file has YAML front matter and an optional body:
|
|
|
79
182
|
title: "Fix the login bug"
|
|
80
183
|
priority: 2
|
|
81
184
|
labels: [bug, auth]
|
|
82
|
-
blocked_by: [
|
|
185
|
+
blocked_by: [5]
|
|
83
186
|
---
|
|
84
187
|
Long-form description in the body.
|
|
85
188
|
```
|
|
86
189
|
|
|
87
190
|
State comparison is case-insensitive. Moving the file between state
|
|
88
191
|
directories is the canonical state transition; the orchestrator does this
|
|
89
|
-
itself in response to `
|
|
90
|
-
filesystem access to the tracker root: it signals
|
|
91
|
-
MCP server and the orchestrator does the file move.
|
|
92
|
-
|
|
93
|
-
## WORKFLOW.
|
|
94
|
-
|
|
95
|
-
`WORKFLOW.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
192
|
+
itself in response to `symphony.transition`. The agent inside the VM does
|
|
193
|
+
**not** have filesystem access to the tracker root: it signals progress
|
|
194
|
+
through the MCP server and the orchestrator does the file move.
|
|
195
|
+
|
|
196
|
+
## WORKFLOW.yaml
|
|
197
|
+
|
|
198
|
+
`WORKFLOW.yaml` is a pure YAML config file (the orchestrator config). Each
|
|
199
|
+
active state's prompt lives in its own `prompt_file` — a
|
|
200
|
+
[Liquid](https://liquidjs.com/)-templated file under `prompts/`, wrapped in the
|
|
201
|
+
shared `prompt.preamble_file`/`footer_file`. The shipped file in this repo is
|
|
202
|
+
the canonical project workflow; see
|
|
203
|
+
[WORKFLOW.template.yaml](./WORKFLOW.template.yaml) for the annotated reference
|
|
99
204
|
covering every supported option, its type, default, and example.
|
|
100
205
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
206
|
+
The workflow is a **state machine**. A required top-level `states:` block
|
|
207
|
+
declares every state an issue can occupy, its `role` (`active` — dispatched;
|
|
208
|
+
`terminal` — triggers cleanup and handoff; `holding` — sits outside the
|
|
209
|
+
dispatch loop, e.g. `Triage`), and optional per-state `adapter`, `model`,
|
|
210
|
+
`max_turns`, and `allowed_transitions` overrides. A single issue can travel
|
|
211
|
+
through any number of states with distinct adapters and instructions; each
|
|
212
|
+
active state names its own `prompt_file`, so the agent in each state sees only
|
|
213
|
+
that state's instructions plus the shared preamble/footer. The shipped workflow
|
|
214
|
+
uses a two-stage `Todo → Review → Done` flow (Claude implements, Codex reviews).
|
|
215
|
+
|
|
216
|
+
Symphony watches the file and its prompt files, and re-applies poll interval,
|
|
217
|
+
concurrency, typed actions, prompts, gondolin settings, etc. on change without
|
|
218
|
+
restart. In-flight runs keep the settings they started with.
|
|
104
219
|
|
|
105
220
|
## Dashboard
|
|
106
221
|
|
|
@@ -130,37 +245,47 @@ API clients. CSRF-relevant content types (`text/plain`,
|
|
|
130
245
|
|
|
131
246
|
Symphony injects an MCP server into each ACP session at
|
|
132
247
|
`http://<host>:<bound-port>/api/v1/issues/<id>/mcp`, gated by a per-dispatch
|
|
133
|
-
bearer token.
|
|
134
|
-
|
|
135
|
-
- **`symphony.
|
|
136
|
-
|
|
137
|
-
`
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
248
|
+
bearer token. Three tools:
|
|
249
|
+
|
|
250
|
+
- **`symphony.transition({ to_state, notes? })`** — canonical (and only)
|
|
251
|
+
exit verb. Moves the issue into another declared state, optionally
|
|
252
|
+
appending markdown `notes` to the issue body before the move so the next
|
|
253
|
+
agent (in `to_state`) reads them as part of `issue.description`. A
|
|
254
|
+
transition into a `role: terminal` state ends the run and triggers
|
|
255
|
+
workspace cleanup; transitions between active/holding states preserve the
|
|
256
|
+
workspace so the same `agent/<id>` git branch survives the handoff.
|
|
257
|
+
Rejected transitions (unknown target, disallowed by
|
|
258
|
+
`allowed_transitions`) return MCP tool-result errors the agent can read
|
|
259
|
+
and retry.
|
|
143
260
|
- **`symphony.request_human_steering({ question, context? })`** — call
|
|
144
261
|
when blocked on something only a human can answer. The turn ends
|
|
145
262
|
immediately; the human's reply arrives as the prompt for the next turn.
|
|
146
263
|
Steering-reply turns don't count against `agent.max_turns`.
|
|
147
|
-
|
|
148
|
-
|
|
264
|
+
- **`symphony.propose_issue({ title, description?, labels?, priority? })`** —
|
|
265
|
+
call when the agent notices work that is out of scope for its current
|
|
266
|
+
task. The proposal lands in the `Triage/` state directory, which the
|
|
267
|
+
orchestrator does **not** dispatch; the operator approves (→ first active
|
|
268
|
+
state) or discards (→ first terminal state, prefers `Cancelled`) from the
|
|
269
|
+
dashboard. The calling issue's identifier and a timestamp are stamped into
|
|
270
|
+
the proposal's front-matter as `proposed_by` / `proposed_at` so provenance
|
|
271
|
+
is visible.
|
|
272
|
+
|
|
273
|
+
In Gondolin, the VM's `127.0.0.1` transparently reaches the host's
|
|
149
274
|
`127.0.0.1` (verified empirically), so the agent reaches the orchestrator
|
|
150
275
|
without any mount or special host alias.
|
|
151
276
|
|
|
152
277
|
## ACP — adapter registry
|
|
153
278
|
|
|
154
279
|
One ACP client (symphony's `agent/acp.ts`), two shipped adapter profiles.
|
|
155
|
-
Each profile encodes the binary symphony launches and the
|
|
156
|
-
|
|
280
|
+
Each profile encodes the binary symphony launches and the credential path
|
|
281
|
+
the adapter reaches for inside the VM:
|
|
157
282
|
|
|
158
|
-
| Adapter | Binary |
|
|
283
|
+
| Adapter | Binary | Credential surface |
|
|
159
284
|
| --------- | ------------------ | --------------------------------- |
|
|
160
|
-
| `claude` | `claude-agent-acp` |
|
|
161
|
-
| `codex` | `codex-acp` |
|
|
285
|
+
| `claude` | `claude-agent-acp` | placeholder + host egress swap |
|
|
286
|
+
| `codex` | `codex-acp` | placeholder + host egress swap |
|
|
162
287
|
|
|
163
|
-
`WORKFLOW.
|
|
288
|
+
`WORKFLOW.yaml`:
|
|
164
289
|
|
|
165
290
|
```yaml
|
|
166
291
|
acp:
|
|
@@ -171,44 +296,64 @@ acp:
|
|
|
171
296
|
stall_timeout_ms: 300000
|
|
172
297
|
```
|
|
173
298
|
|
|
174
|
-
Selecting an adapter is enough — symphony auto-derives the launch command
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
299
|
+
Selecting an adapter is enough — symphony auto-derives the launch command.
|
|
300
|
+
For `claude`, a per-VM identity file (organization + account UUIDs only,
|
|
301
|
+
no tokens) is staged into the workspace runtime dir and copied to
|
|
302
|
+
`~/.claude.json` inside the VM; the guest holds only a token-shaped
|
|
303
|
+
placeholder, and the host substitutes the real access token into the
|
|
304
|
+
outbound request at Gondolin egress. For `codex`, no identity file is
|
|
305
|
+
staged (OpenAI ships no third-party fingerprint check); the VM is launched
|
|
306
|
+
with `OPENAI_API_KEY=<placeholder>`, and the host substitutes the real
|
|
307
|
+
OpenAI credential at egress. Set `command:` only to override (testing a
|
|
308
|
+
forked adapter, a non-standard binary path).
|
|
309
|
+
|
|
310
|
+
Credentials **never enter the VM** for either adapter. For `claude`, the
|
|
311
|
+
host's `~/.claude/.credentials.json` is read only on the host side; the VM
|
|
312
|
+
sees `~/.claude.json` (identity-only) plus the placeholder value in its
|
|
313
|
+
`Authorization` header, which the host swaps for the real token at egress.
|
|
314
|
+
For `codex`, the host's `~/.codex/auth.json` (access token /
|
|
315
|
+
`OPENAI_API_KEY`, **never** the refresh token) is read only host-side; the
|
|
316
|
+
real `OPENAI_API_KEY` is stripped from the forwarded VM boot env, so the VM
|
|
317
|
+
holds only the placeholder.
|
|
318
|
+
|
|
319
|
+
## After-run handoff: pull request
|
|
320
|
+
|
|
321
|
+
On transition into the Done state the orchestrator runs that state's typed
|
|
322
|
+
`actions:` block — two records, `push_branch` then `create_pr_if_missing` —
|
|
323
|
+
which push the per-issue branch and open a PR when a GitHub repo is configured:
|
|
324
|
+
set `workspace.github_repo: <owner>/<repo>` in `WORKFLOW.yaml` (or export
|
|
325
|
+
`SYMPHONY_REPO=<owner>/<repo>`, which overrides the file). Each action's
|
|
326
|
+
`if: $repo` predicate short-circuits to a no-op in local-only mode (neither
|
|
327
|
+
set), so the branch is simply left in the workspace until cleanup; pick the
|
|
328
|
+
commits up with `git log agent/<id>` against your local clone. The PR is opened with `gh pr create --base
|
|
329
|
+
$base_branch ...`, which requires `gh auth status` to be clean on the host; the
|
|
330
|
+
token never enters the VM.
|
|
331
|
+
|
|
332
|
+
The orchestrator stages the action context — `$branch`, `$base_branch`,
|
|
333
|
+
`$pr_title` (already id-prefixed), and `$pr_body_file` (a temp file holding the
|
|
334
|
+
current issue body) — before the block fires, so the PR description carries
|
|
335
|
+
every `symphony.transition` notes block accumulated across the run, the full
|
|
336
|
+
handoff thread from implementer through reviewer to approval. Per-action retry
|
|
337
|
+
and snapshot plumbing replaces the old opaque shell-exit surface: on a
|
|
338
|
+
rate-limit the `create_pr_if_missing` action surfaces "retrying in 60s" on the
|
|
339
|
+
dashboard rather than failing silently.
|
|
340
|
+
|
|
341
|
+
See `states.Done.actions` in [WORKFLOW.yaml](./WORKFLOW.yaml) for the canonical
|
|
342
|
+
record pair and [WORKFLOW.template.yaml](./WORKFLOW.template.yaml) for the
|
|
343
|
+
typed-action reference.
|
|
202
344
|
|
|
203
345
|
## Trust posture
|
|
204
346
|
|
|
205
|
-
Sandbox isolation comes from running each agent inside a
|
|
206
|
-
The VM has no
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
347
|
+
Sandbox isolation comes from running each agent inside a Gondolin microVM.
|
|
348
|
+
The VM has no OAuth refresh tokens or long-lived access tokens: for both
|
|
349
|
+
`claude` and `codex`, the guest holds only a token-shaped placeholder and
|
|
350
|
+
the host substitutes the real credential into the outbound request at
|
|
351
|
+
Gondolin egress, so no real Anthropic or OpenAI credential is present in
|
|
352
|
+
the VM. The VM has no tracker filesystem access (the tracker is reached
|
|
353
|
+
only through the MCP server) and stripped git remotes (set by the
|
|
354
|
+
orchestrator's `setupWorkspaceDir`).
|
|
210
355
|
|
|
211
|
-
Within the ACP session, the orchestrator follows SPEC §
|
|
356
|
+
Within the ACP session, the orchestrator follows SPEC §6.1's "high-trust"
|
|
212
357
|
posture:
|
|
213
358
|
|
|
214
359
|
- Command execution and file change approvals: auto-approve.
|
|
@@ -220,12 +365,16 @@ posture:
|
|
|
220
365
|
|
|
221
366
|
```bash
|
|
222
367
|
npm run typecheck # tsc --noEmit
|
|
223
|
-
npm test #
|
|
224
|
-
# adapters, http,
|
|
368
|
+
npm test # 170 tests across workflow, tracker, prompt, workspace,
|
|
369
|
+
# adapters, http, mcp, acp-bridge, orchestrator, run log,
|
|
370
|
+
# runner state resolution, and tool-call summary surfaces
|
|
225
371
|
npm run build # tsc emit to dist/
|
|
226
372
|
```
|
|
227
373
|
|
|
228
|
-
An end-to-end smoke run needs
|
|
374
|
+
An end-to-end smoke run needs the built agent image (see `images/agents/`).
|
|
375
|
+
|
|
376
|
+
See [CHANGELOG.md](./CHANGELOG.md) for operator-visible changes between
|
|
377
|
+
releases.
|
|
229
378
|
|
|
230
379
|
## License
|
|
231
380
|
|