smol-symphony 0.2.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 +41 -22
- package/DESIGN.md +494 -273
- package/README.md +109 -57
- package/SPEC.md +33 -24
- package/WORKFLOW.minimal.yaml +34 -0
- package/{WORKFLOW.template.md → WORKFLOW.template.yaml} +409 -256
- 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/{actions/parsing.js → src/core/actions/parse.js} +33 -114
- 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/{http.js → src/core/http/render.js} +472 -738
- package/dist/src/core/http/render.js.map +1 -0
- package/dist/{http-handlers.js → src/core/http/routes.js} +52 -87
- 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/{reconciler → src/core/reconcile}/pr-decide.js +25 -12
- 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 +21 -9
- 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 +312 -90
- package/WORKFLOW.md +0 -744
- package/dist/acp-bridge.js +0 -324
- package/dist/acp-bridge.js.map +0 -1
- package/dist/actions/cache.js +0 -191
- package/dist/actions/cache.js.map +0 -1
- package/dist/actions/effects.js +0 -41
- package/dist/actions/effects.js.map +0 -1
- package/dist/actions/executor.js +0 -570
- package/dist/actions/executor.js.map +0 -1
- package/dist/actions/index.js +0 -13
- package/dist/actions/index.js.map +0 -1
- package/dist/actions/parsing.js.map +0 -1
- package/dist/actions/predicate-env.js +0 -27
- package/dist/actions/predicate-env.js.map +0 -1
- package/dist/actions/predicates.js +0 -49
- package/dist/actions/predicates.js.map +0 -1
- package/dist/actions/templating.js +0 -66
- package/dist/actions/templating.js.map +0 -1
- package/dist/actions/types.js +0 -15
- package/dist/actions/types.js.map +0 -1
- package/dist/agent/acp.js +0 -473
- package/dist/agent/acp.js.map +0 -1
- package/dist/agent/adapter-names.js +0 -159
- package/dist/agent/adapter-names.js.map +0 -1
- package/dist/agent/adapters.js +0 -511
- package/dist/agent/adapters.js.map +0 -1
- package/dist/agent/credential-extractors.js +0 -342
- package/dist/agent/credential-extractors.js.map +0 -1
- package/dist/agent/credential-secrets.js +0 -628
- package/dist/agent/credential-secrets.js.map +0 -1
- package/dist/agent/credential-ticker.js +0 -57
- package/dist/agent/credential-ticker.js.map +0 -1
- package/dist/agent/gondolin-creds-staging.js +0 -356
- package/dist/agent/gondolin-creds-staging.js.map +0 -1
- package/dist/agent/gondolin-dispatch.js +0 -375
- package/dist/agent/gondolin-dispatch.js.map +0 -1
- package/dist/agent/gondolin.js +0 -124
- package/dist/agent/gondolin.js.map +0 -1
- package/dist/agent/runner-decisions.js +0 -134
- package/dist/agent/runner-decisions.js.map +0 -1
- package/dist/agent/runner.js +0 -1456
- package/dist/agent/runner.js.map +0 -1
- package/dist/agent/tool-call-summary.js +0 -102
- package/dist/agent/tool-call-summary.js.map +0 -1
- package/dist/agent/vm-acp-mapping.js +0 -73
- package/dist/agent/vm-acp-mapping.js.map +0 -1
- package/dist/agent/vm-guards.js +0 -262
- package/dist/agent/vm-guards.js.map +0 -1
- package/dist/agent/vm-port.js +0 -22
- package/dist/agent/vm-port.js.map +0 -1
- package/dist/agent/vm-process-registry.js +0 -79
- package/dist/agent/vm-process-registry.js.map +0 -1
- package/dist/bin/cli-args.js +0 -105
- package/dist/bin/cli-args.js.map +0 -1
- package/dist/bin/symphony.js +0 -794
- package/dist/bin/symphony.js.map +0 -1
- package/dist/errors.js +0 -15
- package/dist/errors.js.map +0 -1
- package/dist/http-disk.js +0 -135
- package/dist/http-disk.js.map +0 -1
- package/dist/http-handlers.js.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/issues.js +0 -178
- package/dist/issues.js.map +0 -1
- package/dist/logging.js +0 -203
- package/dist/logging.js.map +0 -1
- package/dist/mcp.js +0 -706
- package/dist/mcp.js.map +0 -1
- package/dist/memory.js +0 -85
- package/dist/memory.js.map +0 -1
- package/dist/orchestrator-decisions.js +0 -331
- package/dist/orchestrator-decisions.js.map +0 -1
- package/dist/orchestrator.js +0 -1569
- package/dist/orchestrator.js.map +0 -1
- package/dist/prompt.js +0 -65
- package/dist/prompt.js.map +0 -1
- package/dist/reconciler/cache.js +0 -65
- package/dist/reconciler/cache.js.map +0 -1
- package/dist/reconciler/index.js +0 -448
- package/dist/reconciler/index.js.map +0 -1
- package/dist/reconciler/ledger.js +0 -131
- package/dist/reconciler/ledger.js.map +0 -1
- package/dist/reconciler/pr-adapters.js +0 -174
- package/dist/reconciler/pr-adapters.js.map +0 -1
- package/dist/reconciler/pr-decide.js.map +0 -1
- package/dist/reconciler/pr.js +0 -422
- package/dist/reconciler/pr.js.map +0 -1
- package/dist/reconciler/types.js +0 -12
- package/dist/reconciler/types.js.map +0 -1
- package/dist/reconciler/vm.js +0 -243
- package/dist/reconciler/vm.js.map +0 -1
- package/dist/reconciler/workspace-defaults.js +0 -83
- package/dist/reconciler/workspace-defaults.js.map +0 -1
- package/dist/reconciler/workspace.js +0 -272
- package/dist/reconciler/workspace.js.map +0 -1
- package/dist/runlog.js +0 -403
- package/dist/runlog.js.map +0 -1
- package/dist/scaffold.js +0 -165
- package/dist/scaffold.js.map +0 -1
- package/dist/trackers/local.js +0 -445
- 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/util/clock.js +0 -12
- package/dist/util/clock.js.map +0 -1
- package/dist/util/crypto.js +0 -25
- package/dist/util/crypto.js.map +0 -1
- package/dist/util/frontmatter.js +0 -70
- package/dist/util/frontmatter.js.map +0 -1
- package/dist/util/fs-issues.js +0 -22
- package/dist/util/fs-issues.js.map +0 -1
- package/dist/util/process.js +0 -152
- package/dist/util/process.js.map +0 -1
- package/dist/util/workspace-key.js +0 -10
- package/dist/util/workspace-key.js.map +0 -1
- package/dist/workflow-loader.js +0 -147
- package/dist/workflow-loader.js.map +0 -1
- package/dist/workflow.js +0 -822
- package/dist/workflow.js.map +0 -1
- package/dist/workspace-types.js +0 -8
- package/dist/workspace-types.js.map +0 -1
- package/dist/workspace.js +0 -443
- package/dist/workspace.js.map +0 -1
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
WORKFLOW.template.
|
|
3
|
-
|
|
4
|
-
A workflow file is
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
# WORKFLOW.template.yaml — annotated reference for symphony workflow files.
|
|
3
|
+
#
|
|
4
|
+
# A workflow file is pure YAML config. The orchestrator parses it into
|
|
5
|
+
# ServiceConfig (see src/types/config.ts) and, per dispatched issue, renders the
|
|
6
|
+
# active state's prompt — its `prompt_file` wrapped in the shared
|
|
7
|
+
# `prompt.preamble_file` / `prompt.footer_file` — with the Liquid context
|
|
8
|
+
# `{ issue, attempt }`.
|
|
9
|
+
#
|
|
10
|
+
# This document lists every supported section, every option within it, the
|
|
11
|
+
# parser default, and a small example. For a complete worked example, see
|
|
12
|
+
# WORKFLOW.yaml in this repo. For the smallest thing that runs — what
|
|
13
|
+
# `npx smol-symphony` scaffolds by default — see WORKFLOW.minimal.yaml; reach for
|
|
14
|
+
# the options below only when you want a power feature it omits.
|
|
15
|
+
#
|
|
16
|
+
# Notation:
|
|
17
|
+
# • Required keys are marked (required).
|
|
18
|
+
# • Types: `string`, `int`, `bool`, `path` (string resolved relative to the
|
|
19
|
+
# workflow file's directory unless absolute), `string[]`, `map<K, V>`.
|
|
20
|
+
# • Defaults are what the parser writes when the key is absent.
|
|
21
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
21
22
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
22
23
|
# tracker — where issues come from.
|
|
23
24
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -26,9 +27,15 @@ tracker:
|
|
|
26
27
|
# files under `root`, one per issue, organized by state subdirectory).
|
|
27
28
|
kind: local
|
|
28
29
|
|
|
29
|
-
# root (path): directory containing `<state>/<id>.md` files.
|
|
30
|
-
#
|
|
31
|
-
|
|
30
|
+
# root (path): directory containing `<state>/<id>.md` files. Optional.
|
|
31
|
+
# An explicit value resolves absolute as-is, `~`-expanded against $HOME, or
|
|
32
|
+
# (relative) against the workflow file's directory.
|
|
33
|
+
# Default (unset): ~/.symphony/trackers/<project> — durable tracker state lives
|
|
34
|
+
# OUTSIDE the repo working tree by default, so it survives a delete / re-clone
|
|
35
|
+
# of the repo. <project> is the `workspace.github_repo` slug's repo name
|
|
36
|
+
# (owner/repo → repo), falling back to this workflow file's directory basename;
|
|
37
|
+
# sanitized so two different projects on one machine never collide.
|
|
38
|
+
# root: ~/.symphony/trackers/my-project
|
|
32
39
|
|
|
33
40
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
34
41
|
# states — per-state configuration map. REQUIRED. Every workflow must declare
|
|
@@ -47,17 +54,21 @@ tracker:
|
|
|
47
54
|
# and the landing directory for `symphony.propose_issue`.
|
|
48
55
|
# adapter (string, optional): override the workflow-level `acp.adapter` for
|
|
49
56
|
# agents dispatched in this state. Must be a known profile (claude,
|
|
50
|
-
# codex
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
# OPENAI_API_KEY
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
57
|
+
# codex). Both use host-side credential substitution at Gondolin
|
|
58
|
+
# egress and are startup-probed so a missing credential fails fast.
|
|
59
|
+
# claude has a single host credential file
|
|
60
|
+
# (~/.claude/.credentials.json) that is probed for readability; codex
|
|
61
|
+
# passes when either ~/.codex/auth.json holds a token (ChatGPT-OAuth
|
|
62
|
+
# tokens.access_token or a top-level OPENAI_API_KEY) or the host
|
|
63
|
+
# OPENAI_API_KEY env var is set.
|
|
64
|
+
# prompt_file (path): this state's prompt template, in its own file. The shell
|
|
65
|
+
# loader reads it and assembles `prompt.preamble_file` + this file +
|
|
66
|
+
# `prompt.footer_file` (see the top-level `prompt:` block below) into
|
|
67
|
+
# the template rendered for issues in this state. Every active
|
|
68
|
+
# (dispatched) state should declare one; a state without `prompt_file`
|
|
69
|
+
# renders the generic fallback prompt. Resolved relative to the
|
|
70
|
+
# workflow file. A missing/unparseable file fails at startup (and
|
|
71
|
+
# `symphony doctor`), not mid-dispatch.
|
|
61
72
|
# model (string, optional): override `acp.model` for this state.
|
|
62
73
|
# Blank or whitespace-only values normalize to "use the adapter
|
|
63
74
|
# default" (same as the workflow-level acp.model semantics).
|
|
@@ -117,12 +128,7 @@ tracker:
|
|
|
117
128
|
# Recognized kinds:
|
|
118
129
|
# push_branch { remote, ref }
|
|
119
130
|
# create_pr_if_missing { base, head, title_from, body_from }
|
|
120
|
-
# ensure_branch { name, seed_from? }
|
|
121
|
-
# checkout { ref }
|
|
122
|
-
# merge { source, target, on_conflict }
|
|
123
|
-
# delete_branch { name, scope: local|remote|both, remote? }
|
|
124
131
|
# run_in_vm { name, cmd: [...], env?, timeout? }
|
|
125
|
-
# propose_followup { title, body?, labels?, priority? }
|
|
126
132
|
#
|
|
127
133
|
# Templating: `$varname` references the fixed ActionContext
|
|
128
134
|
# namespace ($identifier, $workspace, $branch, $base_branch,
|
|
@@ -137,20 +143,24 @@ tracker:
|
|
|
137
143
|
# Retry: optional `on_error.retry: { count, backoff_ms }`. Default
|
|
138
144
|
# policy is 3 retries with exponential backoff starting at 1s,
|
|
139
145
|
# then abort. `on_error.then: { route_to: <state> }` reroutes the
|
|
140
|
-
# issue
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
146
|
+
# issue OUT of the action's state into <state> (which must be
|
|
147
|
+
# declared — validated at parse time) instead of aborting; the
|
|
148
|
+
# runner moves the tracker file there with the failure reason
|
|
149
|
+
# appended as notes. The canonical use is the Done handoff (issue
|
|
150
|
+
# 235): a `push_branch` / `create_pr_if_missing` that fails after
|
|
151
|
+
# its retries reroutes into a `HandoffFailed` holding state so a
|
|
152
|
+
# stranded handoff (no branch on the remote, no PR) is operator-
|
|
153
|
+
# visible instead of dead-ending silently in terminal Done. A
|
|
154
|
+
# rerouted handoff also RETAINS the per-issue workspace (the
|
|
155
|
+
# handoff-pending marker, issue 234) so the unpushed commit
|
|
156
|
+
# survives for a manual push. A `.github/workflows/`-touching push
|
|
157
|
+
# is the common trigger: the shared fine-grained PAT is not granted
|
|
158
|
+
# Workflows:write, so GitHub server-side-declines it and the routed
|
|
159
|
+
# reason is rewritten to an actionable "manual SSH push required".
|
|
160
|
+
#
|
|
161
|
+
# run_in_vm runs uncached: every dispatch into the state re-execs
|
|
162
|
+
# the command on the live per-issue VM. `name` labels its run-log
|
|
163
|
+
# output (no caching layer; the action is the plain escape hatch).
|
|
154
164
|
# pr (map, optional): PR autopilot routing for this state (issue 139).
|
|
155
165
|
# Valid only on a `terminal` state, and only acts when the
|
|
156
166
|
# top-level `pr:` engine block (below) has `enabled: true`. This is
|
|
@@ -174,6 +184,39 @@ tracker:
|
|
|
174
184
|
# terminal state may declare `auto_merge`, and at most one may
|
|
175
185
|
# declare `close`; an `on_conflict.route_to` naming an undeclared
|
|
176
186
|
# state is rejected at parse time.
|
|
187
|
+
# spawn (map, optional): recurring-spawn trigger for this state (the sleep
|
|
188
|
+
# cycle as a recurring STATE). Valid only on an `active` state. When
|
|
189
|
+
# a trigger fires the orchestrator MINTS a FRESH ephemeral issue into
|
|
190
|
+
# this state (it runs once and terminates in a dedicated terminal),
|
|
191
|
+
# instead of re-arming one immortal parked ticket. Fields:
|
|
192
|
+
# • on_idle (bool): spawn when the orchestrator is idle AND >=1
|
|
193
|
+
# issue reached a terminal state since the last cycle (the ">=1
|
|
194
|
+
# since last cycle" gate is load-bearing — without it an idle
|
|
195
|
+
# orchestrator re-spawns in a tight loop with nothing new to
|
|
196
|
+
# mine). Default false.
|
|
197
|
+
# • after_terminal (int): a backstop for busy stretches that never
|
|
198
|
+
# go idle — spawn once this many issues have reached a terminal
|
|
199
|
+
# state (Done/Cancelled/the spawn's terminal) since the last
|
|
200
|
+
# cycle. 0 disables the count trigger. Default 0.
|
|
201
|
+
# • title (string): title template for the minted issue;
|
|
202
|
+
# `{{ stamp }}` → the mint timestamp (e.g. "2026-06-03 12:00").
|
|
203
|
+
# Default "Reflection {{ stamp }}".
|
|
204
|
+
# • body (string, optional): lead-in line for the GENERATED
|
|
205
|
+
# provenance body (the trigger + counter + timestamp the static
|
|
206
|
+
# prompt can't know are always appended). Default: a generic
|
|
207
|
+
# "Auto-spawned reflection cycle." lead-in.
|
|
208
|
+
# • max_in_flight (int): never mint a second issue while this many
|
|
209
|
+
# are already live in the spawn state. Load-bearing — it replaces
|
|
210
|
+
# the immortal ticket's built-in "one location = one reflection"
|
|
211
|
+
# mutex, so a busy-stretch after_terminal trigger can't pile up
|
|
212
|
+
# cycles. Default 1.
|
|
213
|
+
# The terminal-transition counter resets to 0 on a successful mint
|
|
214
|
+
# and is held in orchestrator memory only (a restart resets it). At
|
|
215
|
+
# most one active state may declare `spawn` (so the spawn state is
|
|
216
|
+
# unambiguous). The spawn's terminal must be a DEDICATED terminal
|
|
217
|
+
# with no `pr:` / `actions:` — a minted issue runs on an empty branch,
|
|
218
|
+
# so a Done-style PR autopilot would try to open a PR off nothing.
|
|
219
|
+
# See the SLEEP CYCLE section below for the full pattern.
|
|
177
220
|
#
|
|
178
221
|
# Declaration order matters: role-filtered listings (active states, terminal
|
|
179
222
|
# states) follow it, and the dashboard renders state columns in the same order.
|
|
@@ -181,6 +224,7 @@ tracker:
|
|
|
181
224
|
states:
|
|
182
225
|
Todo:
|
|
183
226
|
role: active
|
|
227
|
+
prompt_file: prompts/Todo.md # this state's prompt template (see `prompt:` below)
|
|
184
228
|
adapter: claude
|
|
185
229
|
model: claude-opus-4-7
|
|
186
230
|
effort: xhigh
|
|
@@ -188,6 +232,7 @@ states:
|
|
|
188
232
|
max_concurrent: 1 # at most one implementer agent at a time
|
|
189
233
|
Review:
|
|
190
234
|
role: active
|
|
235
|
+
prompt_file: prompts/Review.md
|
|
191
236
|
adapter: codex
|
|
192
237
|
model: gpt-5-codex
|
|
193
238
|
max_turns: 4
|
|
@@ -205,14 +250,22 @@ states:
|
|
|
205
250
|
# open a PR if one does not already exist. Templates resolve against the
|
|
206
251
|
# fixed ActionContext namespace; the orchestrator stages $pr_title and
|
|
207
252
|
# $pr_body_file from the issue file before firing.
|
|
253
|
+
# A handoff that fails after its retries reroutes the issue OUT of Done into
|
|
254
|
+
# the HandoffFailed holding state (issue 235) via `on_error.then.route_to`,
|
|
255
|
+
# so a stranded handoff is operator-visible instead of silently terminal-Done.
|
|
208
256
|
# actions:
|
|
209
|
-
# -
|
|
257
|
+
# - kind: push_branch
|
|
258
|
+
# remote: origin
|
|
259
|
+
# ref: $branch
|
|
260
|
+
# if: $repo
|
|
261
|
+
# on_error: { then: { route_to: HandoffFailed } }
|
|
210
262
|
# - kind: create_pr_if_missing
|
|
211
263
|
# base: $base_branch
|
|
212
264
|
# head: $branch
|
|
213
265
|
# title_from: $pr_title
|
|
214
266
|
# body_from: $pr_body_file
|
|
215
267
|
# if: $repo
|
|
268
|
+
# on_error: { then: { route_to: HandoffFailed } }
|
|
216
269
|
Cancelled:
|
|
217
270
|
role: terminal
|
|
218
271
|
# PR autopilot close state (issue 139). Derived as the close state because
|
|
@@ -221,11 +274,46 @@ states:
|
|
|
221
274
|
# close: true
|
|
222
275
|
Triage:
|
|
223
276
|
role: holding
|
|
277
|
+
HandoffFailed:
|
|
278
|
+
# Landing state for a Done handoff that FAILED (issue 235): the failing
|
|
279
|
+
# action's `on_error.then.route_to` (above) reroutes the issue here with the
|
|
280
|
+
# reason appended. Holding → never dispatched; it parks for an operator to
|
|
281
|
+
# push the branch by hand (the workspace is retained by issue 234's marker)
|
|
282
|
+
# and move the issue back to Done, or to Cancelled. Declared AFTER Triage so
|
|
283
|
+
# Triage stays the `propose_issue` landing (the first declared holding state).
|
|
284
|
+
role: holding
|
|
224
285
|
|
|
225
286
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
226
|
-
#
|
|
287
|
+
# prompt — shared prompt-assembly files (per-state prompt split). OPTIONAL.
|
|
288
|
+
#
|
|
289
|
+
# When an active state declares a `prompt_file` (see the states block above), the
|
|
290
|
+
# shell loader builds that state's prompt by concatenating, in order:
|
|
291
|
+
#
|
|
292
|
+
# prompt.preamble_file (shared header)
|
|
293
|
+
# + the state's prompt_file (the state-specific body)
|
|
294
|
+
# + prompt.footer_file (shared footer)
|
|
295
|
+
#
|
|
296
|
+
# and renders the result — so the config reads as the shape of the workflow and
|
|
297
|
+
# each state's prompt lives in its own file under `prompts/`. The Liquid context
|
|
298
|
+
# is `{ issue, attempt }`; each file is an ordinary Liquid template fragment.
|
|
299
|
+
#
|
|
300
|
+
# Both keys are paths resolved relative to the workflow file, and both are
|
|
301
|
+
# optional: omit `preamble_file`/`footer_file` to wrap a state body in nothing.
|
|
302
|
+
# A workflow file is pure YAML config — there is no inline prompt body. Every
|
|
303
|
+
# active state names its own `prompt_file`; a state without one renders the
|
|
304
|
+
# generic fallback prompt, so give each dispatched state a `prompt_file`. See
|
|
305
|
+
# WORKFLOW.minimal.yaml for the smallest example and WORKFLOW.yaml in this repo
|
|
306
|
+
# for a full worked example.
|
|
307
|
+
#
|
|
308
|
+
# prompt:
|
|
309
|
+
# preamble_file: prompts/_preamble.md
|
|
310
|
+
# footer_file: prompts/_footer.md
|
|
311
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
312
|
+
|
|
313
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
314
|
+
# SLEEP CYCLE — a recurring reflection STATE that mines finished work for harness
|
|
227
315
|
# improvements (issue 122). Optional, opt-in pattern; layered on top of the
|
|
228
|
-
# states block above. The shipped smol-symphony WORKFLOW.
|
|
316
|
+
# states block above. The shipped smol-symphony WORKFLOW.yaml wires it for the
|
|
229
317
|
# dogfooding (symphony-on-symphony) setup.
|
|
230
318
|
#
|
|
231
319
|
# The idea: every dispatch starts from the same static prompt + config, no
|
|
@@ -233,16 +321,21 @@ states:
|
|
|
233
321
|
# rejected, burn their turn budget, or fight the harness. A periodic
|
|
234
322
|
# "reflection" turn closes that feedback loop — it reads completed-task history
|
|
235
323
|
# (the read-only mounts `eval_mode` exposes), distils *recurring* friction, and
|
|
236
|
-
# files improvement proposals against the HARNESS (this WORKFLOW.
|
|
324
|
+
# files improvement proposals against the HARNESS (this WORKFLOW.yaml's prompt
|
|
237
325
|
# branches and per-state model/max_turns/allowed_transitions/effort/actions, the
|
|
238
326
|
# gondolin image config, acceptance criteria, timeouts) — never the product code under
|
|
239
327
|
# review. Proposals land in Triage via `propose_issue`, so a human stays the
|
|
240
328
|
# gate. This is the "self-improving agent" pattern aimed at the harness rather
|
|
241
329
|
# than the product.
|
|
242
330
|
#
|
|
243
|
-
#
|
|
331
|
+
# SHAPE: recurring STATE, NOT an immortal ticket. The cycle is modelled as a
|
|
332
|
+
# recurring state that SPAWNS ephemeral reflection issues. There is no parked
|
|
333
|
+
# "Sleep cycle" ticket that ping-pongs between two states forever: when a trigger
|
|
334
|
+
# fires the orchestrator MINTS a fresh issue into the spawn state; it runs once
|
|
335
|
+
# and terminates in a dedicated terminal, like every other ticket. Two states
|
|
336
|
+
# implement it:
|
|
244
337
|
#
|
|
245
|
-
# Reflect (role: active, eval_mode: true):
|
|
338
|
+
# Reflect (role: active, eval_mode: true, spawn: {...}):
|
|
246
339
|
# - eval_mode binds /symphony/issues (all state dirs, incl. the Done/*.md
|
|
247
340
|
# handoff transcripts) + /symphony/logs (per-issue JSONL run logs)
|
|
248
341
|
# read-only into the VM. No extra mount plumbing — it reuses the existing
|
|
@@ -250,23 +343,24 @@ states:
|
|
|
250
343
|
# - Give it a capable adapter/model (large context helps: a reflection turn
|
|
251
344
|
# reads many transcripts + logs) and a higher max_turns than your
|
|
252
345
|
# implement/review states.
|
|
253
|
-
# - allowed_transitions: [
|
|
254
|
-
# cannot route itself into the
|
|
255
|
-
# improvements goes through
|
|
256
|
-
# of allowed_transitions.
|
|
257
|
-
# - The
|
|
346
|
+
# - allowed_transitions: [Reflected] — the reflector may ONLY terminate in
|
|
347
|
+
# its dedicated terminal. It cannot route itself into the
|
|
348
|
+
# implement/review/done flow. Filing improvements goes through
|
|
349
|
+
# propose_issue (→ Triage), which is independent of allowed_transitions.
|
|
350
|
+
# - The `spawn:` block (see the states-field docs above) declares the
|
|
351
|
+
# triggers (on_idle / after_terminal), the minted-issue title template, and
|
|
352
|
+
# max_in_flight. This is what makes the cycle recurring — no cron needed.
|
|
353
|
+
# - The Reflect state's `prompt_file` encodes the
|
|
258
354
|
# read → distil → propose loop and the GUARDRAILS below.
|
|
259
355
|
#
|
|
260
|
-
#
|
|
261
|
-
# -
|
|
262
|
-
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
265
|
-
#
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
# Dormant issue would mis-route it. Re-arm via cron/CLI/filesystem, not the
|
|
269
|
-
# dashboard buttons.
|
|
356
|
+
# Reflected (role: terminal):
|
|
357
|
+
# - DEDICATED terminal for a completed reflection — NOT Done. Done carries the
|
|
358
|
+
# PR autopilot `actions:` (push_branch + create_pr_if_missing); a minted
|
|
359
|
+
# reflection runs on an empty branch (it only files propose_issue), so
|
|
360
|
+
# terminating in Done would try to open a PR off nothing. So `Reflected`
|
|
361
|
+
# declares NO `pr:` and NO `actions:`. Each cycle lands here as a browsable,
|
|
362
|
+
# per-run audit trail — one issue per cycle — instead of one ever-growing
|
|
363
|
+
# immortal ticket body.
|
|
270
364
|
#
|
|
271
365
|
# GUARDRAILS (this is a self-modifying loop — keep the human in it):
|
|
272
366
|
# - Output is proposals into Triage (holding, never auto-dispatched). The
|
|
@@ -276,13 +370,14 @@ states:
|
|
|
276
370
|
# - Each proposal must cite the issue ids that motivated it, so the operator
|
|
277
371
|
# checks the lesson against the evidence rather than the reflector's summary.
|
|
278
372
|
#
|
|
279
|
-
# CADENCE
|
|
280
|
-
#
|
|
281
|
-
#
|
|
282
|
-
#
|
|
283
|
-
#
|
|
284
|
-
#
|
|
285
|
-
#
|
|
373
|
+
# CADENCE: the orchestrator auto-spawns a fresh reflection issue from the
|
|
374
|
+
# Reflect state's `spawn:` block — `on_idle` (idle with >=1 issue finished since
|
|
375
|
+
# the last cycle) or `after_terminal` (a backstop once N issues have reached a
|
|
376
|
+
# terminal state since the last cycle). The counter resets on a successful mint;
|
|
377
|
+
# `max_in_flight: 1` prevents a second cycle while one is live. An operator can
|
|
378
|
+
# also mint a cycle by hand by creating a Reflect issue (a real dashboard
|
|
379
|
+
# "reflect now" button or a `symphony reflect` verb is a natural fit) — a clean
|
|
380
|
+
# replacement for the old "re-arm by mv/cron" path.
|
|
286
381
|
#
|
|
287
382
|
# Example states to add (names are yours to choose):
|
|
288
383
|
#
|
|
@@ -294,11 +389,16 @@ states:
|
|
|
294
389
|
# model: claude-opus-4-8[1m] # large context for reading transcripts
|
|
295
390
|
# max_turns: 20 # higher than implement/review
|
|
296
391
|
# eval_mode: true
|
|
297
|
-
# allowed_transitions: [
|
|
392
|
+
# allowed_transitions: [Reflected]
|
|
393
|
+
# spawn:
|
|
394
|
+
# on_idle: true
|
|
395
|
+
# after_terminal: 10 # backstop for busy stretches (0 disables)
|
|
396
|
+
# title: "Reflection {{ stamp }}"
|
|
397
|
+
# max_in_flight: 1 # never two reflections live at once
|
|
298
398
|
# Triage:
|
|
299
|
-
# role: holding # declared before Dormant
|
|
300
|
-
# Dormant:
|
|
301
399
|
# role: holding
|
|
400
|
+
# Reflected:
|
|
401
|
+
# role: terminal # dedicated terminal — NO pr:/actions:
|
|
302
402
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
303
403
|
|
|
304
404
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -359,47 +459,50 @@ pr:
|
|
|
359
459
|
# within the window. Default 30000.
|
|
360
460
|
poll_interval_ms: 30000
|
|
361
461
|
# ----------------------------------------------------------------------------
|
|
362
|
-
# SLEEP CYCLE (
|
|
363
|
-
#
|
|
364
|
-
#
|
|
462
|
+
# SLEEP CYCLE (recurring spawn) — the recurrence lives in the `spawn:` block on
|
|
463
|
+
# the active reflection state (see the states-field docs + the SLEEP CYCLE
|
|
464
|
+
# section above). There is NO top-level `sleep_cycle:` block and NO `arm:` block;
|
|
465
|
+
# instead of re-arming one immortal parked ticket, the orchestrator MINTS a fresh
|
|
466
|
+
# ephemeral reflection issue when a trigger fires:
|
|
365
467
|
#
|
|
366
468
|
# states:
|
|
367
469
|
# Reflect:
|
|
368
470
|
# role: active
|
|
369
|
-
#
|
|
370
|
-
#
|
|
371
|
-
#
|
|
372
|
-
#
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
#
|
|
471
|
+
# allowed_transitions: [Reflected]
|
|
472
|
+
# spawn:
|
|
473
|
+
# on_idle: true # spawn when idle with >=1 terminal since last cycle
|
|
474
|
+
# after_terminal: 10 # spawn after N terminal transitions (0 disables)
|
|
475
|
+
# title: "Reflection {{ stamp }}"
|
|
476
|
+
# max_in_flight: 1 # never two reflections live at once
|
|
477
|
+
# Reflected:
|
|
478
|
+
# role: terminal # dedicated terminal — NO pr:/actions:
|
|
479
|
+
#
|
|
480
|
+
# SEMANTICS:
|
|
481
|
+
# - on_idle: spawn when the orchestrator is idle (nothing running, claimed, or
|
|
377
482
|
# pending retry, and no active candidate this poll) AND >=1 issue has reached
|
|
378
|
-
# a terminal state since the last
|
|
379
|
-
# load-bearing: without it an idle orchestrator re-
|
|
483
|
+
# a terminal state since the last cycle. The ">=1 since last cycle" gate is
|
|
484
|
+
# load-bearing: without it an idle orchestrator re-spawns in a tight loop with
|
|
380
485
|
# nothing new to mine.
|
|
381
|
-
# - after_terminal: a backstop for busy stretches that never go idle —
|
|
382
|
-
# this many issues have reached a terminal state
|
|
383
|
-
#
|
|
384
|
-
#
|
|
385
|
-
#
|
|
486
|
+
# - after_terminal: a backstop for busy stretches that never go idle — spawn
|
|
487
|
+
# once this many issues have reached a terminal state since the last cycle.
|
|
488
|
+
# 0 disables the count trigger.
|
|
489
|
+
# - max_in_flight: never mint a second issue while this many are already live in
|
|
490
|
+
# the spawn state (replaces the immortal ticket's built-in one-at-a-time
|
|
491
|
+
# mutex). Default 1.
|
|
492
|
+
# The terminal-transition counter resets to 0 on a successful mint (and is
|
|
493
|
+
# restored if the mint fails) and is held in orchestrator memory only (a restart
|
|
494
|
+
# resets it). A finished reflection's OWN terminal move (out of the spawn state)
|
|
495
|
+
# is excluded from the counter, so a completed cycle never counts toward spawning
|
|
496
|
+
# the next.
|
|
386
497
|
#
|
|
387
498
|
# VALIDATION (structural, from each state's own role — no dedicated re-validator):
|
|
388
|
-
# `
|
|
389
|
-
# `
|
|
390
|
-
#
|
|
499
|
+
# `spawn:` is only valid on an `active` state, and at most one active state may
|
|
500
|
+
# declare `spawn`. Unlike the retired `arm:` block it needs no parked issue and
|
|
501
|
+
# no from-state.
|
|
391
502
|
#
|
|
392
|
-
# GUARDRAILS:
|
|
503
|
+
# GUARDRAILS: spawning ONLY mints the reflection issue. The proposals the
|
|
393
504
|
# reflector files still land in Triage and still require human approve/discard —
|
|
394
|
-
#
|
|
395
|
-
# `arm.issue` resting in `arm.from` (created by the operator); the trigger is
|
|
396
|
-
# inert until that issue exists.
|
|
397
|
-
#
|
|
398
|
-
# MIGRATION: a deprecated top-level `sleep_cycle:` block is still parsed for one
|
|
399
|
-
# release and folded onto states.<reflect_state>.arm (dormant_state -> from,
|
|
400
|
-
# reflect_state -> the armed state, issue_id -> issue, arm_on_idle -> on_idle,
|
|
401
|
-
# arm_after_done -> after_terminal) with a startup deprecation warning. Prefer
|
|
402
|
-
# the per-state `arm:` block.
|
|
505
|
+
# spawning does not bypass the human gate.
|
|
403
506
|
# ----------------------------------------------------------------------------
|
|
404
507
|
|
|
405
508
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -415,8 +518,11 @@ polling:
|
|
|
415
518
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
416
519
|
workspace:
|
|
417
520
|
# root (path): parent directory holding `<issue-id>/` working trees.
|
|
418
|
-
#
|
|
419
|
-
|
|
521
|
+
# An explicit value resolves absolute as-is, `~`-expanded against $HOME, or
|
|
522
|
+
# (relative) against the workflow file's directory.
|
|
523
|
+
# Default (unset): ~/.symphony/workspaces/<project> (same <project> derivation
|
|
524
|
+
# as tracker.root above).
|
|
525
|
+
# root: ~/.symphony/workspaces/my-project
|
|
420
526
|
|
|
421
527
|
# github_repo (string | null): the GitHub `owner/repo` slug symphony pushes the
|
|
422
528
|
# per-issue `agent/<id>` branch to and opens a PR against on the Done-state
|
|
@@ -512,8 +618,11 @@ workspace:
|
|
|
512
618
|
#
|
|
513
619
|
# Console routing: while the file sink is active (the default), the structured
|
|
514
620
|
# stream goes to the file ONLY — the console shows just the startup banner
|
|
515
|
-
# (workflow, tracker root, dashboard URL,
|
|
516
|
-
# file
|
|
621
|
+
# (workflow, tracker root, dashboard URL, MCP endpoint, ACP `/acp` WebSocket
|
|
622
|
+
# endpoint, log-file path). The dashboard/MCP/ACP all share the one HTTP port,
|
|
623
|
+
# which defaults to ephemeral, so the banner is how the operator learns which
|
|
624
|
+
# port got bound. `tail -f` the
|
|
625
|
+
# log file to follow the detail. Pass `--verbose` (alias `--foreground`) to mirror
|
|
517
626
|
# the structured stream back onto the console for interactive debugging. With
|
|
518
627
|
# no file sink configured, the structured stream stays on stderr.
|
|
519
628
|
#
|
|
@@ -523,8 +632,11 @@ workspace:
|
|
|
523
632
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
524
633
|
logs:
|
|
525
634
|
# root (path): directory holding per-issue JSONL files and symphony.log.
|
|
526
|
-
#
|
|
527
|
-
|
|
635
|
+
# An explicit value resolves absolute as-is, `~`-expanded against $HOME, or
|
|
636
|
+
# (relative) against the workflow file's directory.
|
|
637
|
+
# Default (unset): ~/.symphony/logs/<project> (same <project> derivation as
|
|
638
|
+
# tracker.root above) — durable run logs live OUTSIDE the repo tree by default.
|
|
639
|
+
# root: ~/.symphony/logs/my-project
|
|
528
640
|
|
|
529
641
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
530
642
|
# workspace lifecycle — no shell `hooks:` surface.
|
|
@@ -537,7 +649,7 @@ logs:
|
|
|
537
649
|
# branch cut + origin/identity) is owned by the orchestrator's TypeScript
|
|
538
650
|
# `setupWorkspaceDir`. The workspace arrives at the agent with: a hardlinked
|
|
539
651
|
# `git clone --local --no-tags` of the source repo (`SYMPHONY_SOURCE_REPO`,
|
|
540
|
-
# default: the dir containing WORKFLOW.
|
|
652
|
+
# default: the dir containing WORKFLOW.yaml) on the base branch
|
|
541
653
|
# (`SYMPHONY_BASE_BRANCH`, default `main`); all network remotes stripped; an
|
|
542
654
|
# `origin` restored to the canonical HTTPS URL when `workspace.github_repo`
|
|
543
655
|
# (or the `SYMPHONY_REPO` env override) is set (so the Done-state push can
|
|
@@ -622,12 +734,6 @@ acp:
|
|
|
622
734
|
# bearer (in a fake ~/.codex/auth.json); the host substitutes the
|
|
623
735
|
# real OpenAI/ChatGPT token at egress. No real credential — and no
|
|
624
736
|
# real OPENAI_API_KEY — enters the VM.
|
|
625
|
-
# opencode — opencode acp, backed by GitHub Copilot (issue 130). The host
|
|
626
|
-
# exchanges the operator's `opencode auth login` GitHub OAuth token
|
|
627
|
-
# for a short-lived Copilot token host-side and substitutes it at
|
|
628
|
-
# egress — the GitHub token never enters the VM. One Copilot
|
|
629
|
-
# credential unlocks many models (GPT-4o/4.1, Claude Sonnet,
|
|
630
|
-
# Gemini, o-series, …).
|
|
631
737
|
adapter: claude
|
|
632
738
|
|
|
633
739
|
# Credentials never enter the VM (issue 113; codex generalized in 116). The
|
|
@@ -650,17 +756,6 @@ acp:
|
|
|
650
756
|
# so codex-acp runs in its native mode without an in-VM OAuth handshake or
|
|
651
757
|
# refresh (both stay host-side). Every credential-bearing var is stripped from
|
|
652
758
|
# the forwarded VM boot env.
|
|
653
|
-
#
|
|
654
|
-
# For opencode: a staged opencode.json (at /root/.config/opencode/opencode.json)
|
|
655
|
-
# declares a custom @ai-sdk/openai-compatible provider whose baseURL/apiKey read
|
|
656
|
-
# the OPENCODE_PROXY_* env vars (a `gho_`-shaped placeholder bearer). The host
|
|
657
|
-
# reads the durable GitHub OAuth token from ~/.local/share/opencode/auth.json
|
|
658
|
-
# (COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKEN env fallback), exchanges it
|
|
659
|
-
# host-side at api.github.com/copilot_internal/v2/token for a short-lived Copilot
|
|
660
|
-
# token (cached + TTL-refreshed before expiry), injects the Copilot editor
|
|
661
|
-
# headers, and substitutes it at egress to api.githubcopilot.com. The durable
|
|
662
|
-
# GitHub token never enters the VM — so do NOT also list it in
|
|
663
|
-
# `gondolin.forward_env`. See docs/research/opencode-copilot-accept-matrix.md.
|
|
664
759
|
|
|
665
760
|
# model (string | null): optional model selector forwarded to the chosen adapter.
|
|
666
761
|
# Each adapter profile knows how to surface it natively:
|
|
@@ -668,10 +763,6 @@ acp:
|
|
|
668
763
|
# claude-agent-acp would (aliases like "opus", "sonnet", or full IDs
|
|
669
764
|
# like "claude-opus-4-7").
|
|
670
765
|
# codex — passed as `-c model="<value>"` argv to codex-acp (parsed as TOML).
|
|
671
|
-
# opencode— baked into the staged opencode.json as model="symphony-copilot/<value>".
|
|
672
|
-
# Use a Copilot chat-completions model id (e.g. gpt-4o, gpt-4.1,
|
|
673
|
-
# claude-sonnet-4.5, gemini-2.5-pro); codex-class models served only
|
|
674
|
-
# on Copilot's /responses path are NOT reachable. Default: gpt-4o.
|
|
675
766
|
# Leave unset / null to use the adapter's own default model. Default: null.
|
|
676
767
|
# model: claude-opus-4-7
|
|
677
768
|
|
|
@@ -689,7 +780,7 @@ acp:
|
|
|
689
780
|
# Leave unset / null for the adapter's own default. Default: null.
|
|
690
781
|
# effort: xhigh
|
|
691
782
|
|
|
692
|
-
# NOTE: the launch shape is fixed (an in-VM agent dials back
|
|
783
|
+
# NOTE: the launch shape is fixed (an in-VM agent dials back the `/acp` WebSocket
|
|
693
784
|
# and spawns the chosen adapter). Customizing what the agent spawns requires
|
|
694
785
|
# forking that agent and rebuilding the VM image with the fork in place.
|
|
695
786
|
|
|
@@ -709,37 +800,19 @@ acp:
|
|
|
709
800
|
# the turn is killed and retried. Default: 300000
|
|
710
801
|
stall_timeout_ms: 300000
|
|
711
802
|
|
|
712
|
-
#
|
|
713
|
-
#
|
|
714
|
-
#
|
|
715
|
-
#
|
|
716
|
-
#
|
|
717
|
-
#
|
|
718
|
-
#
|
|
719
|
-
#
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
# bind_port (int): port symphony binds the listener on. 0 picks an ephemeral
|
|
727
|
-
# port (used port surfaces via the in-VM SYMPHONY_ACP_URL env var). Default: 8788
|
|
728
|
-
bind_port: 8788
|
|
729
|
-
|
|
730
|
-
# reach_host (string): host the in-VM agent dials back to. Under Gondolin this is
|
|
731
|
-
# 127.0.0.1 because the guest loopback hits the host loopback. Other sandboxes
|
|
732
|
-
# may need a different alias. Default: 127.0.0.1
|
|
733
|
-
reach_host: 127.0.0.1
|
|
734
|
-
|
|
735
|
-
# reach_url (string|null): full URL override for the in-VM agent's dial
|
|
736
|
-
# destination, e.g. through a reverse proxy or different scheme. When null,
|
|
737
|
-
# symphony constructs `tcp://<reach_host>:<bind_port>`. Default: null
|
|
738
|
-
# reach_url: null
|
|
739
|
-
|
|
740
|
-
# connect_timeout_ms (int): how long to wait for the in-VM agent to connect after
|
|
741
|
-
# the sandbox is launched, before failing the attempt. Default: 30000
|
|
742
|
-
connect_timeout_ms: 30000
|
|
803
|
+
# ACP transport — the in-VM agent dials back a `/acp` WebSocket on symphony's unified
|
|
804
|
+
# HTTP server (the SAME listener that serves the dashboard + MCP), reached through the
|
|
805
|
+
# SAME `tcp.hosts` tunnel MCP uses (the guest dials `ws://symphony-mcp:7001/acp`). It
|
|
806
|
+
# authenticates with a per-dispatch bearer sent as the first WebSocket message, then ACP
|
|
807
|
+
# JSON-RPC frames flow as WebSocket frames; the in-VM agent (`/opt/symphony/vm-agent.mjs`)
|
|
808
|
+
# spawns the adapter via `child_process.spawn` with kernel pipes and pumps the frames to
|
|
809
|
+
# the adapter's stdio. There is NO separate ACP listener / bind port — the raw-TCP bridge
|
|
810
|
+
# (`acp.bridge.*`: bind_host/bind_port/reach_host/reach_url) was retired; those keys are
|
|
811
|
+
# ignored if present.
|
|
812
|
+
|
|
813
|
+
# connect_timeout_ms (int): how long to wait for the in-VM agent to dial back the `/acp`
|
|
814
|
+
# WebSocket after the sandbox is launched, before failing the attempt. Default: 30000
|
|
815
|
+
connect_timeout_ms: 30000
|
|
743
816
|
|
|
744
817
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
745
818
|
# credentials — host credential lifecycle (issue 113). The host substitutes the
|
|
@@ -758,20 +831,82 @@ credentials:
|
|
|
758
831
|
# systemd timer instead). Default: 21600000 (6 hours).
|
|
759
832
|
ticker_interval_ms: 21600000
|
|
760
833
|
|
|
834
|
+
# refresh_margin_ms (int): how far ahead of a token's expiry the host refreshes it.
|
|
835
|
+
# Drives BOTH the per-VM proactive tick (scheduled at `expiresAt - margin`) AND the
|
|
836
|
+
# egress request-side lazy refresh (a request bound for a credential host within this
|
|
837
|
+
# margin of expiry awaits a fresh token before going out). Must comfortably cover the
|
|
838
|
+
# refresh round-trip (`claude -p ok` rotate + re-read + fan-out) plus any in-flight long
|
|
839
|
+
# request, or a token expiring mid-dispatch loses the refresh/request race and 401s the
|
|
840
|
+
# egress (issue 214). Default: 300000 (5 minutes).
|
|
841
|
+
refresh_margin_ms: 300000
|
|
842
|
+
|
|
761
843
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
762
844
|
# gondolin — microVM execution environment (Gondolin substrate).
|
|
763
845
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
764
846
|
gondolin:
|
|
765
|
-
# image
|
|
766
|
-
# image
|
|
767
|
-
#
|
|
768
|
-
#
|
|
769
|
-
#
|
|
770
|
-
#
|
|
771
|
-
#
|
|
772
|
-
#
|
|
773
|
-
#
|
|
774
|
-
|
|
847
|
+
# image: the agent rootfs source. THREE forms, in precedence order
|
|
848
|
+
# (image > oci_image > managed):
|
|
849
|
+
#
|
|
850
|
+
# 1. `managed` (the DEFAULT when neither `image` nor `oci_image` is set, and what a
|
|
851
|
+
# fresh scaffold emits): FETCH a prebuilt Gondolin asset published to symphony's
|
|
852
|
+
# OWN GitHub releases for the running symphony version + host arch (issue 224).
|
|
853
|
+
# No docker, no `npm run build:image`, no local convert — onboarding is
|
|
854
|
+
# `scaffold → run`. On the first poll the orchestrator downloads + verifies (against
|
|
855
|
+
# the published `.sha256`) + imports the asset ONCE (the dashboard shows the
|
|
856
|
+
# one-time fetch) and HOLDS VM dispatch until it's ready, then boots the cached
|
|
857
|
+
# asset. Published for x86_64 and arm64/aarch64 (the `release.yml` agent-image
|
|
858
|
+
# matrix); any OTHER arch makes the managed source inert and the doctor FAILs
|
|
859
|
+
# with an unsupported-arch message.
|
|
860
|
+
# Override `SYMPHONY_RELEASE_REPO` to fetch from a fork/staging release.
|
|
861
|
+
#
|
|
862
|
+
# 2. a PRE-CONVERTED asset selector — the low-level escape hatch. Build it ONCE with
|
|
863
|
+
# `npm run build:image` (see images/agents/); the build prints a content-addressed
|
|
864
|
+
# build id (a digest) — pin that here for an immutable reference. A `name:tag` ref
|
|
865
|
+
# (e.g. `symphony-agents:latest`) or a path to an exported asset directory also
|
|
866
|
+
# work. WINS over `oci_image` and the managed source when set.
|
|
867
|
+
#
|
|
868
|
+
# 3. `oci_image` (below): a normal OCI ref symphony auto-converts on first reconcile.
|
|
869
|
+
#
|
|
870
|
+
# The image ships only `mise`; node + the ACP CLIs (claude-agent-acp, codex-acp)
|
|
871
|
+
# are mise-installed at dispatch and the in-VM launcher is staged at
|
|
872
|
+
# /opt/symphony/vm-agent.mjs — so dispatch needs no runtime mounts. Default: managed.
|
|
873
|
+
image: managed
|
|
874
|
+
|
|
875
|
+
# oci_image (string | null): a NORMAL OCI image reference (a docker/podman repo
|
|
876
|
+
# string, optionally `:tag` or `@sha256:…`) that symphony auto-converts + caches into
|
|
877
|
+
# a Gondolin asset as part of the reconcile loop (issue 206) — no manual
|
|
878
|
+
# `npm run build:image` step. On the first poll where the asset isn't cached, the
|
|
879
|
+
# orchestrator converts it ONCE (the dashboard shows a "building microVM image
|
|
880
|
+
# (one-time setup)" banner) and HOLDS VM dispatch until it's ready; the cache key is
|
|
881
|
+
# the resolved OCI digest, re-checked cheaply each reconcile tick (a read-only LOCAL
|
|
882
|
+
# resolve, no pull), so a moving tag whose locally-resolved digest changes (e.g. after
|
|
883
|
+
# a re-pull) reconverts before dispatch resumes — readiness tracks the live digest, not
|
|
884
|
+
# a ref string that converted once. `oci_pull_policy` governs the one-time conversion
|
|
885
|
+
# pull, not this readiness check. Once converted, dispatch boots the cached asset
|
|
886
|
+
# automatically — set ONLY
|
|
887
|
+
# this key and go; you do NOT also need to set `image`. The MVP targets the "golden"
|
|
888
|
+
# path — a published ref that already bakes the guest contract (Node ≥ 21 + the ACP
|
|
889
|
+
# CLIs on PATH; the launcher is staged at dispatch). `image` stays the escape hatch
|
|
890
|
+
# for an asset you converted yourself, and WINS when both are set: when `image` is
|
|
891
|
+
# set the reconcile gate boots IT and the `oci_image` auto-convert path is bypassed
|
|
892
|
+
# entirely — dispatch is never held and no one-time build runs. Default: null.
|
|
893
|
+
# oci_image: ghcr.io/your-org/symphony-agents:1.0.0
|
|
894
|
+
|
|
895
|
+
# oci_pull_policy (if-not-present | always | never): how the OCI image is pulled
|
|
896
|
+
# while resolving its digest for the one-time conversion. `if-not-present` pulls
|
|
897
|
+
# only when the ref isn't already in the local container store; `always` re-pulls
|
|
898
|
+
# even when it IS present locally, so a moving tag (`repo:latest`) picks up its
|
|
899
|
+
# fresh registry digest (and reconverts when that digest changed); `never` never
|
|
900
|
+
# pulls and requires the image to already be in the local store. The cache key and
|
|
901
|
+
# the converted asset are always keyed on the POST-pull digest, so `always` can't
|
|
902
|
+
# cache against a stale local one. Only consulted when `oci_image` is set (and not
|
|
903
|
+
# by the per-tick readiness probe, which is always pull-free). Default: if-not-present.
|
|
904
|
+
# oci_pull_policy: if-not-present
|
|
905
|
+
|
|
906
|
+
# oci_runtime (docker | podman | null): container runtime used for the conversion
|
|
907
|
+
# pull/export. null = auto-detect (prefers docker, falls back to podman). Only
|
|
908
|
+
# consulted when `oci_image` is set. Default: null (auto-detect).
|
|
909
|
+
# oci_runtime: docker
|
|
775
910
|
|
|
776
911
|
# cpus (int): vCPU count per VM. Default: 2.
|
|
777
912
|
cpus: 2
|
|
@@ -779,6 +914,14 @@ gondolin:
|
|
|
779
914
|
# mem_mib (int): RAM per VM in MiB. Default: 2048.
|
|
780
915
|
mem_mib: 4096
|
|
781
916
|
|
|
917
|
+
# rootfs_size (string): guest rootfs virtual-disk size (qemu size syntax, e.g. "3G"),
|
|
918
|
+
# passed to the VM substrate as the MINIMUM rootfs size. The agent toolchain installs
|
|
919
|
+
# onto the guest ROOTFS each dispatch (chmod works there; the sandboxfs bind mount
|
|
920
|
+
# silently drops it — issue 222), so the rootfs must be big enough for the ephemeral
|
|
921
|
+
# install: node alone is ~123 MB plus the agent CLIs, and the default ~593 MB rootfs
|
|
922
|
+
# leaves too little headroom. Default: "3G".
|
|
923
|
+
# rootfs_size: 3G
|
|
924
|
+
|
|
782
925
|
# volumes (list): additional host:guest VFS mounts beyond the auto-mounted
|
|
783
926
|
# workspace. Gondolin's VFS is programmable (no hard per-VM mount cap), but keep
|
|
784
927
|
# this lean — if ANY state sets `eval_mode: true` it adds two read-only mounts
|
|
@@ -800,6 +943,38 @@ gondolin:
|
|
|
800
943
|
- OPENAI_API_KEY
|
|
801
944
|
- ANTHROPIC_API_KEY
|
|
802
945
|
|
|
946
|
+
# mise (jdx/mise) toolchain provisioning. This is ALWAYS ON and is the ONLY toolchain
|
|
947
|
+
# path (issue 233) — there is no enable/disable toggle. The agent image ships ONLY the
|
|
948
|
+
# `mise` binary (+ glibc essentials); node + the agent CLIs (claude-code, codex,
|
|
949
|
+
# claude-agent-acp, codex-acp) come from a mise SYSTEM config symphony
|
|
950
|
+
# STAGES into the guest at /etc/mise/config.toml at dispatch, and a consuming repo's
|
|
951
|
+
# own `mise.toml` / `.tool-versions` (higher precedence) ADDS project toolchains
|
|
952
|
+
# (rust, go, kotlin+gradle, a different node, …) on top. `mise install` runs once
|
|
953
|
+
# per dispatch, installing the toolchain onto the guest ROOTFS at /opt/symphony/mise-data
|
|
954
|
+
# (EPHEMERAL per VM — see below); the agent runtime node is resolved system-scoped via
|
|
955
|
+
# `mise which node` (so a project mise.toml can't downgrade the agent below the Node ≥ 21
|
|
956
|
+
# the launcher needs). Bumping an agent CLI is a one-line edit to
|
|
957
|
+
# assets/symphony-mise.system.toml + a restart — NO image rebuild + digest repin.
|
|
958
|
+
#
|
|
959
|
+
# WHY the rootfs, not a bind mount (issue 222): the gondolin sandboxfs bind mount has no
|
|
960
|
+
# chmod opcode (chmod is a silent no-op there), so mise's create-then-chmod extractor +
|
|
961
|
+
# npm postinstall would produce NON-executable binaries on it; the guest rootfs (ext4)
|
|
962
|
+
# honors chmod, so installs land there executable. Grow it via `gondolin.rootfs_size`
|
|
963
|
+
# (default 3G) so the per-VM install fits. Only the pure downloads (node tarballs + the
|
|
964
|
+
# npm package cache) persist across dispatches, on the bind-mounted `data_dir` below.
|
|
965
|
+
#
|
|
966
|
+
# The only tunable here is `data_dir` (the download cache location).
|
|
967
|
+
mise:
|
|
968
|
+
# data_dir (string): host directory bind-mounted RW → /opt/symphony/mise-cache as the
|
|
969
|
+
# persistent mise DOWNLOAD CACHE (node tarballs + the npm package cache) — NOT the
|
|
970
|
+
# install dir (issue 222): installs need chmod, which the sandboxfs bind mount silently
|
|
971
|
+
# drops, so the toolchain installs onto the ephemeral guest rootfs and only the pure
|
|
972
|
+
# downloads live here (so a cold install isn't re-downloaded every dispatch). SHARED
|
|
973
|
+
# across every VM; host-isolated from your own ~/.local/share/mise. Absolute as-is,
|
|
974
|
+
# `~`/`$VAR`-expanded, relative → resolved against the workflow-file dir.
|
|
975
|
+
# Default: ~/.symphony/mise.
|
|
976
|
+
# data_dir: ~/.symphony/mise
|
|
977
|
+
|
|
803
978
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
804
979
|
# egress — general dev-tooling firewall for the in-VM agent.
|
|
805
980
|
#
|
|
@@ -819,12 +994,23 @@ gondolin:
|
|
|
819
994
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
820
995
|
egress:
|
|
821
996
|
# allowed_hosts (string[]): hostnames the in-VM agent may reach for dev tooling.
|
|
822
|
-
# Default:
|
|
823
|
-
#
|
|
997
|
+
# Default: the mise provisioning hosts [nodejs.org, registry.npmjs.org, mise.jdx.dev,
|
|
998
|
+
# mise-versions.jdx.dev] — ALWAYS, since mise provisioning is unconditional (issue 233)
|
|
999
|
+
# — so `mise install` of the staged SYSTEM config isn't firewall-blocked. Bare
|
|
1000
|
+
# hostnames ONLY — no scheme, port, or path (`github.com`, not
|
|
824
1001
|
# `https://github.com/...`). A malformed entry fails safe (the host simply stays
|
|
825
1002
|
# blocked, never opened). Each entry is matched against the request host exactly.
|
|
1003
|
+
#
|
|
1004
|
+
# An explicit list REPLACES the default — so if you set `allowed_hosts`, re-list all
|
|
1005
|
+
# four mise hosts here alongside your own (omitting mise-versions.jdx.dev re-hits the
|
|
1006
|
+
# cold-cache node@<N> resolution failure issue 223 documents). PROJECT toolchains pull
|
|
1007
|
+
# from their own hosts; add those too (rust → static.rust-lang.org, gradle →
|
|
1008
|
+
# services.gradle.org, JDK → api.adoptium.net, …).
|
|
826
1009
|
allowed_hosts:
|
|
827
|
-
-
|
|
1010
|
+
- nodejs.org # mise node prebuilts
|
|
1011
|
+
- registry.npmjs.org # npm install + mise npm: backend (agent CLIs)
|
|
1012
|
+
- mise.jdx.dev # mise registry redirect
|
|
1013
|
+
- mise-versions.jdx.dev # mise precompiled tool version lists (node@N, etc.)
|
|
828
1014
|
- github.com # git-based deps / release pages
|
|
829
1015
|
- codeload.github.com # GitHub tarball fetch
|
|
830
1016
|
- objects.githubusercontent.com # release-binary downloads
|
|
@@ -833,9 +1019,13 @@ egress:
|
|
|
833
1019
|
# server — HTTP dashboard + MCP endpoint listener.
|
|
834
1020
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
835
1021
|
server:
|
|
836
|
-
# port (int | null):
|
|
837
|
-
#
|
|
838
|
-
port
|
|
1022
|
+
# port (int | null): HTTP listener port. `--port <n>` on the CLI overrides
|
|
1023
|
+
# this. When both are unset symphony binds an ephemeral port (0 → the kernel
|
|
1024
|
+
# picks a free port), so it "just works" with no config and two concurrent
|
|
1025
|
+
# instances never collide; the actually-bound port + dashboard URL are printed
|
|
1026
|
+
# to stdout at startup. Set a value here to pin a fixed port. Default: null
|
|
1027
|
+
# (ephemeral).
|
|
1028
|
+
# port: 8787
|
|
839
1029
|
|
|
840
1030
|
# host (string): bind address. Default: '127.0.0.1'. Bind to '0.0.0.0' only
|
|
841
1031
|
# inside a trusted network boundary; the dashboard has no built-in auth.
|
|
@@ -880,68 +1070,31 @@ mcp:
|
|
|
880
1070
|
# orchestrator through the host gateway (e.g. bridge networking with a
|
|
881
1071
|
# fixed reverse-proxy URL). Default: null.
|
|
882
1072
|
host_url: null
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
this
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
You are picking up a single issue and shepherding it through the workflow.
|
|
913
|
-
|
|
914
|
-
Issue: **{{ issue.identifier }} — {{ issue.title }}**
|
|
915
|
-
State: {{ issue.state }}
|
|
916
|
-
{% if issue.priority -%}Priority: {{ issue.priority }}{%- endif %}
|
|
917
|
-
{% if issue.labels.size > 0 -%}Labels: {% for l in issue.labels %}{{ l }}{% unless forloop.last %}, {% endunless %}{% endfor %}{%- endif %}
|
|
918
|
-
|
|
919
|
-
{% if issue.description -%}
|
|
920
|
-
Description:
|
|
921
|
-
|
|
922
|
-
{{ issue.description }}
|
|
923
|
-
{%- endif %}
|
|
924
|
-
|
|
925
|
-
Goals:
|
|
926
|
-
|
|
927
|
-
1. Work in the current directory only; treat it as the issue workspace.
|
|
928
|
-
2. Make the smallest correct change that satisfies the issue.
|
|
929
|
-
3. Hand off when done. `symphony.transition({ to_state, notes? })` is the
|
|
930
|
-
canonical (and only) exit verb: pass a declared state name and optional
|
|
931
|
-
markdown notes that get appended to the issue body for the next agent.
|
|
932
|
-
For single-agent workflows, transition straight into the first declared
|
|
933
|
-
`role: terminal` state to end the run.
|
|
934
|
-
4. If you cannot proceed without human input, call
|
|
935
|
-
`symphony.request_human_steering({ question, context? })`. Your turn ends
|
|
936
|
-
immediately; the human's reply arrives as your next prompt.
|
|
937
|
-
5. If you notice work out of scope for this issue — unrelated bugs, follow-ups
|
|
938
|
-
a human should size, refactors worth a separate dispatch — call
|
|
939
|
-
`symphony.propose_issue({ title, description?, labels?, priority? })`. It
|
|
940
|
-
lands in the first declared `role: holding` state directory (defaults to
|
|
941
|
-
`Triage/`); the operator approves or discards. Do not graft unrelated
|
|
942
|
-
edits onto this branch.
|
|
943
|
-
|
|
944
|
-
{% if attempt -%}
|
|
945
|
-
This is continuation/retry attempt {{ attempt }}. Inspect the workspace before
|
|
946
|
-
making new edits; your previous run may have left state behind.
|
|
947
|
-
{%- endif %}
|
|
1073
|
+
|
|
1074
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
1075
|
+
# prompts — per-state files (there is NO inline prompt body).
|
|
1076
|
+
#
|
|
1077
|
+
# A workflow file is pure YAML config; it carries no prompt body. Each active
|
|
1078
|
+
# state's prompt is its `states.<name>.prompt_file` (a Liquid template) wrapped
|
|
1079
|
+
# in the shared `prompt.preamble_file` / `prompt.footer_file` (see the `prompt:`
|
|
1080
|
+
# and `states:` sections above). The runner renders the matching state's
|
|
1081
|
+
# assembled template fresh on every dispatch, so each state's agent sees only its
|
|
1082
|
+
# own instructions plus the shared preamble / footer.
|
|
1083
|
+
#
|
|
1084
|
+
# Liquid context available to every prompt file ({ issue, attempt }):
|
|
1085
|
+
# issue.identifier — the issue's external id (e.g. "DEMO-42").
|
|
1086
|
+
# issue.title — issue title (string).
|
|
1087
|
+
# issue.state — current state (string, matches a key in `states:`).
|
|
1088
|
+
# issue.description — body text (string or empty). `symphony.transition`
|
|
1089
|
+
# appends its `notes` block here before the file moves, so
|
|
1090
|
+
# the next state's agent reads the previous state's handoff
|
|
1091
|
+
# message verbatim.
|
|
1092
|
+
# issue.priority — number or null.
|
|
1093
|
+
# issue.labels — list of strings (lowercased).
|
|
1094
|
+
# attempt — int, 1-based attempt counter; absent on first attempt.
|
|
1095
|
+
#
|
|
1096
|
+
# Available Liquid filters: standard Shopify Liquid plus `escape_once`.
|
|
1097
|
+
#
|
|
1098
|
+
# See prompts/ alongside WORKFLOW.yaml in this repo for worked prompt files, and
|
|
1099
|
+
# WORKFLOW.minimal.yaml for the smallest single-state example.
|
|
1100
|
+
# ─────────────────────────────────────────────────────────────────────────────
|