akm-cli 0.9.2-alpha.4 → 0.9.2

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.
Files changed (143) hide show
  1. package/CHANGELOG.md +493 -0
  2. package/STABILITY.md +23 -5
  3. package/dist/assets/hints/cli-hints-full.md +12 -7
  4. package/dist/assets/tasks/core/extract.yml +3 -5
  5. package/dist/assets/tasks/core/improve.yml +3 -5
  6. package/dist/assets/tasks/core/index-refresh.yml +3 -5
  7. package/dist/assets/tasks/core/sync.yml +3 -5
  8. package/dist/assets/tasks/core/version-check.yml +3 -5
  9. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +3 -5
  10. package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -6
  11. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +3 -5
  12. package/dist/assets/tasks/improve/akm-improve-frequent.yml +3 -5
  13. package/dist/assets/tasks/improve/akm-improve-nightly.yml +3 -5
  14. package/dist/cli/unknown-flags.js +12 -1
  15. package/dist/cli.js +8 -1
  16. package/dist/commands/command/command-execution.js +23 -2
  17. package/dist/commands/health/improve-metrics.js +38 -0
  18. package/dist/commands/health/windows.js +8 -4
  19. package/dist/commands/health.js +8 -4
  20. package/dist/commands/lint/index.js +1 -1
  21. package/dist/commands/migrate-cli.js +130 -24
  22. package/dist/commands/proposal/validators/proposal-validators.js +7 -2
  23. package/dist/commands/tasks/explain.js +304 -0
  24. package/dist/commands/tasks/tasks-cli.js +185 -3
  25. package/dist/commands/tasks/tasks.js +265 -52
  26. package/dist/commands/workflow/plan.js +159 -0
  27. package/dist/commands/workflow-cli.js +94 -2
  28. package/dist/core/activation-policy.js +2 -12
  29. package/dist/core/adapter/adapters/akm-lint.js +7 -4
  30. package/dist/core/adapter/adapters/akm-metadata.js +26 -14
  31. package/dist/core/adapter/adapters/akm-task-adapter.js +13 -10
  32. package/dist/core/errors.js +45 -0
  33. package/dist/core/json-schema.js +15 -5
  34. package/dist/core/state/migrations.js +57 -0
  35. package/dist/core/state-db.js +16 -14
  36. package/dist/core/subprocess.js +47 -13
  37. package/dist/execution/guarded-source.js +44 -0
  38. package/dist/execution/input-contract.js +250 -0
  39. package/dist/execution/target-ref.js +63 -0
  40. package/dist/indexer/usage/usage-events.js +14 -3
  41. package/dist/integrations/agent/execution-lowering.js +12 -1
  42. package/dist/output/shapes/passthrough.js +2 -0
  43. package/dist/output/text/helpers.js +1 -1
  44. package/dist/output/text/migrate.js +12 -3
  45. package/dist/output/text/workflow-format.js +192 -10
  46. package/dist/output/text/workflow.js +2 -1
  47. package/dist/runtime.js +1 -0
  48. package/dist/scripts/akm-migrate-node.js +11838 -10118
  49. package/dist/scripts/akm-migrate.js +11828 -10117
  50. package/dist/setup/steps/tasks.js +34 -17
  51. package/dist/storage/repositories/task-history-repository.js +5 -1
  52. package/dist/storage/repositories/workflow-runs-repository.js +144 -6
  53. package/dist/tasks/backends/launchd.js +31 -84
  54. package/dist/tasks/embedded.js +13 -7
  55. package/dist/tasks/model/invocation.js +4 -0
  56. package/dist/tasks/prepare/prepare-script-target.js +9 -0
  57. package/dist/tasks/prepare/prepare-support.js +154 -0
  58. package/dist/tasks/prepare/prepare.js +117 -0
  59. package/dist/tasks/prepare/prepared-execution.js +4 -0
  60. package/dist/tasks/prepare/script-capture.js +80 -0
  61. package/dist/tasks/run/attempt-lifecycle.js +165 -0
  62. package/dist/tasks/run/load-task.js +117 -0
  63. package/dist/tasks/run/provenance.js +20 -0
  64. package/dist/tasks/run/run-command-task.js +92 -0
  65. package/dist/tasks/run/run-native-task.js +222 -0
  66. package/dist/tasks/run/run-task.js +99 -0
  67. package/dist/tasks/run/run-workflow-task.js +222 -0
  68. package/dist/tasks/run/task-history.js +134 -0
  69. package/dist/tasks/run/task-log.js +179 -0
  70. package/dist/tasks/run/task-result.js +19 -0
  71. package/dist/tasks/scheduler-binding.js +66 -2
  72. package/dist/tasks/scheduler-invocation.js +63 -3
  73. package/dist/tasks/scheduler-sync.js +77 -14
  74. package/dist/tasks/source/bounded-document.js +455 -0
  75. package/dist/tasks/source/parse-task-source.js +59 -0
  76. package/dist/tasks/source/project-v4.js +62 -0
  77. package/dist/tasks/source/task-input-diagnostics.js +36 -0
  78. package/dist/tasks/source/task-source-v4.js +626 -0
  79. package/dist/tasks/source-v3.js +10 -733
  80. package/dist/tasks/task-run-reserved-flags.js +79 -0
  81. package/dist/workflows/authoring/authoring.js +17 -8
  82. package/dist/workflows/exec/child-invocation.js +34 -0
  83. package/dist/workflows/exec/child-workflow.js +370 -0
  84. package/dist/workflows/exec/exec-unit.js +50 -170
  85. package/dist/workflows/exec/frozen-judge.js +19 -2
  86. package/dist/workflows/exec/native-executor.js +49 -27
  87. package/dist/workflows/exec/param-secrets.js +12 -0
  88. package/dist/workflows/exec/run-workflow.js +48 -59
  89. package/dist/workflows/exec/step-work.js +222 -80
  90. package/dist/workflows/exec/unit-dispatch.js +72 -0
  91. package/dist/workflows/freeze/child-output-references.js +94 -0
  92. package/dist/workflows/freeze/environment.js +174 -0
  93. package/dist/workflows/freeze/identity.js +22 -0
  94. package/dist/workflows/freeze/resolve-steps.js +78 -0
  95. package/dist/workflows/freeze/source-freeze.js +57 -0
  96. package/dist/workflows/freeze/step-values.js +68 -0
  97. package/dist/workflows/freeze/targets/child-workflow.js +206 -0
  98. package/dist/workflows/freeze/targets/command.js +81 -0
  99. package/dist/workflows/freeze/targets/script.js +57 -0
  100. package/dist/workflows/freeze/targets/shell.js +31 -0
  101. package/dist/workflows/freeze/targets/task.js +179 -0
  102. package/dist/workflows/freeze/task-bindings.js +180 -0
  103. package/dist/workflows/ir/compile.js +59 -11
  104. package/dist/workflows/ir/environment-v4.js +3 -3
  105. package/dist/workflows/ir/freeze-v4.js +41 -7
  106. package/dist/workflows/ir/params.js +58 -131
  107. package/dist/workflows/ir/plan-hash.js +3 -3
  108. package/dist/workflows/ir/schema-v4.js +246 -17
  109. package/dist/workflows/parser.js +74 -2
  110. package/dist/workflows/program/schema.js +5 -2
  111. package/dist/workflows/resource-limits.js +20 -0
  112. package/dist/workflows/runtime/plan-classifier.js +24 -7
  113. package/dist/workflows/runtime/run-outputs.js +103 -0
  114. package/dist/workflows/runtime/runs.js +114 -9
  115. package/dist/workflows/runtime/workflow-asset-loader.js +14 -6
  116. package/dist/workflows/source-files.js +5 -5
  117. package/dist/workflows/source-ir/compare.js +17 -0
  118. package/dist/workflows/source-ir/compile.js +7 -3
  119. package/dist/workflows/source-ir/github-yaml.js +64 -17
  120. package/dist/workflows/source-ir/schema.js +69 -21
  121. package/dist/workflows/source-ir/semantics.js +7 -25
  122. package/dist/workflows/source-ir/triggers.js +79 -0
  123. package/dist/workflows/source-ir/uses.js +33 -7
  124. package/docs/migration/README.md +1 -1
  125. package/docs/migration/release-notes/0.9.2.md +87 -11
  126. package/docs/migration/release-notes/README.md +3 -2
  127. package/docs/migration/v0.8-to-v0.9.md +13 -11
  128. package/docs/migration/v0.9.0-troubleshooting.md +20 -13
  129. package/docs/migration/v0.9.1-to-v0.9.2.md +598 -49
  130. package/docs/reference/README.md +1 -1
  131. package/docs/reference/cli.md +140 -46
  132. package/docs/reference/configuration.md +6 -5
  133. package/docs/reference/supported-formats.md +9 -5
  134. package/docs/reference/tasks.md +338 -75
  135. package/docs/reference/workflow-schema.md +290 -16
  136. package/docs/reference/workflows.md +57 -7
  137. package/package.json +1 -1
  138. package/schemas/akm-task.json +173 -118
  139. package/schemas/akm-workflow.json +28 -0
  140. package/dist/tasks/runner.js +0 -941
  141. package/dist/tasks/runtime-v3.js +0 -281
  142. package/dist/workflows/ir/source-freeze-v4.js +0 -506
  143. package/dist/workflows/source-ir/ordering.js +0 -38
