UNPKG

akm-cli

Version:

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 Cur

514 lines (392 loc) • 22.3 kB
# Agent, Command, Engine, and Model Resolution > **Historical implementation design.** The 0.9.2 implementation is complete; > current public contracts live in [Tasks](../../reference/tasks.md) and > [Workflow Schema](../../reference/workflow-schema.md). The staged checkpoints > below are retained as design history and are not current status. **Status:** Approved target design **Decision date:** 2026-08-18 **Implementation baseline:** The 0.9.2 line implements WP2 model maps, the WP3 common cascade/authorization boundary, the WP4 command surface, and WP5 runtime engine lowering convergence. Task v3 remains WP6, and the final source-to-frozen durable workflow IR/resume representation remains WP7; see the [0.9.2 implementation plan](../../plans/0.9.2-agent-command-workflow-plan.md). This specification defines how agent personas, command templates, execution engines, model mappings, tasks, and workflows interact. It is authoritative for those semantics and for the 0.9.2 task/workflow format direction. ## 1. Goals The design has four goals: 1. Native Claude Code, OpenCode, and similar agent assets remain useful in place, without migration or synchronization. 2. AKM gives the same agent, command, engine, and model settings the same precedence regardless of whether execution starts at the CLI, a scheduled task, or a workflow. 3. Portable behavior stays deliberately small. Native-only behavior is not guessed or partially emulated. 4. Runtime policy remains separate from asset configuration. An asset can select requested tools or a model, but it cannot override operator authorization or budget policy. ## 2. The concepts ### 2.1 Agent: who performs the work An agent asset is a **persona**, not executable work. It may contribute: - a persona/system prompt; - a requested tool policy; - a model preference; - an optional default engine; and - other ordinary execution defaults recognized by its format and adapter. An agent is selected with an `agent` selector. An agent ref MUST NOT be used as an executable `uses` target. A direct invocation such as: ```sh akm agent agents/reviewer --prompt "Review this change" ``` is shorthand for selecting `agents/reviewer` as the persona and using the provided prompt as the work. Agent files extend the native agent-file concepts of their source formats. They do not select a special AKM-only runtime merely because AKM indexed them. ### 2.2 Command: reusable agent work A command asset is a reusable **agent prompt template**, compatible with the custom/slash-command concept in native agent tools. It is not an operating system command. A command may contribute defaults such as an agent selector, engine, model, tools, and timeout. Those values participate in the normal cascade and can be overridden by a nearer caller. AKM owns command resolution. It loads the command through its bundle adapter, applies the portable argument contract, resolves the agent/engine/model cascade, and dispatches the resulting work. AKM MUST NOT send an unresolved slash-command invocation to a native harness and rely on that harness to reinterpret it. `akm command run` is the target canonical CLI. `akm agent --command` may remain as a compatibility alias, but both MUST call the same resolver and produce the same behavior. ### 2.3 Engine: how the work runs An engine is a named execution backend. It may be an agent harness or a direct LLM connection. Agent and command assets may provide an optional default engine, but neither is required to do so. The same agent and command assets may run through agent or LLM engines. AKM does not maintain a central, exhaustive capability registry and does not reject an engine merely because its kind is assumed not to support a field. See [Optimistic lowering](#7-optimistic-lowering). ### 2.4 Model mapping: portable intent to provider configuration `model` accepts either: - a known alias; or - an exact provider-native identifier. Alias identity is registry-based, not heuristic. If a value matches a known alias, the selected engine's mapping MUST resolve it. A known alias without a mapping is an actionable lint/resolution error. A value that is not a known alias is an exact identifier and passes through unchanged. ### 2.5 Task: when work runs A task is a scheduling wrapper around existing work. It adds scheduling and invocation overrides but does not define another agent, command, or model resolution system. A task may describe or reference: - a command; - a workflow; - a script or explicit shell operation; or - inline command content with an optional agent selector. There is no separate prompt executable type. Prompt text is command content: stored content is a command asset, while inline content is an anonymous command invocation using the same resolver and execution path. ### 2.6 Workflow: durable composition A workflow composes work into a frozen, journaled run. A workflow step may reuse a task's work definition; scheduling-only task fields such as `schedule` and `enabled` do not join the step. Step values are nearer and therefore override the referenced task. Workflow authoring is multi-format. AKM Markdown workflows remain first-class with no planned deprecation. GitHub-shaped YAML is an additional format, and future known formats may be added through adapters. Every adapter compiles to one versioned internal execution IR before the run is frozen; source files are never rewritten into another authoring format. Nested workflows are outside the initial design. A separately journaled child workflow may be added after v1 if real usage demonstrates the need. ### 2.7 Script or shell work: deterministic process execution Scripts and explicit shell/process declarations are the deterministic execution surface. They MUST remain distinct from command assets. Calling a prompt template a command does not authorize it to run as an OS command. The 0.9.2 task/workflow `run` field follows GitHub step semantics: it is a string executed through the selected shell, with compatible `shell` and `working-directory` controls where the host supports them. ## 3. Native bundles and runtime translation Native tool directories such as `.claude` and `.opencode` are registered as ordinary AKM bundles. The owning `BundleAdapter` reads their native files and translates recognized assets into AKM's runtime representation. The following rules are explicit: - The native file is authoritative. - AKM does not create a canonical copy. - AKM does not synchronize native directories with one another. - AKM does not write native agent or command assets. - Runtime translation is not a migration or a projection stored on disk. - Identically named assets in different bundles remain distinct and can be addressed with bundle-qualified refs. Fields shared with a native format remain in that format's normal location. Optional AKM-only extensions SHOULD be namespaced under `akm` to reduce the chance of colliding with future native fields: ```yaml --- description: Review a change model: balanced akm: engine: reviewer timeout: 20m --- ``` This namespace does not imply that AKM writes the file. It only gives a native bundle author a collision-resistant place to opt into AKM-specific runtime defaults. ## 4. One configuration cascade Ordinary execution values use one far-to-near cascade: ```text installation defaults -> selected engine -> selected agent -> selected command -> task/workflow defaults -> current task, step, or CLI invocation ``` The nearest explicit value wins. This rule includes engine, model, tools, timeout, and other ordinary execution settings. Examples: - a command's model overrides its selected agent's model preference; - a task or workflow step overrides the command; - a direct CLI model flag overrides every asset default; and - omitting a field preserves the value from the next-farthest layer. Selection and authorization are separate. In particular: ```text selected tools = nearest explicit tools value effective tools = selected tools authorized by machine/user runtime policy ``` Agent and command tool declarations do not intersect with each other. The nearer declaration replaces the farther declaration like any other setting. If the selected tools exceed operator authorization, AKM MUST fail explicitly; it MUST NOT silently grant or silently reduce them. Installed third-party bundle metadata participates in the same cascade as locally authored metadata. Provenance does not create a second precedence system. Authorization and budget policy remain the enforcement boundaries. ## 5. Engine selection and fallback The ordinary cascade selects the engine. In practical nearest-first terms: ```text CLI/step/task override -> command default -> agent default -> configured installation default -> documented fallback ``` When no layer selects an engine, AKM uses the fixed `opencode-sdk` fallback if it is available. The fallback MUST be announced, never silent. A configured `defaults.engine` is the normal way to select an installation default and preempts the fallback. If the fallback is unavailable, AKM fails with setup guidance. The fallback is deliberately not separately configurable: such a setting would duplicate `defaults.engine`. ## 6. Model maps and structured aliases AKM ships a small starter map of provider-neutral intent aliases. The initial vocabulary SHOULD stay small; `fast`, `balanced`, and `reasoning` are the approved starting shape. These are conveniences, not permanent universal model classifications. The authoritative mechanism is data-driven and operator-owned. The long-term mapping precedence is: ```text AKM starter defaults -> explicitly adopted mapping pack -> user or organization configuration -> engine-specific overrides ``` Bundles may select aliases. They MUST NOT redefine what an alias means on the host. A bundle may distribute a suggested map, but it becomes active only when the operator explicitly adopts it. AKM 0.9.2 does not implement reusable mapping packs. It ships an immutable default `models.json` with the installation and reads an optional, user-editable `models.json` from the AKM configuration directory. The user file overlays the installed default by alias and by field, so users need only state differences. The default MUST NOT live in the cache: cache deletion or eviction cannot be allowed to change model resolution. AKM provides an explicit command that can copy the installed defaults into the user config directory for full customization. An alias mapping may be either: 1. a simple exact model identifier; or 2. a structured inference profile containing a model and related defaults. A structured alias expands as defaults at the same cascade layer that selected it. Explicit sibling fields and nearer layers win: ```text farther layers -> selected alias profile -> explicit fields beside the alias -> nearer layers ``` For example, if `reasoning` supplies `effort: high`, then an explicit `effort: medium` beside `model: reasoning` wins. ## 7. Optimistic lowering AKM does not maintain a static matrix of every feature every model, endpoint, and harness supports. Such a matrix would become stale and reject engines that gain features independently. Instead: 1. Resolve the common cascade. 2. Let the selected engine adapter translate the fields it understands. 3. Emit structured notices for fields the adapter does not translate. 4. Dispatch optimistically. 5. Treat an actual provider or harness rejection as a runtime failure. An untranslated setting is not a pre-dispatch capability failure. An operator authorization violation is still a hard failure because it is policy, not a capability guess. When an engine has no native system-prompt channel, AKM MUST preserve the persona by deterministically composing a clearly delimited persona block into the user prompt. It SHOULD emit a lowering notice when it uses this fallback. The 0.9.2 implementation makes that adapter choice structural. Every registered harness contributes a concrete resolved-request lowerer through the harness registry, and direct LLM is the remaining registered lowerer. The registry is an inventory of implementations, not a table predicting model/provider capabilities. Lowerers receive the exact model and inference selected by the common cascade; they do not reinterpret aliases. They return stable translated and untranslated field paths plus structured notices whose fixed messages and metadata contain no prompt, environment value, credential value, or provider error body. LLM and SDK-fallback credentials stay as symbolic descriptors in engine transport and frozen runner material; secret values never enter the resolved request. Only final runner dispatch reads their current environment values. An already-frozen runner uses the config-free lowering entry point, which does not consult live config, aliases, environment variables, or credentials before dispatch. ## 8. Native agent selectors A qualified `agents/...` ref is portable and resolves through AKM. A bare agent name in a native command is a native harness selector. For the initial implementation: - a bare selector works with its matching native harness; - an operator-defined selector mapping may translate it; - the selected engine adapter may translate or consume it; and - AKM fails with an actionable portability error if no deterministic translation exists. The core MUST NOT use fuzzy name or content matching to guess an equivalent persona. ## 9. Command arguments The initial portable command-template contract is deliberately limited to a single, one-pass `$ARGUMENTS` substitution. The invocation supplies the exact argument string. AKM MUST NOT initially claim portable support for positional `$N` placeholders or named placeholders. Native tools disagree about positional indexing and tokenization, and AKM has not established a portable named-argument source syntax. Native-only template constructs may remain in native source files and continue to work when users invoke those files through their native tool. When AKM owns execution, an unsupported native construct MUST produce an actionable portability error before dispatch. AKM MUST NOT partially expand a command and send the remainder to the model. Template substitution is intentionally non-programmable: no expressions, loops, conditionals, or recursive expansion. ## 10. Resolution time and sessions Direct command invocations and scheduled tasks resolve the current assets and configuration when they execute. Workflows use the same semantic resolver, then freeze its output when a run is created. The frozen plan must include every dispatch-significant resolved input needed for deterministic resume and replay, including the selected agent/persona, command content after argument substitution, exact engine/model settings, and relevant source identities or hashes. AKM command execution starts a fresh, one-shot session by default. Reusing or resuming a native session requires an explicit invocation option. ## 11. Task and workflow source formats ### 11.1 Task v3 Task v3 is an intentional breaking replacement for the 0.9.1 task schema. AKM does not keep the v2 parser as a compatibility execution path. Instead, `akm migrate` provides an explicit, previewable, fail-closed conversion. It backs up files before writing, converts only deterministic cases, and stops for manual review when an argv array or another v2 construct cannot be translated portably into the v3 shell-string contract. The executable part of a v3 task is GitHub-step-shaped: - exactly one of `uses` or `run` selects the work; - compatible fields such as `name`, `with`, `env`, `shell`, and `working-directory` keep their GitHub spelling and location; and - scheduling and other AKM-only controls use the `akm` namespace when the source is a step-shaped task. `uses` accepts both existing AKM refs and GitHub action refs. Their grammars are deterministic: AKM does not introduce an `akm:` URI alias or guess whether an unresolved string was intended as inline content. AKM command refs, workflow refs, script refs, and future GitHub action refs remain distinct resolved target kinds. An agent ref is never executable through `uses`. Inline command content uses a built-in command action rather than a separate prompt target. Its contract requires exactly one of `with.ref` or `with.content`; `with.arguments` supplies the exact string substituted for the portable `$ARGUMENTS` placeholder. Stored and inline forms compile to the same command IR. AKM accepts scheduling information through adapters in three source shapes: 1. a step-shaped task with `akm.schedule`; 2. a step-shaped task with a GitHub-style `on` block; or 3. a complete GitHub-style `on` plus `jobs` document. The third shape is exposed as one workflow asset, not as both a task and a workflow. Its locally representable triggers create internal scheduler bindings that use the existing OS-native scheduler backends. `schedule` maps to scheduled execution and `workflow_dispatch` maps to manual execution. Repository and service events such as `push`, `pull_request`, and `issues` produce an explicit unsupported-trigger result in local execution; AKM does not silently ignore them or install polling daemons. ### 11.2 Workflow formats and internal IR AKM Markdown and GitHub-shaped YAML are peer authoring formats. Adapters compile both into a shared, internal, versioned IR. The IR deliberately reuses known GitHub concepts such as `jobs`, `needs`, `steps`, `uses`, `run`, `with`, and `env` where they fit. It is not the literal GitHub workflow schema and is not a fourth public authoring format. The IR also carries the information AKM needs for deterministic execution: resolved command and persona snapshots, engine/model/tool settings, source identity and hashes, adapter-owned supported extensions, lowering notices, and journal/freeze metadata. Format adapters may preserve supported native constructs explicitly. An unsupported construct produces an actionable portability error or a structured lowering notice; it never creates a format-specific executor alongside the shared scheduler. GitHub interoperability is consumption-first. GitHub workflow and action files remain authoritative and AKM will consume them through adapters; AKM does not generate or synchronize GitHub files. Full GitHub workflow/action execution is 0.9.3 work. A separate, deliberate future bridge is a public GitHub Action package that invokes AKM from a GitHub workflow. That package uses typed subpath actions such as `/command`, `/workflow`, and `/task`, backed by one runtime. There is no `/prompt` action because prompt content is a command. ## 12. 0.9.2 support boundary 0.9.2 delivers the coherent MVP across direct CLI invocation, scheduled tasks, and workflow freeze/resume. All currently registered execution profiles must consume the same resolved request and lowering contract. The native agent/command authoring formats in scope are the formats AKM already recognizes: AKM native, Claude, and OpenCode. 0.9.2 does not add native file adapters for Codex, Gemini, Aider, Copilot, Pi, Amazon Q, or OpenHands, but their existing execution profiles must still accept unified resolved work. New native authoring formats, full GitHub action/workflow ingestion, and the public GitHub Action package begin in 0.9.3 or later. ## 13. Implementation status This document describes both the approved design and the staged 0.9.2 implementation boundary. The current line implements: - the installed/operator `models.json` layers and exact alias/profile expansion in the common far-to-near cascade; - selection-versus-authorization handling for tools before engine lowering; - canonical `akm command run`, adapter-rendered command/persona loading, strict one-pass `$ARGUMENTS`, and the delegating non-interactive `akm agent` compatibility surface; - an engine-owned optimistic lowerer for all ten registered harnesses plus direct LLM, with exact selected models, translated/untranslated field inventories, deterministic persona/conversation composition, and secret-free structured notices; - runtime adapters for the existing task-v2 prompt arm, improve/proposal model work, current frozen workflow units and judges, index passes, and shared structured LLM calls; and - symbolic LLM and SDK-fallback credentials until dispatch, including a config-free path that lowers already-frozen runner material without re-reading live config or aliases. WP5 is therefore implemented as **runtime lowering convergence**. It does not claim the still-separate WP6 task-v3 source schema/migrator, nor WP7's final source-to-frozen durable workflow IR and resume-persistence convergence. The current workflow adapter lowers its already-frozen engine invocation at run time; that is not proof that the source plan froze a complete `ResolvedExecutionRequestV1`. Workflow lowering notices are currently live result/diagnostic metadata and are intentionally excluded from durable result/evidence journal data; this specification does not assign future notice persistence to WP7. GitHub-step-shaped task sources, GitHub-shaped workflow compilation, durable common-request freeze/resume, and their migrations remain WP6/WP7 work. Full GitHub Actions semantics, remote action acquisition, and the public GitHub Action package remain unsupported and out of scope. Implementation work MUST preserve current public behavior deliberately or document a migration. It MUST NOT describe a remaining WP6/WP7 gap as approved semantics merely because an older task or workflow runtime already exists. ## 14. Deferred decisions The following remain deliberately outside 0.9.2: - portable positional or named command arguments; - nested or child workflows; - reusable model mapping packs beyond the installed/user `models.json` layers; - full GitHub workflow/action execution and the public GitHub Action package; - additional native agent/command authoring formats; and - the CLI syntax for explicit session reuse. These require separate decisions or implementation evidence. They are not license to add synchronization, native-asset write-back, a central capability registry, or a second command-execution mode.