architecture.mdx
July 24, 2026 ยท View on GitHub
What runs where
Agent Plane has three layers with different responsibilities:
- CLI runtime (
packages/agentplane/src) - Shared models and config (
packages/core/src) - Generated schema/spec layer (
schemasandpackages/spec/schemas)
The runtime layer owns command behavior. The core layer owns parsing, defaults, validators, and shared contracts. The root schemas/ directory is the repository discovery surface for generated public schemas. The spec layer is a generated mirror for tooling and external consumers, synchronized from runtime code into schemas, packages/spec/schemas, and packages/core/schemas.
Durable config and task artifact contracts now use Zod in packages/core/src/** as the single source of truth, with generated JSON Schema mirrors emitted for tooling and external consumers.
For the architectural decision and practical boundary guidance, see ADR: Zod Contract SSOT and Schema validation strategy.
Current priority
This page describes the current 0.4 implementation surfaces. It is not an endorsement of expanding
recipe, runner, or prompt-assembly scope outside an approved task plan.
The former 0.3 stabilization backlog is historical. Current work should treat release notes, ADRs,
tests, and the runtime contracts below as the active evidence source.
Framework control plane
The framework layer is the reusable control plane that recipes and runner-specific code now consume instead of rebuilding local helper state.
- Harness resolution:
packages/agentplane/src/runtime/harness/*- Produces
ResolvedHarnessContractfrom repo policy gateway, config, workflow mode, task contract, backend restrictions, and protected-path rules.
- Canonical execution context:
packages/agentplane/src/runtime/execution-context.ts- Produces
AgentplaneExecutionContext/ReadOnlyUsecaseContextwith repo, task backend, harness, approvals, capability registry, execution-profile runtime, task-intake runtime, explain payloads, and protocol surfaces.
- Behavior precedence and traces:
packages/agentplane/src/runtime/behavior/*- Formal precedence is
harness -> extension -> user -> builtin, with traceable winners and conflicts.
- Capabilities:
packages/agentplane/src/runtime/capabilities/*- Unifies backend- and runner-facing capability projection, including unavailable/blocked semantics.
- Governance runtime:
packages/agentplane/src/policy/*packages/agentplane/src/runtime/approvals/*packages/agentplane/src/runtime/execution-profile/*- Makes approvals, risky actions, budgets, stop/handoff conditions, trace policy, and timeout policy explicit runtime inputs.
- Task intake:
packages/agentplane/src/runtime/task-intake/*- Defines
TaskIntakeContext, clarification contracts, graph drafts, and materialization plans without binding them to a specific recipe or runner adapter.
- Explain and protocol:
packages/agentplane/src/runtime/explain/*packages/agentplane/src/runtime/protocol/*- Produces machine-readable explain payloads plus additive, versioned protocol/result envelopes that can be persisted and extended without replacing the core model.
CLI runtime map
- Command entry and global argument handling:
packages/agentplane/src/cli/run-cli.ts
- Command registry and lazy loading:
packages/agentplane/src/cli/run-cli/command-catalog.ts
- Command handlers:
packages/agentplane/src/commands/**
- Shared module topology:
- Task backend integration:
packages/agentplane/src/backends/task-backend/load.ts
- Built-in task backends:
packages/agentplane/src/backends/task-backend/local-backend.tspackages/agentplane/src/backends/task-backend/cloud-backend.ts
- Cloud connector integration:
- Provider-specific sync adapters, including Redmine, live outside the public CLI behind the cloud backend contract.
Core map
- Project resolution:
packages/core/src/project/
- Config parsing and defaults:
packages/core/src/config/
- Task document and snapshot primitives:
packages/core/src/tasks/
Runtime data flow
- CLI resolves project root, runtime mode, and
.agentplane/WORKFLOW.md. runtime/harnessresolves the repo-level contract intoResolvedHarnessContract.runtime/execution-context.tsassembles the canonical execution context around that harness.- Behavior, capability, approval, execution-profile, task-intake, explain, and protocol modules derive reusable runtime inputs from the canonical context.
- Command handlers and runner usecases consume the same context instead of rebuilding ad hoc task/repo/config helpers.
- Backend mutation and task projection update
.agentplane/tasks/<task-id>/README.mdand optional generated export snapshots. - Shared runner flows persist production run artifacts under
<git-common-dir>/agentplane/runner/tasks/<task-id>/runs/<run-id>/, including machine-readable framework explain/protocol payloads in the bundle. The supervisor-owned root is stable across linked worktrees and protected from native Codexread-onlyandworkspace-writesandboxes.danger-full-accessand host-authority custom or Hermes runners can address that root, so their filesystem authority remains unverified. Reads through public runner usecases retain a narrow compatibility path for historical 0.6.24 task-local run artifacts; new run creation never uses that legacy location. Cancelling a prepared legacy run may update its existing state and events, but a running legacy run is never signaled or synthesized as terminal because its supervisor does not participate in the cooperative cancellation protocol. Unsafe, invalid, or incomplete supervisor paths fail closed instead of falling back. Per-task execution claims serialize provider authority inside one repository instance. A stale claim is recovered only under a generation-scoped exclusive recovery lease and only when the claimed run is absent, terminal, or incomplete before provider spawn. Active or unverified owners, ambiguous non-terminal runs, and existing or invalid recovery leases remain fail-closed; a recovery lease is never stolen based on age or apparent owner death. Terminal supervisor state is projected to TaskData before the claim is retired; non-local projections use the backend's revision guard. A terminal claim remains non-recoverable when process cleanup is failed, unknown, or reports a live residual; supervisor-owner death alone cannot bypass that process boundary. Confirmed cleanup retires authority for the declared managed scope even when descendant containment remains limited; this avoids wedging every current POSIX and Windows run while keeping failed, unknown, and residual cleanup fail-closed. Direct-child cleanup therefore records process-group and descendant-lifetime checks asnot_run, not failed. Limited process lifetime keeps workspace-write and host-authority success policies unverified with an explicit residual risk. Only an exact inherited native read-only boundary with no writable scope may establish overall observed success through filesystem-effect containment, without upgrading the separate process-lifetime claim. The currently claimed run is authoritative across runs even if the wall clock moves backwards, while same-run lifecycle rank prevents a terminal state from regressing torunningorprepared. Without current-claim authority,created_atkeeps delayed historical projection from replacing a newer run. Atomic TaskData and runner control-file publications fsync file contents and, where the operating system and filesystem support it, the parent directory. Unsupported directory fsync is best-effort, so the contract does not claim universal power-loss durability. Pure Node does not exposeopenat/linkat: path ancestry and inode changes are checked before and after operations, but a hostile same-user swap inside the syscall-sized check/use gap remains a platform limitation. Cross-clone execution coordination is likewise outside the repository-local claim contract. - Agent Change Record support derives
.agentplane/tasks/<task-id>/acr.jsonfrom the same task, policy, verification, finish, and Git evidence instead of adding a parallel task source of truth.
Task file decision
Current target:
- Keep one file per task.
- Keep
.agentplane/tasks/<task-id>/README.mdas the canonical container for now. - Treat frontmatter as the canonical task state, including
revision,sections, status, and lifecycle metadata. - Treat the visible markdown body as a generated projection, not as the operational write surface.
Why README stays the target for now:
- It preserves the current human-first workflow: one readable task file, stable diffs, and no split between structured state and narrative view.
- Canonical frontmatter already gives the system the structured write surface it needed for generated body, migration, and revision groundwork.
- Moving to single-file YAML now would impose migration and tooling cost without solving a correctness problem that the current README-plus-frontmatter model still has.
Revisit a future task.yaml target only if at least one of these becomes true:
- Frontmatter grows large enough that task files become materially harder to scan than the generated body helps.
- Most task mutations become machine-driven and the rendered markdown view stops being the primary human surface.
- Non-local backends or external integrations need a stricter structured payload than YAML frontmatter inside README can express cleanly.
- Projection repair, normalization, or container-specific drift starts costing more complexity than a format migration would remove.
Harness engineering loop
Agent Plane architecture is designed for an iterative control loop:
- Constrain: define scope and policy via contracts/config.
- Execute: run small, explicit command steps.
- Observe: capture structured artifacts and diagnostics.
- Recover: use deterministic fallback/restore paths.
- Integrate: merge verified increments quickly.
This loop keeps autonomy useful while preserving operator control and repository legibility.
Upgrade and policy flow
agentplane upgrade applies managed framework assets and can emit plan-only upgrade artifacts.
- In agent mode, run artifacts are created under
.agentplane/.upgrade/agent/<runId>/only when a plan-only report is needed (changes to add/update). - When there are no managed changes, agent mode exits via fast no-op and does not create per-run artifacts.
- Auto mode uses replace-first behavior for managed files;
.agentplane/policy/incidents.mdis append-only when local content already exists.
Policy enforcement now resolves through the framework layer and is then consumed by command handlers, runner flows, and guard paths:
ResolvedHarnessContractdefines workflow, task, policy, and backend restrictions.PolicyEngineclassifies actions andApprovalRuntimeevaluates gated behavior such as network, fs, git, config, and force mutations.ResolvedExecutionProfileRuntimecarries approval escalation, budgets, stop/handoff conditions, trace policy, and timeout policy.- Runner and recipe-adjacent flows receive the same resolved policy inputs through the canonical context and persisted runner bundle.
The existence of these shared surfaces should not be read as an active mandate to broaden runner or recipe architecture without a scoped task and verification plan.
Release flow
Release is split into planning and apply:
agentplane release plangenerates patch candidate and notes inputs.agentplane release applyupdates versions and changelog artifacts.- Local prepublish gates must pass before
--push. - npm publish is GitHub-only with provenance enforced by package scripts and workflow checks.