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
package/WORKFLOW.md
DELETED
|
@@ -1,744 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
# WORKFLOW.md — symphony dispatched against smol-symphony itself.
|
|
3
|
-
#
|
|
4
|
-
# Run with:
|
|
5
|
-
#
|
|
6
|
-
# npx symphony WORKFLOW.md
|
|
7
|
-
#
|
|
8
|
-
# The per-issue workspace clones from this repo's `.git` directory and the agent
|
|
9
|
-
# has no network credentials. The remote PR flow is configured in-file via
|
|
10
|
-
# `workspace.github_repo` below (dizk/smol-symphony): on a terminal transition
|
|
11
|
-
# the Done-state actions push the per-issue branch and open a PR. `gh` on the
|
|
12
|
-
# host must be authenticated (`gh auth status` clean); the token never enters
|
|
13
|
-
# the VM.
|
|
14
|
-
#
|
|
15
|
-
# For a fully local setup (branch left in the workspace until cleanup, nothing
|
|
16
|
-
# pushed), set `workspace.github_repo: none`. The SYMPHONY_REPO env var still
|
|
17
|
-
# overrides the in-file value when exported.
|
|
18
|
-
#
|
|
19
|
-
# Every section and option is documented in WORKFLOW.template.md.
|
|
20
|
-
|
|
21
|
-
# Declared workflow states. Drives dispatch eligibility (role: active),
|
|
22
|
-
# terminal cleanup (role: terminal), and the propose_issue landing directory
|
|
23
|
-
# (role: holding). This map is the single source of truth — there are no
|
|
24
|
-
# separate active/terminal lists to keep in sync.
|
|
25
|
-
#
|
|
26
|
-
# Per-state `adapter` / `model` / `max_turns` override the workflow-level
|
|
27
|
-
# `acp.*` and `agent.max_turns` defaults at dispatch time, and `max_concurrent`
|
|
28
|
-
# caps how many agents run at once in this state (the global
|
|
29
|
-
# `agent.max_concurrent_agents` stays the cross-state host ceiling).
|
|
30
|
-
# `allowed_transitions` narrows the targets the agent can pass to
|
|
31
|
-
# `symphony.transition` while operating in this state (omit for "any declared
|
|
32
|
-
# state is reachable").
|
|
33
|
-
states:
|
|
34
|
-
Todo:
|
|
35
|
-
role: active
|
|
36
|
-
adapter: claude
|
|
37
|
-
# Opus 4.8, 1M-context variant. The plain `claude-opus-4-7` is the 200K
|
|
38
|
-
# variant — a γ-class refactor dispatch hit two mid-turn compactions before
|
|
39
|
-
# reaching the edit phase; `[1m]` gives ~30x headroom and removes the stall.
|
|
40
|
-
# The suffix is Claude Code's model-selection convention, forwarded to the
|
|
41
|
-
# adapter via ANTHROPIC_MODEL. Review stays on codex (cross-model review).
|
|
42
|
-
model: claude-opus-4-8[1m]
|
|
43
|
-
max_turns: 10
|
|
44
|
-
# Per-state concurrency cap (issue 137): at most one implementer agent at a
|
|
45
|
-
# time. Lives on the state now, symmetric with max_turns; the global
|
|
46
|
-
# `agent.max_concurrent_agents` below remains the cross-state host ceiling.
|
|
47
|
-
max_concurrent: 1
|
|
48
|
-
Review:
|
|
49
|
-
# Codex picks up the implementer's branch and approves or rejects. On
|
|
50
|
-
# approval it transitions the issue to Done with PR-body notes; on
|
|
51
|
-
# rejection it transitions back to Todo with rework instructions.
|
|
52
|
-
role: active
|
|
53
|
-
adapter: codex
|
|
54
|
-
# codex-acp accepts the model via `-c model="..."` argv (TOML); see
|
|
55
|
-
# src/agent/adapters.ts. `gpt-5-codex` was historically rejected with the
|
|
56
|
-
# ChatGPT-account user, so leave `model` unset and let codex-acp pick its
|
|
57
|
-
# own default code-review model. Operators with an API-key Codex setup can
|
|
58
|
-
# pin a specific model here once that's known-good.
|
|
59
|
-
max_turns: 6
|
|
60
|
-
allowed_transitions: [Todo, Done]
|
|
61
|
-
Reflect:
|
|
62
|
-
# Sleep cycle (issue 122). A single recurring "Sleep cycle" issue rests in
|
|
63
|
-
# Dormant; the operator — or an external cron / `symphony reflect` verb —
|
|
64
|
-
# arms a cycle by moving it into Reflect. eval_mode binds the read-only
|
|
65
|
-
# /symphony/issues (all state dirs, including the Done/*.md handoff
|
|
66
|
-
# transcripts) and /symphony/logs (per-issue JSONL run logs) mounts so the
|
|
67
|
-
# agent can mine finished work for *recurring* harness friction, distil
|
|
68
|
-
# lessons, and file improvement proposals via propose_issue (which land in
|
|
69
|
-
# Triage — the human gate). It reflects on *how symphony runs work*
|
|
70
|
-
# (WORKFLOW.md prompt branches, per-state model/max_turns/effort/actions,
|
|
71
|
-
# the gondolin image config, acceptance criteria, timeouts), NOT the product code under
|
|
72
|
-
# review. After filing it transitions to Dormant and waits to be re-armed.
|
|
73
|
-
# See the Reflect prompt branch (the `when "Reflect"` case in the body) for
|
|
74
|
-
# the read → distil → propose loop and the guardrails. Cadence: the operator
|
|
75
|
-
# / an external cron / a `mv` on disk can still arm a cycle, and the
|
|
76
|
-
# orchestrator now also auto-arms Dormant → Reflect on idle or after N
|
|
77
|
-
# terminal transitions (issue 140 — see this state's `arm:` block below).
|
|
78
|
-
role: active
|
|
79
|
-
adapter: claude
|
|
80
|
-
# 1M-context Opus: a reflection turn reads many Done/*.md transcripts plus
|
|
81
|
-
# the relevant logs/<id>.jsonl, so the large-context variant avoids mid-turn
|
|
82
|
-
# compaction (same rationale as the Todo state).
|
|
83
|
-
model: claude-opus-4-8[1m]
|
|
84
|
-
# Higher than Todo/Review: reading the history, distilling patterns, and
|
|
85
|
-
# filing one proposal per lesson takes more turns than a single edit/review.
|
|
86
|
-
max_turns: 20
|
|
87
|
-
# Bind the read-only /symphony/issues + /symphony/logs mounts for this state.
|
|
88
|
-
eval_mode: true
|
|
89
|
-
# The reflector may ONLY go dormant — it cannot route itself into
|
|
90
|
-
# Todo/Review/Done. A guardrail on this self-modifying loop; filing
|
|
91
|
-
# improvements happens through propose_issue (→ Triage), which is
|
|
92
|
-
# independent of allowed_transitions.
|
|
93
|
-
allowed_transitions: [Dormant]
|
|
94
|
-
# Auto-arm trigger (issue 140; replaces the former top-level auto-arm block).
|
|
95
|
-
# This active state arms itself: the orchestrator moves `arm.issue` out of
|
|
96
|
-
# its `arm.from` holding state (Dormant) into Reflect automatically —
|
|
97
|
-
# `on_idle` when the orchestrator is idle and >=1 issue reached a terminal
|
|
98
|
-
# state since the last run, and `after_terminal` as a backstop once that many
|
|
99
|
-
# issues have reached a terminal state since the last run. The
|
|
100
|
-
# terminal-transition counter resets to 0 the moment the issue is armed.
|
|
101
|
-
# GUARDRAILS (carried over from issue 122): auto-arming ONLY moves the issue
|
|
102
|
-
# into Reflect — the proposals it files still land in Triage and still require
|
|
103
|
-
# human approve/discard, so this does not bypass the human gate. Requires a
|
|
104
|
-
# single `sleep-cycle` issue resting in Dormant.
|
|
105
|
-
arm:
|
|
106
|
-
issue: sleep-cycle
|
|
107
|
-
from: Dormant
|
|
108
|
-
on_idle: true
|
|
109
|
-
after_terminal: 10
|
|
110
|
-
Done:
|
|
111
|
-
role: terminal
|
|
112
|
-
# PR autopilot routing (issue 38; moved onto the state in issue 139). Done
|
|
113
|
-
# is the merge state: a MERGEABLE Done-state PR has GitHub auto-merge armed
|
|
114
|
-
# with `squash` (matches the repo's `NN: title (#PR)` history); a
|
|
115
|
-
# CONFLICTING one is routed back to `on_conflict.route_to` (Todo) for the
|
|
116
|
-
# dispatched agent to rebase. The host-global on/off switch + poll TTL live
|
|
117
|
-
# in the top-level `pr:` block below; the merge/close/route targets are
|
|
118
|
-
# derived by scanning states for this `pr:` field (no named-string sibling
|
|
119
|
-
# block). While the engine is enabled, transitions into Done no longer fire
|
|
120
|
-
# the standard terminal workspace cleanup — the pr resource owns the
|
|
121
|
-
# workspace until its PR merges or closes.
|
|
122
|
-
pr:
|
|
123
|
-
auto_merge: squash
|
|
124
|
-
on_conflict:
|
|
125
|
-
route_to: Todo
|
|
126
|
-
# Issue 36 (reconciler v2 / typed action DAG): the legacy `after_run`
|
|
127
|
-
# shell that pushed the branch and opened a PR is replaced by two typed
|
|
128
|
-
# actions. The host pre-stages SYMPHONY_PR_TITLE / SYMPHONY_PR_BODY_FILE /
|
|
129
|
-
# SYMPHONY_BRANCH (the same values the old shell read); the action
|
|
130
|
-
# executor exposes them as $pr_title / $pr_body_file / $branch /
|
|
131
|
-
# $base_branch / $repo in the fixed template namespace
|
|
132
|
-
# (src/actions/types.ts → ActionContext). The `if: $repo` predicate
|
|
133
|
-
# matches the old `[ -n "${SYMPHONY_REPO:-}" ] || exit 0` short-circuit
|
|
134
|
-
# so the local-only mode is still a no-op. Per-action retry/snapshot
|
|
135
|
-
# plumbing replaces the opaque shell-exit-code surface; on rate-limit
|
|
136
|
-
# the create_pr_if_missing action shows "retrying in 60s" on the
|
|
137
|
-
# dashboard instead of a silent failure.
|
|
138
|
-
actions:
|
|
139
|
-
- kind: push_branch
|
|
140
|
-
name: push-branch
|
|
141
|
-
remote: origin
|
|
142
|
-
ref: $branch
|
|
143
|
-
if: $repo
|
|
144
|
-
- kind: create_pr_if_missing
|
|
145
|
-
name: open-pr
|
|
146
|
-
base: $base_branch
|
|
147
|
-
head: $branch
|
|
148
|
-
title_from: $pr_title
|
|
149
|
-
body_from: $pr_body_file
|
|
150
|
-
if: $repo
|
|
151
|
-
Cancelled:
|
|
152
|
-
role: terminal
|
|
153
|
-
# Cancelled means the work was abandoned; no patch, no PR. The workspace is
|
|
154
|
-
# cleaned up after the run unwinds and the commits are discarded with it.
|
|
155
|
-
# PR autopilot close state (issue 139): when the engine is enabled, an open
|
|
156
|
-
# PR for a Cancelled issue is closed without merge and its remote branch is
|
|
157
|
-
# best-effort-deleted. Unlike the merge state, the close path needs no
|
|
158
|
-
# workspace, so standard terminal cleanup still runs on transition in.
|
|
159
|
-
pr:
|
|
160
|
-
close: true
|
|
161
|
-
Triage:
|
|
162
|
-
# Landing directory for `symphony.propose_issue`. Never dispatched; the
|
|
163
|
-
# operator approves or discards from the dashboard. Declared FIRST among
|
|
164
|
-
# holding states so it stays the `propose_issue` landing + triage target
|
|
165
|
-
# (both resolve the first declared holding state).
|
|
166
|
-
role: holding
|
|
167
|
-
Dormant:
|
|
168
|
-
# Resting place for the recurring "Sleep cycle" issue (issue 122) between
|
|
169
|
-
# reflection runs. Holding → never dispatched. A reflection cycle re-arms by
|
|
170
|
-
# moving the issue from Dormant back into Reflect: the orchestrator's
|
|
171
|
-
# `states.Reflect.arm` auto-arm (issue 140) does this on idle / after N
|
|
172
|
-
# terminal transitions, and an external cron, a `symphony reflect` verb, or
|
|
173
|
-
# `mv` on disk still work too. NOTE: the dashboard currently
|
|
174
|
-
# renders triage approve/discard buttons on every holding row and the
|
|
175
|
-
# tracker resolves a move by issue id regardless of source directory, so
|
|
176
|
-
# clicking those buttons on a Dormant issue would mis-route it — re-arm via
|
|
177
|
-
# cron/CLI/filesystem, not the dashboard buttons. A follow-up restricts
|
|
178
|
-
# those buttons to the triage-landing state.
|
|
179
|
-
role: holding
|
|
180
|
-
|
|
181
|
-
tracker:
|
|
182
|
-
kind: local
|
|
183
|
-
# Operator-scoped tracker root (outside the repo). State transitions and
|
|
184
|
-
# propose_issue writes don't dirty the codebase's git status. Symphony
|
|
185
|
-
# auto-mkdirs every declared state directory under this root on startup.
|
|
186
|
-
root: ~/.symphony/trackers/smol-symphony
|
|
187
|
-
|
|
188
|
-
# PR autopilot engine toggle (issue 38, simplified by issue 101; routing moved
|
|
189
|
-
# onto states in issue 139). This is the slim host-global half only — the
|
|
190
|
-
# on/off switch and the per-PR `gh pr view` cache TTL. The merge/close/route
|
|
191
|
-
# targets and the auto-merge strategy now live ON the states they describe:
|
|
192
|
-
# `states.Done.pr` (merge state — auto_merge + on_conflict.route_to) and
|
|
193
|
-
# `states.Cancelled.pr` (close state — close: true), above. The reconciler
|
|
194
|
-
# derives those by scanning states; there is no named-string sibling block.
|
|
195
|
-
#
|
|
196
|
-
# Enabled 2026-05-25 so MERGEABLE Done-state PRs have GitHub auto-merge armed
|
|
197
|
-
# and CONFLICTING ones are routed back to Todo for the dispatched agent to
|
|
198
|
-
# rebase (the host runs `git fetch origin <base>` before each dispatch so
|
|
199
|
-
# `origin/<base>` is current, and the Todo prompt's first step is
|
|
200
|
-
# `git rebase origin/<base>`). There is no autopilot-side rebase machinery and
|
|
201
|
-
# no consecutive-failure circuit breaker.
|
|
202
|
-
#
|
|
203
|
-
# PREREQUISITE: `gh pr merge --auto` requires at least one branch-protection
|
|
204
|
-
# rule on `main`, or arming auto-merge errors. Ensure one exists in the repo's
|
|
205
|
-
# GitHub settings. To disable, set `enabled: false` (the resource is then never
|
|
206
|
-
# constructed and Done-state behavior reverts to the actions-block PR-create +
|
|
207
|
-
# operator merge).
|
|
208
|
-
pr:
|
|
209
|
-
enabled: true
|
|
210
|
-
poll_interval_ms: 30000
|
|
211
|
-
|
|
212
|
-
polling:
|
|
213
|
-
interval_ms: 5000
|
|
214
|
-
|
|
215
|
-
# The canonical clone + base-branch checkout + `agent/<id>` branch cut +
|
|
216
|
-
# origin/identity setup is owned by the orchestrator's TypeScript
|
|
217
|
-
# `setupWorkspaceDir` action (issue 34 / reconciler stage 3) — there is no
|
|
218
|
-
# shell `hooks:` surface. The per-issue workspace arrives at the dispatched
|
|
219
|
-
# agent with:
|
|
220
|
-
#
|
|
221
|
-
# • a hardlinked `git clone --local` of the source repo on the base branch
|
|
222
|
-
# (`workspace.base_branch`, or the SYMPHONY_BASE_BRANCH env override,
|
|
223
|
-
# default `main`) at the source repo's current local base SHA
|
|
224
|
-
# • all network remotes stripped (in-VM `git push`/`git fetch` fail closed)
|
|
225
|
-
# • when `workspace.github_repo` (or the SYMPHONY_REPO env override) is set:
|
|
226
|
-
# `origin` restored to the canonical HTTPS URL so the host's Done-state
|
|
227
|
-
# `push_branch` action can push (`gh auth setup-git` runs best-effort on the
|
|
228
|
-
# host so the push has credentials; the token never enters the VM)
|
|
229
|
-
# • `user.name = symphony-agent` / `user.email = agent@symphony.local`
|
|
230
|
-
# • `agent/<id>` checked out
|
|
231
|
-
#
|
|
232
|
-
# The source repo's local `<base>` is the single source of truth for the
|
|
233
|
-
# workspace's base ref. To pick up a new base, update the source repo
|
|
234
|
-
# (`git pull` / `git fetch && git checkout <base>`) before the next dispatch;
|
|
235
|
-
# symphony does not implicitly fetch from `origin/<base>` at setup time.
|
|
236
|
-
#
|
|
237
|
-
# Need extra per-VM tooling on top of that? Bake it into the agent image
|
|
238
|
-
# (`images/agents/`), or run arbitrary guest commands from a state's `actions:`
|
|
239
|
-
# via `run_in_vm`. The post-attempt push + PR-create handoff is the Done
|
|
240
|
-
# state's `actions:` block above.
|
|
241
|
-
workspace:
|
|
242
|
-
root: ./.symphony/workspaces
|
|
243
|
-
# PR/push target for the dogfood (symphony-on-symphony) setup: the Done-state
|
|
244
|
-
# actions push the per-issue branch + open a PR against this repo. Set to
|
|
245
|
-
# `none` for local-only (branch left in the workspace). The SYMPHONY_REPO env
|
|
246
|
-
# var still overrides this if exported.
|
|
247
|
-
github_repo: dizk/smol-symphony
|
|
248
|
-
# Branch the per-issue workspace clones from + targets as the PR base. The
|
|
249
|
-
# SYMPHONY_BASE_BRANCH env var still overrides this if exported.
|
|
250
|
-
base_branch: main
|
|
251
|
-
|
|
252
|
-
# Per-issue JSONL run logs plus an orchestrator-side `symphony.log` mirror.
|
|
253
|
-
# One JSONL file per issue, appended across attempts and process restarts;
|
|
254
|
-
# captures every ACP JSON-RPC frame to/from the VM, raw adapter stderr,
|
|
255
|
-
# typed-action output, and orchestrator lifecycle events — intended for
|
|
256
|
-
# later evaluation by another agent. The sibling `symphony.log` captures the
|
|
257
|
-
# orchestrator's structured log (dispatch, actions, reconciler, shutdown) in the
|
|
258
|
-
# same `key=value` format so a post-hoc review has both surfaces in one
|
|
259
|
-
# directory. While the file sink is active the console shows only the startup
|
|
260
|
-
# banner; `tail -f symphony.log` follows the detail, and `--verbose` mirrors it
|
|
261
|
-
# back to the console. See WORKFLOW.template.md for the full schema.
|
|
262
|
-
logs:
|
|
263
|
-
root: ./.symphony/logs
|
|
264
|
-
|
|
265
|
-
agent:
|
|
266
|
-
# SERIALIZED to 1 (2026-05-27) to stop the FC/IS burn-down conflict storm:
|
|
267
|
-
# every burn-down PR edits the same policy files (package.json --max-warnings
|
|
268
|
-
# ratchet, .dependency-cruiser.cjs, eslint.config.js), so any two in flight
|
|
269
|
-
# conflict by construction. Serial dispatch makes each PR rebase on the prior
|
|
270
|
-
# merge. Revert to 2 once the arch-burndown queue drains.
|
|
271
|
-
max_concurrent_agents: 1
|
|
272
|
-
max_turns: 6
|
|
273
|
-
max_retry_backoff_ms: 120000
|
|
274
|
-
|
|
275
|
-
acp:
|
|
276
|
-
# Selecting "claude" is enough: symphony probes ~/.claude/.credentials.json
|
|
277
|
-
# on the host at startup and auto-generates a launch command for the in-VM
|
|
278
|
-
# agent. There is no `command` escape hatch under the TCP bridge transport —
|
|
279
|
-
# the launch shape is fixed; fork scripts/vm-agent.mjs if you need to customize
|
|
280
|
-
# what the agent spawns.
|
|
281
|
-
adapter: claude
|
|
282
|
-
# Credentials never enter the VM (issue 113; codex generalized in 116). The
|
|
283
|
-
# guest holds only a token-shaped placeholder; the host substitutes the real
|
|
284
|
-
# upstream credential into the outbound request at Gondolin egress (TLS-MITM):
|
|
285
|
-
# for claude, the Anthropic OAuth access token; for codex (the Review state's
|
|
286
|
-
# adapter), the OpenAI credential read from ~/.codex/auth.json (access token or
|
|
287
|
-
# OPENAI_API_KEY, never the refresh token). Every credential-bearing var is
|
|
288
|
-
# stripped from the forwarded VM boot env, so no real credential lands in the VM.
|
|
289
|
-
# Reasoning effort forwarded to claude-agent-acp via a staged settings.json
|
|
290
|
-
# (`{"effortLevel": "xhigh"}`) copied into /root/.claude/settings.json before the
|
|
291
|
-
# adapter starts. xhigh is the second-highest tier under Opus 4.7 (max is the top
|
|
292
|
-
# but is meaningfully slower); operators on a Haiku-backed model must drop this
|
|
293
|
-
# because Haiku rejects xhigh at adapter startup. Valid set is `low|medium|high|xhigh|max`,
|
|
294
|
-
# model-gated by claude-agent-acp's `supportedEffortLevels`.
|
|
295
|
-
effort: xhigh
|
|
296
|
-
shell: bash
|
|
297
|
-
# Hard cap on a single session/prompt regardless of activity. Raised from 30min to
|
|
298
|
-
# 60min (the code default) because a heavy refactor turn at effort=xhigh can run a
|
|
299
|
-
# single uninterrupted turn past 30min — issue 103's healthy attempt was killed
|
|
300
|
-
# mid-edit at the old 1800000 cap with turns_completed:0. Distinct from
|
|
301
|
-
# stall_timeout_ms below (which only trips on NO activity).
|
|
302
|
-
prompt_timeout_ms: 3600000
|
|
303
|
-
read_timeout_ms: 30000
|
|
304
|
-
# ACP TCP bridge. Symphony binds a listener on `bridge.bind_host:bind_port`; the in-VM
|
|
305
|
-
# agent (`/opt/symphony/vm-agent.mjs`) dials `bridge.reach_host:bind_port` on startup
|
|
306
|
-
# and authenticates with a per-dispatch bearer token. This replaced the earlier
|
|
307
|
-
# in-VM-exec stdio path so symphony is not coupled to any particular sandbox's quirks.
|
|
308
|
-
bridge:
|
|
309
|
-
bind_host: 0.0.0.0
|
|
310
|
-
bind_port: 8788
|
|
311
|
-
reach_host: 127.0.0.1
|
|
312
|
-
# Time between any ACP event from the adapter before symphony kills the attempt as stalled.
|
|
313
|
-
# Raised from the 5-minute default because Opus 4.7 at effort=xhigh can take many minutes to
|
|
314
|
-
# produce its first thought chunk on a heavy prompt. If a real wedge happens, attempts will
|
|
315
|
-
# die at this longer threshold; if the agent is just thinking, we let it finish.
|
|
316
|
-
stall_timeout_ms: 1800000
|
|
317
|
-
|
|
318
|
-
gondolin:
|
|
319
|
-
# Per-issue microVM (Gondolin substrate). `image` is the agent rootfs the VM
|
|
320
|
-
# boots, built ONCE with `npm run build:image` (see images/agents/) — not baked
|
|
321
|
-
# per issue. The value is a Gondolin image selector: the content-addressed build
|
|
322
|
-
# id printed by the build (pinned below for reproducibility), a `name:tag` ref
|
|
323
|
-
# like `symphony-agents:latest`, or a path to an exported asset directory.
|
|
324
|
-
image: cb875342-03ef-56e0-9306-dde8628aa17d
|
|
325
|
-
cpus: 2
|
|
326
|
-
mem_mib: 4096
|
|
327
|
-
# No runtime bind-mounts. The in-VM launcher (/opt/symphony/vm-agent.mjs) is
|
|
328
|
-
# baked into the image, so it needs no per-dispatch mount. Keeping `volumes`
|
|
329
|
-
# empty leaves room for an eval_mode state's two read-only mounts (/symphony/issues
|
|
330
|
-
# + /symphony/logs) on top of the auto-mounted workspace. Credentials never
|
|
331
|
-
# mount: the host substitutes the real token at Gondolin egress; the tracker is
|
|
332
|
-
# reached via the symphony MCP server (or the eval_mode mount).
|
|
333
|
-
volumes: []
|
|
334
|
-
# forward_env is a generic passthrough into the VM boot env, but the runner
|
|
335
|
-
# strips EVERY credential-bearing var before boot (the guest holds only a
|
|
336
|
-
# placeholder Gondolin substitutes at egress) — so listing OPENAI_API_KEY here
|
|
337
|
-
# does NOT plant the real key in a VM.
|
|
338
|
-
forward_env:
|
|
339
|
-
- OPENAI_API_KEY
|
|
340
|
-
- ANTHROPIC_API_KEY
|
|
341
|
-
|
|
342
|
-
egress:
|
|
343
|
-
# General dev-tooling firewall for the in-VM agent. Gondolin denies guest egress
|
|
344
|
-
# by default; the agent can always reach its own inference host (handled by the
|
|
345
|
-
# credential layer), and these hosts are additionally opened so gates can run
|
|
346
|
-
# (`npm install`, git-based deps, release binaries). SECURITY: nothing here ever
|
|
347
|
-
# gets a real token substituted — listing a host grants plain network egress
|
|
348
|
-
# only. The real upstream token is substituted solely on each adapter's inference
|
|
349
|
-
# host (see src/agent/credential-secrets.ts).
|
|
350
|
-
allowed_hosts:
|
|
351
|
-
- registry.npmjs.org # npm install
|
|
352
|
-
- github.com # git-based deps / release pages
|
|
353
|
-
- codeload.github.com # GitHub tarball fetch
|
|
354
|
-
- objects.githubusercontent.com # release-binary downloads
|
|
355
|
-
|
|
356
|
-
server:
|
|
357
|
-
port: 8787
|
|
358
|
-
# Bound to all interfaces because access is gated by tailscale, not by the
|
|
359
|
-
# HTTP server itself. The endpoint has no auth; only expose it inside a
|
|
360
|
-
# trusted network boundary.
|
|
361
|
-
host: 0.0.0.0
|
|
362
|
-
|
|
363
|
-
mcp:
|
|
364
|
-
# Gondolin maps a synthetic guest host to the host's loopback (`tcp.hosts`), so
|
|
365
|
-
# 127.0.0.1 from inside the VM hits the host's listener. Override only if
|
|
366
|
-
# your VMM has a different host alias.
|
|
367
|
-
host: 127.0.0.1
|
|
368
|
-
---
|
|
369
|
-
You are working on **smol-symphony**, a TypeScript orchestrator that dispatches
|
|
370
|
-
coding agents into per-issue Gondolin microVMs and talks to them over the Agent
|
|
371
|
-
Client Protocol (ACP). Your workspace is a fresh clone of this repo.
|
|
372
|
-
|
|
373
|
-
Issue: **{{ issue.identifier }} — {{ issue.title }}**
|
|
374
|
-
State: {{ issue.state }}
|
|
375
|
-
{% if issue.priority -%}Priority: {{ issue.priority }}{%- endif %}
|
|
376
|
-
{% if issue.labels.size > 0 -%}Labels: {% for l in issue.labels %}{{ l }}{% unless forloop.last %}, {% endunless %}{% endfor %}{%- endif %}
|
|
377
|
-
|
|
378
|
-
{% if issue.description -%}
|
|
379
|
-
Description:
|
|
380
|
-
|
|
381
|
-
{{ issue.description }}
|
|
382
|
-
{%- endif %}
|
|
383
|
-
|
|
384
|
-
Orientation:
|
|
385
|
-
|
|
386
|
-
- This is the smol-symphony codebase. Start by reading `README.md` and
|
|
387
|
-
`PRODUCT.md` if you haven't seen them. `SPEC.md` is the long-form design
|
|
388
|
-
spec. `CLAUDE.md` (if present) has any standing instructions for this repo.
|
|
389
|
-
- Source lives under `src/`. Tests live under `tests/`. Before declaring work
|
|
390
|
-
done, run `npm run typecheck`, `npm test`, `npm run lint:arch` (import
|
|
391
|
-
direction + hexagonal layering: domain must reach infra only through injected
|
|
392
|
-
ports), and `npm run lint` (functional-core purity + imperative-shell
|
|
393
|
-
complexity budgets); all must pass.
|
|
394
|
-
- You are on a per-issue branch (`agent/{{ issue.identifier }}`) checked out
|
|
395
|
-
from the configured base branch. Commit your work locally. You do **not**
|
|
396
|
-
have network credentials; pushing is the host's job, after the issue lands
|
|
397
|
-
in a terminal state.
|
|
398
|
-
- Symphony's active states are **Todo** (you, implementing), **Review**
|
|
399
|
-
(Codex, reviewing), and **Reflect** (the sleep-cycle reflection turn that
|
|
400
|
-
mines finished work for harness improvements). Read the per-state
|
|
401
|
-
instructions below.
|
|
402
|
-
- **Work as a single agent — do not fan out.** Do NOT invoke the `Workflow`
|
|
403
|
-
tool or spawn nested / parallel sub-agents, even if the task looks like it
|
|
404
|
-
would benefit from multi-agent orchestration. (The word "workflow" and the
|
|
405
|
-
`WORKFLOW.md` filename here name symphony's state machine — they are *not* an
|
|
406
|
-
opt-in to multi-agent fan-out.) A fan-out turn holds one streaming request
|
|
407
|
-
open for many minutes and hits an upstream connection-reset ceiling (~16 min)
|
|
408
|
-
inside the sandbox; the turn is then discarded and the issue re-dispatched
|
|
409
|
-
from scratch (this looped issue 135 eight times). Keep each turn focused and
|
|
410
|
-
sequential, and rely on `max_turns` for breadth instead.
|
|
411
|
-
|
|
412
|
-
{% case issue.state %}
|
|
413
|
-
{% when "Todo" %}
|
|
414
|
-
You are the **implementer**. Your job: turn the issue into a working change on
|
|
415
|
-
the per-issue branch, then hand off to the reviewer.
|
|
416
|
-
|
|
417
|
-
1. **Rebase onto a fresh base first.** Symphony has just fetched
|
|
418
|
-
`origin/main` into your workspace (or whatever base branch
|
|
419
|
-
`SYMPHONY_BASE_BRANCH` names — `main` is the default and matches this
|
|
420
|
-
project). The very first thing to do is rebase your branch onto it:
|
|
421
|
-
|
|
422
|
-
```
|
|
423
|
-
git rebase origin/main
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
- On a fresh issue this is a no-op (you're already on top of base).
|
|
427
|
-
- On a re-dispatch where base has advanced this picks up the new commits.
|
|
428
|
-
- If `git rebase` reports conflicts, **resolve them in-tree as part of
|
|
429
|
-
this turn** (reconcile your change with what landed on base), `git add`
|
|
430
|
-
the resolved files, and `git rebase --continue` (repeat per replayed
|
|
431
|
-
commit). Then proceed to step 2. There is no separate conflict state
|
|
432
|
-
to route to — handling the conflict is part of normal implementation
|
|
433
|
-
work, just like any other rebase you'd do on your own machine.
|
|
434
|
-
2. Read enough of the codebase to understand the change you need to make.
|
|
435
|
-
3. Decide where the change belongs before writing it. The orchestrator
|
|
436
|
-
(`src/agent/runner.ts`, `src/mcp.ts`, `src/orchestrator.ts`) owns the
|
|
437
|
-
state machine and the tracker. Repo-local glue (`git push`, `gh pr
|
|
438
|
-
create`, rescuing artifacts) lives in a state's typed `actions:` block
|
|
439
|
-
(or, for arbitrary guest commands, a `run_in_vm` action); workspace
|
|
440
|
-
setup is the orchestrator's `setupWorkspaceDir`, and per-VM tooling is
|
|
441
|
-
baked into the agent image. State-machine behavior (new transitions,
|
|
442
|
-
anything that mutates tracker files or runtime entry state) belongs in
|
|
443
|
-
the orchestrator with typed APIs and tests — not in an action. If you
|
|
444
|
-
find yourself adding a `SYMPHONY_*` env var so an action can reach into
|
|
445
|
-
orchestrator state, or writing an action that the runner then has to
|
|
446
|
-
re-detect via a post-action scan, that is the signal you are on the wrong
|
|
447
|
-
side of the seam: stop and put the logic in the runner/MCP layer
|
|
448
|
-
instead. The issue body may sketch a shell-shaped solution; treat that
|
|
449
|
-
as one option, not a directive.
|
|
450
|
-
4. Make the smallest correct change for the issue's stated scope, and keep it
|
|
451
|
-
focused. If you notice work beyond what the issue states, call
|
|
452
|
-
`symphony.propose_issue` for it rather than expanding this change to swallow
|
|
453
|
-
follow-up work. Add or update tests where the change is testable. Before
|
|
454
|
-
handing off, run `npm run typecheck`, `npm test`, `npm run lint:arch`, and
|
|
455
|
-
`npm run lint` — all must pass. `node_modules` may be absent on dispatch;
|
|
456
|
-
if you `npm install` to run those gates, the image's npm can rewrite
|
|
457
|
-
`package-lock.json` (e.g. bumping the root package `engines.node` from
|
|
458
|
-
`>=20` to `>=23.6.0`). That drift is unrelated to your change — before
|
|
459
|
-
handing off, run `git status` and `git checkout -- package-lock.json` to
|
|
460
|
-
drop any incidental lockfile churn you did not intend. The handoff tree
|
|
461
|
-
must be clean.
|
|
462
|
-
**Do NOT edit the `--max-warnings` ratchet in `package.json`** — leave that line
|
|
463
|
-
exactly as-is. It is tightened in one pass at the end of the burn-down. Your change
|
|
464
|
-
only needs to keep `npm run lint` green at the *current* ratchet (it will, as long
|
|
465
|
-
as you reduce or hold the warning count). Lowering it yourself just collides with
|
|
466
|
-
every other in-flight issue's `package.json` and forces manual conflict resolution.
|
|
467
|
-
5. Commit your work to the per-issue branch with a short message.
|
|
468
|
-
6. **Re-read the issue's Acceptance criteria and confirm your diff satisfies
|
|
469
|
-
every bullet before handing off.** An acceptance bullet you've left unmet —
|
|
470
|
-
because closing it would touch a path outside the stated `allowed_paths`, or
|
|
471
|
-
because you'd rather defer it to a `symphony.propose_issue` follow-up — means
|
|
472
|
-
the issue is **not done**. `allowed_paths` describes where the change
|
|
473
|
-
*normally* lands; it is not license to hand off an unmet acceptance bullet.
|
|
474
|
-
Satisfy the criterion (touch the extra path and say why in your notes — the
|
|
475
|
-
way you would for a required `CHANGELOG.md` edit), and do **not**
|
|
476
|
-
`symphony.propose_issue` work the acceptance criteria require of *this*
|
|
477
|
-
issue. If a criterion genuinely cannot be met within scope (it conflicts
|
|
478
|
-
with another constraint, or needs a decision only a human can make), call
|
|
479
|
-
`symphony.request_human_steering` rather than handing off a partial change
|
|
480
|
-
with the gap described in the notes. (If satisfying a bullet here means new
|
|
481
|
-
edits, re-run the gates from step 4 and amend your commit before handing
|
|
482
|
-
off.)
|
|
483
|
-
7. Hand off to the reviewer by calling:
|
|
484
|
-
|
|
485
|
-
```
|
|
486
|
-
symphony.transition({
|
|
487
|
-
to_state: "Review",
|
|
488
|
-
notes: "# <imperative-voice title, ≤72 chars>\n\n<one- to three-paragraph
|
|
489
|
-
summary of what you changed, why, files touched, and tests added>"
|
|
490
|
-
})
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
The notes describe **this change**. Out-of-scope items you noticed —
|
|
494
|
-
unrelated bugs, refactors, follow-ups, a future ticket someone should
|
|
495
|
-
size — go through `symphony.propose_issue` (see the shared section below).
|
|
496
|
-
Do not park them in a "Follow-ups not done" section in the notes; that
|
|
497
|
-
surface dies in `Done/<id>.md` and no agent ever sees it again.
|
|
498
|
-
|
|
499
|
-
Don't include a verification section restating that
|
|
500
|
-
`npm run typecheck` / `npm test` / `npm run build` passed — that's an
|
|
501
|
-
AGENTS.md requirement and the reviewer re-runs them. Mention test count
|
|
502
|
-
or extra commands only when something is atypical (test count dropped,
|
|
503
|
-
you ran a smoke against a live service, etc.).
|
|
504
|
-
|
|
505
|
-
The notes block is appended to the issue body **before** the file moves to
|
|
506
|
-
`Review/`, so the reviewer sees it as part of `issue.description` on the
|
|
507
|
-
next dispatch. Write it as if it were the PR body — because if the reviewer
|
|
508
|
-
approves, the entire issue body (including this block) becomes the PR
|
|
509
|
-
description. Then end your turn; do not call any further tools.
|
|
510
|
-
|
|
511
|
-
{% when "Review" %}
|
|
512
|
-
You are the **reviewer**. The implementer has committed work to the per-issue
|
|
513
|
-
branch (`agent/{{ issue.identifier }}`) and handed off. Their summary is in
|
|
514
|
-
the issue description above. Your job: decide whether the work is correct and
|
|
515
|
-
either approve (→ Done) or send it back (→ Todo) with specific findings.
|
|
516
|
-
|
|
517
|
-
1. Read the implementer's notes in the issue description carefully — title,
|
|
518
|
-
summary, files claimed touched. (Follow-ups belong in `propose_issue`,
|
|
519
|
-
not the notes; if you see a "Follow-ups not done" section in the notes,
|
|
520
|
-
reject and ask the implementer to file each item as a separate
|
|
521
|
-
`propose_issue` call instead.)
|
|
522
|
-
2. Inspect the diff against the freshly-fetched base. The host fetched
|
|
523
|
-
`origin/main` (or whatever base branch `SYMPHONY_BASE_BRANCH` names — `main`
|
|
524
|
-
is the default here) into this workspace before the dispatch, and the
|
|
525
|
-
implementer rebased onto it, so `origin/main` is the true base:
|
|
526
|
-
|
|
527
|
-
```
|
|
528
|
-
git log --oneline origin/main..HEAD
|
|
529
|
-
git diff origin/main..HEAD
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
Diff against `origin/main`, **not** the local `main` ref: your workspace's
|
|
533
|
-
local `main` is frozen at clone time and goes **stale** as sibling PRs merge
|
|
534
|
-
— `origin/main` advances but local `main` does not. Diffing `main..HEAD` then
|
|
535
|
-
surfaces commits already on base as if they were the implementer's change,
|
|
536
|
-
and can make a correctly-based branch look like it *reverts* recently-landed
|
|
537
|
-
work. (Local-only mode — no `origin` remote — has no such drift, so `main`
|
|
538
|
-
stays the correct base there.) If `HEAD`'s merge-base is behind `origin/main`
|
|
539
|
-
(e.g. `git merge-tree --write-tree HEAD origin/main` reports conflicts),
|
|
540
|
-
reject to `Todo` asking the implementer to rebase onto `origin/main` — don't
|
|
541
|
-
agonize over an apparent revert.
|
|
542
|
-
|
|
543
|
-
Look at each file the implementer claimed to touch. Spot-check tests and
|
|
544
|
-
typecheck pass:
|
|
545
|
-
|
|
546
|
-
```
|
|
547
|
-
npm run typecheck
|
|
548
|
-
npm test
|
|
549
|
-
```
|
|
550
|
-
|
|
551
|
-
3. Placement check — is the change on the right side of the seam?
|
|
552
|
-
|
|
553
|
-
The orchestrator (`src/agent/runner.ts`, `src/mcp.ts`, `src/orchestrator.ts`)
|
|
554
|
-
owns the state machine and tracker. Repo-local glue (`git push`, `gh pr
|
|
555
|
-
create`, rescuing artifacts) lives in a state's typed `actions:` block
|
|
556
|
-
(or a `run_in_vm` action for arbitrary guest commands). Reject when the
|
|
557
|
-
diff crosses that line:
|
|
558
|
-
|
|
559
|
-
- An action implements a new state transition, or mutates the tracker
|
|
560
|
-
filesystem the orchestrator owns (e.g. `mv issues/<state>/<id>.md
|
|
561
|
-
issues/<other-state>/<id>.md`).
|
|
562
|
-
- An action mutates runtime state the orchestrator committed earlier (e.g.
|
|
563
|
-
undoing a cleanup flag) and the runner now has to re-detect what the
|
|
564
|
-
action did via a post-action scan.
|
|
565
|
-
- A new `SYMPHONY_*` env var is added so an action can reach into
|
|
566
|
-
orchestrator-owned state. The contract is growing because the logic is
|
|
567
|
-
on the wrong side; surface it as a typed call in the runner/MCP layer
|
|
568
|
-
instead.
|
|
569
|
-
|
|
570
|
-
If any of the above fires, reject with a pointer to the right home
|
|
571
|
-
(runner, MCP tool, or orchestrator). Action-only diffs that stay within
|
|
572
|
-
repo-local glue (push/PR/format-patch) are fine — this check is
|
|
573
|
-
about state-machine logic leaking into a state's `actions:`.
|
|
574
|
-
|
|
575
|
-
4. Decide:
|
|
576
|
-
|
|
577
|
-
- **Approve**: the change is correct, tests pass, no blocking issues. Call
|
|
578
|
-
|
|
579
|
-
```
|
|
580
|
-
symphony.transition({
|
|
581
|
-
to_state: "Done",
|
|
582
|
-
notes: "<approval rationale; this becomes the PR body>"
|
|
583
|
-
})
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
Your notes are appended to the issue body and feed straight into the PR
|
|
587
|
-
description the host opens against the base branch. Be specific about
|
|
588
|
-
what you verified.
|
|
589
|
-
|
|
590
|
-
- **Reject**: the change is wrong, incomplete, or has issues that need
|
|
591
|
-
rework. Call
|
|
592
|
-
|
|
593
|
-
```
|
|
594
|
-
symphony.transition({
|
|
595
|
-
to_state: "Todo",
|
|
596
|
-
notes: "<specific findings: file paths, line numbers, what's wrong,
|
|
597
|
-
what needs to change. Be concrete — the implementer will see
|
|
598
|
-
this as their next prompt.>"
|
|
599
|
-
})
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
The issue goes back to Todo with your findings appended. The same
|
|
603
|
-
workspace and `agent/{{ issue.identifier }}` branch survive the round
|
|
604
|
-
trip, so the next implementer dispatch sees both your notes and their
|
|
605
|
-
prior commits.
|
|
606
|
-
|
|
607
|
-
Either way, end your turn after the transition call. Do not call any
|
|
608
|
-
further tools.
|
|
609
|
-
|
|
610
|
-
{% when "Reflect" %}
|
|
611
|
-
You are the **reflector** running symphony's *sleep cycle*. You are not
|
|
612
|
-
implementing or reviewing a product change. Your job: mine symphony's own
|
|
613
|
-
finished work for *recurring* friction in **how it runs work**, distil concrete
|
|
614
|
-
lessons, and file one harness-improvement proposal per lesson into Triage —
|
|
615
|
-
where a human operator decides whether to adopt it. Then go dormant.
|
|
616
|
-
|
|
617
|
-
This is a self-modifying loop: you read agent-authored transcripts and then
|
|
618
|
-
propose changes to *your own* operating instructions. The guardrails below are
|
|
619
|
-
load-bearing — follow them exactly.
|
|
620
|
-
|
|
621
|
-
**What you can read** (read-only mounts present only in this state):
|
|
622
|
-
|
|
623
|
-
- `/symphony/issues/` — every issue file across every state directory. The
|
|
624
|
-
richest signal is `/symphony/issues/Done/*.md`: each file is the full handoff
|
|
625
|
-
thread (every `symphony.transition` notes block from implementer → reviewer →
|
|
626
|
-
approval is appended to the body), so a Done file shows how the work actually
|
|
627
|
-
went, not just the final result. `Triage/`, `Cancelled/`, and the active
|
|
628
|
-
state dirs are visible too.
|
|
629
|
-
- `/symphony/logs/<id>.jsonl` — the per-issue run log: every ACP frame, adapter
|
|
630
|
-
stderr line, typed-action output, and orchestrator lifecycle event for that issue.
|
|
631
|
-
This is where stalls, turn-budget exhaustion, retries, and timeouts show up
|
|
632
|
-
in detail.
|
|
633
|
-
- Your workspace is a clone of the symphony repo, so you can read `WORKFLOW.md`,
|
|
634
|
-
`WORKFLOW.template.md`, `src/`, `images/agents/`, etc. to ground each proposal
|
|
635
|
-
in the concrete knob it would change.
|
|
636
|
-
|
|
637
|
-
If structured per-issue run summaries exist (companion issue #123), start from
|
|
638
|
-
those as an index; otherwise skim `Done/*.md` and open the
|
|
639
|
-
`/symphony/logs/<id>.jsonl` for the issues that look anomalous.
|
|
640
|
-
|
|
641
|
-
**What to look for — *recurring* patterns, not one-offs.** One bad run is
|
|
642
|
-
noise; the same failure shape across several issues is signal. For example:
|
|
643
|
-
|
|
644
|
-
- repeated `Review → Todo` rejects with the same root cause (the reviewer keeps
|
|
645
|
-
catching the same class of mistake the implementer prompt doesn't prevent);
|
|
646
|
-
- turn-budget exhaustion (a state hits `max_turns` before it can transition);
|
|
647
|
-
- stalls / timeouts (`stall_timeout_ms` / `prompt_timeout_ms` trips);
|
|
648
|
-
- rebase / merge-conflict churn on re-dispatch;
|
|
649
|
-
- credential re-login loops;
|
|
650
|
-
- acceptance-criteria misses a sharper prompt or checklist would have caught;
|
|
651
|
-
- prompt ambiguity that forced `request_human_steering`.
|
|
652
|
-
|
|
653
|
-
**For each distilled lesson, file exactly one `symphony.propose_issue` call**
|
|
654
|
-
(one per fix — never batch multiple fixes into one proposal; Triage is
|
|
655
|
-
per-item). Each proposal must:
|
|
656
|
-
|
|
657
|
-
- name a single concrete change to the **harness / operating config**: a
|
|
658
|
-
`WORKFLOW.md` prompt branch, a per-state `model` / `max_turns` /
|
|
659
|
-
`allowed_transitions` / `effort` / `actions`, the `gondolin` image config, an
|
|
660
|
-
acceptance criterion, or a timeout;
|
|
661
|
-
- include a **before → after** (what the config/prompt says now, what you'd
|
|
662
|
-
change it to);
|
|
663
|
-
- cite the **evidence** — the issue ids (and, where useful, the log lines or
|
|
664
|
-
Done-file quotes) that motivated it — so the operator can check the lesson
|
|
665
|
-
against the trajectories rather than trusting your summary.
|
|
666
|
-
|
|
667
|
-
**Hard guardrails — a proposal that violates any of these must NOT be filed:**
|
|
668
|
-
|
|
669
|
-
- Propose changes to the **harness only** — `WORKFLOW.md` /
|
|
670
|
-
`WORKFLOW.template.md`, per-state config (including `actions:`), the `gondolin`
|
|
671
|
-
image config, acceptance criteria, timeouts. Do **not** propose edits to product/source code under
|
|
672
|
-
`src/` as a "fix" for a trajectory; if a genuine product bug is the root
|
|
673
|
-
cause, that is an ordinary `propose_issue` for an implementer, not a harness
|
|
674
|
-
change, and you should frame it that way.
|
|
675
|
-
- Never propose anything that **weakens a quality gate.** Do not weaken or
|
|
676
|
-
remove the Review state, the `npm run typecheck` / `npm test` /
|
|
677
|
-
`npm run lint:arch` / `npm run lint` gates, or the Triage human-approval gate
|
|
678
|
-
itself. The whole point of this loop is that a human stays in it; proposals
|
|
679
|
-
that would let the loop dispatch its own changes without review are
|
|
680
|
-
forbidden, even if the trajectories seem to "justify" them.
|
|
681
|
-
- One fix per proposal, each with cited evidence. No proposal without issue ids.
|
|
682
|
-
|
|
683
|
-
When you have filed your proposals — or concluded there is no recurring pattern
|
|
684
|
-
worth acting on this cycle — hand off by going dormant:
|
|
685
|
-
|
|
686
|
-
```
|
|
687
|
-
symphony.transition({
|
|
688
|
-
to_state: "Dormant",
|
|
689
|
-
notes: "<one-paragraph log of this cycle: how many issues you reviewed, the
|
|
690
|
-
patterns you found, and the proposal titles you filed (or 'no
|
|
691
|
-
actionable pattern this cycle')>"
|
|
692
|
-
})
|
|
693
|
-
```
|
|
694
|
-
|
|
695
|
-
Then end your turn; do not call any further tools. A later cadence (operator,
|
|
696
|
-
cron, or `symphony reflect`) re-arms you by moving the issue back into Reflect.
|
|
697
|
-
|
|
698
|
-
{% else %}
|
|
699
|
-
This state (`{{ issue.state }}`) does not have a state-specific prompt yet in
|
|
700
|
-
this pipeline. Re-read the issue body for instructions; if you can't infer
|
|
701
|
-
what to do safely, call `symphony.request_human_steering` rather than guessing.
|
|
702
|
-
{% endcase %}
|
|
703
|
-
|
|
704
|
-
If you genuinely cannot proceed — ambiguous requirements, missing context that
|
|
705
|
-
only a human can supply, a design decision that needs human input — call
|
|
706
|
-
`symphony.request_human_steering({ question, context })` instead of guessing.
|
|
707
|
-
Your turn will end immediately and the human's response will arrive as your
|
|
708
|
-
next prompt.
|
|
709
|
-
|
|
710
|
-
Steering tips:
|
|
711
|
-
|
|
712
|
-
- The operator's dashboard already shows the original issue title and body
|
|
713
|
-
alongside your question. Do **not** restate or paraphrase the issue body in
|
|
714
|
-
`question`; ask the specific thing you need answered.
|
|
715
|
-
- Use `context` for facts the operator wouldn't otherwise see: what you've
|
|
716
|
-
inspected, what you've already tried, what constraint is forcing the
|
|
717
|
-
question.
|
|
718
|
-
|
|
719
|
-
If during your work you notice something worth fixing that is **out of scope**
|
|
720
|
-
for your current task — an unrelated bug, a follow-up the operator should
|
|
721
|
-
size, a refactor a future agent could pick up — call
|
|
722
|
-
`symphony.propose_issue({ title, description?, labels?, priority? })`. The
|
|
723
|
-
proposal lands in a Triage state directory that the orchestrator does **not**
|
|
724
|
-
dispatch; the operator approves or discards it from the dashboard. Your
|
|
725
|
-
current issue is automatically recorded as the proposal's parent — do not
|
|
726
|
-
paste it into the body. Use this instead of grafting unrelated changes onto
|
|
727
|
-
your current task; keep your branch focused.
|
|
728
|
-
|
|
729
|
-
File **one `propose_issue` call per follow-up**, not a batched call with
|
|
730
|
-
multiple items in one body. Triage is per-item triage; the operator's
|
|
731
|
-
approve/discard verb is per-issue, so a batched proposal forces an
|
|
732
|
-
all-or-nothing decision and loses the individual sizing/priority each
|
|
733
|
-
follow-up deserves. The "Follow-ups not done" pattern of writing a bulleted
|
|
734
|
-
list in the handoff notes is the wrong surface — those notes ride into the
|
|
735
|
-
PR and then die in `Done/<id>.md`; only `propose_issue` puts the items in
|
|
736
|
-
front of the operator on the dashboard.
|
|
737
|
-
|
|
738
|
-
{% if attempt -%}
|
|
739
|
-
This is continuation/retry attempt {{ attempt }}. Inspect the workspace before
|
|
740
|
-
making new edits; your previous run may have left commits on the branch. Check
|
|
741
|
-
`git log agent/{{ issue.identifier }}` to see what's there. If the work is
|
|
742
|
-
already complete in the current state, call `symphony.transition` with the
|
|
743
|
-
appropriate next state and notes summarising what was already done, then stop.
|
|
744
|
-
{%- endif %}
|