akm-cli 0.9.28-alpha.5 → 0.9.28-alpha.7

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 CHANGED
@@ -6,6 +6,55 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.28-alpha.7] - 2026-10-08
10
+
11
+ ### Added
12
+
13
+ - **An agent engine can name a default `agent`.** `engines.<name>.agent` (`opencode`, `opencode-sdk`, `claude`)
14
+ is the native agent the engine runs when a request names none, so an `opencode-sdk` engine, which takes no
15
+ `args`, can run e.g. `akm-workflow` for workflows and tasks. A request's own agent wins, a persona is kept,
16
+ and model work keeps its confined agent. See [Configuration](docs/reference/configuration.md) (#1049).
17
+
18
+ ### Changed
19
+
20
+ - **Stability tiers for 0.10's stabilization work.** Experimental: the built-in
21
+ improve strategies other than `default` and `consolidate` (`quick`,
22
+ `reflect-distill`, `thorough`, `catchup`), the proactive-maintenance and
23
+ high-salience lanes, and session extraction (`akm proposal extract`).
24
+ Evolving and now listed: `akm command run` and `akm models`; every agent
25
+ harness (the `opencode` CLI path, `copilot`, `pi`, `gemini`, `aider`,
26
+ `amazonq`, `openhands` included) and the `okf`, `llm-wiki` and
27
+ `generic-files` adapters are named Evolving. `akm upgrade`'s plugin step and
28
+ `--next` are targeted to become Stable before the 0.9 series ends.
29
+
30
+ - **Workflows are Experimental.** The `akm workflow` commands (`run`, `status`,
31
+ `list`, `create`, `resume`, `abandon`, `plan`), the workflow asset format and
32
+ the engine move to Experimental in STABILITY.md and the help text, for the rest
33
+ of 0.9 and all of 0.10, which stabilizes the feature and then promotes it or
34
+ removes it. Nothing changes in how they run.
35
+
36
+ ### Fixed
37
+
38
+ - **Consolidate's pair pass no longer retires a knowledge note in favour of a memory (#1092).** Knowledge is the
39
+ reviewed form and a memory is raw capture, often the very memory the note was promoted from, yet a `duplicate`,
40
+ `supersedes` or `subsumed` verdict could retire `knowledge/...` for `memories/...` (a `.derived` memory counts as a
41
+ memory). When the verdict would do that and the judge lists no claim held only by the memory, the memory is retired
42
+ in favour of the note instead, through the same guards and staging as any memory retirement; when the memory holds
43
+ a claim of its own, nothing is minted and the pair is counted as a no-action verdict. A memory is still retired in
44
+ favour of a knowledge note, and knowledge against knowledge is unchanged.
45
+
46
+ ## [0.9.28-alpha.6] - 2026-10-08
47
+
48
+ ### Fixed
49
+
50
+ - **The #1063 fix now reaches files that have not changed (#1063).** An incremental `akm index` skips a
51
+ directory whose files are unchanged, so a reference file already filed as a command stayed
52
+ `commands/skills/<name>/...` until `akm index --full`. The `akm` adapter's version, which is part of each
53
+ directory's freshness, is bumped, so the next `akm index` after upgrading re-files those rows once (about 18
54
+ entries in a 18,000-entry library) and drops their old refs. Reading every directory once makes that run slower
55
+ (about 27 s against 2 s on that library) and re-embeds the entries whose embedding hash was written by an older
56
+ release (about 8,000 of them); later runs cost what they did before.
57
+
9
58
  ## [0.9.28-alpha.5] - 2026-10-08
10
59
 
11
60
  ### Added
package/STABILITY.md CHANGED
@@ -54,17 +54,17 @@ enumeration of the whole `proposal` noun group.
54
54
  | `akm bundle show` | Evolving | See note above. |
55
55
  | `akm bundle remove` | Stable | |
56
56
  | `akm bundle update` | Stable | |
57
- | `akm upgrade` | Evolving | |
57
+ | `akm upgrade` | Evolving | The plugin step and `--next` (0.9.28) are being verified on real hosts to become Stable before the 0.9 series ends. |
58
58
  | `akm search` | Stable | |
59
59
  | `akm curate` | Stable | |
60
60
  | `akm show` | Stable | |
