akm-cli 0.9.30 → 0.9.31
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 +29 -0
- package/README.md +10 -10
- package/ROADMAP.md +112 -0
- package/dist/commands/improve/improve-cli.js +33 -12
- package/dist/core/file-lock.js +10 -1
- package/dist/llm/client.js +33 -3
- package/dist/scripts/akm-migrate-node.js +5 -1
- package/dist/scripts/akm-migrate.js +5 -1
- package/docs/README.md +42 -41
- package/docs/agents/README.md +15 -0
- package/docs/agents/agent-install.md +14 -0
- package/docs/architecture/README.md +67 -0
- package/docs/architecture/adapters.md +272 -0
- package/docs/architecture/akm-architecture-decision-history.md +2055 -0
- package/docs/architecture/akm-core-principles.md +126 -0
- package/docs/architecture/architecture.md +579 -0
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +550 -0
- package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +72 -0
- package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +142 -0
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +189 -0
- package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +97 -0
- package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +108 -0
- package/docs/architecture/decisions/0006-task-source-version-routing.md +124 -0
- package/docs/architecture/decisions/0007-workflow-composition-bounds.md +83 -0
- package/docs/architecture/decisions/0008-task-binding-normalization.md +88 -0
- package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +80 -0
- package/docs/architecture/decisions/0010-driver-protocol-cut.md +36 -0
- package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +125 -0
- package/docs/architecture/decisions/README.md +62 -0
- package/docs/architecture/improvement.md +440 -0
- package/docs/architecture/internals/classification.md +154 -0
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +40 -0
- package/docs/architecture/internals/functional-contract-patterns.md +340 -0
- package/docs/architecture/internals/health-advisories.md +110 -0
- package/docs/architecture/internals/improve-workflow.md +713 -0
- package/docs/architecture/internals/indexing.md +498 -0
- package/docs/architecture/internals/registry-network-boundary.md +57 -0
- package/docs/architecture/internals/search.md +249 -0
- package/docs/architecture/internals/storage-locations.md +943 -0
- package/docs/architecture/persisted-data-compat.md +59 -0
- package/docs/architecture/reviews/env-secret-access.md +319 -0
- package/docs/architecture/runtime-boundary-design.md +153 -0
- package/docs/architecture/specs/0.9.0-close-out-plan.md +361 -0
- package/docs/architecture/specs/0.9.0-decisions.md +528 -0
- package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +745 -0
- package/docs/architecture/specs/0.9.0-open-items-register.md +135 -0
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +740 -0
- package/docs/architecture/specs/0.9.0-release-surface-review.md +636 -0
- package/docs/architecture/specs/agent-command-engine-model-design.md +513 -0
- package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +501 -0
- package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +291 -0
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +2059 -0
- package/docs/architecture/specs/di-seams-plan.md +539 -0
- package/docs/architecture/specs/driver-protocol-keep-or-cut.md +275 -0
- package/docs/architecture/specs/fact-asset-type.md +142 -0
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +634 -0
- package/docs/architecture/specs/okf-support.md +148 -0
- package/docs/architecture/specs/ref.md +329 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/README.md +72 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +152 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +352 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +300 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +402 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +758 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +645 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +602 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +74 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +15 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +132 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +147 -0
- package/docs/architecture/specs/stash-conventions-code-spec.md +275 -0
- package/docs/architecture/specs/stash-organization-conventions.md +377 -0
- package/docs/architecture/specs/task-workflow-format-unification.md +721 -0
- package/docs/architecture/specs/workflow-engine-buy-vs-build.md +231 -0
- package/docs/architecture/specs/workflow-format-unification.md +437 -0
- package/docs/architecture/testing/manual-testing-checklist.md +3420 -0
- package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +924 -0
- package/docs/architecture/testing/task-workflow-manual-tests.md +1817 -0
- package/docs/architecture/testing/testing-workflow.md +446 -0
- package/docs/architecture/workflow-engine.md +274 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/author-bundles.md +310 -0
- package/docs/guides/author-workflows.md +520 -0
- package/docs/guides/bundles.md +321 -0
- package/docs/guides/capture-knowledge.md +136 -0
- package/docs/guides/claude-code-vs-akm-workflows.md +30 -0
- package/docs/guides/concepts.md +93 -0
- package/docs/guides/discover-and-load.md +158 -0
- package/docs/guides/getting-started.md +240 -0
- package/docs/guides/improve-the-library.md +246 -0
- package/docs/guides/knowledge-management.md +18 -0
- package/docs/guides/recipes/headless-install.md +97 -0
- package/docs/guides/recipes/website-source.md +28 -0
- package/docs/guides/run-workflows.md +279 -0
- package/docs/guides/scheduling.md +123 -0
- package/docs/guides/use-with-any-agent.md +129 -0
- package/docs/guides/wikis.md +81 -0
- package/docs/maintainers/README.md +19 -0
- package/docs/maintainers/curate-workmap.md +336 -0
- package/docs/maintainers/eval.md +3 -0
- package/docs/maintainers/local-development.md +108 -0
- package/docs/maintainers/release-checklist.md +103 -0
- package/docs/migration/README.md +2 -2
- package/docs/migration/release-notes/0.0.13.md +1 -1
- package/docs/migration/release-notes/0.1.0.md +1 -1
- package/docs/migration/release-notes/0.2.0.md +1 -1
- package/docs/migration/release-notes/0.3.0.md +1 -1
- package/docs/migration/release-notes/0.5.0.md +1 -1
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.3.md +2 -2
- package/docs/migration/release-notes/0.7.4.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +1 -1
- package/docs/migration/release-notes/0.8.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +1 -1
- package/docs/migration/release-notes/0.9.14.md +1 -1
- package/docs/migration/release-notes/0.9.15.md +1 -1
- package/docs/migration/release-notes/0.9.16.md +1 -1
- package/docs/migration/release-notes/0.9.17.md +1 -1
- package/docs/migration/release-notes/0.9.19.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +1 -1
- package/docs/migration/release-notes/README.md +27 -31
- package/docs/migration/v0.5-to-v0.6.md +759 -0
- package/docs/migration/v0.8-to-v0.9.md +1 -1
- package/docs/plans/0.9.2-agent-command-workflow-plan.md +423 -0
- package/docs/posts/README.md +30 -0
- package/docs/posts/akm-command-tour.md +495 -0
- package/docs/posts/akm-logo-sized.webp +0 -0
- package/docs/posts/belief-aware-memory-12.md +139 -0
- package/docs/posts/config-v2-lessons-16.md +191 -0
- package/docs/posts/improve-loop-autonomous-10.md +225 -0
- package/docs/posts/improve-pipeline-debugging-0803.md +179 -0
- package/docs/posts/intro-part-01.md +76 -0
- package/docs/posts/intro-part-02.md +221 -0
- package/docs/posts/intro-part-03.md +190 -0
- package/docs/posts/intro-part-04.md +221 -0
- package/docs/posts/llm-mode-reflect-13.md +166 -0
- package/docs/posts/openpalm-built-on-akm.md +86 -0
- package/docs/posts/progressive-disclosure-06.md +129 -0
- package/docs/posts/proposal-safety-net-15.md +112 -0
- package/docs/posts/release-0.5.0.md +247 -0
- package/docs/posts/release-0.6.0.md +117 -0
- package/docs/posts/release-0.7.0.md +159 -0
- package/docs/posts/release-0.8.0.md +332 -0
- package/docs/posts/scattered-skills-05.md +100 -0
- package/docs/posts/task-assets-persistent-workflows-11.md +222 -0
- package/docs/posts/team-skills-07.md +198 -0
- package/docs/posts/wiki-agent-knowledge-08.md +223 -0
- package/docs/posts/workflows-vaults-09.md +321 -0
- package/docs/product-surface.md +54 -0
- package/docs/reference/README.md +1 -2
- package/docs/reference/asset-types.md +168 -0
- package/docs/reference/cli.md +5 -6
- package/docs/reference/env-and-secrets.md +126 -0
- package/docs/reference/memory.md +124 -0
- package/docs/reference/refs.md +156 -0
- package/docs/reference/registry.md +489 -0
- package/docs/reference/website-sources.md +141 -0
- package/package.json +12 -15
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
# Task / Workflow Unification: One Target Vocabulary, One Prose Rule
|
|
2
|
+
|
|
3
|
+
Status: PROPOSAL v9 — v8 (the post-Opus-review redesign) revised against a
|
|
4
|
+
four-lens Sonnet panel, then re-verified claim-by-claim against the current
|
|
5
|
+
baseline (98 claims checked, 22 corrected; a further 7 corrections from an
|
|
6
|
+
audit of that pass). Review corpus:
|
|
7
|
+
[`reviews/task-workflow-unification/`](./reviews/task-workflow-unification/).
|
|
8
|
+
Baselined on `origin/main` @ `17a0dca`, which merged the 0.9 polish branch
|
|
9
|
+
(`71bb686`). Breaking changes are approved for 0.9.0.
|
|
10
|
+
Date: 2026-08-01
|
|
11
|
+
Related: [`workflow-format-unification.md`](./workflow-format-unification.md),
|
|
12
|
+
[`okf-support.md`](./okf-support.md),
|
|
13
|
+
[`docs/reference/workflows.md`](../../reference/workflows.md)
|
|
14
|
+
|
|
15
|
+
> **2026-08-18 owner clarification:**
|
|
16
|
+
> [Agent, Command, Engine, and Model Resolution](./agent-command-engine-model-design.md)
|
|
17
|
+
> is authoritative wherever this proposal discusses agent personas, command
|
|
18
|
+
> execution, command placeholders, engine/model cascading, tool policy,
|
|
19
|
+
> capability handling, or model aliases. In particular, this proposal's
|
|
20
|
+
> `with:`/named/positional command-template grammar, primary-bundle tool-policy
|
|
21
|
+
> ceiling, static engine-capability declarations, and built-in wildcard alias
|
|
22
|
+
> recommendations are superseded. The owner subsequently settled the 0.9.2
|
|
23
|
+
> source-format direction in the
|
|
24
|
+
> [0.9.2 implementation plan](../../plans/0.9.2-agent-command-workflow-plan.md):
|
|
25
|
+
> task v3 is GitHub-step-shaped, AKM Markdown and GitHub-shaped YAML are peer
|
|
26
|
+
> workflow formats, and both compile through one internal versioned IR. The
|
|
27
|
+
> concrete schemas and examples below are therefore non-normative. The
|
|
28
|
+
> still-compatible concepts — tasks as scheduling wrappers, agents as
|
|
29
|
+
> selectors rather than targets, task composition in workflow steps, live task
|
|
30
|
+
> resolution, and frozen workflow resolution — remain design input.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. Grounding — what tasks and workflows are in akm
|
|
35
|
+
|
|
36
|
+
Owner's model; everything below derives from it.
|
|
37
|
+
|
|
38
|
+
1. **A task is a bundle asset that abstracts over OS-scheduled work** —
|
|
39
|
+
discovered like any asset, *enabled* into a cron/launchd/schtasks entry
|
|
40
|
+
that executes the defined work or dispatches an agent with the task's
|
|
41
|
+
prompt. A platform-agnostic way to share repeatable processes behind one
|
|
42
|
+
CLI.
|
|
43
|
+
2. **A workflow step is a task** — defined inline or referenced by ref — so
|
|
44
|
+
the same repeatable process is composable without duplicating content or
|
|
45
|
+
config.
|
|
46
|
+
3. **Fewer concepts, lower cognitive load.** akm is a simple, intuitive
|
|
47
|
+
abstraction layer over the tools and processes autonomous agents use.
|
|
48
|
+
|
|
49
|
+
Not in scope: tasks do not grow `steps:`; workflows do not grow `schedule:`.
|
|
50
|
+
The unit of sharing is the asset, of scheduling the task, of procedure the
|
|
51
|
+
workflow.
|
|
52
|
+
|
|
53
|
+
## 2. The format (stable since v5–v6, corrections applied)
|
|
54
|
+
|
|
55
|
+
### 2.1 Targets
|
|
56
|
+
|
|
57
|
+
| Declaration | Work performed |
|
|
58
|
+
|---|---|
|
|
59
|
+
| *(none)* | Agent, prompted with **the nearest prose** — a task's body, or a step's `## <id>` section |
|
|
60
|
+
| `uses: <asset-ref>` | Execute the referenced asset per its subdir-declared type (§2.2) |
|
|
61
|
+
| `run: <shell text>` | Shell, no AI — GitHub-Actions semantics; `sh` on POSIX, `powershell` on Windows, `shell:` override |
|
|
62
|
+
|
|
63
|
+
`uses:` xor `run:` — one schema rule; the double-target error class is
|
|
64
|
+
structurally impossible. No ref-vs-inline sniffing exists.
|
|
65
|
+
|
|
66
|
+
> **The prose rule.** The machine surface names the target; the nearest
|
|
67
|
+
> prose is the instructions. With no target key, the prose *is* the work.
|
|
68
|
+
|
|
69
|
+
### 2.2 `uses:` — a closed set of four executable types
|
|
70
|
+
|
|
71
|
+
| Ref | Execution | Inputs |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `uses: commands/<n>` | Fill the template (§2.4), dispatch an agent | `with:` |
|
|
74
|
+
| `uses: scripts/<n>` | Execute per the script's `run`/`setup`/`cwd` — gated by the execution-activation policy (§5.6) | `env:` |
|
|
75
|
+
| `uses: tasks/<n>` *(steps only)* | Compose the task as this step's work (§2.3) | the task's own, overridable |
|
|
76
|
+
| `uses: workflows/<r>` *(tasks only)* | `runWorkflowSteps()` | `with:` → declared param flags |
|
|
77
|
+
|
|
78
|
+
Any other subdir (including `agents/` — a persona, not work) is an error
|
|
79
|
+
with a targeted hint. **`with:` replaces v5–v7's call-site `params:`** —
|
|
80
|
+
review finding M1 (3/3): `params:` already means *declarations* (name →
|
|
81
|
+
JSON Schema) in workflow frontmatter, and one key carrying declarations,
|
|
82
|
+
run-arguments, placeholder fills, *and* a cascading value was the same
|
|
83
|
+
overload this spec deletes `prompt:` for. GHA's `inputs:`/`with:` split
|
|
84
|
+
exists precisely here, and §2.4/§4 give `with:` exactly one meaning:
|
|
85
|
+
**inputs handed to the referenced asset, never cascaded.**
|
|
86
|
+
|
|
87
|
+
Two `uses:` modes differ in kind, named for authors: `tasks/<n>`
|
|
88
|
+
**composes** — the referenced definition becomes this step's own work —
|
|
89
|
+
while `workflows/<r>` **invokes** — a child run executes and returns.
|
|
90
|
+
`with:` merge on a composition chain (a step referencing a task that
|
|
91
|
+
itself targets a command or workflow) is per-key shallow merge, referencing
|
|
92
|
+
step wins; `with.arguments` is one key, replaced whole. The merged mapping
|
|
93
|
+
feeds the final target: placeholder fill for a command, declared param
|
|
94
|
+
flags for a workflow.
|
|
95
|
+
|
|
96
|
+
### 2.3 Steps are tasks — composition by reference
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
steps:
|
|
100
|
+
- id: lint
|
|
101
|
+
uses: tasks/lint-check # the task's target, fields, env, and body
|
|
102
|
+
timeout: 2m # call-site override (one cascade layer nearer)
|
|
103
|
+
- id: fix
|
|
104
|
+
run: bun run fix # inline task: same keys, defined here
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- Step keys override the referenced task's keys — the task and the step are
|
|
108
|
+
adjacent cascade layers (§4); `env:` concatenates task-then-step.
|
|
109
|
+
- Trigger keys (`schedule`, `enabled`) are consumed **only** by
|
|
110
|
+
`akm task sync` and, at fire time, the task runner's enabled gate
|
|
111
|
+
(`src/tasks/runner.ts:169` — v7's "sync-only" wording corrected).
|
|
112
|
+
Anywhere else they are no-ops with a lint notice; a referenced task
|
|
113
|
+
cannot double-fire.
|
|
114
|
+
- **Call-site prose is appended at freeze, not at dispatch.** Review
|
|
115
|
+
finding (3/3): there is no "one assembled prompt seam" — prompts are
|
|
116
|
+
built per-unit at dispatch, and the unit hash covers the *frozen
|
|
117
|
+
template*, not the assembled string. So: when the resolved work is
|
|
118
|
+
agent-dispatched, the step's section text is concatenated onto the
|
|
119
|
+
frozen instruction template (blank-line separator, byte-exact) **at
|
|
120
|
+
freeze**, which puts it inside the hash preimage automatically and keeps
|
|
121
|
+
the append ahead of the item/inputs/gate blocks. For shell work the
|
|
122
|
+
section is documentation, ignored at runtime.
|
|
123
|
+
- Refs resolve at freeze (§5.4), so in-flight runs are immune to edits.
|
|
124
|
+
- No nesting: a referenced task targeting `workflows/*` is a compile error
|
|
125
|
+
on a step; a task referencing a task is an error.
|
|
126
|
+
|
|
127
|
+
### 2.4 Command templates — filled against the real placeholder grammar
|
|
128
|
+
|
|
129
|
+
Review finding M2 (3/3): command placeholders are `$ARGUMENTS` / `$1`–`$9`
|
|
130
|
+
(positional) and `{{name}}` per the advertised grammar
|
|
131
|
+
(`extractParameters`, `src/output/renderers.ts:164-186`); the actual
|
|
132
|
+
filler is `fillPlaceholders()` in
|
|
133
|
+
`src/commands/agent/agent-dispatch.ts:67-72`, which substitutes only
|
|
134
|
+
positional `{{0}}` forms, leniently — a live bug fixed by this work, and
|
|
135
|
+
a second call site the new `with:` contract replaces. Three further
|
|
136
|
+
grammars for the same placeholders exist today and diverge from each
|
|
137
|
+
other: the indexer's recognition sniff `COMMAND_PLACEHOLDER_RE`
|
|
138
|
+
(`src/indexer/walk/matchers.ts:126`, consumed at `:239`) matching only
|
|
139
|
+
`$ARGUMENTS`/`$1`–`$3`; `extractCommandParameters`
|
|
140
|
+
(`src/indexer/passes/metadata.ts:440-461`), a near-clone of the display
|
|
141
|
+
grammar that differs from it in case-sensitivity and digit bounding; and
|
|
142
|
+
a lenient sniff at
|
|
143
|
+
`src/core/adapter/adapters/tool-dir-shared.ts:201-204`.
|
|
144
|
+
|
|
145
|
+
**Convergence is scoped to the fill and display grammars — the two
|
|
146
|
+
recognition sniffs keep their `$`-only forms.** Adding `{{name}}` to
|
|
147
|
+
`COMMAND_PLACEHOLDER_RE` would be a live mis-classification hazard, not a
|
|
148
|
+
cleanup: it returns specificity 18, outranking the directory rules
|
|
149
|
+
(10/15), so any `knowledge/`, `facts/`, or `instructions/` `.md`
|
|
150
|
+
containing a mustache token would be re-typed `command`. The recognition
|
|
151
|
+
gap is narrower than it looks anyway — `classifyByDirectory` /
|
|
152
|
+
`classifyByParentDirHint` (`matchers.ts:43-47`, `:147-156`, `:178-197`)
|
|
153
|
+
already type any `.md` under `commands/` as a command at specificity
|
|
154
|
+
10/15, beating `classifyBySmartMd`'s `knowledge` (5). The sniff is only
|
|
155
|
+
the fallback for command-shaped `.md` living *outside* `commands/`
|
|
156
|
+
without `tools:`/`agent:` frontmatter. The contract, defined against that
|
|
157
|
+
reality:
|
|
158
|
+
|
|
159
|
+
- `with:` mapping keys fill `{{name}}` placeholders.
|
|
160
|
+
- The reserved key `with.arguments` (string) fills `$ARGUMENTS`, and its
|
|
161
|
+
whitespace-split words fill `$1`–`$9`.
|
|
162
|
+
- An unmatched placeholder or unused `with:` key is a **lint warning and is
|
|
163
|
+
left verbatim** — not a runtime hard error, so imported `$ARGUMENTS`
|
|
164
|
+
commands remain usable as targets.
|
|
165
|
+
- `with.arguments` is reserved: a literal `{{arguments}}` placeholder is
|
|
166
|
+
filled by it too, with a lint warning about the shadowing. Words past
|
|
167
|
+
`$9` remain reachable only through `$ARGUMENTS`.
|
|
168
|
+
|
|
169
|
+
Filling happens at freeze (workflows) / dispatch (tasks), producing the
|
|
170
|
+
prompt string. Bodies remain verbatim — templating stays scoped to the
|
|
171
|
+
command asset type, whose definition is "a template with placeholders."
|
|
172
|
+
|
|
173
|
+
## 3. The task asset
|
|
174
|
+
|
|
175
|
+
`<bundle>/tasks/<id>.md`: the shared envelope (`$ref
|
|
176
|
+
akm-asset-envelope.json`, OKF v0.2 families included), trigger keys, at
|
|
177
|
+
most one target, and any §4 fields. No `version:` key. **Recognition
|
|
178
|
+
requires frontmatter `type: task`, honored in two subsystems** (R2
|
|
179
|
+
finding: v8 cited only one). At the bundle-adapter layer, the workflow
|
|
180
|
+
adapter is ordered ahead of the task and generic akm adapters in the
|
|
181
|
+
source-root probe list (6th of 11 —
|
|
182
|
+
`src/core/adapter/adapters/index.ts:73-90`; that array is `looksLikeRoot`
|
|
183
|
+
probe order, and only the adapter that claims a root ever calls
|
|
184
|
+
`recognize()` on its files), and inside an akm-workflow bundle it claims
|
|
185
|
+
every `.md` file whose frontmatter does not declare a contrary `type:`
|
|
186
|
+
(`akm-workflow-adapter.ts:67-70`, `:160`). At the per-file
|
|
187
|
+
indexer classifier — the path that actually types `tasks/*.md` during
|
|
188
|
+
normal indexing — `src/indexer/walk/matchers.ts` gains a `type: task`
|
|
189
|
+
branch **ordered before** its existing `"agent" in fm → command` rule
|
|
190
|
+
(`matchers.ts:234-236`), which would otherwise misclassify any task
|
|
191
|
+
carrying an `agent:` selector — including this section's own example.
|
|
192
|
+
Residence is a lint *expectation*, not a recognition signal.
|
|
193
|
+
|
|
194
|
+
````markdown
|
|
195
|
+
---
|
|
196
|
+
type: task
|
|
197
|
+
description: Weekly review digest.
|
|
198
|
+
schedule: "0 8 * * 1"
|
|
199
|
+
agent: agents/reviewer
|
|
200
|
+
timeout: 10m
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
Review the week's completed tasks and summarize action items.
|
|
204
|
+
````
|
|
205
|
+
|
|
206
|
+
````markdown
|
|
207
|
+
---
|
|
208
|
+
type: task
|
|
209
|
+
description: Full nightly quality sweep.
|
|
210
|
+
schedule: "15 2 * * *"
|
|
211
|
+
run: akm improve --strategy thorough --skip-if-locked
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
# Nightly improve sweep
|
|
215
|
+
|
|
216
|
+
Runbook prose: indexed, shown, never executed.
|
|
217
|
+
````
|
|
218
|
+
|
|
219
|
+
````markdown
|
|
220
|
+
---
|
|
221
|
+
type: task
|
|
222
|
+
schedule: "@daily"
|
|
223
|
+
uses: commands/weekly-review
|
|
224
|
+
with: { scope: team }
|
|
225
|
+
env: [env/prod]
|
|
226
|
+
---
|
|
227
|
+
````
|
|
228
|
+
|
|
229
|
+
Lifecycle unchanged: discover via search/show; enable via `enabled:` +
|
|
230
|
+
`task sync`; the OS entry still invokes `akm task run <id>`. Lifecycle
|
|
231
|
+
interactions pinned (review minors): `status: draft` → `sync` never
|
|
232
|
+
installs, regardless of `enabled:`; `status: deprecated` → installs with a
|
|
233
|
+
warning; a previously-installed task that becomes `draft` (or
|
|
234
|
+
`enabled: false`) is uninstalled by the next `sync` — reconciliation is to
|
|
235
|
+
desired state, both directions.
|
|
236
|
+
|
|
237
|
+
Two adapter-policy changes with named mechanisms (panel M13 follow-up):
|
|
238
|
+
the akm adapter's current `type: "task"` special-case — parse as pure
|
|
239
|
+
YAML, `frontmatter: null`, so markdown base checks never fire
|
|
240
|
+
(`akm-adapter.ts:404-412`) — is **removed with the format**, and markdown
|
|
241
|
+
tasks get the full markdown base-check suite; and tasks are declared
|
|
242
|
+
**improve-ineligible**. No such site exists on `BundleAdapter`
|
|
243
|
+
(`src/core/adapter/bundle-adapter.ts:69-121` declares only adapter-level
|
|
244
|
+
optional methods), so v8's "where the adapter already declares per-type
|
|
245
|
+
capabilities" was wrong. Three candidate homes, cheapest first: the
|
|
246
|
+
existing per-type refusal set `DISTILL_REFUSED_INPUT_TYPES`
|
|
247
|
+
(`src/commands/improve/distill.ts:134-142`, already gated at
|
|
248
|
+
`eligibility.ts:380` and documented as driving the planner "for free")
|
|
249
|
+
gains `task`; or the per-type table `TYPE_PRESENTATION`
|
|
250
|
+
(`src/core/type-presentation.ts:74`) gains an eligibility flag; or
|
|
251
|
+
`eligibility.ts` gains an explicit type filter. A task body is an
|
|
252
|
+
executable prompt,
|
|
253
|
+
not curatable knowledge. Lint runs; improve never rewrites it.
|
|
254
|
+
|
|
255
|
+
## 4. Configuration: two selectors, one value vocabulary, one cascade — built, not "exposed"
|
|
256
|
+
|
|
257
|
+
v7 claimed freeze "already implements" the cascade. Review finding C4
|
|
258
|
+
(3/3): freeze's layer list is exactly `[documentDefaults, unit]`
|
|
259
|
+
(`freeze.ts:50`); `DefaultsSchema` has **no** `model` field and is
|
|
260
|
+
`.passthrough()`, so v7's own worked example is a silent no-op today
|
|
261
|
+
(`config-schema.ts:102-108`); `defaults.llm` is hard-rejected as retired;
|
|
262
|
+
no persona layer exists. What exists is a two-layer resolver whose *shape*
|
|
263
|
+
proves the pattern fits. This section specifies **building** the rest.
|
|
264
|
+
|
|
265
|
+
**Selectors** (nearest wins; each picks a node whose fields join the
|
|
266
|
+
cascade):
|
|
267
|
+
|
|
268
|
+
| Selector | Node | Source |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| `engine:` | execution node | config `engines.<name>` |
|
|
271
|
+
| `agent:` | persona node | bundle `agents/<name>` |
|
|
272
|
+
|
|
273
|
+
**Value fields** — legal at every layer, merged per-field, nearest wins;
|
|
274
|
+
`env:` concatenates: `model` · `temperature` · `max_tokens` ·
|
|
275
|
+
`extra_params` · `timeout` · `env` · `cwd` · `shell` · `on_error` · `retry`.
|
|
276
|
+
|
|
277
|
+
(`with:` is *not* a value field — it binds to one referenced asset. `params`
|
|
278
|
+
no longer exists as a field name outside workflow declarations. `on_error`/
|
|
279
|
+
`retry` join the vocabulary because `defaults.on_error` already exists at
|
|
280
|
+
document level today — review M12 — making "graph keys are steps-only"
|
|
281
|
+
false for them; they remain meaningless on a task and lint says so. Value
|
|
282
|
+
fields other than `timeout`/`env` on a `uses: workflows/*` task draw the
|
|
283
|
+
same inapplicable-field notice — they configure a unit, and a workflow
|
|
284
|
+
invocation has none.)
|
|
285
|
+
|
|
286
|
+
**Merge classes, stated once** (panel finding: a generic "nearest wins"
|
|
287
|
+
would silently downgrade the existing deep-merge): **scalars** (`model`,
|
|
288
|
+
`temperature`, `max_tokens`, `timeout`, `cwd`, `shell`, `on_error`) —
|
|
289
|
+
nearest wins whole; **mappings** (`extra_params`) — deep-merged along the
|
|
290
|
+
chain, preserving today's `deepMergeConfig` behavior
|
|
291
|
+
(`freeze.ts:211-216`); **lists** (`env`) — concatenated, later wins;
|
|
292
|
+
**`retry`** — replaced whole (half-merging `max`/`on` would be
|
|
293
|
+
incoherent). `with:` merges per-key at its target (§2.2), outside the
|
|
294
|
+
cascade.
|
|
295
|
+
|
|
296
|
+
**Layers, far → near:**
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
config defaults: → engines.<selected> → agents/<selected> → document defaults: → uses: tasks/<ref> → step/task keys
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
(`document defaults:` is the workflow frontmatter's `defaults:` block and
|
|
303
|
+
exists only there — a standalone task IS its own call site, so for tasks
|
|
304
|
+
that layer is simply absent, not an implied new task key.)
|
|
305
|
+
|
|
306
|
+
**What must be built (the honest inventory):**
|
|
307
|
+
|
|
308
|
+
1. `DefaultsSchema` gains the value fields, and stops silently swallowing
|
|
309
|
+
unknown keys (strict with migration-safe notices).
|
|
310
|
+
2. A **persona snapshot**: the agent asset resolved through the
|
|
311
|
+
provenance ceiling — 07 P1-D, today inline in the show command
|
|
312
|
+
(`src/commands/read/show.ts:433-445`): self-declared `tools:` honored
|
|
313
|
+
ONLY for the operator's **primary bundle**, keyed off primary-bundle
|
|
314
|
+
identity, explicitly *not* the writable bit, failing closed. That
|
|
315
|
+
check is **extracted into a shared persona resolver** consumed by both
|
|
316
|
+
`show` and freeze — a named refactor in §9, since its current home is
|
|
317
|
+
a CLI formatter. The snapshot `{systemPrompt, toolPolicy, model,
|
|
318
|
+
…valueFields}` freezes into the plan; `toolPolicy` is consumed by
|
|
319
|
+
agent-kind engines and draws the standard unconsumed-field notice on
|
|
320
|
+
LLM engines. (This also fixes the live bug where `prompt: agents/x`
|
|
321
|
+
ships raw file bytes *including frontmatter* to the model —
|
|
322
|
+
`runner.ts:592-593`.)
|
|
323
|
+
3. One cascade module — a new shared module (e.g. `src/core/cascade.ts`;
|
|
324
|
+
there is no `src/exec/` tree today, only `src/workflows/exec/` and
|
|
325
|
+
`src/tasks/`) — the only implementation of layer merge, consumed at
|
|
326
|
+
freeze (workflows) and dispatch (tasks). It
|
|
327
|
+
consolidates the three engine/model resolution sites that exist today
|
|
328
|
+
(`freeze.ts:163-209`, `tasks/runner.ts:479-514`, engine-resolution)
|
|
329
|
+
including their subtly divergent opencode-sdk `llmEngine` fallback
|
|
330
|
+
rules — one implementation, one fallback rule.
|
|
331
|
+
4. **Capability notices replace both kind-gates.** The task path's hard
|
|
332
|
+
error and freeze's guard — which review M6 showed is *dead code*
|
|
333
|
+
(`freeze.ts:67-73` computes `llm` only for llm engines, then guards
|
|
334
|
+
`kind !== "llm"`), meaning workflows already silently drop these fields
|
|
335
|
+
— are both replaced by one behavior: engines declare the fields they
|
|
336
|
+
consume; an unconsumed field is a lint/freeze **notice**. Strictness
|
|
337
|
+
stays only where the kind is known at authoring time: the engine node's
|
|
338
|
+
own schema (which today is `.passthrough()` + blacklist; it becomes
|
|
339
|
+
genuinely strict as part of this work — review minor).
|
|
340
|
+
5. Aliases: resolution runs once, after the cascade settles `model`,
|
|
341
|
+
through the existing `resolveModel()` chain. Review M4 (3/3): the
|
|
342
|
+
builtin table has only `claude`/`opencode` columns, so portability to
|
|
343
|
+
LLM endpoints is currently *false* — the builtin entries gain a `"*"`
|
|
344
|
+
column, and an alias that resolves nowhere for the selected platform is
|
|
345
|
+
a freeze/lint notice, not silent pass-through.
|
|
346
|
+
6. The gate judge (`workflow.judgeEngine`) stays outside the cascade in
|
|
347
|
+
0.9.0 — frozen separately, as shipped. Noted, not changed.
|
|
348
|
+
|
|
349
|
+
One sentence to teach: *set a field where it should usually apply;
|
|
350
|
+
override it closer when a case differs; the nearest value wins.*
|
|
351
|
+
|
|
352
|
+
## 5. Execution architecture
|
|
353
|
+
|
|
354
|
+
### 5.1 One target model, two executors
|
|
355
|
+
|
|
356
|
+
A shared target module resolves every declaration to a typed value:
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
Target = { kind: agent-prose } # nearest prose is the prompt
|
|
360
|
+
| { kind: command, ref, with } # template fill → agent prompt
|
|
361
|
+
| { kind: script, ref } # script asset, exec
|
|
362
|
+
| { kind: shell, text, shell } # inline run:
|
|
363
|
+
| { kind: workflow, ref, with } # tasks only
|
|
364
|
+
| { kind: task, ref } # steps only; resolves recursively once
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Execution is a strategy seam with exactly two implementations:
|
|
368
|
+
|
|
369
|
+
- **AgentUnitExecutor** — today's paths (task runner's `executeRunner()`;
|
|
370
|
+
the orchestrator's journaled `UnitDispatcher`), consuming an assembled
|
|
371
|
+
prompt + frozen engine + persona snapshot.
|
|
372
|
+
- **ShellUnitExecutor** — `Bun.spawn()` for `run:` text and script assets,
|
|
373
|
+
used by both the task runner and the orchestrator.
|
|
374
|
+
|
|
375
|
+
Staging is symmetric and named (panel: the task path's staging was
|
|
376
|
+
unstated): **tasks** run *resolve → execute* — the same resolve stage
|
|
377
|
+
(cascade, persona, targets, templates) with no plan persistence;
|
|
378
|
+
**workflows** run *compile → resolve → freeze → execute* (§5.4). Both
|
|
379
|
+
executors sit behind one interface; each surface wraps results into its
|
|
380
|
+
own recording sink (`task_history`/`logs.db` vs the run journal) — the
|
|
381
|
+
adapter lives at the sink, not inside the executor, which is how the
|
|
382
|
+
`RunnerSpec`-vs-`UnitDispatchRequest` split stays out of the executors'
|
|
383
|
+
type signatures: the resolve stage produces one dispatch plan both
|
|
384
|
+
consume. **ShellUnitExecutor is extracted from the task runner's existing
|
|
385
|
+
hardened command path** (`runManagedSubprocess`, `src/core/subprocess.ts`,
|
|
386
|
+
called at `tasks/runner.ts:277-289`: process-group spawn, SIGTERM→SIGKILL
|
|
387
|
+
kill ladder, injectable spawn/timer seams, `AKM_EVENT_SOURCE` stamping)
|
|
388
|
+
and adopted by the orchestrator — not a new spawn wrapper.
|
|
389
|
+
(`src/tasks/backends/exec-utils.ts` is the scheduler-backend exec seam,
|
|
390
|
+
not part of this path.) Composition is monotemporal by rule: a referenced
|
|
391
|
+
task's fields join the cascade from the copy resolved at freeze, under the
|
|
392
|
+
workflow's config snapshot — a composed task never re-reads config at
|
|
393
|
+
dispatch.
|
|
394
|
+
|
|
395
|
+
Run recording stays split (cron job vs journaled plan) — that boundary is
|
|
396
|
+
real. Everything upstream unifies: target resolution, template filling,
|
|
397
|
+
cascade, alias resolution, env assembly.
|
|
398
|
+
|
|
399
|
+
### 5.2 Shell units in the IR — v3 → v4, not a non-goal
|
|
400
|
+
|
|
401
|
+
Review C2 (3/3): `IrInvocation.engine` and `UnitDispatchRequest.engine`
|
|
402
|
+
are required, the engine snapshot union is closed, freeze hard-errors with
|
|
403
|
+
no engine, and the IR rejects empty instructions — v7's "no IR changes"
|
|
404
|
+
was false. Owned properly:
|
|
405
|
+
|
|
406
|
+
- `IrInvocation` becomes a discriminated union:
|
|
407
|
+
`{ kind: "agent", engine, … }` | `{ kind: "shell", script, shell, cwd,
|
|
408
|
+
timeoutMs }` (`timeout` is a value field for `run:`, so the shell member
|
|
409
|
+
carries it). Shell members exclude engine/llm fields **structurally** —
|
|
410
|
+
by union-member shape, not by decoder-validated absence.
|
|
411
|
+
- Engine resolution happens **per unit kind**: shell units need no engine,
|
|
412
|
+
so a shell-only workflow freezes on an engine-less machine (the current
|
|
413
|
+
"no engine selected" error narrows to plans containing agent units).
|
|
414
|
+
- Instructions become optional for shell units (parser + IR relaxation —
|
|
415
|
+
review M10; agent units keep the non-empty invariant).
|
|
416
|
+
- Shell units journal as normal `workflow_run_units` rows (status, timing,
|
|
417
|
+
attempts, `failure_reason`; no tokens). Under the external driver
|
|
418
|
+
protocol, shell units are **orchestrator-owned**: `brief` lists them as
|
|
419
|
+
non-claimable and the engine executes them natively — a harness never
|
|
420
|
+
claims shell work.
|
|
421
|
+
- Crash/restart: shell units use the same claim/lease rows as agent
|
|
422
|
+
units; a running shell unit whose lease expires re-dispatches on resume
|
|
423
|
+
under its retry policy. Re-execution idempotency is the author's
|
|
424
|
+
contract — the same contract every cron job already carries — stated in
|
|
425
|
+
the docs, not solvable by the engine.
|
|
426
|
+
- Plan IR version bumps to 4; decoders reject v4 plans in older binaries
|
|
427
|
+
(existing plan-version machinery).
|
|
428
|
+
|
|
429
|
+
### 5.3 Unit identity — hashVersion 5, preimage stated
|
|
430
|
+
|
|
431
|
+
Review C3 (3/3): hashVersion 4's preimage (`step-work.ts:333-392`) covers
|
|
432
|
+
the frozen template bytes but none of the *other* new inputs — shell text,
|
|
433
|
+
the `uses:` target kind/ref/content hash, and the persona snapshot.
|
|
434
|
+
Without a bump, editing `run:` text, re-pointing a `uses:` ref, or editing
|
|
435
|
+
`agents/<n>` would silently reuse completed journal rows. (Freeze-time
|
|
436
|
+
prose appending, §2.3, already rides in via `template`.) hashVersion 5's
|
|
437
|
+
preimage, explicitly:
|
|
438
|
+
|
|
439
|
+
| Field | Notes |
|
|
440
|
+
|---|---|
|
|
441
|
+
| template instructions | **post** freeze-time prose append (§2.3) and **post** template fill, so `with:` values are covered via the filled bytes |
|
|
442
|
+
| target kind + `uses:` ref + resolved content hash | a re-pointed or edited referenced asset re-dispatches; also the retained provenance for composed steps (the "single-file provenance" minor). Script bytes are **embedded at resolve**, like a command's filled text — execution never re-reads live files, keeping composition monotemporal (§5.1) |
|
|
443
|
+
| persona snapshot hash | system prompt, tool policy, and value fields of the frozen persona — editing `agents/<n>` re-dispatches (panel critical: omitted in v8) |
|
|
444
|
+
| shell text, `shell`, `cwd` | shell units |
|
|
445
|
+
| item / inputs / params / dispatch / invocation / schema | as v4 |
|
|
446
|
+
| env **names** + env **literal values** | see §5.5 — literals are plan content; ref-sourced values stay names-only |
|
|
447
|
+
| isolation, gateFeedback | as v4 |
|
|
448
|
+
|
|
449
|
+
`retry`/`on_error` stay excluded (policy, not input) — unchanged rationale.
|
|
450
|
+
|
|
451
|
+
### 5.4 Freeze becomes two stages; lint gets a dry freeze
|
|
452
|
+
|
|
453
|
+
Review M11: `uses:` resolution needs asset IO inside a function documented
|
|
454
|
+
pure, and freeze currently has exactly one caller (run start), so every
|
|
455
|
+
composition error would escape lint. Restructure: **compile** (pure) →
|
|
456
|
+
**resolve** (asset loader injected: personas, referenced tasks, command
|
|
457
|
+
templates) → **freeze** (snapshot + hash). `akm lint --type workflows`
|
|
458
|
+
runs compile+resolve with the real loader and no persistence, so dangling
|
|
459
|
+
`uses:` refs, back-door workflow nesting, placeholder mismatches, and
|
|
460
|
+
capability notices all surface at lint time. Composed instructions carry
|
|
461
|
+
the existing 256 KiB cap with a lint warning at 80%.
|
|
462
|
+
|
|
463
|
+
### 5.5 `env:` — one shape, two provenance classes
|
|
464
|
+
|
|
465
|
+
Format unchanged from v6 (list of env-asset refs and literal mappings,
|
|
466
|
+
later wins, bare-mapping shorthand). Semantics corrected by review M3
|
|
467
|
+
(3/3), which showed "strictly additive" was false at the IR/hash/redaction
|
|
468
|
+
layers. The clean line is **provenance, not shape**:
|
|
469
|
+
|
|
470
|
+
- **Literal entries** are plan content: author-written bytes already
|
|
471
|
+
durable in the source file — frozen into the plan, hashed (§5.3), shown
|
|
472
|
+
by `brief`, **never redacted** (`LOG_LEVEL: debug` must not scrub
|
|
473
|
+
"debug" from every log — the over-redaction finding).
|
|
474
|
+
- **Ref-sourced entries** (`env/<n>` groups, `secrets/<n>` values) are
|
|
475
|
+
runtime-resolved: hashed by **name only**, resolved at dispatch, values
|
|
476
|
+
joined to `sensitiveValues` for redaction, never durable. (Existing
|
|
477
|
+
contract, now stated as the rule.)
|
|
478
|
+
- IR `env` becomes a typed entry list (ref | literal-pair) — an IR v4
|
|
479
|
+
change, not "additive."
|
|
480
|
+
- Env assembly moves per-unit where fan-out requires it: a `map:` step
|
|
481
|
+
with a shell target receives `AKM_ITEM` (JSON) and `AKM_ITEM_INDEX`
|
|
482
|
+
per unit — set as env-object entries on the spawned process (the
|
|
483
|
+
`runManagedSubprocess` `env:` pattern — `src/core/subprocess.ts`, as
|
|
484
|
+
used at `tasks/runner.ts:284`), never spliced into shell text.
|
|
485
|
+
- Literal entries run the existing secret-shape heuristic
|
|
486
|
+
(`param-secrets.ts`'s `detectSecretShapedParams`, built for exactly this
|
|
487
|
+
risk on params): a secret-shaped literal is a lint error pointing at
|
|
488
|
+
`secrets/<n>`.
|
|
489
|
+
- The split is enforced at one place: a single env-assembly resolver (§8
|
|
490
|
+
plumbing) is the only producer of env entries and of their
|
|
491
|
+
`sensitiveValues` contributions, so the literal/ref line cannot
|
|
492
|
+
silently diverge per call site.
|
|
493
|
+
|
|
494
|
+
### 5.6 Executing scripts inherits the tools: ceiling — no new trust machinery
|
|
495
|
+
|
|
496
|
+
v8 proposed a per-bundle grant key. The panel killed it twice over:
|
|
497
|
+
`activation-policy.ts` documents a standing decision **against new
|
|
498
|
+
persisted trust machinery**, and the claimed precedent — the `tools:`
|
|
499
|
+
provenance ceiling — has **no override at all**. v9 inherits the ceiling
|
|
500
|
+
exactly instead of imitating it loosely:
|
|
501
|
+
|
|
502
|
+
- Shell-class work (a script asset, or the `run:` text of a task) executes
|
|
503
|
+
**only when its defining asset lives in the operator's primary bundle** —
|
|
504
|
+
the same line 07 P1-D draws for self-declared tool grants
|
|
505
|
+
(`show.ts:433-445`): keyed off primary-bundle identity, explicitly *not*
|
|
506
|
+
the writable bit, failing closed.
|
|
507
|
+
- Evaluated in the **resolve stage** (§5.1) — the shared stage both
|
|
508
|
+
surfaces run before any execution — so there is no sync-time/fire-time
|
|
509
|
+
gap and no standing grant for a bundle update to swap content under.
|
|
510
|
+
- Composition chains inherit the rule from the **defining asset's own
|
|
511
|
+
source**: a primary-bundle task that `uses:` a third-party script — or
|
|
512
|
+
composes a third-party task whose target is shell — refuses with an
|
|
513
|
+
error naming the ref and its source. No chain launders provenance.
|
|
514
|
+
- The remedy is an existing verb, not a config bit: `akm clone <ref>`
|
|
515
|
+
copies the asset into the primary bundle, where the operator owns and
|
|
516
|
+
reviews the bytes; the refusal message says exactly that.
|
|
517
|
+
- Scope: this ceiling governs the **new non-AI exec surface only**.
|
|
518
|
+
Agent-dispatched third-party tasks remain governed by the existing
|
|
519
|
+
scheduling gates (setup/sync review, `enabled:`), unchanged.
|
|
520
|
+
|
|
521
|
+
Zero new config, zero persisted trust state. Loosening later (per-bundle
|
|
522
|
+
grants) is an additive future decision that must revisit the
|
|
523
|
+
activation-policy document — deliberately out of 0.9.0 scope.
|
|
524
|
+
|
|
525
|
+
### 5.7 Shell ergonomics
|
|
526
|
+
|
|
527
|
+
- Bare `akm` in shell/script work resolves to the current installation by
|
|
528
|
+
a **synthesized shim**, not a bare PATH prepend: `resolveAkmInvocation()`
|
|
529
|
+
can return a multi-element launcher invocation (`bun <script>` — the
|
|
530
|
+
case the argv-splice was built for, panel M9 follow-up), so the runner
|
|
531
|
+
writes a platform-appropriate shim (sh script / `.cmd`) invoking the
|
|
532
|
+
exact resolved invocation into the run's temp dir and prepends that dir
|
|
533
|
+
to the child `PATH` (case-insensitive `Path` merge on Windows). Replaces
|
|
534
|
+
the argv rewrite for shell work and covers scripts for free; the task
|
|
535
|
+
runner keeps the argv rewrite only for legacy `.yml` until retirement.
|
|
536
|
+
- `cwd:` under `isolation: worktree` is resolved relative to the worktree
|
|
537
|
+
root; `cwd:` on the LLM runner is a capability notice (review minors).
|
|
538
|
+
|
|
539
|
+
## 6. GitHub Actions alignment — familiar, not copied
|
|
540
|
+
|
|
541
|
+
Adopted: `uses:`/`run:` pair with mutual exclusion; **`with:` for inputs
|
|
542
|
+
to the referenced thing** (returned to the adopted column by M1);
|
|
543
|
+
step-level keys with no nesting bag; shell semantics with per-OS defaults
|
|
544
|
+
and `shell:`; `env:` bare-mapping shorthand; `cwd:`; `on_error`/`timeout`
|
|
545
|
+
as step keys. Kept akm: typed asset refs (the subdir says what executes —
|
|
546
|
+
GHA's `uses:` is opaque); `params:` reserved for declarations; no step
|
|
547
|
+
`name:`; bundles as the sharing unit.
|
|
548
|
+
|
|
549
|
+
## 7. Steps flatten to the task shape — with the schema collision fixed
|
|
550
|
+
|
|
551
|
+
The `unit:` bag and `map.unit` are still deleted; targets and value fields
|
|
552
|
+
sit on the step; `map:` keeps `over`/`concurrency`/`reducer`. But v7's
|
|
553
|
+
"duplicate `output` wart" was **wrong** — review C1 (3/3):
|
|
554
|
+
`unit.output` compiles to the per-dispatch structured-result `schema`
|
|
555
|
+
(driving structured retry / `parse_error`) while `step.output` compiles to
|
|
556
|
+
`outputSchema`, the promoted artifact the gate validates
|
|
557
|
+
(`compile.ts:204,229` — verified). Two concepts, two homes:
|
|
558
|
+
|
|
559
|
+
- **`output:`** on a step — the step's **artifact** schema, all step kinds.
|
|
560
|
+
On a unit step it also serves as the dispatch result schema (result *is*
|
|
561
|
+
the artifact).
|
|
562
|
+
- **`map.output:`** — the **per-item** result schema of a map step's units;
|
|
563
|
+
the step's `output:` continues to describe the reduced artifact.
|
|
564
|
+
|
|
565
|
+
```yaml
|
|
566
|
+
- id: review
|
|
567
|
+
map: { over: steps.intake.output.files, concurrency: 3, output: { type: object } }
|
|
568
|
+
output: { type: array } # what `steps.review.output` resolves to
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## 8. Migration — inside the hardened 0.9.0 cutover
|
|
572
|
+
|
|
573
|
+
Rebuilt against the `71bb686` migrator and review M7 (3/3):
|
|
574
|
+
|
|
575
|
+
- **The converter joins the content-migration step with a vendored,
|
|
576
|
+
frozen copy of the v2 task parser** — the current
|
|
577
|
+
`task-target-ref-migration.ts` imports the *live* parser from `src/`,
|
|
578
|
+
which violates the frozen-migrator principle and breaks the moment the
|
|
579
|
+
live parser is replaced; that gets fixed as part of this work.
|
|
580
|
+
- Mapping: `command: <shell string>` → `run:` verbatim; `command:
|
|
581
|
+
[argv…]` → `run:` with each element shell-escaped **for POSIX `sh`, the
|
|
582
|
+
migrated task recording `shell: sh` explicitly** so the Windows
|
|
583
|
+
`powershell` default never reinterprets the quoting; `prompt: |` →
|
|
584
|
+
body; `prompt: commands/x` → `uses:` + `with:`; `prompt: agents/x` →
|
|
585
|
+
`agent:`; `prompt: ./file.md` → inlined; `workflow:`+`params` →
|
|
586
|
+
`uses: workflows/…` + `with:`; `timeoutMs` → `timeout`;
|
|
587
|
+
`llm.maxTokens`/`llm.temperature`/`llm.extraParams` → flat fields;
|
|
588
|
+
**`name:` → the body's H1** when the converted body has none, else a
|
|
589
|
+
per-task migration notice (never silently dropped);
|
|
590
|
+
`llm.supportsJsonSchema`/`contextLength`/`enableThinking` are
|
|
591
|
+
endpoint-capability facts that belong on the **engine node** — the
|
|
592
|
+
migrator emits a per-task notice naming the value and the config key
|
|
593
|
+
(lossy-with-notice, never silent).
|
|
594
|
+
- Scheduler entries untouched: ids and the `akm task run <id>` ABI do not
|
|
595
|
+
change.
|
|
596
|
+
- **The `.yml` tombstone rule** replaces v7's false "structural" claim
|
|
597
|
+
(refusals key on config/DB shape, not stray files, and placement
|
|
598
|
+
filters by extension — a stray `.yml` today would be invisible or
|
|
599
|
+
wrongly installed): task discovery keeps matching `tasks/*.yml`
|
|
600
|
+
**permanently, as a diagnostic**. In **writable** bundles, `sync`,
|
|
601
|
+
`doctor`, and `lint` hard-error naming the file and the fix; in
|
|
602
|
+
**read-only/third-party** bundles the same diagnostic is a warning —
|
|
603
|
+
the operator cannot edit those files, matching the migrator's existing
|
|
604
|
+
read-only carve-out (`task-target-ref-migration.ts:253-271`). Either
|
|
605
|
+
way a `.yml` is never installed and never silently skipped.
|
|
606
|
+
`<id>.yml` + `<id>.md` colliding on one conceptId is the same named
|
|
607
|
+
error. **Conversion is interruption-safe by ordering**: the migrator
|
|
608
|
+
journals the `.md` write and verifies it before removing the `.yml`,
|
|
609
|
+
and the collision diagnostic special-cases the byte-equivalent
|
|
610
|
+
mid-migration pair (resume completes the removal instead of erroring on
|
|
611
|
+
the migrator's own half-applied state — the panel's crash-window
|
|
612
|
+
finding; the current *backup* model journals whole-DB/config artifacts
|
|
613
|
+
only (`migration-backup.ts:54`), so per-file crash safety lives in the
|
|
614
|
+
content-migration step's own resume ledger —
|
|
615
|
+
`content-migration-report.json`'s `reservedRenames`
|
|
616
|
+
(`config-migrate.ts:518-575`); the `.md`-write-then-`.yml`-delete
|
|
617
|
+
ordering extends that existing ledger rather than introducing per-file
|
|
618
|
+
journaling, costed in §9).
|
|
619
|
+
- Embedded templates convert to `.md`; `listEmbeddedTasks` and `akm
|
|
620
|
+
setup`'s task review move to markdown-aware editing (the current YAML
|
|
621
|
+
round-trip would destroy bodies — review minor).
|
|
622
|
+
- The id-grammar work (subdir ids, scheduler-id `/` → `--` mapping with
|
|
623
|
+
collision lint) lands **in the same migration step, before scheduler
|
|
624
|
+
reconciliation** — sequencing the panel flagged as unstated.
|
|
625
|
+
- The pre-flatten workflow schema (`unit:`, `map.unit`, `defaults.llm`)
|
|
626
|
+
converts in the same step: bag fields lift, `llm` flattens,
|
|
627
|
+
`unit.output` → `map.output` or step `output:` per §7.
|
|
628
|
+
|
|
629
|
+
## 9. Cost inventory — what this actually changes
|
|
630
|
+
|
|
631
|
+
Honest replacement for v7's §10 (review: "non-goals false ×4").
|
|
632
|
+
|
|
633
|
+
| Surface | Change |
|
|
634
|
+
|---|---|
|
|
635
|
+
| IR | v3 → v4: invocation union, optional instructions (shell), typed env entries, `map.output` |
|
|
636
|
+
| Unit hash | hashVersion 4 → 5 (§5.3 preimage) |
|
|
637
|
+
| Freeze | two-stage (compile/resolve/freeze), per-kind engine resolution, persona snapshot, prose append, capability notices |
|
|
638
|
+
| Dispatch | executor strategy (agent/shell); persona fields reach `UnitDispatchRequest` |
|
|
639
|
+
| Schemas | shared target+value defs; task schema rewritten; workflow schema flattened; `DefaultsSchema` extended and made strict; engine schemas made strict |
|
|
640
|
+
| Parsers | `parseTaskDocument` retired to the migrator (vendored); unified parser gains task recognition; section-required rule relaxed per target kind; the indexer classifier (`matchers.ts`) gains a `type: task` branch ordered ahead of the `"agent" in fm` rule |
|
|
641
|
+
| Adapters | markdown task recognition (`type: task`); the `type: "task"` pure-YAML special-case removed (markdown base checks apply); improve-ineligibility declared per-type (§3 — `DISTILL_REFUSED_INPUT_TYPES` is the cheapest of three homes); akm-task format-family goldens rewritten directly (they carry `specificationGolden: true` / `adapterStatus: NOT IMPLEMENTED`, and `DESIGNATIONS.json` does not cover that tree at all). **DESIGNATIONS re-pointing is mandatory pre-work**: six entries are touched — `cli/c-tasks-family.json` (already `re-baseline`, chunk 9) plus five goldens pinning `tasks/*.yml` paths — `recognition/all-types.json`, `placement/all-types.json`, `minting/oracle.json` (chunk 4), `lint/all-types.json` (chunk 3), `renderer/all-types.json` (chunk 8) — whose `reBaselineChunk` must be re-pointed at this change *before* it lands, per the DESIGNATIONS `$policy` surface-owner rule |
|
|
642
|
+
| Named refactors | 07 P1-D ceiling extracted from `show.ts` into a shared persona resolver; ShellUnitExecutor extracted from the task runner's hardened command path; the three engine/model resolution sites consolidated into the cascade module; the `akm` shim mechanism; per-file create-verify-delete ordering added to the content-migration step's existing `reservedRenames` resume ledger |
|
|
643
|
+
| CLI | `task create`; `task add` retires with `.yml`; capability notices in lint/doctor |
|
|
644
|
+
| Storage | `task_history.target_kind` values widened (additive) |
|
|
645
|
+
| Docs/tests | reference docs, ~10 templates, format-family goldens, parser/freeze/executor suites |
|
|
646
|
+
|
|
647
|
+
Inherited bugs fixed en route: `{{0}}`-only placeholder filling; raw
|
|
648
|
+
frontmatter shipped to models via `prompt: agents/x`; subdir task ids
|
|
649
|
+
indexed but unrunnable (`validateTaskId` rejects `/` — the id grammar
|
|
650
|
+
gains subdir support with the scheduler-id mapping documented); freeze's
|
|
651
|
+
dead llm guard.
|
|
652
|
+
|
|
653
|
+
## 10. Non-goals (now true)
|
|
654
|
+
|
|
655
|
+
- No new orchestration semantics: `map`/`route`/`gate` behavior, leases,
|
|
656
|
+
check-ins, replay *logic*, and the driver protocol are unchanged (shell
|
|
657
|
+
units are orchestrator-owned under it).
|
|
658
|
+
- No scheduler-backend, `sync`-reconciliation, or `akm task run <id>` ABI
|
|
659
|
+
changes.
|
|
660
|
+
- No change to how command/script/agent/env/secret assets are authored.
|
|
661
|
+
- No multi-file config merging; the cascade layers are config nodes,
|
|
662
|
+
bundle assets, and document/call-site keys.
|
|
663
|
+
- Gate judge selection stays outside the cascade in 0.9.0.
|
|
664
|
+
|
|
665
|
+
## 11. Findings cross-reference and decision log
|
|
666
|
+
|
|
667
|
+
| Finding (consolidated) | Resolution |
|
|
668
|
+
|---|---|
|
|
669
|
+
| C1 output collision (3/3) | §7 — two schemas, two homes (`output:` / `map.output:`) |
|
|
670
|
+
| C2 shell units unrepresentable (3/3) | §5.2 — IR v4 invocation union, per-kind engine resolution |
|
|
671
|
+
| C3 hash preimage (3/3) | §5.3 — hashVersion 5, preimage table; §2.3 freeze-time append |
|
|
672
|
+
| C4 cascade layers don't exist (3/3) | §4 — "built, not exposed"; build inventory |
|
|
673
|
+
| C5 script execution security (2/3) | §5.6 — the tools: ceiling inherited exactly (primary-bundle only, no override); v8's grant key withdrawn after the panel showed it contradicted activation-policy's no-new-trust-machinery decision |
|
|
674
|
+
| M1 params overload (3/3) | §2.2 — `with:` for inputs; `params:` declarations only; neither cascades |
|
|
675
|
+
| M2 placeholder grammar (3/3) | §2.4 — `with:`/`with.arguments` against the real grammar; lenient + lint |
|
|
676
|
+
| M3 env not additive (3/3) | §5.5 — literal/ref provenance split; IR v4; per-unit env |
|
|
677
|
+
| M4 alias portability (3/3) | §4.5 — `"*"` columns + unresolved-alias notice |
|
|
678
|
+
| M5 agent plumbing + ceiling; false corroboration | §4.2 — persona snapshot via show layer; corroboration claim retracted |
|
|
679
|
+
| M6 dead kind-gate (2/3) | §4.4 — both gates → capability notices |
|
|
680
|
+
| M7 migration overclaims (3/3) | §8 — vendored parser, full mapping, tombstone rule |
|
|
681
|
+
| M8 adapter recognition (2/3) | §3 — `type: task` required |
|
|
682
|
+
| M9 akm-bin rewrite (2/3) | §5.7 — synthesized shim (a bare PATH prepend cannot cover multi-element launcher invocations) |
|
|
683
|
+
| M10 prose invariants (2/3) | §5.2 — per-kind relaxation, costed |
|
|
684
|
+
| M11 lint never freezes (1/3) | §5.4 — dry freeze in lint |
|
|
685
|
+
| M12 `defaults.on_error` (2/3) | §4 — `on_error`/`retry` join the value vocabulary |
|
|
686
|
+
| M13 improve surface (1/3) | §3 — improve excluded from task bodies |
|
|
687
|
+
| Minors | §3 (draft/deprecated), §5.7 (cwd), §8 (embedded/setup, collisions), §9 (bugs fixed, target_kind, goldens) |
|
|
688
|
+
|
|
689
|
+
Decisions 1–14 (rounds 1–6) stand as logged in v7 except where this
|
|
690
|
+
revision supersedes them with review evidence: call-site `params:` →
|
|
691
|
+
`with:` (M1); "expose the cascade" → "build the cascade" (C4); "duplicate
|
|
692
|
+
output" → two-schema design (C1); §10 non-goals → §9 cost inventory
|
|
693
|
+
(C2/C3). v7's remaining question (cascade sign-off) is superseded by this
|
|
694
|
+
section's cross-reference — the cascade shape survived review; its cost
|
|
695
|
+
didn't, and is now stated.
|
|
696
|
+
|
|
697
|
+
**Round 1 Sonnet panel (v8 → v9).** Four independent reviewers (coverage
|
|
698
|
+
audit, architecture, fresh adversarial, security+migration; full reports
|
|
699
|
+
`sonnet-r1-*.md` in the session scratchpad). Panel criticals, all applied:
|
|
700
|
+
the §5.6 grant key contradicted activation-policy's documented
|
|
701
|
+
no-new-trust-machinery decision → replaced by exact ceiling inheritance;
|
|
702
|
+
the v8 hash preimage omitted the persona snapshot → added; `with:` merge
|
|
703
|
+
on composition chains was undefined → §2.2; the tombstone hard-error was
|
|
704
|
+
unactionable on read-only bundles → warning carve-out. Panel majors, all
|
|
705
|
+
applied: task-path staging named (resolve → execute); executor sinks as
|
|
706
|
+
the adapter boundary; ShellUnitExecutor extracted from the task runner's
|
|
707
|
+
hardened path, not rebuilt; monotemporal composition rule; persona
|
|
708
|
+
resolver extraction scoped; merge classes stated (deep-merge preserved
|
|
709
|
+
for `extra_params`); shell invocation carries `timeoutMs`; shell-unit
|
|
710
|
+
crash/lease semantics; toolPolicy under capability notices; improve
|
|
711
|
+
exclusion given a named mechanism; migration crash-window ordering;
|
|
712
|
+
POSIX-pinned migrated quoting; launcher-aware shim. One panel claim was
|
|
713
|
+
verified false and rejected: "the tools: ceiling doesn't exist" — it does
|
|
714
|
+
(`show.ts:433-445`), inline in the show command, which is exactly why §4
|
|
715
|
+
scopes its extraction.
|
|
716
|
+
|
|
717
|
+
Open items: none blocking. Two implementation-time choices are delegated
|
|
718
|
+
to the implementer with defaults: the exact capability-declaration shape
|
|
719
|
+
per engine kind (default: a static field list per kind), and the
|
|
720
|
+
scheduler-id mapping for subdir task ids (default: `/` → `--` with
|
|
721
|
+
collision lint).
|