@@ -1,10 +1,14 @@
1
1
  # Migrating from akm 0.9.1 to 0.9.2
2
2
 
3
- AKM 0.9.2 makes task v3 the only executable task source and introduces peer
4
- Markdown and GitHub-shaped YAML workflow sources. Authored task-v2 files
5
- require an explicit, fail-closed migration. Durable workflow plans created by
6
- 0.9.1 are pre-v4 and cannot resume in 0.9.2; restart those runs from the current
7
- authored workflow source so AKM can freeze a new v4 plan.
3
+ AKM 0.9.2 makes **task source v4 the only executable task source** and
4
+ introduces peer Markdown and GitHub-shaped YAML workflow sources, compiled
5
+ through a shared source IR to durable plan **`irVersion` 5**. Authored
6
+ task-v2 and task-v3 files require an explicit, fail-closed migration
7
+ `akm migrate apply` now runs both generations in one pass. Durable workflow
8
+ plans created by 0.9.1, and any plan frozen before this release's
9
+ `irVersion` 5, cannot resume in 0.9.2 — see
10
+ [Before you upgrade](#before-you-upgrade) below for the exact recovery
11
+ steps; no run data is lost.
8
12
 
9
13
  The released 0.9.1 state ledger already includes historical migration 018, so
10
14
  the normal 0.9.1→0.9.2 database step is additive and automatic. If a pre-release
@@ -16,9 +20,47 @@ recheck, snapshot, and migration share one writer-exclusion window, so another
16
20
  WAL writer cannot commit between the copy and 018. Unknown or divergent ledgers
17
21
  remain unsupported.
18
22
 
19
- ## Before: 0.9.1 task v2
23
+ ## Before you upgrade
20
24
 
21
- A 0.9.1 inline prompt task could look like this:
25
+ 1. **Check for workflow runs in flight** and either let them finish or
26
+ abandon them deliberately — a run frozen at a pre-`irVersion`-5 plan
27
+ cannot `resume`/`next`/`complete`/`run` after the upgrade (it can still
28
+ be inspected and abandoned). See
29
+ [Pre-`irVersion`-5 stored plans](#pre-irversion-5-stored-plans-complete-or-abandon-before-upgrading)
30
+ below for the exact recovery sequence if you upgrade with runs still
31
+ active.
32
+
33
+ ```sh
34
+ akm workflow list --active
35
+ ```
36
+
37
+ 2. **Commit or otherwise snapshot your authored task and workflow bundles**
38
+ before running any migrator — both the task-v2→v3 and v3→task-source-v4
39
+ generations back up every file they touch, but a snapshot at the repo
40
+ level is cheap insurance regardless.
41
+
42
+ 3. **Do not downgrade below 0.9.2 once you've recorded task history on
43
+ it.** Task run history's `target.kind` vocabulary changed in this
44
+ release, tagged with a metadata marker a pre-0.9.2 akm's decoder does
45
+ not recognize — a pre-0.9.2 akm reading a row this release (or later)
46
+ wrote **throws** rather than misreading it. Upgrading is always safe (a
47
+ 0.9.2-or-later akm reads older rows correctly); only downgrading, or
48
+ otherwise pointing an older binary at a `state.db` a newer one has
49
+ already written to, is the hazard. See
50
+ [Task history result vocabulary](#task-history-result-vocabulary-targetkind)
51
+ below.
52
+
53
+ Everything else below can happen after the binary upgrade, at your own
54
+ pace: task sources keep failing closed with an actionable hint until you
55
+ migrate them (nothing silently breaks or half-runs), and pre-`irVersion`-5
56
+ runs stay inspectable indefinitely.
57
+
58
+ ## Task sources
59
+
60
+ akm 0.9.2 has shipped three task source generations. Only the newest,
61
+ **task source v4**, is accepted by `src/` in this release.
62
+
63
+ **Before — 0.9.1 task v2:**
22
64
 
23
65
  ```yaml
24
66
  version: 2
@@ -32,13 +74,8 @@ timeoutMs: 45000
32
74
  redact: [REVIEW_TOKEN]
33
75
  ```
34
76
 
35
- Normal 0.9.2 execution rejects v2. It never guesses how to execute an old
36
- target or rewrites a task as a side effect of `run`, `sync`, or `doctor`.
37
-
38
- ## After: 0.9.2 task v3
39
-
40
- After migration, the 0.9.2 task v3 result uses the built-in command action and moves
41
- AKM-specific scheduling and resolver controls under `akm`:
77
+ **An intermediate generation task v3** (shipped earlier in the 0.9.x
78
+ line; also no longer accepted):
42
79
 
43
80
  ```yaml
44
81
  version: 3
@@ -55,21 +92,101 @@ akm:
55
92
  redact: [REVIEW_TOKEN]
56
93
  ```
57
94
 
58
- Workflow refs become `uses: workflows/<name>` with the old `params` mapping
59
- preserved as `with`. Deterministic command strings become `run`. Command refs
60
- become `uses: commands/<name>`.
95
+ **After 0.9.2 task source v4**, the migration destination:
61
96
 
62
- ## Safe migration procedure: preview, then apply
97
+ ```yaml
98
+ version: 4
99
+ name: Contract review
100
+ uses: akm/command
101
+ with:
102
+ content: Review the execution contract.
103
+ schedule:
104
+ - cron: "15 4 * * 1"
105
+ enabled: false
106
+ engine: reviewer
107
+ model: exact-model-id
108
+ timeout: 45000
109
+ redact: [REVIEW_TOKEN]
110
+ ```
63
111
 
64
- 1. Commit or otherwise snapshot your authored bundles.
112
+ What changed between v3 and v4 (v2's changes to v3 are unchanged from
113
+ earlier 0.9.x releases and are summarized further down):
114
+
115
+ - **The `akm:` options bag is gone.** Every field it carried is a top-level
116
+ key instead: `akm.description` → `description`, `akm.when_to_use` →
117
+ `when_to_use`, `akm.tags` → `tags`, `akm.agent` → `agent`, `akm.engine` →
118
+ `engine`, `akm.model` → `model`, `akm.inference` → `inference`,
119
+ `akm.outputSchema` → `output`, `akm.tools` → `tools`, `akm.timeout` →
120
+ `timeout`, `akm.redact` → `redact`, `akm.maxSteps` → `maxSteps`,
121
+ `akm.maxRetries` → `maxRetries`.
122
+ - **The `on:` trigger block is gone**, and with it the second scheduling
123
+ syntax. `akm.schedule` → the string-shorthand top-level `schedule:`;
124
+ `on.schedule` (a list of `{cron}` records) → the list-form `schedule:`,
125
+ with every ordinal preserved; `on.workflow_dispatch` (with no
126
+ `on.schedule`) **drops silently** — a v3 document whose only trigger was
127
+ manual dispatch simply has no `schedule:` key in v4, since every v4 task
128
+ is always runnable manually with `akm task run` regardless of whether it
129
+ has a schedule. The migrator emits an informational notice when it makes
130
+ this specific drop, naming the file.
131
+ - **Scheduling is now optional.** A v4 document with no `schedule:` at all
132
+ parses, runs with `akm task run`, and is silently skipped by
133
+ `akm task sync` (zero bindings, zero failures) — it never has to declare
134
+ a trigger just to be a valid document.
135
+ - **`akm.enabled` becomes per-schedule-binding.** v3's single
136
+ document-level `enabled: false` becomes that schedule entry's own
137
+ `enabled: false` in v4 — there is no longer a document-level flag at all.
138
+ A disabled task with no cron trigger (only `on.workflow_dispatch`) has no
139
+ v4 representation and is `blocked` for manual review (see
140
+ [The migration procedure](#the-migration-procedure)).
141
+ - **Typed `inputs:` with defaults and `required:`.** v4 tasks can declare
142
+ named, bounded-JSON-Schema parameters, each optionally carrying a
143
+ `default` or `required: true` (mutually exclusive). `akm task run`
144
+ accepts one exact-name flag per declared input; a `schedule:` entry can
145
+ supply literal `inputs:` too. A `required: true` input may not carry a
146
+ `default:`, and a scheduled firing supplies no flags, so every `schedule:`
147
+ entry must name a value for each such input — a document that leaves one
148
+ unsatisfied is rejected at parse (`TASK_SOURCE_INVALID`) instead of
149
+ installing a schedule that fails at every fire. See
150
+ [Tasks: Typed inputs and output](../reference/tasks.md#typed-inputs-and-output)
151
+ for the full grammar.
152
+ - **A single bounded `output:` schema** replaces v3's `akm.outputSchema`.
153
+ - **The GitHub-action `uses:` target is removed outright.** v3 recognized
154
+ (and always rejected before dispatch) an `owner/repo[/path]@ref` spelling
155
+ such as `owner/repo@v1`; v4 does not recognize that shape as a `uses:`
156
+ target at all — it fails at parse alongside every other unrecognized
157
+ value. See
158
+ [GitHub Action locators are no longer recognized anywhere](#github-action-locators-are-no-longer-recognized-anywhere)
159
+ under Workflow cutover.
160
+ - **`with:` narrows to `uses: akm/command` only.** Every other target
161
+ (`commands/`, `scripts/`, `workflows/`, `run:`) uses `inputs:` for typed
162
+ parameters instead.
163
+ - `akm task add` now authors task source v4 directly (`--params` renders
164
+ typed `inputs:` with `default:` values instead of a `with:` bag;
165
+ `--disabled` now requires `--schedule`).
166
+
167
+ See [Tasks](../reference/tasks.md) for the complete grammar reference,
168
+ including the retired v3 grammar (kept purely so you can read an old file
169
+ while migrating it).
170
+
171
+ ## The migration procedure
172
+
173
+ `akm migrate status` and `akm migrate apply [--dry-run]` run **both**
174
+ generations in one pass against the same tree: task-v2 → task-v3 first,
175
+ then task-v3 → task source v4 against the resulting files. Each generation
176
+ keeps its own lock, `O_EXCL` backup, prevalidation, TOCTOU recheck, atomic
177
+ replace, and reverse rollback — a file blocked in generation 1 does not
178
+ stop generation 2 from converting files that are already `version: 3`.
179
+
180
+ 1. Commit or otherwise snapshot your authored bundles (see
181
+ [Before you upgrade](#before-you-upgrade)).
65
182
  2. Preview the pure migration plan. This performs no source write:
66
183
 
67
184
  ```sh
68
185
  akm migrate apply --dry-run
69
186
  ```
70
187
 
71
- 3. Review every input file. The report is stable and names an exact status for
72
- each file: `changed`, `skipped`, or `blocked`.
188
+ 3. Review every input file. The report is stable and names an exact status
189
+ for each file, per generation: `changed`, `skipped`, or `blocked`.
73
190
  4. Resolve every blocked file manually, then preview again.
74
191
  5. Apply the same planner:
75
192
 
@@ -77,22 +194,15 @@ become `uses: commands/<name>`.
77
194
  akm migrate apply
78
195
  ```
79
196
 
80
- For each `changed` file, AKM validates the complete v3 bytes before replacement.
81
- At apply time it rechecks the planned generation,
82
- backs up that file immediately before replacement, preserves its file mode,
83
- and then installs the validated replacement. A race or validation failure
197
+ For each `changed` file, AKM validates the complete replacement bytes
198
+ before writing. At apply time it rechecks the planned generation, backs up
199
+ that file immediately before replacement, preserves its file mode, and
200
+ then installs the validated replacement. A race or validation failure
84
201
  stops instead of applying stale output.
85
202
 
86
- Exact translations preserve the schedule. They preserve enabled state and params.
87
- They preserve timeout and redaction names. They preserve resolver overrides
88
- (engine, model, inference, tools, and agent where admitted). Empty
89
- collections, explicit false/zero, and meaningful null values remain distinct
90
- when the v3 contract supports them.
91
-
92
- ## Blocked files and manual review
203
+ ### v2 v3 blocked cases
93
204
 
94
- The migrator blocks any case whose execution meaning is not provably portable.
95
- In particular, a v2 argv array has no unambiguous v3 shell-string equivalent:
205
+ A v2 argv array has no unambiguous v3 shell-string equivalent:
96
206
 
97
207
  ```yaml
98
208
  version: 2
@@ -100,28 +210,460 @@ schedule: "@daily"
100
210
  command: [node, scripts/release.js, "--exact value"]
101
211
  ```
102
212
 
103
- Shell-sensitive strings—assignments, shell builtins, reserved words, and
104
- similar constructs—are also blocked when translating them would invent shell
105
- semantics. The original bytes remain untouched. Author a v3 `run` string or a
106
- script/command asset deliberately, validate it, and rerun the preview.
213
+ Shell-sensitive strings assignments, shell builtins, reserved words, and
214
+ similar constructs are also blocked when translating them would invent
215
+ shell semantics. The original bytes remain untouched. Author a v3 `run`
216
+ string or a script/command asset deliberately, validate it, and rerun the
217
+ preview. (This step still produces v3 output, which the second generation
218
+ then carries the rest of the way to v4 in the same `akm migrate apply` run.)
219
+
220
+ ### Migrating task v3 to task source v4
221
+
222
+ The second generation converts an eligible `version: 3` task source to
223
+ `version: 4`. It translates structure, never intent: it never invents an
224
+ `inputs:` declaration on a file's behalf, regardless of how inferable a
225
+ `with:` value's shape looks — declaring `inputs:` (and rewriting a step to
226
+ bind it) is left to the person editing the migrated file by hand.
227
+
228
+ Common blocked reasons and what to do about each:
229
+
230
+ | Reason | Meaning | Fix |
231
+ |---|---|---|
232
+ | `github-action-target-removed` | The task's `uses:` is a GitHub Action locator (`owner/repo[/path]@ref`); that spelling has no task source v4 equivalent. | Rewrite the target as `commands/`, `scripts/`, `workflows/`, or `akm/command` by hand. |
233
+ | `with-on-non-command-target` | A `with:` block is authored on a target other than `uses: akm/command`. | Declare `inputs:` on the task instead; a workflow step composing it binds them with its own `with:`. |
234
+ | `ambiguous-scheduling-source` | The document declares both `akm.schedule` and `on:`. | Pick one; the migrator will not guess which one wins. |
235
+ | `enabled-false-has-no-schedule-entry` | `akm.enabled: false` with no cron trigger to attach it to (the only trigger is `on.workflow_dispatch`). | Task source v4 has no document-level `enabled` flag — decide whether the task should be scheduled (add a cron) or left manual-only (drop `akm.enabled`), then re-run. |
236
+ | `read-only-source` | The owning source or file is not writable. | Move or re-source the file somewhere writable, or edit it by hand. |
237
+ | `invalid-v3-task` | The v3 document itself is structurally invalid (unknown fields, missing selector, malformed trigger, etc). | Fix the underlying v3 document first — the migrator translates structure, it does not repair it. |
238
+
239
+ If you only want to run this generation in isolation (for example, your
240
+ tree is already all `version: 3` and you want to preview just this step),
241
+ the frozen migrator's standalone entry points remain available as a
242
+ separate executable, installed alongside `akm`:
243
+
244
+ ```sh
245
+ akm-migrate task-v4-status
246
+ akm-migrate task-v4-apply --dry-run
247
+ akm-migrate task-v4-apply
248
+ ```
249
+
250
+ ## Task history result vocabulary (`target.kind`)
251
+
252
+ This is about **run history**, not task source files — nothing here is a
253
+ document you author or migrate. `akm task history` and `akm task run`'s
254
+ result envelope both carry a `target.kind` field, and its vocabulary
255
+ changed:
256
+
257
+ | Old (0.9.1) | New (0.9.2) | Meaning |
258
+ |---|---|---|
259
+ | `"prompt"` | `"command"` | A prepared command dispatched to an agent/LLM engine. |
260
+ | `"command"` (shared) | `"shell"` or `"script"` | A native shell or script execution — previously one shared `"command"` label for both. |
261
+
262
+ `"prompt"` mislabeled an LLM-routed dispatch as a literal prompt, and one
263
+ shared `"command"` conflated two materially different execution shapes.
264
+ 0.9.2 renames the vocabulary going forward and, at the same time, adds a
265
+ per-row marker (`targetVocab: 2`, stored in each row's metadata) so a
266
+ reader can always tell which generation a row belongs to.
267
+
268
+ **The read side is a permanent legacy mapping, not a one-time conversion.**
269
+ `task_history` is an append-only log — there is no "convert existing rows
270
+ in place" step, and there never will be. `akm task history` keeps reading
271
+ BOTH generations correctly forever: a row with no `targetVocab` marker
272
+ (written before this release) is read with the OLD meaning — `"prompt"` →
273
+ `{kind: "command", engine}`, `"command"` → `{kind: "shell"}` — and a row
274
+ carrying `targetVocab: 2` is read with the NEW meaning directly. You do not
275
+ need to do anything for your existing history; this mapping is built in and
276
+ will not be removed.
277
+
278
+ **Mixed-fleet ordering hazard (one-way, hard failure).** The metadata
279
+ decoder rejects any field it does not recognize — it is a closed allowlist,
280
+ not a permissive parser that ignores extras. A **pre-0.9.2** akm's decoder
281
+ does not have `targetVocab` in that allowlist, because the field did not
282
+ exist yet. If a task's history lives in a `state.db` that both a 0.9.2 (or
283
+ later) akm and a pre-0.9.2 akm read — for example, a global install and a
284
+ pinned `npx akm@<old>` pointed at the same state directory, or a downgrade
285
+ — the OLDER binary throws `invalid task_history metadata_json: unknown
286
+ fields: targetVocab` (an uncaught error, not a handled `UsageError`) the
287
+ first time it tries to read a row a 0.9.2-or-later akm wrote. A
288
+ **0.9.2-or-later** akm has no such problem: it reads a legacy (unmarked)
289
+ row correctly using the mapping above, so upgrading is always safe in that
290
+ direction. Only downgrading, or otherwise pointing an older binary at a
291
+ state directory a newer one has already written to, is the hazard. Keep
292
+ one akm version reading a given `state.db` at a time; do not alternate
293
+ versions against the same state directory, and do not downgrade below
294
+ 0.9.2 once a 0.9.2-or-later akm has recorded task history there.
107
295
 
108
296
  ## Workflow cutover
109
297
 
110
298
  Markdown `.md` and GitHub-shaped `.yml` are peer workflow source formats in
111
299
  0.9.2 and compile to source IR version 1. New workflow starts freeze durable
112
- plan IR v4, the sole executable plan format. Pre-v4 stored plans are rejected;
113
- start a new run from current source. A v4 resume does not re-read authored
114
- workflow/command/agent source, configuration, model maps, or the asset index.
300
+ plan **`irVersion` 5**, the sole executable plan format. A resume does not
301
+ re-read authored workflow/command/agent source, configuration, model maps, or
302
+ the asset index.
115
303
 
116
- The `inherit_env` removal is breaking because every new v4 start rejects it.
304
+ The `inherit_env` removal is breaking because every new start rejects it.
117
305
  Use named environment bindings and `pass_env` as the bounded replacement for fixed, secret, and per-machine values.
118
- There is no compatibility reader for the historical flag or pre-v4 plans.
306
+ There is no compatibility reader for the historical flag.
307
+
308
+ The GitHub-shaped source format is intentionally local and bounded: **AKM
309
+ YAML uses a familiar GitHub-step-shaped syntax but is an AKM workflow
310
+ format, executed by AKM's native engine.** It accepts schedule and empty
311
+ `workflow_dispatch` triggers, `runs-on: [self-hosted]`, and the documented
312
+ local step subset. Full expressions, contexts, remote/local or Docker
313
+ actions, service-event automation, and arbitrary runners remain
314
+ unsupported. A step composing another workflow (`uses: workflows/<ref>`, or a
315
+ task whose own target is a workflow) is new in 0.9.2 — see
316
+ [Child workflows](#child-workflows) below.
317
+
318
+ ### Multi-job YAML is rejected at the adapter boundary
319
+
320
+ A GitHub-shaped document whose `jobs:` map does not contain exactly one job
321
+ now fails to compile at all — it never reaches lint, plan, or run as a
322
+ partially-valid document. Before this release, a multi-job document parsed
323
+ and ordered its jobs cleanly, and was refused only much later, in two
324
+ different places, with two different shapes:
325
+
326
+ ```
327
+ # 0.9.1: parsed clean, then refused at freeze with a bare thrown error
328
+ Multi-job workflow cannot execute until job boundaries and needs have a
329
+ durable runtime representation.
330
+ ```
331
+
332
+ ```
333
+ # 0.9.2: refused at compile, with the offending job count and a `line`
334
+ AKM workflow YAML requires exactly one job; this document declares 2.
335
+ AKM's YAML is an AKM workflow format executed by AKM's native engine, not
336
+ GitHub Actions — split the jobs into separate workflows.
337
+ ```
338
+
339
+ surfaced from `akm workflow run` (and `akm workflow plan`) as `UsageError`
340
+ code `COMPOSITION_INVALID`, exit 2. **Fix:** split a multi-job document into
341
+ separate single-job workflows and compose them with a child-workflow step
342
+ (`uses: workflows/<ref>`) — see [Child workflows](#child-workflows).
343
+
344
+ ### GitHub Action locators are no longer recognized anywhere
345
+
346
+ A workflow step's `uses: owner/repo[/path]@ref` (e.g.
347
+ `uses: actions/checkout@v4`) used to be recognized and rejected with a
348
+ locator-specific message:
349
+
350
+ ```
351
+ # 0.9.1
352
+ Remote action acquisition is out of scope for "actions/checkout@v4".
353
+ ```
354
+
355
+ In 0.9.2 the locator grammar itself is gone from native classification; the
356
+ same value now fails the same way any other unrecognized `uses:` shape does
357
+ — the canonical target-ref classifier's own rejection:
119
358
 
120
- The GitHub-shaped source format is intentionally local and bounded. It accepts
121
- schedule and empty `workflow_dispatch` triggers, `runs-on: [self-hosted]`, and
122
- the documented local step subset. Full expressions, contexts, remote/local or
123
- Docker actions, nested workflows, service-event automation, and arbitrary
124
- runners remain unsupported.
359
+ ```
360
+ # 0.9.2
361
+ Target ref "actions/checkout@v4" must be a canonical commands/, scripts/,
362
+ tasks/, or workflows/ asset ref.
363
+ ```
364
+
365
+ with code `unsupported-uses-target`. Nothing acquired or executed a remote
366
+ action in any akm release, so this is a message and classification change,
367
+ not a capability removal. A task's own `uses:` GitHub Action locator fails
368
+ the same way, at parse, with `TASK_SOURCE_INVALID` — see
369
+ [Task sources](#task-sources) above. The migrator still names the target
370
+ explicitly when it blocks a v3 → v4 conversion
371
+ (`github-action-target-removed`).
372
+
373
+ ### Pre-`irVersion`-5 stored plans: complete or abandon before upgrading
374
+
375
+ Every 0.9.1 (and pre-P3a 0.9.2-alpha) durable plan was frozen at an older
376
+ `irVersion`. Upgrading does not delete or migrate those runs, but it does
377
+ retire them as **executable**:
378
+
379
+ - `akm workflow status <id>`, `akm workflow list`, and
380
+ `akm workflow abandon <id>` keep working exactly as before — nothing about
381
+ those runs is deleted, and abandoning one leaves its step spine untouched.
382
+ - `akm workflow resume`, `next`, `complete`, and a bare `run` against that
383
+ run id now fail closed with:
384
+
385
+ ```
386
+ Workflow run <id> was frozen as workflow plan irVersion <n>; pre-irVersion-5
387
+ plans cannot execute after the 0.9.2 upgrade. Complete them before upgrading,
388
+ or run 'akm workflow abandon <id>' and start a new run from the authored
389
+ workflow. 'akm workflow status' and 'akm workflow list' still work on this run.
390
+ ```
391
+
392
+ as a `UsageError` with code `WORKFLOW_IR_VERSION_UNSUPPORTED`, exit 2.
393
+
394
+ There is no second executor and no compatibility replay layer for an old
395
+ plan version — a blocked run's only way forward is a fresh start.
396
+
397
+ **Before upgrading**, check for runs in flight and let them finish, or
398
+ abandon them deliberately (see [Before you upgrade](#before-you-upgrade)).
399
+
400
+ **After upgrading**, if a run is blocked by this policy, recover it with the
401
+ two-command sequence the error message itself names:
402
+
403
+ ```sh
404
+ akm workflow abandon <id>
405
+ akm workflow run <ref>
406
+ ```
407
+
408
+ No data is lost either way: the blocked run's row, its step spine, and its
409
+ journaled events all remain readable through `akm workflow status`/`list`
410
+ indefinitely — only `resume`/`next`/`complete`/`run` against that specific
411
+ run id are refused.
412
+
413
+ ## `with:` on a task-composed step now binds — or rejects
414
+
415
+ A workflow step's `uses: tasks/<ref>` target with an authored `with:` mapping
416
+ used to decode without error and then have that mapping silently dropped when
417
+ the workflow was frozen — the authored inputs never reached the task, with no
418
+ error and no warning. 0.9.2 makes this fail closed, and, where the target
419
+ supports it, actually deliver the mapping:
420
+
421
+ - If the target task source declares `inputs:` (task source v4), `with:`
422
+ now **binds** them — a literal value, or a `{from: "steps.<id>.output…"}`
423
+ reference resolved just before the unit dispatches. An unknown key, a
424
+ missing required input, or a reference to a step that doesn't exist
425
+ earlier in the job fails at freeze with `UsageError` code
426
+ `INPUT_BINDING_INVALID`. (The reference grammar also accepts
427
+ `{from: "params.<name>"}`, naming a declared param of the *composing*
428
+ workflow — but a composing step is only authorable in a GitHub-shaped
429
+ document, whose root keys can never include `params:`, so that form is
430
+ not reachable in this release. `{from: "steps.<id>.output…"}` is the one
431
+ reference form you can actually use today.)
432
+ - If the target task declares **no** `inputs:` at all (a `version: 4` task
433
+ with no `inputs:` key), freezing the step now throws
434
+
435
+ ```
436
+ Workflow step <id> cannot pass with: to task target <ref>; <ref> declares no inputs.
437
+ ```
438
+
439
+ as a `UsageError` with code `COMPOSITION_INVALID` (exit 2). This fires for
440
+ any authored `with:` shape that survives decode — including an empty
441
+ mapping (`with: {}`) — not just a non-empty one.
442
+ - The same `COMPOSITION_INVALID` rejection now also fires for a `with:`
443
+ authored on `uses: commands/<ref>` or `uses: scripts/<ref>` — neither is a
444
+ binding surface, and this authored mapping used to be silently dropped too.
445
+ Remove `with:` from any such step:
446
+
447
+ ```diff
448
+ - id: dispatch
449
+ uses: commands/review
450
+ - with:
451
+ - scope: all
452
+ ```
453
+
454
+ A step targeting any task with no `with:` at all is unaffected and keeps
455
+ freezing exactly as before. `with:` on `uses: akm/command` is a different,
456
+ unaffected path — it is still required to supply the builtin action's
457
+ arguments and continues to work as documented. `with:` on a
458
+ **child-workflow** target (direct or task-wrapped) is different again: it
459
+ binds the child's declared `params:` — see [Child workflows](#child-workflows).
460
+
461
+ **Resume identity.** A reference binding's *resolved* value is part of the
462
+ unit's durable input-identity hash, alongside the reference's own text
463
+ (`from: "steps.discover.output.files"`) inside the frozen target: any unit
464
+ whose target carries bindings hashes the effective values it actually
465
+ receives (the same values delivered through the `## Task inputs` prompt
466
+ block and `AKM_TASK_INPUTS`). In the ordinary case this changes nothing —
467
+ a frozen plan never re-reads source, so the same reference resolves to the
468
+ same journaled upstream output on every attempt, the recomputed hash
469
+ matches, and a resume reuses completed rows exactly as before. What it
470
+ closes is the stale-reuse hole: journaled `workflow_run_units` rows are
471
+ still read-only durable state, and if an earlier, already-completed step's
472
+ journaled output is altered before a resume, a later bound unit now
473
+ recomputes a *different* input hash and the run fails loudly with the
474
+ executor's replay-divergence error ("journaled with different inputs")
475
+ instead of silently reusing a row bound to the now-stale value. Units
476
+ without bindings are unaffected.
477
+
478
+ See [`with:` on a task-composed step](../reference/workflow-schema.md#github-shaped-yaml-subset)
479
+ for the full binding grammar, delivery surfaces (`AKM_TASK_INPUTS`, the
480
+ `## Task inputs` prompt block), and `akm task explain` for inspecting what a
481
+ task-composed step would actually receive.
482
+
483
+ ## Child workflows
484
+
485
+ Nothing to migrate here in the strict sense: composing a child workflow is
486
+ itself new in 0.9.2, so no run from before this release ever has a stored
487
+ child. There is no pre-existing child-run data to convert or backfill. But
488
+ if you are restructuring a multi-job document to work around the new
489
+ one-job limit (above), this is the mechanism you restructure into.
490
+
491
+ **Two authoring forms**, both lowering to the same child-workflow target:
492
+
493
+ - **Direct**: a step's `uses: workflows/<ref>` composes another workflow
494
+ directly. `with:` on the step binds the child's declared `params:`.
495
+ - **Task-wrapped**: a step's `uses: tasks/<ref>` composes a task whose own
496
+ target is itself `uses: workflows/<ref>`. The task's own effective
497
+ `inputs:` (its declared defaults plus whatever the composing step's
498
+ `with:` bound against the task's contract) are re-bound, by name, against
499
+ the child workflow's declared `params:`.
500
+
501
+ Composition is bounded, checked entirely at **freeze**, before the parent
502
+ run is published, and failing with `UsageError` code `COMPOSITION_INVALID`
503
+ when violated:
504
+
505
+ - **Depth**: the root workflow plus 8 descendant levels (a 9th fails).
506
+ - **Cycles**: a composition cycle (a workflow composing itself, directly or
507
+ transitively) fails before any durable mutation.
508
+ - **Aggregate size**: the sum of every embedded child plan's canonical-JSON
509
+ bytes across one root freeze is capped at half the single-plan byte
510
+ ceiling (currently 1 MiB total).
511
+
512
+ The child workflow is compiled, validated, and frozen **completely** — its
513
+ own complete plan embedded inside the parent's — before the parent run
514
+ exists, so editing the child's source afterward cannot affect an
515
+ already-frozen parent, and the child's transitive sources join the
516
+ parent's guarded source read set.
517
+
518
+ **Execution.** Running a step whose target is a child workflow drives that
519
+ child to completion (or as far as it gets) inline, in the parent's own
520
+ process, with the same engine `akm workflow run` uses on the child's frozen
521
+ plan — not a separately scheduled job. Publication is idempotent, so a
522
+ retried or resumed composing step reuses the same child rather than
523
+ starting a new one.
524
+
525
+ **Status mapping.** The child's final status maps onto the composing step
526
+ and the parent run: `completed` promotes the child's declared `outputs:`
527
+ (see [Workflow outputs](#workflow-outputs)) — or `{runId, status}` when it
528
+ declares none — as the step's output, and the parent continues; `failed`
529
+ fails the step and the run; `blocked` blocks the step and the run.
530
+
531
+ **Cancellation propagates because the drive is inline.** Whatever aborts
532
+ the parent's own dispatch — `Ctrl-C`, a `--timeout`, a budget ceiling, or
533
+ the parent losing its run lease — also aborts the child drive, since it is
534
+ the same process. Both runs are left resumable, never partially torn down.
535
+
536
+ **Independent resume.** A blocked child blocks its composing step; AKM does
537
+ not resume a child for you, because a gate is a gate for a child workflow
538
+ too. The step's notes name the exact three-command sequence — resume the
539
+ **child** first, then resume and re-run the **parent**, since re-driving
540
+ the parent is what re-enters the composing step and drives the now-resumed
541
+ child:
542
+
543
+ ```sh
544
+ akm workflow resume <childRunId>
545
+ akm workflow resume <parentRunId>
546
+ akm workflow run <parentRunId>
547
+ ```
548
+
549
+ A child run id always works directly with `status`/`resume`/`abandon`/`run`,
550
+ whether or not it is listed. `akm workflow status` on a run that composes
551
+ children renders a `children:` tree. `akm workflow list` excludes child
552
+ runs by default now that they exist at all — pass `--children` to include
553
+ them.
554
+
555
+ See [Workflow Schema: Child workflows](../reference/workflow-schema.md#child-workflows)
556
+ and [Workflow Schema: Child execution](../reference/workflow-schema.md#child-execution)
557
+ for the complete grammar, status-mapping table, and nested-block recovery
558
+ sequence, and
559
+ [Running Workflows: Child runs](https://github.com/itlackey/akm/blob/main/docs/guides/run-workflows.md#child-runs)
560
+ for an operational walkthrough.
561
+
562
+ ## Workflow outputs
563
+
564
+ A workflow may declare a run-level export in its Markdown frontmatter:
565
+
566
+ ```yaml
567
+ outputs:
568
+ summary:
569
+ from: steps.review.output.summary
570
+ fileCount:
571
+ from: steps.scan.output.files
572
+ schema: { type: array }
573
+ ```
574
+
575
+ Up to 64 entries, each `{from: steps.<id>.output(.<segment>)*, schema?}`,
576
+ resolved **once**, from persisted step evidence, at run completion. An
577
+ unresolvable reference, a truncated step artifact, or a schema violation
578
+ rolls the completion back — `UsageError` code `WORKFLOW_OUTPUT_INVALID`:
579
+ the run stays `active` and its final step stays `pending` rather than
580
+ completing with missing exports. A run with no `outputs:` declaration
581
+ exports `{runId, status}` instead. When this run is itself a composed
582
+ child, its exported result (whichever of the two shapes above) becomes the
583
+ composing parent step's own output — see
584
+ [Child workflows](#child-workflows).
585
+
586
+ This is a Markdown-frontmatter-only key — a GitHub-shaped workflow's closed
587
+ root key set (`name`, `on`, `jobs`) has no extension surface for it, the
588
+ same reason it cannot declare `params:` either. See
589
+ [Workflow Schema: Workflow outputs](../reference/workflow-schema.md#workflow-outputs).
590
+
591
+ ## New commands
592
+
593
+ Both are read-only and zero-write — neither spawns anything, writes
594
+ history, or publishes a run. `akm workflow plan` is secret-free **by
595
+ construction**: it never prints a resolved reference value, request
596
+ content, script byte, or credential, because that data never reaches the
597
+ command in the first place. `akm task explain` instead **redacts**
598
+ secret-shaped input values on a best-effort heuristic basis (see below) —
599
+ a value that doesn't match the heuristic (short, low-entropy, or
600
+ unusually named) can still print unredacted, so don't treat its output as
601
+ a guaranteed-safe paste target.
602
+
603
+ **`akm workflow plan <ref>`** compiles, resolves, and freezes a workflow
604
+ exactly as starting a run would, then stops. It prints the canonical step
605
+ graph, per-step frozen target kinds, task/child expansion, input bindings,
606
+ the source read set, and freeze-time lowering notices.
607
+
608
+ ```sh
609
+ akm workflow plan release --format json
610
+ ```
611
+
612
+ Use it before committing to a run — especially after restructuring a
613
+ multi-job document into a composed set of workflows (above) — to confirm
614
+ the plan looks the way you expect, including which children it would
615
+ compose.
616
+
617
+ **`akm task explain <ref> [input flags]`** prints a task's source path and
618
+ version, its declared `inputs:` (with defaults — a secret-shaped default
619
+ prints as `<redacted>`), the supplied values with provenance
620
+ (`default` | `flag` | `schedule-binding`, likewise redacted when
621
+ secret-shaped), the resolved target kind/ref, effective execution settings
622
+ with field-level provenance, and schedule bindings.
623
+
624
+ ```sh
625
+ akm task explain nightly-review --scope all # doclint:ignore
626
+ ```
627
+
628
+ Its default output (no `--format` flag) is the same raw JSON as
629
+ `--format json`, byte for byte. `--format text` is a separate renderer: it
630
+ flattens the envelope into `dotted.path=value` lines instead of printing
631
+ JSON. See [Tasks: `akm task explain`](../reference/tasks.md#akm-task-explain).
632
+
633
+ ## Diagnostics
634
+
635
+ `INVALID_FLAG_VALUE` is now rare in task or workflow domain failures, with
636
+ two named exceptions (below). Every OTHER task-source, workflow-source,
637
+ target-classification, and composition failure now reports a
638
+ phase-specific code:
639
+
640
+ | Code | Domain |
641
+ |---|---|
642
+ | `TASK_SOURCE_INVALID` | A task document's field- or semantic-level validation failure, or a malformed/oversized/too-deep YAML front end failure. |
643
+ | `TASK_SCHEMA_VERSION_UNSUPPORTED` | A task document's `version:` is not `4` and is recognizable as a legacy generation (`3` or `2`). |
644
+ | `TARGET_REF_INVALID` | A value is not a canonical `commands/`, `scripts/`, `tasks/`, or `workflows/` asset ref (malformed shapes, GitHub locators, other asset families). |
645
+ | `WORKFLOW_SOURCE_INVALID` | A workflow-source compile failure other than the one below. |
646
+ | `COMPOSITION_INVALID` | A composition-policy rejection: a rejected `with:`, a multi-job document, a composition cycle/depth/size violation. |
647
+ | `INPUT_BINDING_INVALID` | A `with:` binding, or a task's declared `inputs:` flag, fails its schema or names something that doesn't exist. |
648
+ | `TASK_TARGET_UNSUPPORTED` | A recognized-but-unsupported task-execution construct (e.g. an interpreter task source v4 does not support). |
649
+ | `WORKFLOW_OUTPUT_INVALID` | A declared `outputs:` entry could not be resolved at run completion. |
650
+ | `WORKFLOW_IR_VERSION_UNSUPPORTED` | A stored plan predates `irVersion` 5 (see [Workflow cutover](#workflow-cutover)). |
651
+
652
+ Two failures are deliberately **not** re-coded and still report
653
+ `INVALID_FLAG_VALUE`, so an existing pinned test's code and message stay
654
+ byte-unchanged: a task's workflow-target `env:` composition rejection (a
655
+ `uses: workflows/<ref>` task that also authors `env:`), and a workflow
656
+ child-ref asset-resolution failure (`Workflow source target <ref> was not
657
+ found.`). Beyond those two, the remaining `INVALID_FLAG_VALUE` sites in the
658
+ task/workflow domains (38 total, across `src/tasks/**` and
659
+ `src/workflows/**`) are scalar CLI-argument parsing (a cron expression, a
660
+ task id, a workflow parameter flag) and one code-allowlist membership entry
661
+ — genuine flag-value validation, not a re-codable task/workflow source or
662
+ composition failure. **Scripts branching on `code` for a task/workflow
663
+ domain error should switch on the specific code above** rather than
664
+ assuming `INVALID_FLAG_VALUE` — except for the two named exceptions, which
665
+ still report `INVALID_FLAG_VALUE`. Exit codes are unchanged — every code
666
+ above is exit 2, same as before.
125
667
 
126
668
  ## Improve triage judgment
127
669
 
@@ -144,7 +686,14 @@ akm health
144
686
  ```
145
687
 
146
688
  Review scheduler changes before activation. Use `akm task sync --rebind` only
147
- when the installed runtime path intentionally changed.
689
+ when the installed runtime path intentionally changed. Spot-check a
690
+ migrated task or a restructured workflow with the two new read-only
691
+ commands before trusting it in production:
692
+
693
+ ```sh
694
+ akm task explain <migrated-task-ref>
695
+ akm workflow plan <restructured-workflow-ref>
696
+ ```
148
697
 
149
698
  See [Tasks](../reference/tasks.md), [Workflow schema](../reference/workflow-schema.md),
150
699
  and the [0.9.2 terminal migration note](release-notes/0.9.2.md).