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.
- package/CHANGELOG.md +493 -0
- package/STABILITY.md +23 -5
- package/dist/assets/hints/cli-hints-full.md +12 -7
- package/dist/assets/tasks/core/extract.yml +3 -5
- package/dist/assets/tasks/core/improve.yml +3 -5
- package/dist/assets/tasks/core/index-refresh.yml +3 -5
- package/dist/assets/tasks/core/sync.yml +3 -5
- package/dist/assets/tasks/core/version-check.yml +3 -5
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +3 -5
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -6
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +3 -5
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +3 -5
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +3 -5
- package/dist/cli/unknown-flags.js +12 -1
- package/dist/cli.js +8 -1
- package/dist/commands/command/command-execution.js +23 -2
- package/dist/commands/health/improve-metrics.js +38 -0
- package/dist/commands/health/windows.js +8 -4
- package/dist/commands/health.js +8 -4
- package/dist/commands/lint/index.js +1 -1
- package/dist/commands/migrate-cli.js +130 -24
- package/dist/commands/proposal/validators/proposal-validators.js +7 -2
- package/dist/commands/tasks/explain.js +304 -0
- package/dist/commands/tasks/tasks-cli.js +185 -3
- package/dist/commands/tasks/tasks.js +265 -52
- package/dist/commands/workflow/plan.js +159 -0
- package/dist/commands/workflow-cli.js +94 -2
- package/dist/core/activation-policy.js +2 -12
- package/dist/core/adapter/adapters/akm-lint.js +7 -4
- package/dist/core/adapter/adapters/akm-metadata.js +26 -14
- package/dist/core/adapter/adapters/akm-task-adapter.js +13 -10
- package/dist/core/errors.js +45 -0
- package/dist/core/json-schema.js +15 -5
- package/dist/core/state/migrations.js +57 -0
- package/dist/core/state-db.js +16 -14
- package/dist/core/subprocess.js +47 -13
- package/dist/execution/guarded-source.js +44 -0
- package/dist/execution/input-contract.js +250 -0
- package/dist/execution/target-ref.js +63 -0
- package/dist/indexer/usage/usage-events.js +14 -3
- package/dist/integrations/agent/execution-lowering.js +12 -1
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +12 -3
- package/dist/output/text/workflow-format.js +192 -10
- package/dist/output/text/workflow.js +2 -1
- package/dist/runtime.js +1 -0
- package/dist/scripts/akm-migrate-node.js +11838 -10118
- package/dist/scripts/akm-migrate.js +11828 -10117
- package/dist/setup/steps/tasks.js +34 -17
- package/dist/storage/repositories/task-history-repository.js +5 -1
- package/dist/storage/repositories/workflow-runs-repository.js +144 -6
- package/dist/tasks/backends/launchd.js +31 -84
- package/dist/tasks/embedded.js +13 -7
- package/dist/tasks/model/invocation.js +4 -0
- package/dist/tasks/prepare/prepare-script-target.js +9 -0
- package/dist/tasks/prepare/prepare-support.js +154 -0
- package/dist/tasks/prepare/prepare.js +117 -0
- package/dist/tasks/prepare/prepared-execution.js +4 -0
- package/dist/tasks/prepare/script-capture.js +80 -0
- package/dist/tasks/run/attempt-lifecycle.js +165 -0
- package/dist/tasks/run/load-task.js +117 -0
- package/dist/tasks/run/provenance.js +20 -0
- package/dist/tasks/run/run-command-task.js +92 -0
- package/dist/tasks/run/run-native-task.js +222 -0
- package/dist/tasks/run/run-task.js +99 -0
- package/dist/tasks/run/run-workflow-task.js +222 -0
- package/dist/tasks/run/task-history.js +134 -0
- package/dist/tasks/run/task-log.js +179 -0
- package/dist/tasks/run/task-result.js +19 -0
- package/dist/tasks/scheduler-binding.js +66 -2
- package/dist/tasks/scheduler-invocation.js +63 -3
- package/dist/tasks/scheduler-sync.js +77 -14
- package/dist/tasks/source/bounded-document.js +455 -0
- package/dist/tasks/source/parse-task-source.js +59 -0
- package/dist/tasks/source/project-v4.js +62 -0
- package/dist/tasks/source/task-input-diagnostics.js +36 -0
- package/dist/tasks/source/task-source-v4.js +626 -0
- package/dist/tasks/source-v3.js +10 -733
- package/dist/tasks/task-run-reserved-flags.js +79 -0
- package/dist/workflows/authoring/authoring.js +17 -8
- package/dist/workflows/exec/child-invocation.js +34 -0
- package/dist/workflows/exec/child-workflow.js +370 -0
- package/dist/workflows/exec/exec-unit.js +50 -170
- package/dist/workflows/exec/frozen-judge.js +19 -2
- package/dist/workflows/exec/native-executor.js +49 -27
- package/dist/workflows/exec/param-secrets.js +12 -0
- package/dist/workflows/exec/run-workflow.js +48 -59
- package/dist/workflows/exec/step-work.js +222 -80
- package/dist/workflows/exec/unit-dispatch.js +72 -0
- package/dist/workflows/freeze/child-output-references.js +94 -0
- package/dist/workflows/freeze/environment.js +174 -0
- package/dist/workflows/freeze/identity.js +22 -0
- package/dist/workflows/freeze/resolve-steps.js +78 -0
- package/dist/workflows/freeze/source-freeze.js +57 -0
- package/dist/workflows/freeze/step-values.js +68 -0
- package/dist/workflows/freeze/targets/child-workflow.js +206 -0
- package/dist/workflows/freeze/targets/command.js +81 -0
- package/dist/workflows/freeze/targets/script.js +57 -0
- package/dist/workflows/freeze/targets/shell.js +31 -0
- package/dist/workflows/freeze/targets/task.js +179 -0
- package/dist/workflows/freeze/task-bindings.js +180 -0
- package/dist/workflows/ir/compile.js +59 -11
- package/dist/workflows/ir/environment-v4.js +3 -3
- package/dist/workflows/ir/freeze-v4.js +41 -7
- package/dist/workflows/ir/params.js +58 -131
- package/dist/workflows/ir/plan-hash.js +3 -3
- package/dist/workflows/ir/schema-v4.js +246 -17
- package/dist/workflows/parser.js +74 -2
- package/dist/workflows/program/schema.js +5 -2
- package/dist/workflows/resource-limits.js +20 -0
- package/dist/workflows/runtime/plan-classifier.js +24 -7
- package/dist/workflows/runtime/run-outputs.js +103 -0
- package/dist/workflows/runtime/runs.js +114 -9
- package/dist/workflows/runtime/workflow-asset-loader.js +14 -6
- package/dist/workflows/source-files.js +5 -5
- package/dist/workflows/source-ir/compare.js +17 -0
- package/dist/workflows/source-ir/compile.js +7 -3
- package/dist/workflows/source-ir/github-yaml.js +64 -17
- package/dist/workflows/source-ir/schema.js +69 -21
- package/dist/workflows/source-ir/semantics.js +7 -25
- package/dist/workflows/source-ir/triggers.js +79 -0
- package/dist/workflows/source-ir/uses.js +33 -7
- package/docs/migration/README.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +87 -11
- package/docs/migration/release-notes/README.md +3 -2
- package/docs/migration/v0.8-to-v0.9.md +13 -11
- package/docs/migration/v0.9.0-troubleshooting.md +20 -13
- package/docs/migration/v0.9.1-to-v0.9.2.md +598 -49
- package/docs/reference/README.md +1 -1
- package/docs/reference/cli.md +140 -46
- package/docs/reference/configuration.md +6 -5
- package/docs/reference/supported-formats.md +9 -5
- package/docs/reference/tasks.md +338 -75
- package/docs/reference/workflow-schema.md +290 -16
- package/docs/reference/workflows.md +57 -7
- package/package.json +1 -1
- package/schemas/akm-task.json +173 -118
- package/schemas/akm-workflow.json +28 -0
- package/dist/tasks/runner.js +0 -941
- package/dist/tasks/runtime-v3.js +0 -281
- package/dist/workflows/ir/source-freeze-v4.js +0 -506
- package/dist/workflows/source-ir/ordering.js +0 -38
|
@@ -59,29 +59,234 @@ jobs:
|
|
|
59
59
|
ref: commands/review
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
AKM's public position on this format: **AKM YAML uses a familiar
|
|
63
|
+
GitHub-step-shaped syntax but is an AKM workflow format, executed by AKM's
|
|
64
|
+
native engine.** It is not Marketplace-action-compatible, does not evaluate
|
|
65
|
+
GitHub expressions or contexts, has no hosted runner images or service
|
|
66
|
+
containers, and does not execute multiple jobs.
|
|
67
|
+
|
|
62
68
|
The accepted 0.9.2 subset is deliberately closed:
|
|
63
69
|
|
|
64
70
|
- `on` accepts five-field `schedule` entries and an empty or null
|
|
65
71
|
`workflow_dispatch`; workflow_dispatch inputs are unsupported.
|
|
66
72
|
- Service events are rejected.
|
|
67
73
|
A rejected service event creates no watcher and no polling daemon.
|
|
74
|
+
- **`jobs:` must contain exactly one job.** A document with zero, two, or
|
|
75
|
+
more jobs fails at the adapter with reason `multi-job-unsupported`,
|
|
76
|
+
surfaced as `UsageError` code `COMPOSITION_INVALID` when the workflow is
|
|
77
|
+
frozen (`akm workflow run` or `akm workflow plan`). Split a multi-job
|
|
78
|
+
document into separate single-job workflows and compose them with a
|
|
79
|
+
child-workflow step (`uses: workflows/<ref>`) instead. A job's `needs:`
|
|
80
|
+
must be empty — a non-empty `needs:` fails for the same reason, since a
|
|
81
|
+
single job has nothing to depend on.
|
|
68
82
|
- Each job requires exactly `runs-on: [self-hosted]`. `name`, `needs`, and
|
|
69
83
|
`steps` are the remaining job fields.
|
|
70
84
|
- Each step requires `id` and exactly one `uses` or `run`; optional fields are
|
|
71
85
|
`name`, `with`, `env`, `shell`, and contained `working-directory`.
|
|
72
86
|
- A `run` accepts only token-safe local command tokens.
|
|
73
87
|
Shell expansion and operators are unsupported and rejected, even when a host shell is named.
|
|
74
|
-
- `uses`
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
- `uses` is classified as a canonical asset ref (`commands/`, `scripts/`,
|
|
89
|
+
`tasks/`, `workflows/`), plus the `akm/command` builtin. `akm/command`,
|
|
90
|
+
command, script, task, and **child-workflow** composition are local
|
|
91
|
+
targets — see [Child workflows](#child-workflows) for `uses:
|
|
92
|
+
workflows/<ref>`.
|
|
93
|
+
Local actions and Docker actions are unsupported and rejected (including
|
|
94
|
+
`./` and `docker://`); a GitHub Action locator (`owner/repo[/path]@ref`,
|
|
95
|
+
e.g. `actions/checkout@v4`) and every other unrecognized shape fail the
|
|
96
|
+
same way — `unsupported-uses-target` — since AKM never acquires or
|
|
97
|
+
executes a remote action. AKM does not recognize the locator grammar as a
|
|
98
|
+
distinct case; it is simply not one of the four canonical asset-ref
|
|
99
|
+
families or the `akm/command` builtin.
|
|
100
|
+
- `with:` on a **task-composed** step (`uses: tasks/<ref>`) **binds** the
|
|
101
|
+
target task source's declared `inputs:` — see
|
|
102
|
+
[Typed inputs and output](tasks.md#typed-inputs-and-output). Each value is either a literal
|
|
103
|
+
(validated against the input's declared schema at freeze) or a reference
|
|
104
|
+
`{from: "steps.<id>.output(.<segment>)*"}`, resolved just before the unit
|
|
105
|
+
dispatches and re-validated against the same schema then. The reference
|
|
106
|
+
grammar also accepts `{from: "params.<name>"}`, naming a declared param of
|
|
107
|
+
the *composing* workflow itself — but a composing step is only authorable
|
|
108
|
+
in a GitHub-shaped document (this section), whose root keys are exactly
|
|
109
|
+
`name`, `on`, and `jobs` with `workflow_dispatch` inputs rejected, so it
|
|
110
|
+
can never declare `params:` of its own. In practice that reference form
|
|
111
|
+
therefore always fails freeze here, with "does not name a declared
|
|
112
|
+
workflow param; declared params: (none)". An unknown `with:` key, a
|
|
113
|
+
missing required input with no default, or a reference naming a step that
|
|
114
|
+
doesn't exist earlier in the job all fail at **freeze** with `UsageError`
|
|
115
|
+
code `INPUT_BINDING_INVALID`, before the plan is ever published. If the
|
|
116
|
+
target task declares **no** `inputs:` at all (a `version: 4` task with no
|
|
117
|
+
`inputs:` key) — or the step targets
|
|
118
|
+
`uses: commands/<ref>` / `uses: scripts/<ref>`, which are never binding
|
|
119
|
+
surfaces — any authored
|
|
120
|
+
`with:`, including an empty mapping (`with: {}`), is rejected at freeze
|
|
121
|
+
with `UsageError` code `COMPOSITION_INVALID`, exit 2. Omitting `with:`
|
|
122
|
+
entirely always freezes normally, regardless of target. `with:` on
|
|
123
|
+
`uses: akm/command` is unaffected by any of this and is still required to
|
|
124
|
+
supply the builtin action's arguments, as in the example above. `with:` on
|
|
125
|
+
a **child-workflow** target (direct or task-wrapped) binds the child's
|
|
126
|
+
declared `params:` instead of `inputs:` — see
|
|
127
|
+
[Child workflows](#child-workflows).
|
|
78
128
|
- GitHub expressions and contexts are unsupported and rejected anywhere in
|
|
79
129
|
the parsed tree.
|
|
80
130
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
131
|
+
## Child workflows
|
|
132
|
+
|
|
133
|
+
A step can compose another workflow, two ways. Composition is authored only
|
|
134
|
+
through the GitHub-shaped `jobs.<id>.steps[].uses` surface — the composing
|
|
135
|
+
(parent) document must be GitHub-shaped YAML, since the Markdown-frontmatter
|
|
136
|
+
step schema has no `uses:` key at all (see [Source formats and shared
|
|
137
|
+
IR](#source-formats-and-shared-ir)). The **child** workflow being composed
|
|
138
|
+
may itself be authored in either format, Markdown or GitHub-shaped:
|
|
139
|
+
|
|
140
|
+
- **Direct** — `uses: workflows/<ref>`:
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
- id: dispatch
|
|
144
|
+
uses: workflows/release-checklist
|
|
145
|
+
with:
|
|
146
|
+
channel: stable
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- **Task-wrapped** — `uses: tasks/<ref>` where `<ref>` names a task source
|
|
150
|
+
v4 document whose own target is a workflow. The task's own effective
|
|
151
|
+
`inputs:` (its declared defaults plus whatever the *task's own* callers
|
|
152
|
+
bound) supply the child's params; a `with:` authored on the *workflow
|
|
153
|
+
step itself* binds on top of that, exactly as it would for a direct step.
|
|
154
|
+
|
|
155
|
+
Both forms bind against the child workflow's own declared `params:`
|
|
156
|
+
frontmatter key — **not** a task's `inputs:` contract, since a workflow has
|
|
157
|
+
no `inputs:`. `with:` follows the same grammar as everywhere else in this
|
|
158
|
+
document: each value is a literal (validated against the param's declared
|
|
159
|
+
type at freeze) or a `{from: "steps.<id>.output(.<segment>)*"}` reference,
|
|
160
|
+
resolved just before the unit dispatches. (The grammar also accepts
|
|
161
|
+
`{from: "params.<name>"}`, naming a declared param of the *composing*
|
|
162
|
+
workflow — but that form is unreachable here for the same reason noted
|
|
163
|
+
above: the composing document is necessarily GitHub-shaped, so it never
|
|
164
|
+
declares `params:` of its own.) An unknown key or an invalid reference
|
|
165
|
+
fails at freeze with `UsageError` code `INPUT_BINDING_INVALID`, exactly like
|
|
166
|
+
a task-composed step's `with:`.
|
|
167
|
+
|
|
168
|
+
### Frozen before publication
|
|
169
|
+
|
|
170
|
+
Composing a child workflow is not a runtime call — it is a **freeze-time**
|
|
171
|
+
resolution. When the parent workflow's plan is frozen, AKM loads the child's
|
|
172
|
+
source, compiles it, validates it, and freezes the child's own complete plan
|
|
173
|
+
*before the parent run is published*. The result is embedded whole inside
|
|
174
|
+
the parent step's frozen target (`kind: "child-workflow"`); nothing about the
|
|
175
|
+
child is re-read at dispatch time. Concretely:
|
|
176
|
+
|
|
177
|
+
- Editing the child's source **after** the parent run has started has no
|
|
178
|
+
effect on that run — the parent already carries its own frozen copy of the
|
|
179
|
+
child's plan.
|
|
180
|
+
- Editing the child's source in the narrow window **between** the parent's
|
|
181
|
+
freeze and its publication fails the whole parent publication atomically,
|
|
182
|
+
with no run row written — the same source-race protection that already
|
|
183
|
+
covers the parent's own command/script/task sources extends to every
|
|
184
|
+
transitive child source file.
|
|
185
|
+
- The child's *own* source files (its workflow document plus every
|
|
186
|
+
command/script/task it in turn resolves) become part of the parent run's
|
|
187
|
+
guarded source read set, exactly like any other source the parent
|
|
188
|
+
workflow depends on.
|
|
189
|
+
|
|
190
|
+
See [Architecture: The Workflow Engine](https://github.com/itlackey/akm/blob/main/docs/architecture/workflow-engine.md#child-workflows)
|
|
191
|
+
for the embedded-plan integrity chain (`irVersion`, `planHash`,
|
|
192
|
+
`contentHash`) and why a tampered embedded child plan fails to decode.
|
|
193
|
+
|
|
194
|
+
### Composition limits
|
|
195
|
+
|
|
196
|
+
Three bounds are enforced at **freeze**, before the parent run is published,
|
|
197
|
+
each failing with `UsageError` code `COMPOSITION_INVALID` (exit 2):
|
|
198
|
+
|
|
199
|
+
| Limit | Value | Message names |
|
|
200
|
+
| --- | --- | --- |
|
|
201
|
+
| Composition depth | 8 levels below the root | the limit and the ref path, e.g. `Workflow step <id> cannot compose <ref>: workflow composition is limited to 8 levels. Path: <a -> b -> …>.` |
|
|
202
|
+
| Cycle detection | a workflow (direct or task-wrapped) reaching itself through any chain | the cycle path, e.g. `Workflow step <id> cannot compose <ref>: that would create a composition cycle. Path: <a -> tasks/w -> b -> a>.` |
|
|
203
|
+
| Aggregate embedded plan bytes | 1 MiB total, summed across every embedded descendant of one root freeze | the cap and the running total, e.g. `Workflow step <id> cannot compose <ref>: the embedded child plans would total <N> bytes, over the <cap>-byte limit for one workflow run.` |
|
|
204
|
+
|
|
205
|
+
The same workflow reached twice through disjoint branches (a diamond, not a
|
|
206
|
+
cycle) is not a violation — each occurrence embeds its own independent copy;
|
|
207
|
+
deduplicating identical embedded plans is not implemented. A step whose
|
|
208
|
+
`uses: workflows/<ref>` (or task-wrapped equivalent) does not resolve to a
|
|
209
|
+
real asset fails with the ordinary asset-resolution error, unchanged by any
|
|
210
|
+
of this.
|
|
211
|
+
|
|
212
|
+
### Child execution
|
|
213
|
+
|
|
214
|
+
Running a step whose own target is `kind: "child-workflow"` publishes (or
|
|
215
|
+
finds, if one already exists — see "Identity and retries" below) a child
|
|
216
|
+
run and drives it to completion, or as far as it gets, before the parent
|
|
217
|
+
step is finalized. The drive happens **inline, in the parent's own
|
|
218
|
+
process**: it is the same engine `akm workflow run` uses on the child's
|
|
219
|
+
frozen plan, not a separately scheduled job. Consequently, whatever aborts
|
|
220
|
+
the parent's own dispatch — `Ctrl-C`, a `--timeout`, a budget ceiling, or
|
|
221
|
+
the parent losing its run lease — also aborts the child drive; both runs
|
|
222
|
+
are left resumable, never partially torn down.
|
|
223
|
+
|
|
224
|
+
The child's final status maps onto the composing step and the parent run:
|
|
225
|
+
|
|
226
|
+
| Child status | Composing step | Parent run |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| `completed` | completes; its output is the child's exported result — its declared `outputs:` (see [What a step's output is](#what-a-steps-output-is)), or `{runId, status}` when the child declares none | continues |
|
|
229
|
+
| `failed` | `failed` | `failed` |
|
|
230
|
+
| `blocked` | `blocked` | `blocked` |
|
|
231
|
+
| aborted mid-drive (parent cancelled/timed out/lost its lease) | left unfinished, not finalized | active and resumable |
|
|
232
|
+
| the child could not be published or its plan failed an integrity re-check | `failed` | `failed` |
|
|
233
|
+
| another process already holds the child's run lease | `failed` | `failed` |
|
|
234
|
+
|
|
235
|
+
**Blocked-child recovery.** A blocked child blocks its composing step —
|
|
236
|
+
`akm` does not resume a child for you, because a gate is a gate for a
|
|
237
|
+
child workflow too. The step's notes name the exact three-command
|
|
238
|
+
sequence: resume the **child** first, then resume and re-run the
|
|
239
|
+
**parent** — re-driving the parent is what advances it, because that is
|
|
240
|
+
what re-enters the composing step and drives the now-resumed child:
|
|
241
|
+
|
|
242
|
+
```sh
|
|
243
|
+
akm workflow resume <childRunId>
|
|
244
|
+
akm workflow resume <parentRunId>
|
|
245
|
+
akm workflow run <parentRunId>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Nested blocks (composition depth 2+).** The three-command sequence above
|
|
249
|
+
clears a block exactly one level deep. It does **not** generalize to a
|
|
250
|
+
grandchild block (root composes child, child composes grandchild, grandchild
|
|
251
|
+
blocks): re-driving the root does not cascade down into re-driving the
|
|
252
|
+
still-blocked grandchild, because a composing step never re-drives a child
|
|
253
|
+
whose own status is already `blocked` — re-running the root just re-observes
|
|
254
|
+
the child's own block and re-blocks the root the same way, without the
|
|
255
|
+
grandchild ever being reached. Resume every blocked run in the chain,
|
|
256
|
+
**deepest first**, then re-run only the root:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
akm workflow resume <grandchildRunId>
|
|
260
|
+
akm workflow resume <childRunId>
|
|
261
|
+
akm workflow resume <rootRunId>
|
|
262
|
+
akm workflow run <rootRunId>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The status tree's own `resume`/`then` commands on a deeply nested node still
|
|
266
|
+
name only that node and the root, never an intermediate ancestor — read the
|
|
267
|
+
tree and resume every `blocked` row before re-running the root.
|
|
268
|
+
|
|
269
|
+
**Identity and retries.** A child run's identity is keyed by the parent run,
|
|
270
|
+
the parent unit, and that unit's input hash — publishing is idempotent, so
|
|
271
|
+
re-driving the composing step (an explicit `akm workflow resume` +
|
|
272
|
+
`akm workflow run`, or a `retry:` policy on the step) finds and continues
|
|
273
|
+
the **same** child run rather than starting a new one. Only a change to the
|
|
274
|
+
composing step's own inputs (params, upstream step outputs it reads, or gate
|
|
275
|
+
feedback from a rejected verification loop) produces a different child.
|
|
276
|
+
|
|
277
|
+
**Visibility.** `akm workflow status` on a run that composes children
|
|
278
|
+
renders a `children:` tree — every descendant run's ref, status, and, for a
|
|
279
|
+
blocked child, its resume command — recursively to the same 8-level
|
|
280
|
+
composition-depth bound described above. Child runs are excluded from `akm
|
|
281
|
+
workflow list` by default; pass `--children` to include them. A child run
|
|
282
|
+
id always works directly with `akm workflow status`/`resume`/`abandon`/`run`,
|
|
283
|
+
listed or not. See
|
|
284
|
+
[Running Workflows: Child runs](https://github.com/itlackey/akm/blob/main/docs/guides/run-workflows.md#child-runs) for a
|
|
285
|
+
worked example, and
|
|
286
|
+
[Architecture: The Workflow Engine](https://github.com/itlackey/akm/blob/main/docs/architecture/workflow-engine.md#child-workflows)
|
|
287
|
+
for the dispatch seam and why reusing the top-level run engine (rather than a
|
|
288
|
+
second executor) is what makes the identity and abort-propagation rules above
|
|
289
|
+
hold for free.
|
|
85
290
|
|
|
86
291
|
## Frontmatter keys
|
|
87
292
|
|
|
@@ -99,6 +304,9 @@ families) plus the orchestration keys:
|
|
|
99
304
|
than dropping the settings for that step. There is no per-step opt-out (`llm:
|
|
100
305
|
{}` is a no-op and `llm: null` is a parse error), so in a mixed document put
|
|
101
306
|
`llm:` on the `unit:` of each LLM step instead of in `defaults:`.
|
|
307
|
+
- `outputs` — name → `{ from, schema? }`, a run-level export projected from
|
|
308
|
+
a step's own artifact (Markdown-only; see [Workflow
|
|
309
|
+
outputs](#workflow-outputs) below).
|
|
102
310
|
- `budget` — run-lifetime ceilings (`max_units`, `max_tokens`; see
|
|
103
311
|
[Budget ceilings](#budget-ceilings) below).
|
|
104
312
|
- `steps` — an ordered list. Each step has an `id`
|
|
@@ -364,6 +572,70 @@ that declares an `output` schema is unaffected — an empty response is not
|
|
|
364
572
|
valid JSON, so it fails as a parse error and can never satisfy a schema as a
|
|
365
573
|
silent `null`.
|
|
366
574
|
|
|
575
|
+
## Workflow outputs
|
|
576
|
+
|
|
577
|
+
A workflow can declare a run-level export: the values a **completed run**
|
|
578
|
+
promotes, projected from its steps' own artifacts. This is a Markdown
|
|
579
|
+
frontmatter key, `outputs:`:
|
|
580
|
+
|
|
581
|
+
```yaml
|
|
582
|
+
outputs:
|
|
583
|
+
report:
|
|
584
|
+
from: steps.summarize.output
|
|
585
|
+
changed_count:
|
|
586
|
+
from: steps.collect.output.total
|
|
587
|
+
schema: { type: integer, minimum: 0 }
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Each entry is a mapping of exactly `from` (required) and `schema`
|
|
591
|
+
(optional):
|
|
592
|
+
|
|
593
|
+
- `from` is a `steps.<id>.output(.<segment>)*` reference into a step's own
|
|
594
|
+
artifact — the same reference grammar `with:`/`inputs:` use elsewhere in
|
|
595
|
+
this document — naming a declared step. `from: params.<name>` is
|
|
596
|
+
rejected: a run's exports come from what its steps produced, not from its
|
|
597
|
+
input params verbatim.
|
|
598
|
+
- `schema`, when present, is validated against the same [enforced JSON
|
|
599
|
+
Schema subset](#the-enforced-json-schema-subset) as a step's own `output:`
|
|
600
|
+
schema, and is bound by the same limit: at most 256 KiB.
|
|
601
|
+
- Output names follow the same pattern as params, `^[A-Za-z_][A-Za-z0-9_]*$`,
|
|
602
|
+
and a workflow may declare at most 64.
|
|
603
|
+
|
|
604
|
+
**This is a Markdown-only key.** GitHub-shaped YAML's root is a closed set —
|
|
605
|
+
`name`, `on`, `jobs` — with no extension surface, the same reason a
|
|
606
|
+
GitHub-shaped workflow cannot declare `params:` either. Composition itself
|
|
607
|
+
is unaffected: the *composing* (parent) document must still be GitHub-shaped
|
|
608
|
+
(only `jobs.<id>.steps[].uses` composes — see [Child
|
|
609
|
+
workflows](#child-workflows)), and the *composed* (child) may be either
|
|
610
|
+
format — but a child that wants to export more than `{runId, status}` must
|
|
611
|
+
be authored in Markdown.
|
|
612
|
+
|
|
613
|
+
**Different from a step's own `output:` schema.** A step's `output:` (see
|
|
614
|
+
[Typed step artifacts](#typed-step-artifacts) below) is a typed-artifact
|
|
615
|
+
contract on *one step*, enforced and retryable through that step's own gate
|
|
616
|
+
loop. A workflow's `outputs:` is a *run-level export projection* over
|
|
617
|
+
already-promoted step artifacts, resolved once, after every step has
|
|
618
|
+
finished. They compose freely: a step can declare `output:` and the
|
|
619
|
+
workflow's `outputs:` can project that same step's artifact under an export
|
|
620
|
+
name.
|
|
621
|
+
|
|
622
|
+
**Resolution happens once, at run completion**, over the run's persisted
|
|
623
|
+
step evidence — never re-evaluated afterward. If a declared `from` cannot
|
|
624
|
+
be resolved, reads a step artifact that was too large to persist in full, or
|
|
625
|
+
its resolved value fails its declared `schema`, run completion itself
|
|
626
|
+
rolls back: the run stays `active`, its final step stays `pending`, and no
|
|
627
|
+
event is emitted. Fix the declaration (or the step that produces the value)
|
|
628
|
+
and the next completion attempt resolves outputs again — a bad `outputs:`
|
|
629
|
+
entry cannot silently strand a run as `completed` with missing exports.
|
|
630
|
+
|
|
631
|
+
**What a completed run exports.** A run with an `outputs:` declaration
|
|
632
|
+
exports exactly those resolved values. A run with none exports
|
|
633
|
+
`{runId, status}` instead — synthesized whenever it is read, never
|
|
634
|
+
persisted. This is what a parent step composing this workflow as a child
|
|
635
|
+
sees at `steps.<id>.output`: see [Child execution](#child-execution) for how
|
|
636
|
+
a composing step's own reference into a child's exports is checked at
|
|
637
|
+
freeze time.
|
|
638
|
+
|
|
367
639
|
## Typed step artifacts
|
|
368
640
|
|
|
369
641
|
When a step declares `output`, the promoted step artifact (the unit's
|
|
@@ -627,6 +899,7 @@ context blocks a model unit gets in its prompt:
|
|
|
627
899
|
| `AKM_PARAMS` | the run params, canonical JSON |
|
|
628
900
|
| `AKM_ITEM`, `AKM_ITEM_INDEX` | a `map` unit's item (canonical JSON) and 0-based index |
|
|
629
901
|
| `AKM_INPUTS` | the step's declared `inputs:` artifacts, keyed by reference string |
|
|
902
|
+
| `AKM_TASK_INPUTS` | a task-composed step's resolved `with:` bindings (canonical JSON), present only when the bindings are non-empty |
|
|
630
903
|
|
|
631
904
|
These are applied *after* your `env:` bindings, so a binding can never shadow
|
|
632
905
|
them.
|
|
@@ -748,16 +1021,17 @@ a committed *value*, so it cannot carry "whatever this build agent's
|
|
|
748
1021
|
Values passed through this way are **not** redacted from the command's output
|
|
749
1022
|
the way `env:` binding values are, so never list a credential here.
|
|
750
1023
|
|
|
751
|
-
#### Durable v4 forbids `inherit_env`
|
|
1024
|
+
#### Durable v4 (`irVersion: 5`) forbids `inherit_env`
|
|
752
1025
|
|
|
753
|
-
Every new workflow start freezes
|
|
754
|
-
`inherit_env: true` and any other
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
part of the unit's input hash.
|
|
1026
|
+
Every new workflow start freezes the durable plan v4 family's current
|
|
1027
|
+
executable format, `irVersion: 5`. It rejects `inherit_env: true` and any other
|
|
1028
|
+
request for whole-process inheritance; use exact named environment bindings
|
|
1029
|
+
and `pass_env:` instead. Both mechanisms are dispatch-significant, keep the
|
|
1030
|
+
visible environment surface bounded, and form part of the unit's input hash.
|
|
758
1031
|
|
|
759
|
-
The historical `inherit_env` spelling is unsupported. Pre
|
|
760
|
-
rejected; they are never upgraded or replayed through a second
|
|
1032
|
+
The historical `inherit_env` spelling is unsupported. Pre-`irVersion`-5 stored
|
|
1033
|
+
plans are rejected; they are never upgraded or replayed through a second
|
|
1034
|
+
runtime.
|
|
761
1035
|
|
|
762
1036
|
### What `akm show` reports for an exec step
|
|
763
1037
|
|
|
@@ -46,20 +46,70 @@ artifacts, and exec vocabulary. The YAML adapter accepts the documented local
|
|
|
46
46
|
`name`/`on`/`jobs` subset. `.yaml` is not a workflow source.
|
|
47
47
|
|
|
48
48
|
Both adapters produce strict source IR version 1. New starts resolve source
|
|
49
|
-
owners and executable targets, then freeze durable plan
|
|
50
|
-
|
|
49
|
+
owners and executable targets, then freeze durable plan `irVersion` 5. Only
|
|
50
|
+
the current `irVersion` executes: a run frozen at an older version keeps
|
|
51
|
+
`status`, `list`, and `abandon` working, but `resume`/`next`/`complete`/`run`
|
|
52
|
+
fail closed — abandon it and start a new run from current source. See
|
|
53
|
+
[Architecture: The Workflow Engine](https://github.com/itlackey/akm/blob/main/docs/architecture/workflow-engine.md#resume-is-journaled-replay)
|
|
54
|
+
for the exact policy and
|
|
55
|
+
[Migrating from akm 0.9.1 to 0.9.2](https://github.com/itlackey/akm/blob/main/docs/migration/v0.9.1-to-v0.9.2.md#workflow-cutover)
|
|
56
|
+
if you are upgrading with runs in flight.
|
|
57
|
+
|
|
58
|
+
A step can compose another workflow as a child — directly
|
|
59
|
+
(`uses: workflows/<ref>`) or through a task whose own target is a workflow
|
|
60
|
+
(`uses: tasks/<ref>`) — frozen completely into the parent's plan before the
|
|
61
|
+
parent run is published. See
|
|
62
|
+
[Workflow Schema: Child workflows](../reference/workflow-schema.md#child-workflows)
|
|
63
|
+
for both forms and their limits. Running a step that composes a child
|
|
64
|
+
workflow drives that child to completion (or as far as it gets) with the
|
|
65
|
+
same engine the parent uses, then maps the child's final status onto the
|
|
66
|
+
composing step: a completed child promotes its declared `outputs:` (or
|
|
67
|
+
`{runId, status}` when it declares none) as the step's own output and the
|
|
68
|
+
parent continues; a failed child fails the step and the run; a blocked
|
|
69
|
+
child blocks the composing step and the run, with recovery notes naming the
|
|
70
|
+
exact `akm workflow resume`/`akm workflow run` sequence. `akm workflow
|
|
71
|
+
status` on a run that composes children renders a `children:` tree showing
|
|
72
|
+
every descendant run's ref and status. See
|
|
73
|
+
[Workflow Schema: Child execution](../reference/workflow-schema.md#child-execution)
|
|
74
|
+
for the full status mapping and the blocked-child recovery flow, and
|
|
75
|
+
[Running Workflows: Child runs](https://github.com/itlackey/akm/blob/main/docs/guides/run-workflows.md#child-runs) for a
|
|
76
|
+
walkthrough.
|
|
77
|
+
|
|
78
|
+
## Workflow outputs
|
|
79
|
+
|
|
80
|
+
A workflow may declare a run-level export in its Markdown frontmatter —
|
|
81
|
+
`outputs: {<name>: {from: steps.<id>.output(.<segment>)*, schema?}}`, up to
|
|
82
|
+
64 entries — resolved once, from persisted step evidence, at run
|
|
83
|
+
completion. A run with no `outputs:` declaration exports `{runId, status}`
|
|
84
|
+
instead; a composing parent step promotes a completed child's `outputs:`
|
|
85
|
+
(or that same `{runId, status}` fallback) as its own step output — see
|
|
86
|
+
[Workflow Schema: Workflow outputs](../reference/workflow-schema.md#workflow-outputs).
|
|
87
|
+
|
|
88
|
+
## Inspecting a workflow without running it
|
|
89
|
+
|
|
90
|
+
`akm workflow plan <ref>` compiles, resolves, and freezes a workflow exactly
|
|
91
|
+
as starting a run would, then stops — zero durable writes, no published run.
|
|
92
|
+
It prints the canonical step graph, per-step frozen target kinds,
|
|
93
|
+
task/child expansion, input bindings, and freeze-time lowering notices, and
|
|
94
|
+
is secret-free by construction. Use it to check what a workflow would
|
|
95
|
+
actually do — including which child workflows it would compose — before
|
|
96
|
+
committing to a run. See
|
|
97
|
+
[CLI reference: workflow plan](cli.md#workflow-plan).
|
|
51
98
|
|
|
52
99
|
## Unsupported boundary and 0.9.3
|
|
53
100
|
|
|
54
101
|
The 0.9.2 GitHub-shaped adapter is a local interoperability seam, not GitHub
|
|
55
102
|
Actions. Full GitHub expressions and contexts, local/Docker/remote actions,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
103
|
+
service events, and arbitrary hosted runners remain outside 0.9.2.
|
|
104
|
+
**Multi-job YAML is rejected outright** — `jobs:` must contain exactly one
|
|
105
|
+
job; a document with zero, two, or more jobs fails to compile at all (it is
|
|
106
|
+
not "indexed but not executed" — it never becomes a valid workflow). Split a
|
|
107
|
+
multi-job source into single-job workflows and compose them with a
|
|
108
|
+
child-workflow step instead. AKM neither fetches remote actions nor creates
|
|
109
|
+
event watchers or polling daemons.
|
|
59
110
|
|
|
60
111
|
These full GitHub semantics, actions, service events, and runner behaviors are
|
|
61
|
-
explicit 0.9.3-or-later work.
|
|
62
|
-
event watchers or polling daemons in the meantime.
|
|
112
|
+
explicit 0.9.3-or-later work.
|
|
63
113
|
|
|
64
114
|
Version 0.9.3 may extend full GitHub expressions and contexts, actions,
|
|
65
115
|
service events, and runners; none of those capabilities is implied by 0.9.2.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.2
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
|
|
6
6
|
"keywords": [
|