akm-cli 0.9.0 → 0.9.1-beta.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 +724 -0
- package/README.md +28 -63
- package/STABILITY.md +4 -2
- package/dist/cli/parse-args.js +7 -1
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/env/child-env.js +14 -0
- package/dist/commands/feedback-cli.js +7 -1
- package/dist/commands/health/llm-usage.js +2 -1
- package/dist/commands/health/surfaces.js +4 -77
- package/dist/commands/health.js +65 -11
- package/dist/commands/improve/distill/quality-gate.js +6 -1
- package/dist/commands/improve/eligibility.js +7 -1
- package/dist/commands/improve/eval-cases.js +2 -0
- package/dist/commands/improve/improve.js +126 -10
- package/dist/commands/improve/locks.js +7 -0
- package/dist/commands/improve/memory/memory-improve.js +9 -0
- package/dist/commands/improve/run-context.js +5 -0
- package/dist/commands/improve/session-asset.js +4 -0
- package/dist/commands/lint/base-linter.js +31 -7
- package/dist/commands/lint/index.js +205 -51
- package/dist/commands/lint/types.js +22 -1
- package/dist/commands/proposal/repository.js +17 -1
- package/dist/commands/sources/add-cli.js +8 -2
- package/dist/commands/sources/info.js +12 -2
- package/dist/commands/sources/installed-stashes.js +6 -1
- package/dist/commands/sources/migration-help.js +12 -3
- package/dist/commands/sources/self-update.js +9 -1
- package/dist/commands/tasks/tasks.js +8 -2
- package/dist/commands/workflow-cli.js +17 -11
- package/dist/core/abort-deadline.js +28 -0
- package/dist/core/adapter/adapters/agent-skills-adapter.js +83 -5
- package/dist/core/adapter/adapters/akm-adapter.js +13 -10
- package/dist/core/adapter/adapters/akm-lint.js +78 -22
- package/dist/core/adapter/adapters/akm-task-adapter.js +43 -20
- package/dist/core/adapter/adapters/dotenv-adapter.js +21 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +5 -3
- package/dist/core/asset/frontmatter.js +10 -1
- package/dist/core/common.js +147 -9
- package/dist/core/concurrent.js +32 -0
- package/dist/core/config/config-io.js +5 -45
- package/dist/core/config/schema/engines.js +14 -3
- package/dist/core/config/schema/workflow.js +11 -0
- package/dist/core/errors.js +25 -0
- package/dist/core/events.js +30 -24
- package/dist/core/extra-params.js +11 -0
- package/dist/core/file-lock.js +7 -1
- package/dist/core/fs-txn.js +15 -2
- package/dist/core/improve-result.js +5 -0
- package/dist/core/json-schema.js +344 -9
- package/dist/core/loopback.js +89 -0
- package/dist/core/migration-operation.js +17 -2
- package/dist/core/path-access.js +107 -0
- package/dist/core/paths.js +16 -2
- package/dist/core/redaction.js +86 -18
- package/dist/core/spawn-env.js +234 -0
- package/dist/core/state-db-scope.js +134 -0
- package/dist/core/state-db.js +1 -0
- package/dist/core/subprocess.js +181 -37
- package/dist/core/write-provenance.js +85 -0
- package/dist/core/write-source.js +33 -2
- package/dist/indexer/db/graph-db.js +17 -6
- package/dist/indexer/ensure-index.js +10 -3
- package/dist/indexer/index-written-assets.js +17 -2
- package/dist/indexer/indexer.js +86 -21
- package/dist/indexer/passes/memory-inference.js +4 -0
- package/dist/indexer/search/db-search.js +25 -17
- package/dist/indexer/walk/walker.js +6 -1
- package/dist/integrations/agent/detect.js +13 -1
- package/dist/integrations/agent/engine-resolution.js +24 -11
- package/dist/integrations/agent/model-aliases.js +1 -1
- package/dist/integrations/agent/profiles.js +9 -1
- package/dist/integrations/agent/spawn.js +15 -87
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +21 -0
- package/dist/integrations/lockfile.js +55 -2
- package/dist/llm/client.js +14 -19
- package/dist/llm/embedder.js +23 -3
- package/dist/llm/embedders/remote.js +27 -2
- package/dist/output/html-render.js +40 -1
- package/dist/output/text/lint-format.js +17 -4
- package/dist/runtime.js +23 -1
- package/dist/scripts/akm-migrate-node.js +1714 -836
- package/dist/scripts/akm-migrate.js +1682 -804
- package/dist/setup/setup.js +22 -7
- package/dist/sources/providers/git-install.js +25 -2
- package/dist/sources/providers/git-stash.js +19 -0
- package/dist/sources/providers/git.js +1 -1
- package/dist/sources/snapshot-fetchers/content-extract.js +63 -1
- package/dist/sources/snapshot-fetchers/website-ingest.js +126 -20
- package/dist/storage/database.js +71 -7
- package/dist/storage/engines/sqlite-migrations.js +61 -2
- package/dist/storage/managed-db.js +19 -0
- package/dist/storage/repositories/index-connection.js +39 -4
- package/dist/storage/repositories/index-entries-repository.js +6 -1
- package/dist/storage/repositories/index-meta-repository.js +11 -0
- package/dist/storage/repositories/index-schema.js +17 -2
- package/dist/storage/repositories/index-vec-repository.js +43 -5
- package/dist/storage/repositories/workflow-runs-repository.js +66 -13
- package/dist/storage/sqlite-pragmas.js +12 -1
- package/dist/tasks/log-redaction.js +156 -0
- package/dist/tasks/parser.js +82 -5
- package/dist/tasks/runner.js +222 -17
- package/dist/tasks/scheduler-invocation.js +19 -0
- package/dist/tasks/schema.js +86 -1
- package/dist/text-import-hook.mjs +1 -1
- package/dist/workflows/concurrency-policy.js +95 -1
- package/dist/workflows/exec/dispatch-redaction.js +114 -0
- package/dist/workflows/exec/exec-unit.js +542 -0
- package/dist/workflows/exec/frozen-judge.js +114 -42
- package/dist/workflows/exec/native-executor.js +465 -238
- package/dist/workflows/exec/param-secrets.js +4 -3
- package/dist/workflows/exec/run-workflow.js +424 -219
- package/dist/workflows/exec/step-work.js +506 -167
- package/dist/workflows/exec/unit-dispatch.js +31 -1
- package/dist/workflows/exec/unit-writer.js +53 -13
- package/dist/workflows/exec/worktree.js +454 -41
- package/dist/workflows/ir/compile.js +26 -2
- package/dist/workflows/ir/freeze.js +82 -15
- package/dist/workflows/ir/schema.js +105 -20
- package/dist/workflows/parser.js +242 -19
- package/dist/workflows/program/schema.js +24 -0
- package/dist/workflows/renderer.js +32 -4
- package/dist/workflows/resource-limits.js +182 -0
- package/dist/workflows/runtime/runs.js +146 -6
- package/dist/workflows/validate-summary.js +17 -2
- package/docs/README.md +74 -32
- package/docs/migration/release-notes/0.9.0.md +2 -1
- package/docs/migration/v0.7-to-v0.8.md +2 -1
- package/docs/migration/v0.8-to-v0.9.md +3 -1
- package/docs/reference/README.md +11 -4
- package/docs/reference/bundle-types.md +19 -0
- package/docs/reference/cli.md +105 -16
- package/docs/reference/configuration.md +15 -2
- package/docs/reference/data-and-telemetry.md +30 -10
- package/docs/reference/supported-formats.md +50 -0
- package/docs/reference/workflow-schema.md +1014 -0
- package/docs/reference/workflows.md +37 -633
- package/package.json +13 -6
- package/schemas/akm-config.json +18 -5
- package/schemas/akm-task.json +27 -5
- package/schemas/akm-workflow.json +92 -13
|
@@ -9,639 +9,43 @@ an interruption without replaying completed units.
|
|
|
9
9
|
> It is the canonical start/resume/execute command; there is no separate
|
|
10
10
|
> external-driver protocol.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
and executes it until completion, failure, verification rejection,
|
|
40
|
-
interruption, or an explicit invocation limit. Run state is scoped to the
|
|
41
|
-
current project directory (nearest `.akm/config.json`, git root, bundle root,
|
|
42
|
-
or current directory), so the same workflow can run independently in separate
|
|
43
|
-
projects.
|
|
44
|
-
|
|
45
|
-
```sh
|
|
46
|
-
akm workflow run workflows/ship-release --version 1.2.3
|
|
47
|
-
akm workflow run workflows/review --changed_files a.ts --changed_files b.ts
|
|
48
|
-
akm workflow run <run-id> --max-retries 2 --timeout 10m
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Parameter flags must come after the target and exactly match declared `params`
|
|
52
|
-
keys. Values are coerced through each parameter's JSON Schema: repeat an array
|
|
53
|
-
flag, pass an object or whole array as JSON, and use a bare boolean flag for
|
|
54
|
-
`true`. There are no hyphen/underscore aliases. The old `--params` JSON bag is
|
|
55
|
-
removed, and parameters are accepted only while creating a new run.
|
|
56
|
-
|
|
57
|
-
`--max-steps <n>` leaves a partial run active after at most `n` steps.
|
|
58
|
-
`--max-retries <n>` retries a failed step on the same run up to `n` additional
|
|
59
|
-
times (0 through 100). `--timeout <duration>` bounds the whole invocation and
|
|
60
|
-
accepts `N`, `Nms`, `Ns`, or `Nm`; bare `N` is milliseconds. A timeout or
|
|
61
|
-
signal abort releases the run lease without advancing the active step, so the
|
|
62
|
-
run remains resumable. Failed, gate-rejected, timed-out, and interrupted runs
|
|
63
|
-
exit nonzero.
|
|
64
|
-
|
|
65
|
-
The run freezes its plan, exact models, execution limits, parameter snapshot,
|
|
66
|
-
and verifier selection at creation. Edits to source or config do not alter an
|
|
67
|
-
in-flight run.
|
|
68
|
-
|
|
69
|
-
## akm workflow status
|
|
70
|
-
|
|
71
|
-
`akm workflow status` shows the full run state — all step statuses, notes, and
|
|
72
|
-
evidence — for a given run ID or workflow ref.
|
|
73
|
-
|
|
74
|
-
```sh
|
|
75
|
-
akm workflow status <run-id>
|
|
76
|
-
akm workflow status workflows/ship-release
|
|
77
|
-
# When given a ref, resolves to the most-recently-updated run in the current scope
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Use this to inspect where a run is after a context window break, or to verify
|
|
81
|
-
all steps completed cleanly before closing a PR.
|
|
82
|
-
|
|
83
|
-
**`--units` — per-unit diagnostics.** For an orchestrated run, add `--units`
|
|
84
|
-
to also list the run's journaled unit rows — each unit's id, status,
|
|
85
|
-
`failure_reason`, and any result/error diagnostic text the row carries:
|
|
86
|
-
|
|
87
|
-
```sh
|
|
88
|
-
akm workflow status <run-id> --units
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
This is a **diagnostic** surface, deliberately kept out of the deterministic
|
|
92
|
-
artifact graph. A step's promoted artifact (what `steps.x.output` resolves to,
|
|
93
|
-
and what a gate judges) keeps only a failed unit's structured `failure_reason`
|
|
94
|
-
— never the raw error text — so step evidence stays reproducible across
|
|
95
|
-
resumes. When you need the human-facing *why*
|
|
96
|
-
behind a failure, `--units` reads the unit journal directly and shows it
|
|
97
|
-
without ever feeding that text back into an artifact or input hash.
|
|
98
|
-
|
|
99
|
-
## akm workflow list
|
|
100
|
-
|
|
101
|
-
`akm workflow list` shows workflow runs in the current scope.
|
|
102
|
-
|
|
103
|
-
```sh
|
|
104
|
-
akm workflow list # All runs in this scope (any status)
|
|
105
|
-
akm workflow list --active # Only status=active (executable) runs
|
|
106
|
-
akm workflow list --ref workflows/ship-release # Runs for a specific workflow
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
`--active` filters to runs whose status is exactly `active` — currently
|
|
110
|
-
executable work. A `blocked` run (parked awaiting a human `akm workflow resume`)
|
|
111
|
-
or a `failed`/`completed` run is **not** active and is excluded, so a script
|
|
112
|
-
that treats `--active` output as runnable never picks one up. Blocked runs
|
|
113
|
-
remain listed by the unfiltered `akm workflow list` with their `blocked` status.
|
|
114
|
-
|
|
115
|
-
**Example: see what is in flight**
|
|
116
|
-
|
|
117
|
-
```sh
|
|
118
|
-
akm workflow list --active
|
|
119
|
-
# → lists runs by workflow ref, status, currentStepId, and updatedAt
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Writing a workflow
|
|
123
|
-
|
|
124
|
-
A workflow is an ordinary AKM markdown asset — the same envelope as every
|
|
125
|
-
other type, OKF-conformant frontmatter plus a markdown body — whose
|
|
126
|
-
frontmatter carries the entire orchestration graph (params, and how each step
|
|
127
|
-
dispatches, fans out, routes, and gates) and whose body carries each step's
|
|
128
|
-
instructions and gate rubric under plain headings, joined to the frontmatter
|
|
129
|
-
by step id. There is **one** format: no separate YAML "program" surface, no
|
|
130
|
-
`.yaml`/`.yml` workflow files.
|
|
131
|
-
|
|
132
|
-
Use `akm workflow create --print` to print a valid starter, then edit it and
|
|
133
|
-
register it with `akm workflow create`.
|
|
134
|
-
|
|
135
|
-
```sh
|
|
136
|
-
akm workflow create my-release --print # Print the template, without writing
|
|
137
|
-
akm workflow create my-release --from ./my-release.md
|
|
138
|
-
akm lint --type workflows # Check for structural errors before using it
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
**A minimal workflow:**
|
|
142
|
-
|
|
143
|
-
```markdown
|
|
144
|
-
---
|
|
145
|
-
type: workflow
|
|
146
|
-
description: Ship a tagged release to production
|
|
147
|
-
params:
|
|
148
|
-
version: { type: string, description: The semver version string to release }
|
|
149
|
-
steps:
|
|
150
|
-
- id: validate
|
|
151
|
-
- id: build
|
|
152
|
-
inputs: [steps.validate.output]
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
# Ship Release
|
|
156
|
-
|
|
157
|
-
## validate
|
|
158
|
-
|
|
159
|
-
Check that the `version` parameter follows semver and the tag does not
|
|
160
|
-
already exist.
|
|
161
|
-
|
|
162
|
-
### gate
|
|
163
|
-
|
|
164
|
-
- `git tag v<version>` does not already exist.
|
|
165
|
-
- The version string matches `^\d+\.\d+\.\d+$`.
|
|
166
|
-
|
|
167
|
-
## build
|
|
168
|
-
|
|
169
|
-
Run `npm run build && npm test`, using the validation from `validate`,
|
|
170
|
-
attached to this unit as input. Fix any failures before proceeding.
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
**Body rules** (checked by `akm lint --type workflows`):
|
|
174
|
-
|
|
175
|
-
1. Every level-2 heading must be `## <step-id>` for a step declared in
|
|
176
|
-
frontmatter, exactly — no titles, no `Step:`/`Step ID:` lines, no
|
|
177
|
-
`# Workflow:` prefix on the H1. (Fenced code blocks are skipped when
|
|
178
|
-
scanning for headings.)
|
|
179
|
-
2. A `unit` or `map` step **must** have a body section — its instructions,
|
|
180
|
-
or its per-item template for a map step, byte-exact to the next H2 or
|
|
181
|
-
EOF. A `route` step **may** have one (documentation, plus a gate rubric
|
|
182
|
-
if it is gated). Everything before the first H2 is free preamble —
|
|
183
|
-
indexed for search, shown in `akm show`, never dispatched.
|
|
184
|
-
3. Inside a step's section, an optional `### gate` sub-heading starts that
|
|
185
|
-
step's gate rubric, running to the section end — the format's **single
|
|
186
|
-
reserved marker**. The judge that evaluates the step receives this whole
|
|
187
|
-
section byte-exact. An omitted or empty `### gate` section needs no
|
|
188
|
-
verification. A non-empty rubric enables mandatory fail-closed verification;
|
|
189
|
-
frontmatter `gate:` only tunes its retry bound.
|
|
190
|
-
|
|
191
|
-
Prose is never templated — see [The reference grammar](#the-reference-grammar)
|
|
192
|
-
for how a step's instructions refer to run params, upstream artifacts, and a
|
|
193
|
-
map unit's item.
|
|
194
|
-
|
|
195
|
-
**Frontmatter**, validated by one published JSON Schema
|
|
196
|
-
(`schemas/akm-workflow.json`): the standard AKM asset envelope (`type`,
|
|
197
|
-
`description`, `tags`, `when_to_use`, `xrefs`, `updated`/`timestamp`, and the
|
|
198
|
-
OKF v0.2 trust/lifecycle families) plus the orchestration keys:
|
|
199
|
-
|
|
200
|
-
- `params` — name → `{ type, description }` (JSON-Schema-typed, unlike a bare
|
|
201
|
-
description string).
|
|
202
|
-
- `defaults` — run-level dispatch defaults (`engine`, `model`, `llm`,
|
|
203
|
-
`timeout`, `on_error`), overridable per unit.
|
|
204
|
-
- `budget` — run-lifetime ceilings (`max_units`, `max_tokens`; see *Budget
|
|
205
|
-
ceilings* below).
|
|
206
|
-
- `steps` — an ordered list. Each step has an `id`
|
|
207
|
-
(`[A-Za-z_][A-Za-z0-9_-]*` — no dots) and **at most one** of `unit`, `map`,
|
|
208
|
-
or `route`. A step with neither is **still a unit step** — bare
|
|
209
|
-
`- id: validate` is the complete minimal declaration. `unit:` is the
|
|
210
|
-
optional dispatch-override bag (`engine`, `model`, `llm`, `timeout`,
|
|
211
|
-
`retry`, `on_error`, `env`, `isolation`; see below).
|
|
212
|
-
- `inputs` — on a `unit`/`map` step, the prior-step artifacts this step
|
|
213
|
-
consumes, as bare reference strings (sub-paths legal:
|
|
214
|
-
`steps.x.output.issues`, not just `steps.x.output`). This is how a step's
|
|
215
|
-
attached context sees upstream data, and how replay hashing gets its exact
|
|
216
|
-
input set — a step re-dispatches only when the slice it actually consumes
|
|
217
|
-
changes.
|
|
218
|
-
- `output` — a JSON Schema for the step's promoted artifact.
|
|
219
|
-
- `gate` — optional validation-loop configuration: `max_loops` bounds
|
|
220
|
-
evaluator-optimizer retries (see *Gates judge the artifact*). The rubric
|
|
221
|
-
itself lives in the body's `### gate` section. Without non-empty rubric
|
|
222
|
-
text, the configuration is inert.
|
|
223
|
-
|
|
224
|
-
No `version:`/`name:` keys — identity is the ref, and the frozen plan already
|
|
225
|
-
versions execution semantics — and no step titles anywhere: a step is its id,
|
|
226
|
-
and the asset's human name is its `description` and H1 like any other asset
|
|
227
|
-
type.
|
|
228
|
-
|
|
229
|
-
**A richer example** — fan-out, routing, retries, gates, and a run budget:
|
|
230
|
-
|
|
231
|
-
```markdown
|
|
232
|
-
---
|
|
233
|
-
type: workflow
|
|
234
|
-
description: Review changed files and route the outcome
|
|
235
|
-
params:
|
|
236
|
-
changed_files: { type: array, description: Files to review }
|
|
237
|
-
defaults: { engine: reviewer, model: balanced, timeout: 10m, on_error: fail }
|
|
238
|
-
budget: { max_units: 40, max_tokens: 200000 }
|
|
239
|
-
steps:
|
|
240
|
-
- id: discover
|
|
241
|
-
output: { type: object, properties: { files: { type: array } }, required: [files] }
|
|
242
|
-
- id: review
|
|
243
|
-
map:
|
|
244
|
-
over: steps.discover.output.files
|
|
245
|
-
concurrency: 8
|
|
246
|
-
unit:
|
|
247
|
-
engine: reviewer
|
|
248
|
-
model: deep
|
|
249
|
-
timeout: 5m
|
|
250
|
-
retry: { max: 1, on: [timeout, llm_rate_limit] }
|
|
251
|
-
on_error: continue
|
|
252
|
-
isolation: worktree
|
|
253
|
-
output: { type: object, properties: { file: { type: string }, verdict: { type: string } }, required: [file, verdict] }
|
|
254
|
-
# `output` here describes the REDUCER RESULT, not one unit's result: the
|
|
255
|
-
# default `collect` reducer folds per-item unit results into an array.
|
|
256
|
-
output: { type: array }
|
|
257
|
-
gate: { max_loops: 2 }
|
|
258
|
-
- id: aggregate
|
|
259
|
-
inputs: [steps.review.output]
|
|
260
|
-
output: { type: object, properties: { verdict: { type: string } }, required: [verdict] }
|
|
261
|
-
- id: triage
|
|
262
|
-
route:
|
|
263
|
-
input: steps.aggregate.output.verdict
|
|
264
|
-
when: [{ match: pass, step: ship }, { match: fail, step: rework }]
|
|
265
|
-
default: manual-triage
|
|
266
|
-
- id: ship
|
|
267
|
-
- id: rework
|
|
268
|
-
- id: manual-triage
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
# Review Changes
|
|
272
|
-
|
|
273
|
-
## discover
|
|
274
|
-
|
|
275
|
-
List the files that need review, drawn from the `changed_files` parameter.
|
|
276
|
-
|
|
277
|
-
### gate
|
|
278
|
-
|
|
279
|
-
Every file named by `changed_files` is listed in the reported result.
|
|
280
|
-
|
|
281
|
-
## review
|
|
282
|
-
|
|
283
|
-
This section is the **map unit template** — the engine attaches each unit's
|
|
284
|
-
item (the file to review) and its index as context; instructions refer to
|
|
285
|
-
"the file you were given," never a template expression.
|
|
286
|
-
|
|
287
|
-
Review the file you were given for correctness bugs.
|
|
288
|
-
|
|
289
|
-
### gate
|
|
290
|
-
|
|
291
|
-
Every changed file has a verdict of `pass` or `fail`.
|
|
292
|
-
|
|
293
|
-
## aggregate
|
|
294
|
-
|
|
295
|
-
Combine the per-file review verdicts — attached to this unit as input via
|
|
296
|
-
`inputs: [steps.review.output]` above — into one overall verdict, `pass` or
|
|
297
|
-
`fail`.
|
|
298
|
-
|
|
299
|
-
## triage
|
|
300
|
-
|
|
301
|
-
Routes on the verdict `aggregate` reported: `pass` proceeds to `ship`, `fail`
|
|
302
|
-
proceeds to `rework`, anything else goes to `manual-triage`.
|
|
303
|
-
|
|
304
|
-
## ship
|
|
305
|
-
|
|
306
|
-
Ship the change.
|
|
307
|
-
|
|
308
|
-
## rework
|
|
309
|
-
|
|
310
|
-
Address the review findings. Confirming the fix is a fresh `akm workflow run`
|
|
311
|
-
of this workflow, not a step this run routes back to.
|
|
312
|
-
|
|
313
|
-
## manual-triage
|
|
314
|
-
|
|
315
|
-
Summarize the ambiguous verdict for a human to triage.
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
## The reference grammar
|
|
319
|
-
|
|
320
|
-
Workflow prose is **never templated** — there is no `${{ … }}`/`{{ … }}`
|
|
321
|
-
interpolation anywhere in a workflow's body, and no escape syntax to learn,
|
|
322
|
-
because there are no delimiters in prose to escape.
|
|
323
|
-
|
|
324
|
-
Bare reference strings appear in exactly three frontmatter positions, each an
|
|
325
|
-
unquoted-style YAML string:
|
|
326
|
-
|
|
327
|
-
| Position | What it names |
|
|
328
|
-
| --- | --- |
|
|
329
|
-
| `map.over` | The list a map step fans out over. |
|
|
330
|
-
| `route.input` | The value a route step matches on. |
|
|
331
|
-
| `inputs` (each entry) | A prior step's artifact this step consumes. |
|
|
332
|
-
|
|
333
|
-
Every reference resolves against exactly two roots:
|
|
334
|
-
|
|
335
|
-
| Reference | Meaning |
|
|
336
|
-
| --- | --- |
|
|
337
|
-
| `params.<name>` | A run parameter, by name. |
|
|
338
|
-
| `steps.<id>.output( .<ident> \| [<int>] )*` | A prior step's artifact, addressed by producer step id; the path walks properties (`.name`) and array indexes (`[0]`). |
|
|
339
|
-
|
|
340
|
-
Nothing else parses: no functions, no clock, no randomness, no ambient
|
|
341
|
-
lookup. `item` and `item_index` are **not** part of the language — a map
|
|
342
|
-
unit's item and its index are never referenced from anywhere in frontmatter
|
|
343
|
-
or body. They arrive as **attached context** instead, the same way as
|
|
344
|
-
everything else a unit needs.
|
|
345
|
-
|
|
346
|
-
**Context attachment, not string splicing.** Each dispatched unit receives,
|
|
347
|
-
alongside its byte-exact instructions, structured context:
|
|
348
|
-
|
|
349
|
-
- every run **param** (params are run-scoped and documented non-secret — see
|
|
350
|
-
*Params are not secret* below);
|
|
351
|
-
- for a **map** unit, its **item** and **item index**;
|
|
352
|
-
- the artifacts named by its step's **`inputs:`**.
|
|
353
|
-
|
|
354
|
-
Instructions refer to this context in plain language — "clone the repository
|
|
355
|
-
named by the `repo` parameter," "review the file you were given," "using the
|
|
356
|
-
intake step's artifact attached to this unit" — never by splicing a value
|
|
357
|
-
into the instruction string. This closes the injection class at the root:
|
|
358
|
-
data never enters the instruction string, spliced or otherwise.
|
|
359
|
-
|
|
360
|
-
`akm lint --type workflows` still checks every bare reference statically —
|
|
361
|
-
unknown step, unknown param, bad path — at lint time.
|
|
362
|
-
|
|
363
|
-
**What a step's output is.** `steps.<id>.output` resolves to the value the
|
|
364
|
-
step's execution produced:
|
|
365
|
-
|
|
366
|
-
- a `unit` step → the unit's structured result (when the unit declares
|
|
367
|
-
`output`) or its text;
|
|
368
|
-
- a `map` step → the collected array of per-item results, in item order
|
|
369
|
-
(under `on_error: continue`, a failed item's slot is `null`), unless the
|
|
370
|
-
step's own `output` schema describes a reduced, single-value shape instead.
|
|
371
|
-
|
|
372
|
-
**An empty successful free-text output is treated as no output.** When a
|
|
373
|
-
schemaless unit (one that declares no `output` schema) succeeds but returns
|
|
374
|
-
the empty string, akm normalizes it to *absent*: nothing is journaled for its
|
|
375
|
-
result, and its contribution to the step artifact is `null` — a `null` slot
|
|
376
|
-
in a collected array, or `output = null` for a solo step. This absence is
|
|
377
|
-
deliberate, so a live run and a resumed run promote the
|
|
378
|
-
identical artifact. The practical consequence: a downstream step that
|
|
379
|
-
declares an empty upstream result in its `inputs:` gets nothing meaningful
|
|
380
|
-
attached for it — akm surfaces this loudly rather than silently attaching an
|
|
381
|
-
empty string. A unit that declares an `output` schema is unaffected — an
|
|
382
|
-
empty response is not valid JSON, so it fails as a parse error and can never
|
|
383
|
-
satisfy a schema as a silent `null`.
|
|
384
|
-
|
|
385
|
-
## Frozen plans
|
|
386
|
-
|
|
387
|
-
The first `akm workflow run <ref>` compiles the workflow and freezes the
|
|
388
|
-
resulting plan on the run row (`plan_json` + `plan_hash`). **A run executes the
|
|
389
|
-
plan compiled at creation; edits to the source file need a new run** — the file
|
|
390
|
-
is never re-read for an in-flight run, so `run` and `resume` retain the same
|
|
391
|
-
workflow no matter what changed on disk. Orchestration decisions are pure
|
|
392
|
-
functions of the frozen plan, run params, and journaled unit results.
|
|
393
|
-
|
|
394
|
-
**Resume is journaled replay.** Every dispatched unit is journaled with a
|
|
395
|
-
content-derived identity — the step id plus a hash of the unit's frozen
|
|
396
|
-
instructions, its item (for a map unit), its declared `inputs:` artifacts,
|
|
397
|
-
and the params snapshot — and its input hash. On re-run, a journaled
|
|
398
|
-
completed unit with the same identity and the same inputs is **reused**,
|
|
399
|
-
never re-dispatched; a failed or missing unit is dispatched live. If a
|
|
400
|
-
journaled completed unit matches by identity but its recorded inputs differ,
|
|
401
|
-
the engine fails the step with a **replay divergence** error naming the unit
|
|
402
|
-
— it never silently re-runs work whose inputs changed under it. (Divergence
|
|
403
|
-
means the program produced different data for the "same" unit across
|
|
404
|
-
invocations — a nondeterminism bug worth surfacing, not papering over.)
|
|
405
|
-
|
|
406
|
-
## Failure policy
|
|
407
|
-
|
|
408
|
-
Fail-fast is the default. Per unit (or via `defaults.on_error`):
|
|
409
|
-
|
|
410
|
-
- `on_error: fail` — the first failed unit fails the step, which fails the
|
|
411
|
-
run (`akm workflow resume` re-opens it; `run` re-dispatches only
|
|
412
|
-
incomplete units).
|
|
413
|
-
- `on_error: continue` — failures are recorded in the step's results and the
|
|
414
|
-
completion gate decides whether the step passes.
|
|
415
|
-
- `retry: { max: <n>, on: [<failure_reason>…] }` — re-dispatches a failed
|
|
416
|
-
unit up to `max` extra times when its recorded `failure_reason` is listed
|
|
417
|
-
(e.g. `timeout`, `llm_rate_limit`, `spawn_failed`, `non_zero_exit`); every
|
|
418
|
-
attempt is journaled separately.
|
|
419
|
-
|
|
420
|
-
A unit's `output` schema is validated on every runner; a validation miss
|
|
421
|
-
re-dispatches once with corrective feedback before the unit is recorded as
|
|
422
|
-
failed.
|
|
423
|
-
|
|
424
|
-
## Routing
|
|
425
|
-
|
|
426
|
-
A `route` step makes classify-and-dispatch first-class: the engine resolves
|
|
427
|
-
the explicit `input:` expression, selects the matching `when:` branch (or
|
|
428
|
-
`default:`), and auto-skips the unselected branch targets as the spine
|
|
429
|
-
reaches them. **Routes are forward-only**: every target (each `when.step`
|
|
430
|
-
and `default`) must be a step declared *later* in the workflow than the
|
|
431
|
-
routing step, and a step never routes to itself — this keeps the plan a DAG,
|
|
432
|
-
so termination is structural rather than a runtime budget's job. A
|
|
433
|
-
`default:` that names an earlier step is a lint error, not a loop. An
|
|
434
|
-
unroutable value with no `default` fails the step rather than letting every
|
|
435
|
-
branch run.
|
|
436
|
-
|
|
437
|
-
**"Go back and fix it" is a gate, not a backward route.** A failed gate
|
|
438
|
-
re-runs its *own* step with the judge's feedback, bounded by `gate.max_loops`
|
|
439
|
-
— and a declared `output:` schema the promoted artifact fails is specifically
|
|
440
|
-
the error a gate loop retries through. A workflow that used to describe "loop
|
|
441
|
-
back to an earlier step until this passes" expresses that as a bounded gate
|
|
442
|
-
on the step doing the work, not as routing.
|
|
443
|
-
|
|
444
|
-
Route decisions are journaled, so a resumed run replays the same choice.
|
|
445
|
-
Skips cascade: when a route step is itself skipped (it was the unselected
|
|
446
|
-
target of an earlier route), its own branch targets are skipped too — a
|
|
447
|
-
router that never decided selects nothing.
|
|
448
|
-
|
|
449
|
-
## Typed step artifacts
|
|
450
|
-
|
|
451
|
-
When a step declares `output`, the promoted step artifact (the unit's
|
|
452
|
-
structured result, the collected array, or a reduced single value — see
|
|
453
|
-
*What a step's output is* above) is validated against that schema **before**
|
|
454
|
-
the step can complete. A mismatch fails the step with the validation errors
|
|
455
|
-
in its summary. This is fail-fast on purpose: a bounded gate loop (next
|
|
456
|
-
section) can re-run the step with those errors as corrective feedback.
|
|
457
|
-
|
|
458
|
-
## Gates judge the artifact; `max_loops` bounds the retry
|
|
459
|
-
|
|
460
|
-
Under `akm workflow run`, a step with a body `### gate` rubric is gated on
|
|
461
|
-
its **artifact**, not on engine prose: the judge receives the step's
|
|
462
|
-
artifact as canonical JSON (clipped at 4000 characters) alongside the
|
|
463
|
-
`### gate` section byte-exact, so the gate evaluates real results rather
|
|
464
|
-
than a machine summary like "Executed 3 units". Each engine-driven gate
|
|
465
|
-
evaluation is itself an LLM call and is journaled as a unit row
|
|
466
|
-
(`<step-id>.gate:l<loop>`).
|
|
467
|
-
|
|
468
|
-
`gate.max_loops: <n>` (frontmatter) turns the gate into a bounded
|
|
469
|
-
evaluator-optimizer loop: on a rejection (or a typed-artifact schema
|
|
470
|
-
mismatch) with loop budget left, the engine re-executes the step's units
|
|
471
|
-
with the gate feedback and the missing-criteria list appended as attached
|
|
472
|
-
context. The feedback changes each unit's inputs, so the re-run naturally
|
|
473
|
-
dispatches fresh units instead of replaying journaled results. When the loop
|
|
474
|
-
budget is spent, the rejection stands exactly as in the one-shot case.
|
|
475
|
-
|
|
476
|
-
## Fail-closed verification
|
|
477
|
-
|
|
478
|
-
With no non-empty `### gate` rubric, no verification runs. When a rubric is
|
|
479
|
-
present, the workflow requires `workflow.judgeEngine` to name a configured LLM
|
|
480
|
-
or agent engine before the plan can be frozen. That verifier invocation is
|
|
481
|
-
frozen into the run.
|
|
482
|
-
|
|
483
|
-
Only a well-formed `complete: true` verdict advances a criteria-bearing step.
|
|
484
|
-
A missing verifier, dispatch failure, or malformed result rejects the gate
|
|
485
|
-
instead of silently bypassing it. A well-formed `complete: false` verdict
|
|
486
|
-
returns its missing criteria and feedback and can trigger another bounded
|
|
487
|
-
`max_loops` attempt.
|
|
488
|
-
|
|
489
|
-
## Budget ceilings
|
|
490
|
-
|
|
491
|
-
The top-level `budget:` key declares run-lifetime ceilings: `max_units`
|
|
492
|
-
(total dispatched units) and `max_tokens` (total reported token usage). Both
|
|
493
|
-
counters are seeded from the unit journal, so they measure the **whole run
|
|
494
|
-
across resumes**, not just the current invocation. Hitting a ceiling aborts
|
|
495
|
-
the step's still-pending dispatches and fails the step with a
|
|
496
|
-
`budget exceeded (<which> ceiling)` summary — budget exhaustion is a hard
|
|
497
|
-
stop that ignores `on_error: continue`. Because the plan is frozen, raising
|
|
498
|
-
a budget means starting a new run.
|
|
499
|
-
|
|
500
|
-
## One engine drives a run (the run lease)
|
|
501
|
-
|
|
502
|
-
`akm workflow run` takes a **run lease** before dispatching anything: a
|
|
503
|
-
random holder id with a 90-second expiry recorded on the run row, renewed
|
|
504
|
-
between steps, and released when the invocation exits. A second
|
|
505
|
-
`workflow run` against a live-leased run refuses up front, naming the holder
|
|
506
|
-
and the expiry. An *expired* lease is claimable, so a crashed engine never
|
|
507
|
-
wedges a run — wait out the expiry and re-run. While the lease is live the
|
|
508
|
-
engine owns the step spine. `workflow status` remains read-only; run detail
|
|
509
|
-
surfaces a live lease as `engineLease` (holder + expiry).
|
|
510
|
-
|
|
511
|
-
## Following a run's events
|
|
512
|
-
|
|
513
|
-
There is no `akm workflow watch` (0.9.0: dropped — a foreground polling
|
|
514
|
-
daemon in a one-shot CLI). `akm log --run <run-id>` reads the same
|
|
515
|
-
`workflow_*` / `workflow_unit_*` events from the general append-only events
|
|
516
|
-
stream: `--since '@offset:<id>'` gives a durable row-id cursor a cooperating
|
|
517
|
-
process can poll from, in place of `watch --stream`'s in-process loop.
|
|
518
|
-
|
|
519
|
-
```sh
|
|
520
|
-
akm workflow run <run-id> & # engine in one shell
|
|
521
|
-
akm log --run <run-id> --since '@offset:0' # backlog so far
|
|
522
|
-
akm log --run <run-id> --since '@offset:<nextOffset>' # poll for more, from the prior call's nextOffset
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
Event metadata is ids/status/enums only — never workflow-authored content —
|
|
526
|
-
so following a run's events is safe to pipe into logs or dashboards.
|
|
527
|
-
|
|
528
|
-
## Worktree isolation
|
|
529
|
-
|
|
530
|
-
A file-mutating unit can declare `isolation: worktree` (agent and sdk
|
|
531
|
-
runners). Each unit attempt gets a fresh **detached git worktree** of the
|
|
532
|
-
run's base repository under a run-scoped temp directory; the worktree path
|
|
533
|
-
is journaled on the unit row and passed to the harness as its working
|
|
534
|
-
directory, so parallel fan-out units can never trample each other's working
|
|
535
|
-
tree. After the unit finishes, a clean worktree (`git status --porcelain`
|
|
536
|
-
empty) is removed automatically; a dirty one is retained and its path
|
|
537
|
-
logged, so uncollected work is never destroyed. Declaring worktree isolation
|
|
538
|
-
in a non-git directory fails the step cleanly before anything dispatches.
|
|
539
|
-
|
|
540
|
-
> **⚠️ Warning — outputs matched by `.gitignore` are treated as disposable.**
|
|
541
|
-
> A worktree-isolated unit's output survives only if it lands on a
|
|
542
|
-
> **collectible path**: a tracked file, or an untracked file your repository
|
|
543
|
-
> does **not** `.gitignore`. Anything a unit writes to a `.gitignore`d path —
|
|
544
|
-
> build outputs, caches, logs, dependency directories like
|
|
545
|
-
> `node_modules`/`dist`, or a scratch file under an ignored directory — is
|
|
546
|
-
> **discarded** when its clean worktree is auto-removed. If a unit produces an
|
|
547
|
-
> artifact that must survive, write it to a non-ignored path, or report it as a
|
|
548
|
-
> result (a structured `output` / free-text result), before the unit returns.
|
|
549
|
-
|
|
550
|
-
The clean probe deliberately does **not** pass `--ignored`, so "uncollected
|
|
551
|
-
work" means tracked or untracked-*unignored* changes only. A worktree whose
|
|
552
|
-
only residue is files your repository's own `.gitignore` matches is treated as
|
|
553
|
-
clean and removed: those files are disposable by the repo's own declaration,
|
|
554
|
-
and retaining a worktree after every package install or build would blow up
|
|
555
|
-
disk under the temp root.
|
|
556
|
-
|
|
557
|
-
## Model tiers
|
|
558
|
-
|
|
559
|
-
Reference semantic aliases in `model:` fields instead of exact model ids so a
|
|
560
|
-
workflow stays harness-agnostic. Recommended vocabulary (convention, not
|
|
561
|
-
hardcoded) via the config-root `modelAliases` key:
|
|
562
|
-
|
|
563
|
-
```jsonc
|
|
564
|
-
{
|
|
565
|
-
"modelAliases": {
|
|
566
|
-
"fast": { "llm": "claude-haiku-4-5", "*": "claude-haiku-4-5" },
|
|
567
|
-
"balanced": { "llm": "claude-sonnet-4-6", "*": "claude-sonnet-4-6" },
|
|
568
|
-
"deep": { "claude": "claude-fable-5", "opencode": "opencode/claude-fable-5", "*": "claude-fable-5" }
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
For an LLM engine, resolution checks its engine-name column, then `llm`, then
|
|
574
|
-
`*`. Agent engines check their harness platform and then `*`.
|
|
575
|
-
|
|
576
|
-
The built-in aliases `fable`, `opus`, `sonnet`, and `haiku` resolve per
|
|
577
|
-
platform with no config. Point `deep` work (review, verification, judging) at
|
|
578
|
-
`fable` — Anthropic's tier above Opus — and keep high-volume fan-out units on
|
|
579
|
-
`fast`/`balanced`.
|
|
580
|
-
|
|
581
|
-
Trust note: a workflow that fans out is authorizing **N parallel agents**, not
|
|
582
|
-
one — the security section below applies with multiplied blast radius. The
|
|
583
|
-
engine enforces a concurrency cap, a lifetime unit cap per run, per-unit
|
|
584
|
-
timeouts, and (when the workflow declares them) run budget ceilings.
|
|
585
|
-
|
|
586
|
-
Native fan-out (`akm workflow run`) uses the minimum of four limits: the map's
|
|
587
|
-
declared `concurrency`, the run's frozen `workflow.maxConcurrency`, the
|
|
588
|
-
selected frozen LLM engine's `concurrency` (including an SDK engine's fallback
|
|
589
|
-
LLM), and the current host's CPU-derived safety limit. Reapplying host safety
|
|
590
|
-
keeps a run safe when it resumes on a smaller machine.
|
|
591
|
-
|
|
592
|
-
- **Unset (default):** the CPU-derived value `min(16, max(1, cores − 2))` — a
|
|
593
|
-
conservative default that leaves headroom on the host and matches the
|
|
594
|
-
original Claude-Code cap.
|
|
595
|
-
- **Set:** an explicit positive integer, clamped when frozen to `[1, 64]`
|
|
596
|
-
(values above 64 are clamped down, never rejected, so one config shared
|
|
597
|
-
across machines with different core counts never hard-fails).
|
|
598
|
-
|
|
599
|
-
```console
|
|
600
|
-
$ akm config set workflow.maxConcurrency 8 # raise the frozen workflow limit
|
|
601
|
-
$ akm config get workflow.maxConcurrency
|
|
602
|
-
8
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
## Security: workflow sources are executed code
|
|
606
|
-
|
|
607
|
-
Workflow steps that include shell commands run with **the full environment
|
|
608
|
-
and PATH of the user invoking `akm workflow run`** — same as if the user had
|
|
609
|
-
typed those commands in their shell. There is no sandbox, no env-var
|
|
610
|
-
allowlist, and no separation between trusted and untrusted workflows.
|
|
611
|
-
|
|
612
|
-
This is by design: a workflow is a runbook authored by you or by a stash
|
|
613
|
-
maintainer you trust. The flexibility of "run any shell command, read any
|
|
614
|
-
file, hit any network" is what makes workflows useful as automation.
|
|
615
|
-
|
|
616
|
-
The consequence is that **you should treat workflow sources the same way you
|
|
617
|
-
treat package dependencies**:
|
|
618
|
-
|
|
619
|
-
- **Only add workflow sources you trust.** `akm bundle add github:<some-user>/stash`
|
|
620
|
-
followed by `akm workflow run workflows/<their-thing>` is functionally
|
|
621
|
-
equivalent to piping a stranger's bash script into your shell. Read the
|
|
622
|
-
workflow file first (`akm show workflows/<name>`) before running it.
|
|
623
|
-
- **Audit before run** for any workflow that touches secrets, deploys to
|
|
624
|
-
production, or writes outside the project tree. Workflow steps can read
|
|
625
|
-
any environment variable visible to the akm process — including secrets
|
|
626
|
-
exported by your shell or injected via `akm env run` / `akm secret run`.
|
|
627
|
-
- **Pin known-good versions** when adding workflow sources from a registry
|
|
628
|
-
or git remote (`akm bundle add github:owner/stash#v1.2.3`), and update
|
|
629
|
-
deliberately rather than via `akm bundle update --all`. A trusted workflow source
|
|
630
|
-
can become hostile if its upstream is compromised.
|
|
631
|
-
- **Workflow steps cannot escape this trust model** by being labeled
|
|
632
|
-
`dryRun` or `interactive` — those flags affect bookkeeping, not execution.
|
|
633
|
-
`akm workflow status` is read-only; `akm workflow run` executes configured
|
|
634
|
-
units with your process's access.
|
|
635
|
-
|
|
636
|
-
If you operate a CI runner or shared host where untrusted workflows might be
|
|
637
|
-
executed, scope the process: a dedicated user account with no secrets in its
|
|
638
|
-
environment, ephemeral working directory, and a network/filesystem allowlist
|
|
639
|
-
enforced outside akm.
|
|
12
|
+
Workflows are one of the execution surfaces AKM directly orchestrates: AKM
|
|
13
|
+
retrieves every supported capability type, but a workflow's declared steps —
|
|
14
|
+
not arbitrary indexed content — are what actually gets dispatched. See
|
|
15
|
+
[Architecture: Core Principles](https://github.com/itlackey/akm/blob/main/docs/architecture/akm-core-principles.md) for
|
|
16
|
+
that boundary.
|
|
17
|
+
|
|
18
|
+
This page is a short map. The full contract now lives across four pages,
|
|
19
|
+
split by what you're doing:
|
|
20
|
+
|
|
21
|
+
- **[Running Workflows](https://github.com/itlackey/akm/blob/main/docs/guides/run-workflows.md)** — operating a run:
|
|
22
|
+
start, check status, resume a blocked run, abandon one, and follow its
|
|
23
|
+
events. Includes the trust model for running a workflow sourced from
|
|
24
|
+
someone else's bundle.
|
|
25
|
+
- **[Author's Guide: Writing Workflows](https://github.com/itlackey/akm/blob/main/docs/guides/author-workflows.md)** —
|
|
26
|
+
writing and testing a workflow definition: the markdown structure, a
|
|
27
|
+
minimal complete example, common authoring mistakes, choosing engines and
|
|
28
|
+
models, and engine-selection troubleshooting.
|
|
29
|
+
- **[Workflow Schema](../reference/workflow-schema.md)** — the exhaustive,
|
|
30
|
+
authoritative reference: every frontmatter key, the bare-reference grammar,
|
|
31
|
+
routing, failure policy, gates, and budget ceilings, with exact syntax.
|
|
32
|
+
- **[Architecture: The Workflow Engine](https://github.com/itlackey/akm/blob/main/docs/architecture/workflow-engine.md)**
|
|
33
|
+
— how a frozen plan actually executes: persistence, the run lease, dispatch,
|
|
34
|
+
worktree isolation, concurrency limits, and resume-without-replay.
|
|
35
|
+
|
|
36
|
+
For task- or schedule-driven workflow runs — an `akm task` bound to
|
|
37
|
+
`--workflow <ref>` and reconciled with the OS scheduler — see
|
|
38
|
+
[Scheduling](https://github.com/itlackey/akm/blob/main/docs/guides/scheduling.md).
|
|
640
39
|
|
|
641
40
|
## See also
|
|
642
41
|
|
|
643
|
-
- [
|
|
644
|
-
|
|
645
|
-
- [
|
|
646
|
-
|
|
647
|
-
- [
|
|
42
|
+
- [Discover and Load](https://github.com/itlackey/akm/blob/main/docs/guides/discover-and-load.md) — find available
|
|
43
|
+
workflows with `akm curate` before running one
|
|
44
|
+
- [Capture Knowledge](https://github.com/itlackey/akm/blob/main/docs/guides/capture-knowledge.md) — turn a workflow run's
|
|
45
|
+
outputs into searchable memories
|
|
46
|
+
- [Improve the Library](https://github.com/itlackey/akm/blob/main/docs/guides/improve-the-library.md) — feed run outcomes
|
|
47
|
+
back into a workflow asset's ranking and proposed edits
|
|
48
|
+
- [Concepts](https://github.com/itlackey/akm/blob/main/docs/guides/concepts.md) — the workflow asset type and run-state
|
|
49
|
+
storage in the broader AKM model
|
|
50
|
+
- [CLI Reference](cli.md) — full flag documentation for all `workflow`
|
|
51
|
+
subcommands
|