61
- | `akm workflow status` | Stable | `--all-scopes` added in 0.9.15 (#942), additive. |
62
- | `akm workflow plan` | Evolving | New in 0.9.2; secret-free provenance output; envelope shape may change. |
63
- | `akm workflow list` | Stable | `--all-scopes` and a top-level `scopeKey` envelope field added in 0.9.15 (#942), both additive. |
64
- | `akm workflow create` | Stable | |
65
- | `akm workflow resume` | Stable | |
66
- | `akm workflow abandon` | Stable | |
67
- | `akm workflow run` | Stable | Canonical start/resume/execute command. |
61
+ | `akm workflow status` | Experimental | `--all-scopes` added in 0.9.15 (#942), additive. |
62
+ | `akm workflow plan` | Experimental | New in 0.9.2; secret-free provenance output; envelope shape may change. |
63
+ | `akm workflow list` | Experimental | `--all-scopes` and a top-level `scopeKey` envelope field added in 0.9.15 (#942), both additive. |
64
+ | `akm workflow create` | Experimental | |
65
+ | `akm workflow resume` | Experimental | |
66
+ | `akm workflow abandon` | Experimental | |
67
+ | `akm workflow run` | Experimental | Canonical start/resume/execute command. |
68
68
  | `akm remember` | Stable | |
69
69
  | `akm import` | Stable | |
70
70
  | `akm sync` | Stable | |
@@ -83,6 +83,8 @@ enumeration of the whole `proposal` noun group.
83
83
  | `akm feedback` | Stable | |
84
84
  | `akm log` | Evolving | |
85
85
  | `akm agent` | Evolving | |
86
+ | `akm command run` | Evolving | Runs stored command templates through the same agent dispatch as `akm agent`. |
87
+ | `akm models` | Evolving | `list` and `copy-defaults` for model intent aliases. |
86
88
  | `akm lint` | Evolving | |
87
89
  | `akm improve` | Evolving | Review-first by default; mutating lanes require `experimental.improveAutonomy` — see below. |
88
90
  | `akm proposal list` | Stable | See reconciliation note above. |
@@ -93,7 +95,7 @@ enumeration of the whole `proposal` noun group.
93
95
  | `akm proposal reopen` | Evolving | New in 0.9.19; undoes a rejection. |
94
96
  | `akm proposal revert` | Evolving | |
95
97
  | `akm proposal drain` | Evolving | |
96
- | `akm proposal extract` | Evolving | Former top-level `akm extract`. |
98
+ | `akm proposal extract` | Experimental | Former top-level `akm extract`. Session extraction quality is still being measured (0.10, #1094). |
97
99
  | `akm proposal new` | Evolving | Former top-level `akm propose`. |
98
100
  | `akm help` | Stable | |
99
101
  | `akm help agents` | Stable | |
@@ -291,9 +293,8 @@ CHANGELOG with a migration note.
291
293
  - **Workflow plan** — `akm workflow plan <ref>`, new in 0.9.2: zero-write
292
294
  compile+freeze introspection (the canonical step graph, task/child
293
295
  expansion, input bindings, and lowering notices for a workflow, without
294
- starting or publishing a run). The envelope shape may still change; the
295
- five long-Stable `workflow` verbs (`status`, `list`, `create`, `resume`,
296
- `abandon`) and `run` are unaffected.
296
+ starting or publishing a run). The envelope shape may still change. Like every
297
+ `workflow` verb it is Experimental from 0.9.28 (see Experimental below).
297
298
  - **Events / log** — `akm log` is the event-stream surface (0.9.0: the
298
299
  asset-scoped `akm history` surface, and `log`'s own `tail` subcommand, were
299
300
  both removed; `log` is now a leaf command — the former `list` surface).
@@ -302,7 +303,8 @@ CHANGELOG with a migration note.
302
303
  commands/agents, knowledge, YAML workflows, tasks, env/secret files, scripts,
303
304
  OKF and LLM-wiki knowledge bases). Config is keyed by `bundles` and
304
305
  `defaultBundle`. The adapter set, bundle-recognition rules, and the
305
- `bundles` config shape may still shift. Bundles are inspected through
306
+ `bundles` config shape may still shift; the `okf`, `llm-wiki` and
307
+ `generic-files` adapters in particular are Evolving. Bundles are inspected through
306
308
  `akm bundle list` / `akm bundle show <name>` and enumerated through
307
309
  `akm search "bundle//"`. (An earlier `akm bundle items` noun group was
308
310
  removed in 0.9.0 as duplicative of `akm search`; the current `akm bundle`
@@ -318,9 +320,15 @@ CHANGELOG with a migration note.
318
320
  `log.md` / `raw/` / `pages/` and its ingest flow); wiki pages are addressed
319
321
  as ordinary concepts inside their bundle. Adapter behavior and page
320
322
  conventions are still iterating.
321
- - **Agent dispatch** — `akm agent` subcommand. Supported backends: `claude`,
322
- `opencode`, `opencode-sdk`, `codex`, `copilot`, `pi`, `gemini`, `aider`,
323
- `amazonq`, `openhands`. The set will grow.
323
+ - **Agent dispatch** — `akm agent` and `akm command run`. Supported backends:
324
+ `claude`, `opencode-sdk` (the primary OpenCode interface), `codex`, and the
325
+ `opencode` CLI path, `copilot`, `pi`, `gemini`, `aider`, `amazonq`,
326
+ `openhands`. Every harness is Evolving: the harness implementation is being
327
+ reworked so harnesses are easy to add, remove and update (0.10), and the
328
+ `opencode` CLI dispatch path is a deprecation candidate once `opencode-sdk`
329
+ covers it. The set will grow.
330
+ - **Model aliases** — `akm models list|copy-defaults` and the intent-alias
331
+ defaults they expose.
324
332
  - **Proposal queue** — quality classifications (`accepted`, `pending`,
325
333
  `proposed`, `rejected`, `archived`) are stable; the JSON shape of a
326
334
  proposal record may add fields.
@@ -330,7 +338,9 @@ CHANGELOG with a migration note.
330
338
  lives outside the CLI, in `scripts/build-registry-index.ts`.
331
339
  - **Upgrade** — `akm upgrade`. Checksum verification is not optional; the
332
340
  recovery hatch is the `AKM_UPGRADE_SKIP_CHECKSUM` environment variable
333
- (Internal), not a flag.
341
+ (Internal), not a flag. The harness plugin step and `--next` (new in 0.9.28)
342
+ are targeted to become Stable before the 0.9 series ends, once verified on
343
+ real hosts.
334
344
  - **Lint** — `akm lint`. The rule set and finding shapes iterate; the
335
345
  `--fail-on-flagged` CI contract and the exit codes are stable.
336
346
  - **Health** — `akm health` and its exit codes (0 pass / 4 warn / 1 fail) are
@@ -342,6 +352,12 @@ CHANGELOG with a migration note.
342
352
  Subject to change without notice within minor releases. Not yet recommended
343
353
  for scripted use.
344
354
 
355
+ - **Workflows** — the whole `akm workflow` surface (`run`, `status`, `list`,
356
+ `create`, `resume`, `abandon`, `plan`), the workflow asset format and the
357
+ workflow engine are Experimental from 0.9.28 and throughout 0.10. The 0.10
358
+ series stabilizes the feature and trims what is not useful, then either
359
+ promotes it out of Experimental or removes it if stabilization does not
360
+ produce a quality feature.
345
361
  - **`akm metrics`** — new in 0.9.28. What it reports, its JSON shape and the
346
362
  `--format html` dashboard may change in any release; do not script against
347
363
  them.
@@ -361,6 +377,13 @@ for scripted use.
361
377
  - **Memory belief-state transitions** — `captureMode`, `beliefState`,
362
378
  contradiction edges, and the consolidate journal are observable but
363
379
  the algorithm that writes them is tuning across patch releases.
380
+ - **Improve built-in strategies and lanes** — the built-in strategies other
381
+ than `default` and `consolidate` (`quick`, `reflect-distill`, `thorough`,
382
+ `catchup`) and the proactive-maintenance and high-salience lanes. 0.10
383
+ measures each and keeps, folds or removes it (#1094).
384
+ - **Session extraction** — `akm proposal extract` and the `extract` process:
385
+ what it extracts, its quality gates and its output may change while 0.10
386
+ measures it (#1094).
364
387
  - **Improve tuning config** — `improve.strategies.*.processes.*` (per-process
365
388
  engines, limits, gates, and the anti-collapse / CLS / fidelity knobs) and
366
389
  the `index.*` per-pass config. The 0.9.x series is explicitly still settling
@@ -581,7 +581,15 @@ async function judgeOne(ctx, candidate) {
581
581
  const decision = decideRetirement(verdict.relation, verdict.redundant, older, newer, verdict);
582
582
  if (!decision)
583
583
  return { failed: false };
584
- const { retired, successor } = decision;
584
+ let { retired, successor } = decision;
585
+ // Owner rule (#1092): knowledge is never replaced with a memory (a `.derived` memory is a memory). When the memory
586
+ // holds nothing the note lacks, retire the memory in favour of the note instead; otherwise leave the pair alone.
587
+ // The flipped pair then runs every guard below like any memory retirement.
588
+ if (retired.asset.type === "knowledge" && successor.asset.type === "memory") {
589
+ if ((successor === older ? verdict.onlyInA : verdict.onlyInB).length > 0)
590
+ return { failed: false };
591
+ [retired, successor] = [successor, retired];
592
+ }
585
593
  // Guards (plan §5.2 step 4 / brief §A "Guards").
586
594
  if (retired.asset.type === "memory" && isHotCapturedMemory(retired.asset.filePath)) {
587
595
  return { failed: false }; // never propose retiring a captureMode: hot memory — leave the pair alone
@@ -26,7 +26,7 @@ import { akmExtract, resolveStandaloneExtractPlan } from "./extract.js";
26
26
  export const extractCommand = defineJsonCommand({
27
27
  meta: {
28
28
  name: "extract",
29
- description: "Extract durable insights from native session files (claude, codex, opencode) and queue them as proposals.",
29
+ description: "Experimental: extract durable insights from native session files (claude, codex, opencode) and queue them as proposals.",
30
30
  },
31
31
  args: {
32
32
  type: {
@@ -432,7 +432,7 @@ const workflowResumeCommand = defineJsonCommand({
432
432
  export const workflowCommand = defineGroupCommand({
433
433
  meta: {
434
434
  name: "workflow",
435
- description: "Author, inspect, and execute step-by-step workflow assets",
435
+ description: "Experimental: author, inspect, and execute step-by-step workflow assets",
436
436
  },
437
437
  subCommands: {
438
438
  status: workflowStatusCommand,
@@ -453,7 +453,11 @@ async function validate(c, changes, ctx) {
453
453
  }
454
454
  export const akmAdapter = {
455
455
  id: "akm",
456
- version: "0.9.0",
456
+ // Bump when a change to the matchers (or `recognize`) can retype or re-ref a
457
+ // file that has not changed: the version is folded into each directory's
458
+ // freshness, so the next incremental `akm index` re-drains it and re-files
459
+ // those rows (#1063). 0.9.1: a skill's resource is never retyped by a `$1`.
460
+ version: "0.9.1",
457
461
  // Recognized-extension HINT, derived from what the matchers accept (§6):
458
462
  // `.md` (Markdown types + workflow peer), `.yml` (task and workflow YAML),
459
463
  // `.yaml` (task near-miss diagnostics), `.env` (env files), and the 16
@@ -13,7 +13,7 @@ import { z } from "zod";
13
13
  // `config-types`, which type-derives from this barrel via
14
14
  // `typeof import("./config-schema")` — routing through config-types would mint
15
15
  // a config-schema ↔ config-types type cycle that collapses inference.
16
- import { HARNESS_AGENT_DISPATCH_IDS, VALID_HARNESS_IDS } from "../../../integrations/harnesses/ids.js";
16
+ import { HARNESS_AGENT_DISPATCH_IDS, HARNESS_NATIVE_AGENT_IDS, VALID_HARNESS_IDS, } from "../../../integrations/harnesses/ids.js";
17
17
  import { WORKFLOW_MAX_TIMEOUT_MS } from "../../../workflows/resource-limits.js";
18
18
  import { chatCompletionsEndpoint, ExtraParamsSchema, engineName, nonEmptyString, positiveInt, symbolicOrWarnApiKey, } from "./primitives.js";
19
19
  /**
@@ -89,7 +89,7 @@ const LlmEngineSchema = z
89
89
  })
90
90
  .passthrough()
91
91
  .superRefine((value, ctx) => {
92
- for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine"]) {
92
+ for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine", "agent"]) {
93
93
  if (key in value)
94
94
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
95
95
  }
@@ -115,6 +115,7 @@ const AgentEngineSchema = z
115
115
  args: z.array(z.string()).optional(),
116
116
  workspace: nonEmptyString.optional(),
117
117
  model: nonEmptyString.optional(),
118
+ agent: nonEmptyString.optional(),
118
119
  timeoutMs: timeoutMsField,
119
120
  llmEngine: engineName.optional(),
120
121
  })
@@ -144,6 +145,13 @@ const AgentEngineSchema = z
144
145
  message: "llmEngine is only valid on opencode-sdk",
145
146
  });
146
147
  }
148
+ if (value.agent !== undefined && !HARNESS_NATIVE_AGENT_IDS.has(value.platform)) {
149
+ ctx.addIssue({
150
+ code: z.ZodIssueCode.custom,
151
+ path: ["agent"],
152
+ message: `agent is not valid on ${value.platform}: it has no native agent selector`,
153
+ });
154
+ }
147
155
  if (value.platform === "opencode-sdk" && value.args !== undefined) {
148
156
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["args"], message: "args is not valid on opencode-sdk" });
149
157
  }
@@ -285,6 +285,7 @@ function lowerAgentEngine(name, engine, config) {
285
285
  parseOutput: "text",
286
286
  ...(engine.workspace ? { workspace: path.resolve(engine.workspace) } : {}),
287
287
  ...(engine.model ? { model: engine.model } : {}),
288
+ ...(engine.agent ? { agent: engine.agent } : {}),
288
289
  };
289
290
  // An engine that sets no timeoutMs leaves it unset, so a caller's own default
290
291
  // (model work's 600 s) can apply; a dispatch with none runs unbounded.
@@ -59,6 +59,8 @@ function engineDefaults(name, engine, config) {
59
59
  return { kind: "llm", platform: engine.provider ?? name, modelMapKey: name, values };
60
60
  if (engine.workspace !== undefined)
61
61
  values.workspace = engine.workspace;
62
+ if (engine.agent !== undefined)
63
+ values.agent = engine.agent;
62
64
  if (engine.platform !== "opencode-sdk") {
63
65
  return { kind: "agent", platform: engine.platform, modelMapKey: engine.platform, values };
64
66
  }
@@ -120,6 +122,7 @@ function runnerDefaults(runner) {
120
122
  ...(inference ? { inference } : {}),
121
123
  ...timeout,
122
124
  ...(runner.profile.workspace !== undefined ? { workspace: runner.profile.workspace } : {}),
125
+ ...(runner.profile.agent !== undefined ? { agent: runner.profile.agent } : {}),
123
126
  },
124
127
  };
125
128
  }
@@ -345,7 +348,12 @@ export function resolveExecution(input) {
345
348
  const layers = [{ id: name, kind: "engine", values: defaults.values }, ...callerLayers];
346
349
  provenance.command = { layer: command.source?.ref ?? "inline", kind: "command", via: "source" };
347
350
  let persona = input.persona;
348
- const agentLayer = nearest(layers, "agent");
351
+ // The engine's own `agent` is only a default for a request that names none: it never replaces a
352
+ // persona, and model work keeps its confined agent.
353
+ const engineAgentApplies = !persona && input.modelWork !== true;
354
+ let agentLayer = nearest(layers, "agent");
355
+ if (agentLayer?.kind === "engine" && !engineAgentApplies)
356
+ agentLayer = undefined;
349
357
  const agent = agentLayer?.values.agent;
350
358
  if (agentLayer) {
351
359
  provenance.agent = explicit(agentLayer);
@@ -4,7 +4,7 @@
4
4
  import { ConfigError } from "../../core/errors.js";
5
5
  import { withSchemaInstruction } from "../../core/structured.js";
6
6
  import { MODEL_WORK_POLICY_ID } from "../../execution/source.js";
7
- import { HARNESS_MODEL_WORK_IDS } from "../harnesses/ids.js";
7
+ import { HARNESS_MODEL_WORK_IDS, HARNESS_NATIVE_AGENT_IDS } from "../harnesses/ids.js";
8
8
  import { composeConversationFallbackPrompt } from "./conversation-fallback.js";
9
9
  import { composePersonaFallbackPrompt } from "./persona-fallback.js";
10
10
  /** A tool selection that actually names tools (not omitted, null, or empty). */
@@ -77,7 +77,7 @@ export function createAgentRequestLowerer(options) {
77
77
  }
78
78
  }
79
79
  else if (typeof request.agent === "string") {
80
- if (!options.nativeAgentSelector) {
80
+ if (!HARNESS_NATIVE_AGENT_IDS.has(options.adapter)) {
81
81
  throw new ConfigError(`The ${options.adapter} transport cannot consume native agent selector ${JSON.stringify(request.agent)}.`, "INVALID_CONFIG_FILE");
82
82
  }
83
83
  dispatch.agent = request.agent;
@@ -69,7 +69,6 @@ export const claudeBuilder = {
69
69
  lower: createAgentRequestLowerer({
70
70
  adapter: "claude",
71
71
  personaChannel: "native",
72
- nativeAgentSelector: true,
73
72
  tools: "all",
74
73
  }),
75
74
  build(profile, req) {
@@ -2,16 +2,16 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  export const HARNESS_ID_TABLE = [
5
- { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true },
6
- { id: "claude", agentDispatch: true, enforcesModelWorkTools: true },
7
- { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true },
8
- { id: "codex", agentDispatch: true, enforcesModelWorkTools: false },
9
- { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false },
10
- { id: "pi", agentDispatch: true, enforcesModelWorkTools: false },
11
- { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false },
12
- { id: "aider", agentDispatch: true, enforcesModelWorkTools: false },
13
- { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false },
14
- { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false },
5
+ { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
6
+ { id: "claude", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
7
+ { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
8
+ { id: "codex", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
9
+ { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
10
+ { id: "pi", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
11
+ { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
12
+ { id: "aider", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
13
+ { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
14
+ { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
15
15
  ];
16
16
  /**
17
17
  * Canonical, ordered list of valid harness / platform ids — the
@@ -24,3 +24,5 @@ export const VALID_HARNESS_IDS = Object.freeze(HARNESS_ID_TABLE.map((h) => h.id)
24
24
  export const HARNESS_AGENT_DISPATCH_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.agentDispatch).map((h) => h.id));
25
25
  /** Harness ids that confine the model-work tool policy, so unattended model work may run on them. */
26
26
  export const HARNESS_MODEL_WORK_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.enforcesModelWorkTools).map((h) => h.id));
27
+ /** Harness ids that can run a named native agent, so an engine may name a default `agent`. */
28
+ export const HARNESS_NATIVE_AGENT_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.nativeAgentSelector).map((h) => h.id));
@@ -45,7 +45,6 @@ export const opencodeBuilder = {
45
45
  lower: createAgentRequestLowerer({
46
46
  adapter: "opencode",
47
47
  personaChannel: "prompt",
48
- nativeAgentSelector: true,
49
48
  tools: "none",
50
49
  inference: MODEL_WORK_AGENT_INFERENCE,
51
50
  }),
@@ -40,7 +40,6 @@ export class OpencodeSdkHarness extends BaseHarness {
40
40
  lower: createAgentRequestLowerer({
41
41
  adapter: "opencode-sdk",
42
42
  personaChannel: "native",
43
- nativeAgentSelector: true,
44
43
  tools: "sdk",
45
44
  inference: MODEL_WORK_AGENT_INFERENCE,
46
45
  }),
@@ -35729,20 +35729,21 @@ var coerce = {
35729
35729
  var NEVER = INVALID;
35730
35730
  // src/integrations/harnesses/ids.ts
35731
35731
  var HARNESS_ID_TABLE = [
35732
- { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true },
35733
- { id: "claude", agentDispatch: true, enforcesModelWorkTools: true },
35734
- { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true },
35735
- { id: "codex", agentDispatch: true, enforcesModelWorkTools: false },
35736
- { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false },
35737
- { id: "pi", agentDispatch: true, enforcesModelWorkTools: false },
35738
- { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false },
35739
- { id: "aider", agentDispatch: true, enforcesModelWorkTools: false },
35740
- { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false },
35741
- { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false }
35732
+ { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
35733
+ { id: "claude", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
35734
+ { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
35735
+ { id: "codex", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35736
+ { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35737
+ { id: "pi", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35738
+ { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35739
+ { id: "aider", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35740
+ { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35741
+ { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false }
35742
35742
  ];
35743
35743
  var VALID_HARNESS_IDS = Object.freeze(HARNESS_ID_TABLE.map((h) => h.id));
35744
35744
  var HARNESS_AGENT_DISPATCH_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.agentDispatch).map((h) => h.id));
35745
35745
  var HARNESS_MODEL_WORK_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.enforcesModelWorkTools).map((h) => h.id));
35746
+ var HARNESS_NATIVE_AGENT_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.nativeAgentSelector).map((h) => h.id));
35746
35747
 
35747
35748
  // src/core/extra-params.ts
35748
35749
  var EXTRA_PARAMS_PROTECTED_TOP_LEVEL_KEYS = [
@@ -36035,7 +36036,7 @@ var LlmEngineSchema = exports_external.object({
36035
36036
  enableThinking: exports_external.boolean().optional(),
36036
36037
  reasoningEffort: nonEmptyString.optional()
36037
36038
  }).passthrough().superRefine((value, ctx) => {
36038
- for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine"]) {
36039
+ for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine", "agent"]) {
36039
36040
  if (key in value)
36040
36041
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
36041
36042
  }
@@ -36056,6 +36057,7 @@ var AgentEngineSchema = exports_external.object({
36056
36057
  args: exports_external.array(exports_external.string()).optional(),
36057
36058
  workspace: nonEmptyString.optional(),
36058
36059
  model: nonEmptyString.optional(),
36060
+ agent: nonEmptyString.optional(),
36059
36061
  timeoutMs: timeoutMsField,
36060
36062
  llmEngine: engineName.optional()
36061
36063
  }).passthrough().superRefine((value, ctx) => {
@@ -36083,6 +36085,13 @@ var AgentEngineSchema = exports_external.object({
36083
36085
  message: "llmEngine is only valid on opencode-sdk"
36084
36086
  });
36085
36087
  }
36088
+ if (value.agent !== undefined && !HARNESS_NATIVE_AGENT_IDS.has(value.platform)) {
36089
+ ctx.addIssue({
36090
+ code: exports_external.ZodIssueCode.custom,
36091
+ path: ["agent"],
36092
+ message: `agent is not valid on ${value.platform}: it has no native agent selector`
36093
+ });
36094
+ }
36086
36095
  if (value.platform === "opencode-sdk" && value.args !== undefined) {
36087
36096
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: ["args"], message: "args is not valid on opencode-sdk" });
36088
36097
  }
@@ -45086,7 +45095,7 @@ async function validate2(c, changes, ctx) {
45086
45095
  }
45087
45096
  var akmAdapter = {
45088
45097
  id: "akm",
45089
- version: "0.9.0",
45098
+ version: "0.9.1",
45090
45099
  extensions: [
45091
45100
  ".md",
45092
45101
  ".yaml",
@@ -51340,7 +51349,7 @@ function createAgentRequestLowerer(options) {
51340
51349
  notices.push(...composed.notices);
51341
51350
  }
51342
51351
  } else if (typeof request.agent === "string") {
51343
- if (!options.nativeAgentSelector) {
51352
+ if (!HARNESS_NATIVE_AGENT_IDS.has(options.adapter)) {
51344
51353
  throw new ConfigError(`The ${options.adapter} transport cannot consume native agent selector ${JSON.stringify(request.agent)}.`, "INVALID_CONFIG_FILE");
51345
51354
  }
51346
51355
  dispatch.agent = request.agent;
@@ -51561,7 +51570,6 @@ var claudeBuilder = {
51561
51570
  lower: createAgentRequestLowerer({
51562
51571
  adapter: "claude",
51563
51572
  personaChannel: "native",
51564
- nativeAgentSelector: true,
51565
51573
  tools: "all"
51566
51574
  }),
51567
51575
  build(profile, req) {
@@ -52603,7 +52611,6 @@ var opencodeBuilder = {
52603
52611
  lower: createAgentRequestLowerer({
52604
52612
  adapter: "opencode",
52605
52613
  personaChannel: "prompt",
52606
- nativeAgentSelector: true,
52607
52614
  tools: "none",
52608
52615
  inference: MODEL_WORK_AGENT_INFERENCE
52609
52616
  }),
@@ -52947,7 +52954,6 @@ class OpencodeSdkHarness extends BaseHarness {
52947
52954
  lower: createAgentRequestLowerer({
52948
52955
  adapter: "opencode-sdk",
52949
52956
  personaChannel: "native",
52950
- nativeAgentSelector: true,
52951
52957
  tools: "sdk",
52952
52958
  inference: MODEL_WORK_AGENT_INFERENCE
52953
52959
  })
@@ -35057,20 +35057,21 @@ var coerce = {
35057
35057
  var NEVER = INVALID;
35058
35058
  // src/integrations/harnesses/ids.ts
35059
35059
  var HARNESS_ID_TABLE = [
35060
- { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true },
35061
- { id: "claude", agentDispatch: true, enforcesModelWorkTools: true },
35062
- { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true },
35063
- { id: "codex", agentDispatch: true, enforcesModelWorkTools: false },
35064
- { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false },
35065
- { id: "pi", agentDispatch: true, enforcesModelWorkTools: false },
35066
- { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false },
35067
- { id: "aider", agentDispatch: true, enforcesModelWorkTools: false },
35068
- { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false },
35069
- { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false }
35060
+ { id: "opencode", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
35061
+ { id: "claude", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
35062
+ { id: "opencode-sdk", agentDispatch: true, enforcesModelWorkTools: true, nativeAgentSelector: true },
35063
+ { id: "codex", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35064
+ { id: "copilot", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35065
+ { id: "pi", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35066
+ { id: "gemini", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35067
+ { id: "aider", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35068
+ { id: "amazonq", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false },
35069
+ { id: "openhands", agentDispatch: true, enforcesModelWorkTools: false, nativeAgentSelector: false }
35070
35070
  ];
35071
35071
  var VALID_HARNESS_IDS = Object.freeze(HARNESS_ID_TABLE.map((h) => h.id));
35072
35072
  var HARNESS_AGENT_DISPATCH_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.agentDispatch).map((h) => h.id));
35073
35073
  var HARNESS_MODEL_WORK_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.enforcesModelWorkTools).map((h) => h.id));
35074
+ var HARNESS_NATIVE_AGENT_IDS = new Set(HARNESS_ID_TABLE.filter((h) => h.nativeAgentSelector).map((h) => h.id));
35074
35075
 
35075
35076
  // src/core/extra-params.ts
35076
35077
  var EXTRA_PARAMS_PROTECTED_TOP_LEVEL_KEYS = [
@@ -35363,7 +35364,7 @@ var LlmEngineSchema = exports_external.object({
35363
35364
  enableThinking: exports_external.boolean().optional(),
35364
35365
  reasoningEffort: nonEmptyString.optional()
35365
35366
  }).passthrough().superRefine((value, ctx) => {
35366
- for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine"]) {
35367
+ for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine", "agent"]) {
35367
35368
  if (key in value)
35368
35369
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
35369
35370
  }
@@ -35384,6 +35385,7 @@ var AgentEngineSchema = exports_external.object({
35384
35385
  args: exports_external.array(exports_external.string()).optional(),
35385
35386
  workspace: nonEmptyString.optional(),
35386
35387
  model: nonEmptyString.optional(),
35388
+ agent: nonEmptyString.optional(),
35387
35389
  timeoutMs: timeoutMsField,
35388
35390
  llmEngine: engineName.optional()
35389
35391
  }).passthrough().superRefine((value, ctx) => {
@@ -35411,6 +35413,13 @@ var AgentEngineSchema = exports_external.object({
35411
35413
  message: "llmEngine is only valid on opencode-sdk"
35412
35414
  });
35413
35415
  }
35416
+ if (value.agent !== undefined && !HARNESS_NATIVE_AGENT_IDS.has(value.platform)) {
35417
+ ctx.addIssue({
35418
+ code: exports_external.ZodIssueCode.custom,
35419
+ path: ["agent"],
35420
+ message: `agent is not valid on ${value.platform}: it has no native agent selector`
35421
+ });
35422
+ }
35414
35423
  if (value.platform === "opencode-sdk" && value.args !== undefined) {
35415
35424
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: ["args"], message: "args is not valid on opencode-sdk" });
35416
35425
  }
@@ -44414,7 +44423,7 @@ async function validate2(c, changes, ctx) {
44414
44423
  }
44415
44424
  var akmAdapter = {
44416
44425
  id: "akm",
44417
- version: "0.9.0",
44426
+ version: "0.9.1",
44418
44427
  extensions: [
44419
44428
  ".md",
44420
44429
  ".yaml",
@@ -51335,7 +51344,7 @@ function createAgentRequestLowerer(options) {
51335
51344
  notices.push(...composed.notices);
51336
51345
  }
51337
51346
  } else if (typeof request.agent === "string") {
51338
- if (!options.nativeAgentSelector) {
51347
+ if (!HARNESS_NATIVE_AGENT_IDS.has(options.adapter)) {
51339
51348
  throw new ConfigError(`The ${options.adapter} transport cannot consume native agent selector ${JSON.stringify(request.agent)}.`, "INVALID_CONFIG_FILE");
51340
51349
  }
51341
51350
  dispatch.agent = request.agent;
@@ -51556,7 +51565,6 @@ var claudeBuilder = {
51556
51565
  lower: createAgentRequestLowerer({
51557
51566
  adapter: "claude",
51558
51567
  personaChannel: "native",
51559
- nativeAgentSelector: true,
51560
51568
  tools: "all"
51561
51569
  }),
51562
51570
  build(profile, req) {
@@ -52598,7 +52606,6 @@ var opencodeBuilder = {
52598
52606
  lower: createAgentRequestLowerer({
52599
52607
  adapter: "opencode",
52600
52608
  personaChannel: "prompt",
52601
- nativeAgentSelector: true,
52602
52609
  tools: "none",
52603
52610
  inference: MODEL_WORK_AGENT_INFERENCE
52604
52611
  }),
@@ -52942,7 +52949,6 @@ class OpencodeSdkHarness extends BaseHarness {
52942
52949
  lower: createAgentRequestLowerer({
52943
52950
  adapter: "opencode-sdk",
52944
52951
  personaChannel: "native",
52945
- nativeAgentSelector: true,
52946
52952
  tools: "sdk",
52947
52953
  inference: MODEL_WORK_AGENT_INFERENCE
52948
52954
  })
package/docs/README.md CHANGED
@@ -12,6 +12,7 @@ Full per-directory indexes: [Guides](https://github.com/itlackey/akm/blob/main/d
12
12
 
13
13
  ## Start
14
14
 
15
+ - [Product Surface](https://github.com/itlackey/akm/blob/main/docs/product-surface.md) -- Every feature and its status
15
16
  - [Getting Started](https://github.com/itlackey/akm/blob/main/docs/guides/getting-started.md) -- Install akm, connect a source, and pull a curated shortlist in five to seven minutes
16
17
  - [Concepts](https://github.com/itlackey/akm/blob/main/docs/guides/concepts.md) -- Capabilities, bundles, adapters, asset types, and refs -- the mental model in one page
17
18
  - [Agent Install Guide](https://github.com/itlackey/akm/blob/main/docs/agents/agent-install.md) -- Step-by-step automated (non-interactive) install for agents
@@ -799,6 +799,9 @@ to run `akm bundle add <origin>` first.
799
799
 
800
800
  ### workflow
801
801
 
802
+ **Experimental** (see [STABILITY.md](../../STABILITY.md)): the workflow commands, asset format and engine may
803
+ change in any release through the 0.10 series, which decides whether the feature is stabilized or removed.
804
+
802
805
  Author, inspect, and execute structured workflow assets.
803
806
 
804
807
  ```sh
@@ -2892,6 +2895,8 @@ authenticates its root; it never falls back to an ambient write target.
2892
2895
 
2893
2896
  #### proposal extract
2894
2897
 
2898
+ **Experimental** (see [STABILITY.md](../../STABILITY.md)): session extraction is still being measured in 0.10.
2899
+
2895
2900
  Extract durable insights from native coding-agent session files (claude-code,
2896
2901
  codex, opencode) and queue them as proposals. This is the standalone
2897
2902
  entrypoint for session extraction — it replaces the legacy session-checkpoint
@@ -129,9 +129,13 @@ value matching this JSON Schema (no prose, no code fences):` followed by the
129
129
  schema), plus the harness's own schema channel where it has one (codex
130
130
  `--output-schema`).
131
131
 
132
- An agent engine may set `bin`, `args`, `workspace`, `model`, and `timeoutMs`;
132
+ An agent engine may set `bin`, `args`, `workspace`, `model`, `agent`, and `timeoutMs`;
133
133
  it takes no inference of its own (see
134
- [Inference on an agent engine](#inference-on-an-agent-engine)). Only `platform: "opencode-sdk"` may set `llmEngine`; it names
134
+ [Inference on an agent engine](#inference-on-an-agent-engine)). `agent` names the
135
+ engine's default native agent (`opencode`, `opencode-sdk` and `claude` only): it
136
+ runs when a request names no agent, e.g. `{"kind":"agent","platform":"opencode-sdk","model":"openai/gpt-5.6-terra","agent":"akm-workflow"}`.
137
+ A request's own agent wins, an agent asset's persona is kept, and model work keeps its confined
138
+ agent. `opencode-sdk` takes no `args`, so `agent` is how an SDK engine names one. Only `platform: "opencode-sdk"` may set `llmEngine`; it names
135
139
  the LLM engine used as that SDK engine's fallback connection. With no
136
140
  `llmEngine`, an SDK engine has no fallback connection and opencode resolves
137
141
  provider, model and auth from its own configuration. `defaults.llmEngine` is
@@ -440,7 +444,9 @@ An improve process's engine follows
440
444
  [the one rule](#engines-for-unattended-model-work); an explicit invalid or
441
445
  incompatible engine never falls back to another engine. Built-in strategies
442
446
  are complete presets. User-defined strategies inherit omitted fields from the
443
- built-in `default` strategy before applying their own overrides.
447
+ built-in `default` strategy before applying their own overrides. The built-in
448
+ strategies other than `default` and `consolidate` are Experimental (see
449
+ [STABILITY.md](../../STABILITY.md)): 0.10 measures each and keeps, folds or removes it.
444
450
 
445
451
  `processes.triage.judgment` explicitly controls the optional judgment tier.
446
452
  Use `true` to enable it, `false` to disable it, or an object with `enabled`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.28-alpha.5",
3
+ "version": "0.9.28-alpha.7",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
6
6
  "keywords": [
@@ -130,6 +130,10 @@
130
130
  "type": "string",
131
131
  "minLength": 1
132
132
  },
133
+ "agent": {
134
+ "type": "string",
135
+ "minLength": 1
136
+ },
133
137
  "timeoutMs": {
134
138
  "anyOf": [
135
139
  {
@@ -1802,6 +1806,10 @@
1802
1806
  "type": "string",
1803
1807
  "minLength": 1
1804
1808
  },
1809
+ "agent": {
1810
+ "type": "string",
1811
+ "minLength": 1
1812
+ },
1805
1813
  "timeoutMs": {
1806
1814
  "anyOf": [
1807
1815
  {