akm-cli 0.9.30 → 0.10.261001-beta
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/CHANGELOG.md +438 -0
- package/README.md +10 -10
- package/ROADMAP.md +112 -0
- package/STABILITY.md +99 -57
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +15 -29
- package/dist/assets/hints/cli-hints-short.md +2 -2
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/feedback-cli.js +75 -49
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/chunking.js +3 -10
- package/dist/commands/improve/consolidate/continuity-check.js +4 -4
- package/dist/commands/improve/consolidate/pair-pass.js +29 -10
- package/dist/commands/improve/consolidate.js +10 -65
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +148 -21
- package/dist/commands/improve/eligibility.js +14 -1
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/extract-prompt.js +17 -7
- package/dist/commands/improve/extract.js +5 -7
- package/dist/commands/improve/improve-cli.js +125 -118
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/improve.js +134 -52
- package/dist/commands/improve/loop-stages.js +18 -5
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +29 -34
- package/dist/commands/improve/retrieval-queries.js +37 -0
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/session-asset.js +4 -1
- package/dist/commands/improve/stage.js +23 -12
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +43 -6
- package/dist/commands/proposal/proposal-cli.js +11 -31
- package/dist/commands/proposal/repository.js +20 -14
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +6 -14
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +10 -63
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +12 -7
- package/dist/core/improve-result.js +13 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/paths.js +4 -0
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/run-lock.js +1 -1
- package/dist/core/subprocess.js +49 -0
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/indexer.js +15 -6
- package/dist/indexer/passes/memory-inference.js +15 -6
- package/dist/indexer/search/db-search.js +49 -36
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/indexer/search/ranking.js +29 -1
- package/dist/indexer/usage/usage-events.js +21 -16
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +74 -14
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15769 -16731
- package/dist/scripts/akm-migrate.js +16339 -17297
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/sources/providers/git-stash.js +94 -13
- package/dist/storage/repositories/index-utility-repository.js +2 -32
- package/dist/storage/repositories/index-vec-repository.js +4 -0
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/run-command-task.js +9 -1
- package/dist/tasks/run/run-workflow-task.js +4 -3
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/run/task-log.js +38 -1
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +43 -42
- package/docs/agents/README.md +15 -0
- package/docs/agents/agent-install.md +14 -0
- package/docs/architecture/0.10-process-rules.md +827 -0
- package/docs/architecture/README.md +67 -0
- package/docs/architecture/adapters.md +258 -0
- package/docs/architecture/akm-architecture-decision-history.md +2055 -0
- package/docs/architecture/akm-core-principles.md +126 -0
- package/docs/architecture/architecture.md +578 -0
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +550 -0
- package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +72 -0
- package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +142 -0
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +189 -0
- package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +97 -0
- package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +108 -0
- package/docs/architecture/decisions/0006-task-source-version-routing.md +124 -0
- package/docs/architecture/decisions/0007-workflow-composition-bounds.md +83 -0
- package/docs/architecture/decisions/0008-task-binding-normalization.md +88 -0
- package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +80 -0
- package/docs/architecture/decisions/0010-driver-protocol-cut.md +36 -0
- package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +125 -0
- package/docs/architecture/decisions/README.md +62 -0
- package/docs/architecture/improvement.md +479 -0
- package/docs/architecture/internals/classification.md +154 -0
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +40 -0
- package/docs/architecture/internals/functional-contract-patterns.md +340 -0
- package/docs/architecture/internals/health-advisories.md +110 -0
- package/docs/architecture/internals/improve-workflow.md +719 -0
- package/docs/architecture/internals/indexing.md +498 -0
- package/docs/architecture/internals/registry-network-boundary.md +57 -0
- package/docs/architecture/internals/search.md +248 -0
- package/docs/architecture/internals/storage-locations.md +943 -0
- package/docs/architecture/persisted-data-compat.md +68 -0
- package/docs/architecture/reviews/env-secret-access.md +319 -0
- package/docs/architecture/runtime-boundary-design.md +153 -0
- package/docs/architecture/specs/0.9.0-close-out-plan.md +361 -0
- package/docs/architecture/specs/0.9.0-decisions.md +532 -0
- package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +745 -0
- package/docs/architecture/specs/0.9.0-open-items-register.md +135 -0
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +740 -0
- package/docs/architecture/specs/0.9.0-release-surface-review.md +636 -0
- package/docs/architecture/specs/agent-command-engine-model-design.md +513 -0
- package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +501 -0
- package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +291 -0
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +2059 -0
- package/docs/architecture/specs/di-seams-plan.md +539 -0
- package/docs/architecture/specs/driver-protocol-keep-or-cut.md +275 -0
- package/docs/architecture/specs/fact-asset-type.md +142 -0
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +634 -0
- package/docs/architecture/specs/okf-support.md +148 -0
- package/docs/architecture/specs/ref.md +329 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/README.md +72 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +152 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +352 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +300 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +402 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +758 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +645 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +602 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +74 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +15 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +132 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +147 -0
- package/docs/architecture/specs/stash-conventions-code-spec.md +275 -0
- package/docs/architecture/specs/stash-organization-conventions.md +377 -0
- package/docs/architecture/specs/task-workflow-format-unification.md +721 -0
- package/docs/architecture/specs/workflow-engine-buy-vs-build.md +231 -0
- package/docs/architecture/specs/workflow-format-unification.md +432 -0
- package/docs/architecture/testing/manual-testing-checklist.md +3411 -0
- package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +924 -0
- package/docs/architecture/testing/task-workflow-manual-tests.md +1720 -0
- package/docs/architecture/testing/testing-workflow.md +446 -0
- package/docs/architecture/workflow-engine.md +223 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/author-bundles.md +310 -0
- package/docs/guides/author-workflows.md +490 -0
- package/docs/guides/bundles.md +323 -0
- package/docs/guides/capture-knowledge.md +136 -0
- package/docs/guides/claude-code-vs-akm-workflows.md +29 -0
- package/docs/guides/concepts.md +93 -0
- package/docs/guides/discover-and-load.md +158 -0
- package/docs/guides/getting-started.md +240 -0
- package/docs/guides/improve-the-library.md +247 -0
- package/docs/guides/knowledge-management.md +18 -0
- package/docs/guides/recipes/headless-install.md +97 -0
- package/docs/guides/recipes/website-source.md +28 -0
- package/docs/guides/run-workflows.md +279 -0
- package/docs/guides/scheduling.md +131 -0
- package/docs/guides/use-with-any-agent.md +174 -0
- package/docs/guides/wikis.md +81 -0
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/README.md +19 -0
- package/docs/maintainers/curate-workmap.md +335 -0
- package/docs/maintainers/eval.md +3 -0
- package/docs/maintainers/local-development.md +108 -0
- package/docs/maintainers/release-checklist.md +135 -0
- package/docs/migration/README.md +4 -2
- package/docs/migration/release-notes/0.0.13.md +1 -1
- package/docs/migration/release-notes/0.1.0.md +1 -1
- package/docs/migration/release-notes/0.10.0.md +201 -0
- package/docs/migration/release-notes/0.2.0.md +1 -1
- package/docs/migration/release-notes/0.3.0.md +1 -1
- package/docs/migration/release-notes/0.5.0.md +1 -1
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.3.md +2 -2
- package/docs/migration/release-notes/0.7.4.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +1 -1
- package/docs/migration/release-notes/0.8.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +1 -1
- package/docs/migration/release-notes/0.9.14.md +1 -1
- package/docs/migration/release-notes/0.9.15.md +1 -1
- package/docs/migration/release-notes/0.9.16.md +1 -1
- package/docs/migration/release-notes/0.9.17.md +1 -1
- package/docs/migration/release-notes/0.9.19.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +1 -1
- package/docs/migration/release-notes/README.md +28 -31
- package/docs/migration/v0.5-to-v0.6.md +759 -0
- package/docs/migration/v0.8-to-v0.9.md +1 -1
- package/docs/migration/v0.9-to-v0.10.md +507 -0
- package/docs/plans/0.9.2-agent-command-workflow-plan.md +423 -0
- package/docs/posts/README.md +30 -0
- package/docs/posts/akm-command-tour.md +495 -0
- package/docs/posts/akm-logo-sized.webp +0 -0
- package/docs/posts/belief-aware-memory-12.md +139 -0
- package/docs/posts/config-v2-lessons-16.md +191 -0
- package/docs/posts/improve-loop-autonomous-10.md +225 -0
- package/docs/posts/improve-pipeline-debugging-0803.md +179 -0
- package/docs/posts/intro-part-01.md +76 -0
- package/docs/posts/intro-part-02.md +221 -0
- package/docs/posts/intro-part-03.md +190 -0
- package/docs/posts/intro-part-04.md +221 -0
- package/docs/posts/llm-mode-reflect-13.md +166 -0
- package/docs/posts/openpalm-built-on-akm.md +86 -0
- package/docs/posts/progressive-disclosure-06.md +129 -0
- package/docs/posts/proposal-safety-net-15.md +112 -0
- package/docs/posts/release-0.5.0.md +247 -0
- package/docs/posts/release-0.6.0.md +117 -0
- package/docs/posts/release-0.7.0.md +159 -0
- package/docs/posts/release-0.8.0.md +332 -0
- package/docs/posts/scattered-skills-05.md +100 -0
- package/docs/posts/task-assets-persistent-workflows-11.md +222 -0
- package/docs/posts/team-skills-07.md +198 -0
- package/docs/posts/wiki-agent-knowledge-08.md +223 -0
- package/docs/posts/workflows-vaults-09.md +321 -0
- package/docs/product-surface.md +54 -0
- package/docs/reference/README.md +2 -2
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +166 -0
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +163 -192
- package/docs/reference/configuration.md +101 -20
- package/docs/reference/data-and-telemetry.md +2 -2
- package/docs/reference/env-and-secrets.md +126 -0
- package/docs/reference/memory.md +124 -0
- package/docs/reference/refs.md +156 -0
- package/docs/reference/registry.md +489 -0
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +141 -0
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +23 -16
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/improve/retrieval-gate.js +0 -132
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/indexer/feedback/utility-policy.js +0 -75
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- package/dist/workflows/runtime/run-outputs.js +0 -80
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Workflow Engine: Buy vs Build
|
|
2
|
+
|
|
3
|
+
Status: DECISION RECORD — A/B investigation complete, recommendation stated
|
|
4
|
+
Date: 2026-08-01
|
|
5
|
+
Question: can a third-party library offload the maintenance burden of akm's
|
|
6
|
+
hand-rolled workflow/task engine?
|
|
7
|
+
Constraints (owner): no server; markdown authoring preserved (simple
|
|
8
|
+
JSON/YAML acceptable only if markdown becomes cumbersome).
|
|
9
|
+
Evidence: [the review corpus](./reviews/task-workflow-unification/README.md) — see its
|
|
10
|
+
library-evaluation section
|
|
11
|
+
Companion: [`task-workflow-format-unification.md`](./task-workflow-format-unification.md)
|
|
12
|
+
(Design A's authoring/config layer, independently reviewed across five rounds)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 0. Answer
|
|
17
|
+
|
|
18
|
+
**Build — keep the engine.** Not for lack of a good library: OpenWorkflow is
|
|
19
|
+
genuinely well-built and empirically durable. The blocker is that the thing
|
|
20
|
+
being "offloaded" is mostly not there. Measured against the actual tree,
|
|
21
|
+
**~7% of `src/workflows/exec` + `ir` is the generic durable-execution
|
|
22
|
+
concern these libraries sell**; the other ~93% is akm's product and would
|
|
23
|
+
survive adoption unchanged — while adoption *subtracts* capabilities the
|
|
24
|
+
engine has today.
|
|
25
|
+
|
|
26
|
+
Take the dependency **below** the engine instead, and cut scope **above**
|
|
27
|
+
it (§7). That is where the maintenance burden actually is.
|
|
28
|
+
|
|
29
|
+
## 1. Method
|
|
30
|
+
|
|
31
|
+
Three independent Opus investigations, all forbidden from relying on
|
|
32
|
+
training knowledge — every claim verified against live artifacts:
|
|
33
|
+
|
|
34
|
+
| Investigation | Scope | Report |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| bunqueue | Full rubric + source read | [`library-eval-bunqueue.md`](./reviews/task-workflow-unification/library-eval-bunqueue.md) |
|
|
37
|
+
| OpenWorkflow | Full rubric + **executed** (SIGKILL durability probe, schema-collision repro) | [`library-eval-openworkflow.md`](./reviews/task-workflow-unification/library-eval-openworkflow.md) |
|
|
38
|
+
| Landscape | 25+ candidates against the hard constraints | [`library-eval-alternatives.md`](./reviews/task-workflow-unification/library-eval-alternatives.md) |
|
|
39
|
+
|
|
40
|
+
Rubric derived from what the engine demonstrably does (established across
|
|
41
|
+
the five review rounds behind the companion spec): embedded in a
|
|
42
|
+
short-lived CLI process; crash-resume from `state.db`; completed-unit reuse
|
|
43
|
+
keyed on **content hashes**; map fan-out with concurrency caps and
|
|
44
|
+
reducers; minutes-long units with leases and stall recovery; judged gate
|
|
45
|
+
loops; and the `brief`/`report` driver protocol.
|
|
46
|
+
|
|
47
|
+
## 2. The decisive measurement
|
|
48
|
+
|
|
49
|
+
`src/workflows/exec` + `src/workflows/ir` = **8,705 LOC**. Composition:
|
|
50
|
+
|
|
51
|
+
| Component | LOC | Would a library replace it? |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `brief.ts` + `report.ts` — external-driver protocol | **2,690 (31%)** | No — no library has an analogue |
|
|
54
|
+
| `ir/` — schema, compile, freeze, plan hash, params | 1,635 | No — determinism/replay identity is akm's contract |
|
|
55
|
+
| Dispatch, gates, worktrees, step-work | ~3,750 | No — agent/LLM dispatch, judged gates, redaction |
|
|
56
|
+
| Journal/resume/lease/concurrency plumbing | **~630 (7%)** | **Yes — this is the addressable surface** |
|
|
57
|
+
|
|
58
|
+
Rows sum to 8,705. The plumbing row is a *region* count, not a file-level
|
|
59
|
+
partition — no whole-file split yields it (the only fully generic files are
|
|
60
|
+
`scheduler.ts` 118 + `unit-writer.ts` 29). The defensible band is ~490–720,
|
|
61
|
+
depending on whether the journal-row rehydration helpers and the gate
|
|
62
|
+
resume seed count as plumbing or as product; the conclusion is unchanged
|
|
63
|
+
anywhere in that band.
|
|
64
|
+
|
|
65
|
+
For calibration, the generic concurrency concern is `src/core/concurrent.ts`
|
|
66
|
+
(40) + `src/workflows/concurrency-policy.ts` (20) = **60 lines** — both of
|
|
67
|
+
which sit *outside* the 8,705.
|
|
68
|
+
|
|
69
|
+
A dependency that replaces 7% while adding an integration seam, a schema
|
|
70
|
+
bridge, and a pre-1.0 upstream is not a burden transfer. It is a burden
|
|
71
|
+
trade at unfavourable odds.
|
|
72
|
+
|
|
73
|
+
## 3. Candidate results
|
|
74
|
+
|
|
75
|
+
| | bunqueue | OpenWorkflow | Weft | Mastra | XState v5 |
|
|
76
|
+
|---|---|---|---|---|---|
|
|
77
|
+
| License | MIT | Apache-2.0 | MIT | Apache-2.0 | MIT |
|
|
78
|
+
| Server-free | ⚠ single-process only | ✅ | ⚠ single-engine only | ✅ | ✅ |
|
|
79
|
+
| SQLite durability + resume | ⚠ name-keyed | ✅ *(SIGKILL-verified)* | ✅ | ⚠ snapshot, no lease | ❌ |
|
|
80
|
+
| Bounded fan-out + reducer | ❌ | ❌ *(issue #20, 9mo)* | ⚠ | ✅ | ⚠ |
|
|
81
|
+
| Error-classified retry | ❌ | ❌ | ⚠ | ⚠ | ⚠ |
|
|
82
|
+
| Per-step timeout / cancel | ⚠ 30s default | ❌ *(no AbortSignal)* | ⚠ | ✅ | ✅ |
|
|
83
|
+
| Windows CI | ❌ | ❌ | ✅ target | ⚠ | ✅ |
|
|
84
|
+
| Bus factor | 1 | 1 | 1 | team | team |
|
|
85
|
+
| **% of exec+ir deletable** | **0–3%** | **8–12%** | ~6% | 10–15% | 4–6% |
|
|
86
|
+
|
|
87
|
+
**Eliminated on the no-server constraint** (one line each in the landscape
|
|
88
|
+
report): Temporal, Inngest, Trigger.dev, Hatchet, Windmill, n8n, Restate,
|
|
89
|
+
Conductor, Camunda/Zeebe, Dapr, Azure Durable Functions, AWS durable
|
|
90
|
+
execution, Convex, Cloudflare Workflows, Vercel Workflow DevKit, Upstash,
|
|
91
|
+
Obelisk, HotMesh, Resonate. **On storage**: BullMQ (Redis), pg-boss/Absurd
|
|
92
|
+
(Postgres), Agenda (Mongo), SideQuest (LGPL — license). **Not
|
|
93
|
+
orchestrators**: bree, croner, better-queue, p-queue, `@deepkit/workflow`,
|
|
94
|
+
liteflow. **Dead**: workflow-es (2022, `inversify@^4`).
|
|
95
|
+
|
|
96
|
+
Three verifications that overturned plausible assumptions:
|
|
97
|
+
|
|
98
|
+
- **DBOS Transact TS is still Postgres-only.** The tarball for
|
|
99
|
+
`@dbos-inc/dbos-sdk@4.25.14` (2026-07-30) contains zero SQLite files;
|
|
100
|
+
only `pg` and `postgresql://`. The June 2026 SQLite announcement was the
|
|
101
|
+
**Go** SDK.
|
|
102
|
+
- **Effect's workflow/cluster packages fail on akm's exact topology** —
|
|
103
|
+
open upstream issues #6176/#6179: `SqliteError: database is locked` with
|
|
104
|
+
one runner plus multiple short-lived client processes on one store.
|
|
105
|
+
- **LangGraph JS's SQLite checkpointer hard-depends on `better-sqlite3`**
|
|
106
|
+
(native addon), which would break `bun build --compile` single-binary
|
|
107
|
+
distribution across all five targets.
|
|
108
|
+
|
|
109
|
+
## 4. The architectural finding (independent of maturity)
|
|
110
|
+
|
|
111
|
+
Every candidate expresses a workflow as **code** — a function whose steps
|
|
112
|
+
are memoized by *call position* as execution proceeds. akm expresses a
|
|
113
|
+
workflow as **data**: markdown compiles to a frozen plan, and units are
|
|
114
|
+
memoized by *content hash* (today `hashVersion 4`: frozen template bytes,
|
|
115
|
+
item, declared inputs, params snapshot, dispatch snapshot, invocation,
|
|
116
|
+
schema, env names, isolation, gate feedback — the companion spec proposes
|
|
117
|
+
`hashVersion 5`, adding post-append/post-fill template bytes, the `uses:`
|
|
118
|
+
target kind plus resolved-asset content hash, the persona snapshot, shell text/`shell`/`cwd`, and env *literal*
|
|
119
|
+
values).
|
|
120
|
+
|
|
121
|
+
Two consequences that no amount of library maturity fixes:
|
|
122
|
+
|
|
123
|
+
1. **Adoption inverts the memoization key.** A code-DSL engine would have
|
|
124
|
+
to be handed a closure generated from akm's plan at runtime; its cache
|
|
125
|
+
then keys on call order, not content. Edit a step's prose and a
|
|
126
|
+
call-order cache happily reuses the completed result — precisely the
|
|
127
|
+
silent-replay-reuse bug the review rounds forced into `hashVersion 5`.
|
|
128
|
+
akm would keep its own hash layer *on top*, so the library's durability
|
|
129
|
+
is redundant rather than substitutive.
|
|
130
|
+
2. **Gate loops are content-addressed retries.** A failed gate re-runs its
|
|
131
|
+
step *with judge feedback* — same call position, materially different
|
|
132
|
+
ask. akm handles this by folding `gateFeedback` into the hash preimage.
|
|
133
|
+
Under call-order memoization, loop 2 either wrongly reuses loop 1 or
|
|
134
|
+
wrongly re-runs everything.
|
|
135
|
+
|
|
136
|
+
This is why bunqueue's reviewer landed on the same phrase independently:
|
|
137
|
+
*code-DSL saga engine for one long-lived process* vs *frozen-data-plan
|
|
138
|
+
executor for concurrent short-lived CLI runs*.
|
|
139
|
+
|
|
140
|
+
## 5. Design A — build (the reviewed plan)
|
|
141
|
+
|
|
142
|
+
The companion spec, as it stands after five review rounds: markdown tasks
|
|
143
|
+
and workflows on one parser, `uses:`/`run:` targets, steps-are-tasks
|
|
144
|
+
composition, the five-layer cascade, IR v4 with a shell invocation kind,
|
|
145
|
+
`hashVersion 5`, env provenance split, ceiling-inherited shell execution,
|
|
146
|
+
migration inside the journaled 0.9.0 cutover.
|
|
147
|
+
|
|
148
|
+
Maintenance burden, honestly: akm owns ~630 LOC of journal/lease/resume
|
|
149
|
+
plumbing plus the IR pipeline. The plumbing is the *stable* part — the
|
|
150
|
+
tables, leases, and claim rows have not been the source of churn; format
|
|
151
|
+
and dispatch semantics have.
|
|
152
|
+
|
|
153
|
+
**Risk:** correctness of concurrency and replay is akm's problem. Mitigated
|
|
154
|
+
by what already exists — the journal, `plan_hash`, deterministic replay
|
|
155
|
+
tests, and the chaos/crash-window suites.
|
|
156
|
+
|
|
157
|
+
## 6. Design B — buy (OpenWorkflow, at its strongest)
|
|
158
|
+
|
|
159
|
+
Designed to win if it can. OpenWorkflow scores best of the candidates
|
|
160
|
+
(embedded, zero runtime deps, empirically SIGKILL-durable, Apache-2.0).
|
|
161
|
+
|
|
162
|
+
**Shape.** Markdown authoring is preserved exactly — the constraint is not
|
|
163
|
+
the discriminator. `akm workflow run` compiles markdown → frozen plan
|
|
164
|
+
→ *generates an OpenWorkflow definition* whose steps call akm dispatch.
|
|
165
|
+
OpenWorkflow owns run/step journaling, resume, memoization, heartbeats.
|
|
166
|
+
akm keeps the parser, IR/freeze, cascade, gates, dispatch, redaction.
|
|
167
|
+
|
|
168
|
+
**What is deleted:** ~670 LOC (~8%, the low end of §3's 8–12% estimate) —
|
|
169
|
+
the run/step journal writer, resume bookkeeping, lease renewal. That is
|
|
170
|
+
~40 LOC above §2's ~630 central estimate and sits inside its ~490–720
|
|
171
|
+
band: OpenWorkflow absorbs a little more than the narrowest reading of
|
|
172
|
+
"plumbing," which is the most favourable assumption available to it.
|
|
173
|
+
|
|
174
|
+
**What must be built to stand still** (each verified absent upstream):
|
|
175
|
+
|
|
176
|
+
| Gap | Consequence |
|
|
177
|
+
|---|---|
|
|
178
|
+
| No concurrency cap (issue #20, open 9 months) | Re-implement bounded fan-out — the capability was the point |
|
|
179
|
+
| No per-step timeout, **no `AbortSignal`** | Lose in-flight cancellation of agent spawns; a runaway unit cannot be preempted |
|
|
180
|
+
| No error classification | Re-implement the 12-value failure taxonomy driving retry |
|
|
181
|
+
| Schema collision — **reproduced**: `no such column: parent_step_attempt_id`, no table-prefix option | A **second DB file**, which breaks single-transaction atomicity across the gate spine |
|
|
182
|
+
| 1,000 step-attempt cap | 10× below akm's 10,000-unit expansion limit |
|
|
183
|
+
| `brief`/`report` (2,690 LOC) are built on the `workflow_run_units` row shape (`WorkflowRunUnitRow`, consumed field-by-field — `input_hash`, `phase`, `claim_holder`, `attempts`, `result_json`, `failure_reason` — through the `withWorkflowRunsRepo` seam, not raw SQL) | The protocol must be re-pointed at a foreign schema it does not control |
|
|
184
|
+
|
|
185
|
+
**Net:** ~670 LOC deleted, ~400+ LOC of adapters and re-implementations
|
|
186
|
+
added, atomicity and cancellation lost, a 10× capacity regression, and a
|
|
187
|
+
bus-factor-1 pre-1.0 dependency placed in the execution path of an
|
|
188
|
+
autonomous scheduled system. The landscape reviewer's phrasing for the
|
|
189
|
+
comparable case applies: *net LOC plausibly negative*.
|
|
190
|
+
|
|
191
|
+
## 7. Recommendation
|
|
192
|
+
|
|
193
|
+
**Adopt Design A.** Then pursue the two moves that actually reduce burden —
|
|
194
|
+
neither of which is a workflow engine:
|
|
195
|
+
|
|
196
|
+
1. **Dependency below the engine, not instead of it.** Replace
|
|
197
|
+
`core/concurrent.ts` with `p-limit`/`p-queue` if desired. Small, real,
|
|
198
|
+
zero architectural risk. (Optional; 40 lines — the other 20 of §2's
|
|
199
|
+
calibration figure are `workflows/concurrency-policy.ts`, whose
|
|
200
|
+
cap-precedence policy survives the swap unchanged.)
|
|
201
|
+
2. **Cut scope above the engine — the real lever.** `brief`/`report` is
|
|
202
|
+
**2,690 LOC, 31% of the engine**, and is Experimental/opt-in behind
|
|
203
|
+
`experimental.workflowEngine` while `run` is Stable and ungated. That
|
|
204
|
+
is the largest maintenance liability in the subsystem *and* the most
|
|
205
|
+
removable. Recommend an explicit keep/cut decision on the external
|
|
206
|
+
driver protocol as its own proposal — cutting it removes ~4× more code
|
|
207
|
+
than the best library adoption would, with no new dependency.
|
|
208
|
+
|
|
209
|
+
**Worth stealing** (patterns, not packages): bunqueue's `pivot()` for plan
|
|
210
|
+
changes mid-run, its non-terminal `compensation-stuck` state, and its
|
|
211
|
+
seeded `simulatedClock()` for deterministic time tests; OpenWorkflow's
|
|
212
|
+
SIGKILL-probe test methodology, which is a stronger durability check than
|
|
213
|
+
akm's current crash-window suites.
|
|
214
|
+
|
|
215
|
+
## 8. Reopen triggers
|
|
216
|
+
|
|
217
|
+
Revisit if any becomes true:
|
|
218
|
+
|
|
219
|
+
- DBOS Transact **TS** ships a SQLite system DB (Go/Python already have it).
|
|
220
|
+
- Weft reaches 1.0 with documented **multi-process lease coordination** —
|
|
221
|
+
it is the only library designed for akm's runtime shape (Bun-native,
|
|
222
|
+
`bun:sqlite`, `windows-x64` compile target); today it explicitly refuses
|
|
223
|
+
concurrent engines against one store and is 8 weeks old.
|
|
224
|
+
- OpenWorkflow lands concurrency caps (#20), `AbortSignal`, and a table
|
|
225
|
+
prefix — the three gaps that force the second DB file and the capability
|
|
226
|
+
regressions.
|
|
227
|
+
- akm's own plumbing becomes a churn source. It has not been; format and
|
|
228
|
+
dispatch semantics have.
|
|
229
|
+
|
|
230
|
+
The trigger is not "a library got popular." It is "a library removes more
|
|
231
|
+
than it adds," measured the way §2 measures it.
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# Workflow Format Unification
|
|
2
|
+
|
|
3
|
+
Status: PROPOSAL v2 — owner decisions from review round 1 applied
|
|
4
|
+
Date: 2026-07-30
|
|
5
|
+
Supersedes: the dual markdown/YAML-program authoring surface (both unreleased)
|
|
6
|
+
|
|
7
|
+
Owner decisions incorporated in v2: no interpolation syntax in prose (§2.3),
|
|
8
|
+
gate rubrics live in the body (§2.4), steps have no titles — bare ids only
|
|
9
|
+
(§2.2).
|
|
10
|
+
|
|
11
|
+
## 0. Why now
|
|
12
|
+
|
|
13
|
+
The workflow feature has never shipped (`experimental.workflowEngine` opt-in,
|
|
14
|
+
0.9.0-rc). There are currently **two authoring formats** for one asset type,
|
|
15
|
+
and the seams between them have started leaking into unrelated systems — the
|
|
16
|
+
OKF provenance work (#730) tripped over workflow's closed frontmatter
|
|
17
|
+
allowlist, which exists only because the markdown format grew its own bespoke
|
|
18
|
+
validation instead of sharing the asset envelope every other type uses. This
|
|
19
|
+
is the moment to unify: nothing on disk to migrate, no users to break.
|
|
20
|
+
|
|
21
|
+
## 1. Review of the two current formats
|
|
22
|
+
|
|
23
|
+
### 1.1 Format A — markdown workflow (`src/workflows/parser.ts`, ~500 lines)
|
|
24
|
+
|
|
25
|
+
A bespoke prose grammar: one magic `# Workflow:` H1, magic `## Step:` H2s, a
|
|
26
|
+
magic `Step ID:` body line, magic `### Instructions` / `### Completion
|
|
27
|
+
Criteria` subsection names. Capabilities: **linear steps only** — no routing,
|
|
28
|
+
fan-out, retry, timeout, engine/model selection, output schemas, or budgets.
|
|
29
|
+
The compile path (`ir/compile.ts` `compileWorkflowPlan`) lowers every step to
|
|
30
|
+
one fail-fast unit node with verbatim instructions.
|
|
31
|
+
|
|
32
|
+
### 1.2 Format B — YAML program (`src/workflows/program/*`, ~1,300 lines)
|
|
33
|
+
|
|
34
|
+
The full orchestration surface: `unit | map | route` steps, `${{ … }}`
|
|
35
|
+
template expressions, retries keyed on the failure taxonomy, timeouts,
|
|
36
|
+
per-unit engine/model/llm overrides, JSON-Schema-typed params and step
|
|
37
|
+
outputs, gates with `max_loops`, budgets, worktree isolation.
|
|
38
|
+
Instructions are embedded YAML block scalars.
|
|
39
|
+
|
|
40
|
+
### 1.3 The divergences (each one is a standing cost)
|
|
41
|
+
|
|
42
|
+
| Concern | Markdown | YAML program |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Step id grammar | `[A-Za-z0-9][A-Za-z0-9._-]*` — dots allowed | `[A-Za-z_][A-Za-z0-9_-]*` — dots forbidden |
|
|
45
|
+
| Params | name → description string, untyped | name → JSON Schema |
|
|
46
|
+
| Templating | **none** — instructions verbatim | `${{ … }}` expressions, real substitution |
|
|
47
|
+
| Gate | `### Completion Criteria` bullets; no `max_loops` | `gate:` with criteria/max_loops |
|
|
48
|
+
| Capabilities | linear only | full orchestration |
|
|
49
|
+
| Frontmatter validation | closed hand-maintained allowlist | closed key lists, JSON Schema published |
|
|
50
|
+
| Title | required `# Workflow:` H1 prefix | `name:` field duplicating the filename |
|
|
51
|
+
| Version | internal `schemaVersion 1` | `version: 2` (IR is v3) |
|
|
52
|
+
|
|
53
|
+
Beyond the table, four structural costs:
|
|
54
|
+
|
|
55
|
+
1. **The fake templating trap.** Every shipped example workflow
|
|
56
|
+
(`scripts/akm-eval/example-stash/workflows/*.md`) uses `{{ repo }}`-style
|
|
57
|
+
moustaches that **the engine never substitutes** — markdown instructions
|
|
58
|
+
compile `templating: "verbatim"`. The YAML format substitutes `${{ … }}`
|
|
59
|
+
for real. Two syntaxes; one is decorative and exists only as a convention
|
|
60
|
+
the executing agent is hoped to honor.
|
|
61
|
+
2. **Content sniffing everywhere.** Two structural probes
|
|
62
|
+
(`looksLikeWorkflow`, `looksLikeWorkflowProgram`) consulted by the indexer
|
|
63
|
+
matchers, the workflow adapter (`recognize()` returns `"markdown" |
|
|
64
|
+
"yaml-program"`), the asset loader (extension dispatch + probe), and the
|
|
65
|
+
proposal validator (which sniffs *content* when no path is available).
|
|
66
|
+
`canonicalizeWorkflowName` collapses `foo.md` / `foo.yaml` / `foo.yml` to
|
|
67
|
+
one identity, so the two formats can silently collide on one ref.
|
|
68
|
+
3. **The closed-allowlist special case.** Workflow markdown is the only AKM
|
|
69
|
+
type validating frontmatter against a closed hand-maintained key set. It
|
|
70
|
+
is why #730's provenance stamping needed a re-validation fallback in the
|
|
71
|
+
promotion path, why the allowlist had to learn `generated`/`verified`/
|
|
72
|
+
`provenance` by name, and why its error message is now stale
|
|
73
|
+
(`validator.ts:94` still enumerates the pre-#730 keys). Every future
|
|
74
|
+
machine-stamped key repeats this.
|
|
75
|
+
4. **Double everything.** Two parsers, two templates, two doc sections, two
|
|
76
|
+
test suites, two JSON representations feeding one `WorkflowPlanDraft`.
|
|
77
|
+
~1,800 lines of format code for one asset type.
|
|
78
|
+
|
|
79
|
+
### 1.4 What is genuinely good and must survive
|
|
80
|
+
|
|
81
|
+
- **The IR and engine.** Both frontends compile to one `WorkflowPlanDraft` →
|
|
82
|
+
frozen IR v3. Deterministic replay, journaled units, leases, brief/report —
|
|
83
|
+
none of that is format-coupled. This proposal changes **frontends only**.
|
|
84
|
+
- **The closed reference grammar** (`program/expressions.ts`) — though in v2
|
|
85
|
+
of this proposal it *shrinks* from a template language to a bare reference
|
|
86
|
+
string format (§2.3).
|
|
87
|
+
- **The program vocabulary** (unit/map/route, gate control, retry taxonomy,
|
|
88
|
+
budgets, defaults): well-designed, schema-validated, kept nearly verbatim.
|
|
89
|
+
- **Markdown prose as the instruction medium.** The example workflows prove
|
|
90
|
+
the point: real instructions are long structured prose with code fences,
|
|
91
|
+
sub-headings, and lists. Markdown is their native medium.
|
|
92
|
+
|
|
93
|
+
## 2. Design
|
|
94
|
+
|
|
95
|
+
### 2.1 Principle
|
|
96
|
+
|
|
97
|
+
> **One file. Machine surface in frontmatter, prose surface in the body,
|
|
98
|
+
> joined by step id. Prose is never templated — data reaches units as
|
|
99
|
+
> attached context, not string splices.**
|
|
100
|
+
|
|
101
|
+
A workflow is an ordinary AKM markdown asset — same envelope as every other
|
|
102
|
+
type, OKF-conformant frontmatter + body — whose frontmatter carries the
|
|
103
|
+
entire orchestration graph and whose body carries per-step instructions and
|
|
104
|
+
gate rubrics under plain headings.
|
|
105
|
+
|
|
106
|
+
### 2.2 The format
|
|
107
|
+
|
|
108
|
+
````markdown
|
|
109
|
+
---
|
|
110
|
+
type: workflow
|
|
111
|
+
description: Drive a batch of GitHub issues to merged PRs.
|
|
112
|
+
params:
|
|
113
|
+
repo: { type: string, description: Target repository owner/name }
|
|
114
|
+
issues: { type: array, description: Issue numbers to implement }
|
|
115
|
+
defaults: { timeout: 10m, on_error: fail }
|
|
116
|
+
budget: { max_units: 60 }
|
|
117
|
+
steps:
|
|
118
|
+
- id: intake
|
|
119
|
+
output: { type: object }
|
|
120
|
+
- id: implement
|
|
121
|
+
map:
|
|
122
|
+
over: steps.intake.output.issues
|
|
123
|
+
concurrency: 3
|
|
124
|
+
unit: { retry: { max: 2, on: [timeout] } }
|
|
125
|
+
# `output` describes the REDUCER RESULT: the default `collect` reducer
|
|
126
|
+
# folds per-item unit results into an array.
|
|
127
|
+
output: { type: array }
|
|
128
|
+
# Retry lives here, not in a backward route: a failed gate re-runs this
|
|
129
|
+
# step with the judge's feedback, bounded by max_loops.
|
|
130
|
+
gate: { max_loops: 2 }
|
|
131
|
+
- id: verdict
|
|
132
|
+
inputs: [steps.implement.output]
|
|
133
|
+
output: { type: object }
|
|
134
|
+
- id: escalate
|
|
135
|
+
inputs: [steps.verdict.output]
|
|
136
|
+
- id: announce
|
|
137
|
+
inputs: [steps.implement.output]
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
# GitHub Issues Parallel Implementer
|
|
141
|
+
|
|
142
|
+
Free preamble prose. Indexed for search, shown in `akm show`, never
|
|
143
|
+
dispatched. Any headings except level-2 are fine here.
|
|
144
|
+
|
|
145
|
+
## intake
|
|
146
|
+
|
|
147
|
+
Everything under this heading, byte-exact, is the step's instructions —
|
|
148
|
+
sub-headings, fences, lists, all of it. The run's params arrive as attached
|
|
149
|
+
context; refer to them by name in prose ("clone the `repo` parameter's
|
|
150
|
+
repository").
|
|
151
|
+
|
|
152
|
+
## implement
|
|
153
|
+
|
|
154
|
+
This section is the **map unit template**. The engine attaches each unit's
|
|
155
|
+
item (and its index) as context; the prose says "the issue you were given."
|
|
156
|
+
|
|
157
|
+
### gate
|
|
158
|
+
|
|
159
|
+
The gate rubric — as long as it needs to be. Full prose, bullets, examples
|
|
160
|
+
of passing and failing artifacts. The judge receives this whole section.
|
|
161
|
+
|
|
162
|
+
- Every issue in the working set has a mergeable PR or a recorded blocker.
|
|
163
|
+
- No PR was opened against a branch other than the declared base.
|
|
164
|
+
|
|
165
|
+
## verdict
|
|
166
|
+
|
|
167
|
+
Inspect the implementation results and report whether the batch is clean or
|
|
168
|
+
needs escalation.
|
|
169
|
+
|
|
170
|
+
## escalate
|
|
171
|
+
|
|
172
|
+
Escalate blockers from the verdict, with the verdict artifact attached as
|
|
173
|
+
context (declared via `inputs:` above).
|
|
174
|
+
|
|
175
|
+
## announce
|
|
176
|
+
|
|
177
|
+
Post the summary. The `implement` step's artifact is attached as context
|
|
178
|
+
(declared via `inputs:` above).
|
|
179
|
+
````
|
|
180
|
+
|
|
181
|
+
**Frontmatter** (validated by one published JSON Schema):
|
|
182
|
+
|
|
183
|
+
- The standard AKM asset envelope — `type`, `description`, `tags`,
|
|
184
|
+
`when_to_use`, `xrefs`, `updated`/`timestamp`, and the OKF v0.2 families
|
|
185
|
+
(`generated`, `verified`, `provenance`, `status`, `stale_after`) — via a
|
|
186
|
+
shared `$ref`'d envelope definition (§2.5).
|
|
187
|
+
- The orchestration keys, adopted from program v2 with these changes:
|
|
188
|
+
- `version:` and `name:` **dropped**. Identity is the ref; the frozen plan
|
|
189
|
+
already versions execution semantics (IR v3); the authoring schema
|
|
190
|
+
evolves additively like every other asset type.
|
|
191
|
+
- `instructions:` keys **removed** — prose lives only in the body.
|
|
192
|
+
- `gate.criteria` **removed** — rubrics live in the body (§2.4). `gate:`
|
|
193
|
+
retains only the optional `max_loops` configuration.
|
|
194
|
+
- **No titles anywhere.** No step `title:` key, no display-title heading
|
|
195
|
+
suffix. A step is its id; the asset's human name is its `description`
|
|
196
|
+
and H1 like any other asset.
|
|
197
|
+
- New `inputs:` key on unit/map steps: the prior-step artifacts this step
|
|
198
|
+
consumes, as bare reference strings (§2.3). Replaces prose splicing as
|
|
199
|
+
the way a step sees upstream data, and gives replay hashing its exact
|
|
200
|
+
input set. Sub-paths are legal (`steps.x.output.issues`, not just
|
|
201
|
+
`steps.x.output`) so a step re-dispatches only when the slice it
|
|
202
|
+
consumes changes.
|
|
203
|
+
- A step with no `map:` and no `route:` **is** a unit step; bare
|
|
204
|
+
`- id: validate` is the complete minimal declaration. `unit:` remains as
|
|
205
|
+
the optional dispatch-override bag (engine/model/llm/timeout/retry/
|
|
206
|
+
on_error/env/isolation).
|
|
207
|
+
- One id grammar everywhere: `[A-Za-z_][A-Za-z0-9_-]*`.
|
|
208
|
+
- Keys stay snake_case (`on_error`, `max_loops`) — the existing AKM/OKF
|
|
209
|
+
frontmatter convention.
|
|
210
|
+
|
|
211
|
+
**Body** (three rules):
|
|
212
|
+
|
|
213
|
+
1. Every level-2 heading must be `## <step-id>` for a declared step, exactly.
|
|
214
|
+
(Fenced code blocks are skipped when scanning for headings.)
|
|
215
|
+
2. A unit or map step **must** have a section (its instructions / per-item
|
|
216
|
+
template, byte-exact to the next H2 or EOF). A route step **may** have one
|
|
217
|
+
(documentation, plus a gate rubric if gated). Everything before the first
|
|
218
|
+
H2 is free preamble.
|
|
219
|
+
3. Inside a step section, an optional `### gate` sub-heading starts the
|
|
220
|
+
step's gate rubric (running to the section end). It is the format's
|
|
221
|
+
**single reserved marker**. Omitted or empty rubric text skips validation;
|
|
222
|
+
a non-empty rubric enables optional validation. Frontmatter `gate:` without
|
|
223
|
+
a rubric is valid but inert.
|
|
224
|
+
|
|
225
|
+
No `Step ID:` lines, no `# Workflow:` prefix, no reserved H3s beyond `gate`.
|
|
226
|
+
|
|
227
|
+
### 2.3 No interpolation syntax — references and attached context
|
|
228
|
+
|
|
229
|
+
v1 of this proposal kept `${{ … }}` templating in prose and added a `$${{`
|
|
230
|
+
escape. The owner asked the right question — *why have the syntax at all?* —
|
|
231
|
+
and the answer is that only the **engine** ever needed deterministic value
|
|
232
|
+
resolution, and the engine only reads **whole-value frontmatter positions**:
|
|
233
|
+
|
|
234
|
+
- `map.over` — the list to fan out over.
|
|
235
|
+
- `route.input` — the value routing matches on.
|
|
236
|
+
- `inputs:` — the artifacts a step consumes (new, replacing prose splicing).
|
|
237
|
+
|
|
238
|
+
Whole-value positions need no delimiters. These become **bare reference
|
|
239
|
+
strings** with the same closed grammar, shrunk from four roots to two:
|
|
240
|
+
|
|
241
|
+
params.<name>
|
|
242
|
+
steps.<id>.output( .<ident> | [<int>] )*
|
|
243
|
+
|
|
244
|
+
`item` and `item_index` are **deleted from the language**: with no splicing
|
|
245
|
+
there is nothing to substitute — the engine attaches each map unit's item and
|
|
246
|
+
index as context alongside the prompt.
|
|
247
|
+
|
|
248
|
+
**Prose is never templated.** Each dispatched unit receives, as structured
|
|
249
|
+
attached context: the run params (params are run-scoped and documented
|
|
250
|
+
non-secret), its item + index (map units), and the artifacts named by its
|
|
251
|
+
step's `inputs:`. Instructions refer to these in plain language — which is
|
|
252
|
+
exactly how the classic driver and all nine example workflows already
|
|
253
|
+
functioned, since their moustaches were never substituted.
|
|
254
|
+
|
|
255
|
+
What this buys:
|
|
256
|
+
|
|
257
|
+
- The escape-syntax question evaporates — there are no delimiters in prose.
|
|
258
|
+
- The P1 injection class dies at the root: data never enters the instruction
|
|
259
|
+
string at all, spliced or otherwise.
|
|
260
|
+
- `program/expressions.ts` shrinks from a template parser (segments,
|
|
261
|
+
literals, offsets) to a small reference-string parser.
|
|
262
|
+
- Bodies are pure markdown — cohesive with every other asset, no syntax an
|
|
263
|
+
OKF reader or a human editor has to know about.
|
|
264
|
+
|
|
265
|
+
Determinism and replay identity are preserved: unit identity hashes the
|
|
266
|
+
frozen template bytes + canonical item JSON + declared-input artifact hashes
|
|
267
|
+
+ the params snapshot — the same inputs the journal's replay machinery keys
|
|
268
|
+
on today, minus the string splice. `inputs:` gives the hash its exact
|
|
269
|
+
upstream set, so a step re-dispatches only when data it actually consumes
|
|
270
|
+
changes (the precision splicing used to provide implicitly).
|
|
271
|
+
|
|
272
|
+
The honest trade-off: prose can no longer compose a value mid-string with
|
|
273
|
+
engine-guaranteed fidelity ("run `git checkout <item>`") — the executing
|
|
274
|
+
agent performs that mapping from attached context. Every current executor is
|
|
275
|
+
an agent/LLM engine, so this is the same trust the instructions already
|
|
276
|
+
extend everywhere else. If a non-agent unit kind (raw shell/exec) is ever
|
|
277
|
+
added, *that unit kind* reintroduces substitution as its own need — scoped
|
|
278
|
+
there, not in prose.
|
|
279
|
+
|
|
280
|
+
### 2.3a Routes are forward-only; gates are the retry mechanism
|
|
281
|
+
|
|
282
|
+
Two invariants inherited unchanged from the program format, doubly enforced
|
|
283
|
+
today (`program/parser.ts:459` and `ir/schema.ts:227`), and preserved here:
|
|
284
|
+
|
|
285
|
+
- **A route target must be a LATER step**, and a step never routes to itself.
|
|
286
|
+
The plan stays a DAG, so termination is structural rather than a runtime
|
|
287
|
+
budget's job.
|
|
288
|
+
- **Retry is a gate, not a backward edge.** A failed gate re-runs its own
|
|
289
|
+
step with the judge's feedback, bounded by `gate.max_loops`; a declared
|
|
290
|
+
`output:` schema that the artifact fails is the one error the gate loop may
|
|
291
|
+
retry through (`artifactSchemaFailure`). Anything wanting "go back and fix
|
|
292
|
+
it" expresses it as a gate on the step being fixed.
|
|
293
|
+
|
|
294
|
+
A backward `default:` therefore does not mean "loop" — it is a lint error.
|
|
295
|
+
|
|
296
|
+
### 2.3b `output:` describes the reducer result
|
|
297
|
+
|
|
298
|
+
For a map step, `output:` validates the **promoted artifact**, i.e. what the
|
|
299
|
+
reducer produced — not one unit's result. The default `collect` reducer folds
|
|
300
|
+
per-item results into an **array**, so a collected map step's schema is
|
|
301
|
+
`{ type: array }`. (`vote` folds to the winning value.) A unit step's
|
|
302
|
+
`output:` describes that single unit's structured result.
|
|
303
|
+
|
|
304
|
+
### 2.4 Gates: control in frontmatter, rubric in the body
|
|
305
|
+
|
|
306
|
+
Owner decision: rubrics are often long — real rubric documents, not
|
|
307
|
+
one-liners — and belong in the body. The split:
|
|
308
|
+
|
|
309
|
+
- **Frontmatter `gate:`** optionally carries `max_loops`. It does not enable
|
|
310
|
+
validation by itself; without a non-empty body rubric it is inert.
|
|
311
|
+
- **Body `### gate`** (inside the step's section) carries the rubric: full
|
|
312
|
+
prose, bullets, worked examples. The judge receives the whole section
|
|
313
|
+
byte-exact. Omitted or empty text skips validation. This replaces both the
|
|
314
|
+
markdown format's `### Completion Criteria` bullets and the program's
|
|
315
|
+
`gate.criteria` string list.
|
|
316
|
+
|
|
317
|
+
### 2.5 Validation model — and the end of the allowlist special case
|
|
318
|
+
|
|
319
|
+
One published JSON Schema (`schemas/akm-workflow.json`, repurposed) validates
|
|
320
|
+
the entire frontmatter. Its top level `$ref`s a new **shared asset-envelope
|
|
321
|
+
schema** — the common keys every AKM markdown type carries, including the
|
|
322
|
+
machine-stamped OKF families. Consequences:
|
|
323
|
+
|
|
324
|
+
- Workflow stops being the only type with a bespoke closed key set; "closed"
|
|
325
|
+
becomes `additionalProperties: false` over `envelope ∪ workflow-keys`,
|
|
326
|
+
defined in one place.
|
|
327
|
+
- A future machine-stamped key is added to the envelope definition **once**,
|
|
328
|
+
and every schema-validated type inherits it — the #730 fallback dance and
|
|
329
|
+
the stale hand-written key-list message become structurally impossible.
|
|
330
|
+
The promotion-path re-validation backstop is deleted.
|
|
331
|
+
- Editors get frontmatter completion/validation via the published schema
|
|
332
|
+
(yaml-language-server association) — tooling no bespoke markdown grammar
|
|
333
|
+
can offer.
|
|
334
|
+
|
|
335
|
+
Semantic passes keep their existing implementations from the program parser,
|
|
336
|
+
retargeted at frontmatter: duplicate ids, route targets exist / are
|
|
337
|
+
forward-only / are unique, reference strings resolve to earlier steps,
|
|
338
|
+
timeout format, retry-reason taxonomy, resource limits. Body checks are the
|
|
339
|
+
three rules of §2.2.
|
|
340
|
+
|
|
341
|
+
Recognition simplifies to: frontmatter `type: workflow`, or residence under
|
|
342
|
+
`workflows/` — no content sniffing. `WORKFLOW_EXTENSIONS` shrinks to `.md`.
|
|
343
|
+
|
|
344
|
+
### 2.6 OKF cohesion
|
|
345
|
+
|
|
346
|
+
The unified asset **is** an OKF-shaped document: frontmatter + markdown
|
|
347
|
+
body, no inline syntax. Provenance stamping applies with zero
|
|
348
|
+
special-casing. A third-party OKF reader sees a normal document — prose
|
|
349
|
+
overview, sections per step — degrading gracefully to readable procedure
|
|
350
|
+
documentation. `status: draft` / `stale_after` become meaningful on
|
|
351
|
+
workflows for free (e.g. a future rule that draft workflows refuse `run` —
|
|
352
|
+
noted, not proposed here).
|
|
353
|
+
|
|
354
|
+
## 3. What gets deleted
|
|
355
|
+
|
|
356
|
+
- `src/workflows/parser.ts`'s grammar: `# Workflow:` / `## Step:` /
|
|
357
|
+
`Step ID:` / reserved-H3 subsections (frontmatter/toc plumbing is reused
|
|
358
|
+
by the new body binder).
|
|
359
|
+
- `looksLikeWorkflow` / `looksLikeWorkflowProgram` sniffing and the
|
|
360
|
+
`"markdown" | "yaml-program"` mode split in the adapter, matchers, loader,
|
|
361
|
+
and proposal validator.
|
|
362
|
+
- The YAML program as a distinct on-disk format; its field validation
|
|
363
|
+
survives as the frontmatter semantic passes.
|
|
364
|
+
- **The template expression language**: `${{ … }}` delimiters, segment
|
|
365
|
+
parsing, `item`/`item_index` roots, and the escape question — replaced by
|
|
366
|
+
bare reference strings in three frontmatter positions plus context
|
|
367
|
+
attachment.
|
|
368
|
+
- The workflow-only closed frontmatter allowlist and its hand-maintained
|
|
369
|
+
error string, replaced by the schema.
|
|
370
|
+
- The #730 promotion-path re-validation fallback.
|
|
371
|
+
- Step titles in all forms; the `name:` and `version:` keys.
|
|
372
|
+
- One of the two authoring templates, one of the two doc sections, the
|
|
373
|
+
extension-collapse logic beyond `.md`, `isWorkflowProgramPath`.
|
|
374
|
+
|
|
375
|
+
Net: two formats' worth of parsing/dispatch (~1,800 lines) replaced by one
|
|
376
|
+
frontmatter schema + semantic passes + a three-rule body binder, with the
|
|
377
|
+
IR, engine, and journal reused unchanged — and the template language itself
|
|
378
|
+
reduced to a reference-string parser.
|
|
379
|
+
|
|
380
|
+
## 4. Blast radius (all unreleased surfaces)
|
|
381
|
+
|
|
382
|
+
- **Engine seam (the one non-frontend change):** unit dispatch gains context
|
|
383
|
+
attachment (params / item / declared inputs) and unit-identity hashing
|
|
384
|
+
keys on (template, item, input hashes, params) instead of instantiated
|
|
385
|
+
strings. Journal shape is already compatible; freeze pins the plan either
|
|
386
|
+
way.
|
|
387
|
+
- **Templates**: both authoring templates → one.
|
|
388
|
+
- **Examples**: 9 example-bundle workflows rewritten; their fake moustaches
|
|
389
|
+
become plain prose references to attached context — which is how they
|
|
390
|
+
already behaved in practice.
|
|
391
|
+
- **Fixtures/goldens**: `format-family-goldens/`, `all-types` fixtures,
|
|
392
|
+
parser/program suites (program-parser tests largely port).
|
|
393
|
+
- **Docs**: `docs/reference/workflows.md` collapses its two format sections;
|
|
394
|
+
the expression-language section shrinks to the reference grammar.
|
|
395
|
+
- **Index cache**: `workflow_documents` re-derives on reindex (unreleased).
|
|
396
|
+
- **CLI**: `akm workflow create` emits the unified template; `create
|
|
397
|
+
<name>.yaml` dies.
|
|
398
|
+
|
|
399
|
+
## 5. Decision log and remaining questions
|
|
400
|
+
|
|
401
|
+
Resolved by owner (review round 1):
|
|
402
|
+
|
|
403
|
+
1. ~~Escape syntax~~ — **moot**: no interpolation in prose at all (§2.3).
|
|
404
|
+
2. ~~Gate criteria location~~ — **body**, under the single reserved
|
|
405
|
+
`### gate` marker; control fields stay in frontmatter (§2.4).
|
|
406
|
+
3. ~~Step titles~~ — **none**; a step is its id.
|
|
407
|
+
4. ~~Heading form~~ — **bare `## <id>`**.
|
|
408
|
+
|
|
409
|
+
Resolved by owner (review round 2):
|
|
410
|
+
|
|
411
|
+
5. **`inputs:` accepts sub-paths.** `steps.x.output` and
|
|
412
|
+
`steps.x.output.issues` are both legal — the reference grammar already
|
|
413
|
+
parses the path form, and a narrower declared input means a narrower
|
|
414
|
+
replay hash, so a step re-dispatches only when the slice it actually
|
|
415
|
+
consumes changes.
|
|
416
|
+
6. **All run params attach to every unit.** No per-step params declaration.
|
|
417
|
+
Params are run-scoped and documented non-secret (`docs/reference/
|
|
418
|
+
workflows.md`, "Params are not secret"); secrets travel as `env:` refs,
|
|
419
|
+
which remain per-unit. This keeps the attachment model uniform: every
|
|
420
|
+
unit receives params, its item + index if it is a map unit, and the
|
|
421
|
+
artifacts its step's `inputs:` names.
|
|
422
|
+
|
|
423
|
+
No open questions remain. This proposal is ready to implement.
|
|
424
|
+
|
|
425
|
+
## 6. Non-goals
|
|
426
|
+
|
|
427
|
+
- No engine, IR, freeze, journal, lease, or brief/report changes beyond the
|
|
428
|
+
dispatch-context seam noted in §4.
|
|
429
|
+
- No new orchestration capabilities (no new step kinds, reducers, or
|
|
430
|
+
reference roots).
|
|
431
|
+
- No change to task/env/script/secret formats; task remains a YAML type —
|
|
432
|
+
tasks are machine schedules, not prose procedures.
|