diff --git a/.opencode/agents/pr-review-worker.md b/.opencode/agents/pr-review-worker.md
index 213c25a34..afa650ea2 100644
--- a/.opencode/agents/pr-review-worker.md
+++ b/.opencode/agents/pr-review-worker.md
@@ -204,7 +204,7 @@ Evaluate the PR against the following 10 categories, in order of importance. Loa
1. **CORRECTNESS** — Does the code do what the linked issue says it should? Do all acceptance criteria pass? Are edge cases handled?
-2. **SPECIFICATION ALIGNMENT** — Does the code align with `docs/specification.md`? If code departs from spec, it is wrong — request correction.
+2. **SPECIFICATION ALIGNMENT** — Does the code align with `docs/specification/`? If code departs from spec, it is wrong — request correction.
3. **TEST QUALITY** — Are there Behave BDD scenarios for all new behavior? Are integration tests updated if component interfaces changed? Are edge cases AND error/failure paths covered? Does coverage stay >= 97%? For bug fixes: does a `@tdd_issue_N` regression test exist? Are Gherkin scenarios well-named and readable as living documentation?
diff --git a/.opencode/skills/cleveragents-contributing/SKILL.md b/.opencode/skills/cleveragents-contributing/SKILL.md
index 6934321dc..3ad473909 100644
--- a/.opencode/skills/cleveragents-contributing/SKILL.md
+++ b/.opencode/skills/cleveragents-contributing/SKILL.md
@@ -85,7 +85,7 @@ Some examples of things covered by this skill:
- Plan lifecycle migration (agents plan use vs agents tell, ULID format, separate
storage backends, no migration path)
- Backwards compatibility policy (none pre-v3.0.0)
-- docs/specification.md as authoritative source
+- docs/specification/ as authoritative source
- Hatch + pyproject.toml toolchain
- Pre-commit hooks via scripts/setup-dev.sh.
@@ -639,7 +639,7 @@ Issue creation — complete requirements:
```
Before touching any production code:
│
-├─ STEP 1: READ docs/specification.md FIRST (mandatory)
+├─ STEP 1: READ docs/specification/ FIRST (mandatory)
│ ├─ Find the sections relevant to your task
│ ├─ Read them completely — understand the intended design
│ ├─ If the spec and the current codebase disagree:
@@ -648,7 +648,7 @@ Before touching any production code:
│ └─ Architectural changes → ADR process required BEFORE writing any code
│ 1. Write the ADR document (see "Am I documenting something?" for format)
│ 2. Submit for review and approval via PR
-│ 3. Once approved → update docs/specification.md
+│ 3. Once approved → update docs/specification/
│ 4. THEN write the code
│
├─ STEP 2: Does a verified issue exist for this work?
@@ -896,7 +896,7 @@ Code review — what to assess and how to decide:
│ │ └─ Are there edge cases not covered that could cause production failures?
│ │
│ ├─ SPECIFICATION ALIGNMENT
-│ │ ├─ Does it align with docs/specification.md?
+│ │ ├─ Does it align with docs/specification/?
│ │ └─ If code departs from spec → it is wrong; request correction
│ │
│ ├─ TEST QUALITY
@@ -1007,7 +1007,7 @@ File placement rules for this project (every path is exact — no variations):
├─ Is this DOCUMENTATION?
│ └─ → /docs/
│ ├─ Must be written in MkDocs-compatible markdown
-│ ├─ docs/specification.md → THE authoritative architecture spec
+│ ├─ docs/specification/ → THE authoritative architecture spec
│ │ ⚠️ Only modify via ADR process, never to match broken code
│ └─ Build with: nox -s docs
│
@@ -1471,7 +1471,7 @@ Diagnosing CI failures in this project:
Documentation standards for this project:
│
├─ WHERE DOES DOCUMENTATION LIVE?
-│ ├─ Architecture and design decisions → docs/specification.md
+│ ├─ Architecture and design decisions → docs/specification/
│ │ (modify only via ADR process — see below)
│ ├─ User-facing guides, API docs, how-tos → docs/ (MkDocs format)
│ ├─ Code documentation → docstrings/inline comments in source files
@@ -1532,9 +1532,9 @@ Documentation standards for this project:
│ ├─ PROCESS:
│ │ 1. Create the ADR document in docs/adr/ (ADR-NNN-title.md)
│ │ 2. Submit for review via PR (labeled as an ADR)
-│ │ 3. Approved → update docs/specification.md with the new decision
+│ │ 3. Approved → update docs/specification/ with the new decision
│ │ 4. THEN write the code
-│ └─ ⚠️ Never edit docs/specification.md to match incorrect code
+│ └─ ⚠️ Never edit docs/specification/ to match incorrect code
│
├─ DOCS/SPECIFICATION.MD (the most important doc)
│ ├─ Read this BEFORE starting any task — relevant sections
@@ -1564,7 +1564,7 @@ CleverAgents plan workflow — two mutually exclusive systems:
│ ├─ Identifiers: ULID — 26-character Crockford base32
│ │ e.g. 01HXM8C2ZK4Q7C2B3F2R4VYV6J
│ ├─ Storage: PlanLifecycleService
-│ └─ Authority: this is the authoritative workflow per docs/specification.md
+│ └─ Authority: this is the authoritative workflow per docs/specification/
│
├─ LEGACY SYSTEM — DEPRECATED, DO NOT START NEW WORK HERE
│ ├─ Commands:
@@ -1777,7 +1777,7 @@ Development environment setup for this project:
│ ├─ npm install -g commitizen@2.8.6 cz-customizable@4.0.0
│ └─ Use git cz instead of git commit going forward
│
-├─ STEP 6: Read docs/specification.md
+├─ STEP 6: Read docs/specification/
│ └─ Before touching ANY code, read the relevant specification sections
│
├─ COMPLETE TOOL INVENTORY FOR THIS PROJECT
@@ -2081,7 +2081,7 @@ Design patterns in this project — use liberally, ad-hoc is NOT acceptable:
| TDD assertion type | **`AssertionError` ONLY** | `assert` or `raise AssertionError(...)` |
| TDD permanent tags | **`@tdd_issue`, `@tdd_issue_N`** | Never removed after merging |
| TDD temporary tag | **`@tdd_expected_fail`** | Removed by bug fix developer |
-| Architecture spec | **`docs/specification.md`** | Authoritative — code aligns to it, not vice versa |
+| Architecture spec | **`docs/specification/`** | Authoritative — code aligns to it, not vice versa |
| Commit first line | **Verbatim from issue Metadata** | When issue prescribes one — copy exactly |
| PR dep direction | **PR → blocks → issue** | NEVER reversed — causes unresolvable deadlock |
| Multi-level testing | **Unit + Integration + Benchmarks** | Every task must address all three |
diff --git a/.opencode/skills/cleveragents-contributing/references/cli-workflow/README.md b/.opencode/skills/cleveragents-contributing/references/cli-workflow/README.md
index fbf72fce1..d25b3981a 100644
--- a/.opencode/skills/cleveragents-contributing/references/cli-workflow/README.md
+++ b/.opencode/skills/cleveragents-contributing/references/cli-workflow/README.md
@@ -24,7 +24,7 @@ entire lifecycle of that plan.
## v3 Workflow (Always Use This)
-Per `docs/specification.md`, the v3 plan lifecycle is the authoritative workflow.
+Per `docs/specification/`, the v3 plan lifecycle is the authoritative workflow.
All new development uses v3 commands exclusively.
```bash
diff --git a/.opencode/skills/cleveragents-contributing/references/file-organization/README.md b/.opencode/skills/cleveragents-contributing/references/file-organization/README.md
index a5d05c0af..73d3150cd 100644
--- a/.opencode/skills/cleveragents-contributing/references/file-organization/README.md
+++ b/.opencode/skills/cleveragents-contributing/references/file-organization/README.md
@@ -26,7 +26,7 @@ cleveragents/ ← repository root
│ └─ *.resource
│
├─ docs/ ← ALL documentation (MkDocs format)
-│ ├─ specification.md ← authoritative architecture spec
+│ ├─ specification/ ← authoritative architecture spec (directory)
│ └─ *.md
│
├─ config/ ← configuration files
@@ -108,7 +108,7 @@ real databases, real message queues. No test doubles permitted.
- Markdown files in MkDocs-compatible format
- Images, diagrams, and supporting assets
-#### `docs/specification.md` — Authoritative Architecture Spec
+#### `docs/specification/` — Authoritative Architecture Spec
This file is **the authoritative source of truth** for all architectural and
design decisions. Rules:
@@ -116,7 +116,7 @@ design decisions. Rules:
- Read the relevant sections **before beginning any task**
- When code contradicts specification → **fix the code, not the spec**
- Spec changes → ADR process required first; approved ADR → spec update → code update
-- Never edit `docs/specification.md` to match broken code
+- Never edit `docs/specification/` to match broken code
### `/config/` — Configuration Files
diff --git a/.opencode/skills/cleveragents-spec/SKILL.md b/.opencode/skills/cleveragents-spec/SKILL.md
index 4010fbd1f..e97cc6a68 100644
--- a/.opencode/skills/cleveragents-spec/SKILL.md
+++ b/.opencode/skills/cleveragents-spec/SKILL.md
@@ -3,7 +3,7 @@ name: cleveragents-spec
description: |
Complete specification skill for CleverAgents — covering every architectural
concept, entity, workflow, CLI command, and design decision from
- docs/specification.md. This skill explains WHAT the system is intended to
+ docs/specification/. This skill explains WHAT the system is intended to
build, and HOW all its parts fit together.
Use this skill whenever you need to know: what a Plan is and how its four
@@ -69,7 +69,7 @@ references:
> code to it (testing, nox, CI, branch naming), use the `cleveragents-contributing`
> skill. For company-wide policies and process, use `cleverthis-guidelines`.
>
-> **Source of truth**: `docs/specification.md`. When implementation and this skill
+> **Source of truth**: `docs/specification/`. When implementation and this skill
> disagree, the specification is authoritative. Align code to spec, not vice versa.
---
diff --git a/.opencode/skills/cleverthis-guidelines/SKILL.md b/.opencode/skills/cleverthis-guidelines/SKILL.md
index 7c472911f..c9f146470 100644
--- a/.opencode/skills/cleverthis-guidelines/SKILL.md
+++ b/.opencode/skills/cleverthis-guidelines/SKILL.md
@@ -203,7 +203,7 @@ What are you about to do?
Before writing any code:
│
├─ SPECIFICATION FIRST (mandatory step)
-│ ├─ Open docs/specification.md
+│ ├─ Open docs/specification/
│ ├─ Read ALL sections relevant to your task
│ ├─ Understand the intended architecture and design
│ └─ If code ≠ specification → ALWAYS align code to specification
@@ -1100,11 +1100,11 @@ Architectural Decision Record (ADR) process:
├─ ADR process:
│ ├─ Capture proposed change in an ADR document
│ ├─ Submit for review and approval
-│ ├─ Once approved → incorporate into specification (docs/specification.md)
+│ ├─ Once approved → incorporate into specification (docs/specification/)
│ └─ Implementation ONLY after specification is updated
│
├─ Source of truth priority:
-│ ├─ docs/specification.md is AUTHORITATIVE
+│ ├─ docs/specification/ is AUTHORITATIVE
│ ├─ When code ≠ specification → align code to specification
│ └─ Never adjust specification to match incorrect code
│
@@ -1241,7 +1241,7 @@ Documentation standards (all code-related docs):
│ └─ Avoid duplicate or parallel documentation for the same content
│
├─ SPECIFICATION vs. CODE
-│ ├─ docs/specification.md is THE authoritative source of truth
+│ ├─ docs/specification/ is THE authoritative source of truth
│ ├─ Before any task: review relevant specification sections
│ ├─ When code ≠ spec → code is wrong, align code to spec
│ └─ Spec changes: go through ADR process, not ad-hoc edits
@@ -1419,7 +1419,7 @@ File organization — every file has a canonical home:
│
├─ /docs/
│ ├─ Documentation and markdown files (project: MkDocs format)
-│ ├─ docs/specification.md → THE authoritative architecture specification
+│ ├─ docs/specification/ → THE authoritative architecture specification
│ └─ API docs, user guides, architecture docs, changelog
│
├─ /config/
@@ -1482,7 +1482,7 @@ Development environment setup (new contributor checklist):
│
├─ STEP 5: Read key documents
│ ├─ CONTRIBUTING.md → all project rules (top priority)
-│ ├─ docs/specification.md → architecture and design decisions
+│ ├─ docs/specification/ → architecture and design decisions
│ └─ This skill file → procedural decision trees
│
├─ VERIFICATION CHECKLIST (examples use Python/nox)
diff --git a/.opencode/skills/cleverthis-guidelines/references/code-style/README.md b/.opencode/skills/cleverthis-guidelines/references/code-style/README.md
index d44a90843..edbfe1757 100644
--- a/.opencode/skills/cleverthis-guidelines/references/code-style/README.md
+++ b/.opencode/skills/cleverthis-guidelines/references/code-style/README.md
@@ -5,7 +5,7 @@
## General Principles
-1. **Specification-First Development**: `docs/specification.md` is authoritative. Code discrepancies → align code to spec (never adjust spec to match code). Architectural changes require ADR process first.
+1. **Specification-First Development**: `docs/specification/` is authoritative. Code discrepancies → align code to spec (never adjust spec to match code). Architectural changes require ADR process first.
2. **Modern Tooling**: Use modern, idiomatic build tools and workflows for the project's language ecosystem. Avoid legacy approaches such as Makefiles or wrapper shell scripts. All tooling should be from the current ecosystem and used as designed — not wrapped in custom scripts.
3. **Prefer Existing Tooling**: Don't add new dependencies when existing tools suffice. Keep the toolchain simple and consistent.
4. **Modular Design**: Files under 500 lines. Break large files into focused, cohesive modules.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 700234833..df6b6a4cb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1157,7 +1157,7 @@ All files must be organized in the following project directories:
### Specification
-`docs/specification.md` is the authoritative source of truth for architectural decisions and
+`docs/specification/` is the authoritative source of truth for architectural decisions and
design details. Before beginning any task, always review the relevant parts of the specification
to understand the fine architectural details. When there is a discrepancy between the current
codebase and the specification document, always assume the specification document is correct.
@@ -1507,7 +1507,7 @@ with an explicit error message explaining the incompatibility.
### The v3 Workflow (Recommended)
-The v3 plan lifecycle is the authoritative workflow per `docs/specification.md`. All new
+The v3 plan lifecycle is the authoritative workflow per `docs/specification/`. All new
development should use v3 commands exclusively:
```bash
diff --git a/docs/specification.md b/docs/specification.md
index 98ec474d0..e6569f53a 100644
--- a/docs/specification.md
+++ b/docs/specification.md
@@ -1,48071 +1,17 @@
# CleverAgents Documentation (Detailed Spec)
-## Overview
-
-CleverAgents is your **command center for AI agents** — a unified platform for orchestrating any task you want agents to accomplish, from developing large software projects to writing comprehensive technical papers, administering databases, managing cloud infrastructure, or any complex multi-step workflow.
-
-The core value proposition is enabling long-running, complex, large-scale tasks to execute autonomously with minimal human intervention, making it ideal for building entire software systems, producing extensive documentation, or managing sophisticated operations largely hands-off.
-
-!!! info "Server Mode"
-
- In **server mode**, CleverAgents becomes a collaborative hub where teams can share resources — prompts, actors, actions, and projects — while executing plans in the cloud. This enables a consistent experience across all your devices: start a complex task on your laptop, check progress from your phone, and review results from any machine.
-
-!!! note "Runtime Foundation"
-
- While CleverAgents leverages LangGraph and LangChain for the underlying LLM runtime primitives (tool calling, graphs, routing), its value lies in what it builds on top of these foundations.
-
-!!! success "Core Capabilities"
-
- - [x] A **first-class plan lifecycle** (Action templates driving Strategize / Execute / Apply phases) for breaking down and tracking complex work
- - [x] A **project + resource model** for grounding tasks in real codebases, databases, documents, and infrastructure
- - [x] A consistent **actor abstraction** for defining and composing intelligent agents
- - [x] An independently registered **resource abstraction** for representing anything that can be read, written, or queried
- - [x] An independently registered **tool abstraction** for reusable, callable operations with resource bindings
- - [x] A **validation abstraction** that extends the tool concept with pass/fail semantics and resource-centric attachment with optional project/plan scoping
- - [x] A consistent **skill abstraction** for organizing tools into composable capability collections
- - [x] A **sandbox + checkpoint** safety model for safe, reversible execution
- - [x] A **CLI/TUI/Web UX** for controlling and monitoring large multi-step autonomous work
-
-!!! example "Advanced Subsystems"
-
- - A scalable **Advanced Context Management System (ACMS)** with a Universal Knowledge Ontology (UKO), a demand-driven Context Request Protocol (CRP), pluggable context strategies, a fusion coordinator, and hot/warm/cold tiers with per-actor views.
- - **Invariants** as first-class constraints (global, project, action, and plan scoped) that flow into the decision tree, with precedence-based conflict resolution via the Invariant Reconciliation Actor.
- - A future-facing ==correction model== where the user can "edit the decision tree" and only recompute affected subtrees.
-
-### Standards Alignment
-
-CleverAgents deliberately adopts open, versioned protocols wherever possible so that clients, tools, and skills can interoperate without bespoke integrations.
-
-!!! tip "Guiding Principles"
-
- 1. **Prefer open protocols** — align with community standards to keep integrations portable and reduce vendor lock-in.
- 2. **Keep adapters at the edge** — standards map into stable internal domain models so core logic remains protocol-agnostic.
-
-The following standards are integrated into the architecture:
-
-| Standard | Role | Key Benefit |
-| :------- | :--- | :---------- |
-| **A2A** (Agent-to-Agent Protocol) | Versioned client-server contract for messaging, task lifecycle, plan management, registry access, and event streaming | Clients are interchangeable; Agent Card discovery enables ecosystem interoperability; reliable remote execution in server mode |
-| **MCP** (Model Context Protocol) | Discovering and invoking external tools over a server boundary | Plug-and-play access to a growing ecosystem of tool providers |
-| **LSP** (Language Server Protocol) | Attaching language intelligence (diagnostics, type info, symbol navigation, completions) to actors and agents | Actors gain semantic code understanding from the mature LSP ecosystem without bespoke language analysis |
-| **Agent Skills** ([AgentSkills.io](https://AgentSkills.io)) | Packaging instruction-driven, multi-step workflows as `SKILL.md` with progressive disclosure | Teaches agents *how* to accomplish complex tasks, complementing MCP tools |
-
-??? info "Agent-to-Agent Protocol (A2A) -- Details"
-
- CleverAgents adopts the external **Agent-to-Agent (A2A) Protocol** standard ([a2a-protocol.org](https://a2a-protocol.org)) as the **sole** communication protocol for all client-server interaction. A2A is the successor to the Agent Client Protocol (ACP), which is now deprecated; A2A retains backward compatibility with ACP's JSON-RPC 2.0 foundation. A2A is built on **JSON-RPC 2.0** (with additional gRPC and REST bindings available) and defines the **fundamental boundary between the Presentation and Application layers** — every client operation flows through A2A regardless of deployment mode. The standard provides operations for messaging (`message/send`, `message/stream`), task lifecycle management, streaming updates via SSE, and **Agent Card**-based capability discovery. CleverAgents extends the standard with `_cleveragents/`-prefixed extension methods (declared via the A2A extension mechanism) for platform operations: plan lifecycle, registry CRUD, entity sync, namespace management, and diagnostics. In local mode, A2A flows over **stdio** via the JSON-RPC binding (agent as subprocess) with platform operations resolved in-process via `A2aLocalFacade`. In server mode, A2A flows over **HTTP** to the CleverAgents server. Both transports use the A2A Python SDK. All clients — CLI, TUI, IDE plugin, and third-party — communicate exclusively through A2A. See [ADR-047](adr/ADR-047-acp-standard-adoption.md), [ADR-048](adr/ADR-048-server-application-architecture.md), and [Server and Client Architecture](#server-and-client-architecture) for the full detail.
-
-??? info "Model Context Protocol (MCP) -- Details"
-
- The standard for discovering and invoking external tools over a server boundary. MCP servers are bridged into the Tool Registry via adapters, giving CleverAgents plug-and-play access to a growing ecosystem of tool providers.
-
-??? info "Language Server Protocol (LSP) -- Details"
-
- The standard for attaching language intelligence to actors and agents. LSP servers are registered in a global LSP Registry (namespaced like all other entities) and bound to actor graph nodes via YAML configuration. When an actor activates, the LSP Runtime starts the appropriate language servers for the actor's bound languages and workspace resources. LSP capabilities — diagnostics, type information, symbol navigation, completions, references, rename, code actions, and more — are exposed to the actor as callable tools (via the `LSPToolAdapter`) and as automatic context enrichment (diagnostics and type annotations injected into the ACMS hot context). Actors can bind LSP servers explicitly by name, by language, or automatically based on the languages detected in their project's resources. Different nodes in an actor's graph can have different LSP bindings, enabling fine-grained control over which agents receive which language intelligence capabilities. See [LSP Integration](#lsp-integration) for the full architectural detail and [ADR-027](adr/ADR-027-language-server-protocol.md) for the decision record.
-
-??? info "Agent Skills (AgentSkills.io) -- Details"
-
- The standard for packaging instruction-driven, multi-step workflows as `SKILL.md` with progressive disclosure. Agent Skills complement MCP tools by teaching agents *how* to accomplish complex tasks rather than simply exposing callable functions.
-
-## Glossary
-
-???+ abstract "Plan Lifecycle"
-
- Plan
- : A ==ULID-identified==, hierarchical unit of work instantiated from an Action template. Progresses through four phases — **Action**, **Strategize**, **Execute**, **Apply** — persisting a decision tree at each step. May spawn child plans. Scoped to one or more projects. Top-level plans carry a namespaced name (`[[server:]namespace/]name`); child plans are identified solely by their plan ID (ULID). All plans are referenced by plan ID when precision is needed, especially in hierarchies containing subplans.
-
- Action
- : A YAML-defined, reusable plan template specifying a description, definition of done, strategy/execution actors, typed arguments, and optional invariants. Project-agnostic until bound to one or more projects via `agents plan use`, which instantiates a Plan. Namespaced as `[[server:]namespace/]name`.
-
- Strategize
- : Second phase of the plan lifecycle (following the Action phase). The first phase where active processing occurs. ==Read-only==: the strategy actor produces the initial decision tree — strategy choices, invariant enforcement records, resource selections, child plan blueprints — without modifying any resources.
-
- Execute
- : Third phase of the plan lifecycle. The execution actor carries out decisions from Strategize — invoking tools, spawning child plans, producing artifacts, creating checkpoints — with all mutations confined to a sandbox. May also create additional decisions constrained by Strategize-phase decisions, based on runtime discoveries.
-
- Apply
- : Fourth and final phase of the plan lifecycle. Merges the sandbox changeset into real project resources. Terminal states: `applied` (success), `constrained` (cannot complete — may revert to Strategize), `errored` (failed), `cancelled` (user/system cancelled).
-
- Decision
- : A persisted choice point in a plan's decision tree, created during Strategize or Execute. Records the question, chosen option, alternatives, confidence score, rationale, context snapshot, and downstream dependencies. Types: `prompt_definition`, `invariant_enforced`, `strategy_choice`, `subplan_spawn`, `subplan_parallel_spawn`, among others. Supports targeted correction with selective subtree recomputation.
-
- Invariant
- : A natural-language constraint on plan execution scoped to global, project, action, or plan level. The runtime precedence chain is four-tier: ==plan > action > project > global==. Exception: global invariants marked `non_overridable` always win regardless of scope. Reconciled by the Invariant Reconciliation Actor at the start of Strategize; recorded as `invariant_enforced` decisions that propagate to child plans.
-
- Automation Profile
- : A named set of confidence thresholds (each `0.0`–`1.0`) gating which plan operations proceed automatically versus requiring human approval. `0.0` = always automatic; `1.0` = always manual. Eight built-in profiles (`manual` through `full-auto`). Custom profiles namespaced as `[[server:]namespace/]name`. Each profile composes a **Safety Profile** that controls hard safety constraints (sandbox, checkpoint, unsafe-tool gating, skill restrictions, cost/retry limits).
-
- Safety Profile
- : A composed sub-model of an Automation Profile that groups all hard safety constraints: `require_sandbox`, `require_checkpoints`, `allow_unsafe_tools`, `require_human_approval`, `allowed_skill_categories`, `max_cost_per_plan`, `max_retries_per_step`, and `max_total_cost`. Safety profiles can also be referenced standalone on Actions when only safety constraints (without full autonomy thresholds) are needed. See [ADR-041](adr/ADR-041-safety-profile-extraction.md).
-
-???+ abstract "Projects & Resources"
-
- Project
- : A named scope linking resources (from the Resource Registry), context policies, invariants, and validation attachments. Does not own resources; a single resource may be linked to multiple projects. Identified solely by its namespaced name (`[[server:]namespace/]name`) — no ULID is generated. May be local or remote.
-
- Resource
- : A ULID-identified entity registered in the Resource Registry representing anything readable, writable, or queryable (git repos, filesystems, databases, etc.). Classified as physical or virtual, typed by a Resource Type, and organized in a DAG via parent/child links.
-
- Resource Type
- : A schema-level definition constraining a category of resources. Specifies accepted CLI arguments, physical/virtual classification, permitted parent/child type relationships, auto-discovery rules, sandbox strategy, and handler implementation. Built-in types (e.g., `git-checkout`, `fs-mount`) are unnamespaced; custom types are namespaced as `[[server:]namespace/]name`. Resource types support single inheritance via the `inherits` field — see [ADR-042](adr/ADR-042-resource-type-inheritance.md).
-
- Resource Type Inheritance
- : A mechanism allowing one resource type to inherit properties, capabilities, child types, sandbox strategy, and handler behavior from another type via the `inherits` field in the type definition. Subtypes can selectively override or extend any inherited field. Tools bound to a parent type automatically work with all subtypes (polymorphic matching). Auto-discovery child type matching and DAG queries are also polymorphic. Single inheritance only; maximum chain depth of 5 levels. See [ADR-042](adr/ADR-042-resource-type-inheritance.md).
-
- Devcontainer
- : A container execution environment defined by a `.devcontainer/devcontainer.json` configuration file per the [Development Containers Specification](https://containers.dev). Auto-discovered when a `git-checkout` or `fs-directory` resource contains a `.devcontainer/` directory. Represented as a `devcontainer-instance` resource type that inherits from `container-instance`. Uses lazy activation — the container is only built when first needed by a plan. See [ADR-043](adr/ADR-043-devcontainer-integration.md).
-
- Execution Environment
- : The runtime context in which tools execute — either the host system or a specific container. Configurable at project scope (`execution_environment` preference), plan scope (`--execution-environment` flag), and resource scope (auto-detected devcontainers). Precedence resolution determines which environment is used when multiple are configured, with `priority: override` forcing a specific container and `priority: fallback` deferring to auto-detected devcontainers. See [ADR-043](adr/ADR-043-devcontainer-integration.md).
-
- Physical Resource
- : A resource bound to a concrete, located artifact — a specific file at a specific path, a specific repo at a specific URL. Directly readable and writable by tools. Two physical resources with identical content remain distinct instances.
-
- Virtual Resource
- : A resource representing an abstract equivalence identity that links physical resources sharing the same content, hash, or name. ==Has no location; cannot be directly read or written.== Equivalence relationships update when underlying physical resources diverge.
-
- Resource Binding
- : The association between a tool and the resources it operates on, declared via typed resource slots. Slots resolve through **contextual binding** (from the plan's project), **static binding** (hardcoded at registration), or **parameter binding** (passed at invocation).
-
- Resource Registry
- : The persistent catalog of all registered resources and their DAG relationships (parent/child links). One of the core registries, alongside the Tool Registry, Skill Registry, Actor Registry, Provider Registry, and LSP Registry.
-
-???+ abstract "Tools & Skills"
-
- Tool
- : The ==atomic unit of execution==: a namespaced, independently registered callable operation. Defined by JSON Schema inputs/outputs, capability metadata (`read_only`, `writes`, `checkpointable`), and a four-stage lifecycle (`discover` / `activate` / `execute` / `deactivate`). Sources: MCP servers, Agent Skills folders, built-ins, or custom Python. Namespaced as `[[server:]namespace/]name`.
-
- Validation
- : A Tool subtype adding: a `mode` (`required` | `informational`) controlling whether failure blocks execution; a structured JSON return with mandatory `passed` boolean, optional `data`, and optional `message`. ==Always read-only== (`writes = false`, `checkpointable = false`). May wrap an existing Tool via `wraps` + `transform`. Managed via `agents validation add/attach/detach`; always attached to a resource, optionally scoped to a project or plan.
-
- Anonymous Tool
- : An inline tool definition embedded in a skill YAML or actor graph node. Same schema as a named tool but unregistered, unnamespaced, and scoped only to its defining context.
-
- Skill
- : A composable, namespaced collection of tools assembled by referencing named tools, defining inline anonymous tools, including other skills, or exposing MCP server tools and Agent Skills ([AgentSkills.io](https://AgentSkills.io)) tools. Actors reference skills by name to acquire capabilities. Namespaced as `[[server:]namespace/]name`.
-
- MCP (Model Context Protocol)
- : A standard for exposing tools and resources over a server boundary via JSON-RPC. CleverAgents discovers MCP tools through the `MCPToolAdapter` and registers them in the Tool Registry with extended capability metadata. MCP tools can be composed into skills and used as tool nodes in actor graphs.
-
- Agent Skills ([AgentSkills.io](https://AgentSkills.io))
- : A standard for packaging instruction-driven, multi-step workflows as `SKILL.md` files with optional `scripts/`, `references/`, and `assets/` directories, using progressive disclosure. Surfaced as tools inside skills and loaded on demand by the actor runtime.
-
-???+ abstract "Actors & Sessions"
-
- Actor
- : A YAML-configured conversational unit — either a single LLM/agent or a composed LangGraph of actors and tool nodes. Specialized roles: strategy actor, execution actor, estimation actor, invariant reconciliation actor. Namespaced as `[[server:]namespace/]name`.
-
- Session
- : A persistent conversation thread tied to an orchestrator actor. Maintains message history across plans and serves as the user's natural-language interface.
-
- Server
- : An optional shared backend providing multi-user storage, namespace resolution, and remote plan execution.
-
-???+ abstract "Protocols & Standards"
-
- A2A (Agent-to-Agent Protocol)
- : The external **Agent-to-Agent (A2A) Protocol** standard ([a2a-protocol.org](https://a2a-protocol.org)), built on **JSON-RPC 2.0** (with gRPC and REST bindings available), used as the **sole** communication protocol for all client-server interaction. A2A is the successor to the Agent Client Protocol (ACP), which is now deprecated; A2A retains backward compatibility with ACP's JSON-RPC 2.0 foundation. A2A defines the **fundamental boundary between the Presentation and Application layers**. Standard A2A operations handle agent messaging (`message/send`, `message/stream`), task lifecycle, streaming updates, and Agent Card-based discovery. CleverAgents `_cleveragents/`-prefixed extension methods handle platform operations (plan lifecycle, registry CRUD, entity sync, namespace management, diagnostics). In local mode A2A flows over stdio via JSON-RPC (agent as subprocess); in server mode over HTTP. Every CLI command maps to an A2A operation. See [Core Concepts > Server > A2A](#agent-to-agent-protocol-a2a) and [Server and Client Architecture](#server-and-client-architecture) for full detail.
-
- LSP (Language Server Protocol)
- : A standard protocol for language intelligence, used in CleverAgents to attach semantic code understanding to actors and agents. LSP servers are registered in the global **LSP Registry** (namespaced as `[[server:]namespace/]name`) and bound to actor graph nodes via YAML configuration. Capabilities — diagnostics, type information, symbol navigation, completions, references, rename, code actions — are exposed as tools (via `LSPToolAdapter`) and as automatic context enrichment. Actors can bind LSP servers explicitly by name, by language, or automatically based on detected resource languages. The LSP Runtime in the Infrastructure layer manages server lifecycle, workspace mapping, and file synchronization. See [LSP Integration](#lsp-integration) for full detail.
-
-???+ abstract "Naming & Identity"
-
- Namespace
- : The scoping segment in the name format `[[server:]namespace/]name`. Defaults to `local/` when omitted. `local/` is reserved for local-only items. Non-`local/` namespaces with server omitted assume the default configured server. Built-in LLM actors use provider prefixes (e.g., `openai/`, `anthropic/`). Built-in resource types are unnamespaced.
-
- ULID
- : ==Universally Unique Lexicographically Sortable Identifier.== Assigned to plans, decisions, resources, correction attempts, and validation attachments. Projects, actions, skills, and tools use their namespaced name as sole identifier instead.
-
-???+ abstract "Context Management (ACMS)"
-
- ACMS (Advanced Context Management System)
- : The pluggable, strategy-driven framework for assembling actor context. Comprises the UKO, CRP, pluggable context strategies, the Context Assembly Pipeline, and hot/warm/cold tiered storage with per-actor scoped views.
-
- UKO (Universal Knowledge Ontology)
- : An RDF-based, inheritance-driven ontology representing resources at multiple abstraction levels with provenance and temporal versioning. Four layers: universal foundation, domain specializations (software, documents, data schemas, infrastructure), paradigm/format specializations (procedural programming, markdown), and technology-specific (Python, PostgreSQL). ==Semantically aware — implicit relationships are inferred from content analysis.==
-
- CRP (Context Request Protocol)
- : A structured vocabulary through which actors declare needed information, desired detail depth, and scope.
-
- Context Strategy
- : A pluggable retrieval component that searches for and assembles ContextFragments using a specific approach (keyword search, semantic embedding, graph navigation, temporal archaeology, etc.). Registered with the Context Assembly Pipeline; executed in parallel by the StrategyExecutor.
-
- Context Assembly Pipeline
- : The central ACMS orchestrator. Ten pluggable Protocol-defined components in three phases: **Strategy Orchestration**, **Fragment Fusion**, and **Context Finalization**. Each component ships with a default implementation and is overridable at global, project, or plan scope.
-
- Skeleton (context)
- : A compressed representation of a plan's accumulated context produced by the SkeletonCompressor. Propagated from parent plans to child plans as inherited context. Size governed by the `skeleton_ratio` budget parameter.
-
-## CLI Commands
-
-!!! adr "Architecture Decision"
- The CLI command structure, output rendering, and interaction patterns are defined in [ADR-021: CLI and Output Rendering](adr/ADR-021-cli-and-output-rendering.md).
-
-### Command Synopsis
-
-
-agents|cleveragents [--data-dir <DATA_PATH>] [--config-path <CONFIG_PATH>]
- [--format (rich|color|table|plain|json|yaml)]
- [--help|-h] [--version]
- [--install-completion [<INST_SHELL>]] [--show-completion [<SHOW_SHELL>]]
- [-v...] <COMMAND> [<ARGS>...]
-
-agents version
-agents info
-agents diagnostics
-agents init [--yes|-y]
-
-agents session create [--actor <ACTOR>]
-agents session list
-agents session show <SESSION_ID>
-agents session delete [--yes|-y] <SESSION_ID>
-agents session export [(--output|-o) <FILE>] <SESSION_ID>
-agents session import (--input|-i) <FILE>
-agents session tell --session <SESSION_ID> [--actor <ACTOR>] [--stream] <PROMPT>
-
-agents project create [(--description|-d) <DESC>] [--resource <RESOURCE>]...
- [--invariant <INVARIANT>]... [--invariant-actor <ACTOR>] <NAME>
-agents project link-resource [--read-only] <PROJECT> <RESOURCE>
-agents project unlink-resource [--yes|-y] <PROJECT> <RESOURCE_NAME>
-agents project list [(--namespace|-n) NS] [<REGEX>]
-agents project show <PROJECT>
-agents project delete [--force|-f] [--yes|-y] <NAME>
-agents project context set[--view (strategize|execute|apply|default)]
- [--include-resource <INCLUDE_RESOURCE>]...
- [--exclude-resource <EXCLUDE_RESOURCE>]...
- [--include-path <INCLUDE_GLOB>]...
- [--exclude-path <EXCLUDE_GLOB>]...
- [--hot-max-tokens <N>]
- [--warm-max-decisions <N_WARM_MAX>]
- [--cold-max-decisions <N_COLD_MAX>]
- [--query-limit <N>]
- [--max-file-size <MAX_FILE_BYTES>]
- [--max-total-size <MAX_TOTAL_BYTES>]
- [--summarize|--no-summarize]
- [--summary-max-tokens <N>]
- [--strategy <STRATEGY>]...
- [--default-breadth <N>]
- [--default-depth <INT_OR_NAME>]
- [--depth-gradient <HOP:INT_OR_NAME>]...
- [--skeleton-ratio <FLOAT>]
- [--temporal-scope (current|recent|all)]
- [--auto-refresh|--no-auto-refresh]
- [--execution-environment <RESOURCE_NAME>]
- [--execution-env-priority (fallback|override)]
- [--clear] <PROJECT>
-agents project context show [--view (strategize|execute|apply|default)]
- <PROJECT>
-agents project context inspect [--view (strategize|execute|apply|default)]
- [--strategy <STRATEGY>]
- [--focus <UKO_URI>]...
- [--breadth <N>] [--depth <INT_OR_NAME>]
- <PROJECT>
-agents project context simulate [--view (strategize|execute|apply|default)]
- [--budget <TOKENS>]
- [--focus <UKO_URI>]...
- [--strategy <STRATEGY>]...
- <PROJECT>
-
-agents validation add --config|-c <FILE> [--update]
-agents validation attach [--project <PROJECT>|--plan <PLAN_ID>]
- <RESOURCE> <VALIDATION> [<ARGS>...]
-agents validation detach [--yes|-y] <ATTACHMENT_ID>
-
-agents actor run [(--output|-o) <OUTPUT_FILE>]
- [-v...] [--unsafe|-u] [--context <CONTEXT_NAME>]
- [--context-dir <CONTEXT_PATH>] [--load-context <LOAD_CONTEXT_NAME>]
- [(--temperature|-t) <TEMP>] [--allow-rxpy-in-run-mode]
- [--skill <SKILL>]... <NAME> <PROMPT>
-agents actor add --config|-c <FILE> [--update]
-agents actor remove <NAME>
-agents actor list
-agents actor show <NAME>
-agents actor context remove [--yes|-y] (--all|-a|<NAME>)
-agents actor context list [<REGEX>]
-agents actor context show <NAME>
-agents actor context export (--output|-o) <FILE> <NAME>
-agents actor context import [--update] (--input|-i) <FILE> [<NAME>]
-agents actor context clear [--yes|-y] (--all|-a|<NAME>)
-
-agents skill add --config|-c <FILE> [--update]
-agents skill remove [--yes|-y] <NAME>
-agents skill list [(--namespace|-n) <NS>] [--source <SOURCE>]
-agents skill show <NAME>
-agents skill tools <NAME>
-
-agents tool add --config|-c <FILE> [--update]
-agents tool remove [--yes|-y] <NAME>
-agents tool list [(--namespace|-n) <NS>] [--source <SOURCE>] [--type (tool|validation)] [<REGEX>]
-agents tool show <NAME>
-
-agents lsp add --config|-c <FILE> [--update]
-agents lsp remove [--yes|-y] <NAME>
-agents lsp list [(--namespace|-n) <NS>] [--language <LANG>]
-agents lsp show <NAME>
-agents lsp serve [--log-level <LEVEL>]
-
-agents resource type add --config|-c <FILE> [--update]
-agents resource type remove [--yes|-y] <NAME>
-agents resource type list [<REGEX>]
-agents resource type show <NAME>
-
-agents resource add [(--description|-d) <DESC>] [--update] <TYPE> <NAME> [type-specific-flags...]
-agents resource remove [--yes|-y] <NAME>
-agents resource list [--all] [(--type|-t) <TYPE>]
-agents resource show <RESOURCE>
-agents resource inspect [--tree] [--file <PATH>] <RESOURCE>
-agents resource tree [(--depth|-d) <N>] [(--type|-t) <TYPE>] <RESOURCE>
-agents resource link-child <PARENT> <CHILD>
-agents resource unlink-child [--yes|-y] <PARENT> <CHILD>
-agents resource stop <NAME>
-agents resource rebuild <NAME>
-
-agents plan list [--phase <PHASE>] [--state <STATE>] [--project <PROJECT>]
- [--action <ACTION>] [<REGEX>]
-agents plan use [--automation-profile <PROFILE>]
- [--invariant <INVARIANT>]...
- [--strategy-actor <STRATEGY_ACTOR>]
- [--execution-actor <EXEC_ACTOR>]
- [--estimation-actor <EST_ACTOR>]
- [--invariant-actor <INV_ACTOR>]
- [--execution-environment <RESOURCE_NAME>]
- [--execution-env-priority (fallback|override)]
- [--arg/-a name=value]...
- <ACTION> <PROJECT>...
-agents plan execute <PLAN_ID>
-agents plan apply [--yes|-y] <PLAN_ID>
-agents plan status <PLAN_ID>
-agents plan cancel [(--reason|-r) <REASON>] <PLAN_ID>
-agents plan tree [--show-superseded] <PLAN_ID>
-agents plan explain [--show-context] [--show-reasoning] <DECISION_ID>
-agents plan correct --mode (revert|append) (--guidance|-g) <GUIDANCE>
- [--dry-run] [--yes|-y] <DECISION_ID>
-agents plan diff (--correction <CORRECTION_ATTEMPT_ID>|<PLAN_ID>)
-agents plan artifacts <PLAN_ID>
-agents plan prompt <PLAN_ID> <GUIDANCE>
-agents plan rollback [--yes|-y] <PLAN_ID> <CHECKPOINT_ID>
-agents plan errors <PLAN_ID>
-
-agents action create --config|-c <CFG_FILE>
-agents action list [(--namespace|-n) <NS>] [(--state|-s) <STATE>] [<REGEX>]
-agents action show <ACTION_NAME>
-agents action archive <ACTION_NAME>
-
-agents automation-profile add --config|-c <FILE> [--update]
-agents automation-profile remove [--yes|-y] <NAME>
-agents automation-profile list [<REGEX>]
-agents automation-profile show <NAME>
-
-agents config set <key> <value>
-agents config get <key>
-agents config list [--filter-values <REGEX>] [<REGEX>]
-
-agents invariant add [--global] [(--project|-p) PROJECT] [--plan PLAN_ID]...
- [--action ACTION]... <INVARIANT_TEXT>
-agents invariant list [--global] [(--project|-p) PROJECT] [--plan PLAN_ID] [--action ACTION]
- [--effective] [<REGEX>]
-agents invariant remove [--yes|-y] <INVARIANT_ID>
-
-
-### Command Reference
-
-!!! info "Output Format Tabs"
- Each command example below is shown in multiple output formats using content tabs. Select a tab to see how the same command renders in that format. The `table` format is visually identical to `rich` in static documentation (the difference is live animation). The `color` format has the same layout as `plain` but with ANSI color codes applied to headers, keys, and values. See **Output Rendering Framework** for full format specifications.
-
-#### Global Options
-
-!!! note "Purpose"
-
- Configure global state locations and shell integration for every command.
-
-**Arguments**
-
-- `--data-dir PATH`: Overrides the global data directory (database, caches, sessions, logs). When omitted, the default data location is used.
-- `--config-path PATH`: Overrides the global configuration file path. When omitted, the default config path is used.
-- `--format rich|color|table|plain|json|yaml`: Set the output rendering format for all subcommands. When omitted, the value is read from the global config key `core.format`. If not set in config either, defaults to `rich`. See **Output Rendering Framework** for full details on each format.
-
- ??? tip "Available Output Formats"
-
- | Format | Description | Best For |
- | :----- | :---------- | :------- |
- | `rich` | Modern rich CLI elements with dynamic effects, animated spinners, progress bars, and generous color | Interactive terminal use **(default)** |
- | `color` | Plain scrolling text with ANSI color codes | Terminals that support color but not advanced rendering |
- | `table` | ASCII box-drawing characters to create structured tables and panels with color | Structured visual output similar to examples in this document |
- | `plain` | Plain text with no color codes or non-ASCII characters | Piping into files, logs, or non-terminal consumers |
- | `json` | Structured JSON output for programmatic consumption | Scripts, CI/CD pipelines, programmatic consumption |
- | `yaml` | Structured YAML output for programmatic consumption | Configuration, programmatic consumption |
-- `--help`, `-h`: Print help for the current command.
-- `--version`: Print the version and exit.
-- `--install-completion [SHELL]`: Install shell completion for the given shell.
-- `--show-completion [SHELL]`: Show the completion script for the given shell.
-- `-v`: Increase log verbosity for a single invocation (repeatable). By default (no `-v`), only normal command output is shown on stdout; logging output is suppressed except on fatal errors where the application exits entirely and displays the error. Each additional `-v` raises the verbosity one level: `-v` = ERROR (non-fatal, recoverable errors), `-vv` = WARN (warnings that may indicate a degraded system but are not necessarily errors), `-vvv` = INFO (routine informative messages useful to common users), `-vvvv` = DEBUG (coarse debugging output), `-vvvvv` = TRACE (the most granular logging level available). Increased verbosity writes to both the log file and stderr by default, keeping log output separate from normal program output on stdout. The destination for log output raised by `-v` is configurable: it can be sent to the terminal (stderr by default, or redirected to another stream such as stdin or a device), to the log file only, or to both. See `core.log.terminal`, `core.log.terminal-stream`, and `core.log.file-enabled` configuration keys for details. This flag does not persist — it only affects the current invocation.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents --data-dir /srv/cleveragents --config-path /srv/cleveragents/config.toml info
-
- ╭─ System Snapshot ─────────────────╮
- │ CleverAgents 1.0.0 │
- │ Mode: local │
- │ Automation: review │
- │ Status: ready │
- ╰───────────────────────────────────╯
-
- ╭─ Paths ───────────────────────────────╮
- │ Data Dir: /srv/cleveragents │
- │ Config: /srv/cleveragents/config.toml │
- │ Logs: /srv/cleveragents/logs │
- │ Cache: /srv/cleveragents/cache │
- │ Database: /srv/cleveragents/agents.db │
- ╰───────────────────────────────────────╯
-
- ╭─ Runtime ──────────╮
- │ PID: 4127 │
- │ Uptime: 00:14:32 │
- │ Python: 3.13.1 │
- │ Host: devbox.local │
- │ Platform: linux │
- ╰────────────────────╯
-
- ╭─ Projects & Sessions ─╮
- │ Projects: 2 │
- │ Sessions: 1 active │
- │ Active Plans: 0 │
- │ Actors: 3 │
- ╰───────────────────────╯
-
- ✓ OK Environment loaded
-
-
-=== "Plain"
-
- ```
- $ agents --data-dir /srv/cleveragents --config-path /srv/cleveragents/config.toml info
-
- System Snapshot
- CleverAgents 1.0.0
- Mode: local
- Automation: review
- Status: ready
-
- Paths
- Data Dir: /srv/cleveragents
- Config: /srv/cleveragents/config.toml
- Logs: /srv/cleveragents/logs
- Cache: /srv/cleveragents/cache
- Database: /srv/cleveragents/agents.db
-
- Runtime
- PID: 4127
- Uptime: 00:14:32
- Python: 3.13.1
- Host: devbox.local
- Platform: linux
-
- Projects & Sessions
- Projects: 2
- Sessions: 1 active
- Active Plans: 0
- Actors: 3
-
- [OK] Environment loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "info",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "system_snapshot": {
- "name": "CleverAgents",
- "version": "1.0.0",
- "mode": "local",
- "automation": "review",
- "status": "ready"
- },
- "paths": {
- "data_dir": "/srv/cleveragents",
- "config": "/srv/cleveragents/config.toml",
- "logs": "/srv/cleveragents/logs",
- "cache": "/srv/cleveragents/cache",
- "database": "/srv/cleveragents/agents.db"
- },
- "runtime": {
- "pid": 4127,
- "uptime": "00:14:32",
- "python": "3.13.1",
- "host": "devbox.local",
- "platform": "linux"
- },
- "projects_and_sessions": {
- "projects": 2,
- "sessions": "1 active",
- "active_plans": 0,
- "actors": 3
- }
- },
- "timing": {
- "duration_ms": 12
- },
- "messages": [
- { "level": "ok", "text": "Environment loaded" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: info
- status: ok
- exit_code: 0
- data:
- system_snapshot:
- name: CleverAgents
- version: "1.0.0"
- mode: local
- automation: review
- status: ready
- paths:
- data_dir: /srv/cleveragents
- config: /srv/cleveragents/config.toml
- logs: /srv/cleveragents/logs
- cache: /srv/cleveragents/cache
- database: /srv/cleveragents/agents.db
- runtime:
- pid: 4127
- uptime: "00:14:32"
- python: "3.13.1"
- host: devbox.local
- platform: linux
- projects_and_sessions:
- projects: 2
- sessions: 1 active
- active_plans: 0
- actors: 3
- timing:
- duration_ms: 12
- messages:
- - level: ok
- text: Environment loaded
- ```
-
-#### agents version
-
-
-
-**Purpose**
-Print the current CLI version.
-
-**Arguments**
-
-None.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents version
-
- ╭─ CLI Version ────╮
- │ CleverAgents CLI │
- │ Version: 1.0.0 │
- │ Channel: stable │
- │ Python: 3.13 │
- ╰──────────────────╯
-
- ╭─ Build ────────────────╮
- │ Build Date: 2026-02-08 │
- │ Commit: a17c3f9 │
- │ Schema: v3 │
- │ Platform: linux-x86_64 │
- ╰────────────────────────╯
-
- ╭─ Dependencies ─────────────────╮
- │ LangGraph: 0.2.60 │
- │ LangChain: 0.3.18 │
- │ MCP SDK: 1.4.0 │
- │ Pydantic: 2.10.4 │
- ╰────────────────────────────────╯
-
- ✓ OK Version reported
-
-
-=== "Plain"
-
- ```
- $ agents version
-
- CLI Version
- CleverAgents CLI
- Version: 1.0.0
- Channel: stable
- Python: 3.13
-
- Build
- Build Date: 2026-02-08
- Commit: a17c3f9
- Schema: v3
- Platform: linux-x86_64
-
- Dependencies
- LangGraph: 0.2.60
- LangChain: 0.3.18
- MCP SDK: 1.4.0
- Pydantic: 2.10.4
-
- [OK] Version reported
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "version",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "cli": {
- "name": "CleverAgents CLI",
- "version": "1.0.0",
- "channel": "stable",
- "python": "3.13"
- },
- "build": {
- "build_date": "2026-02-08",
- "commit": "a17c3f9",
- "schema": "v3",
- "platform": "linux-x86_64"
- },
- "dependencies": {
- "langgraph": "0.2.60",
- "langchain": "0.3.18",
- "mcp_sdk": "1.4.0",
- "pydantic": "2.10.4"
- }
- },
- "timing": {
- "duration_ms": 8
- },
- "messages": [
- { "level": "ok", "text": "Version reported" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: version
- status: ok
- exit_code: 0
- data:
- cli:
- name: CleverAgents CLI
- version: "1.0.0"
- channel: stable
- python: "3.13"
- build:
- build_date: "2026-02-08"
- commit: a17c3f9
- schema: v3
- platform: linux-x86_64
- dependencies:
- langgraph: "0.2.60"
- langchain: "0.3.18"
- mcp_sdk: "1.4.0"
- pydantic: "2.10.4"
- timing:
- duration_ms: 8
- messages:
- - level: ok
- text: Version reported
- ```
-
-#### agents info
-
-
-
-**Purpose**
-Show configuration and runtime information useful for debugging or support.
-
-**Arguments**
-
-None.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents info
-
- ╭─ Environment ───────────────────────────────────────────────╮
- │ Data Dir: /home/alex/.cleveragents │
- │ Config: /home/alex/.cleveragents/config.toml │
- │ Database: sqlite:///home/alex/.cleveragents/cleveragents.db │
- │ Server Mode: disabled │
- │ Platform: Linux 6.8.0 (x86_64) │
- ╰─────────────────────────────────────────────────────────────╯
-
- ╭─ Runtime ─────────────────────────╮
- │ Automation: review │
- │ Providers: 3 configured │
- │ Sessions: 2 active │
- │ Active Plans: 1 │
- ╰───────────────────────────────────╯
-
- ╭─ Storage ─────╮
- │ Cache: 118 MB │
- │ Logs: 42 MB │
- │ Backups: 3 │
- │ DB Size: 8 MB │
- ╰───────────────╯
-
- ╭─ Indexing ─────────────╮
- │ Text Index: ready │
- │ Vector Index: ready │
- │ Graph Store: disabled │
- │ Indexed Files: 1,247 │
- ╰────────────────────────╯
-
- ✓ OK Environment details ready
-
-
-=== "Plain"
-
- ```
- $ agents info
-
- Environment
- Data Dir: /home/alex/.cleveragents
- Config: /home/alex/.cleveragents/config.toml
- Database: sqlite:///home/alex/.cleveragents/cleveragents.db
- Server Mode: disabled
- Platform: Linux 6.8.0 (x86_64)
-
- Runtime
- Automation: review
- Providers: 3 configured
- Sessions: 2 active
- Active Plans: 1
-
- Storage
- Cache: 118 MB
- Logs: 42 MB
- Backups: 3
- DB Size: 8 MB
-
- Indexing
- Text Index: ready
- Vector Index: ready
- Graph Store: disabled
- Indexed Files: 1,247
-
- [OK] Environment details ready
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "info",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "environment": {
- "data_dir": "/home/alex/.cleveragents",
- "config": "/home/alex/.cleveragents/config.toml",
- "database": "sqlite:///home/alex/.cleveragents/cleveragents.db",
- "server_mode": "disabled",
- "platform": "Linux 6.8.0 (x86_64)"
- },
- "runtime": {
- "automation": "review",
- "providers": 3,
- "sessions": "2 active",
- "active_plans": 1
- },
- "storage": {
- "cache_mb": 118,
- "logs_mb": 42,
- "backups": 3,
- "db_size_mb": 8
- },
- "indexing": {
- "text_index": "ready",
- "vector_index": "ready",
- "graph_store": "disabled",
- "indexed_files": 1247
- }
- },
- "timing": {
- "duration_ms": 18
- },
- "messages": [
- { "level": "ok", "text": "Environment details ready" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: info
- status: ok
- exit_code: 0
- data:
- environment:
- data_dir: /home/alex/.cleveragents
- config: /home/alex/.cleveragents/config.toml
- database: sqlite:///home/alex/.cleveragents/cleveragents.db
- server_mode: disabled
- platform: Linux 6.8.0 (x86_64)
- runtime:
- automation: review
- providers: 3
- sessions: 2 active
- active_plans: 1
- storage:
- cache_mb: 118
- logs_mb: 42
- backups: 3
- db_size_mb: 8
- indexing:
- text_index: ready
- vector_index: ready
- graph_store: disabled
- indexed_files: 1247
- timing:
- duration_ms: 18
- messages:
- - level: ok
- text: Environment details ready
- ```
-
-#### agents diagnostics
-
-
-
-**Purpose**
-Run health checks for configuration, providers, and filesystem permissions.
-
-**Arguments**
-
-None.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents diagnostics
-
- ╭─ Checks ──────────────────────────────────────────────────╮
- │ Check Status Details │
- │ ─────────────────────────── ────── ───────────────────── │
- │ Config file OK readable │
- │ Database OK writable │
- │ OpenAI key WARN missing │
- │ Anthropic key OK configured │
- │ Google key WARN missing │
- │ Gemini key WARN missing │
- │ Azure OpenAI key WARN missing │
- │ OpenRouter key WARN missing │
- │ Cohere key WARN missing │
- │ Groq key WARN missing │
- │ Together key WARN missing │
- │ Disk space OK 2.1 GB free │
- │ Text index OK tantivy 0.22 │
- │ Vector index OK faiss (CPU) │
- │ Graph store WARN not configured │
- │ File permissions OK data dir r/w │
- │ Git OK git 2.43.0 │
- ╰───────────────────────────────────────────────────────────╯
-
- ╭─ Summary ─────────╮
- │ Checks: 17 total │
- │ Warnings: 9 │
- │ Errors: 0 │
- │ Duration: 0.6s │
- ╰───────────────────╯
-
- ╭─ Recommendations ──────────────────────────────────────────────╮
- │ - Set OPENAI_API_KEY to enable OpenAI models │
- │ - Set GOOGLE_API_KEY to enable Google models │
- │ - Set GEMINI_API_KEY to enable Gemini models │
- │ - Set AZURE_OPENAI_API_KEY to enable Azure OpenAI models │
- │ - Set OPENROUTER_API_KEY to enable OpenRouter models │
- │ - Set COHERE_API_KEY to enable Cohere models │
- │ - Set GROQ_API_KEY to enable Groq models │
- │ - Set TOGETHER_API_KEY to enable Together models │
- │ - Configure a graph store backend for structural code queries │
- ╰────────────────────────────────────────────────────────────────╯
-
- ⚠ WARN 9 warnings require attention
-
-
-=== "Plain"
-
- ```
- $ agents diagnostics
-
- Checks
- Check Status Details
- ------------------------ ------ --------------
- Config file OK readable
- Database OK writable
- OpenAI key WARN missing
- Anthropic key OK configured
- Google key WARN missing
- Gemini key WARN missing
- Azure OpenAI key WARN missing
- OpenRouter key WARN missing
- Cohere key WARN missing
- Groq key WARN missing
- Together key WARN missing
- Disk space OK 2.1 GB free
- Text index OK tantivy 0.22
- Vector index OK faiss (CPU)
- Graph store WARN not configured
- File permissions OK data dir r/w
- Git OK git 2.43.0
-
- Summary
- Checks: 17 total
- Warnings: 9
- Errors: 0
- Duration: 0.6s
-
- Recommendations
- - Set OPENAI_API_KEY to enable OpenAI models
- - Set GOOGLE_API_KEY to enable Google models
- - Set GEMINI_API_KEY to enable Gemini models
- - Set AZURE_OPENAI_API_KEY to enable Azure OpenAI models
- - Set OPENROUTER_API_KEY to enable OpenRouter models
- - Set COHERE_API_KEY to enable Cohere models
- - Set GROQ_API_KEY to enable Groq models
- - Set TOGETHER_API_KEY to enable Together models
- - Configure a graph store backend for structural code queries
-
- [WARN] 9 warnings require attention
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "diagnostics",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "checks": [
- { "check": "Config file", "status": "ok", "details": "readable" },
- { "check": "Database", "status": "ok", "details": "writable" },
- { "check": "OpenAI key", "status": "warn", "details": "missing" },
- { "check": "Anthropic key", "status": "ok", "details": "configured" },
- { "check": "Google key", "status": "warn", "details": "missing" },
- { "check": "Gemini key", "status": "warn", "details": "missing" },
- { "check": "Azure OpenAI key", "status": "warn", "details": "missing" },
- { "check": "OpenRouter key", "status": "warn", "details": "missing" },
- { "check": "Cohere key", "status": "warn", "details": "missing" },
- { "check": "Groq key", "status": "warn", "details": "missing" },
- { "check": "Together key", "status": "warn", "details": "missing" },
- { "check": "Disk space", "status": "ok", "details": "2.1 GB free" },
- { "check": "Text index", "status": "ok", "details": "tantivy 0.22" },
- { "check": "Vector index", "status": "ok", "details": "faiss (CPU)" },
- { "check": "Graph store", "status": "warn", "details": "not configured" },
- { "check": "File permissions", "status": "ok", "details": "data dir r/w" },
- { "check": "Git", "status": "ok", "details": "git 2.43.0" }
- ],
- "summary": {
- "total": 17,
- "warnings": 9,
- "errors": 0,
- "duration_s": 0.6
- },
- "recommendations": [
- "Set OPENAI_API_KEY to enable OpenAI models",
- "Set GOOGLE_API_KEY to enable Google models",
- "Set GEMINI_API_KEY to enable Gemini models",
- "Set AZURE_OPENAI_API_KEY to enable Azure OpenAI models",
- "Set OPENROUTER_API_KEY to enable OpenRouter models",
- "Set COHERE_API_KEY to enable Cohere models",
- "Set GROQ_API_KEY to enable Groq models",
- "Set TOGETHER_API_KEY to enable Together models",
- "Configure a graph store backend for structural code queries"
- ]
- },
- "timing": {
- "duration_ms": 600
- },
- "messages": [
- { "level": "warn", "text": "9 warnings require attention" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: diagnostics
- status: ok
- exit_code: 0
- data:
- checks:
- - check: Config file
- status: ok
- details: readable
- - check: Database
- status: ok
- details: writable
- - check: OpenAI key
- status: warn
- details: missing
- - check: Anthropic key
- status: ok
- details: configured
- - check: Google key
- status: warn
- details: missing
- - check: Gemini key
- status: warn
- details: missing
- - check: Azure OpenAI key
- status: warn
- details: missing
- - check: OpenRouter key
- status: warn
- details: missing
- - check: Cohere key
- status: warn
- details: missing
- - check: Groq key
- status: warn
- details: missing
- - check: Together key
- status: warn
- details: missing
- - check: Disk space
- status: ok
- details: 2.1 GB free
- - check: Text index
- status: ok
- details: tantivy 0.22
- - check: Vector index
- status: ok
- details: faiss (CPU)
- - check: Graph store
- status: warn
- details: not configured
- - check: File permissions
- status: ok
- details: data dir r/w
- - check: Git
- status: ok
- details: git 2.43.0
- summary:
- total: 17
- warnings: 9
- errors: 0
- duration_s: 0.6
- recommendations:
- - Set OPENAI_API_KEY to enable OpenAI models
- - Set GOOGLE_API_KEY to enable Google models
- - Set GEMINI_API_KEY to enable Gemini models
- - Set AZURE_OPENAI_API_KEY to enable Azure OpenAI models
- - Set OPENROUTER_API_KEY to enable OpenRouter models
- - Set COHERE_API_KEY to enable Cohere models
- - Set GROQ_API_KEY to enable Groq models
- - Set TOGETHER_API_KEY to enable Together models
- - Configure a graph store backend for structural code queries
- timing:
- duration_ms: 600
- messages:
- - level: warn
- text: 9 warnings require attention
- ```
-
-When critical checks fail, diagnostics reports errors:
-
-=== "Rich"
-
-
- $ agents diagnostics
-
- ╭─ Checks ──────────────────────────────────────────────────╮
- │ Check Status Details │
- │ ─────────────────────────── ─────── ───────────────────────────── │
- │ Config file OK readable │
- │ Database ERROR locked by another process │
- │ OpenAI key ERROR invalid key format │
- │ Anthropic key OK configured │
- │ Google key WARN missing │
- │ Gemini key WARN missing │
- │ Azure OpenAI key WARN missing │
- │ OpenRouter key WARN missing │
- │ Cohere key WARN missing │
- │ Groq key WARN missing │
- │ Together key WARN missing │
- │ Disk space WARN 312 MB free (low) │
- │ Text index OK tantivy 0.22 │
- │ Vector index ERROR FAISS library not found │
- │ Graph store OK neo4j 5.15 │
- │ File permissions OK data dir r/w │
- │ Git OK git 2.43.0 │
- ╰───────────────────────────────────────────────────────────╯
-
- ╭─ Summary ─────────╮
- │ Checks: 17 total │
- │ Warnings: 8 │
- │ Errors: 3 │
- │ Duration: 1.2s │
- ╰───────────────────╯
-
- ╭─ Errors (must fix) ─────────────────────────────────────────────────╮
- │ 1. Database is locked by PID 12847 — stop the other process or │
- │ delete the lock file at ~/.cleveragents/agents.db-lock │
- │ 2. OpenAI key starts with "pk-" — expected "sk-" prefix │
- │ Run: agents config set provider.openai.api-key │
- │ 3. FAISS library not installed — vector search will not work │
- │ Run: pip install faiss-cpu │
- ╰─────────────────────────────────────────────────────────────────────╯
-
- ✗ ERROR 3 errors must be resolved before CleverAgents can operate
-
-
-=== "Plain"
-
- ```
- $ agents diagnostics
-
- Checks
- Check Status Details
- ------------------------ ------- --------------------------
- Config file OK readable
- Database ERROR locked by another process
- OpenAI key ERROR invalid key format
- Anthropic key OK configured
- Google key WARN missing
- Gemini key WARN missing
- Azure OpenAI key WARN missing
- OpenRouter key WARN missing
- Cohere key WARN missing
- Groq key WARN missing
- Together key WARN missing
- Disk space WARN 312 MB free (low)
- Text index OK tantivy 0.22
- Vector index ERROR FAISS library not found
- Graph store OK neo4j 5.15
- File permissions OK data dir r/w
- Git OK git 2.43.0
-
- Summary
- Checks: 17 total
- Warnings: 8
- Errors: 3
- Duration: 1.2s
-
- Errors (must fix)
- 1. Database is locked by PID 12847 -- stop the other process or
- delete the lock file at ~/.cleveragents/agents.db-lock
- 2. OpenAI key starts with "pk-" -- expected "sk-" prefix
- Run: agents config set provider.openai.api-key
- 3. FAISS library not installed -- vector search will not work
- Run: pip install faiss-cpu
-
- [ERROR] 3 errors must be resolved before CleverAgents can operate
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "diagnostics",
- "status": "error",
- "exit_code": 1,
- "data": {
- "checks": [
- { "check": "Config file", "status": "ok", "details": "readable" },
- { "check": "Database", "status": "error", "details": "locked by another process" },
- { "check": "OpenAI key", "status": "error", "details": "invalid key format" },
- { "check": "Anthropic key", "status": "ok", "details": "configured" },
- { "check": "Google key", "status": "warn", "details": "missing" },
- { "check": "Gemini key", "status": "warn", "details": "missing" },
- { "check": "Azure OpenAI key", "status": "warn", "details": "missing" },
- { "check": "OpenRouter key", "status": "warn", "details": "missing" },
- { "check": "Cohere key", "status": "warn", "details": "missing" },
- { "check": "Groq key", "status": "warn", "details": "missing" },
- { "check": "Together key", "status": "warn", "details": "missing" },
- { "check": "Disk space", "status": "warn", "details": "312 MB free (low)" },
- { "check": "Text index", "status": "ok", "details": "tantivy 0.22" },
- { "check": "Vector index", "status": "error", "details": "FAISS library not found" },
- { "check": "Graph store", "status": "ok", "details": "neo4j 5.15" },
- { "check": "File permissions", "status": "ok", "details": "data dir r/w" },
- { "check": "Git", "status": "ok", "details": "git 2.43.0" }
- ],
- "summary": {
- "total": 17,
- "warnings": 8,
- "errors": 3,
- "duration_s": 1.2
- },
- "errors": [
- {
- "index": 1,
- "message": "Database is locked by PID 12847 -- stop the other process or delete the lock file at ~/.cleveragents/agents.db-lock"
- },
- {
- "index": 2,
- "message": "OpenAI key starts with \"pk-\" -- expected \"sk-\" prefix",
- "fix": "agents config set provider.openai.api-key "
- },
- {
- "index": 3,
- "message": "FAISS library not installed -- vector search will not work",
- "fix": "pip install faiss-cpu"
- }
- ]
- },
- "timing": {
- "duration_ms": 1200
- },
- "messages": [
- { "level": "error", "text": "3 errors must be resolved before CleverAgents can operate" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: diagnostics
- status: error
- exit_code: 1
- data:
- checks:
- - check: Config file
- status: ok
- details: readable
- - check: Database
- status: error
- details: locked by another process
- - check: OpenAI key
- status: error
- details: invalid key format
- - check: Anthropic key
- status: ok
- details: configured
- - check: Google key
- status: warn
- details: missing
- - check: Gemini key
- status: warn
- details: missing
- - check: Azure OpenAI key
- status: warn
- details: missing
- - check: OpenRouter key
- status: warn
- details: missing
- - check: Cohere key
- status: warn
- details: missing
- - check: Groq key
- status: warn
- details: missing
- - check: Together key
- status: warn
- details: missing
- - check: Disk space
- status: warn
- details: 312 MB free (low)
- - check: Text index
- status: ok
- details: tantivy 0.22
- - check: Vector index
- status: error
- details: FAISS library not found
- - check: Graph store
- status: ok
- details: neo4j 5.15
- - check: File permissions
- status: ok
- details: data dir r/w
- - check: Git
- status: ok
- details: git 2.43.0
- summary:
- total: 17
- warnings: 8
- errors: 3
- duration_s: 1.2
- errors:
- - index: 1
- message: >-
- Database is locked by PID 12847 -- stop the other process or
- delete the lock file at ~/.cleveragents/agents.db-lock
- - index: 2
- message: >-
- OpenAI key starts with "pk-" -- expected "sk-" prefix
- fix: agents config set provider.openai.api-key
- - index: 3
- message: >-
- FAISS library not installed -- vector search will not work
- fix: pip install faiss-cpu
- timing:
- duration_ms: 1200
- messages:
- - level: error
- text: 3 errors must be resolved before CleverAgents can operate
- ```
-
-#### agents init
-
-
-
-!!! danger "Destructive Operation"
-
- This command ==wipes all existing data== and re-creates the global config and database. A backup is created automatically, but all sessions, plans, and registry entries will be removed.
-
-**Purpose**
-Initialize or reset the global CleverAgents environment. This wipes any existing data and re-creates the global config and database.
-
-**Arguments**
-
-- `--yes`: Skip the confirmation prompt and proceed with the wipe.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents init
-
- Warning: This will remove all data in /home/alex/.cleveragents
- Continue? [y/N]: y
-
- ╭─ Environment Reset ────────────────────────────────╮
- │ Config: /home/alex/.cleveragents/config.toml │
- │ Database: /home/alex/.cleveragents/cleveragents.db │
- │ Backup: /home/alex/.cleveragents.backup-2026-02-08 │
- │ Status: ready │
- ╰────────────────────────────────────────────────────╯
-
- ╭─ Defaults ──────────────────────────────────╮
- │ Automation Profile: supervised │
- │ Built-in Profiles: 8 loaded │
- ╰─────────────────────────────────────────────╯
-
- ╭─ Created ─────────────────╮
- │ Config: config.toml │
- │ Database: cleveragents.db │
- │ Logs: logs/ │
- │ Cache: cache/ │
- │ Backups: backups/ │
- ╰───────────────────────────╯
-
- ╭─ Schema ───────────────────────╮
- │ Version: v3 │
- │ Tables: 12 created │
- │ Migrations: up to date │
- ╰────────────────────────────────╯
-
- ✓ OK Environment initialized
-
-
-=== "Plain"
-
- ```
- $ agents init
-
- Warning: This will remove all data in /home/alex/.cleveragents
- Continue? [y/N]: y
-
- Environment Reset
- Config: /home/alex/.cleveragents/config.toml
- Database: /home/alex/.cleveragents/cleveragents.db
- Backup: /home/alex/.cleveragents.backup-2026-02-08
- Status: ready
-
- Defaults
- Automation Profile: supervised
- Built-in Profiles: 8 loaded
-
- Created
- Config: config.toml
- Database: cleveragents.db
- Logs: logs/
- Cache: cache/
- Backups: backups/
-
- Schema
- Version: v3
- Tables: 12 created
- Migrations: up to date
-
- [OK] Environment initialized
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "init",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "environment_reset": {
- "config": "/home/alex/.cleveragents/config.toml",
- "database": "/home/alex/.cleveragents/cleveragents.db",
- "backup": "/home/alex/.cleveragents.backup-2026-02-08",
- "status": "ready"
- },
- "defaults": {
- "automation_profile": "supervised",
- "builtin_profiles": 8
- },
- "created": {
- "config": "config.toml",
- "database": "cleveragents.db",
- "logs": "logs/",
- "cache": "cache/",
- "backups": "backups/"
- },
- "schema": {
- "version": "v3",
- "tables": 12,
- "migrations": "up to date"
- }
- },
- "timing": {
- "duration_ms": 340
- },
- "messages": [
- { "level": "ok", "text": "Environment initialized" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: init
- status: ok
- exit_code: 0
- data:
- environment_reset:
- config: /home/alex/.cleveragents/config.toml
- database: /home/alex/.cleveragents/cleveragents.db
- backup: /home/alex/.cleveragents.backup-2026-02-08
- status: ready
- defaults:
- automation_profile: supervised
- builtin_profiles: 8
- created:
- config: config.toml
- database: cleveragents.db
- logs: logs/
- cache: cache/
- backups: backups/
- schema:
- version: v3
- tables: 12
- migrations: up to date
- timing:
- duration_ms: 340
- messages:
- - level: ok
- text: Environment initialized
- ```
-
-Non-interactive initialization using `--yes` (useful in scripts and CI):
-
-=== "Rich"
-
-
- $ agents init --yes
-
- ╭─ Initialized ──────────────────────────────────────────╮
- │ Data Dir: /home/alex/.cleveragents (created) │
- │ Config: /home/alex/.cleveragents/config.toml │
- │ Database: initialized (schema v3) │
- │ Directories: logs, cache, sessions, contexts │
- ╰────────────────────────────────────────────────────────╯
-
- ✓ OK Initialized (non-interactive)
-
-
-=== "Plain"
-
- ```
- $ agents init --yes
-
- Initialized
- Data Dir: /home/alex/.cleveragents (created)
- Config: /home/alex/.cleveragents/config.toml
- Database: initialized (schema v3)
- Directories: logs, cache, sessions, contexts
-
- [OK] Initialized (non-interactive)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "init --yes",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "initialized": {
- "data_dir": "/home/alex/.cleveragents",
- "config": "/home/alex/.cleveragents/config.toml",
- "database": "initialized (schema v3)",
- "directories": ["logs", "cache", "sessions", "contexts"]
- }
- },
- "timing": {
- "duration_ms": 280
- },
- "messages": [
- { "level": "ok", "text": "Initialized (non-interactive)" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: init --yes
- status: ok
- exit_code: 0
- data:
- initialized:
- data_dir: /home/alex/.cleveragents
- config: /home/alex/.cleveragents/config.toml
- database: initialized (schema v3)
- directories:
- - logs
- - cache
- - sessions
- - contexts
- timing:
- duration_ms: 280
- messages:
- - level: ok
- text: Initialized (non-interactive)
- ```
-
-#### agents session
-
-**Purpose**
-Manage interactive sessions that hold a conversation history and orchestrator state.
-
-##### agents session create
-
-agents session create [--actor <ACTOR>]
-
-**Purpose**
-Create a new session for interactive work.
-
-**Arguments**
-
-- `--actor ACTOR`: Orchestrator actor to use for `session tell`.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents session create --actor local/orchestrator
-
- ╭─ Session ───────────────────────╮
- │ ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ Actor: local/orchestrator │
- │ Created: 2026-02-08 12:44 │
- │ Namespace: local │
- ╰─────────────────────────────────╯
-
- ╭─ Settings ─────────────╮
- │ Automation: review │
- │ Streaming: off │
- │ Context: default │
- │ Memory: enabled │
- │ Max History: 50 turns │
- ╰────────────────────────╯
-
- ╭─ Actor Details ───────────────────╮
- │ Provider: anthropic │
- │ Model: claude-3.5 │
- │ Temperature: 0.7 │
- │ Context Window: 200K tokens │
- ╰───────────────────────────────────╯
-
- ✓ OK Session created
-
-
-=== "Plain"
-
- ```
- $ agents session create --actor local/orchestrator
-
- Session
- ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- Actor: local/orchestrator
- Created: 2026-02-08 12:44
- Namespace: local
-
- Settings
- Automation: review
- Streaming: off
- Context: default
- Memory: enabled
- Max History: 50 turns
-
- Actor Details
- Provider: anthropic
- Model: claude-3.5
- Temperature: 0.7
- Context Window: 200K tokens
-
- [OK] Session created
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session create --actor local/orchestrator",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "session": {
- "id": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "actor": "local/orchestrator",
- "created": "2026-02-08T12:44:00Z",
- "namespace": "local"
- },
- "settings": {
- "automation": "review",
- "streaming": "off",
- "context": "default",
- "memory": "enabled",
- "max_history": 50
- },
- "actor_details": {
- "provider": "anthropic",
- "model": "claude-3.5",
- "temperature": 0.7,
- "context_window": "200K tokens"
- }
- },
- "timing": { "duration_ms": 120 },
- "messages": [{ "level": "ok", "text": "Session created" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session create --actor local/orchestrator
- status: ok
- exit_code: 0
- data:
- session:
- id: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- actor: local/orchestrator
- created: "2026-02-08T12:44:00Z"
- namespace: local
- settings:
- automation: review
- streaming: "off"
- context: default
- memory: enabled
- max_history: 50
- actor_details:
- provider: anthropic
- model: claude-3.5
- temperature: 0.7
- context_window: 200K tokens
- timing:
- duration_ms: 120
- messages:
- - level: ok
- text: Session created
- ```
-
-##### agents session list
-
-
-
-**Purpose**
-List sessions available on the local machine.
-
-**Arguments**
-
-None.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents --format table session list
-
- ╭─ Sessions ───────────────────────────────────────────────────────────────────╮
- │ ID Name Actor Messages Updated │
- │ ──────── ─────────────── ────────────────── ──────── ──────────────── │
- │ 01HXM2A6 weekly-planning local/orchestrator 6 2026-02-08 12:44 │
- │ 01HXM1F2 refactor-sprint local/orchestrator 14 2026-02-07 18:11 │
- ╰──────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ────────────────────╮
- │ Total: 2 │
- │ Most Recent: weekly-planning │
- │ Oldest: refactor-sprint │
- │ Total Messages: 20 │
- │ Storage: 42 KB │
- ╰──────────────────────────────╯
-
- ✓ OK 2 sessions listed
-
-
-=== "Plain"
-
- ```
- $ agents --format table session list
-
- Sessions
- ID Name Actor Messages Updated
- -------- --------------- ------------------ -------- ----------------
- 01HXM2A6 weekly-planning local/orchestrator 6 2026-02-08 12:44
- 01HXM1F2 refactor-sprint local/orchestrator 14 2026-02-07 18:11
-
- Summary
- Total: 2
- Most Recent: weekly-planning
- Oldest: refactor-sprint
- Total Messages: 20
- Storage: 42 KB
-
- [OK] 2 sessions listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents --format table session list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "sessions": [
- {
- "id": "01HXM2A6",
- "name": "weekly-planning",
- "actor": "local/orchestrator",
- "messages": 6,
- "updated": "2026-02-08T12:44:00Z"
- },
- {
- "id": "01HXM1F2",
- "name": "refactor-sprint",
- "actor": "local/orchestrator",
- "messages": 14,
- "updated": "2026-02-07T18:11:00Z"
- }
- ],
- "summary": {
- "total": 2,
- "most_recent": "weekly-planning",
- "oldest": "refactor-sprint",
- "total_messages": 20,
- "storage": "42 KB"
- }
- },
- "timing": { "duration_ms": 85 },
- "messages": [{ "level": "ok", "text": "2 sessions listed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents --format table session list
- status: ok
- exit_code: 0
- data:
- sessions:
- - id: 01HXM2A6
- name: weekly-planning
- actor: local/orchestrator
- messages: 6
- updated: "2026-02-08T12:44:00Z"
- - id: 01HXM1F2
- name: refactor-sprint
- actor: local/orchestrator
- messages: 14
- updated: "2026-02-07T18:11:00Z"
- summary:
- total: 2
- most_recent: weekly-planning
- oldest: refactor-sprint
- total_messages: 20
- storage: 42 KB
- timing:
- duration_ms: 85
- messages:
- - level: ok
- text: 2 sessions listed
- ```
-
-##### agents session show
-
-agents session show <SESSION_ID>
-
-**Purpose**
-Show details and recent messages for a session.
-
-**Arguments**
-
-- ``: The session identifier.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents session show 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- ╭─ Session Summary ───────────────╮
- │ ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ Actor: local/orchestrator │
- │ Messages: 6 │
- │ Created: 2026-02-08 12:30 │
- │ Updated: 2026-02-08 12:44 │
- │ Automation: review │
- ╰─────────────────────────────────╯
-
- ╭─ Recent Messages ──────────────────────────────────╮
- │ user Create an action to refresh dependency locks │
- │ assistant Plan created, running commands... │
- │ assistant Completed 2 commands │
- ╰────────────────────────────────────────────────────╯
-
- ╭─ Linked Plans ────────────────────────────────╮
- │ Plan ID Phase State │
- │ ────────────────────────── ────── ──────── │
- │ 01HXM8C2ZK4Q7C2B3F2R4VYV6J execute complete │
- ╰───────────────────────────────────────────────╯
-
- ╭─ Token Usage ──────────────╮
- │ Input Tokens: 3,420 │
- │ Output Tokens: 1,185 │
- │ Estimated Cost: $0.0184 │
- ╰────────────────────────────╯
-
- ✓ OK Session details loaded
-
-
-=== "Plain"
-
- ```
- $ agents session show 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- Session Summary
- ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- Actor: local/orchestrator
- Messages: 6
- Created: 2026-02-08 12:30
- Updated: 2026-02-08 12:44
- Automation: review
-
- Recent Messages
- user Create an action to refresh dependency locks
- assistant Plan created, running commands...
- assistant Completed 2 commands
-
- Linked Plans
- Plan ID Phase State
- -------------------------- ------- --------
- 01HXM8C2ZK4Q7C2B3F2R4VYV6J execute complete
-
- Token Usage
- Input Tokens: 3,420
- Output Tokens: 1,185
- Estimated Cost: $0.0184
-
- [OK] Session details loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session show 01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "session_summary": {
- "id": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "actor": "local/orchestrator",
- "messages": 6,
- "created": "2026-02-08T12:30:00Z",
- "updated": "2026-02-08T12:44:00Z",
- "automation": "review"
- },
- "recent_messages": [
- { "role": "user", "text": "Create an action to refresh dependency locks" },
- { "role": "assistant", "text": "Plan created, running commands..." },
- { "role": "assistant", "text": "Completed 2 commands" }
- ],
- "linked_plans": [
- {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "state": "complete"
- }
- ],
- "token_usage": {
- "input_tokens": 3420,
- "output_tokens": 1185,
- "estimated_cost": "$0.0184"
- }
- },
- "timing": { "duration_ms": 95 },
- "messages": [{ "level": "ok", "text": "Session details loaded" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session show 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- status: ok
- exit_code: 0
- data:
- session_summary:
- id: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- actor: local/orchestrator
- messages: 6
- created: "2026-02-08T12:30:00Z"
- updated: "2026-02-08T12:44:00Z"
- automation: review
- recent_messages:
- - role: user
- text: Create an action to refresh dependency locks
- - role: assistant
- text: Plan created, running commands...
- - role: assistant
- text: Completed 2 commands
- linked_plans:
- - plan_id: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- phase: execute
- state: complete
- token_usage:
- input_tokens: 3420
- output_tokens: 1185
- estimated_cost: "$0.0184"
- timing:
- duration_ms: 95
- messages:
- - level: ok
- text: Session details loaded
- ```
-
-##### agents session delete
-
-agents session delete [--yes|-y] <SESSION_ID>
-
-!!! danger "Irreversible Deletion"
- This command ==permanently deletes== a session and its stored conversation history. Messages and context cannot be recovered after deletion. Use `--yes` to skip the confirmation prompt.
-
-**Arguments**
-
-- ``: The session identifier.
-- `--yes, -y`: Skip the confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents session delete 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- Delete session 01HXM2A6K1P2E9Q9D4GQ7J4S7Z? [y/N]: y
-
- ╭─ Deletion Summary ──────────────────╮
- │ Session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ Messages: 6 removed │
- │ Storage: 18 KB freed │
- │ Plans Orphaned: 0 │
- ╰─────────────────────────────────────╯
-
- ╭─ Cleanup ───────────╮
- │ Backups: none │
- │ Logs: preserved │
- │ Context: cleared │
- │ Checkpoints: none │
- ╰─────────────────────╯
-
- ✓ OK Session deleted
-
-
-=== "Plain"
-
- ```
- $ agents session delete 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- Delete session 01HXM2A6K1P2E9Q9D4GQ7J4S7Z? [y/N]: y
-
- Deletion Summary
- Session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- Messages: 6 removed
- Storage: 18 KB freed
- Plans Orphaned: 0
-
- Cleanup
- Backups: none
- Logs: preserved
- Context: cleared
- Checkpoints: none
-
- [OK] Session deleted
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session delete 01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "deletion_summary": {
- "session": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "id": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "messages_removed": 6,
- "storage_freed": "18 KB",
- "plans_orphaned": 0
- },
- "cleanup": {
- "backups": "none",
- "logs": "preserved",
- "context": "cleared",
- "checkpoints": "none"
- }
- },
- "timing": { "duration_ms": 62 },
- "messages": [{ "level": "ok", "text": "Session deleted" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session delete 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- status: ok
- exit_code: 0
- data:
- deletion_summary:
- session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- id: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- messages_removed: 6
- storage_freed: 18 KB
- plans_orphaned: 0
- cleanup:
- backups: none
- logs: preserved
- context: cleared
- checkpoints: none
- timing:
- duration_ms: 62
- messages:
- - level: ok
- text: Session deleted
- ```
-
-##### agents session export
-
-agents session export [(--output|-o) <FILE>] <SESSION_ID>
-
-**Purpose**
-Export a session as a portable JSON file.
-
-**Arguments**
-
-- ``: The session identifier.
-- `--output/-o FILE`: Output file path (optional).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents session export --output /tmp/weekly-planning.json 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- ╭─ Session Export ────────────────────╮
- │ Session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ Output: /tmp/weekly-planning.json │
- │ Messages: 6 │
- │ Size: 24 KB │
- │ Format: JSON │
- ╰─────────────────────────────────────╯
-
- ╭─ Contents ─────────────────╮
- │ Messages: 6 │
- │ Plan References: 1 │
- │ Metadata Keys: 2 │
- │ Actor Config: included │
- │ Schema Version: v3 │
- ╰────────────────────────────╯
-
- ╭─ Integrity ──────────────────╮
- │ Checksum: sha256:7a9b...42c1 │
- │ Encrypted: no │
- ╰──────────────────────────────╯
-
- ✓ OK Export completed
-
-
-=== "Plain"
-
- ```
- $ agents session export --output /tmp/weekly-planning.json 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- Session Export
- Session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- Output: /tmp/weekly-planning.json
- Messages: 6
- Size: 24 KB
- Format: JSON
-
- Contents
- Messages: 6
- Plan References: 1
- Metadata Keys: 2
- Actor Config: included
- Schema Version: v3
-
- Integrity
- Checksum: sha256:7a9b...42c1
- Encrypted: no
-
- [OK] Export completed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session export --output /tmp/weekly-planning.json 01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "session_export": {
- "session": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "output": "/tmp/weekly-planning.json",
- "messages": 6,
- "size": "24 KB",
- "format": "JSON"
- },
- "contents": {
- "messages": 6,
- "plan_references": 1,
- "metadata_keys": 2,
- "actor_config": "included",
- "schema_version": "v3"
- },
- "integrity": {
- "checksum": "sha256:7a9b...42c1",
- "encrypted": false
- }
- },
- "timing": { "duration_ms": 140 },
- "messages": [{ "level": "ok", "text": "Export completed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session export --output /tmp/weekly-planning.json 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- status: ok
- exit_code: 0
- data:
- session_export:
- session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- output: /tmp/weekly-planning.json
- messages: 6
- size: 24 KB
- format: JSON
- contents:
- messages: 6
- plan_references: 1
- metadata_keys: 2
- actor_config: included
- schema_version: v3
- integrity:
- checksum: "sha256:7a9b...42c1"
- encrypted: false
- timing:
- duration_ms: 140
- messages:
- - level: ok
- text: Export completed
- ```
-
-##### agents session import
-
-agents session import (--input|-i) <FILE>
-
-**Purpose**
-Import a session JSON file.
-
-**Arguments**
-
-- `--input/-i FILE`: Input JSON file.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents session import --input /tmp/weekly-planning.json
-
- ╭─ Session Import ────────────────────────╮
- │ Input: /tmp/weekly-planning.json │
- │ Session ID: 01HXM3D3B2W4CQYQ3P4ZB8A5T1 │
- │ Messages: 6 │
- │ Schema: v3 │
- ╰─────────────────────────────────────────╯
-
- ╭─ Validation ────────────╮
- │ Checksum: verified │
- │ Schema: compatible │
- │ Actor Ref: resolved │
- ╰─────────────────────────╯
-
- ╭─ Merge ──────────────╮
- │ Existing: none │
- │ Strategy: create new │
- ╰──────────────────────╯
-
- ✓ OK Import completed
-
-
-=== "Plain"
-
- ```
- $ agents session import --input /tmp/weekly-planning.json
-
- Session Import
- Input: /tmp/weekly-planning.json
- Session ID: 01HXM3D3B2W4CQYQ3P4ZB8A5T1
- Messages: 6
- Schema: v3
-
- Validation
- Checksum: verified
- Schema: compatible
- Actor Ref: resolved
-
- Merge
- Existing: none
- Strategy: create new
-
- [OK] Import completed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session import --input /tmp/weekly-planning.json",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "session_import": {
- "input": "/tmp/weekly-planning.json",
- "session_id": "01HXM3D3B2W4CQYQ3P4ZB8A5T1",
- "messages": 6,
- "schema": "v3"
- },
- "validation": {
- "checksum": "verified",
- "schema": "compatible",
- "actor_ref": "resolved"
- },
- "merge": {
- "existing": "none",
- "strategy": "create new"
- }
- },
- "timing": { "duration_ms": 210 },
- "messages": [{ "level": "ok", "text": "Import completed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session import --input /tmp/weekly-planning.json
- status: ok
- exit_code: 0
- data:
- session_import:
- input: /tmp/weekly-planning.json
- session_id: 01HXM3D3B2W4CQYQ3P4ZB8A5T1
- messages: 6
- schema: v3
- validation:
- checksum: verified
- schema: compatible
- actor_ref: resolved
- merge:
- existing: none
- strategy: create new
- timing:
- duration_ms: 210
- messages:
- - level: ok
- text: Import completed
- ```
-
-##### agents session tell
-
-agents session tell --session <SESSION_ID> [--actor <ACTOR>] [--stream] <PROMPT>
-
-!!! tip "Primary User Interface"
-
- This is the main natural-language interface for interacting with CleverAgents. The orchestrator interprets your request and issues the necessary CleverAgents commands under the hood — creating actions, plans, or project changes as needed. Use `--stream` to see responses in real time.
-
-**Purpose**
-Send a natural-language request to the orchestrator. The orchestrator can create actions, plans, or project changes by issuing the necessary CleverAgents commands under the hood.
-
-**Arguments**
-
-- ``: Instruction text (positional argument).
-- `--session SESSION_ID`: Session to use (required).
-- `--actor ACTOR`: Override the session actor for this request.
-- `--stream`: Stream progress as the orchestrator works.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents session tell "Create an action to refresh dependency locks and add it to the platform project" \
- --session 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- ╭─ Plan Request ──────────────────────────────────────────╮
- │ Actor: local/orchestrator │
- │ Session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ Automation: review │
- │ Prompt: Create an action to refresh dependency locks... │
- ╰─────────────────────────────────────────────────────────╯
-
- ╭─ Commands Executed ─────────────────────────────────────────────────────────────────────────────────────────╮
- │ - agents action create --config ./actions/refresh-locks.yaml │
- │ - agents resource add git-checkout local/platform-repo --path /repos/platform │
- │ - agents project link-resource local/platform local/platform-repo │
- ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Result ──────────────────────────╮
- │ Action: local/refresh-locks │
- │ Project: local/platform │
- │ Resource: local/platform-repo │
- ╰───────────────────────────────────╯
-
- ╭─ Usage ─────────────────────╮
- │ Input Tokens: 1,842 │
- │ Output Tokens: 624 │
- │ Cost: $0.0094 │
- │ Duration: 3.2s │
- │ Tool Calls: 3 │
- ╰─────────────────────────────╯
-
- ✓ OK Orchestrator completed 3 commands
-
-
-=== "Plain"
-
- ```
- $ agents session tell "Create an action to refresh dependency locks and add it to the platform project" \
- --session 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
-
- Plan Request
- Actor: local/orchestrator
- Session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- Automation: review
- Prompt: Create an action to refresh dependency locks...
-
- Commands Executed
- - agents action create --config ./actions/refresh-locks.yaml
- - agents resource add git-checkout local/platform-repo --path /repos/platform
- - agents project link-resource local/platform local/platform-repo
-
- Result
- Action: local/refresh-locks
- Project: local/platform
- Resource: local/platform-repo
-
- Usage
- Input Tokens: 1,842
- Output Tokens: 624
- Cost: $0.0094
- Duration: 3.2s
- Tool Calls: 3
-
- [OK] Orchestrator completed 3 commands
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session tell \"Create an action to refresh dependency locks and add it to the platform project\" --session 01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_request": {
- "actor": "local/orchestrator",
- "session": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "automation": "review",
- "prompt": "Create an action to refresh dependency locks..."
- },
- "commands_executed": [
- "agents action create --config ./actions/refresh-locks.yaml",
- "agents resource add git-checkout local/platform-repo --path /repos/platform",
- "agents project link-resource local/platform local/platform-repo"
- ],
- "result": {
- "action": "local/refresh-locks",
- "project": "local/platform",
- "resource": "local/platform-repo"
- },
- "usage": {
- "input_tokens": 1842,
- "output_tokens": 624,
- "cost": "$0.0094",
- "duration_s": 3.2,
- "tool_calls": 3
- }
- },
- "timing": { "duration_ms": 3200 },
- "messages": [{ "level": "ok", "text": "Orchestrator completed 3 commands" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session tell "Create an action to refresh dependency locks and add it to the platform project" --session 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- status: ok
- exit_code: 0
- data:
- plan_request:
- actor: local/orchestrator
- session: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- automation: review
- prompt: Create an action to refresh dependency locks...
- commands_executed:
- - agents action create --config ./actions/refresh-locks.yaml
- - agents resource add git-checkout local/platform-repo --path /repos/platform
- - agents project link-resource local/platform local/platform-repo
- result:
- action: local/refresh-locks
- project: local/platform
- resource: local/platform-repo
- usage:
- input_tokens: 1842
- output_tokens: 624
- cost: "$0.0094"
- duration_s: 3.2
- tool_calls: 3
- timing:
- duration_ms: 3200
- messages:
- - level: ok
- text: Orchestrator completed 3 commands
- ```
-
-Using `--stream` to see the response as it is generated (token by token):
-
-=== "Rich"
-
-
- $ agents session tell --session 01HXM2A6K1 --stream "What files were changed in the last plan?"
-
- ╭─ Session ──────────────────────────╮
- │ ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z │
- │ Actor: local/orchestrator │
- │ Mode: streaming │
- ╰────────────────────────────────────╯
-
- ▍ The last plan (01HXM8C2ZK) modified 6 files in the auth module:
-
- 1. `src/auth/session.py` — refactored session validation
- 2. `src/auth/tokens.py` — updated token expiry to 7200s
- 3. `src/auth/__init__.py` — updated exports
- 4. `tests/test_auth.py` — added 12 new test cases
- 5. `tests/test_session.py` — updated session fixtures
- 6. `docs/auth.md` — updated API documentation
-
- All changes passed validation (24/24 tests, lint clean).
-
- ╭─ Usage ──────────────────╮
- │ Tokens: 1,240 (stream) │
- │ Duration: 3.1s │
- │ Tool Calls: 2 │
- ╰──────────────────────────╯
-
- ✓ OK Stream complete
-
-
-=== "Plain"
-
- ```
- $ agents session tell --session 01HXM2A6K1 --stream "What files were changed in the last plan?"
-
- Session
- ID: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- Actor: local/orchestrator
- Mode: streaming
-
- The last plan (01HXM8C2ZK) modified 6 files in the auth module:
-
- 1. src/auth/session.py -- refactored session validation
- 2. src/auth/tokens.py -- updated token expiry to 7200s
- 3. src/auth/__init__.py -- updated exports
- 4. tests/test_auth.py -- added 12 new test cases
- 5. tests/test_session.py -- updated session fixtures
- 6. docs/auth.md -- updated API documentation
-
- All changes passed validation (24/24 tests, lint clean).
-
- Usage
- Tokens: 1,240 (stream)
- Duration: 3.1s
- Tool Calls: 2
-
- [OK] Stream complete
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents session tell --session 01HXM2A6K1 --stream \"What files were changed in the last plan?\"",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "session": {
- "id": "01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
- "actor": "local/orchestrator",
- "mode": "streaming"
- },
- "response": "The last plan (01HXM8C2ZK) modified 6 files in the auth module:\n\n1. src/auth/session.py \u2014 refactored session validation\n2. src/auth/tokens.py \u2014 updated token expiry to 7200s\n3. src/auth/__init__.py \u2014 updated exports\n4. tests/test_auth.py \u2014 added 12 new test cases\n5. tests/test_session.py \u2014 updated session fixtures\n6. docs/auth.md \u2014 updated API documentation\n\nAll changes passed validation (24/24 tests, lint clean).",
- "files_changed": [
- "src/auth/session.py",
- "src/auth/tokens.py",
- "src/auth/__init__.py",
- "tests/test_auth.py",
- "tests/test_session.py",
- "docs/auth.md"
- ],
- "usage": {
- "tokens": 1240,
- "duration_s": 3.1,
- "tool_calls": 2
- }
- },
- "timing": { "duration_ms": 3100 },
- "messages": [{ "level": "ok", "text": "Stream complete" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents session tell --session 01HXM2A6K1 --stream "What files were changed in the last plan?"
- status: ok
- exit_code: 0
- data:
- session:
- id: 01HXM2A6K1P2E9Q9D4GQ7J4S7Z
- actor: local/orchestrator
- mode: streaming
- response: >
- The last plan (01HXM8C2ZK) modified 6 files in the auth module:
- 1. src/auth/session.py -- refactored session validation
- 2. src/auth/tokens.py -- updated token expiry to 7200s
- 3. src/auth/__init__.py -- updated exports
- 4. tests/test_auth.py -- added 12 new test cases
- 5. tests/test_session.py -- updated session fixtures
- 6. docs/auth.md -- updated API documentation
- All changes passed validation (24/24 tests, lint clean).
- files_changed:
- - src/auth/session.py
- - src/auth/tokens.py
- - src/auth/__init__.py
- - tests/test_auth.py
- - tests/test_session.py
- - docs/auth.md
- usage:
- tokens: 1240
- duration_s: 3.1
- tool_calls: 2
- timing:
- duration_ms: 3100
- messages:
- - level: ok
- text: Stream complete
- ```
-
-#### agents project
-
-**Purpose**
-Manage projects and their resources.
-
-##### agents project create
-
-agents project create [(--description|-d) <DESC>] [--resource <RESOURCE>]...
- [--invariant <INVARIANT>]... [--invariant-actor <ACTOR>] <NAME>
-
-**Purpose**
-Create a new project record.
-
-**Arguments**
-
-- ``: Namespaced project name (positional argument).
-- `--description/-d TEXT`: Optional description.
-- `--resource RESOURCE`: Resource name or ULID to link to the project at creation time (repeatable).
-- `--invariant TEXT`: Invariant to attach to this project (repeatable). These invariants apply to all plans targeting this project.
-- `--invariant-actor ACTOR`: Invariant Reconciliation Actor for this project. Used to reconcile project-level invariants against global invariants for all plans targeting this project (unless the plan overrides it).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project create --description "Backend API" local/api-service
-
- ╭─ Project ──────────────────────╮
- │ Name: local/api-service │
- │ Description: Backend API │
- │ Type: local │
- │ Created: 2026-02-08 12:46 │
- ╰────────────────────────────────╯
-
- ╭─ Paths ────────────────────────────────────╮
- │ Root: /repos/api-service │
- │ Data Dir: /repos/api-service/.cleveragents │
- ╰────────────────────────────────────────────╯
-
- ╭─ Defaults ──────────────────────────────╮
- │ Sandbox: git_worktree │
- │ Validations: 0 │
- │ Context Filters: none │
- │ Automation Profile: (inherits global) │
- ╰─────────────────────────────────────────╯
-
- ╭─ Resources ──────╮
- │ Total: 0 │
- │ Indexed: 0 │
- │ Sandboxable: 0 │
- ╰──────────────────╯
-
- ✓ OK Project created
-
-
-=== "Plain"
-
- ```
- $ agents project create --description "Backend API" local/api-service
-
- Project
- Name: local/api-service
- Description: Backend API
- Type: local
- Created: 2026-02-08 12:46
-
- Paths
- Root: /repos/api-service
- Data Dir: /repos/api-service/.cleveragents
-
- Defaults
- Sandbox: git_worktree
- Validations: 0
- Context Filters: none
- Automation Profile: (inherits global)
-
- Resources
- Total: 0
- Indexed: 0
- Sandboxable: 0
-
- [OK] Project created
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project create --description \"Backend API\" local/api-service",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "project": {
- "name": "local/api-service",
- "description": "Backend API",
- "type": "local",
- "created": "2026-02-08T12:46:00Z"
- },
- "paths": {
- "root": "/repos/api-service",
- "data_dir": "/repos/api-service/.cleveragents"
- },
- "defaults": {
- "sandbox": "git_worktree",
- "validations": 0,
- "context_filters": null,
- "automation_profile": null
- },
- "resources": {
- "total": 0,
- "indexed": 0,
- "sandboxable": 0
- }
- },
- "timing": { "duration_ms": 85 },
- "messages": [{ "level": "ok", "text": "Project created" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project create --description "Backend API" local/api-service
- status: ok
- exit_code: 0
- data:
- project:
- name: local/api-service
- description: Backend API
- type: local
- created: "2026-02-08T12:46:00Z"
- paths:
- root: /repos/api-service
- data_dir: /repos/api-service/.cleveragents
- defaults:
- sandbox: git_worktree
- validations: 0
- context_filters: null
- automation_profile: null
- resources:
- total: 0
- indexed: 0
- sandboxable: 0
- timing:
- duration_ms: 85
- messages:
- - level: ok
- text: Project created
- ```
-
-Creating a project with resources and invariants in one command:
-
-=== "Rich"
-
-
- $ agents project create -d "Frontend web application" \
- --resource local/web-repo --resource local/web-db \
- --invariant "All components must have unit tests" \
- --invariant "CSS must pass stylelint checks" \
- --invariant-actor local/invariant-resolver \
- local/web-app
-
- ╭─ Project Created ─────────────────────╮
- │ Name: local/web-app │
- │ Description: Frontend web app │
- │ Remote: no │
- ╰───────────────────────────────────────╯
-
- ╭─ Linked Resources ───────────────────────────────────────╮
- │ Name Type Read-Only │
- │ ───────────────── ────────────── ───────── │
- │ local/web-repo git-checkout no │
- │ local/web-db local/database no │
- ╰──────────────────────────────────────────────────────────╯
-
- ╭─ Invariants ────────────────────────────────────╮
- │ 1. All components must have unit tests │
- │ 2. CSS must pass stylelint checks │
- │ Reconciliation Actor: local/invariant-resolver │
- ╰─────────────────────────────────────────────────╯
-
- ✓ OK Project created
-
-
-=== "Plain"
-
- ```
- $ agents project create -d "Frontend web application" \
- --resource local/web-repo --resource local/web-db \
- --invariant "All components must have unit tests" \
- --invariant "CSS must pass stylelint checks" \
- --invariant-actor local/invariant-resolver \
- local/web-app
-
- Project Created
- Name: local/web-app
- Description: Frontend web app
- Remote: no
-
- Linked Resources
- Name Type Read-Only
- ----------------- -------------- ---------
- local/web-repo git-checkout no
- local/web-db local/database no
-
- Invariants
- 1. All components must have unit tests
- 2. CSS must pass stylelint checks
- Reconciliation Actor: local/invariant-resolver
-
- [OK] Project created
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project create -d \"Frontend web application\" --resource local/web-repo --resource local/web-db --invariant \"All components must have unit tests\" --invariant \"CSS must pass stylelint checks\" --invariant-actor local/invariant-resolver local/web-app",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "project": {
- "name": "local/web-app",
- "description": "Frontend web app",
- "remote": false
- },
- "linked_resources": [
- { "name": "local/web-repo", "type": "git-checkout", "read_only": false },
- { "name": "local/web-db", "type": "local/database", "read_only": false }
- ],
- "invariants": {
- "items": [
- "All components must have unit tests",
- "CSS must pass stylelint checks"
- ],
- "reconciliation_actor": "local/invariant-resolver"
- }
- },
- "timing": { "duration_ms": 120 },
- "messages": [{ "level": "ok", "text": "Project created" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project create -d "Frontend web application" --resource local/web-repo --resource local/web-db --invariant "All components must have unit tests" --invariant "CSS must pass stylelint checks" --invariant-actor local/invariant-resolver local/web-app
- status: ok
- exit_code: 0
- data:
- project:
- name: local/web-app
- description: Frontend web app
- remote: false
- linked_resources:
- - name: local/web-repo
- type: git-checkout
- read_only: false
- - name: local/web-db
- type: local/database
- read_only: false
- invariants:
- items:
- - All components must have unit tests
- - CSS must pass stylelint checks
- reconciliation_actor: local/invariant-resolver
- timing:
- duration_ms: 120
- messages:
- - level: ok
- text: Project created
- ```
-
-##### agents project link-resource
-
-agents project link-resource [--read-only] <PROJECT> <RESOURCE>
-
-**Purpose**
-Link a registered resource to a project. The resource must already be registered via `agents resource add`. A resource can be linked to multiple projects. Optionally, the resource can be marked as read-only within this project context, and given an alias for convenience.
-
-**Arguments**
-
-- ``: Project name (positional argument).
-- ``: Resource name or ULID (positional argument).
-- `--read-only`: Mark the resource as read-only within this project (even if the resource itself is writable).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource add git-checkout local/api-repo --path /repos/api --branch main
- $ agents project link-resource local/api-service local/api-repo
-
- ╭─ Resource Linked ───────────────────────╮
- │ Project: local/api-service │
- │ Resource: local/api-repo │
- │ Type: git-checkout │
- │ Read-Only: no │
- ╰─────────────────────────────────────────╯
-
- ╭─ Access ─────────────────╮
- │ Read: allowed │
- │ Write: allowed │
- │ Apply: requires approval │
- ╰──────────────────────────╯
-
- ╭─ Indexing ─────────────────────╮
- │ Status: indexing... │
- │ Files Found: 347 │
- │ Language: Python (primary) │
- │ Estimated Time: ~20 seconds │
- ╰────────────────────────────────╯
-
- ✓ OK Resource linked to project
-
-
-=== "Plain"
-
- ```
- $ agents resource add git-checkout local/api-repo --path /repos/api --branch main
- $ agents project link-resource local/api-service local/api-repo
-
- Resource Linked
- Project: local/api-service
- Resource: local/api-repo
- Type: git-checkout
- Read-Only: no
-
- Access
- Read: allowed
- Write: allowed
- Apply: requires approval
-
- Indexing
- Status: indexing...
- Files Found: 347
- Language: Python (primary)
- Estimated Time: ~20 seconds
-
- [OK] Resource linked to project
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project link-resource local/api-service local/api-repo",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resource_linked": {
- "project": "local/api-service",
- "resource": "local/api-repo",
- "type": "git-checkout",
- "read_only": false
- },
- "access": {
- "read": "allowed",
- "write": "allowed",
- "apply": "requires approval"
- },
- "indexing": {
- "status": "indexing",
- "files_found": 347,
- "language": "Python (primary)",
- "estimated_time_seconds": 20
- }
- },
- "timing": { "duration_ms": 92 },
- "messages": [{ "level": "ok", "text": "Resource linked to project" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project link-resource local/api-service local/api-repo
- status: ok
- exit_code: 0
- data:
- resource_linked:
- project: local/api-service
- resource: local/api-repo
- type: git-checkout
- read_only: false
- access:
- read: allowed
- write: allowed
- apply: requires approval
- indexing:
- status: indexing
- files_found: 347
- language: Python (primary)
- estimated_time_seconds: 20
- timing:
- duration_ms: 92
- messages:
- - level: ok
- text: Resource linked to project
- ```
-
-##### agents project unlink-resource
-
-agents project unlink-resource [--yes|-y] <PROJECT> <RESOURCE_NAME>
-
-**Purpose**
-Unlink a resource from a project. The resource itself remains registered in the Resource Registry and can still be linked to other projects. Active plans using this resource in this project context will be warned.
-
-**Arguments**
-
-- ``: Project name (positional argument).
-- ``: Resource name (positional argument). Only user-added (named) resources can be unlinked.
-- `--yes, -y`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project unlink-resource local/api-service local/api-repo
-
- Unlink local/api-repo from local/api-service? [y/N]: y
-
- ╭─ Resource Unlinked ─────────────────────────────────╮
- │ Project: local/api-service │
- │ Resource: local/api-repo │
- │ Type: git-checkout │
- ╰─────────────────────────────────────────────────────╯
-
- ╭─ Index Cleanup ──────────╮
- │ Text Index: 347 removed │
- │ Vectors: 892 removed │
- │ Graph Triples: cleared │
- │ Duration: 0.3s │
- ╰──────────────────────────╯
-
- ╭─ Project Summary ──────────────╮
- │ Linked Resources: 1 remaining │
- │ Last Updated: 2026-02-09 10:30 │
- │ Active Plans: 0 │
- ╰────────────────────────────────╯
-
- ✓ OK Resource unlinked from project
-
-
-=== "Plain"
-
- ```
- $ agents project unlink-resource local/api-service local/api-repo
-
- Unlink local/api-repo from local/api-service? [y/N]: y
-
- Resource Unlinked
- Project: local/api-service
- Resource: local/api-repo
- Type: git-checkout
-
- Index Cleanup
- Text Index: 347 removed
- Vectors: 892 removed
- Graph Triples: cleared
- Duration: 0.3s
-
- Project Summary
- Linked Resources: 1 remaining
- Last Updated: 2026-02-09 10:30
- Active Plans: 0
-
- [OK] Resource unlinked from project
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project unlink-resource local/api-service local/api-repo",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resource_unlinked": {
- "project": "local/api-service",
- "resource": "local/api-repo",
- "type": "git-checkout"
- },
- "index_cleanup": {
- "text_index": "347 removed",
- "vectors": "892 removed",
- "graph_triples": "cleared",
- "duration_seconds": 0.3
- },
- "project_summary": {
- "linked_resources": 1,
- "last_updated": "2026-02-09T10:30:00Z",
- "active_plans": 0
- }
- },
- "timing": { "duration_ms": 340 },
- "messages": [{ "level": "ok", "text": "Resource unlinked from project" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project unlink-resource local/api-service local/api-repo
- status: ok
- exit_code: 0
- data:
- resource_unlinked:
- project: local/api-service
- resource: local/api-repo
- type: git-checkout
- index_cleanup:
- text_index: 347 removed
- vectors: 892 removed
- graph_triples: cleared
- duration_seconds: 0.3
- project_summary:
- linked_resources: 1
- last_updated: "2026-02-09T10:30:00Z"
- active_plans: 0
- timing:
- duration_ms: 340
- messages:
- - level: ok
- text: Resource unlinked from project
- ```
-
-##### agents project list
-
-agents project list [(--namespace|-n) NS] [<REGEX>]
-
-**Purpose**
-List projects with optional filters.
-
-**Arguments**
-
-- `--namespace/-n NS`: Filter by namespace.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents --format table project list
-
- ╭─ Projects ────────────────────────────────────────────────────╮
- │ Name Resources Remote Active Plans │
- │ ───────────────── ───────── ────── ──────────── │
- │ local/api-service 2 No 1 │
- │ local/docs 1 No 0 │
- ╰───────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ──────────────────╮
- │ Total: 2 │
- │ With Resources: 2 │
- │ Remote: 0 │
- │ Total Resources: 3 │
- │ Indexed Files: 1,247 │
- │ Active Plans: 1 │
- ╰────────────────────────────╯
-
- ✓ OK 2 projects listed
-
-
-=== "Plain"
-
- ```
- $ agents --format table project list
-
- Projects
- Name Resources Remote Active Plans
- ----------------- --------- ------ ------------
- local/api-service 2 No 1
- local/docs 1 No 0
-
- Summary
- Total: 2
- With Resources: 2
- Remote: 0
- Total Resources: 3
- Indexed Files: 1,247
- Active Plans: 1
-
- [OK] 2 projects listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents --format table project list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "projects": [
- { "name": "local/api-service", "resources": 2, "remote": false, "active_plans": 1 },
- { "name": "local/docs", "resources": 1, "remote": false, "active_plans": 0 }
- ],
- "summary": {
- "total": 2,
- "with_resources": 2,
- "remote": 0,
- "total_resources": 3,
- "indexed_files": 1247,
- "active_plans": 1
- }
- },
- "timing": { "duration_ms": 45 },
- "messages": [{ "level": "ok", "text": "2 projects listed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents --format table project list
- status: ok
- exit_code: 0
- data:
- projects:
- - name: local/api-service
- resources: 2
- remote: false
- active_plans: 1
- - name: local/docs
- resources: 1
- remote: false
- active_plans: 0
- summary:
- total: 2
- with_resources: 2
- remote: 0
- total_resources: 3
- indexed_files: 1247
- active_plans: 1
- timing:
- duration_ms: 45
- messages:
- - level: ok
- text: 2 projects listed
- ```
-
-##### agents project show
-
-agents project show <PROJECT>
-
-**Purpose**
-Show full project details.
-
-**Arguments**
-
-- ``: Project name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project show local/api-service
-
- ╭─ Project Details ──────────────╮
- │ Name: local/api-service │
- │ Description: Backend API │
- │ Resources: 2 │
- │ Remote: no │
- │ Created: 2026-02-08 12:46 │
- ╰────────────────────────────────╯
-
- ╭─ Linked Resources ──────────────────────────────────────────────────────╮
- │ Resource Type Sandbox Read-Only │
- │ ──────────────── ────────────── ──────────────────── ───────── │
- │ local/api-repo git-checkout git_worktree no │
- │ local/staging-db local/database transaction_rollback yes │
- ╰─────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Validations (3) ──────────────────────────────────────────────────────────────────╮
- │ local/run-tests Run unit tests with coverage required │
- │ resource: local/api-repo scope: project (attachment: 01HXM5A1B2C3D4E5F6G7…) │
- │ local/lint-check Lint check required │
- │ resource: local/api-repo scope: direct (always active) (attachment: 01HXM5…) │
- │ local/check-bundle-size Check bundle size (advisory) informational │
- │ resource: local/api-repo scope: project (attachment: 01HXM5D4E5F6G7H8J9…) │
- ╰────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Context ───────────────────╮
- │ Include: repo │
- │ Exclude: **/node_modules/** │
- │ Max File Size: 1 MB │
- ╰─────────────────────────────╯
-
- ╭─ Indexing Status ──────────╮
- │ Text Index: ready │
- │ Vector Index: ready │
- │ Graph Store: disabled │
- │ Indexed Files: 347 │
- │ Last Indexed: 12:48 │
- ╰────────────────────────────╯
-
- ╭─ Active Plans ──────────────────────────╮
- │ Plan ID Action Phase │
- │ ──────── ─────────────────── ─────── │
- │ 01HXM7A9 local/code-coverage execute │
- ╰─────────────────────────────────────────╯
-
- ✓ OK Project loaded
-
-
-=== "Plain"
-
- ```
- $ agents project show local/api-service
-
- Project Details
- Name: local/api-service
- Description: Backend API
- Resources: 2
- Remote: no
- Created: 2026-02-08 12:46
-
- Linked Resources
- Resource Type Sandbox Read-Only
- ---------------- -------------- -------------------- ---------
- local/api-repo git-checkout git_worktree no
- local/staging-db local/database transaction_rollback yes
-
- Validations (3)
- local/run-tests Run unit tests with coverage required
- resource: local/api-repo scope: project (attachment: 01HXM5A1B2C3D4E5F6G7...)
- local/lint-check Lint check required
- resource: local/api-repo scope: direct (always active) (attachment: 01HXM5...)
- local/check-bundle-size Check bundle size (advisory) informational
- resource: local/api-repo scope: project (attachment: 01HXM5D4E5F6G7H8J9...)
-
- Context
- Include: repo
- Exclude: **/node_modules/**
- Max File Size: 1 MB
-
- Indexing Status
- Text Index: ready
- Vector Index: ready
- Graph Store: disabled
- Indexed Files: 347
- Last Indexed: 12:48
-
- Active Plans
- Plan ID Action Phase
- -------- ------------------- -------
- 01HXM7A9 local/code-coverage execute
-
- [OK] Project loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project show local/api-service",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "project": {
- "name": "local/api-service",
- "description": "Backend API",
- "resources": 2,
- "remote": false,
- "created": "2026-02-08T12:46:00Z"
- },
- "linked_resources": [
- { "name": "local/api-repo", "type": "git-checkout", "sandbox": "git_worktree", "read_only": false },
- { "name": "local/staging-db", "type": "local/database", "sandbox": "transaction_rollback", "read_only": true }
- ],
- "validations": [
- {
- "name": "local/run-tests",
- "description": "Run unit tests with coverage",
- "mode": "required",
- "resource": "local/api-repo",
- "scope": "project",
- "attachment_id": "01HXM5A1B2C3D4E5F6G7"
- },
- {
- "name": "local/lint-check",
- "description": "Lint check",
- "mode": "required",
- "resource": "local/api-repo",
- "scope": "direct",
- "attachment_id": "01HXM5"
- },
- {
- "name": "local/check-bundle-size",
- "description": "Check bundle size (advisory)",
- "mode": "informational",
- "resource": "local/api-repo",
- "scope": "project",
- "attachment_id": "01HXM5D4E5F6G7H8J9"
- }
- ],
- "context": {
- "include": ["repo"],
- "exclude": ["**/node_modules/**"],
- "max_file_size_bytes": 1048576
- },
- "indexing_status": {
- "text_index": "ready",
- "vector_index": "ready",
- "graph_store": "disabled",
- "indexed_files": 347,
- "last_indexed": "12:48"
- },
- "active_plans": [
- { "plan_id": "01HXM7A9", "action": "local/code-coverage", "phase": "execute" }
- ]
- },
- "timing": { "duration_ms": 62 },
- "messages": [{ "level": "ok", "text": "Project loaded" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project show local/api-service
- status: ok
- exit_code: 0
- data:
- project:
- name: local/api-service
- description: Backend API
- resources: 2
- remote: false
- created: "2026-02-08T12:46:00Z"
- linked_resources:
- - name: local/api-repo
- type: git-checkout
- sandbox: git_worktree
- read_only: false
- - name: local/staging-db
- type: local/database
- sandbox: transaction_rollback
- read_only: true
- validations:
- - name: local/run-tests
- description: Run unit tests with coverage
- mode: required
- resource: local/api-repo
- scope: project
- attachment_id: 01HXM5A1B2C3D4E5F6G7
- - name: local/lint-check
- description: Lint check
- mode: required
- resource: local/api-repo
- scope: direct
- attachment_id: 01HXM5
- - name: local/check-bundle-size
- description: Check bundle size (advisory)
- mode: informational
- resource: local/api-repo
- scope: project
- attachment_id: 01HXM5D4E5F6G7H8J9
- context:
- include:
- - repo
- exclude:
- - "**/node_modules/**"
- max_file_size_bytes: 1048576
- indexing_status:
- text_index: ready
- vector_index: ready
- graph_store: disabled
- indexed_files: 347
- last_indexed: "12:48"
- active_plans:
- - plan_id: 01HXM7A9
- action: local/code-coverage
- phase: execute
- timing:
- duration_ms: 62
- messages:
- - level: ok
- text: Project loaded
- ```
-
-##### agents project validations
-
-Note: Validations are managed as a top-level entity via `agents validation` commands (see the **agents validation** section below). A validation is always attached to a resource, but can optionally be scoped to a project via `agents validation attach --project `. When scoped to a project, the validation only runs when that resource is accessed through the specified project. The `agents project show` command displays all validations relevant to the project — both directly-attached validations on linked resources and project-scoped validations.
-
-See: [agents validation](#agents-validation) for full details on creating, managing, and attaching validations.
-
-##### agents project delete
-
-agents project delete [--force|-f] [--yes|-y] <NAME>
-
-!!! warning "Irreversible Action"
-
- Deleting a project ==cannot be undone==. All resource links, validation attachments, and context policies will be removed. The resources themselves remain in the Resource Registry. Use `--force` to also cancel active plans targeting this project.
-
-**Purpose**
-Delete a project and unlink all associated resources. The resources themselves remain in the Resource Registry.
-
-**Arguments**
-
-- ``: Project name.
-- `--force/-f`: Delete even if active plans exist.
-- `--yes`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project delete local/docs
-
- Delete project local/docs? This cannot be undone. [y/N]: y
-
- ╭─ Deletion Summary ──────────────────╮
- │ Project: local/docs │
- │ Resources: 1 unlinked │
- │ Data Dir: /repos/docs/.cleveragents │
- ╰─────────────────────────────────────╯
-
- ╭─ Index Cleanup ────────╮
- │ Text Index: cleared │
- │ Vectors: 240 removed │
- │ Graph Triples: none │
- │ Storage Freed: 12 MB │
- ╰────────────────────────╯
-
- ╭─ Backups ────────────────────────────────────╮
- │ Snapshot: /backups/local-docs-2026-02-08.tgz │
- │ Retention: 7 days │
- ╰──────────────────────────────────────────────╯
-
- ✓ OK Project deleted
-
-
-=== "Plain"
-
- ```
- $ agents project delete local/docs
-
- Delete project local/docs? This cannot be undone. [y/N]: y
-
- Deletion Summary
- Project: local/docs
- Resources: 1 unlinked
- Data Dir: /repos/docs/.cleveragents
-
- Index Cleanup
- Text Index: cleared
- Vectors: 240 removed
- Graph Triples: none
- Storage Freed: 12 MB
-
- Backups
- Snapshot: /backups/local-docs-2026-02-08.tgz
- Retention: 7 days
-
- [OK] Project deleted
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project delete local/docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "deletion_summary": {
- "project": "local/docs",
- "resources_unlinked": 1,
- "data_dir": "/repos/docs/.cleveragents"
- },
- "index_cleanup": {
- "text_index": "cleared",
- "vectors": "240 removed",
- "graph_triples": "none",
- "storage_freed_mb": 12
- },
- "backups": {
- "snapshot": "/backups/local-docs-2026-02-08.tgz",
- "retention_days": 7
- }
- },
- "timing": { "duration_ms": 530 },
- "messages": [{ "level": "ok", "text": "Project deleted" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project delete local/docs
- status: ok
- exit_code: 0
- data:
- deletion_summary:
- project: local/docs
- resources_unlinked: 1
- data_dir: /repos/docs/.cleveragents
- index_cleanup:
- text_index: cleared
- vectors: 240 removed
- graph_triples: none
- storage_freed_mb: 12
- backups:
- snapshot: /backups/local-docs-2026-02-08.tgz
- retention_days: 7
- timing:
- duration_ms: 530
- messages:
- - level: ok
- text: Project deleted
- ```
-
-Attempting to delete a project that has active plans (without `--force`):
-
-=== "Rich"
-
-
- $ agents project delete local/api-service
-
- Delete project local/api-service? [y/N]: y
-
- ╭─ Delete Blocked ──────────────────────────────────────────╮
- │ Cannot delete: project has active plans │
- │ Active Plans: 2 │
- │ 01HXM7A9 — execute/processing (local/code-coverage) │
- │ 01HXM4J1 — strategize/processing (local/refactor-api) │
- ╰───────────────────────────────────────────────────────────╯
-
- ╭─ Resolution ──────────────────────────────────────────────────────╮
- │ - Cancel or complete active plans first, or │
- │ - Use --force to cancel all active plans and delete the project │
- ╰───────────────────────────────────────────────────────────────────╯
-
- ✗ ERROR Delete blocked — 2 active plans
-
-
-=== "Plain"
-
- ```
- $ agents project delete local/api-service
-
- Delete project local/api-service? [y/N]: y
-
- Delete Blocked
- Cannot delete: project has active plans
- Active Plans: 2
- 01HXM7A9 -- execute/processing (local/code-coverage)
- 01HXM4J1 -- strategize/processing (local/refactor-api)
-
- Resolution
- - Cancel or complete active plans first, or
- - Use --force to cancel all active plans and delete the project
-
- [ERROR] Delete blocked -- 2 active plans
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project delete local/api-service",
- "status": "error",
- "exit_code": 1,
- "data": {
- "delete_blocked": {
- "reason": "project has active plans",
- "active_plans": [
- { "plan_id": "01HXM7A9", "phase": "execute/processing", "action": "local/code-coverage" },
- { "plan_id": "01HXM4J1", "phase": "strategize/processing", "action": "local/refactor-api" }
- ]
- },
- "resolution": [
- "Cancel or complete active plans first",
- "Use --force to cancel all active plans and delete the project"
- ]
- },
- "timing": { "duration_ms": 38 },
- "messages": [{ "level": "error", "text": "Delete blocked — 2 active plans" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project delete local/api-service
- status: error
- exit_code: 1
- data:
- delete_blocked:
- reason: project has active plans
- active_plans:
- - plan_id: 01HXM7A9
- phase: execute/processing
- action: local/code-coverage
- - plan_id: 01HXM4J1
- phase: strategize/processing
- action: local/refactor-api
- resolution:
- - Cancel or complete active plans first
- - Use --force to cancel all active plans and delete the project
- timing:
- duration_ms: 38
- messages:
- - level: error
- text: "Delete blocked \u2014 2 active plans"
- ```
-
-Force-deleting a project with active plans:
-
-=== "Rich"
-
-
- $ agents project delete --force --yes local/api-service
-
- ╭─ Force Delete ─────────────────────────────────────────╮
- │ Cancelling: 2 active plans │
- │ 01HXM7A9 — cancelled (was execute/processing) │
- │ 01HXM4J1 — cancelled (was strategize/processing) │
- ╰────────────────────────────────────────────────────────╯
-
- ╭─ Deleted ────────────────────╮
- │ Project: local/api-service │
- │ Resources Unlinked: 2 │
- │ Validations Detached: 3 │
- │ Plans Cancelled: 2 │
- │ Context Policies: cleared │
- ╰──────────────────────────────╯
-
- ✓ OK Project force-deleted
-
-
-=== "Plain"
-
- ```
- $ agents project delete --force --yes local/api-service
-
- Force Delete
- Cancelling: 2 active plans
- 01HXM7A9 -- cancelled (was execute/processing)
- 01HXM4J1 -- cancelled (was strategize/processing)
-
- Deleted
- Project: local/api-service
- Resources Unlinked: 2
- Validations Detached: 3
- Plans Cancelled: 2
- Context Policies: cleared
-
- [OK] Project force-deleted
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents project delete --force --yes local/api-service",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "force_delete": {
- "cancelled_plans": [
- { "plan_id": "01HXM7A9", "previous_state": "execute/processing" },
- { "plan_id": "01HXM4J1", "previous_state": "strategize/processing" }
- ]
- },
- "deleted": {
- "project": "local/api-service",
- "resources_unlinked": 2,
- "validations_detached": 3,
- "plans_cancelled": 2,
- "context_policies": "cleared"
- }
- },
- "timing": { "duration_ms": 245 },
- "messages": [{ "level": "ok", "text": "Project force-deleted" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents project delete --force --yes local/api-service
- status: ok
- exit_code: 0
- data:
- force_delete:
- cancelled_plans:
- - plan_id: 01HXM7A9
- previous_state: execute/processing
- - plan_id: 01HXM4J1
- previous_state: strategize/processing
- deleted:
- project: local/api-service
- resources_unlinked: 2
- validations_detached: 3
- plans_cancelled: 2
- context_policies: cleared
- timing:
- duration_ms: 245
- messages:
- - level: ok
- text: Project force-deleted
- ```
-
-##### agents project context
-
-**Purpose**
-Manage ACMS context policies for the hot/warm/cold tiers, per-view context selection, strategy configuration, UKO depth/breadth parameters, and context budget tuning.
-
-###### agents project context set
-
-agents project context set[--view (strategize|execute|apply|default)]
- [--include-resource <INCLUDE_RESOURCE>]...
- [--exclude-resource <EXCLUDE_RESOURCE>]...
- [--include-path <INCLUDE_GLOB>]...
- [--exclude-path <EXCLUDE_GLOB>]...
- [--hot-max-tokens <N>]
- [--warm-max-decisions <N_WARM_MAX>]
- [--cold-max-decisions <N_COLD_MAX>]
- [--query-limit <N>]
- [--max-file-size <MAX_FILE_BYTES>]
- [--max-total-size <MAX_TOTAL_BYTES>]
- [--summarize|--no-summarize]
- [--summary-max-tokens <N>]
- [--strategy <STRATEGY>]...
- [--default-breadth <N>]
- [--default-depth <INT_OR_NAME>]
- [--depth-gradient <HOP:INT_OR_NAME>]...
- [--skeleton-ratio <FLOAT>]
- [--temporal-scope (current|recent|all)]
- [--auto-refresh|--no-auto-refresh]
- [--execution-environment <RESOURCE_NAME>]
- [--execution-env-priority (fallback|override)]
- [--clear] <PROJECT>
-
-**Purpose**
-Set the context policy for a project and (optionally) a specific view.
-
-**Arguments**
-
-- ``: Project name (positional argument, at end of command).
-- `--view strategize|execute|apply|default`: Which view this policy applies to.
-- `--include-resource NAME`: Resource allowlist (repeatable).
-- `--exclude-resource NAME`: Resource denylist (repeatable).
-- `--include-path GLOB`: Path allowlist (repeatable).
-- `--exclude-path GLOB`: Path denylist (repeatable).
-- `--hot-max-tokens N`: Maximum token budget for hot context. This is a soft cap and may be null. The actor/LLM hard limit can be lower; the effective hot context is the lesser of the two.
-- `--warm-max-decisions N`: Maximum number of decisions kept in warm context.
-- `--cold-max-decisions N`: Maximum number of decisions kept in cold context.
-- `--query-limit N`: Max number of retrieval results per query.
-- `--max-file-size BYTES`: Max file size included in context.
-- `--max-total-size BYTES`: Max total size across included files.
-- `--summarize/--no-summarize`: Enable or disable summarization for large context segments.
-- `--summary-max-tokens N`: Token limit for generated summaries.
-- `--strategy STRATEGY`: ACMS context strategy to enable for this view (repeatable). Overrides the global `context.strategies.enabled` list. Built-in: `simple-keyword`, `semantic-embedding`, `breadth-depth-navigator`, `arce`, `temporal-archaeology`, `plan-decision-context`.
-- `--default-breadth N`: Default number of hops from focus nodes in the UKO graph. `0` = focus nodes only. Default: `2`.
-- `--default-depth INT_OR_NAME`: Default detail depth for context fragments. Accepts a raw integer (e.g., `4`) or a named level from the active domain's DetailLevelMap (e.g., `SIGNATURES`, `MEMBER_SUMMARY`). Named levels are resolved to integers via the DetailLevelMap inheritance chain. Default: `3` (typically `MEMBER_SUMMARY` / `FULL_TOC` / `TYPED_COLUMNS` depending on domain).
-- `--depth-gradient HOP:INT_OR_NAME`: Per-hop detail depth override (repeatable). Format: `0:9`, `1:4`, `2:0` or `0:FULL_SOURCE`, `1:SIGNATURES`, `2:MODULE_LISTING`. Hops not specified use `--default-depth`.
-- `--skeleton-ratio FLOAT`: Fraction of context budget reserved for inherited plan skeleton. Range: 0.0–1.0. Default: `0.15`.
-- `--temporal-scope current|recent|all`: Temporal scope for UKO node resolution. Default: `current`.
-- `--auto-refresh/--no-auto-refresh`: Enable or disable automatic context re-assembly on budget changes.
-- `--execution-environment RESOURCE_NAME`: Name of a `container-instance` or `devcontainer-instance` resource to use as the default execution environment for this project. When set, tool invocations during plan execution are routed to this container unless overridden at the plan level. See [ADR-043 §3.3](adr/ADR-043-devcontainer-integration.md).
-- `--execution-env-priority fallback|override`: Priority semantics for the project-level execution environment. `fallback` (default): defers to auto-detected devcontainers when present; used only when no closer-scoped environment exists. `override`: always uses the specified environment, bypassing devcontainer auto-detection. See §Execution Environment Routing.
-- `--clear`: Clear the policy for the selected view.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project context set --view strategize \
- --include-resource repo --exclude-path "**/node_modules/**" \
- --hot-max-tokens 12000 --warm-max-decisions 50 --cold-max-decisions 200 \
- --summarize --summary-max-tokens 800 local/api-service
-
- ╭─ Context Policy ────────────╮
- │ Project: local/api-service │
- │ View: strategize │
- │ Include: repo │
- │ Exclude: **/node_modules/** │
- ╰─────────────────────────────╯
-
- ╭─ Limits ─────────────────────╮
- │ Hot Tokens: 12000 (soft cap) │
- │ Warm Decisions: 50 │
- │ Cold Decisions: 200 │
- │ Query Limit: 20 │
- │ Max File Size: 1 MB │
- │ Max Total Size: 50 MB │
- ╰──────────────────────────────╯
-
- ╭─ Summarization ─╮
- │ Enabled: yes │
- │ Max Tokens: 800 │
- ╰─────────────────╯
-
- ╭─ Other Views ────────╮
- │ execute: (default) │
- │ apply: (default) │
- │ default: (unset) │
- ╰──────────────────────╯
-
- ✓ OK Context policy updated
-
-
-=== "Plain"
-
- ```
- $ agents project context set --view strategize \
- --include-resource repo --exclude-path "**/node_modules/**" \
- --hot-max-tokens 12000 --warm-max-decisions 50 --cold-max-decisions 200 \
- --summarize --summary-max-tokens 800 local/api-service
-
- Context Policy
- Project: local/api-service
- View: strategize
- Include: repo
- Exclude: **/node_modules/**
-
- Limits
- Hot Tokens: 12000 (soft cap)
- Warm Decisions: 50
- Cold Decisions: 200
- Query Limit: 20
- Max File Size: 1 MB
- Max Total Size: 50 MB
-
- Summarization
- Enabled: yes
- Max Tokens: 800
-
- Other Views
- execute: (default)
- apply: (default)
- default: (unset)
-
- [OK] Context policy updated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "project context set",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_policy": {
- "project": "local/api-service",
- "view": "strategize",
- "include_resources": ["repo"],
- "exclude_paths": ["**/node_modules/**"]
- },
- "limits": {
- "hot_max_tokens": 12000,
- "warm_max_decisions": 50,
- "cold_max_decisions": 200,
- "query_limit": 20,
- "max_file_size": "1 MB",
- "max_total_size": "50 MB"
- },
- "summarization": {
- "enabled": true,
- "max_tokens": 800
- },
- "other_views": {
- "execute": "(default)",
- "apply": "(default)",
- "default": "(unset)"
- }
- },
- "timing": {
- "duration_ms": 42
- },
- "messages": ["Context policy updated"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: project context set
- status: ok
- exit_code: 0
- data:
- context_policy:
- project: local/api-service
- view: strategize
- include_resources:
- - repo
- exclude_paths:
- - "**/node_modules/**"
- limits:
- hot_max_tokens: 12000
- warm_max_decisions: 50
- cold_max_decisions: 200
- query_limit: 20
- max_file_size: 1 MB
- max_total_size: 50 MB
- summarization:
- enabled: true
- max_tokens: 800
- other_views:
- execute: (default)
- apply: (default)
- default: (unset)
- timing:
- duration_ms: 42
- messages:
- - Context policy updated
- ```
-
-###### agents project context show
-
-agents project context show [--view (strategize|execute|apply|default)]
- <PROJECT>
-
-**Purpose**
-Show the active context policy for a project.
-
-**Arguments**
-
-- ``: Project name (positional argument, at end of command).
-- `--view strategize|execute|apply|default`: View to display.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project context show --view strategize local/api-service
-
- ╭─ Context Policy ────────────╮
- │ Project: local/api-service │
- │ View: strategize │
- │ Include: repo │
- │ Exclude: **/node_modules/** │
- ╰─────────────────────────────╯
-
- ╭─ Limits ─────────────────────╮
- │ Hot Tokens: 12000 (soft cap) │
- │ Warm Decisions: 50 │
- │ Cold Decisions: 200 │
- │ Query Limit: 20 │
- │ Max File Size: 1 MB │
- │ Max Total Size: 50 MB │
- ╰──────────────────────────────╯
-
- ╭─ Summarization ─╮
- │ Enabled: yes │
- │ Max Tokens: 800 │
- ╰─────────────────╯
-
- ╭─ Current Usage ──────────────╮
- │ Hot Context: 8,420 / 12,000 │
- │ Warm Entries: 12 / 50 │
- │ Cold Entries: 47 / 200 │
- │ Indexed Resources: 1 │
- ╰──────────────────────────────╯
-
- ✓ OK Context policy loaded
-
-
-=== "Plain"
-
- ```
- $ agents project context show --view strategize local/api-service
-
- Context Policy
- Project: local/api-service
- View: strategize
- Include: repo
- Exclude: **/node_modules/**
-
- Limits
- Hot Tokens: 12000 (soft cap)
- Warm Decisions: 50
- Cold Decisions: 200
- Query Limit: 20
- Max File Size: 1 MB
- Max Total Size: 50 MB
-
- Summarization
- Enabled: yes
- Max Tokens: 800
-
- Current Usage
- Hot Context: 8,420 / 12,000
- Warm Entries: 12 / 50
- Cold Entries: 47 / 200
- Indexed Resources: 1
-
- [OK] Context policy loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "project context show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_policy": {
- "project": "local/api-service",
- "view": "strategize",
- "include_resources": ["repo"],
- "exclude_paths": ["**/node_modules/**"]
- },
- "limits": {
- "hot_max_tokens": 12000,
- "warm_max_decisions": 50,
- "cold_max_decisions": 200,
- "query_limit": 20,
- "max_file_size": "1 MB",
- "max_total_size": "50 MB"
- },
- "summarization": {
- "enabled": true,
- "max_tokens": 800
- },
- "current_usage": {
- "hot_context_tokens": 8420,
- "hot_context_limit": 12000,
- "warm_entries": 12,
- "warm_limit": 50,
- "cold_entries": 47,
- "cold_limit": 200,
- "indexed_resources": 1
- }
- },
- "timing": {
- "duration_ms": 38
- },
- "messages": ["Context policy loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: project context show
- status: ok
- exit_code: 0
- data:
- context_policy:
- project: local/api-service
- view: strategize
- include_resources:
- - repo
- exclude_paths:
- - "**/node_modules/**"
- limits:
- hot_max_tokens: 12000
- warm_max_decisions: 50
- cold_max_decisions: 200
- query_limit: 20
- max_file_size: 1 MB
- max_total_size: 50 MB
- summarization:
- enabled: true
- max_tokens: 800
- current_usage:
- hot_context_tokens: 8420
- hot_context_limit: 12000
- warm_entries: 12
- warm_limit: 50
- cold_entries: 47
- cold_limit: 200
- indexed_resources: 1
- timing:
- duration_ms: 38
- messages:
- - Context policy loaded
- ```
-
-###### agents project context inspect
-
-agents project context inspect [--view (strategize|execute|apply|default)]
- [--strategy <STRATEGY>]
- [--focus <UKO_URI>]...
- [--breadth <N>] [--depth <INT_OR_NAME>]
- <PROJECT>
-
-**Purpose**
-Inspect the current state of the ACMS context assembly for a project. Shows the UKO graph structure, active strategies, indexed resources, context budget usage, and the most recent fusion result. Useful for debugging context quality issues.
-
-**Arguments**
-
-- ``: Project name (positional argument, at end of command).
-- `--view strategize|execute|apply|default`: View to inspect. Default: `default`.
-- `--strategy STRATEGY`: Filter to show results from a specific strategy only.
-- `--focus UKO_URI`: Show the UKO subgraph rooted at these focus nodes (repeatable). When omitted, shows a summary of the full indexed graph.
-- `--breadth N`: Override the breadth (hop count) for the focus node expansion. Default: uses the view's `default_breadth`.
-- `--depth INT_OR_NAME`: Override the detail depth for the display. Accepts a raw integer or a named level from the active DetailLevelMap. Default: uses the view's `default_depth`.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project context inspect --view execute --focus uko-py:module/src.auth --breadth 2 local/api-service
-
- ╭─ ACMS Context Inspection ────────────────────────────────────────╮
- │ Project: local/api-service │
- │ View: execute │
- │ Focus: uko-py:module/src.auth │
- │ Breadth: 2 hops │ Depth: 3 (MEMBER_SUMMARY) │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ UKO Graph (2-hop neighborhood) ─────────────────────────────────╮
- │ uko-py:module/src.auth (depth 9/FULL_SOURCE, 1,240 tokens) │
- │ ├─ contains → uko-py:class/AuthHandler (depth 3, 320 tokens) │
- │ ├─ contains → uko-py:class/TokenValidator (depth 3, 280 tok) │
- │ ├─ imports → uko-py:module/src.db (depth 0, 90 tokens) │
- │ └─ imports → uko-py:module/src.config (depth 0, 60 tok) │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Active Strategies ──────────────────────────────────────────────╮
- │ breadth-depth-navigator quality=0.85 budget=45% 4 fragments │
- │ semantic-embedding quality=0.60 budget=35% 6 fragments │
- │ simple-keyword quality=0.30 budget=20% 3 fragments │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Budget ─────────────────────────────╮
- │ Model Window: 128,000 tokens │
- │ Response Reserve: 4,096 tokens │
- │ Tool Definitions: 2,400 tokens │
- │ System Prompt: 1,200 tokens │
- │ Skeleton Reserve: 18,046 (15%) │
- │ Available Budget: 102,258 tokens │
- │ Used: 1,990 / 102,258 (1.9%) │
- ╰──────────────────────────────────────╯
-
- ✓ OK Context inspection complete
-
-
-=== "Plain"
-
- ```
- $ agents project context inspect --view execute --focus uko-py:module/src.auth --breadth 2 local/api-service
-
- ACMS Context Inspection
- Project: local/api-service
- View: execute
- Focus: uko-py:module/src.auth
- Breadth: 2 hops Depth: 3 (MEMBER_SUMMARY)
-
- UKO Graph (2-hop neighborhood)
- uko-py:module/src.auth (depth 9/FULL_SOURCE, 1,240 tokens)
- contains -> uko-py:class/AuthHandler (depth 3, 320 tokens)
- contains -> uko-py:class/TokenValidator (depth 3, 280 tok)
- imports -> uko-py:module/src.db (depth 0, 90 tokens)
- imports -> uko-py:module/src.config (depth 0, 60 tok)
-
- Active Strategies
- Strategy Quality Budget Fragments
- ------------------------- ------- ------ ---------
- breadth-depth-navigator 0.85 45% 4
- semantic-embedding 0.60 35% 6
- simple-keyword 0.30 20% 3
-
- Budget
- Model Window: 128,000 tokens
- Response Reserve: 4,096 tokens
- Tool Definitions: 2,400 tokens
- System Prompt: 1,200 tokens
- Skeleton Reserve: 18,046 (15%)
- Available Budget: 102,258 tokens
- Used: 1,990 / 102,258 (1.9%)
-
- [OK] Context inspection complete
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "project context inspect",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "inspection": {
- "project": "local/api-service",
- "view": "execute",
- "focus": ["uko-py:module/src.auth"],
- "breadth": 2,
- "depth": 3,
- "depth_name": "MEMBER_SUMMARY"
- },
- "uko_graph": {
- "root": "uko-py:module/src.auth",
- "root_depth": 9,
- "root_depth_name": "FULL_SOURCE",
- "root_tokens": 1240,
- "edges": [
- { "relation": "contains", "target": "uko-py:class/AuthHandler", "depth": 3, "tokens": 320 },
- { "relation": "contains", "target": "uko-py:class/TokenValidator", "depth": 3, "tokens": 280 },
- { "relation": "imports", "target": "uko-py:module/src.db", "depth": 0, "tokens": 90 },
- { "relation": "imports", "target": "uko-py:module/src.config", "depth": 0, "tokens": 60 }
- ]
- },
- "active_strategies": [
- { "name": "breadth-depth-navigator", "quality": 0.85, "budget_pct": 0.45, "fragments": 4 },
- { "name": "semantic-embedding", "quality": 0.60, "budget_pct": 0.35, "fragments": 6 },
- { "name": "simple-keyword", "quality": 0.30, "budget_pct": 0.20, "fragments": 3 }
- ],
- "budget": {
- "model_window": 128000,
- "response_reserve": 4096,
- "tool_definitions": 2400,
- "system_prompt": 1200,
- "skeleton_reserve": 18046,
- "skeleton_ratio": 0.15,
- "available_budget": 102258,
- "used": 1990,
- "utilization": 0.019
- }
- },
- "timing": {
- "duration_ms": 185
- },
- "messages": ["Context inspection complete"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: project context inspect
- status: ok
- exit_code: 0
- data:
- inspection:
- project: local/api-service
- view: execute
- focus:
- - uko-py:module/src.auth
- breadth: 2
- depth: 3
- depth_name: MEMBER_SUMMARY
- uko_graph:
- root: uko-py:module/src.auth
- root_depth: 9
- root_depth_name: FULL_SOURCE
- root_tokens: 1240
- edges:
- - relation: contains
- target: uko-py:class/AuthHandler
- depth: 3
- tokens: 320
- - relation: contains
- target: uko-py:class/TokenValidator
- depth: 3
- tokens: 280
- - relation: imports
- target: uko-py:module/src.db
- depth: 0
- tokens: 90
- - relation: imports
- target: uko-py:module/src.config
- depth: 0
- tokens: 60
- active_strategies:
- - name: breadth-depth-navigator
- quality: 0.85
- budget_pct: 0.45
- fragments: 4
- - name: semantic-embedding
- quality: 0.60
- budget_pct: 0.35
- fragments: 6
- - name: simple-keyword
- quality: 0.30
- budget_pct: 0.20
- fragments: 3
- budget:
- model_window: 128000
- response_reserve: 4096
- tool_definitions: 2400
- system_prompt: 1200
- skeleton_reserve: 18046
- skeleton_ratio: 0.15
- available_budget: 102258
- used: 1990
- utilization: 0.019
- timing:
- duration_ms: 185
- messages:
- - Context inspection complete
- ```
-
-###### agents project context simulate
-
-agents project context simulate [--view (strategize|execute|apply|default)]
- [--budget <TOKENS>]
- [--focus <UKO_URI>]...
- [--strategy <STRATEGY>]...
- <PROJECT>
-
-**Purpose**
-Simulate a context assembly run without invoking an actor. Produces a dry-run report showing what the Context Assembly Pipeline would include in the context payload, which strategies contributed, how the budget was allocated, and what was excluded. Useful for tuning context view configurations before running plans.
-
-**Arguments**
-
-- ``: Project name (positional argument, at end of command).
-- `--view strategize|execute|apply|default`: View to simulate. Default: `default`.
-- `--budget TOKENS`: Override the context budget in tokens. When omitted, uses the dynamic budget calculation.
-- `--focus UKO_URI`: Focus nodes for the simulation (repeatable). When omitted, uses a default focus derived from recent plan activity.
-- `--strategy STRATEGY`: Override which strategies to run (repeatable). When omitted, uses the view's configured strategies.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents project context simulate --view strategize --budget 16000 \
- --focus uko-py:module/src.auth --focus uko-py:module/src.db \
- local/api-service
-
- ╭─ ACMS Simulation ────────────────────────────────────────────────╮
- │ Project: local/api-service │
- │ View: strategize │
- │ Budget: 16,000 tokens (override) │
- │ Focus: uko-py:module/src.auth, uko-py:module/src.db │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Strategy Results ───────────────────────────────────────────────╮
- │ breadth-depth-navigator │
- │ Confidence: 0.85 │ Budget: 7,200 tokens │ 12 fragments │
- │ Top: src/auth/__init__.py (depth 9, 1,240t, score=0.95) │
- │ src/db/models.py (depth 3, 480t, score=0.88) │
- │ │
- │ semantic-embedding │
- │ Confidence: 0.60 │ Budget: 5,600 tokens │ 8 fragments │
- │ Top: src/auth/jwt.py (depth 3, 380t, score=0.82) │
- │ src/middleware/auth_check.py (depth 3, 290t, score=0.79) │
- │ │
- │ simple-keyword │
- │ Confidence: 0.30 │ Budget: 3,200 tokens │ 5 fragments │
- │ Top: src/auth/utils.py (depth 6, 210t, score=0.71) │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Fusion Result ──────────────────────────────────────────────────╮
- │ Included: 18 fragments (14,820 tokens, 92.6% of budget) │
- │ Excluded: 7 fragments (3,200 tokens, below budget cutoff) │
- │ Deduplicated: 4 fragments merged │
- │ Skeleton: 2,400 tokens (15% reserve) │
- │ Preamble: 180 tokens │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ✓ OK Simulation complete (dry run — no context was assembled)
-
-
-=== "Plain"
-
- ```
- $ agents project context simulate --view strategize --budget 16000 \
- --focus uko-py:module/src.auth --focus uko-py:module/src.db \
- local/api-service
-
- ACMS Simulation
- Project: local/api-service
- View: strategize
- Budget: 16,000 tokens (override)
- Focus: uko-py:module/src.auth, uko-py:module/src.db
-
- Strategy Results
- breadth-depth-navigator
- Confidence: 0.85 Budget: 7,200 tokens 12 fragments
- Top: src/auth/__init__.py (depth 9, 1,240t, score=0.95)
- src/db/models.py (depth 3, 480t, score=0.88)
-
- semantic-embedding
- Confidence: 0.60 Budget: 5,600 tokens 8 fragments
- Top: src/auth/jwt.py (depth 3, 380t, score=0.82)
- src/middleware/auth_check.py (depth 3, 290t, score=0.79)
-
- simple-keyword
- Confidence: 0.30 Budget: 3,200 tokens 5 fragments
- Top: src/auth/utils.py (depth 6, 210t, score=0.71)
-
- Fusion Result
- Included: 18 fragments (14,820 tokens, 92.6% of budget)
- Excluded: 7 fragments (3,200 tokens, below budget cutoff)
- Deduplicated: 4 fragments merged
- Skeleton: 2,400 tokens (15% reserve)
- Preamble: 180 tokens
-
- [OK] Simulation complete (dry run -- no context was assembled)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "project context simulate",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "simulation": {
- "project": "local/api-service",
- "view": "strategize",
- "budget": 16000,
- "budget_source": "override",
- "focus": ["uko-py:module/src.auth", "uko-py:module/src.db"]
- },
- "strategy_results": [
- {
- "name": "breadth-depth-navigator",
- "confidence": 0.85,
- "budget_tokens": 7200,
- "fragments": 12,
- "top": [
- { "path": "src/auth/__init__.py", "depth": 9, "tokens": 1240, "score": 0.95 },
- { "path": "src/db/models.py", "depth": 3, "tokens": 480, "score": 0.88 }
- ]
- },
- {
- "name": "semantic-embedding",
- "confidence": 0.60,
- "budget_tokens": 5600,
- "fragments": 8,
- "top": [
- { "path": "src/auth/jwt.py", "depth": 3, "tokens": 380, "score": 0.82 },
- { "path": "src/middleware/auth_check.py", "depth": 3, "tokens": 290, "score": 0.79 }
- ]
- },
- {
- "name": "simple-keyword",
- "confidence": 0.30,
- "budget_tokens": 3200,
- "fragments": 5,
- "top": [
- { "path": "src/auth/utils.py", "depth": 6, "tokens": 210, "score": 0.71 }
- ]
- }
- ],
- "fusion_result": {
- "included_fragments": 18,
- "included_tokens": 14820,
- "budget_utilization": 0.926,
- "excluded_fragments": 7,
- "excluded_tokens": 3200,
- "deduplicated_fragments": 4,
- "skeleton_tokens": 2400,
- "skeleton_ratio": 0.15,
- "preamble_tokens": 180
- }
- },
- "timing": {
- "duration_ms": 310
- },
- "messages": ["Simulation complete (dry run -- no context was assembled)"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: project context simulate
- status: ok
- exit_code: 0
- data:
- simulation:
- project: local/api-service
- view: strategize
- budget: 16000
- budget_source: override
- focus:
- - uko-py:module/src.auth
- - uko-py:module/src.db
- strategy_results:
- - name: breadth-depth-navigator
- confidence: 0.85
- budget_tokens: 7200
- fragments: 12
- top:
- - path: src/auth/__init__.py
- depth: 9
- tokens: 1240
- score: 0.95
- - path: src/db/models.py
- depth: 3
- tokens: 480
- score: 0.88
- - name: semantic-embedding
- confidence: 0.60
- budget_tokens: 5600
- fragments: 8
- top:
- - path: src/auth/jwt.py
- depth: 3
- tokens: 380
- score: 0.82
- - path: src/middleware/auth_check.py
- depth: 3
- tokens: 290
- score: 0.79
- - name: simple-keyword
- confidence: 0.30
- budget_tokens: 3200
- fragments: 5
- top:
- - path: src/auth/utils.py
- depth: 6
- tokens: 210
- score: 0.71
- fusion_result:
- included_fragments: 18
- included_tokens: 14820
- budget_utilization: 0.926
- excluded_fragments: 7
- excluded_tokens: 3200
- deduplicated_fragments: 4
- skeleton_tokens: 2400
- skeleton_ratio: 0.15
- preamble_tokens: 180
- timing:
- duration_ms: 310
- messages:
- - "Simulation complete (dry run -- no context was assembled)"
- ```
-
-#### agents actor
-
-**Purpose**
-Manage actors and run actor configurations directly.
-
-##### agents actor run
-
-agents actor run [(--output|-o) <OUTPUT_FILE>]
- [-v...] [--unsafe|-u] [--context <CONTEXT_NAME>]
- [--context-dir <CONTEXT_PATH>] [--load-context <LOAD_CONTEXT_NAME>]
- [(--temperature|-t) <TEMP>] [--allow-rxpy-in-run-mode]
- [--skill <SKILL>]... <NAME> <PROMPT>
-
-**Purpose**
-Run a named actor in isolation with simple, manual context.
-
-**Arguments**
-
-- ``: The name of the actor to run (required).
-- ``: Prompt text (positional argument).
-- `--output/-o FILE`: Output file path.
-- `--verbose/-v`: Increase log verbosity (repeatable). Same semantics as the global `-v` flag: no `-v` = normal output only, `-v` = ERROR, `-vv` = WARN, `-vvv` = INFO, `-vvvv` = DEBUG, `-vvvvv` = TRACE.
-- `--unsafe/-u`: Allow unsafe configs.
-- `--context NAME`: Named actor context to attach.
-- `--context-dir PATH`: Context storage location.
-- `--load-context FILE`: Load context from JSON.
-- `--temperature/-t FLOAT`: Override temperature.
-- `--skill NAME`: Skill to attach (repeatable).
-- `--allow-rxpy-in-run-mode`: Allow RxPy routes in run mode.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor run --context docs local/code_reader "Summarize the README"
-
- ╭─ Run Summary ─────────────────╮
- │ Actor: local/code_reader │
- │ Context: docs │
- │ Temperature: 0.2 │
- │ Provider: anthropic │
- │ Model: claude-3.5 │
- ╰───────────────────────────────╯
-
- ╭─ Inputs ─────────────────────╮
- │ Prompt: Summarize the README │
- │ Context Files: 3 │
- │ Context Size: 12.4 KB │
- ╰──────────────────────────────╯
-
- ╭─ Result Metrics ───────╮
- │ Output: stdout │
- │ Input Tokens: 1,524 │
- │ Output Tokens: 842 │
- │ Duration: 1.8s │
- │ Cost: $0.0021 │
- │ Tool Calls: 0 │
- ╰────────────────────────╯
-
- ✓ OK Summary generated
-
-
-=== "Plain"
-
- ```
- $ agents actor run --context docs local/code_reader "Summarize the README"
-
- Run Summary
- Actor: local/code_reader
- Context: docs
- Temperature: 0.2
- Provider: anthropic
- Model: claude-3.5
-
- Inputs
- Prompt: Summarize the README
- Context Files: 3
- Context Size: 12.4 KB
-
- Result Metrics
- Output: stdout
- Input Tokens: 1,524
- Output Tokens: 842
- Duration: 1.8s
- Cost: $0.0021
- Tool Calls: 0
-
- [OK] Summary generated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor run --context docs local/code_reader \"Summarize the README\"",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "run_summary": {
- "actor": "local/code_reader",
- "context": "docs",
- "temperature": 0.2,
- "provider": "anthropic",
- "model": "claude-3.5"
- },
- "inputs": {
- "prompt": "Summarize the README",
- "context_files": 3,
- "context_size": "12.4 KB"
- },
- "result_metrics": {
- "output": "stdout",
- "input_tokens": 1524,
- "output_tokens": 842,
- "duration_s": 1.8,
- "cost": "$0.0021",
- "tool_calls": 0
- }
- },
- "timing": {
- "duration_ms": 1800
- },
- "messages": [
- { "level": "ok", "text": "Summary generated" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor run --context docs local/code_reader "Summarize the README"
- status: ok
- exit_code: 0
- data:
- run_summary:
- actor: local/code_reader
- context: docs
- temperature: 0.2
- provider: anthropic
- model: claude-3.5
- inputs:
- prompt: Summarize the README
- context_files: 3
- context_size: 12.4 KB
- result_metrics:
- output: stdout
- input_tokens: 1524
- output_tokens: 842
- duration_s: 1.8
- cost: "$0.0021"
- tool_calls: 0
- timing:
- duration_ms: 1800
- messages:
- - level: ok
- text: Summary generated
- ```
-
-Running an actor with a custom temperature and skill attachment:
-
-=== "Rich"
-
-
- $ agents actor run --temperature 0.2 --skill local/code-analysis \
- local/reviewer "Review the auth module for security issues"
-
- ╭─ Actor Run ─────────────────────────╮
- │ Actor: local/reviewer │
- │ Type: agent │
- │ Temperature: 0.2 │
- │ Skill: local/code-analysis │
- ╰─────────────────────────────────────╯
-
- ╭─ Response ────────────────────────────────────────────────────────╮
- │ I identified 3 potential security concerns in the auth module: │
- │ │
- │ 1. Token expiry not validated in `validate_session()` at │
- │ src/auth/session.py:42. The JWT expiry claim is decoded but │
- │ not checked against current time. │
- │ │
- │ 2. Missing rate limiting on the `/auth/refresh` endpoint. │
- │ An attacker could brute-force refresh tokens. │
- │ │
- │ 3. Low severity: Password hashing uses bcrypt with cost=10. │
- │ Consider cost=12 for production deployments. │
- ╰───────────────────────────────────────────────────────────────────╯
-
- ╭─ Usage ──────────────╮
- │ Tokens: 2,840 │
- │ Duration: 4.2s │
- │ Cost: $0.009 │
- │ Tool Calls: 6 │
- ╰──────────────────────╯
-
- ✓ OK Actor run completed
-
-
-=== "Plain"
-
- ```
- $ agents actor run --temperature 0.2 --skill local/code-analysis \
- local/reviewer "Review the auth module for security issues"
-
- Actor Run
- Actor: local/reviewer
- Type: agent
- Temperature: 0.2
- Skill: local/code-analysis
-
- Response
- I identified 3 potential security concerns in the auth module:
-
- 1. Token expiry not validated in validate_session() at
- src/auth/session.py:42. The JWT expiry claim is decoded but
- not checked against current time.
-
- 2. Missing rate limiting on the /auth/refresh endpoint.
- An attacker could brute-force refresh tokens.
-
- 3. Low severity: Password hashing uses bcrypt with cost=10.
- Consider cost=12 for production deployments.
-
- Usage
- Tokens: 2,840
- Duration: 4.2s
- Cost: $0.009
- Tool Calls: 6
-
- [OK] Actor run completed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor run --temperature 0.2 --skill local/code-analysis local/reviewer \"Review the auth module for security issues\"",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actor_run": {
- "actor": "local/reviewer",
- "type": "agent",
- "temperature": 0.2,
- "skill": "local/code-analysis"
- },
- "response": {
- "text": "I identified 3 potential security concerns in the auth module:\n\n1. Token expiry not validated in validate_session() at src/auth/session.py:42. The JWT expiry claim is decoded but not checked against current time.\n\n2. Missing rate limiting on the /auth/refresh endpoint. An attacker could brute-force refresh tokens.\n\n3. Low severity: Password hashing uses bcrypt with cost=10. Consider cost=12 for production deployments.",
- "issues_found": 3
- },
- "usage": {
- "tokens": 2840,
- "duration_s": 4.2,
- "cost": "$0.009",
- "tool_calls": 6
- }
- },
- "timing": {
- "duration_ms": 4200
- },
- "messages": [
- { "level": "ok", "text": "Actor run completed" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: >-
- agents actor run --temperature 0.2 --skill local/code-analysis
- local/reviewer "Review the auth module for security issues"
- status: ok
- exit_code: 0
- data:
- actor_run:
- actor: local/reviewer
- type: agent
- temperature: 0.2
- skill: local/code-analysis
- response:
- text: >-
- I identified 3 potential security concerns in the auth module:
-
- 1. Token expiry not validated in validate_session() at
- src/auth/session.py:42. The JWT expiry claim is decoded but
- not checked against current time.
-
- 2. Missing rate limiting on the /auth/refresh endpoint.
- An attacker could brute-force refresh tokens.
-
- 3. Low severity: Password hashing uses bcrypt with cost=10.
- Consider cost=12 for production deployments.
- issues_found: 3
- usage:
- tokens: 2840
- duration_s: 4.2
- cost: "$0.009"
- tool_calls: 6
- timing:
- duration_ms: 4200
- messages:
- - level: ok
- text: Actor run completed
- ```
-
-Saving actor output to a file:
-
-=== "Rich"
-
-
- $ agents actor run --output review.md local/reviewer "Write a code review report"
-
- ╭─ Actor Run ───────────────╮
- │ Actor: local/reviewer │
- │ Output: review.md │
- │ Tokens: 4,120 │
- │ Duration: 6.8s │
- ╰───────────────────────────╯
-
- ✓ OK Output written to review.md (2.4 KB)
-
-
-=== "Plain"
-
- ```
- $ agents actor run --output review.md local/reviewer "Write a code review report"
-
- Actor Run
- Actor: local/reviewer
- Output: review.md
- Tokens: 4,120
- Duration: 6.8s
-
- [OK] Output written to review.md (2.4 KB)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor run --output review.md local/reviewer \"Write a code review report\"",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actor_run": {
- "actor": "local/reviewer",
- "output": "review.md",
- "tokens": 4120,
- "duration_s": 6.8
- }
- },
- "timing": {
- "duration_ms": 6800
- },
- "messages": [
- { "level": "ok", "text": "Output written to review.md (2.4 KB)" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor run --output review.md local/reviewer "Write a code review report"
- status: ok
- exit_code: 0
- data:
- actor_run:
- actor: local/reviewer
- output: review.md
- tokens: 4120
- duration_s: 6.8
- timing:
- duration_ms: 6800
- messages:
- - level: ok
- text: Output written to review.md (2.4 KB)
- ```
-
-##### agents actor add
-
-agents actor add --config|-c <FILE> [--update]
-
-**Purpose**
-Add a new actor configuration, or replace an existing one with `--update`. The actor is fully defined by the YAML configuration file specified with `--config`. If a local actor with the same name already exists, the command fails unless the `--update` flag is provided, which replaces the existing actor.
-
-**Arguments**
-
-- `--config/-c FILE`: Actor config file (required). The file must fully define the actor, including the `name` field which determines the actor's registered name.
-- `--update`: Replace an existing local actor with the same name. Without this flag, attempting to add an actor whose name is already registered will fail.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor add --config ./actors/reviewer.yaml
-
- ╭─ Actor Added ────────╮
- │ Name: local/reviewer │
- │ Provider: openai │
- │ Model: gpt-4 │
- │ Default: yes │
- │ Unsafe: no │
- │ Type: graph │
- ╰──────────────────────╯
-
- ╭─ Config ─────────────────────╮
- │ Path: ./actors/reviewer.yaml │
- │ Hash: 8b3f3d2 │
- │ Options: 4 │
- │ Nodes: 3 │
- │ Edges: 4 │
- ╰──────────────────────────────╯
-
- ╭─ Capabilities ───────╮
- │ - code review │
- │ - diff summarization │
- │ - lint guidance │
- ╰──────────────────────╯
-
- ╭─ Tools ────────────────────────╮
- │ Tool Read-Only Safe │
- │ ──────────── ───────── ──── │
- │ read_file yes yes │
- │ search_files yes yes │
- │ git_diff yes yes │
- ╰────────────────────────────────╯
-
- ✓ OK Actor added
-
-
-=== "Plain"
-
- ```
- $ agents actor add --config ./actors/reviewer.yaml
-
- Actor Added
- Name: local/reviewer
- Provider: openai
- Model: gpt-4
- Default: yes
- Unsafe: no
- Type: graph
-
- Config
- Path: ./actors/reviewer.yaml
- Hash: 8b3f3d2
- Options: 4
- Nodes: 3
- Edges: 4
-
- Capabilities
- - code review
- - diff summarization
- - lint guidance
-
- Tools
- Tool Read-Only Safe
- ------------ --------- ----
- read_file yes yes
- search_files yes yes
- git_diff yes yes
-
- [OK] Actor added
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor add --config ./actors/reviewer.yaml",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actor_added": {
- "name": "local/reviewer",
- "provider": "openai",
- "model": "gpt-4",
- "default": true,
- "unsafe": false,
- "type": "graph"
- },
- "config": {
- "path": "./actors/reviewer.yaml",
- "hash": "8b3f3d2",
- "options": 4,
- "nodes": 3,
- "edges": 4
- },
- "capabilities": [
- "code review",
- "diff summarization",
- "lint guidance"
- ],
- "tools": [
- { "tool": "read_file", "read_only": true, "safe": true },
- { "tool": "search_files", "read_only": true, "safe": true },
- { "tool": "git_diff", "read_only": true, "safe": true }
- ]
- },
- "timing": {
- "duration_ms": 95
- },
- "messages": [
- { "level": "ok", "text": "Actor added" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor add --config ./actors/reviewer.yaml
- status: ok
- exit_code: 0
- data:
- actor_added:
- name: local/reviewer
- provider: openai
- model: gpt-4
- default: true
- unsafe: false
- type: graph
- config:
- path: ./actors/reviewer.yaml
- hash: 8b3f3d2
- options: 4
- nodes: 3
- edges: 4
- capabilities:
- - code review
- - diff summarization
- - lint guidance
- tools:
- - tool: read_file
- read_only: true
- safe: true
- - tool: search_files
- read_only: true
- safe: true
- - tool: git_diff
- read_only: true
- safe: true
- timing:
- duration_ms: 95
- messages:
- - level: ok
- text: Actor added
- ```
-
-Attempting to register an actor that already exists (without `--update`):
-
-=== "Rich"
-
-
- $ agents actor add --config ./actors/reviewer.yaml
-
- ╭─ Error ─────────────────────────────────────────────────╮
- │ Actor already exists: local/reviewer │
- │ Registered: 2026-02-07 14:22 │
- │ Use --update to replace the existing actor definition. │
- ╰─────────────────────────────────────────────────────────╯
-
- ✗ ERROR Actor already registered — use --update to replace
-
-
-=== "Plain"
-
- ```
- $ agents actor add --config ./actors/reviewer.yaml
-
- Error
- Actor already exists: local/reviewer
- Registered: 2026-02-07 14:22
- Use --update to replace the existing actor definition.
-
- [ERROR] Actor already registered -- use --update to replace
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor add --config ./actors/reviewer.yaml",
- "status": "error",
- "exit_code": 1,
- "data": {
- "error": {
- "message": "Actor already exists: local/reviewer",
- "registered": "2026-02-07T14:22:00Z",
- "hint": "Use --update to replace the existing actor definition."
- }
- },
- "timing": {
- "duration_ms": 42
- },
- "messages": [
- { "level": "error", "text": "Actor already registered -- use --update to replace" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor add --config ./actors/reviewer.yaml
- status: error
- exit_code: 1
- data:
- error:
- message: "Actor already exists: local/reviewer"
- registered: "2026-02-07T14:22:00Z"
- hint: Use --update to replace the existing actor definition.
- timing:
- duration_ms: 42
- messages:
- - level: error
- text: Actor already registered -- use --update to replace
- ```
-
-Updating an existing actor with `--update`:
-
-=== "Rich"
-
-
- $ agents actor add --config ./actors/reviewer.yaml --update
-
- ╭─ Actor Updated ─────────────────────╮
- │ Name: local/reviewer │
- │ Type: agent │
- │ Status: updated │
- ╰─────────────────────────────────────╯
-
- ╭─ Changes ────────────────────────────╮
- │ Skills: +1 (local/code-analysis) │
- │ Model: unchanged │
- │ Graph: updated │
- ╰──────────────────────────────────────╯
-
- ✓ OK Actor updated
-
-
-=== "Plain"
-
- ```
- $ agents actor add --config ./actors/reviewer.yaml --update
-
- Actor Updated
- Name: local/reviewer
- Type: agent
- Status: updated
-
- Changes
- Skills: +1 (local/code-analysis)
- Model: unchanged
- Graph: updated
-
- [OK] Actor updated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor add --config ./actors/reviewer.yaml --update",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actor_updated": {
- "name": "local/reviewer",
- "type": "agent",
- "status": "updated"
- },
- "changes": {
- "skills": "+1 (local/code-analysis)",
- "model": "unchanged",
- "graph": "updated"
- }
- },
- "timing": {
- "duration_ms": 88
- },
- "messages": [
- { "level": "ok", "text": "Actor updated" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor add --config ./actors/reviewer.yaml --update
- status: ok
- exit_code: 0
- data:
- actor_updated:
- name: local/reviewer
- type: agent
- status: updated
- changes:
- skills: "+1 (local/code-analysis)"
- model: unchanged
- graph: updated
- timing:
- duration_ms: 88
- messages:
- - level: ok
- text: Actor updated
- ```
-
-##### agents actor remove
-
-agents actor remove <NAME>
-
-!!! warning "Destructive Operation"
- Removes a custom actor registration. Active plans and actions referencing this actor will lose their actor binding. Check the **Impact** section in the output to verify no active plans or sessions are affected.
-
-**Arguments**
-
-- ``: Actor name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor remove local/reviewer
-
- ╭─ Actor Removed ──────╮
- │ Name: local/reviewer │
- │ Provider: openai │
- │ Model: gpt-4 │
- ╰──────────────────────╯
-
- ╭─ Impact ───────────────────────────────────╮
- │ Sessions: 0 affected │
- │ Active Plans: 0 affected │
- │ Actions Referencing: 0 │
- ╰────────────────────────────────────────────╯
-
- ╭─ Cleanup ──────────────╮
- │ Config: kept on disk │
- │ Contexts: 1 orphaned │
- ╰────────────────────────╯
-
- ✓ OK Actor removed
-
-
-=== "Plain"
-
- ```
- $ agents actor remove local/reviewer
-
- Actor Removed
- Name: local/reviewer
- Provider: openai
- Model: gpt-4
-
- Impact
- Sessions: 0 affected
- Active Plans: 0 affected
- Actions Referencing: 0
-
- Cleanup
- Config: kept on disk
- Contexts: 1 orphaned
-
- [OK] Actor removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor remove local/reviewer",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actor_removed": {
- "name": "local/reviewer",
- "provider": "openai",
- "model": "gpt-4"
- },
- "impact": {
- "sessions": 0,
- "active_plans": 0,
- "actions_referencing": 0
- },
- "cleanup": {
- "config": "kept on disk",
- "contexts": "1 orphaned"
- }
- },
- "timing": {
- "duration_ms": 65
- },
- "messages": [
- { "level": "ok", "text": "Actor removed" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor remove local/reviewer
- status: ok
- exit_code: 0
- data:
- actor_removed:
- name: local/reviewer
- provider: openai
- model: gpt-4
- impact:
- sessions: 0
- active_plans: 0
- actions_referencing: 0
- cleanup:
- config: kept on disk
- contexts: 1 orphaned
- timing:
- duration_ms: 65
- messages:
- - level: ok
- text: Actor removed
- ```
-
-##### agents actor list
-
-
-
-**Purpose**
-List all actors.
-
-**Arguments**
-
-None.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor list
-
- ╭─ Actors ──────────────────────────────────────────────────────────────╮
- │ Name Provider Model Default Built-in Unsafe │
- │ ────────────── ───────── ────────── ─────── ──────── ────── │
- │ local/reviewer openai gpt-4 ✓ no │
- │ openai/gpt-4 openai gpt-4 ✓ no │
- │ anthropic/3.5 anthropic claude-3.5 ✓ no │
- ╰───────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ──────────────╮
- │ Total: 3 │
- │ Built-in: 2 │
- │ Custom: 1 │
- │ Unsafe: 0 │
- │ Providers Used: 2 │
- ╰────────────────────────╯
-
- ✓ OK 3 actors listed
-
-
-=== "Plain"
-
- ```
- $ agents actor list
-
- Actors
- Name Provider Model Default Built-in Unsafe
- -------------- --------- ---------- ------- -------- ------
- local/reviewer openai gpt-4 yes no
- openai/gpt-4 openai gpt-4 yes no
- anthropic/3.5 anthropic claude-3.5 yes no
-
- Summary
- Total: 3
- Built-in: 2
- Custom: 1
- Unsafe: 0
- Providers Used: 2
-
- [OK] 3 actors listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actors": [
- {
- "name": "local/reviewer",
- "provider": "openai",
- "model": "gpt-4",
- "default": true,
- "builtin": false,
- "unsafe": false
- },
- {
- "name": "openai/gpt-4",
- "provider": "openai",
- "model": "gpt-4",
- "default": false,
- "builtin": true,
- "unsafe": false
- },
- {
- "name": "anthropic/3.5",
- "provider": "anthropic",
- "model": "claude-3.5",
- "default": false,
- "builtin": true,
- "unsafe": false
- }
- ],
- "summary": {
- "total": 3,
- "builtin": 2,
- "custom": 1,
- "unsafe": 0,
- "providers_used": 2
- }
- },
- "timing": {
- "duration_ms": 55
- },
- "messages": [
- { "level": "ok", "text": "3 actors listed" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor list
- status: ok
- exit_code: 0
- data:
- actors:
- - name: local/reviewer
- provider: openai
- model: gpt-4
- default: true
- builtin: false
- unsafe: false
- - name: openai/gpt-4
- provider: openai
- model: gpt-4
- default: false
- builtin: true
- unsafe: false
- - name: anthropic/3.5
- provider: anthropic
- model: claude-3.5
- default: false
- builtin: true
- unsafe: false
- summary:
- total: 3
- builtin: 2
- custom: 1
- unsafe: 0
- providers_used: 2
- timing:
- duration_ms: 55
- messages:
- - level: ok
- text: 3 actors listed
- ```
-
-##### agents actor show
-
-
-
-**Purpose**
-Show details for a single actor.
-
-**Arguments**
-
-- ``: Actor name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor show local/reviewer
-
- ╭─ Actor Details ────────────────────╮
- │ Name: local/reviewer │
- │ Provider: openai │
- │ Model: gpt-4 │
- │ Default: yes │
- │ Built-in: no │
- │ Unsafe: no │
- │ Type: graph │
- │ Created: 2026-02-08 12:35 │
- │ Updated: 2026-02-08 12:40 │
- │ Config: ./actors/reviewer.yaml │
- │ Config Hash: 9c4e2a1 │
- ╰────────────────────────────────────╯
-
- ╭─ Options ──────────╮
- │ - temperature: 0.2 │
- │ - max_tokens: 2048 │
- │ - top_p: 1.0 │
- ╰────────────────────╯
-
- ╭─ Graph Structure ─╮
- │ Nodes: 3 │
- │ Edges: 4 │
- │ Entry: analyze │
- │ Exit: report │
- ╰───────────────────╯
-
- ╭─ Tools ────────────────────────╮
- │ Tool Read-Only Safe │
- │ ──────────── ───────── ──── │
- │ read_file yes yes │
- │ search_files yes yes │
- │ git_diff yes yes │
- ╰────────────────────────────────╯
-
- ╭─ Access ────────────╮
- │ Unsafe: no │
- │ Filesystem: allowed │
- │ Network: restricted │
- ╰─────────────────────╯
-
- ╭─ Usage ─────────────────────────────────────────╮
- │ Referenced by Actions: 1 (local/code-coverage) │
- │ Active in Sessions: 0 │
- │ Total Runs: 14 │
- │ Avg Cost/Run: $0.0032 │
- ╰─────────────────────────────────────────────────╯
-
- ✓ OK Actor loaded
-
-
-=== "Plain"
-
- ```
- $ agents actor show local/reviewer
-
- Actor Details
- Name: local/reviewer
- Provider: openai
- Model: gpt-4
- Default: yes
- Built-in: no
- Unsafe: no
- Type: graph
- Created: 2026-02-08 12:35
- Updated: 2026-02-08 12:40
- Config: ./actors/reviewer.yaml
- Config Hash: 9c4e2a1
-
- Options
- - temperature: 0.2
- - max_tokens: 2048
- - top_p: 1.0
-
- Graph Structure
- Nodes: 3
- Edges: 4
- Entry: analyze
- Exit: report
-
- Tools
- Tool Read-Only Safe
- ------------ --------- ----
- read_file yes yes
- search_files yes yes
- git_diff yes yes
-
- Access
- Unsafe: no
- Filesystem: allowed
- Network: restricted
-
- Usage
- Referenced by Actions: 1 (local/code-coverage)
- Active in Sessions: 0
- Total Runs: 14
- Avg Cost/Run: $0.0032
-
- [OK] Actor loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor show local/reviewer",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actor_details": {
- "name": "local/reviewer",
- "provider": "openai",
- "model": "gpt-4",
- "default": true,
- "builtin": false,
- "unsafe": false,
- "type": "graph",
- "created": "2026-02-08T12:35:00Z",
- "updated": "2026-02-08T12:40:00Z",
- "config": "./actors/reviewer.yaml",
- "config_hash": "9c4e2a1"
- },
- "options": {
- "temperature": 0.2,
- "max_tokens": 2048,
- "top_p": 1.0
- },
- "graph_structure": {
- "nodes": 3,
- "edges": 4,
- "entry": "analyze",
- "exit": "report"
- },
- "tools": [
- { "tool": "read_file", "read_only": true, "safe": true },
- { "tool": "search_files", "read_only": true, "safe": true },
- { "tool": "git_diff", "read_only": true, "safe": true }
- ],
- "access": {
- "unsafe": false,
- "filesystem": "allowed",
- "network": "restricted"
- },
- "usage": {
- "referenced_by_actions": "1 (local/code-coverage)",
- "active_in_sessions": 0,
- "total_runs": 14,
- "avg_cost_per_run": "$0.0032"
- }
- },
- "timing": {
- "duration_ms": 78
- },
- "messages": [
- { "level": "ok", "text": "Actor loaded" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor show local/reviewer
- status: ok
- exit_code: 0
- data:
- actor_details:
- name: local/reviewer
- provider: openai
- model: gpt-4
- default: true
- builtin: false
- unsafe: false
- type: graph
- created: "2026-02-08T12:35:00Z"
- updated: "2026-02-08T12:40:00Z"
- config: ./actors/reviewer.yaml
- config_hash: 9c4e2a1
- options:
- temperature: 0.2
- max_tokens: 2048
- top_p: 1.0
- graph_structure:
- nodes: 3
- edges: 4
- entry: analyze
- exit: report
- tools:
- - tool: read_file
- read_only: true
- safe: true
- - tool: search_files
- read_only: true
- safe: true
- - tool: git_diff
- read_only: true
- safe: true
- access:
- unsafe: false
- filesystem: allowed
- network: restricted
- usage:
- referenced_by_actions: 1 (local/code-coverage)
- active_in_sessions: 0
- total_runs: 14
- avg_cost_per_run: "$0.0032"
- timing:
- duration_ms: 78
- messages:
- - level: ok
- text: Actor loaded
- ```
-
-##### agents actor context
-
-**Purpose**
-Manage manual context for actor runs. These commands mirror the legacy context behavior but are scoped to an actor context name.
-
-###### agents actor context remove
-
-agents actor context remove [--yes|-y] (--all|-a|<NAME>)
-
-!!! warning "Context Data Loss"
- Remove files or directories from an actor context. Use `--all` to clear all contexts at once. Context data is not recoverable after removal.
-
-**Arguments**
-
-- ``: Context name (positional argument). Use --all/-a to target all contexts.
-- `--all, -a`: Target all contexts instead of a named one.
-- `--yes, -y`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor context remove docs
-
- ╭─ Context Removed ───────────╮
- │ Context: docs │
- │ Status: removed │
- ╰─────────────────────────────╯
-
- ╭─ Stats ───────────────────╮
- │ Remaining Size: 48 KB │
- │ Updated: 2026-02-08 13:06 │
- ╰───────────────────────────╯
-
- ✓ OK Context updated
-
-
-=== "Plain"
-
- ```
- $ agents actor context remove docs
-
- Context Removed
- Context: docs
- Status: removed
-
- Stats
- Remaining Size: 48 KB
- Updated: 2026-02-08 13:06
-
- [OK] Context updated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor context remove docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_removed": {
- "context": "docs",
- "status": "removed"
- },
- "stats": {
- "remaining_size_kb": 48,
- "updated": "2026-02-08T13:06:00Z"
- }
- },
- "timing": { "duration_ms": 65 },
- "messages": [{ "level": "ok", "text": "Context updated" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor context remove docs
- status: ok
- exit_code: 0
- data:
- context_removed:
- context: docs
- status: removed
- stats:
- remaining_size_kb: 48
- updated: "2026-02-08T13:06:00Z"
- timing:
- duration_ms: 65
- messages:
- - level: ok
- text: Context updated
- ```
-
-###### agents actor context list
-
-agents actor context list [<REGEX>]
-
-**Purpose**
-List files stored in an actor context.
-
-**Arguments**
-
-- `[REGEX]`: Optional regex filter for context names.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor context list docs
-
- ╭─ Context Files ──────────────────────────────╮
- │ Name Type Size Added │
- │ ──────────────── ──── ─────── ────────── │
- │ README.md file 4.2 KB 02-08 12:10 │
- │ docs/overview.md file 12.8 KB 02-08 12:10 │
- │ docs/cli.md file 9.5 KB 02-08 12:10 │
- ╰──────────────────────────────────────────────╯
-
- ╭─ Stats ───────────────────────╮
- │ Total Files: 3 │
- │ Total Size: 26.5 KB │
- │ Estimated Tokens: ~6,600 │
- │ Languages: Markdown │
- ╰───────────────────────────────╯
-
- ✓ OK 3 files listed
-
-
-=== "Plain"
-
- ```
- $ agents actor context list docs
-
- Context Files
- Name Type Size Added
- ---------------- ---- ------- ----------
- README.md file 4.2 KB 02-08 12:10
- docs/overview.md file 12.8 KB 02-08 12:10
- docs/cli.md file 9.5 KB 02-08 12:10
-
- Stats
- Total Files: 3
- Total Size: 26.5 KB
- Estimated Tokens: ~6,600
- Languages: Markdown
-
- [OK] 3 files listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor context list docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_files": [
- { "name": "README.md", "type": "file", "size_kb": 4.2, "added": "2026-02-08T12:10:00Z" },
- { "name": "docs/overview.md", "type": "file", "size_kb": 12.8, "added": "2026-02-08T12:10:00Z" },
- { "name": "docs/cli.md", "type": "file", "size_kb": 9.5, "added": "2026-02-08T12:10:00Z" }
- ],
- "stats": {
- "total_files": 3,
- "total_size_kb": 26.5,
- "estimated_tokens": 6600,
- "languages": ["Markdown"]
- }
- },
- "timing": { "duration_ms": 35 },
- "messages": [{ "level": "ok", "text": "3 files listed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor context list docs
- status: ok
- exit_code: 0
- data:
- context_files:
- - name: README.md
- type: file
- size_kb: 4.2
- added: "2026-02-08T12:10:00Z"
- - name: docs/overview.md
- type: file
- size_kb: 12.8
- added: "2026-02-08T12:10:00Z"
- - name: docs/cli.md
- type: file
- size_kb: 9.5
- added: "2026-02-08T12:10:00Z"
- stats:
- total_files: 3
- total_size_kb: 26.5
- estimated_tokens: 6600
- languages:
- - Markdown
- timing:
- duration_ms: 35
- messages:
- - level: ok
- text: 3 files listed
- ```
-
-###### agents actor context show
-
-agents actor context show <NAME>
-
-**Purpose**
-Show content of a file in an actor context.
-
-**Arguments**
-
-- ``: Context name (positional argument).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor context show docs
-
- ╭─ Context Summary ───────────╮
- │ Context: docs │
- │ Files: 3 │
- │ Total Size: 26.5 KB │
- │ Estimated Tokens: ~6,600 │
- │ Created: 2026-02-08 12:10 │
- ╰─────────────────────────────╯
-
- ✓ OK Context displayed
-
-
-=== "Plain"
-
- ```
- $ agents actor context show docs
-
- Context Summary
- Context: docs
- Files: 3
- Total Size: 26.5 KB
- Estimated Tokens: ~6,600
- Created: 2026-02-08 12:10
-
- [OK] Context displayed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor context show docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_summary": {
- "context": "docs",
- "files": 3,
- "total_size_kb": 26.5,
- "estimated_tokens": 6600,
- "created": "2026-02-08T12:10:00Z"
- }
- },
- "timing": { "duration_ms": 45 },
- "messages": [{ "level": "ok", "text": "Context displayed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor context show docs
- status: ok
- exit_code: 0
- data:
- context_summary:
- context: docs
- files: 3
- total_size_kb: 26.5
- estimated_tokens: 6600
- created: "2026-02-08T12:10:00Z"
- timing:
- duration_ms: 45
- messages:
- - level: ok
- text: Context displayed
- ```
-
-###### agents actor context export
-
-agents actor context export (--output|-o) <FILE> <NAME>
-
-**Purpose**
-Export a context as JSON.
-
-**Arguments**
-
-- ``: Context name (positional argument).
-- `--output/-o FILE`: Output file path (required).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor context export --output /tmp/docs-context.json docs
-
- ╭─ Context Export ───────────────╮
- │ Context: docs │
- │ Output: /tmp/docs-context.json │
- │ Items: 12 │
- │ Size: 48 KB │
- ╰────────────────────────────────╯
-
- ╭─ Integrity ──────────────────╮
- │ Checksum: sha256:19b2...a7d0 │
- │ Compressed: no │
- ╰──────────────────────────────╯
-
- ✓ OK Export completed
-
-
-=== "Plain"
-
- ```
- $ agents actor context export --output /tmp/docs-context.json docs
-
- Context Export
- Context: docs
- Output: /tmp/docs-context.json
- Items: 12
- Size: 48 KB
-
- Integrity
- Checksum: sha256:19b2...a7d0
- Compressed: no
-
- [OK] Export completed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor context export --output /tmp/docs-context.json docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_export": {
- "context": "docs",
- "output": "/tmp/docs-context.json",
- "items": 12,
- "size_kb": 48
- },
- "integrity": {
- "checksum": "sha256:19b2...a7d0",
- "compressed": false
- }
- },
- "timing": { "duration_ms": 180 },
- "messages": [{ "level": "ok", "text": "Export completed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor context export --output /tmp/docs-context.json docs
- status: ok
- exit_code: 0
- data:
- context_export:
- context: docs
- output: /tmp/docs-context.json
- items: 12
- size_kb: 48
- integrity:
- checksum: "sha256:19b2...a7d0"
- compressed: false
- timing:
- duration_ms: 180
- messages:
- - level: ok
- text: Export completed
- ```
-
-###### agents actor context import
-
-agents actor context import [--update] (--input|-i) <FILE> [<NAME>]
-
-**Purpose**
-Import a context from JSON.
-
-**Arguments**
-
-- `[NAME]`: Context name (optional, inferred from file if omitted).
-- `--input/-i FILE`: Input JSON file (required).
-- `--update`: Replace an existing context with the same name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor context import --input /tmp/docs-context.json docs
-
- ╭─ Context Import ──────────────╮
- │ Context: docs │
- │ Input: /tmp/docs-context.json │
- │ Items: 12 │
- ╰───────────────────────────────╯
-
- ╭─ Merge ───────────╮
- │ Strategy: replace │
- │ Conflicts: 0 │
- ╰───────────────────╯
-
- ✓ OK Import completed
-
-
-=== "Plain"
-
- ```
- $ agents actor context import --input /tmp/docs-context.json docs
-
- Context Import
- Context: docs
- Input: /tmp/docs-context.json
- Items: 12
-
- Merge
- Strategy: replace
- Conflicts: 0
-
- [OK] Import completed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor context import --input /tmp/docs-context.json docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_import": {
- "context": "docs",
- "input": "/tmp/docs-context.json",
- "items": 12
- },
- "merge": {
- "strategy": "replace",
- "conflicts": 0
- }
- },
- "timing": { "duration_ms": 210 },
- "messages": [{ "level": "ok", "text": "Import completed" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor context import --input /tmp/docs-context.json docs
- status: ok
- exit_code: 0
- data:
- context_import:
- context: docs
- input: /tmp/docs-context.json
- items: 12
- merge:
- strategy: replace
- conflicts: 0
- timing:
- duration_ms: 210
- messages:
- - level: ok
- text: Import completed
- ```
-
-###### agents actor context clear
-
-agents actor context clear [--yes|-y] (--all|-a|<NAME>)
-
-**Purpose**
-Clear all files from a context but keep the context itself.
-
-**Arguments**
-
-- ``: Context name (positional argument). Use --all/-a to target all contexts.
-- `--all, -a`: Target all contexts instead of a named one.
-- `--yes, -y`: Skip confirmation.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents actor context clear docs
-
- Clear context docs? [y/N]: y
-
- ╭─ Context Cleared ────╮
- │ Context: docs │
- │ Items: 12 removed │
- │ Storage: 48 KB freed │
- ╰──────────────────────╯
-
- ╭─ Retention ────────╮
- │ Context: preserved │
- │ Files: removed │
- ╰────────────────────╯
-
- ✓ OK Context cleared
-
-
-=== "Plain"
-
- ```
- $ agents actor context clear docs
-
- Clear context docs? [y/N]: y
-
- Context Cleared
- Context: docs
- Items: 12 removed
- Storage: 48 KB freed
-
- Retention
- Context: preserved
- Files: removed
-
- [OK] Context cleared
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "agents actor context clear docs",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "context_cleared": {
- "context": "docs",
- "items": "12 removed",
- "storage": "48 KB freed"
- },
- "retention": {
- "context": "preserved",
- "files": "removed"
- }
- },
- "timing": { "duration_ms": 85 },
- "messages": [{ "level": "ok", "text": "Context cleared" }]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: agents actor context clear docs
- status: ok
- exit_code: 0
- data:
- context_cleared:
- context: docs
- items: 12 removed
- storage: 48 KB freed
- retention:
- context: preserved
- files: removed
- timing:
- duration_ms: 85
- messages:
- - level: ok
- text: Context cleared
- ```
-
-#### agents skill
-
-!!! info "Purpose"
-
- Manage skills — reusable, namespaced collections of tools. Skills are defined in their own YAML configuration files and registered in the system through these commands. Once registered, skills can be referenced by actors.
-
-##### agents skill add
-
-agents skill add --config|-c <FILE> [--update]
-
-**Purpose**
-Register a new skill. The skill is fully defined by the YAML configuration file specified with `--config`. If a skill with the same name already exists, the command fails unless the `--update` flag is provided, which allows overwriting the existing registration with the new configuration.
-
-**Arguments**
-
-- `--config/-c FILE`: Path to the skill YAML configuration file (required). The file must fully define the skill, including the `name` field which determines the skill's registered name.
-- `--update`: Allow overwriting an existing skill registration. Without this flag, attempting to add a skill whose name is already registered will fail.
-
-**Examples**
-
-Registering a new skill:
-
-=== "Rich"
-
-
- $ agents skill add --config ./skills/devops-toolkit.yaml
-
- ╭─ Skill Registered ────────────────────────╮
- │ Name: local/devops-toolkit │
- │ Description: Full-stack development tools │
- │ Config: ./skills/devops-toolkit.yaml │
- │ Created: 2026-02-08 13:10 │
- ╰───────────────────────────────────────────╯
-
- ╭─ Includes ────────────────────╮
- │ local/file-ops (registered) │
- │ local/git-ops (registered) │
- │ local/github (registered) │
- ╰───────────────────────────────╯
-
- ╭─ Tool Sources ────────────────────────────────╮
- │ Source Count Details │
- │ ───────────── ───── ─────────────────── │
- │ builtin 14 file, dir, git, shell │
- │ mcp 6 github (4), linear (2) │
- │ agent_skill 2 deploy, code-review │
- │ custom 1 run_migrations │
- │ ───────────── ───── ─────────────────── │
- │ Total: 23 │
- ╰───────────────────────────────────────────────╯
-
- ╭─ MCP Servers ────────────────────╮
- │ linear: validated (2 tools) │
- ╰──────────────────────────────────╯
-
- ✓ OK Skill registered with 23 tools
-
-
-=== "Plain"
-
- ```
- $ agents skill add --config ./skills/devops-toolkit.yaml
-
- Skill Registered
- Name: local/devops-toolkit
- Description: Full-stack development tools
- Config: ./skills/devops-toolkit.yaml
- Created: 2026-02-08 13:10
-
- Includes
- local/file-ops (registered)
- local/git-ops (registered)
- local/github (registered)
-
- Tool Sources
- Source Count Details
- ------------- ----- -------------------
- builtin 14 file, dir, git, shell
- mcp 6 github (4), linear (2)
- agent_skill 2 deploy, code-review
- custom 1 run_migrations
- ------------- ----- -------------------
- Total: 23
-
- MCP Servers
- linear: validated (2 tools)
-
- [OK] Skill registered with 23 tools
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill add --config ./skills/devops-toolkit.yaml",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "skill": {
- "name": "local/devops-toolkit",
- "description": "Full-stack development tools",
- "config": "./skills/devops-toolkit.yaml",
- "created": "2026-02-08T13:10:00Z"
- },
- "includes": [
- { "name": "local/file-ops", "status": "registered" },
- { "name": "local/git-ops", "status": "registered" },
- { "name": "local/github", "status": "registered" }
- ],
- "tool_sources": [
- { "source": "builtin", "count": 14, "details": "file, dir, git, shell" },
- { "source": "mcp", "count": 6, "details": "github (4), linear (2)" },
- { "source": "agent_skill", "count": 2, "details": "deploy, code-review" },
- { "source": "custom", "count": 1, "details": "run_migrations" }
- ],
- "total_tools": 23,
- "mcp_servers": [
- { "name": "linear", "status": "validated", "tools": 2 }
- ]
- },
- "timing": {
- "duration_ms": 150
- },
- "messages": [
- { "level": "ok", "text": "Skill registered with 23 tools" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill add --config ./skills/devops-toolkit.yaml
- status: ok
- exit_code: 0
- data:
- skill:
- name: local/devops-toolkit
- description: Full-stack development tools
- config: ./skills/devops-toolkit.yaml
- created: "2026-02-08T13:10:00Z"
- includes:
- - name: local/file-ops
- status: registered
- - name: local/git-ops
- status: registered
- - name: local/github
- status: registered
- tool_sources:
- - source: builtin
- count: 14
- details: file, dir, git, shell
- - source: mcp
- count: 6
- details: github (4), linear (2)
- - source: agent_skill
- count: 2
- details: deploy, code-review
- - source: custom
- count: 1
- details: run_migrations
- total_tools: 23
- mcp_servers:
- - name: linear
- status: validated
- tools: 2
- timing:
- duration_ms: 150
- messages:
- - level: ok
- text: Skill registered with 23 tools
- ```
-
-Attempting to add a skill that already exists (without `--update`):
-
-=== "Rich"
-
-
- $ agents skill add --config ./skills/devops-toolkit-v2.yaml
-
- ✗ Error: Skill 'local/devops-toolkit' is already registered.
-
- To overwrite the existing configuration, re-run with --update:
-
- agents skill add --config ./skills/devops-toolkit-v2.yaml --update
-
-
-=== "Plain"
-
- ```
- $ agents skill add --config ./skills/devops-toolkit-v2.yaml
-
- Error: Skill 'local/devops-toolkit' is already registered.
-
- To overwrite the existing configuration, re-run with --update:
-
- agents skill add --config ./skills/devops-toolkit-v2.yaml --update
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill add --config ./skills/devops-toolkit-v2.yaml",
- "status": "error",
- "exit_code": 1,
- "data": {
- "skill_name": "local/devops-toolkit",
- "reason": "already registered"
- },
- "timing": {
- "duration_ms": 30
- },
- "messages": [
- { "level": "error", "text": "Skill 'local/devops-toolkit' is already registered." },
- { "level": "info", "text": "To overwrite the existing configuration, re-run with --update" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill add --config ./skills/devops-toolkit-v2.yaml
- status: error
- exit_code: 1
- data:
- skill_name: local/devops-toolkit
- reason: already registered
- timing:
- duration_ms: 30
- messages:
- - level: error
- text: "Skill 'local/devops-toolkit' is already registered."
- - level: info
- text: To overwrite the existing configuration, re-run with --update
- ```
-
-Updating an existing skill with `--update`:
-
-=== "Rich"
-
-
- $ agents skill add --config ./skills/devops-toolkit-v2.yaml --update
-
- ╭─ Skill Updated ───────────────────────────╮
- │ Name: local/devops-toolkit │
- │ Description: Full-stack development tools │
- │ Updated: 2026-02-08 14:22 │
- ╰───────────────────────────────────────────╯
-
- ╭─ Changes ─────────────────────╮
- │ Tools Added: 2 │
- │ Tools Removed: 0 │
- │ Tools Modified: 1 │
- │ Includes Changed: no │
- │ MCP Servers Changed: no │
- ╰───────────────────────────────╯
-
- ╭─ Affected Actors ─────────────────────────────╮
- │ Warning: 2 actors reference this skill: │
- │ - local/code-assistant │
- │ - local/full-stack-assistant │
- │ These actors will pick up changes on next use │
- ╰───────────────────────────────────────────────╯
-
- ✓ OK Skill updated (23 → 25 tools)
-
-
-=== "Plain"
-
- ```
- $ agents skill add --config ./skills/devops-toolkit-v2.yaml --update
-
- Skill Updated
- Name: local/devops-toolkit
- Description: Full-stack development tools
- Updated: 2026-02-08 14:22
-
- Changes
- Tools Added: 2
- Tools Removed: 0
- Tools Modified: 1
- Includes Changed: no
- MCP Servers Changed: no
-
- Affected Actors
- Warning: 2 actors reference this skill:
- - local/code-assistant
- - local/full-stack-assistant
- These actors will pick up changes on next use
-
- [OK] Skill updated (23 -> 25 tools)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill add --config ./skills/devops-toolkit-v2.yaml --update",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "skill": {
- "name": "local/devops-toolkit",
- "description": "Full-stack development tools",
- "updated": "2026-02-08T14:22:00Z"
- },
- "changes": {
- "tools_added": 2,
- "tools_removed": 0,
- "tools_modified": 1,
- "includes_changed": false,
- "mcp_servers_changed": false
- },
- "affected_actors": [
- "local/code-assistant",
- "local/full-stack-assistant"
- ],
- "tool_count": {
- "before": 23,
- "after": 25
- }
- },
- "timing": {
- "duration_ms": 180
- },
- "messages": [
- { "level": "ok", "text": "Skill updated (23 -> 25 tools)" },
- { "level": "warn", "text": "2 actors reference this skill and will pick up changes on next use" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill add --config ./skills/devops-toolkit-v2.yaml --update
- status: ok
- exit_code: 0
- data:
- skill:
- name: local/devops-toolkit
- description: Full-stack development tools
- updated: "2026-02-08T14:22:00Z"
- changes:
- tools_added: 2
- tools_removed: 0
- tools_modified: 1
- includes_changed: false
- mcp_servers_changed: false
- affected_actors:
- - local/code-assistant
- - local/full-stack-assistant
- tool_count:
- before: 23
- after: 25
- timing:
- duration_ms: 180
- messages:
- - level: ok
- text: "Skill updated (23 -> 25 tools)"
- - level: warn
- text: 2 actors reference this skill and will pick up changes on next use
- ```
-
-##### agents skill remove
-
-agents skill remove [--yes|-y] <NAME>
-
-!!! warning "Cascading Impact"
- Removing a skill ==unregisters all tools== provided by that skill and closes any associated MCP server connections. Other skills that include this skill, and actors that reference it, will lose access to those tools.
-
-**Arguments**
-
-- ``: Skill name to remove.
-- `--yes`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents skill remove local/devops-toolkit
-
- Remove skill local/devops-toolkit? [y/N]: y
-
- ╭─ Skill Removed ──────────────────────╮
- │ Name: local/devops-toolkit │
- │ Tools: 23 removed from registry │
- │ MCP Servers: 1 connection closed │
- ╰──────────────────────────────────────╯
-
- ╭─ Dependency Check ─────────────────────────────────╮
- │ Warning: 1 skill includes this skill: │
- │ - local/full-stack-dev (will lose devops tools) │
- │ Warning: 2 actors reference this skill: │
- │ - local/code-assistant │
- │ - local/full-stack-assistant │
- ╰────────────────────────────────────────────────────╯
-
- ✓ OK Skill removed
-
-
-=== "Plain"
-
- ```
- $ agents skill remove local/devops-toolkit
-
- Remove skill local/devops-toolkit? [y/N]: y
-
- Skill Removed
- Name: local/devops-toolkit
- Tools: 23 removed from registry
- MCP Servers: 1 connection closed
-
- Dependency Check
- Warning: 1 skill includes this skill:
- - local/full-stack-dev (will lose devops tools)
- Warning: 2 actors reference this skill:
- - local/code-assistant
- - local/full-stack-assistant
-
- [OK] Skill removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill remove local/devops-toolkit",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "skill": {
- "name": "local/devops-toolkit",
- "tools_removed": 23,
- "mcp_servers_closed": 1
- },
- "dependency_check": {
- "including_skills": [
- { "name": "local/full-stack-dev", "impact": "will lose devops tools" }
- ],
- "referencing_actors": [
- "local/code-assistant",
- "local/full-stack-assistant"
- ]
- }
- },
- "timing": {
- "duration_ms": 95
- },
- "messages": [
- { "level": "ok", "text": "Skill removed" },
- { "level": "warn", "text": "1 skill includes this skill" },
- { "level": "warn", "text": "2 actors reference this skill" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill remove local/devops-toolkit
- status: ok
- exit_code: 0
- data:
- skill:
- name: local/devops-toolkit
- tools_removed: 23
- mcp_servers_closed: 1
- dependency_check:
- including_skills:
- - name: local/full-stack-dev
- impact: will lose devops tools
- referencing_actors:
- - local/code-assistant
- - local/full-stack-assistant
- timing:
- duration_ms: 95
- messages:
- - level: ok
- text: Skill removed
- - level: warn
- text: 1 skill includes this skill
- - level: warn
- text: 2 actors reference this skill
- ```
-
-##### agents skill list
-
-agents skill list [(--namespace|-n) <NS>] [--source <SOURCE>]
-
-**Purpose**
-List registered skills with optional filters.
-
-**Arguments**
-
-- `--namespace/-n NS`: Filter by namespace.
-- `--source SOURCE`: Filter by tool source type (mcp, agent_skill, builtin, custom).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents skill list
-
- ╭─ Skills ────────────────────────────────────────────────────────────╮
- │ Name Tools Includes Sources │
- │ ────────────────────── ───── ──────── ────────────────────── │
- │ local/file-ops 9 0 builtin │
- │ local/git-ops 4 0 builtin │
- │ local/github 4 0 mcp │
- │ local/devops-toolkit 23 3 builtin, mcp, custom │
- │ local/full-stack-dev 25 4 builtin, mcp, custom │
- ╰─────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ─────────╮
- │ Total: 5 │
- │ Local: 5 │
- │ Server: 0 │
- │ Total Tools: 28 │
- ╰───────────────────╯
-
- ✓ OK 5 skills listed
-
-
-=== "Plain"
-
- ```
- $ agents skill list
-
- Skills
- Name Tools Includes Sources
- ---------------------- ----- -------- ----------------------
- local/file-ops 9 0 builtin
- local/git-ops 4 0 builtin
- local/github 4 0 mcp
- local/devops-toolkit 23 3 builtin, mcp, custom
- local/full-stack-dev 25 4 builtin, mcp, custom
-
- Summary
- Total: 5
- Local: 5
- Server: 0
- Total Tools: 28
-
- [OK] 5 skills listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "skills": [
- { "name": "local/file-ops", "tools": 9, "includes": 0, "sources": ["builtin"] },
- { "name": "local/git-ops", "tools": 4, "includes": 0, "sources": ["builtin"] },
- { "name": "local/github", "tools": 4, "includes": 0, "sources": ["mcp"] },
- { "name": "local/devops-toolkit", "tools": 23, "includes": 3, "sources": ["builtin", "mcp", "custom"] },
- { "name": "local/full-stack-dev", "tools": 25, "includes": 4, "sources": ["builtin", "mcp", "custom"] }
- ],
- "summary": {
- "total": 5,
- "local": 5,
- "server": 0,
- "total_tools": 28
- }
- },
- "timing": {
- "duration_ms": 45
- },
- "messages": [
- { "level": "ok", "text": "5 skills listed" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill list
- status: ok
- exit_code: 0
- data:
- skills:
- - name: local/file-ops
- tools: 9
- includes: 0
- sources:
- - builtin
- - name: local/git-ops
- tools: 4
- includes: 0
- sources:
- - builtin
- - name: local/github
- tools: 4
- includes: 0
- sources:
- - mcp
- - name: local/devops-toolkit
- tools: 23
- includes: 3
- sources:
- - builtin
- - mcp
- - custom
- - name: local/full-stack-dev
- tools: 25
- includes: 4
- sources:
- - builtin
- - mcp
- - custom
- summary:
- total: 5
- local: 5
- server: 0
- total_tools: 28
- timing:
- duration_ms: 45
- messages:
- - level: ok
- text: 5 skills listed
- ```
-
-##### agents skill show
-
-
-
-**Purpose**
-Show full details for a registered skill, including its includes, tool sources, and capability summary.
-
-**Arguments**
-
-- ``: Skill name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents skill show local/devops-toolkit
-
- ╭─ Skill Details ──────────────────────────────╮
- │ Name: local/devops-toolkit │
- │ Description: Full-stack development tools │
- │ Config: ./skills/devops-toolkit.yaml │
- │ Created: 2026-02-08 13:10 │
- │ Updated: 2026-02-08 14:22 │
- ╰──────────────────────────────────────────────╯
-
- ╭─ Includes (3) ────────────────────────────╮
- │ local/file-ops → 9 tools (builtin) │
- │ local/git-ops → 4 tools (builtin) │
- │ local/github → 4 tools (mcp) │
- ╰───────────────────────────────────────────╯
-
- ╭─ Direct Tools (6) ────────────────────────────────────────╮
- │ Name Source Writes Checkpoint │
- │ ──────────────── ─────────── ────── ────────── │
- │ create_issue mcp:linear yes no │
- │ list_issues mcp:linear no — │
- │ deploy-to-staging agent_skill yes composite │
- │ code-review agent_skill no — │
- │ run_migrations custom yes transaction │
- │ shell_execute builtin yes snapshot │
- ╰───────────────────────────────────────────────────────────╯
-
- ╭─ MCP Servers (1) ───────────────────╮
- │ linear: stdio, 2 tools, connected │
- ╰─────────────────────────────────────╯
-
- ╭─ Capability Summary ──────────╮
- │ Total Tools: 23 │
- │ Read-Only: 10 │
- │ Writes: 13 │
- │ Checkpointable: 10 │
- │ Has Side Effects: 3 │
- │ Requires Approval: 1 │
- ╰───────────────────────────────╯
-
- ╭─ Referenced By ───────────────────╮
- │ Actors: local/code-assistant │
- │ Skills: local/full-stack-dev │
- ╰───────────────────────────────────╯
-
- ✓ OK Skill loaded
-
-
-=== "Plain"
-
- ```
- $ agents skill show local/devops-toolkit
-
- Skill Details
- Name: local/devops-toolkit
- Description: Full-stack development tools
- Config: ./skills/devops-toolkit.yaml
- Created: 2026-02-08 13:10
- Updated: 2026-02-08 14:22
-
- Includes (3)
- local/file-ops -> 9 tools (builtin)
- local/git-ops -> 4 tools (builtin)
- local/github -> 4 tools (mcp)
-
- Direct Tools (6)
- Name Source Writes Checkpoint
- ---------------- ----------- ------ ----------
- create_issue mcp:linear yes no
- list_issues mcp:linear no -
- deploy-to-staging agent_skill yes composite
- code-review agent_skill no -
- run_migrations custom yes transaction
- shell_execute builtin yes snapshot
-
- MCP Servers (1)
- linear: stdio, 2 tools, connected
-
- Capability Summary
- Total Tools: 23
- Read-Only: 10
- Writes: 13
- Checkpointable: 10
- Has Side Effects: 3
- Requires Approval: 1
-
- Referenced By
- Actors: local/code-assistant
- Skills: local/full-stack-dev
-
- [OK] Skill loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill show local/devops-toolkit",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "skill": {
- "name": "local/devops-toolkit",
- "description": "Full-stack development tools",
- "config": "./skills/devops-toolkit.yaml",
- "created": "2026-02-08T13:10:00Z",
- "updated": "2026-02-08T14:22:00Z"
- },
- "includes": [
- { "name": "local/file-ops", "tools": 9, "source": "builtin" },
- { "name": "local/git-ops", "tools": 4, "source": "builtin" },
- { "name": "local/github", "tools": 4, "source": "mcp" }
- ],
- "direct_tools": [
- { "name": "create_issue", "source": "mcp:linear", "writes": true, "checkpoint": "no" },
- { "name": "list_issues", "source": "mcp:linear", "writes": false, "checkpoint": null },
- { "name": "deploy-to-staging", "source": "agent_skill", "writes": true, "checkpoint": "composite" },
- { "name": "code-review", "source": "agent_skill", "writes": false, "checkpoint": null },
- { "name": "run_migrations", "source": "custom", "writes": true, "checkpoint": "transaction" },
- { "name": "shell_execute", "source": "builtin", "writes": true, "checkpoint": "snapshot" }
- ],
- "mcp_servers": [
- { "name": "linear", "transport": "stdio", "tools": 2, "status": "connected" }
- ],
- "capability_summary": {
- "total_tools": 23,
- "read_only": 10,
- "writes": 13,
- "checkpointable": 10,
- "has_side_effects": 3,
- "requires_approval": 1
- },
- "referenced_by": {
- "actors": ["local/code-assistant"],
- "skills": ["local/full-stack-dev"]
- }
- },
- "timing": {
- "duration_ms": 110
- },
- "messages": [
- { "level": "ok", "text": "Skill loaded" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill show local/devops-toolkit
- status: ok
- exit_code: 0
- data:
- skill:
- name: local/devops-toolkit
- description: Full-stack development tools
- config: ./skills/devops-toolkit.yaml
- created: "2026-02-08T13:10:00Z"
- updated: "2026-02-08T14:22:00Z"
- includes:
- - name: local/file-ops
- tools: 9
- source: builtin
- - name: local/git-ops
- tools: 4
- source: builtin
- - name: local/github
- tools: 4
- source: mcp
- direct_tools:
- - name: create_issue
- source: "mcp:linear"
- writes: true
- checkpoint: "no"
- - name: list_issues
- source: "mcp:linear"
- writes: false
- checkpoint: null
- - name: deploy-to-staging
- source: agent_skill
- writes: true
- checkpoint: composite
- - name: code-review
- source: agent_skill
- writes: false
- checkpoint: null
- - name: run_migrations
- source: custom
- writes: true
- checkpoint: transaction
- - name: shell_execute
- source: builtin
- writes: true
- checkpoint: snapshot
- mcp_servers:
- - name: linear
- transport: stdio
- tools: 2
- status: connected
- capability_summary:
- total_tools: 23
- read_only: 10
- writes: 13
- checkpointable: 10
- has_side_effects: 3
- requires_approval: 1
- referenced_by:
- actors:
- - local/code-assistant
- skills:
- - local/full-stack-dev
- timing:
- duration_ms: 110
- messages:
- - level: ok
- text: Skill loaded
- ```
-
-##### agents skill tools
-
-agents skill tools <NAME>
-
-**Purpose**
-List all tools provided by a skill, including those inherited from included skills (the flattened tool set).
-
-**Arguments**
-
-- ``: Skill name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents skill tools local/devops-toolkit
-
- ╭─ Tools for local/devops-toolkit ─────────────────────────────────────────────────────────╮
- │ Tool Source From Skill Read-Only Writes Checkpoint │
- │ ───────────────── ─────────── ────────────── ───────── ────── ────────── │
- │ read_file builtin local/file-ops ✓ — — │
- │ write_file builtin local/file-ops — ✓ file │
- │ edit_file builtin local/file-ops — ✓ file │
- │ delete_file builtin local/file-ops — ✓ file │
- │ move_file builtin local/file-ops — ✓ file │
- │ copy_file builtin local/file-ops — ✓ file │
- │ create_directory builtin local/file-ops — ✓ file │
- │ list_directory builtin local/file-ops ✓ — — │
- │ delete_directory builtin local/file-ops — ✓ file │
- │ git_status builtin local/git-ops ✓ — — │
- │ git_diff builtin local/git-ops ✓ — — │
- │ git_log builtin local/git-ops ✓ — — │
- │ git_blame builtin local/git-ops ✓ — — │
- │ create_issue mcp:github local/github — ✓ no │
- │ create_pr mcp:github local/github — ✓ no │
- │ list_repos mcp:github local/github ✓ — — │
- │ get_file_contents mcp:github local/github ✓ — — │
- │ create_issue mcp:linear (direct) — ✓ no │
- │ list_issues mcp:linear (direct) ✓ — — │
- │ run_migrations custom (direct) — ✓ transaction │
- │ deploy-to-staging agent_skill (direct) — ✓ composite │
- │ code-review agent_skill (direct) ✓ — — │
- │ shell_execute builtin (direct) — ✓ snapshot │
- ╰──────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ──────────────────╮
- │ Total: 23 │
- │ From Includes: 17 │
- │ Direct: 6 │
- │ Read-Only: 10 │
- │ Writes: 13 │
- │ Checkpointable: 10 │
- ╰────────────────────────────╯
-
- ✓ OK 23 tools listed
-
-
-=== "Plain"
-
- ```
- $ agents skill tools local/devops-toolkit
-
- Tools for local/devops-toolkit
- Tool Source From Skill Read-Only Writes Checkpoint
- ----------------- ----------- -------------- --------- ------ ----------
- read_file builtin local/file-ops yes - -
- write_file builtin local/file-ops - yes file
- edit_file builtin local/file-ops - yes file
- delete_file builtin local/file-ops - yes file
- move_file builtin local/file-ops - yes file
- copy_file builtin local/file-ops - yes file
- create_directory builtin local/file-ops - yes file
- list_directory builtin local/file-ops yes - -
- delete_directory builtin local/file-ops - yes file
- git_status builtin local/git-ops yes - -
- git_diff builtin local/git-ops yes - -
- git_log builtin local/git-ops yes - -
- git_blame builtin local/git-ops yes - -
- create_issue mcp:github local/github - yes no
- create_pr mcp:github local/github - yes no
- list_repos mcp:github local/github yes - -
- get_file_contents mcp:github local/github yes - -
- create_issue mcp:linear (direct) - yes no
- list_issues mcp:linear (direct) yes - -
- run_migrations custom (direct) - yes transaction
- deploy-to-staging agent_skill (direct) - yes composite
- code-review agent_skill (direct) yes - -
- shell_execute builtin (direct) - yes snapshot
-
- Summary
- Total: 23
- From Includes: 17
- Direct: 6
- Read-Only: 10
- Writes: 13
- Checkpointable: 10
-
- [OK] 23 tools listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "skill tools local/devops-toolkit",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "tools": [
- { "name": "read_file", "source": "builtin", "from_skill": "local/file-ops", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "write_file", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "edit_file", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "delete_file", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "move_file", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "copy_file", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "create_directory", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "list_directory", "source": "builtin", "from_skill": "local/file-ops", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "delete_directory", "source": "builtin", "from_skill": "local/file-ops", "read_only": false, "writes": true, "checkpoint": "file" },
- { "name": "git_status", "source": "builtin", "from_skill": "local/git-ops", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "git_diff", "source": "builtin", "from_skill": "local/git-ops", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "git_log", "source": "builtin", "from_skill": "local/git-ops", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "git_blame", "source": "builtin", "from_skill": "local/git-ops", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "create_issue", "source": "mcp:github", "from_skill": "local/github", "read_only": false, "writes": true, "checkpoint": "no" },
- { "name": "create_pr", "source": "mcp:github", "from_skill": "local/github", "read_only": false, "writes": true, "checkpoint": "no" },
- { "name": "list_repos", "source": "mcp:github", "from_skill": "local/github", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "get_file_contents", "source": "mcp:github", "from_skill": "local/github", "read_only": true, "writes": false, "checkpoint": null },
- { "name": "create_issue", "source": "mcp:linear", "from_skill": null, "read_only": false, "writes": true, "checkpoint": "no" },
- { "name": "list_issues", "source": "mcp:linear", "from_skill": null, "read_only": true, "writes": false, "checkpoint": null },
- { "name": "run_migrations", "source": "custom", "from_skill": null, "read_only": false, "writes": true, "checkpoint": "transaction" },
- { "name": "deploy-to-staging", "source": "agent_skill", "from_skill": null, "read_only": false, "writes": true, "checkpoint": "composite" },
- { "name": "code-review", "source": "agent_skill", "from_skill": null, "read_only": true, "writes": false, "checkpoint": null },
- { "name": "shell_execute", "source": "builtin", "from_skill": null, "read_only": false, "writes": true, "checkpoint": "snapshot" }
- ],
- "summary": {
- "total": 23,
- "from_includes": 17,
- "direct": 6,
- "read_only": 10,
- "writes": 13,
- "checkpointable": 10
- }
- },
- "timing": {
- "duration_ms": 85
- },
- "messages": [
- { "level": "ok", "text": "23 tools listed" }
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: skill tools local/devops-toolkit
- status: ok
- exit_code: 0
- data:
- tools:
- - name: read_file
- source: builtin
- from_skill: local/file-ops
- read_only: true
- writes: false
- checkpoint: null
- - name: write_file
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: edit_file
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: delete_file
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: move_file
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: copy_file
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: create_directory
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: list_directory
- source: builtin
- from_skill: local/file-ops
- read_only: true
- writes: false
- checkpoint: null
- - name: delete_directory
- source: builtin
- from_skill: local/file-ops
- read_only: false
- writes: true
- checkpoint: file
- - name: git_status
- source: builtin
- from_skill: local/git-ops
- read_only: true
- writes: false
- checkpoint: null
- - name: git_diff
- source: builtin
- from_skill: local/git-ops
- read_only: true
- writes: false
- checkpoint: null
- - name: git_log
- source: builtin
- from_skill: local/git-ops
- read_only: true
- writes: false
- checkpoint: null
- - name: git_blame
- source: builtin
- from_skill: local/git-ops
- read_only: true
- writes: false
- checkpoint: null
- - name: create_issue
- source: "mcp:github"
- from_skill: local/github
- read_only: false
- writes: true
- checkpoint: "no"
- - name: create_pr
- source: "mcp:github"
- from_skill: local/github
- read_only: false
- writes: true
- checkpoint: "no"
- - name: list_repos
- source: "mcp:github"
- from_skill: local/github
- read_only: true
- writes: false
- checkpoint: null
- - name: get_file_contents
- source: "mcp:github"
- from_skill: local/github
- read_only: true
- writes: false
- checkpoint: null
- - name: create_issue
- source: "mcp:linear"
- from_skill: null
- read_only: false
- writes: true
- checkpoint: "no"
- - name: list_issues
- source: "mcp:linear"
- from_skill: null
- read_only: true
- writes: false
- checkpoint: null
- - name: run_migrations
- source: custom
- from_skill: null
- read_only: false
- writes: true
- checkpoint: transaction
- - name: deploy-to-staging
- source: agent_skill
- from_skill: null
- read_only: false
- writes: true
- checkpoint: composite
- - name: code-review
- source: agent_skill
- from_skill: null
- read_only: true
- writes: false
- checkpoint: null
- - name: shell_execute
- source: builtin
- from_skill: null
- read_only: false
- writes: true
- checkpoint: snapshot
- summary:
- total: 23
- from_includes: 17
- direct: 6
- read_only: 10
- writes: 13
- checkpointable: 10
- timing:
- duration_ms: 85
- messages:
- - level: ok
- text: 23 tools listed
- ```
-
-#### agents tool
-
-!!! info "Purpose"
- Manage ==tools== — namespaced, independently registered, callable operations. Tools are defined in their own YAML configuration files and registered in the system through these commands. Once registered, tools can be referenced by name in skills (as part of a tool collection) and in actor graphs (as tool nodes).
-
-??? tip "Tool Lifecycle Overview"
- | Stage | Command | Description |
- | :---- | :------ | :---------- |
- | **Register** | `agents tool add` | Register from YAML config |
- | **Inspect** | `agents tool show` | View tool details and capabilities |
- | **List** | `agents tool list` | Browse registered tools |
- | **Update** | `agents tool add --update` | Re-register with updated config |
- | **Remove** | `agents tool remove` | Unregister a tool |
-
-##### agents tool add
-
-agents tool add --config|-c <FILE> [--update]
-
-**Purpose**
-Register a new tool. The tool is fully defined by the YAML configuration file specified with `--config`. If a tool with the same name already exists, the command fails unless the `--update` flag is provided, which allows overwriting the existing registration with the new configuration.
-
-**Arguments**
-
-- `--config/-c FILE`: Path to the tool YAML configuration file (required). The file must fully define the tool, including the `name` field which determines the tool's registered name.
-- `--update`: Allow overwriting an existing tool registration. Without this flag, attempting to add a tool whose name is already registered will fail.
-
-**Examples**
-
-Registering a new tool:
-
-=== "Rich"
-
-
- $ agents tool add --config ./tools/run-migrations.yaml
-
- ╭─ Tool Registered ────────────────────────────╮
- │ Name: local/run-migrations │
- │ Description: Run database migrations │
- │ Source: custom │
- │ Config: ./tools/run-migrations.yaml │
- │ Created: 2026-02-09 10:15 │
- ╰──────────────────────────────────────────────╯
-
- ╭─ Capability ─────────────────────╮
- │ Writes: true │
- │ Write Scope: database:migrations │
- │ Checkpointable: true │
- │ Checkpoint Scope: transaction │
- │ Side Effects: schema_mutation │
- ╰──────────────────────────────────╯
-
- ✓ OK Tool registered
-
-
-=== "Plain"
-
- ```
- $ agents tool add --config ./tools/run-migrations.yaml
-
- Tool Registered
- Name: local/run-migrations
- Description: Run database migrations
- Source: custom
- Config: ./tools/run-migrations.yaml
- Created: 2026-02-09 10:15
-
- Capability
- Writes: true
- Write Scope: database:migrations
- Checkpointable: true
- Checkpoint Scope: transaction
- Side Effects: schema_mutation
-
- [OK] Tool registered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "tool_registered": {
- "name": "local/run-migrations",
- "description": "Run database migrations",
- "source": "custom",
- "config": "./tools/run-migrations.yaml",
- "created": "2026-02-09T10:15:00Z"
- },
- "capability": {
- "writes": true,
- "write_scope": "database:migrations",
- "checkpointable": true,
- "checkpoint_scope": "transaction",
- "side_effects": ["schema_mutation"]
- }
- },
- "timing": { "duration_ms": 58 },
- "messages": ["Tool registered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool add
- status: ok
- exit_code: 0
- data:
- tool_registered:
- name: local/run-migrations
- description: Run database migrations
- source: custom
- config: ./tools/run-migrations.yaml
- created: "2026-02-09T10:15:00Z"
- capability:
- writes: true
- write_scope: "database:migrations"
- checkpointable: true
- checkpoint_scope: transaction
- side_effects:
- - schema_mutation
- timing:
- duration_ms: 58
- messages:
- - Tool registered
- ```
-
-Attempting to add a tool that already exists (without `--update`):
-
-=== "Rich"
-
-
- $ agents tool add --config ./tools/run-migrations-v2.yaml
-
- ✗ Error: Tool 'local/run-migrations' is already registered.
-
- To overwrite the existing configuration, re-run with --update:
-
- agents tool add --config ./tools/run-migrations-v2.yaml --update
-
-
-=== "Plain"
-
- ```
- $ agents tool add --config ./tools/run-migrations-v2.yaml
-
- [ERROR] Tool 'local/run-migrations' is already registered.
-
- To overwrite the existing configuration, re-run with --update:
-
- agents tool add --config ./tools/run-migrations-v2.yaml --update
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool add",
- "status": "error",
- "exit_code": 1,
- "data": {
- "error": "Tool 'local/run-migrations' is already registered.",
- "hint": "To overwrite the existing configuration, re-run with --update",
- "suggested_command": "agents tool add --config ./tools/run-migrations-v2.yaml --update"
- },
- "timing": { "duration_ms": 12 },
- "messages": ["Tool 'local/run-migrations' is already registered."]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool add
- status: error
- exit_code: 1
- data:
- error: "Tool 'local/run-migrations' is already registered."
- hint: "To overwrite the existing configuration, re-run with --update"
- suggested_command: "agents tool add --config ./tools/run-migrations-v2.yaml --update"
- timing:
- duration_ms: 12
- messages:
- - "Tool 'local/run-migrations' is already registered."
- ```
-
-Updating an existing tool with `--update`:
-
-=== "Rich"
-
-
- $ agents tool add --config ./tools/db-migrate.yaml --update
-
- ╭─ Tool Updated ─────────────────────────────╮
- │ Name: local/db-migrate │
- │ Source: custom (Python) │
- │ Status: updated (was version 1 → now 2) │
- ╰────────────────────────────────────────────╯
-
- ╭─ Changes ─────────────────────────────────────╮
- │ Input Schema: modified (added batch_size) │
- │ Capabilities: unchanged (writes, checkpoint) │
- │ Description: updated │
- ╰───────────────────────────────────────────────╯
-
- ╭─ References ──────────────────╮
- │ Skills: 1 (local/db-tools) │
- │ Actors: 0 │
- │ Referencing skills will use │
- │ the updated definition. │
- ╰───────────────────────────────╯
-
- ✓ OK Tool updated
-
-
-=== "Plain"
-
- ```
- $ agents tool add --config ./tools/db-migrate.yaml --update
-
- Tool Updated
- Name: local/db-migrate
- Source: custom (Python)
- Status: updated (was version 1 -> now 2)
-
- Changes
- Input Schema: modified (added batch_size)
- Capabilities: unchanged (writes, checkpoint)
- Description: updated
-
- References
- Skills: 1 (local/db-tools)
- Actors: 0
- Referencing skills will use the updated definition.
-
- [OK] Tool updated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "tool_updated": {
- "name": "local/db-migrate",
- "source": "custom",
- "source_language": "Python",
- "status": "updated",
- "previous_version": 1,
- "current_version": 2
- },
- "changes": {
- "input_schema": "modified (added batch_size)",
- "capabilities": "unchanged (writes, checkpoint)",
- "description": "updated"
- },
- "references": {
- "skills": ["local/db-tools"],
- "actors": []
- }
- },
- "timing": { "duration_ms": 45 },
- "messages": ["Tool updated"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool add
- status: ok
- exit_code: 0
- data:
- tool_updated:
- name: local/db-migrate
- source: custom
- source_language: Python
- status: updated
- previous_version: 1
- current_version: 2
- changes:
- input_schema: "modified (added batch_size)"
- capabilities: "unchanged (writes, checkpoint)"
- description: updated
- references:
- skills:
- - local/db-tools
- actors: []
- timing:
- duration_ms: 45
- messages:
- - Tool updated
- ```
-
-##### agents tool remove
-
-agents tool remove [--yes|-y] <NAME>
-
-!!! danger "Destructive Operation"
- Remove a registered tool. Because Validations are a subtype of Tool and share the same registry, this command ==also removes validations==. When removing a Validation, all attachments are automatically detached before the entry is removed from the registry.
-
- References from skills and actor graphs will **break** until resolved.
-
-**Arguments**
-
-- ``: Tool or validation name to remove.
-- `--yes`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents tool remove local/run-migrations
-
- Remove tool local/run-migrations? [y/N]: y
-
- ╭─ Tool Removed ────────────────────╮
- │ Name: local/run-migrations │
- │ Source: custom │
- ╰───────────────────────────────────╯
-
- ╭─ References ──────────────────────────────────────╮
- │ Warning: This tool is referenced by: │
- │ - Skill: local/devops-toolkit │
- │ - Actor graph node: code_executor.run_db_migrate │
- │ These references will break until resolved. │
- ╰───────────────────────────────────────────────────╯
-
- ✓ OK Tool removed
-
-
-=== "Plain"
-
- ```
- $ agents tool remove local/run-migrations
-
- Remove tool local/run-migrations? [y/N]: y
-
- Tool Removed
- Name: local/run-migrations
- Source: custom
-
- References
- Warning: This tool is referenced by:
- - Skill: local/devops-toolkit
- - Actor graph node: code_executor.run_db_migrate
- These references will break until resolved.
-
- [OK] Tool removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "tool_removed": {
- "name": "local/run-migrations",
- "source": "custom"
- },
- "broken_references": [
- { "type": "skill", "name": "local/devops-toolkit" },
- { "type": "actor_graph_node", "name": "code_executor.run_db_migrate" }
- ]
- },
- "timing": { "duration_ms": 34 },
- "messages": [
- "Tool removed",
- "Warning: This tool is referenced by 1 skill and 1 actor graph node. These references will break until resolved."
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool remove
- status: ok
- exit_code: 0
- data:
- tool_removed:
- name: local/run-migrations
- source: custom
- broken_references:
- - type: skill
- name: local/devops-toolkit
- - type: actor_graph_node
- name: code_executor.run_db_migrate
- timing:
- duration_ms: 34
- messages:
- - Tool removed
- - "Warning: This tool is referenced by 1 skill and 1 actor graph node. These references will break until resolved."
- ```
-
-When removing a validation, attachments are cleaned up automatically:
-
-=== "Rich"
-
-
- $ agents tool remove local/check-bundle-size
-
- Remove validation local/check-bundle-size? [y/N]: y
-
- ╭─ Validation Removed ─────────────────────────────╮
- │ Name: local/check-bundle-size │
- │ Description: Check bundle size (advisory) │
- ╰──────────────────────────────────────────────────╯
-
- ╭─ Detached From ────────────────────────────────────────────╮
- │ Warning: This validation had 2 attachments: │
- │ - local/api-repo (scope: project local/api-service) │
- │ - local/api-repo (direct) │
- │ These attachments have been removed. │
- ╰────────────────────────────────────────────────────────────╯
-
- ✓ OK Validation removed─
-
-
-=== "Plain"
-
- ```
- $ agents tool remove local/check-bundle-size
-
- Remove validation local/check-bundle-size? [y/N]: y
-
- Validation Removed
- Name: local/check-bundle-size
- Description: Check bundle size (advisory)
-
- Detached From
- Warning: This validation had 2 attachments:
- - local/api-repo (scope: project local/api-service)
- - local/api-repo (direct)
- These attachments have been removed.
-
- [OK] Validation removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_removed": {
- "name": "local/check-bundle-size",
- "description": "Check bundle size (advisory)"
- },
- "detached_attachments": [
- { "resource": "local/api-repo", "scope": "project", "project": "local/api-service" },
- { "resource": "local/api-repo", "scope": "direct" }
- ]
- },
- "timing": { "duration_ms": 41 },
- "messages": [
- "Validation removed",
- "Warning: This validation had 2 attachments which have been removed."
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool remove
- status: ok
- exit_code: 0
- data:
- validation_removed:
- name: local/check-bundle-size
- description: "Check bundle size (advisory)"
- detached_attachments:
- - resource: local/api-repo
- scope: project
- project: local/api-service
- - resource: local/api-repo
- scope: direct
- timing:
- duration_ms: 41
- messages:
- - Validation removed
- - "Warning: This validation had 2 attachments which have been removed."
- ```
-
-##### agents tool list
-
-agents tool list [(--namespace|-n) <NS>] [--source <SOURCE>] [--type (tool|validation)] [<REGEX>]
-
-**Purpose**
-List registered tools with optional filters. Because Validations are a subtype of Tool and share the same registry, this command lists both plain tools and validations. Use `--type validation` to show only validations, or `--type tool` to show only plain tools. When `--type` is omitted, both are listed with a `Type` column distinguishing them.
-
-**Arguments**
-
-- `--namespace/-n NS`: Filter by namespace.
-- `--source SOURCE`: Filter by tool source type (mcp, agent_skill, builtin, custom).
-- `--type TYPE`: Filter by entry type: `tool` (plain tools only) or `validation` (validations only). When omitted, both are listed.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents tool list --namespace local
-
- ╭─ Tools ─────────────────────────────────────────────────────────────────╮
- │ Name Type Source Read-Only Writes │
- │ ───────────────────────── ────────── ─────── ───────── ────── │
- │ local/run-migrations tool custom — ✓ │
- │ local/validate-api-compat tool custom — ✓ │
- │ local/create-subplan tool custom — ✓ │
- │ local/deploy-staging tool agent — ✓ │
- │ local/run-tests validation custom ✓ — │
- │ local/lint-check validation custom ✓ — │
- │ local/check-bundle-size validation custom ✓ — │
- │ local/type-check validation custom ✓ — │
- ╰─────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ────────────────╮
- │ Total: 8 │
- │ Tools: 4 │
- │ Validations: 4 │
- │ Read-Only: 4 │
- │ Writes: 4 │
- ╰──────────────────────────╯
-
- ✓ OK 8 tools listed
-
-
-=== "Plain"
-
- ```
- $ agents tool list --namespace local
-
- Tools
- Name Type Source Read-Only Writes
- ------------------------- ---------- ------- --------- ------
- local/run-migrations tool custom - yes
- local/validate-api-compat tool custom - yes
- local/create-subplan tool custom - yes
- local/deploy-staging tool agent - yes
- local/run-tests validation custom yes -
- local/lint-check validation custom yes -
- local/check-bundle-size validation custom yes -
- local/type-check validation custom yes -
-
- Summary
- Total: 8
- Tools: 4
- Validations: 4
- Read-Only: 4
- Writes: 4
-
- [OK] 8 tools listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "tools": [
- { "name": "local/run-migrations", "type": "tool", "source": "custom", "read_only": false, "writes": true },
- { "name": "local/validate-api-compat", "type": "tool", "source": "custom", "read_only": false, "writes": true },
- { "name": "local/create-subplan", "type": "tool", "source": "custom", "read_only": false, "writes": true },
- { "name": "local/deploy-staging", "type": "tool", "source": "agent", "read_only": false, "writes": true },
- { "name": "local/run-tests", "type": "validation", "source": "custom", "read_only": true, "writes": false },
- { "name": "local/lint-check", "type": "validation", "source": "custom", "read_only": true, "writes": false },
- { "name": "local/check-bundle-size", "type": "validation", "source": "custom", "read_only": true, "writes": false },
- { "name": "local/type-check", "type": "validation", "source": "custom", "read_only": true, "writes": false }
- ],
- "summary": {
- "total": 8,
- "tools": 4,
- "validations": 4,
- "read_only": 4,
- "writes": 4
- }
- },
- "timing": { "duration_ms": 22 },
- "messages": ["8 tools listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool list
- status: ok
- exit_code: 0
- data:
- tools:
- - name: local/run-migrations
- type: tool
- source: custom
- read_only: false
- writes: true
- - name: local/validate-api-compat
- type: tool
- source: custom
- read_only: false
- writes: true
- - name: local/create-subplan
- type: tool
- source: custom
- read_only: false
- writes: true
- - name: local/deploy-staging
- type: tool
- source: agent
- read_only: false
- writes: true
- - name: local/run-tests
- type: validation
- source: custom
- read_only: true
- writes: false
- - name: local/lint-check
- type: validation
- source: custom
- read_only: true
- writes: false
- - name: local/check-bundle-size
- type: validation
- source: custom
- read_only: true
- writes: false
- - name: local/type-check
- type: validation
- source: custom
- read_only: true
- writes: false
- summary:
- total: 8
- tools: 4
- validations: 4
- read_only: 4
- writes: 4
- timing:
- duration_ms: 22
- messages:
- - 8 tools listed
- ```
-
-=== "Rich"
-
-
- $ agents tool list --type validation --namespace local
-
- ╭─ Validations ─────────────────────────────────────────────────────────────────╮
- │ Name Source Mode Attachments │
- │ ───────────────────────── ─────── ──────────── ──────────────────────── │
- │ local/run-tests custom required 2 (1 direct, 1 project) │
- │ local/lint-check custom required 1 (1 direct) │
- │ local/check-bundle-size custom informational 1 (1 project) │
- │ local/type-check custom required 2 (2 project) │
- ╰───────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ──────────────╮
- │ Total: 4 │
- │ Required: 3 │
- │ Informational: 1 │
- ╰────────────────────────╯
-
- ✓ OK 4 validations listed
-
-
-=== "Plain"
-
- ```
- $ agents tool list --type validation --namespace local
-
- Validations
- Name Source Mode Attachments
- ------------------------- ------- ------------ ------------------------
- local/run-tests custom required 2 (1 direct, 1 project)
- local/lint-check custom required 1 (1 direct)
- local/check-bundle-size custom informational 1 (1 project)
- local/type-check custom required 2 (2 project)
-
- Summary
- Total: 4
- Required: 3
- Informational: 1
-
- [OK] 4 validations listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validations": [
- { "name": "local/run-tests", "source": "custom", "mode": "required", "attachments": { "total": 2, "direct": 1, "project": 1 } },
- { "name": "local/lint-check", "source": "custom", "mode": "required", "attachments": { "total": 1, "direct": 1 } },
- { "name": "local/check-bundle-size", "source": "custom", "mode": "informational", "attachments": { "total": 1, "project": 1 } },
- { "name": "local/type-check", "source": "custom", "mode": "required", "attachments": { "total": 2, "project": 2 } }
- ],
- "summary": {
- "total": 4,
- "required": 3,
- "informational": 1
- }
- },
- "timing": { "duration_ms": 18 },
- "messages": ["4 validations listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool list
- status: ok
- exit_code: 0
- data:
- validations:
- - name: local/run-tests
- source: custom
- mode: required
- attachments:
- total: 2
- direct: 1
- project: 1
- - name: local/lint-check
- source: custom
- mode: required
- attachments:
- total: 1
- direct: 1
- - name: local/check-bundle-size
- source: custom
- mode: informational
- attachments:
- total: 1
- project: 1
- - name: local/type-check
- source: custom
- mode: required
- attachments:
- total: 2
- project: 2
- summary:
- total: 4
- required: 3
- informational: 1
- timing:
- duration_ms: 18
- messages:
- - 4 validations listed
- ```
-
-##### agents tool show
-
-
-
-**Purpose**
-Show full details for a registered tool, including its schema, capability metadata, and where it is referenced. Because Validations are a subtype of Tool and share the same registry, this command also shows validation details. When showing a Validation, additional validation-specific fields are displayed: `Mode` (required/informational) and `Attached To` (listing each resource attachment with its scope — direct, project-scoped, or plan-scoped).
-
-**Arguments**
-
-- ``: Tool or validation name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents tool show local/run-migrations
-
- ╭─ Tool Details ───────────────────────────────╮
- │ Name: local/run-migrations │
- │ Description: Run database migrations │
- │ Source: custom │
- │ Config: ./tools/run-migrations.yaml │
- │ Registered: 2026-02-09 10:15 │
- ╰──────────────────────────────────────────────╯
-
- ╭─ Input Schema ─────────────────────────────────╮
- │ direction: string (required) enum: [up, down] │
- │ count: integer (default: 1) │
- ╰────────────────────────────────────────────────╯
-
- ╭─ Capability ──────────────────────╮
- │ Read-Only: false │
- │ Writes: true │
- │ Write Scope: database:migrations │
- │ Checkpointable: true │
- │ Checkpoint Scope: transaction │
- │ Side Effects: schema_mutation │
- │ Idempotent: false │
- ╰───────────────────────────────────╯
-
- ╭─ Referenced By ───────────────────────╮
- │ Skills: │
- │ - local/devops-toolkit │
- │ Actor Graph Nodes: │
- │ - code_executor.run_db_migrate │
- ╰───────────────────────────────────────╯
-
- ✓ OK Tool details loaded
-
-
-=== "Plain"
-
- ```
- $ agents tool show local/run-migrations
-
- Tool Details
- Name: local/run-migrations
- Description: Run database migrations
- Source: custom
- Config: ./tools/run-migrations.yaml
- Registered: 2026-02-09 10:15
-
- Input Schema
- direction: string (required) enum: [up, down]
- count: integer (default: 1)
-
- Capability
- Read-Only: false
- Writes: true
- Write Scope: database:migrations
- Checkpointable: true
- Checkpoint Scope: transaction
- Side Effects: schema_mutation
- Idempotent: false
-
- Referenced By
- Skills:
- - local/devops-toolkit
- Actor Graph Nodes:
- - code_executor.run_db_migrate
-
- [OK] Tool details loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "tool_details": {
- "name": "local/run-migrations",
- "description": "Run database migrations",
- "source": "custom",
- "config": "./tools/run-migrations.yaml",
- "registered": "2026-02-09T10:15:00Z"
- },
- "input_schema": {
- "direction": { "type": "string", "required": true, "enum": ["up", "down"] },
- "count": { "type": "integer", "default": 1 }
- },
- "capability": {
- "read_only": false,
- "writes": true,
- "write_scope": "database:migrations",
- "checkpointable": true,
- "checkpoint_scope": "transaction",
- "side_effects": ["schema_mutation"],
- "idempotent": false
- },
- "referenced_by": {
- "skills": ["local/devops-toolkit"],
- "actor_graph_nodes": ["code_executor.run_db_migrate"]
- }
- },
- "timing": { "duration_ms": 15 },
- "messages": ["Tool details loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool show
- status: ok
- exit_code: 0
- data:
- tool_details:
- name: local/run-migrations
- description: Run database migrations
- source: custom
- config: ./tools/run-migrations.yaml
- registered: "2026-02-09T10:15:00Z"
- input_schema:
- direction:
- type: string
- required: true
- enum:
- - up
- - down
- count:
- type: integer
- default: 1
- capability:
- read_only: false
- writes: true
- write_scope: "database:migrations"
- checkpointable: true
- checkpoint_scope: transaction
- side_effects:
- - schema_mutation
- idempotent: false
- referenced_by:
- skills:
- - local/devops-toolkit
- actor_graph_nodes:
- - code_executor.run_db_migrate
- timing:
- duration_ms: 15
- messages:
- - Tool details loaded
- ```
-
-When showing a Validation, the output includes validation-specific sections:
-
-=== "Rich"
-
-
- $ agents tool show local/run-tests
-
- ╭─ Validation Details ──────────────────────────────╮
- │ Name: local/run-tests │
- │ Type: validation │
- │ Description: Run unit tests with coverage │
- │ Source: custom │
- │ Mode: required │
- │ Config: ./validations/run-tests.yaml │
- │ Registered: 2026-02-09 10:15 │
- ╰───────────────────────────────────────────────────╯
-
- ╭─ Input Schema ─────────────────────────────────────╮
- │ coverage_threshold: integer (default: 80) │
- ╰────────────────────────────────────────────────────╯
-
- ╭─ Output Schema (Validation Return Format) ─────────╮
- │ passed: boolean (required) │
- │ message: string (optional) │
- │ data: object (optional, arbitrary structure) │
- ╰────────────────────────────────────────────────────╯
-
- ╭─ Capability ──────────────────────╮
- │ Read-Only: true (enforced) │
- │ Checkpointable: false (enforced) │
- │ Timeout: 600s │
- ╰───────────────────────────────────╯
-
- ╭─ Attached To ─────────────────────────────────────────────────────╮
- │ local/api-repo (direct, always active) │
- │ (attachment: 01HXM5B2C3D4E5F6G7H8J9K0L1) │
- │ local/api-repo (scope: project local/api-service) │
- │ (attachment: 01HXM5A1B2C3D4E5F6G7H8J9K0) │
- ╰───────────────────────────────────────────────────────────────────╯
-
- ✓ OK Validation details loaded
-
-
-=== "Plain"
-
- ```
- $ agents tool show local/run-tests
-
- Validation Details
- Name: local/run-tests
- Type: validation
- Description: Run unit tests with coverage
- Source: custom
- Mode: required
- Config: ./validations/run-tests.yaml
- Registered: 2026-02-09 10:15
-
- Input Schema
- coverage_threshold: integer (default: 80)
-
- Output Schema (Validation Return Format)
- passed: boolean (required)
- message: string (optional)
- data: object (optional, arbitrary structure)
-
- Capability
- Read-Only: true (enforced)
- Checkpointable: false (enforced)
- Timeout: 600s
-
- Attached To
- local/api-repo (direct, always active)
- (attachment: 01HXM5B2C3D4E5F6G7H8J9K0L1)
- local/api-repo (scope: project local/api-service)
- (attachment: 01HXM5A1B2C3D4E5F6G7H8J9K0)
-
- [OK] Validation details loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "tool show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_details": {
- "name": "local/run-tests",
- "type": "validation",
- "description": "Run unit tests with coverage",
- "source": "custom",
- "mode": "required",
- "config": "./validations/run-tests.yaml",
- "registered": "2026-02-09T10:15:00Z"
- },
- "input_schema": {
- "coverage_threshold": { "type": "integer", "default": 80 }
- },
- "output_schema": {
- "passed": { "type": "boolean", "required": true },
- "message": { "type": "string", "required": false },
- "data": { "type": "object", "required": false, "description": "arbitrary structure" }
- },
- "capability": {
- "read_only": true,
- "read_only_enforced": true,
- "checkpointable": false,
- "checkpointable_enforced": true,
- "timeout_seconds": 600
- },
- "attached_to": [
- { "resource": "local/api-repo", "scope": "direct", "attachment_id": "01HXM5B2C3D4E5F6G7H8J9K0L1" },
- { "resource": "local/api-repo", "scope": "project", "project": "local/api-service", "attachment_id": "01HXM5A1B2C3D4E5F6G7H8J9K0" }
- ]
- },
- "timing": { "duration_ms": 19 },
- "messages": ["Validation details loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: tool show
- status: ok
- exit_code: 0
- data:
- validation_details:
- name: local/run-tests
- type: validation
- description: Run unit tests with coverage
- source: custom
- mode: required
- config: ./validations/run-tests.yaml
- registered: "2026-02-09T10:15:00Z"
- input_schema:
- coverage_threshold:
- type: integer
- default: 80
- output_schema:
- passed:
- type: boolean
- required: true
- message:
- type: string
- required: false
- data:
- type: object
- required: false
- description: arbitrary structure
- capability:
- read_only: true
- read_only_enforced: true
- checkpointable: false
- checkpointable_enforced: true
- timeout_seconds: 600
- attached_to:
- - resource: local/api-repo
- scope: direct
- attachment_id: 01HXM5B2C3D4E5F6G7H8J9K0L1
- - resource: local/api-repo
- scope: project
- project: local/api-service
- attachment_id: 01HXM5A1B2C3D4E5F6G7H8J9K0
- timing:
- duration_ms: 19
- messages:
- - Validation details loaded
- ```
-
-#### agents lsp
-
-!!! info "Purpose"
- Manage the **LSP Registry** — the global registry of Language Server Protocol servers that provide language intelligence (diagnostics, type information, completions, references, definitions, symbols, formatting, code actions, renaming) to actors. LSP servers are Infrastructure-layer components attached to actors via the `lsp:` configuration field; they have nothing to do with IDE integration. Each registered LSP server has a namespaced name (`[[server:]namespace/]name`), a launch command, supported languages, initialization options, and capability declarations. The `agents lsp` commands mirror the structure of `agents tool` commands.
-
-##### agents lsp add
-
-agents lsp add [--update|-u] (--config|-c) <FILE>
-
-**Purpose**
-Register an LSP server from a YAML configuration file. The config file defines the server's namespaced name, launch command, supported languages, initialization options, and capability declarations. If the server already exists and `--update` is not provided, the command fails with an error and a hint to use `--update`.
-
-**Arguments**
-
-- `--config/-c FILE`: Path to LSP server YAML configuration file (required).
-- `--update/-u`: Overwrite if the server already exists in the registry.
-
-**Examples**
-
-Registering a new LSP server:
-
-=== "Rich"
-
-
- $ agents lsp add --config lsp/pyright.yaml
-
- ╭─ LSP Server Registered ──────────────────────────────────╮
- │ Name: local/pyright │
- │ Languages: python │
- │ Command: pyright-langserver --stdio │
- │ Capabilities: diagnostics, hover, completions, │
- │ references, definitions, symbols, │
- │ rename, code_actions │
- ╰──────────────────────────────────────────────────────────╯
-
- ✓ OK LSP server registered
-
-
-=== "Plain"
-
- ```
- $ agents lsp add --config lsp/pyright.yaml
-
- LSP Server Registered
- Name: local/pyright
- Languages: python
- Command: pyright-langserver --stdio
- Capabilities: diagnostics, hover, completions, references, definitions, symbols, rename, code_actions
-
- [OK] LSP server registered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "lsp add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "lsp_server": {
- "name": "local/pyright",
- "languages": ["python"],
- "command": "pyright-langserver --stdio",
- "capabilities": [
- "diagnostics", "hover", "completions", "references",
- "definitions", "symbols", "rename", "code_actions"
- ]
- }
- },
- "timing": { "duration_ms": 12 },
- "messages": ["LSP server registered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: lsp add
- status: ok
- exit_code: 0
- data:
- lsp_server:
- name: local/pyright
- languages:
- - python
- command: pyright-langserver --stdio
- capabilities:
- - diagnostics
- - hover
- - completions
- - references
- - definitions
- - symbols
- - rename
- - code_actions
- timing:
- duration_ms: 12
- messages:
- - LSP server registered
- ```
-
-Attempting to add a server that already exists (without `--update`):
-
-=== "Rich"
-
-
- $ agents lsp add --config lsp/pyright.yaml
-
- ✗ ERROR LSP server 'local/pyright' already exists
-
- Hint: Use --update to overwrite: agents lsp add --update --config lsp/pyright.yaml
-
-
-=== "Plain"
-
- ```
- $ agents lsp add --config lsp/pyright.yaml
-
- [ERROR] LSP server 'local/pyright' already exists
- Hint: Use --update to overwrite: agents lsp add --update --config lsp/pyright.yaml
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "lsp add",
- "status": "error",
- "exit_code": 1,
- "data": {
- "error": "LSP server 'local/pyright' already exists"
- },
- "hint": "Use --update to overwrite",
- "suggested_command": "agents lsp add --update --config lsp/pyright.yaml",
- "timing": { "duration_ms": 5 },
- "messages": ["LSP server 'local/pyright' already exists"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: lsp add
- status: error
- exit_code: 1
- data:
- error: "LSP server 'local/pyright' already exists"
- hint: Use --update to overwrite
- suggested_command: agents lsp add --update --config lsp/pyright.yaml
- timing:
- duration_ms: 5
- messages:
- - "LSP server 'local/pyright' already exists"
- ```
-
-##### agents lsp remove
-
-agents lsp remove [--yes|-y] <NAME>
-
-!!! danger "Destructive Operation"
- Remove a registered LSP server from the LSP Registry. Running LSP server processes bound to the removed entry are terminated. Actor configurations referencing this server by name will fail at activation until resolved.
-
-**Arguments**
-
-- ``: Namespaced LSP server name to remove.
-- `--yes/-y`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents lsp remove local/pyright
-
- Remove LSP server local/pyright? [y/N]: y
-
- ╭─ LSP Server Removed ─────────────────────╮
- │ Name: local/pyright │
- │ Languages: python │
- ╰──────────────────────────────────────────╯
-
- ╭─ References ──────────────────────────────────────────────────╮
- │ Warning: This LSP server is referenced by: │
- │ - Actor: local/code-reviewer (lsp: [local/pyright]) │
- │ - Actor: local/refactor-agent (lsp: [local/pyright]) │
- │ These actor LSP bindings will fail until resolved. │
- ╰───────────────────────────────────────────────────────────────╯
-
- ✓ OK LSP server removed
-
-
-=== "Plain"
-
- ```
- $ agents lsp remove local/pyright
-
- Remove LSP server local/pyright? [y/N]: y
-
- LSP Server Removed
- Name: local/pyright
- Languages: python
-
- References
- Warning: This LSP server is referenced by:
- - Actor: local/code-reviewer (lsp: [local/pyright])
- - Actor: local/refactor-agent (lsp: [local/pyright])
- These actor LSP bindings will fail until resolved.
-
- [OK] LSP server removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "lsp remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "lsp_server_removed": {
- "name": "local/pyright",
- "languages": ["python"]
- },
- "broken_references": [
- { "type": "actor", "name": "local/code-reviewer" },
- { "type": "actor", "name": "local/refactor-agent" }
- ]
- },
- "timing": { "duration_ms": 28 },
- "messages": [
- "LSP server removed",
- "Warning: This LSP server is referenced by 2 actors. These actor LSP bindings will fail until resolved."
- ]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: lsp remove
- status: ok
- exit_code: 0
- data:
- lsp_server_removed:
- name: local/pyright
- languages:
- - python
- broken_references:
- - type: actor
- name: local/code-reviewer
- - type: actor
- name: local/refactor-agent
- timing:
- duration_ms: 28
- messages:
- - LSP server removed
- - "Warning: This LSP server is referenced by 2 actors. These actor LSP bindings will fail until resolved."
- ```
-
-##### agents lsp list
-
-agents lsp list [(--namespace|-n) <NS>] [--language <LANG>] [<REGEX>]
-
-**Purpose**
-List registered LSP servers with optional filters. Shows each server's name, supported languages, command, and the number of actors currently bound to it.
-
-**Arguments**
-
-- `--namespace/-n NS`: Filter by namespace.
-- `--language LANG`: Filter by supported language (e.g., `python`, `typescript`).
-- ``: Optional name filter pattern.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents lsp list
-
- ╭─ LSP Registry (3 servers) ───────────────────────────────────────────────────────────╮
- │ Name │ Languages │ Command │ Bound │
- │─────────────────────────│──────────────────────│─────────────────────────────│───────│
- │ local/pyright │ python │ pyright-langserver --stdio │ 3 │
- │ local/ts-server │ typescript, jsx, tsx │ typescript-language-server │ 2 │
- │ local/gopls │ go │ gopls serve │ 1 │
- ╰──────────────────────────────────────────────────────────────────────────────────────╯
-
-
-=== "Plain"
-
- ```
- $ agents lsp list
-
- LSP Registry (3 servers)
- Name Languages Command Bound
- local/pyright python pyright-langserver --stdio 3
- local/ts-server typescript, jsx, tsx typescript-language-server 2
- local/gopls go gopls serve 1
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "lsp list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "lsp_servers": [
- {
- "name": "local/pyright",
- "languages": ["python"],
- "command": "pyright-langserver --stdio",
- "bound_actors": 3
- },
- {
- "name": "local/ts-server",
- "languages": ["typescript", "jsx", "tsx"],
- "command": "typescript-language-server",
- "bound_actors": 2
- },
- {
- "name": "local/gopls",
- "languages": ["go"],
- "command": "gopls serve",
- "bound_actors": 1
- }
- ],
- "total": 3
- },
- "timing": { "duration_ms": 8 },
- "messages": ["3 LSP servers listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: lsp list
- status: ok
- exit_code: 0
- data:
- lsp_servers:
- - name: local/pyright
- languages:
- - python
- command: pyright-langserver --stdio
- bound_actors: 3
- - name: local/ts-server
- languages:
- - typescript
- - jsx
- - tsx
- command: typescript-language-server
- bound_actors: 2
- - name: local/gopls
- languages:
- - go
- command: gopls serve
- bound_actors: 1
- total: 3
- timing:
- duration_ms: 8
- messages:
- - 3 LSP servers listed
- ```
-
-Filtering by language:
-
-=== "Rich"
-
-
- $ agents lsp list --language python
-
- ╭─ LSP Registry (1 server, filtered: language=python) ─────────────────────────────╮
- │ Name │ Languages │ Command │ Bound │
- │─────────────────────────│────────────│───────────────────────────────────│───────│
- │ local/pyright │ python │ pyright-langserver --stdio │ 3 │
- ╰──────────────────────────────────────────────────────────────────────────────────╯
-
-
-=== "Plain"
-
- ```
- $ agents lsp list --language python
-
- LSP Registry (1 server, filtered: language=python)
- Name Languages Command Bound
- local/pyright python pyright-langserver --stdio 3
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "lsp list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "lsp_servers": [
- {
- "name": "local/pyright",
- "languages": ["python"],
- "command": "pyright-langserver --stdio",
- "bound_actors": 3
- }
- ],
- "total": 1,
- "filter": { "language": "python" }
- },
- "timing": { "duration_ms": 6 },
- "messages": ["1 LSP server listed (filtered: language=python)"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: lsp list
- status: ok
- exit_code: 0
- data:
- lsp_servers:
- - name: local/pyright
- languages:
- - python
- command: pyright-langserver --stdio
- bound_actors: 3
- total: 1
- filter:
- language: python
- timing:
- duration_ms: 6
- messages:
- - "1 LSP server listed (filtered: language=python)"
- ```
-
-##### agents lsp show
-
-
-
-**Purpose**
-Show full details for a registered LSP server, including its configuration, supported languages, capabilities, initialization options, and which actors are bound to it.
-
-**Arguments**
-
-- ``: Namespaced LSP server name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents lsp show local/pyright
-
- ╭─ LSP Server Details ──────────────────────────────────────────╮
- │ Name: local/pyright │
- │ Languages: python │
- │ Command: pyright-langserver --stdio │
- │ Root path: {{ project.root }} │
- │ Init options: │
- │ python.analysis.typeCheckingMode: standard │
- │ python.analysis.autoSearchPaths: true │
- ╰───────────────────────────────────────────────────────────────╯
-
- ╭─ Capabilities ────────────────────────────────────────────────╮
- │ diagnostics, hover, completions, references, definitions, │
- │ symbols, rename, code_actions │
- ╰───────────────────────────────────────────────────────────────╯
-
- ╭─ Bound Actors ────────────────────────────────────────────────╮
- │ local/code-reviewer (explicit binding) │
- │ local/refactor-agent (language-based: python) │
- │ local/polyglot-planner (auto-discovery) │
- ╰───────────────────────────────────────────────────────────────╯
-
-
-=== "Plain"
-
- ```
- $ agents lsp show local/pyright
-
- LSP Server Details
- Name: local/pyright
- Languages: python
- Command: pyright-langserver --stdio
- Root path: {{ project.root }}
- Init options:
- python.analysis.typeCheckingMode: standard
- python.analysis.autoSearchPaths: true
-
- Capabilities
- diagnostics, hover, completions, references, definitions, symbols, rename, code_actions
-
- Bound Actors
- local/code-reviewer (explicit binding)
- local/refactor-agent (language-based: python)
- local/polyglot-planner (auto-discovery)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "lsp show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "lsp_server": {
- "name": "local/pyright",
- "languages": ["python"],
- "command": "pyright-langserver --stdio",
- "root_path": "{{ project.root }}",
- "init_options": {
- "python.analysis.typeCheckingMode": "standard",
- "python.analysis.autoSearchPaths": true
- },
- "capabilities": [
- "diagnostics", "hover", "completions", "references",
- "definitions", "symbols", "rename", "code_actions"
- ],
- "bound_actors": [
- { "name": "local/code-reviewer", "binding_mode": "explicit" },
- { "name": "local/refactor-agent", "binding_mode": "language_based", "language": "python" },
- { "name": "local/polyglot-planner", "binding_mode": "auto_discovery" }
- ]
- }
- },
- "timing": { "duration_ms": 14 },
- "messages": ["LSP server details loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: lsp show
- status: ok
- exit_code: 0
- data:
- lsp_server:
- name: local/pyright
- languages:
- - python
- command: pyright-langserver --stdio
- root_path: "{{ project.root }}"
- init_options:
- python.analysis.typeCheckingMode: standard
- python.analysis.autoSearchPaths: true
- capabilities:
- - diagnostics
- - hover
- - completions
- - references
- - definitions
- - symbols
- - rename
- - code_actions
- bound_actors:
- - name: local/code-reviewer
- binding_mode: explicit
- - name: local/refactor-agent
- binding_mode: language_based
- language: python
- - name: local/polyglot-planner
- binding_mode: auto_discovery
- timing:
- duration_ms: 14
- messages:
- - LSP server details loaded
- ```
-
-##### agents lsp serve
-
-agents lsp serve [--log-level <LEVEL>]
-
-**Purpose**
-Launch the stub LSP server over stdin/stdout using the JSON-RPC base protocol with Content-Length header framing. The server supports the `initialize`, `shutdown`, and `exit` lifecycle methods. Requests received **before** `initialize` are rejected with `ServerNotInitialized` (-32002) per the LSP specification. After initialization, unsupported LSP methods return a `MethodNotFound` (-32601) error. After `shutdown` is received, only `exit` is accepted; other requests are rejected with `InvalidRequest` (-32600). Sending `initialize` a second time is also rejected with `InvalidRequest`.
-
-This command is intended for development and testing of LSP transport integration. In a future milestone the stub handlers will be replaced by real LSP server proxying through the A2A facade.
-
-**Arguments**
-
-- `--log-level LEVEL`: Logging level for the server process. Valid values: `debug`, `info` (default), `warning`, `error`. Invalid values cause immediate exit with a descriptive error message.
-
-**Transport Limits**
-
-| Limit | Value | Description |
-|-------|-------|-------------|
-| Max Content-Length | 10 MB | Messages exceeding this are rejected with a warning log (DoS guard) |
-| Max header lines | 32 | Headers with more lines are rejected with a warning log (DoS guard) |
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents lsp serve
-
- CleverAgents LSP Server (stub) starting — PID 7412
- Log level: info
- Transport: stdin/stdout (JSON-RPC, Content-Length framing)
- Supported methods: initialize, shutdown, exit
- All other methods → MethodNotFound (-32601)
-
-
-=== "Plain"
-
- ```
- $ agents lsp serve
-
- CleverAgents LSP Server (stub) starting — PID 7412
- Log level: info
- Transport: stdin/stdout (JSON-RPC, Content-Length framing)
- Supported methods: initialize, shutdown, exit
- All other methods → MethodNotFound (-32601)
- ```
-
-#### agents validation
-
-!!! info "Purpose"
- Register and attach ==validations== — a specialized subtype of Tool that extends the Tool class with pass/fail semantics and attachment scoping. A Validation inherits all base Tool properties (name, source, input_schema, capability, resource bindings, lifecycle hooks, etc.) and adds: a `mode` field (`required` or `informational`), and a structured JSON return format with a mandatory `passed` boolean, an optional `message` string, and an optional `data` object for arbitrary informational output. Since Validation extends Tool, it shares the same backing sources (custom, MCP, agent_skill, builtin) plus the additional `wrapped` source type for Validations that wrap an existing Tool via the `wraps` field. It uses the same YAML configuration format (with an additional `validation` block and optional `wraps`/`transform` fields), and the same registries and resolution mechanisms. Validations are always read-only (`writes` is always `false`, `checkpointable` is always `false`).
-
-Because Validations are a subtype of Tool and share the same Tool Registry and naming namespace, only validation-specific operations have dedicated subcommands here: `add` (registration with validation-specific fields like `mode`), `attach`, and `detach`. General tool operations — listing, inspection, and removal — are handled through the `agents tool` commands:
-
-- **List validations**: `agents tool list --type validation`
-- **Show validation details**: `agents tool show ` (displays validation-specific fields when the entry is a Validation)
-- **Remove a validation**: `agents tool remove ` (automatically removes all attachments)
-
-A validation is always attached to a resource. The optional `--project` or `--plan` flag controls the scope of the attachment:
-- **Direct attachment** (no scope flag): The validation is always active for that resource, regardless of which plan or project accesses it. Use `agents validation attach [args...]`.
-- **Project-scoped attachment** (`--project`): The validation only runs for that resource when it is being interacted with through the specified project. Use `agents validation attach --project [args...]`.
-- **Plan-scoped attachment** (`--plan`): The validation only runs for that resource when it is being interacted with through the specified plan. Use `agents validation attach --plan [args...]`.
-
-The same validation can be attached to the same resource multiple times — directly, through different projects, and through different plans — and since validations accept arguments, attaching the same validation to the same resource multiple times with different arguments is a common and useful configuration pattern (e.g., running the same test suite with different coverage thresholds for different projects).
-
-Each `attach` invocation returns a system-assigned **attachment ULID** uniquely identifying that attachment. Use this ULID with `agents validation detach ` to remove a specific attachment.
-
-When multiple attachment scopes apply, the union of all applicable validations is used. A resource with a directly-attached validation will always have that validation run, plus any additional validations attached through the active project or plan.
-
-##### agents validation add
-
-agents validation add --config|-c <FILE> [--required | --informational] [--update]
-
-**Purpose**
-Register a new validation. The validation is fully defined by the YAML configuration file specified with `--config`. The validation is registered in the shared Tool Registry under the name specified in the config file; the name must not conflict with any existing tool or validation. If a validation with the same name already exists, the command fails unless `--update` is provided. The validation YAML may use `wraps` to reference an existing Tool, reusing its implementation and interpreting its output through a `transform` function (see Tool Wrapping under Core Concepts > Validation). When `wraps` is used, the wrapped Tool must already be registered.
-
-**Arguments**
-
-- `--config/-c FILE`: Path to the validation YAML configuration file (required). The file must fully define the validation, including the `name` field which determines the validation's registered name, the `validation.mode` field (`required` or `informational`), and either inline implementation (`source` + `code`) or wrapping (`wraps` + `transform`).
-- `--required`: Override the mode in the YAML config to `required`. Mutually exclusive with `--informational`.
-- `--informational`: Override the mode in the YAML config to `informational`. Mutually exclusive with `--required`.
-- `--update`: Allow overwriting an existing validation registration.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents validation add --config ./validations/run-tests.yaml
-
- ╭─ Validation Registered ────────────────────────────────╮
- │ Name: local/run-tests │
- │ Description: Run unit tests with coverage │
- │ Source: custom │
- │ Mode: required │
- │ Config: ./validations/run-tests.yaml │
- │ Created: 2026-02-09 10:15 │
- ╰────────────────────────────────────────────────────────╯
-
- ╭─ Capability ────────────────────────╮
- │ Read-Only: true (enforced) │
- │ Checkpointable: false (enforced) │
- │ Timeout: 600s │
- ╰─────────────────────────────────────╯
-
- ✓ OK Validation registered
-
-
-=== "Plain"
-
- ```
- $ agents validation add --config ./validations/run-tests.yaml
-
- Validation Registered
- Name: local/run-tests
- Description: Run unit tests with coverage
- Source: custom
- Mode: required
- Config: ./validations/run-tests.yaml
- Created: 2026-02-09 10:15
-
- Capability
- Read-Only: true (enforced)
- Checkpointable: false (enforced)
- Timeout: 600s
-
- [OK] Validation registered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_registered": {
- "name": "local/run-tests",
- "description": "Run unit tests with coverage",
- "source": "custom",
- "mode": "required",
- "config": "./validations/run-tests.yaml",
- "created": "2026-02-09 10:15"
- },
- "capability": {
- "read_only": "true (enforced)",
- "checkpointable": "false (enforced)",
- "timeout": "600s"
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 120 },
- "messages": ["Validation registered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation add
- status: ok
- exit_code: 0
- data:
- validation_registered:
- name: local/run-tests
- description: Run unit tests with coverage
- source: custom
- mode: required
- config: ./validations/run-tests.yaml
- created: "2026-02-09 10:15"
- capability:
- read_only: "true (enforced)"
- checkpointable: "false (enforced)"
- timeout: 600s
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 120
- messages:
- - "Validation registered"
- ```
-
-=== "Rich"
-
-
- $ agents validation add --config ./validations/lint-check.yaml
-
- ╭─ Validation Registered ──────────────╮
- │ Name: local/lint-check │
- │ Description: Lint check │
- │ Source: custom │
- │ Mode: required │
- │ Timeout: 300s │
- ╰──────────────────────────────────────╯
-
- ✓ OK Validation registered
-
-
-=== "Plain"
-
- ```
- $ agents validation add --config ./validations/lint-check.yaml
-
- Validation Registered
- Name: local/lint-check
- Description: Lint check
- Source: custom
- Mode: required
- Timeout: 300s
-
- [OK] Validation registered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_registered": {
- "name": "local/lint-check",
- "description": "Lint check",
- "source": "custom",
- "mode": "required",
- "timeout": "300s"
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 95 },
- "messages": ["Validation registered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation add
- status: ok
- exit_code: 0
- data:
- validation_registered:
- name: local/lint-check
- description: Lint check
- source: custom
- mode: required
- timeout: 300s
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 95
- messages:
- - "Validation registered"
- ```
-
-=== "Rich"
-
-
- $ agents validation add --config ./validations/check-bundle-size.yaml
-
- ╭─ Validation Registered ───────────────────────────╮
- │ Name: local/check-bundle-size │
- │ Description: Check bundle size (advisory) │
- │ Source: custom │
- │ Mode: informational │
- │ Timeout: 300s │
- ╰───────────────────────────────────────────────────╯
-
- ✓ OK Validation registered
-
-
-=== "Plain"
-
- ```
- $ agents validation add --config ./validations/check-bundle-size.yaml
-
- Validation Registered
- Name: local/check-bundle-size
- Description: Check bundle size (advisory)
- Source: custom
- Mode: informational
- Timeout: 300s
-
- [OK] Validation registered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_registered": {
- "name": "local/check-bundle-size",
- "description": "Check bundle size (advisory)",
- "source": "custom",
- "mode": "informational",
- "timeout": "300s"
- }
- },
- "timing": { "started": "2026-02-09T10:16:00Z", "duration_ms": 88 },
- "messages": ["Validation registered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation add
- status: ok
- exit_code: 0
- data:
- validation_registered:
- name: local/check-bundle-size
- description: "Check bundle size (advisory)"
- source: custom
- mode: informational
- timeout: 300s
- timing:
- started: "2026-02-09T10:16:00Z"
- duration_ms: 88
- messages:
- - "Validation registered"
- ```
-
-##### agents validation attach
-
-agents validation attach [--project <PROJECT>|--plan <PLAN_ID>]
- <RESOURCE> <VALIDATION> [<ARGS>...]
-
-**Purpose**
-Attach a registered validation to a resource, with an optional project or plan scope. A resource is always required — validations are fundamentally resource-centric. The optional `--project` or `--plan` flag narrows when the validation is active: without either flag, the validation runs whenever any plan or project accesses the resource; with `--project`, it only runs when the resource is accessed through that project; with `--plan`, it only runs when the resource is accessed through that plan. At most one scope flag may be provided per invocation.
-
-The command returns a system-assigned **attachment ULID** that uniquely identifies this specific attachment association. This ULID is used to detach the validation later via `agents validation detach `. The same validation can be attached to the same resource multiple times — directly, through different projects, through different plans, and even to the same resource and scope multiple times with different arguments.
-
-**Arguments**
-
-- ``: Resource name or ULID to attach the validation to (positional argument, required).
-- ``: Validation name (positional argument, required).
-- `--project PROJECT`: Scope the attachment to a specific project. The validation only runs for this resource when it is accessed through the specified project.
-- `--plan PLAN_ID`: Scope the attachment to a specific plan. The validation only runs for this resource when it is accessed through the specified plan.
-- `...`: Optional validation-specific arguments (passed through to the validation tool's `input_schema` at execution time).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents validation attach --project local/api-service local/api-repo local/run-tests
-
- ╭─ Validation Attached ──────────────────────────────────────╮
- │ Attachment ID: 01HXM5A1B2C3D4E5F6G7H8J9K0 │
- │ Validation: local/run-tests │
- │ Mode: required │
- │ Resource: local/api-repo │
- │ Scope: project local/api-service │
- ╰────────────────────────────────────────────────────────────╯
-
- ✓ OK Validation attached
-
-
-=== "Plain"
-
- ```
- $ agents validation attach --project local/api-service local/api-repo local/run-tests
-
- Validation Attached
- Attachment ID: 01HXM5A1B2C3D4E5F6G7H8J9K0
- Validation: local/run-tests
- Mode: required
- Resource: local/api-repo
- Scope: project local/api-service
-
- [OK] Validation attached
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation attach",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_attached": {
- "attachment_id": "01HXM5A1B2C3D4E5F6G7H8J9K0",
- "validation": "local/run-tests",
- "mode": "required",
- "resource": "local/api-repo",
- "scope": "project local/api-service"
- }
- },
- "timing": { "started": "2026-02-09T10:20:00Z", "duration_ms": 45 },
- "messages": ["Validation attached"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation attach
- status: ok
- exit_code: 0
- data:
- validation_attached:
- attachment_id: 01HXM5A1B2C3D4E5F6G7H8J9K0
- validation: local/run-tests
- mode: required
- resource: local/api-repo
- scope: project local/api-service
- timing:
- started: "2026-02-09T10:20:00Z"
- duration_ms: 45
- messages:
- - "Validation attached"
- ```
-
-=== "Rich"
-
-
- $ agents validation attach local/api-repo local/lint-check
-
- ╭─ Validation Attached ──────────────────────────────────────╮
- │ Attachment ID: 01HXM5B2C3D4E5F6G7H8J9K0L1 │
- │ Validation: local/lint-check │
- │ Mode: required │
- │ Resource: local/api-repo │
- │ Scope: direct (always active) │
- │ This validation will run for ALL plans/projects │
- │ that access this resource. │
- ╰────────────────────────────────────────────────────────────╯
-
- ✓ OK Validation attached
-
-
-=== "Plain"
-
- ```
- $ agents validation attach local/api-repo local/lint-check
-
- Validation Attached
- Attachment ID: 01HXM5B2C3D4E5F6G7H8J9K0L1
- Validation: local/lint-check
- Mode: required
- Resource: local/api-repo
- Scope: direct (always active)
- This validation will run for ALL plans/projects
- that access this resource.
-
- [OK] Validation attached
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation attach",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_attached": {
- "attachment_id": "01HXM5B2C3D4E5F6G7H8J9K0L1",
- "validation": "local/lint-check",
- "mode": "required",
- "resource": "local/api-repo",
- "scope": "direct (always active)",
- "note": "This validation will run for ALL plans/projects that access this resource."
- }
- },
- "timing": { "started": "2026-02-09T10:21:00Z", "duration_ms": 42 },
- "messages": ["Validation attached"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation attach
- status: ok
- exit_code: 0
- data:
- validation_attached:
- attachment_id: 01HXM5B2C3D4E5F6G7H8J9K0L1
- validation: local/lint-check
- mode: required
- resource: local/api-repo
- scope: "direct (always active)"
- note: "This validation will run for ALL plans/projects that access this resource."
- timing:
- started: "2026-02-09T10:21:00Z"
- duration_ms: 42
- messages:
- - "Validation attached"
- ```
-
-Attaching with validation-specific arguments:
-
-=== "Rich"
-
-
- $ agents validation attach --project local/api-service local/api-repo local/run-tests --coverage-threshold 90
-
- ╭─ Validation Attached ──────────────────────────────────────╮
- │ Attachment ID: 01HXM5C3D4E5F6G7H8J9K0L1M2 │
- │ Validation: local/run-tests │
- │ Mode: required │
- │ Resource: local/api-repo │
- │ Scope: project local/api-service │
- │ Args: coverage_threshold=90 │
- ╰────────────────────────────────────────────────────────────╯
-
- ✓ OK Validation attached
-
-
-=== "Plain"
-
- ```
- $ agents validation attach --project local/api-service local/api-repo local/run-tests --coverage-threshold 90
-
- Validation Attached
- Attachment ID: 01HXM5C3D4E5F6G7H8J9K0L1M2
- Validation: local/run-tests
- Mode: required
- Resource: local/api-repo
- Scope: project local/api-service
- Args: coverage_threshold=90
-
- [OK] Validation attached
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation attach",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_attached": {
- "attachment_id": "01HXM5C3D4E5F6G7H8J9K0L1M2",
- "validation": "local/run-tests",
- "mode": "required",
- "resource": "local/api-repo",
- "scope": "project local/api-service",
- "args": {
- "coverage_threshold": 90
- }
- }
- },
- "timing": { "started": "2026-02-09T10:22:00Z", "duration_ms": 48 },
- "messages": ["Validation attached"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation attach
- status: ok
- exit_code: 0
- data:
- validation_attached:
- attachment_id: 01HXM5C3D4E5F6G7H8J9K0L1M2
- validation: local/run-tests
- mode: required
- resource: local/api-repo
- scope: project local/api-service
- args:
- coverage_threshold: 90
- timing:
- started: "2026-02-09T10:22:00Z"
- duration_ms: 48
- messages:
- - "Validation attached"
- ```
-
-##### agents validation detach
-
-agents validation detach [--yes|-y] <ATTACHMENT_ID>
-
-**Purpose**
-Detach a validation by its attachment ULID. The attachment ULID is returned by `agents validation attach` when the attachment is created and is also displayed by `agents tool show ` in the "Attached To" section. Because a validation may be attached to the same resource multiple times — directly, through different projects, through different plans, or even to the same resource and scope with different arguments — the ULID uniquely identifies the specific attachment to remove. The validation itself remains registered in the Tool Registry; only the attachment association is removed.
-
-**Arguments**
-
-- ``: The ULID of the attachment to remove (returned by `agents validation attach`).
-- `--yes, -y`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents validation detach 01HXM5A1B2C3D4E5F6G7H8J9K0
-
- Detach validation local/run-tests from resource local/api-repo (scope: project local/api-service)? [y/N]: y
-
- ╭─ Validation Detached ───────────────────────────────────────╮
- │ Attachment ID: 01HXM5A1B2C3D4E5F6G7H8J9K0 │
- │ Validation: local/run-tests │
- │ Resource: local/api-repo │
- │ Scope: project local/api-service │
- ╰─────────────────────────────────────────────────────────────╯
-
- ✓ OK Validation detached
-
-
-=== "Plain"
-
- ```
- $ agents validation detach 01HXM5A1B2C3D4E5F6G7H8J9K0
-
- Detach validation local/run-tests from resource local/api-repo (scope: project local/api-service)? [y/N]: y
-
- Validation Detached
- Attachment ID: 01HXM5A1B2C3D4E5F6G7H8J9K0
- Validation: local/run-tests
- Resource: local/api-repo
- Scope: project local/api-service
-
- [OK] Validation detached
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "validation detach",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "validation_detached": {
- "attachment_id": "01HXM5A1B2C3D4E5F6G7H8J9K0",
- "validation": "local/run-tests",
- "resource": "local/api-repo",
- "scope": "project local/api-service"
- },
- "confirmation": "Detach validation local/run-tests from resource local/api-repo (scope: project local/api-service)? [y/N]: y"
- },
- "timing": { "started": "2026-02-09T10:25:00Z", "duration_ms": 1200 },
- "messages": ["Validation detached"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: validation detach
- status: ok
- exit_code: 0
- data:
- validation_detached:
- attachment_id: 01HXM5A1B2C3D4E5F6G7H8J9K0
- validation: local/run-tests
- resource: local/api-repo
- scope: project local/api-service
- confirmation: "Detach validation local/run-tests from resource local/api-repo (scope: project local/api-service)? [y/N]: y"
- timing:
- started: "2026-02-09T10:25:00Z"
- duration_ms: 1200
- messages:
- - "Validation detached"
- ```
-
-#### agents resource type
-
-**Purpose**
-Manage resource type definitions. Resource types are schema-level definitions that constrain categories of resources — they define what CLI arguments `agents resource add ` accepts, whether instances are physical or virtual, allowed parent/child types, auto-discovery behavior, sandbox strategy, and handler implementation. Built-in types (`git-checkout`, `git`, `fs-mount`, `fs-directory`, and their child types) are hardcoded. Custom types are defined in YAML configuration files and extend the system with new `agents resource add` subcommands.
-
-##### agents resource type add
-
-agents resource type add --config|-c <FILE> [--update]
-
-**Purpose**
-Register a new custom resource type. The resource type is fully defined by the YAML configuration file specified with `--config`.
-
-**Arguments**
-
-- `--config/-c FILE`: Path to the resource type YAML configuration file (required). The file must fully define the resource type, including the `name` field which determines the type's registered name.
-- `--update`: If the type name already exists, overwrite it. Without this flag, adding a duplicate name fails with an error.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource type add --config ./resource-types/svn.yaml
-
- ╭─ Resource Type ────────────────────╮
- │ Name: local/svn │
- │ Physical/Virtual: physical │
- │ User Addable: yes │
- │ Registered: 2026-02-09 10:15 │
- ╰────────────────────────────────────╯
-
- ╭─ CLI Arguments ────────────────────────╮
- │ Argument Required Description │
- │ ──────────── ──────── ───────────── │
- │ --url yes Repository URL │
- │ --checkout no Local checkout │
- ╰────────────────────────────────────────╯
-
- ╭─ Child Types ──────────────────────────╮
- │ Auto-discover: svn-revision, svn-file │
- │ Manual link: fs-mount │
- ╰────────────────────────────────────────╯
-
- ╭─ Sandbox ──────────────────────╮
- │ Strategy: copy_on_write │
- │ Handler: SVNHandler (custom) │
- ╰────────────────────────────────╯
-
- ✓ OK Resource type registered
- ℹ New subcommand available: agents resource add local/svn
-
-
-=== "Plain"
-
- ```
- $ agents resource type add --config ./resource-types/svn.yaml
-
- Resource Type
- Name: local/svn
- Physical/Virtual: physical
- User Addable: yes
- Registered: 2026-02-09 10:15
-
- CLI Arguments
- Argument Required Description
- ------------ -------- -------------
- --url yes Repository URL
- --checkout no Local checkout
-
- Child Types
- Auto-discover: svn-revision, svn-file
- Manual link: fs-mount
-
- Sandbox
- Strategy: copy_on_write
- Handler: SVNHandler (custom)
-
- [OK] Resource type registered
- Info: New subcommand available: agents resource add local/svn
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource type add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/svn",
- "physical_virtual": "physical",
- "user_addable": true,
- "registered": "2026-02-09T10:15:00Z",
- "cli_arguments": [
- { "argument": "--url", "required": true, "description": "Repository URL" },
- { "argument": "--checkout", "required": false, "description": "Local checkout" }
- ],
- "child_types": {
- "auto_discover": ["svn-revision", "svn-file"],
- "manual_link": ["fs-mount"]
- },
- "sandbox": {
- "strategy": "copy_on_write",
- "handler": "SVNHandler (custom)"
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 85 },
- "messages": ["Resource type registered", "New subcommand available: agents resource add local/svn"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource type add
- status: ok
- exit_code: 0
- data:
- name: local/svn
- physical_virtual: physical
- user_addable: true
- registered: "2026-02-09T10:15:00Z"
- cli_arguments:
- - argument: "--url"
- required: true
- description: Repository URL
- - argument: "--checkout"
- required: false
- description: Local checkout
- child_types:
- auto_discover:
- - svn-revision
- - svn-file
- manual_link:
- - fs-mount
- sandbox:
- strategy: copy_on_write
- handler: "SVNHandler (custom)"
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 85
- messages:
- - "Resource type registered"
- - "New subcommand available: agents resource add local/svn"
- ```
-
-##### agents resource type remove
-
-agents resource type remove [--yes|-y] <NAME>
-
-!!! warning "Destructive Operation"
- Remove a custom resource type. ==Built-in types cannot be removed.== Fails if any registered resources currently use this type — remove those resources first.
-
-**Arguments**
-
-- ``: Resource type name.
-- `--yes`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource type remove local/svn
-
- Remove resource type local/svn? [y/N]: y
-
- ╭─ Resource Type Removed ───────╮
- │ Name: local/svn │
- │ Resources Using: 0 │
- │ Subcommand Removed: yes │
- ╰───────────────────────────────╯
-
- ✓ OK Resource type removed
-
-
-=== "Plain"
-
- ```
- $ agents resource type remove local/svn
-
- Remove resource type local/svn? [y/N]: y
-
- Resource Type Removed
- Name: local/svn
- Resources Using: 0
- Subcommand Removed: yes
-
- [OK] Resource type removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource type remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/svn",
- "resources_using": 0,
- "subcommand_removed": true
- },
- "timing": { "started": "2026-02-09T10:16:00Z", "duration_ms": 60 },
- "messages": ["Resource type removed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource type remove
- status: ok
- exit_code: 0
- data:
- name: local/svn
- resources_using: 0
- subcommand_removed: true
- timing:
- started: "2026-02-09T10:16:00Z"
- duration_ms: 60
- messages:
- - "Resource type removed"
- ```
-
-##### agents resource type list
-
-agents resource type list [<REGEX>]
-
-**Purpose**
-List all registered resource types (built-in and custom).
-
-**Arguments**
-
-None (use the global `--format` option to control output format).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource type list
-
- ╭─ Resource Types ──────────────────────────────────────────────────────────────────────────────────╮
- │ Name Source Phys/Virt Addable Auto-children │
- │ ─────────────────── ──────── ───────── ─────── ────────────────────────────────────── │
- │ git-checkout built-in physical yes git, fs-directory │
- │ git built-in physical yes git-remote, git-branch, git-tag, │
- │ git-commit, git-stash, git-submodule │
- │ git-remote built-in physical no (none) │
- │ git-branch built-in physical no git-commit │
- │ git-tag built-in physical no (none) │
- │ git-commit built-in physical no git-tree │
- │ git-tree built-in physical no git-tree-entry │
- │ git-tree-entry built-in physical no (none) │
- │ git-stash built-in physical no (none) │
- │ git-submodule built-in physical no (none) │
- │ fs-mount built-in physical yes fs-directory │
- │ fs-directory built-in physical yes fs-file, fs-directory, │
- │ fs-symlink, fs-hardlink │
- │ fs-file built-in physical no (none) │
- │ fs-symlink built-in physical no (none) │
- │ fs-hardlink built-in physical no (none) │
- │ file built-in virtual no (none) │
- │ directory built-in virtual no (none) │
- │ symlink built-in virtual no (none) │
- │ commit built-in virtual no (none) │
- │ branch built-in virtual no (none) │
- │ tag built-in virtual no (none) │
- │ remote built-in virtual no (none) │
- │ submodule built-in virtual no (none) │
- │ tree built-in virtual no (none) │
- │ local/svn custom physical yes svn-revision, svn-file │
- ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ─────────────────╮
- │ Built-in: 24 │
- │ Custom: 1 │
- │ User Addable: 4 │
- ╰───────────────────────────╯
-
- ✓ OK 25 resource types listed
-
-
-=== "Plain"
-
- ```
- $ agents resource type list
-
- Resource Types
- -------------------
- Name Source Phys/Virt Addable Auto-children
- ------------------- -------- --------- ------- --------------------------------------
- git-checkout built-in physical yes git, fs-directory
- git built-in physical yes git-remote, git-branch, git-tag, git-commit, git-stash, git-submodule
- git-remote built-in physical no (none)
- git-branch built-in physical no git-commit
- git-tag built-in physical no (none)
- git-commit built-in physical no git-tree
- git-tree built-in physical no git-tree-entry
- git-tree-entry built-in physical no (none)
- git-stash built-in physical no (none)
- git-submodule built-in physical no (none)
- fs-mount built-in physical yes fs-directory
- fs-directory built-in physical yes fs-file, fs-directory, fs-symlink, fs-hardlink
- fs-file built-in physical no (none)
- fs-symlink built-in physical no (none)
- fs-hardlink built-in physical no (none)
- file built-in virtual no (none)
- directory built-in virtual no (none)
- symlink built-in virtual no (none)
- commit built-in virtual no (none)
- branch built-in virtual no (none)
- tag built-in virtual no (none)
- remote built-in virtual no (none)
- submodule built-in virtual no (none)
- tree built-in virtual no (none)
- local/svn custom physical yes svn-revision, svn-file
-
- Summary
- Built-in: 24
- Custom: 1
- User Addable: 4
-
- [OK] 25 resource types listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource type list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resource_types": [
- { "name": "git-checkout", "source": "built-in", "physical_virtual": "physical", "addable": true, "auto_children": ["git", "fs-directory"] },
- { "name": "git", "source": "built-in", "physical_virtual": "physical", "addable": true, "auto_children": ["git-remote", "git-branch", "git-tag", "git-commit", "git-stash", "git-submodule"] },
- { "name": "git-remote", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "git-branch", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": ["git-commit"] },
- { "name": "git-tag", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "git-commit", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": ["git-tree"] },
- { "name": "git-tree", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": ["git-tree-entry"] },
- { "name": "git-tree-entry", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "git-stash", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "git-submodule", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "fs-mount", "source": "built-in", "physical_virtual": "physical", "addable": true, "auto_children": ["fs-directory"] },
- { "name": "fs-directory", "source": "built-in", "physical_virtual": "physical", "addable": true, "auto_children": ["fs-file", "fs-directory", "fs-symlink", "fs-hardlink"] },
- { "name": "fs-file", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "fs-symlink", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "fs-hardlink", "source": "built-in", "physical_virtual": "physical", "addable": false, "auto_children": [] },
- { "name": "file", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "directory", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "symlink", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "commit", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "branch", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "tag", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "remote", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "submodule", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "tree", "source": "built-in", "physical_virtual": "virtual", "addable": false, "auto_children": [] },
- { "name": "local/svn", "source": "custom", "physical_virtual": "physical", "addable": true, "auto_children": ["svn-revision", "svn-file"] }
- ],
- "summary": {
- "built_in": 24,
- "custom": 1,
- "user_addable": 4
- }
- },
- "timing": { "started": "2026-02-09T10:16:00Z", "duration_ms": 45 },
- "messages": ["25 resource types listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource type list
- status: ok
- exit_code: 0
- data:
- resource_types:
- - name: git-checkout
- source: built-in
- physical_virtual: physical
- addable: true
- auto_children: [git, fs-directory]
- - name: git
- source: built-in
- physical_virtual: physical
- addable: true
- auto_children: [git-remote, git-branch, git-tag, git-commit, git-stash, git-submodule]
- - name: git-remote
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: git-branch
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: [git-commit]
- - name: git-tag
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: git-commit
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: [git-tree]
- - name: git-tree
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: [git-tree-entry]
- - name: git-tree-entry
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: git-stash
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: git-submodule
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: fs-mount
- source: built-in
- physical_virtual: physical
- addable: true
- auto_children: [fs-directory]
- - name: fs-directory
- source: built-in
- physical_virtual: physical
- addable: true
- auto_children: [fs-file, fs-directory, fs-symlink, fs-hardlink]
- - name: fs-file
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: fs-symlink
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: fs-hardlink
- source: built-in
- physical_virtual: physical
- addable: false
- auto_children: []
- - name: file
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: directory
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: symlink
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: commit
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: branch
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: tag
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: remote
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: submodule
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: tree
- source: built-in
- physical_virtual: virtual
- addable: false
- auto_children: []
- - name: local/svn
- source: custom
- physical_virtual: physical
- addable: true
- auto_children: [svn-revision, svn-file]
- summary:
- built_in: 24
- custom: 1
- user_addable: 4
- timing:
- started: "2026-02-09T10:16:00Z"
- duration_ms: 45
- messages:
- - "25 resource types listed"
- ```
-
-##### agents resource type show
-
-agents resource type show <NAME>
-
-**Purpose**
-Show detailed information about a resource type, including its full schema.
-
-**Arguments**
-
-- ``: Resource type name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource type show git-checkout
-
- ╭─ Resource Type ──────────────────────────────────────────────────────╮
- │ Name: git-checkout │
- │ Source: built-in │
- │ Description: A locally checked-out git repository with worktree │
- │ Physical/Virtual: physical │
- │ User Addable: yes │
- ╰──────────────────────────────────────────────────────────────────────╯
-
- ╭─ CLI Arguments (agents resource add git-checkout) ─────────────────╮
- │ Argument Required Type Description │
- │ ────────── ──────── ────── ────────────────────────────── │
- │ --path yes path Local checkout directory │
- │ --branch no string Default branch (default: main) │
- ╰────────────────────────────────────────────────────────────────────╯
-
- ╭─ Parent Types ───────────────╮
- │ Allowed: (any, top-level OK) │
- ╰──────────────────────────────╯
-
- ╭─ Child Types ────────────────────────────────────────────────────╮
- │ Type Auto Manual Link Description │
- │ ───────────── ──── ─────────── ────────────────────────── │
- │ git yes no Repo object DB and history │
- │ fs-directory yes no Worktree root directory │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Sandbox ──────────────────────╮
- │ Strategy: git_worktree │
- │ Checkpointable: yes │
- │ Handler: GitCheckoutHandler │
- ╰────────────────────────────────╯
-
- ✓ OK Resource type details loaded
-
-
-=== "Plain"
-
- ```
- $ agents resource type show git-checkout
-
- Resource Type
- Name: git-checkout
- Source: built-in
- Description: A locally checked-out git repository with worktree
- Physical/Virtual: physical
- User Addable: yes
-
- CLI Arguments (agents resource add git-checkout)
- Argument Required Type Description
- ---------- -------- ------ ------------------------------
- --path yes path Local checkout directory
- --branch no string Default branch (default: main)
-
- Parent Types
- Allowed: (any, top-level OK)
-
- Child Types
- Type Auto Manual Link Description
- ------------- ---- ----------- --------------------------
- git yes no Repo object DB and history
- fs-directory yes no Worktree root directory
-
- Sandbox
- Strategy: git_worktree
- Checkpointable: yes
- Handler: GitCheckoutHandler
-
- [OK] Resource type details loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource type show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "git-checkout",
- "source": "built-in",
- "description": "A locally checked-out git repository with worktree",
- "physical_virtual": "physical",
- "user_addable": true,
- "cli_arguments": [
- { "argument": "--path", "required": true, "type": "path", "description": "Local checkout directory" },
- { "argument": "--branch", "required": false, "type": "string", "description": "Default branch (default: main)" }
- ],
- "parent_types": {
- "allowed": "any",
- "top_level": true
- },
- "child_types": [
- { "type": "git", "auto": true, "manual_link": false, "description": "Repo object DB and history" },
- { "type": "fs-directory", "auto": true, "manual_link": false, "description": "Worktree root directory" }
- ],
- "sandbox": {
- "strategy": "git_worktree",
- "checkpointable": true,
- "handler": "GitCheckoutHandler"
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 42 },
- "messages": ["Resource type details loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource type show
- status: ok
- exit_code: 0
- data:
- name: git-checkout
- source: built-in
- description: "A locally checked-out git repository with worktree"
- physical_virtual: physical
- user_addable: true
- cli_arguments:
- - argument: "--path"
- required: true
- type: path
- description: "Local checkout directory"
- - argument: "--branch"
- required: false
- type: string
- description: "Default branch (default: main)"
- parent_types:
- allowed: any
- top_level: true
- child_types:
- - type: git
- auto: true
- manual_link: false
- description: "Repo object DB and history"
- - type: fs-directory
- auto: true
- manual_link: false
- description: "Worktree root directory"
- sandbox:
- strategy: git_worktree
- checkpointable: true
- handler: GitCheckoutHandler
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 42
- messages:
- - "Resource type details loaded"
- ```
-
-#### agents resource
-
-!!! info "Purpose"
- Manage independently registered ==resources==. Resources represent anything that can be read, written, or queried — git repositories, filesystems, databases, APIs, and more. Resources are registered independently of projects and linked to one or more projects via `agents project link-resource`. Resources form a ==directed acyclic graph (DAG)== with parent/child relationships, and child resources are often auto-discovered when a parent resource is registered.
-
-??? example "Supported Resource Types"
- | Type | Physical | Description |
- | :--- | :------: | :---------- |
- | `git-checkout` | Yes | Local git working directory |
- | `git` | Yes | Bare git repository |
- | `fs-mount` | Yes | Filesystem mount point |
- | `fs-directory` | Virtual | Directory within a mount |
- | `fs-file` | Virtual | Individual file reference |
- | `container-instance` | Yes | Container instance ([ADR-039](adr/ADR-039-container-resource-types.md)) |
- | `devcontainer-instance` | Yes | Devcontainer instance ([ADR-043](adr/ADR-043-devcontainer-integration.md)) |
- | Custom types | Varies | Registered via `agents resource type add` |
-
-##### agents resource add
-
-agents resource add [(--description|-d) <DESC>] [--update] <TYPE> <NAME> [type-specific-flags...]
-
-**Purpose**
-Register a new resource. Every resource receives a system-assigned ULID. User-added resources also require a namespaced name (`[[server:]namespace/]name`) specified at creation time. The `add` command uses type-specific subcommands — each registered resource type (built-in or custom) provides its own subcommand with type-appropriate arguments. On success, the command returns both the name and the ULID assigned to the newly created resource.
-
-**Arguments**
-
-- ``: Resource type name (e.g., `git-checkout`, `git`, `fs-mount`, `fs-directory`, `local/svn`). Determines type-specific flags.
-- ``: Namespaced resource name (positional, required). Must be globally unique following the standard `[[server:]namespace/]name` format.
-- `--description/-d TEXT`: Optional resource description.
-
-Type-specific flags depend on the resource type. See `agents resource type show ` for available arguments.
-
-**Container-specific flags** (for `container-instance` and `devcontainer-instance` types):
-
-- `--image IMAGE_REF`: Container image reference (e.g., `ubuntu:latest`, `python:3.12-slim`). Required for `container-instance` when `--container-id` is not provided. Not required for `devcontainer-instance` (image is derived from `devcontainer.json`).
-- `--mount RESOURCE_OR_PATH:CONTAINER_PATH`: Mount a resource or host path into the container (repeatable). Accepts either a resource reference (`local/api-repo:/workspace`) or a raw host path (`/home/user/projects/api:/workspace`). See [ADR-043 §3.2](adr/ADR-043-devcontainer-integration.md).
-- `--clone-into REPO_URL:CONTAINER_PATH`: Clone a remote repository into the container at the specified path. The clone happens lazily on first container start.
-
-The command returns the name and ULID of the newly created resource. Auto-discovered child resources are created automatically with ULIDs only (no names).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource add git-checkout local/api-repo --path /home/user/projects/api-service --branch main
-
- ╭─ Resource ──────────────────────────────────────╮
- │ Name: local/api-repo │
- │ ID: 01HXR1A1B2C3D4E5F6G7H8J9K0 │
- │ Type: git-checkout │
- │ Physical/Virtual: physical │
- │ Path: /home/user/projects/api-service │
- │ Branch: main │
- │ Created: 2026-02-09 10:20 │
- ╰─────────────────────────────────────────────────╯
-
- ╭─ Auto-discovered Children ─────────────────────────────────────────╮
- │ ID Type Status │
- │ ─────────────── ────────────── ───────────────── │
- │ 01HXR1A1B2C3… git created │
- │ 01HXR1A1B2C4… git-remote created │
- │ 01HXR1A1B2C5… git-branch created │
- │ 01HXR1A1B2C6… git-branch created │
- │ 01HXR1A1B2C7… fs-directory created │
- │ + 47 git-commit resources │
- │ + 312 git-tree-entry resources │
- │ + 3 fs-directory + 28 fs-file │
- ╰────────────────────────────────────────────────────────────────────╯
-
- ╭─ Capabilities ─────────────────╮
- │ Readable: yes │
- │ Writable: yes │
- │ Sandboxable: yes │
- │ Checkpointable: yes │
- │ Sandbox Strategy: git_worktree │
- ╰────────────────────────────────╯
-
- ✓ OK Resource registered (395 child resources discovered)
-
-
-
- $ agents resource add fs-mount local/docs --mount-path /docs/api-reference
-
- ╭─ Resource ──────────────────────────────────────╮
- │ Name: local/docs │
- │ ID: 01HXR2B3C4D5E6F7G8H9J0K1L2 │
- │ Type: fs-mount │
- │ Physical/Virtual: physical │
- │ Mount Path: /docs/api-reference │
- │ Created: 2026-02-09 10:22 │
- ╰─────────────────────────────────────────────────╯
-
- ╭─ Auto-discovered Children ────────────────────╮
- │ + 1 fs-directory (root) │
- │ + 3 fs-directory resources │
- │ + 28 fs-file resources │
- ╰───────────────────────────────────────────────╯
-
- ╭─ Capabilities ──────────────────────╮
- │ Readable: yes │
- │ Writable: yes │
- │ Sandboxable: yes │
- │ Checkpointable: yes │
- │ Sandbox Strategy: copy_on_write │
- ╰─────────────────────────────────────╯
-
- ✓ OK Resource registered (31 child resources discovered)
-
-
-
- $ agents resource add container-instance local/api-dev --mount local/api-repo:/workspace --mount /home/user/.config/nvim:/home/dev/.config/nvim
-
- ╭─ Resource ──────────────────────────────────────╮
- │ Name: local/api-dev │
- │ ID: 01HXR3C4D5E6F7G8H9J0K1L2M3 │
- │ Type: container-instance │
- │ Physical/Virtual: physical │
- │ State: created (not started) │
- │ Created: 2026-02-09 10:25 │
- ╰─────────────────────────────────────────────────╯
-
- ╭─ Mounts ──────────────────────────────────────────────────────────╮
- │ Source Container Path Kind │
- │ ──────────────────────────────── ─────────────── ─────────── │
- │ local/api-repo /workspace resource-ref │
- │ /home/user/.config/nvim /home/dev/… host-path │
- ╰───────────────────────────────────────────────────────────────────╯
-
- ✓ OK Container resource registered (container will start on first access)
-
-
-
- $ agents resource add container-instance cloud/ci-runner --clone-into https://github.com/acme/api.git:/workspace
-
- ╭─ Resource ──────────────────────────────────────╮
- │ Name: cloud/ci-runner │
- │ ID: 01HXR4D5E6F7G8H9J0K1L2M3N4 │
- │ Type: container-instance │
- │ Physical/Virtual: physical │
- │ State: created (not started) │
- │ Clone: https://github.com/acme/api.git │
- │ Clone Target: /workspace │
- │ Created: 2026-02-09 10:27 │
- ╰─────────────────────────────────────────────────╯
-
- ✓ OK Container resource registered (repo will be cloned on first start)
-
-
-
- $ agents resource add git-checkout local/webapp --path /home/user/projects/webapp
-
- ╭─ Resource ──────────────────────────────────────────╮
- │ Name: local/webapp │
- │ ID: 01HXR5E6F7G8H9J0K1L2M3N4O5 │
- │ Type: git-checkout │
- │ Physical/Virtual: physical │
- │ Path: /home/user/projects/webapp │
- │ Branch: main │
- │ Created: 2026-02-09 10:30 │
- ╰─────────────────────────────────────────────────────╯
-
- ╭─ Auto-discovered Children ─────────────────────────────────────────╮
- │ ID Type Status │
- │ ─────────────── ────────────────────── ─────────────────── │
- │ 01HXR5E6F7G9… git created │
- │ 01HXR5E6F7GA… devcontainer-instance detected (not built) │
- │ 01HXR5E6F7GB… fs-directory created │
- │ + 52 git-commit resources │
- │ + 189 git-tree-entry resources │
- ╰────────────────────────────────────────────────────────────────────╯
-
- ⚠ Devcontainer detected at .devcontainer/devcontainer.json
- Container will be built lazily on first access.
- Use agents resource show 01HXR5E6F7GA… to inspect.
-
- ✓ OK Resource registered (245 child resources discovered)
-
-
-=== "Plain"
-
- ```
- $ agents resource add git-checkout local/api-repo --path /home/user/projects/api-service --branch main
-
- Resource
- Name: local/api-repo
- ID: 01HXR1A1B2C3D4E5F6G7H8J9K0
- Type: git-checkout
- Physical/Virtual: physical
- Path: /home/user/projects/api-service
- Branch: main
- Created: 2026-02-09 10:20
-
- Auto-discovered Children
- ID Type Status
- --------------- -------------- -----------------
- 01HXR1A1B2C3.. git created
- 01HXR1A1B2C4.. git-remote created
- 01HXR1A1B2C5.. git-branch created
- 01HXR1A1B2C6.. git-branch created
- 01HXR1A1B2C7.. fs-directory created
- + 47 git-commit resources
- + 312 git-tree-entry resources
- + 3 fs-directory + 28 fs-file
-
- Capabilities
- Readable: yes
- Writable: yes
- Sandboxable: yes
- Checkpointable: yes
- Sandbox Strategy: git_worktree
-
- [OK] Resource registered (395 child resources discovered)
-
- $ agents resource add fs-mount local/docs --mount-path /docs/api-reference
-
- Resource
- Name: local/docs
- ID: 01HXR2B3C4D5E6F7G8H9J0K1L2
- Type: fs-mount
- Physical/Virtual: physical
- Mount Path: /docs/api-reference
- Created: 2026-02-09 10:22
-
- Auto-discovered Children
- + 1 fs-directory (root)
- + 3 fs-directory resources
- + 28 fs-file resources
-
- Capabilities
- Readable: yes
- Writable: yes
- Sandboxable: yes
- Checkpointable: yes
- Sandbox Strategy: copy_on_write
-
- [OK] Resource registered (31 child resources discovered)
-
- $ agents resource add container-instance local/api-dev --mount local/api-repo:/workspace --mount /home/user/.config/nvim:/home/dev/.config/nvim
-
- Resource
- Name: local/api-dev
- ID: 01HXR3C4D5E6F7G8H9J0K1L2M3
- Type: container-instance
- Physical/Virtual: physical
- State: created (not started)
- Created: 2026-02-09 10:25
-
- Mounts
- Source Container Path Kind
- -------------------------------- --------------- ---------
- local/api-repo /workspace resource-ref
- /home/user/.config/nvim /home/dev/... host-path
-
- [OK] Container resource registered (container will start on first access)
-
- $ agents resource add container-instance cloud/ci-runner --clone-into https://github.com/acme/api.git:/workspace
-
- Resource
- Name: cloud/ci-runner
- ID: 01HXR4D5E6F7G8H9J0K1L2M3N4
- Type: container-instance
- Physical/Virtual: physical
- State: created (not started)
- Clone: https://github.com/acme/api.git
- Clone Target: /workspace
- Created: 2026-02-09 10:27
-
- [OK] Container resource registered (repo will be cloned on first start)
-
- $ agents resource add git-checkout local/webapp --path /home/user/projects/webapp
-
- Resource
- Name: local/webapp
- ID: 01HXR5E6F7G8H9J0K1L2M3N4O5
- Type: git-checkout
- Physical/Virtual: physical
- Path: /home/user/projects/webapp
- Branch: main
- Created: 2026-02-09 10:30
-
- Auto-discovered Children
- ID Type Status
- --------------- ---------------------- -----------------
- 01HXR5E6F7G9.. git created
- 01HXR5E6F7GA.. devcontainer-instance detected (not built)
- 01HXR5E6F7GB.. fs-directory created
- + 52 git-commit resources
- + 189 git-tree-entry resources
-
- [WARN] Devcontainer detected at .devcontainer/devcontainer.json
- Container will be built lazily on first access.
- Use agents resource show 01HXR5E6F7GA… to inspect.
-
- [OK] Resource registered (245 child resources discovered)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/api-repo",
- "id": "01HXR1A1B2C3D4E5F6G7H8J9K0",
- "type": "git-checkout",
- "physical_virtual": "physical",
- "path": "/home/user/projects/api-service",
- "branch": "main",
- "created": "2026-02-09T10:20:00Z",
- "auto_discovered_children": [
- { "id": "01HXR1A1B2C3…", "type": "git", "status": "created" },
- { "id": "01HXR1A1B2C4…", "type": "git-remote", "status": "created" },
- { "id": "01HXR1A1B2C5…", "type": "git-branch", "status": "created" },
- { "id": "01HXR1A1B2C6…", "type": "git-branch", "status": "created" },
- { "id": "01HXR1A1B2C7…", "type": "fs-directory", "status": "created" }
- ],
- "children_summary": {
- "git_commit": 47,
- "git_tree_entry": 312,
- "fs_directory": 3,
- "fs_file": 28
- },
- "total_children": 395,
- "capabilities": {
- "readable": true,
- "writable": true,
- "sandboxable": true,
- "checkpointable": true,
- "sandbox_strategy": "git_worktree"
- }
- },
- "timing": { "started": "2026-02-09T10:20:00Z", "duration_ms": 250 },
- "messages": ["Resource registered (395 child resources discovered)"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource add
- status: ok
- exit_code: 0
- data:
- name: local/api-repo
- id: 01HXR1A1B2C3D4E5F6G7H8J9K0
- type: git-checkout
- physical_virtual: physical
- path: /home/user/projects/api-service
- branch: main
- created: "2026-02-09T10:20:00Z"
- auto_discovered_children:
- - id: "01HXR1A1B2C3\u2026"
- type: git
- status: created
- - id: "01HXR1A1B2C4\u2026"
- type: git-remote
- status: created
- - id: "01HXR1A1B2C5\u2026"
- type: git-branch
- status: created
- - id: "01HXR1A1B2C6\u2026"
- type: git-branch
- status: created
- - id: "01HXR1A1B2C7\u2026"
- type: fs-directory
- status: created
- children_summary:
- git_commit: 47
- git_tree_entry: 312
- fs_directory: 3
- fs_file: 28
- total_children: 395
- capabilities:
- readable: true
- writable: true
- sandboxable: true
- checkpointable: true
- sandbox_strategy: git_worktree
- timing:
- started: "2026-02-09T10:20:00Z"
- duration_ms: 250
- messages:
- - "Resource registered (395 child resources discovered)"
- ```
-
-##### agents resource remove
-
-agents resource remove [--yes|-y] <NAME>
-
-!!! danger "Cascading Deletion"
- Removes a registered resource ==and all its auto-discovered child resources==. A `git-checkout` resource can have hundreds of child resources (files, directories). This operation fails if the resource is linked to any project — use `agents project unlink-resource` first.
-
-**Arguments**
-
-- ``: Resource name (only user-added resources can be removed).
-- `--yes`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource remove local/api-repo
-
- Remove resource local/api-repo and 395 child resources? [y/N]: y
-
- ╭─ Resource Removed ──────────────────────────────────╮
- │ Name: local/api-repo │
- │ Type: git-checkout │
- │ Children Removed: 395 │
- │ Projects Unlinked: 0 │
- ╰─────────────────────────────────────────────────────╯
-
- ✓ OK Resource removed
-
-
-=== "Plain"
-
- ```
- $ agents resource remove local/api-repo
-
- Remove resource local/api-repo and 395 child resources? [y/N]: y
-
- Resource Removed
- Name: local/api-repo
- Type: git-checkout
- Children Removed: 395
- Projects Unlinked: 0
-
- [OK] Resource removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/api-repo",
- "type": "git-checkout",
- "children_removed": 395,
- "projects_unlinked": 0
- },
- "timing": { "started": "2026-02-09T10:24:00Z", "duration_ms": 120 },
- "messages": ["Resource removed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource remove
- status: ok
- exit_code: 0
- data:
- name: local/api-repo
- type: git-checkout
- children_removed: 395
- projects_unlinked: 0
- timing:
- started: "2026-02-09T10:24:00Z"
- duration_ms: 120
- messages:
- - "Resource removed"
- ```
-
-##### agents resource list
-
-agents resource list [--all] [(--type|-t) <TYPE>]
-
-**Purpose**
-List registered resources with optional filters. By default, lists only user-added (named) resources. Use `--all` to include auto-discovered child resources.
-
-**Arguments**
-
-- `--type/-t TYPE`: Filter by resource type (accepts a regex).
-- `--all`: Include auto-discovered child resources (by default only user-added resources are shown).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource list
-
- ╭─ Resources ──────────────────────────────────────────────────────────────────────────────────────────────╮
- │ Name ID Type Phys/Virt Children Projects │
- │ ───────────────── ──────────────────────────── ─────────── ───────── ──────── ──────────────── │
- │ local/api-repo 01HXR1A1B2C3D4E5F6G7H8J9K0 git-checkout physical 395 local/api-service │
- │ local/docs 01HXR2B2C3D4E5F6G7H8J9K0L1 fs-mount physical 32 local/api-service │
- │ local/staging-db 01HXR3C3D4E5F6G7H8J9K0L1M2 database physical 12 local/api-service, │
- │ local/staging │
- ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ───────────╮
- │ Total: 3 │
- │ Physical: 3 │
- │ Virtual: 0 │
- │ Total Children: 405 │
- ╰─────────────────────╯
-
- ✓ OK 3 resources listed
-
-
-=== "Plain"
-
- ```
- $ agents resource list
-
- Resources
- ---------
- Name ID Type Phys/Virt Children Projects
- ----------------- ---------------------------- ----------- --------- -------- ----------------
- local/api-repo 01HXR1A1B2C3D4E5F6G7H8J9K0 git-checkout physical 395 local/api-service
- local/docs 01HXR2B2C3D4E5F6G7H8J9K0L1 fs-mount physical 32 local/api-service
- local/staging-db 01HXR3C3D4E5F6G7H8J9K0L1M2 database physical 12 local/api-service, local/staging
-
- Summary
- Total: 3
- Physical: 3
- Virtual: 0
- Total Children: 405
-
- [OK] 3 resources listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resources": [
- {
- "name": "local/api-repo",
- "id": "01HXR1A1B2C3D4E5F6G7H8J9K0",
- "type": "git-checkout",
- "physical_virtual": "physical",
- "children": 395,
- "projects": ["local/api-service"]
- },
- {
- "name": "local/docs",
- "id": "01HXR2B2C3D4E5F6G7H8J9K0L1",
- "type": "fs-mount",
- "physical_virtual": "physical",
- "children": 32,
- "projects": ["local/api-service"]
- },
- {
- "name": "local/staging-db",
- "id": "01HXR3C3D4E5F6G7H8J9K0L1M2",
- "type": "database",
- "physical_virtual": "physical",
- "children": 12,
- "projects": ["local/api-service", "local/staging"]
- }
- ],
- "summary": {
- "total": 3,
- "physical": 3,
- "virtual": 0,
- "total_children": 405
- }
- },
- "timing": { "started": "2026-02-09T10:25:00Z", "duration_ms": 90 },
- "messages": ["3 resources listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource list
- status: ok
- exit_code: 0
- data:
- resources:
- - name: local/api-repo
- id: 01HXR1A1B2C3D4E5F6G7H8J9K0
- type: git-checkout
- physical_virtual: physical
- children: 395
- projects:
- - local/api-service
- - name: local/docs
- id: 01HXR2B2C3D4E5F6G7H8J9K0L1
- type: fs-mount
- physical_virtual: physical
- children: 32
- projects:
- - local/api-service
- - name: local/staging-db
- id: 01HXR3C3D4E5F6G7H8J9K0L1M2
- type: database
- physical_virtual: physical
- children: 12
- projects:
- - local/api-service
- - local/staging
- summary:
- total: 3
- physical: 3
- virtual: 0
- total_children: 405
- timing:
- started: "2026-02-09T10:25:00Z"
- duration_ms: 90
- messages:
- - "3 resources listed"
- ```
-
-##### agents resource show
-
-agents resource show <RESOURCE>
-
-**Purpose**
-Show detailed information about a registered resource including its type, capabilities, parent/child relationships, and linked projects.
-
-**Arguments**
-
-- ``: Resource name or ULID.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource show local/api-repo
-
- ╭─ Resource ─────────────────────────────────────────╮
- │ Name: local/api-repo │
- │ ID: 01HXR1A1B2C3D4E5F6G7H8J9K0 │
- │ Type: git-checkout │
- │ Physical/Virtual: physical │
- │ Path: /home/user/projects/api-service │
- │ Branch: main │
- │ Created: 2026-02-09 10:20 │
- ╰────────────────────────────────────────────────────╯
-
- ╭─ Capabilities ────────────────────╮
- │ Readable: yes │
- │ Writable: yes │
- │ Sandboxable: yes │
- │ Checkpointable: yes │
- │ Sandbox Strategy: git_worktree │
- ╰───────────────────────────────────╯
-
- ╭─ Parents ────╮
- │ (top-level) │
- ╰──────────────╯
-
- ╭─ Direct Children ──────────────────────────────────────────────────────╮
- │ ID Type Auto Children │
- │ ──────────────────────────── ──────────── ──── ──────── │
- │ 01HXR4D4E5F6G7H8J9K0L1M2N3 git yes 363 │
- │ 01HXR5E5F6G7H8J9K0L1M2N3P4 fs-directory yes 32 │
- ╰────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Linked Projects ─────────────╮
- │ - local/api-service (r/w) │
- ╰───────────────────────────────╯
-
- ╭─ Tool Bindings ────────────────────────────────╮
- │ Tool Slot Access │
- │ ──────────────────────── ───── ─────────── │
- │ (builtin) git_status repo read_only │
- │ (builtin) git_diff repo read_only │
- │ (builtin) git_log repo read_only │
- │ local/run-migrations db (not bound) │
- ╰────────────────────────────────────────────────╯
-
- ✓ OK Resource details loaded
-
-
-=== "Plain"
-
- ```
- $ agents resource show local/api-repo
-
- Resource
- Name: local/api-repo
- ID: 01HXR1A1B2C3D4E5F6G7H8J9K0
- Type: git-checkout
- Physical/Virtual: physical
- Path: /home/user/projects/api-service
- Branch: main
- Created: 2026-02-09 10:20
-
- Capabilities
- Readable: yes
- Writable: yes
- Sandboxable: yes
- Checkpointable: yes
- Sandbox Strategy: git_worktree
-
- Parents
- (top-level)
-
- Direct Children
- ID Type Auto Children
- ---------------------------- ------------ ---- --------
- 01HXR4D4E5F6G7H8J9K0L1M2N3 git yes 363
- 01HXR5E5F6G7H8J9K0L1M2N3P4 fs-directory yes 32
-
- Linked Projects
- - local/api-service (r/w)
-
- Tool Bindings
- Tool Slot Access
- ------------------------ ----- -----------
- (builtin) git_status repo read_only
- (builtin) git_diff repo read_only
- (builtin) git_log repo read_only
- local/run-migrations db (not bound)
-
- [OK] Resource details loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/api-repo",
- "id": "01HXR1A1B2C3D4E5F6G7H8J9K0",
- "type": "git-checkout",
- "physical_virtual": "physical",
- "path": "/home/user/projects/api-service",
- "branch": "main",
- "created": "2026-02-09T10:20:00Z",
- "capabilities": {
- "readable": true,
- "writable": true,
- "sandboxable": true,
- "checkpointable": true,
- "sandbox_strategy": "git_worktree"
- },
- "parents": ["(top-level)"],
- "direct_children": [
- { "id": "01HXR4D4E5F6G7H8J9K0L1M2N3", "type": "git", "auto": true, "children": 363 },
- { "id": "01HXR5E5F6G7H8J9K0L1M2N3P4", "type": "fs-directory", "auto": true, "children": 32 }
- ],
- "linked_projects": [
- { "name": "local/api-service", "access": "r/w" }
- ],
- "tool_bindings": [
- { "tool": "(builtin) git_status", "slot": "repo", "access": "read_only" },
- { "tool": "(builtin) git_diff", "slot": "repo", "access": "read_only" },
- { "tool": "(builtin) git_log", "slot": "repo", "access": "read_only" },
- { "tool": "local/run-migrations", "slot": "db", "access": "(not bound)" }
- ]
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 65 },
- "messages": ["Resource details loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource show
- status: ok
- exit_code: 0
- data:
- name: local/api-repo
- id: 01HXR1A1B2C3D4E5F6G7H8J9K0
- type: git-checkout
- physical_virtual: physical
- path: /home/user/projects/api-service
- branch: main
- created: "2026-02-09T10:20:00Z"
- capabilities:
- readable: true
- writable: true
- sandboxable: true
- checkpointable: true
- sandbox_strategy: git_worktree
- parents:
- - (top-level)
- direct_children:
- - id: 01HXR4D4E5F6G7H8J9K0L1M2N3
- type: git
- auto: true
- children: 363
- - id: 01HXR5E5F6G7H8J9K0L1M2N3P4
- type: fs-directory
- auto: true
- children: 32
- linked_projects:
- - name: local/api-service
- access: r/w
- tool_bindings:
- - tool: (builtin) git_status
- slot: repo
- access: read_only
- - tool: (builtin) git_diff
- slot: repo
- access: read_only
- - tool: (builtin) git_log
- slot: repo
- access: read_only
- - tool: local/run-migrations
- slot: db
- access: (not bound)
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 65
- messages:
- - Resource details loaded
- ```
-
-##### agents resource inspect
-
-agents resource inspect [--tree] [--file <PATH>] <RESOURCE>
-
-**Purpose**
-Inspect a resource's contents. For file-based resources (git checkouts, filesystem mounts, directories), displays the file tree or the contents of a specific file. Works with any resource — user-added or auto-discovered — via name or ULID.
-
-**Arguments**
-
-- ``: Resource name or ULID.
-- `--tree`: Show the resource's file/content tree.
-- `--file PATH`: Show contents of a specific file within the resource.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource inspect local/api-repo --tree
-
- ╭─ Resource Tree: local/api-repo ──────────────────────────────────────╮
- │ │
- │ /home/user/projects/api-service │
- │ ├── src/ │
- │ │ ├── api/ │
- │ │ │ ├── __init__.py │
- │ │ │ ├── auth/ │
- │ │ │ │ ├── auth_middleware.py │
- │ │ │ │ ├── token_service.py │
- │ │ │ │ └── rbac.py │
- │ │ │ ├── routes/ │
- │ │ │ └── models/ │
- │ │ └── utils/ │
- │ ├── tests/ │
- │ ├── README.md │
- │ └── pyproject.toml │
- │ │
- ╰──────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ──────────────╮
- │ Directories: 8 │
- │ Files: 41 │
- │ Total Size: 284 KB │
- ╰────────────────────────╯
-
- ✓ OK Resource tree displayed
-
-
-=== "Plain"
-
- ```
- $ agents resource inspect local/api-repo --tree
-
- Resource Tree: local/api-repo
-
- /home/user/projects/api-service
- +-- src/
- | +-- api/
- | | +-- __init__.py
- | | +-- auth/
- | | | +-- auth_middleware.py
- | | | +-- token_service.py
- | | | +-- rbac.py
- | | +-- routes/
- | | +-- models/
- | +-- utils/
- +-- tests/
- +-- README.md
- +-- pyproject.toml
-
- Summary
- Directories: 8
- Files: 41
- Total Size: 284 KB
-
- [OK] Resource tree displayed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource inspect",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resource": "local/api-repo",
- "mode": "tree",
- "root": "/home/user/projects/api-service",
- "tree": [
- {
- "name": "src/",
- "type": "directory",
- "children": [
- {
- "name": "api/",
- "type": "directory",
- "children": [
- { "name": "__init__.py", "type": "file" },
- {
- "name": "auth/",
- "type": "directory",
- "children": [
- { "name": "auth_middleware.py", "type": "file" },
- { "name": "token_service.py", "type": "file" },
- { "name": "rbac.py", "type": "file" }
- ]
- },
- { "name": "routes/", "type": "directory" },
- { "name": "models/", "type": "directory" }
- ]
- },
- { "name": "utils/", "type": "directory" }
- ]
- },
- { "name": "tests/", "type": "directory" },
- { "name": "README.md", "type": "file" },
- { "name": "pyproject.toml", "type": "file" }
- ],
- "summary": {
- "directories": 8,
- "files": 41,
- "total_size": "284 KB"
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 150 },
- "messages": ["Resource tree displayed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource inspect
- status: ok
- exit_code: 0
- data:
- resource: local/api-repo
- mode: tree
- root: /home/user/projects/api-service
- tree:
- - name: src/
- type: directory
- children:
- - name: api/
- type: directory
- children:
- - name: __init__.py
- type: file
- - name: auth/
- type: directory
- children:
- - name: auth_middleware.py
- type: file
- - name: token_service.py
- type: file
- - name: rbac.py
- type: file
- - name: routes/
- type: directory
- - name: models/
- type: directory
- - name: utils/
- type: directory
- - name: tests/
- type: directory
- - name: README.md
- type: file
- - name: pyproject.toml
- type: file
- summary:
- directories: 8
- files: 41
- total_size: 284 KB
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 150
- messages:
- - Resource tree displayed
- ```
-
-=== "Rich"
-
-
- $ agents resource inspect local/api-repo --file src/api/auth/auth_middleware.py
-
- ╭─ File: src/api/auth/auth_middleware.py ──────────────────╮
- │ Resource: local/api-repo │
- │ Size: 2.4 KB │
- │ Language: Python │
- │ Last Modified: 2026-02-10 14:32 │
- ╰──────────────────────────────────────────────────────────╯
-
- 1 │ from fastapi import Request, HTTPException
- 2 │ from .token_service import validate_token
- 3 │
- 4 │ async def auth_middleware(request: Request):
- 5 │ token = request.headers.get("Authorization")
- 6 │ if not token:
- 7 │ raise HTTPException(status_code=401)
- 8 │ user = await validate_token(token)
- 9 │ request.state.user = user
- 10 │ return user
- │ ... (24 more lines)
-
- ✓ OK File displayed
-
-
-=== "Plain"
-
- ```
- $ agents resource inspect local/api-repo --file src/api/auth/auth_middleware.py
-
- File: src/api/auth/auth_middleware.py
- Resource: local/api-repo
- Size: 2.4 KB
- Language: Python
- Last Modified: 2026-02-10 14:32
-
- 1 | from fastapi import Request, HTTPException
- 2 | from .token_service import validate_token
- 3 |
- 4 | async def auth_middleware(request: Request):
- 5 | token = request.headers.get("Authorization")
- 6 | if not token:
- 7 | raise HTTPException(status_code=401)
- 8 | user = await validate_token(token)
- 9 | request.state.user = user
- 10 | return user
- | ... (24 more lines)
-
- [OK] File displayed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource inspect",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resource": "local/api-repo",
- "mode": "file",
- "file": {
- "path": "src/api/auth/auth_middleware.py",
- "size": "2.4 KB",
- "language": "Python",
- "last_modified": "2026-02-10T14:32:00Z",
- "lines_shown": 10,
- "total_lines": 34,
- "content": "from fastapi import Request, HTTPException\nfrom .token_service import validate_token\n\nasync def auth_middleware(request: Request):\n token = request.headers.get(\"Authorization\")\n if not token:\n raise HTTPException(status_code=401)\n user = await validate_token(token)\n request.state.user = user\n return user\n"
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 30 },
- "messages": ["File displayed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource inspect
- status: ok
- exit_code: 0
- data:
- resource: local/api-repo
- mode: file
- file:
- path: src/api/auth/auth_middleware.py
- size: 2.4 KB
- language: Python
- last_modified: "2026-02-10T14:32:00Z"
- lines_shown: 10
- total_lines: 34
- content: |
- from fastapi import Request, HTTPException
- from .token_service import validate_token
-
- async def auth_middleware(request: Request):
- token = request.headers.get("Authorization")
- if not token:
- raise HTTPException(status_code=401)
- user = await validate_token(token)
- request.state.user = user
- return user
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 30
- messages:
- - File displayed
- ```
-
-##### agents resource tree
-
-agents resource tree [(--depth|-d) <N>] [(--type|-t) <TYPE>] <RESOURCE>
-
-**Purpose**
-Display the resource DAG as a tree starting from a given resource, showing parent/child relationships.
-
-**Arguments**
-
-- ``: Resource name or ULID.
-- `--depth/-d N`: Maximum depth to display (default: 3).
-- `--type/-t TYPE`: Filter to only show children of a specific type.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource tree local/api-repo --depth 2
-
- ╭─ Resource Tree: local/api-repo ─────────────────────────────────────╮
- │ │
- │ git-checkout 01HXR1A1..J9K0 (physical) │
- │ ├── git 01HXR4D4..M2N3 (physical) │
- │ │ ├── git-remote 01HXR6F6..P4Q5 │
- │ │ ├── git-branch 01HXR7G7..Q5R6 │
- │ │ │ ├── git-commit 01HXR8H8..R6S7 │
- │ │ │ └── ... 22 more git-commit resources │
- │ │ └── git-branch 01HXR9J9..S7T8 │
- │ │ └── ... 26 git-commit resources │
- │ └── fs-directory 01HXR5E5..N3P4 (physical) │
- │ ├── fs-directory 01HXRAK1..T8U9 │
- │ ├── fs-directory 01HXRBL2..U9V0 │
- │ └── ... 28 more fs-file resources │
- │ │
- ╰─────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ──────────────╮
- │ Total shown: 14 │
- │ Total in subtree: 395 │
- │ Max depth: 2 │
- ╰────────────────────────╯
-
- ✓ OK Resource tree displayed
-
-
-=== "Plain"
-
- ```
- $ agents resource tree local/api-repo --depth 2
-
- Resource Tree: local/api-repo
-
- git-checkout 01HXR1A1..J9K0 (physical)
- +-- git 01HXR4D4..M2N3 (physical)
- | +-- git-remote 01HXR6F6..P4Q5
- | +-- git-branch 01HXR7G7..Q5R6
- | | +-- git-commit 01HXR8H8..R6S7
- | | +-- ... 22 more git-commit resources
- | +-- git-branch 01HXR9J9..S7T8
- | +-- ... 26 git-commit resources
- +-- fs-directory 01HXR5E5..N3P4 (physical)
- +-- fs-directory 01HXRAK1..T8U9
- +-- fs-directory 01HXRBL2..U9V0
- +-- ... 28 more fs-file resources
-
- Summary
- Total shown: 14
- Total in subtree: 395
- Max depth: 2
-
- [OK] Resource tree displayed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource tree",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "resource": "local/api-repo",
- "max_depth": 2,
- "tree": {
- "type": "git-checkout",
- "id": "01HXR1A1..J9K0",
- "physical": true,
- "children": [
- {
- "type": "git",
- "id": "01HXR4D4..M2N3",
- "physical": true,
- "children": [
- { "type": "git-remote", "id": "01HXR6F6..P4Q5" },
- {
- "type": "git-branch",
- "id": "01HXR7G7..Q5R6",
- "children": [
- { "type": "git-commit", "id": "01HXR8H8..R6S7" },
- "... 22 more git-commit resources"
- ]
- },
- {
- "type": "git-branch",
- "id": "01HXR9J9..S7T8",
- "children": ["... 26 git-commit resources"]
- }
- ]
- },
- {
- "type": "fs-directory",
- "id": "01HXR5E5..N3P4",
- "physical": true,
- "children": [
- { "type": "fs-directory", "id": "01HXRAK1..T8U9" },
- { "type": "fs-directory", "id": "01HXRBL2..U9V0" },
- "... 28 more fs-file resources"
- ]
- }
- ]
- },
- "summary": {
- "total_shown": 14,
- "total_in_subtree": 395,
- "max_depth": 2
- }
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 85 },
- "messages": ["Resource tree displayed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource tree
- status: ok
- exit_code: 0
- data:
- resource: local/api-repo
- max_depth: 2
- tree:
- type: git-checkout
- id: 01HXR1A1..J9K0
- physical: true
- children:
- - type: git
- id: 01HXR4D4..M2N3
- physical: true
- children:
- - type: git-remote
- id: 01HXR6F6..P4Q5
- - type: git-branch
- id: 01HXR7G7..Q5R6
- children:
- - type: git-commit
- id: 01HXR8H8..R6S7
- - "... 22 more git-commit resources"
- - type: git-branch
- id: 01HXR9J9..S7T8
- children:
- - "... 26 git-commit resources"
- - type: fs-directory
- id: 01HXR5E5..N3P4
- physical: true
- children:
- - type: fs-directory
- id: 01HXRAK1..T8U9
- - type: fs-directory
- id: 01HXRBL2..U9V0
- - "... 28 more fs-file resources"
- summary:
- total_shown: 14
- total_in_subtree: 395
- max_depth: 2
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 85
- messages:
- - Resource tree displayed
- ```
-
-##### agents resource link-child
-
-agents resource link-child <PARENT> <CHILD>
-
-**Purpose**
-Manually link one resource as a child of another. The child resource must already be registered. The resource types must be compatible (the parent type must allow the child type). A resource can have multiple parents.
-
-**Arguments**
-
-- ``: Parent resource name or ULID.
-- ``: Child resource name or ULID.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource link-child local/api-repo 01HXR2B2C3D4E5F6G7H8J9K0L1
-
- ╭─ Child Linked ──────────────────────────────────────╮
- │ Parent: local/api-repo │
- │ Child: 01HXR2B2C3D4E5F6G7H8J9K0L1 │
- │ Child Type: fs-mount │
- │ Status: linked │
- ╰─────────────────────────────────────────────────────╯
-
- ✓ OK Child resource linked
-
-
-=== "Plain"
-
- ```
- $ agents resource link-child local/api-repo 01HXR2B2C3D4E5F6G7H8J9K0L1
-
- Child Linked
- Parent: local/api-repo
- Child: 01HXR2B2C3D4E5F6G7H8J9K0L1
- Child Type: fs-mount
- Status: linked
-
- [OK] Child resource linked
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource link-child",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "parent": "local/api-repo",
- "child": "01HXR2B2C3D4E5F6G7H8J9K0L1",
- "child_type": "fs-mount",
- "status": "linked"
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 38 },
- "messages": ["Child resource linked"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource link-child
- status: ok
- exit_code: 0
- data:
- parent: local/api-repo
- child: 01HXR2B2C3D4E5F6G7H8J9K0L1
- child_type: fs-mount
- status: linked
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 38
- messages:
- - Child resource linked
- ```
-
-##### agents resource unlink-child
-
-agents resource unlink-child [--yes|-y] <PARENT> <CHILD>
-
-**Purpose**
-Remove a manual parent/child link between two resources. Auto-discovered links cannot be manually unlinked.
-
-**Arguments**
-
-- ``: Parent resource name or ULID.
-- ``: Child resource name or ULID.
-- `--yes`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource unlink-child local/api-repo 01HXR2B2C3D4E5F6G7H8J9K0L1
-
- Unlink 01HXR2B2C3D4E5F6G7H8J9K0L1 from parent local/api-repo? [y/N]: y
-
- ╭─ Child Unlinked ────────────────────────────────────╮
- │ Parent: local/api-repo │
- │ Child: 01HXR2B2C3D4E5F6G7H8J9K0L1 │
- │ Status: unlinked │
- ╰─────────────────────────────────────────────────────╯
-
- ✓ OK Child resource unlinked
-
-
-=== "Plain"
-
- ```
- $ agents resource unlink-child local/api-repo 01HXR2B2C3D4E5F6G7H8J9K0L1
-
- Unlink 01HXR2B2C3D4E5F6G7H8J9K0L1 from parent local/api-repo? [y/N]: y
-
- Child Unlinked
- Parent: local/api-repo
- Child: 01HXR2B2C3D4E5F6G7H8J9K0L1
- Status: unlinked
-
- [OK] Child resource unlinked
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "resource unlink-child",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "parent": "local/api-repo",
- "child": "01HXR2B2C3D4E5F6G7H8J9K0L1",
- "status": "unlinked"
- },
- "timing": { "started": "2026-02-09T10:15:00Z", "duration_ms": 45 },
- "messages": ["Child resource unlinked"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: resource unlink-child
- status: ok
- exit_code: 0
- data:
- parent: local/api-repo
- child: 01HXR2B2C3D4E5F6G7H8J9K0L1
- status: unlinked
- timing:
- started: "2026-02-09T10:15:00Z"
- duration_ms: 45
- messages:
- - Child resource unlinked
- ```
-
-##### agents resource stop
-
-agents resource stop <NAME> [--yes | -y]
-
-**Purpose**
-Stop an active `devcontainer-instance` or `container-instance` resource. Transitions the container through `running → stopping → stopped`. Only container-typed resources may be stopped; attempting to stop other resource types produces an error.
-
-**Arguments**
-
-- ``: Resource name or ULID of the devcontainer to stop.
-
-**Options**
-
-- `--yes` / `-y`: Skip the confirmation prompt (useful in scripts and automation).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource stop local/my-dc
-
- Stopping container local/my-dc (state: running)...
- Stopped: local/my-dc
-
-
-=== "Plain"
-
- ```
- $ agents resource stop local/my-dc
-
- Stopping container local/my-dc (state: running)...
- Stopped: local/my-dc
- ```
-
-##### agents resource rebuild
-
-agents resource rebuild <NAME> [--yes | -y]
-
-**Purpose**
-Rebuild a stopped or failed `devcontainer-instance` resource. Transitions the container through `stopped/failed → building → running` by invoking `devcontainer up` with the resource's workspace location. Only `devcontainer-instance` resources may be rebuilt since the rebuild process invokes the devcontainer CLI; generic `container-instance` resources do not support rebuild.
-
-**Arguments**
-
-- ``: Resource name or ULID of the devcontainer to rebuild.
-
-**Options**
-
-- `--yes` / `-y`: Skip the confirmation prompt (useful in scripts and automation).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents resource rebuild local/my-dc
-
- Rebuilding local/my-dc...
- Rebuilt: local/my-dc
-
-
-=== "Plain"
-
- ```
- $ agents resource rebuild local/my-dc
-
- Rebuilding local/my-dc...
- Rebuilt: local/my-dc
- ```
-
-#### agents plan
-
-!!! info "Purpose"
- Manage ==plans== through the **Strategize → Execute → Apply** lifecycle (instantiated from Action templates).
-
-??? abstract "Plan Lifecycle at a Glance"
- ```
- Action ──use──▶ Strategize ──execute──▶ Execute ──apply──▶ Apply
- ▲ │ │
- └──────────────────────┘ │
- ▲ (reversion) │
- └────────────────────────────────────────┘
- ```
-
- - [x] **Action** — Reusable template defining work, actors, and constraints
- - [x] **Strategize** — Strategy actor produces a decision tree
- - [x] **Execute** — Execution actor implements the strategy in a sandbox
- - [x] **Apply** — Changeset is merged into real project resources
-
- !!! note "Phase Reversion"
- Both Execute and Apply can revert to Strategize when constraints are too restrictive. See `delete_content` and `access_network` automation profile flags.
-
-##### agents plan list
-
-agents plan list [--phase <PHASE>] [--state <STATE>] [--project <PROJECT>]
- [--action <ACTION>] [<REGEX>]
-
-**Purpose**
-List plans with optional filtering.
-
-**Arguments**
-
-- `--phase PHASE`: Filter by phase.
-- `--state STATE`: Filter by processing state.
-- `--project PROJECT`: Filter by project.
-- `--action ACTION`: Filter by action name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents --format table plan list --phase execute
-
- ╭─ Plans ──────────────────────────────────────────────────────────────────────────────╮
- │ ID Phase State Action Project Elapsed │
- │ ──────── ─────── ────────── ─────────────────── ───────────────── ───────── │
- │ 01HXM7A9 execute processing local/code-coverage local/api-service 00:01:12 │
- ╰──────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Filters ──────╮
- │ Phase: execute │
- │ State: (any) │
- │ Project: (any) │
- │ Action: (any) │
- ╰────────────────╯
-
- ╭─ Summary ─────────╮
- │ Total: 1 │
- │ Processing: 1 │
- │ Completed: 0 │
- │ Errored: 0 │
- ╰───────────────────╯
-
- ✓ OK 1 plan listed
-
-
-=== "Plain"
-
- ```
- $ agents --format table plan list --phase execute
-
- Plans
- ID Phase State Action Project Elapsed
- -------- ------- ---------- ------------------- ----------------- ---------
- 01HXM7A9 execute processing local/code-coverage local/api-service 00:01:12
-
- Filters
- Phase: execute
- State: (any)
- Project: (any)
- Action: (any)
-
- Summary
- Total: 1
- Processing: 1
- Completed: 0
- Errored: 0
-
- [OK] 1 plan listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plans": [
- {
- "id": "01HXM7A9",
- "phase": "execute",
- "state": "processing",
- "action": "local/code-coverage",
- "project": "local/api-service",
- "elapsed": "00:01:12"
- }
- ],
- "filters": {
- "phase": "execute",
- "state": null,
- "project": null,
- "action": null
- },
- "summary": {
- "total": 1,
- "processing": 1,
- "completed": 0,
- "errored": 0
- }
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 95 },
- "messages": ["1 plan listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan list
- status: ok
- exit_code: 0
- data:
- plans:
- - id: "01HXM7A9"
- phase: execute
- state: processing
- action: "local/code-coverage"
- project: "local/api-service"
- elapsed: "00:01:12"
- filters:
- phase: execute
- state: null
- project: null
- action: null
- summary:
- total: 1
- processing: 1
- completed: 0
- errored: 0
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 95
- messages:
- - "1 plan listed"
- ```
-
-Listing all plans without filters shows plans across all phases and states:
-
-=== "Rich"
-
-
- $ agents plan list
-
- ╭─ Plans ──────────────────────────────────────────────────────────────────────────────────────╮
- │ ID Phase State Action Project Elapsed │
- │ ──────── ────────── ────────── ─────────────────── ───────────────── ───────── │
- │ 01HXM7A9 execute processing local/code-coverage local/api-service 00:01:12 │
- │ 01HXM6R3 apply applied local/add-auth local/api-service 00:07:14 │
- │ 01HXM5K2 execute errored local/migrate-db local/api-service 00:04:33 │
- │ 01HXM4J1 strategize processing local/refactor-api local/web-app 00:00:45 │
- │ 01HXM3H8 cancelled cancelled local/add-logging local/api-service 00:02:10 │
- ╰──────────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ─────────────╮
- │ Total: 5 │
- │ Processing: 2 │
- │ Completed: 1 │
- │ Errored: 1 │
- │ Cancelled: 1 │
- ╰───────────────────────╯
-
- ✓ OK 5 plans listed
-
-
-=== "Plain"
-
- ```
- $ agents plan list
-
- Plans
- ID Phase State Action Project Elapsed
- -------- ---------- ---------- ------------------- ----------------- ---------
- 01HXM7A9 execute processing local/code-coverage local/api-service 00:01:12
- 01HXM6R3 apply applied local/add-auth local/api-service 00:07:14
- 01HXM5K2 execute errored local/migrate-db local/api-service 00:04:33
- 01HXM4J1 strategize processing local/refactor-api local/web-app 00:00:45
- 01HXM3H8 cancelled cancelled local/add-logging local/api-service 00:02:10
-
- Summary
- Total: 5
- Processing: 2
- Completed: 1
- Errored: 1
- Cancelled: 1
-
- [OK] 5 plans listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plans": [
- { "id": "01HXM7A9", "phase": "execute", "state": "processing", "action": "local/code-coverage", "project": "local/api-service", "elapsed": "00:01:12" },
- { "id": "01HXM6R3", "phase": "apply", "state": "applied", "action": "local/add-auth", "project": "local/api-service", "elapsed": "00:07:14" },
- { "id": "01HXM5K2", "phase": "execute", "state": "errored", "action": "local/migrate-db", "project": "local/api-service", "elapsed": "00:04:33" },
- { "id": "01HXM4J1", "phase": "strategize", "state": "processing", "action": "local/refactor-api", "project": "local/web-app", "elapsed": "00:00:45" },
- { "id": "01HXM3H8", "phase": "cancelled", "state": "cancelled", "action": "local/add-logging", "project": "local/api-service", "elapsed": "00:02:10" }
- ],
- "summary": {
- "total": 5,
- "processing": 2,
- "completed": 1,
- "errored": 1,
- "cancelled": 1
- }
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 95 },
- "messages": ["5 plans listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan list
- status: ok
- exit_code: 0
- data:
- plans:
- - id: "01HXM7A9"
- phase: execute
- state: processing
- action: "local/code-coverage"
- project: "local/api-service"
- elapsed: "00:01:12"
- - id: "01HXM6R3"
- phase: apply
- state: applied
- action: "local/add-auth"
- project: "local/api-service"
- elapsed: "00:07:14"
- - id: "01HXM5K2"
- phase: execute
- state: errored
- action: "local/migrate-db"
- project: "local/api-service"
- elapsed: "00:04:33"
- - id: "01HXM4J1"
- phase: strategize
- state: processing
- action: "local/refactor-api"
- project: "local/web-app"
- elapsed: "00:00:45"
- - id: "01HXM3H8"
- phase: cancelled
- state: cancelled
- action: "local/add-logging"
- project: "local/api-service"
- elapsed: "00:02:10"
- summary:
- total: 5
- processing: 2
- completed: 1
- errored: 1
- cancelled: 1
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 95
- messages:
- - "5 plans listed"
- ```
-
-Filtering by project with `--project`:
-
-=== "Rich"
-
-
- $ agents plan list --project local/web-app
-
- ╭─ Plans ──────────────────────────────────────────────────────────────────────────────╮
- │ ID Phase State Action Project Elapsed │
- │ ──────── ────────── ────────── ─────────────────── ───────────── ───────── │
- │ 01HXM4J1 strategize processing local/refactor-api local/web-app 00:00:45 │
- ╰──────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Filters ─────────────────╮
- │ Phase: (any) │
- │ State: (any) │
- │ Project: local/web-app │
- │ Action: (any) │
- ╰───────────────────────────╯
-
- ✓ OK 1 plan listed
-
-
-=== "Plain"
-
- ```
- $ agents plan list --project local/web-app
-
- Plans
- ID Phase State Action Project Elapsed
- -------- ---------- ---------- ------------------- ------------- ---------
- 01HXM4J1 strategize processing local/refactor-api local/web-app 00:00:45
-
- Filters
- Phase: (any)
- State: (any)
- Project: local/web-app
- Action: (any)
-
- [OK] 1 plan listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plans": [
- {
- "id": "01HXM4J1",
- "phase": "strategize",
- "state": "processing",
- "action": "local/refactor-api",
- "project": "local/web-app",
- "elapsed": "00:00:45"
- }
- ],
- "filters": {
- "phase": null,
- "state": null,
- "project": "local/web-app",
- "action": null
- },
- "total": 1
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 85 },
- "messages": ["1 plan listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan list
- status: ok
- exit_code: 0
- data:
- plans:
- - id: "01HXM4J1"
- phase: strategize
- state: processing
- action: "local/refactor-api"
- project: "local/web-app"
- elapsed: "00:00:45"
- filters:
- phase: null
- state: null
- project: "local/web-app"
- action: null
- total: 1
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 85
- messages:
- - "1 plan listed"
- ```
-
-##### agents plan use
-
-agents plan use [--automation-profile <PROFILE>]
- [--invariant <INVARIANT>]...
- [--strategy-actor <STRATEGY_ACTOR>]
- [--execution-actor <EXEC_ACTOR>]
- [--estimation-actor <EST_ACTOR>]
- [--invariant-actor <INV_ACTOR>]
- [--execution-environment <RESOURCE_NAME>]
- [--execution-env-priority (fallback|override)]
- [--arg/-a name=value]...
- <ACTION> <PROJECT>...
-
-**Purpose**
-Apply an action to one or more projects and start the Strategize phase.
-
-**Arguments**
-
-- ``: Action name.
-- ``: One or more project names (positional arguments, repeatable).
-- `--arg/-a name=value`: Action argument (repeatable).
-- `--automation-profile PROFILE`: Automation profile name (e.g., `trusted`, `auto`, `local/careful-auto`). Overrides the profile inherited from the action, project, or global config.
-- `--strategy-actor ACTOR`: Override the action's strategy actor for this plan.
-- `--execution-actor ACTOR`: Override the action's execution actor for this plan.
-- `--estimation-actor ACTOR`: Override the action's estimation actor for this plan.
-- `--invariant-actor ACTOR`: Override the action's Invariant Reconciliation Actor for this plan.
-- `--invariant TEXT`: Invariant to attach to the created plan (repeatable). These are added as plan-level invariants in addition to any invariants inherited from the action, project, or global scope.
-- `--execution-environment RESOURCE_NAME`: Name of a `container-instance` or `devcontainer-instance` resource to use as the execution environment for this plan. Overrides or supplements the project-level `execution_environment` setting depending on `--execution-env-priority`. See [ADR-043 §3.3](adr/ADR-043-devcontainer-integration.md).
-- `--execution-env-priority fallback|override`: Priority semantics for the plan-level execution environment. `fallback` (default): defers to auto-detected devcontainers or project-level overrides. `override`: always uses the specified environment, bypassing all other resolution. See §Execution Environment Routing.
-
-All actor arguments (`--strategy-actor`, `--execution-actor`, `--estimation-actor`, `--invariant-actor`) are optional overrides. When provided, they replace whatever was set when creating the action. When omitted, the action's configured actors are used.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan use local/code-coverage local/api-service \
- --arg target_coverage_percent=85 --automation-profile trusted
-
- ╭─ Plan Created ──────────────────────╮
- │ Plan ID: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: strategize │
- │ Action: local/code-coverage │
- │ Project: local/api-service │
- │ Automation: trusted │
- │ Attempt: 1 │
- ╰─────────────────────────────────────╯
-
- ╭─ Inputs ──────────────────────╮
- │ - target_coverage_percent=85 │
- │ - automation_profile=trusted │
- ╰───────────────────────────────╯
-
- ╭─ Actors ────────────────────────╮
- │ Strategy: local/strategist │
- │ Execution: local/executor │
- │ Estimation: (none) │
- ╰─────────────────────────────────╯
-
- ╭─ Automation ─────────────────────────╮
- │ Profile: trusted │
- │ Source: CLI flag │
- │ Read-Only: no │
- ╰──────────────────────────────────────╯
-
- ╭─ Context ───────────────────────╮
- │ Resources: 2 (repo, db) │
- │ Indexed Files: 347 │
- │ View: strategize │
- │ Hot Token Budget: 12,000 │
- ╰─────────────────────────────────╯
-
- ╭─ Next Steps ─────────────────────────────────────╮
- │ - agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ - agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ - agents plan tree 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- ╰──────────────────────────────────────────────────╯
-
- ✓ OK Plan created
-
-
-=== "Plain"
-
- ```
- $ agents plan use local/code-coverage local/api-service \
- --arg target_coverage_percent=85 --automation-profile trusted
-
- Plan Created
- Plan ID: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Phase: strategize
- Action: local/code-coverage
- Project: local/api-service
- Automation: trusted
- Attempt: 1
-
- Inputs
- - target_coverage_percent=85
- - automation_profile=trusted
-
- Actors
- Strategy: local/strategist
- Execution: local/executor
- Estimation: (none)
-
- Automation
- Profile: trusted
- Source: CLI flag
- Read-Only: no
-
- Context
- Resources: 2 (repo, db)
- Indexed Files: 347
- View: strategize
- Hot Token Budget: 12,000
-
- Next Steps
- - agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- - agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- - agents plan tree 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- [OK] Plan created
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan use",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "phase": "strategize",
- "action": "local/code-coverage",
- "project": "local/api-service",
- "automation_profile": "trusted",
- "attempt": 1,
- "inputs": {
- "target_coverage_percent": 85,
- "automation_profile": "trusted"
- },
- "actors": {
- "strategy": "local/strategist",
- "execution": "local/executor",
- "estimation": null
- },
- "automation": {
- "profile": "trusted",
- "source": "CLI flag",
- "read_only": false
- },
- "context": {
- "resources": 2,
- "indexed_files": 347,
- "view": "strategize",
- "hot_token_budget": 12000
- },
- "next_steps": [
- "agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "agents plan tree 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- ]
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 95 },
- "messages": ["Plan created"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan use
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- phase: strategize
- action: "local/code-coverage"
- project: "local/api-service"
- automation_profile: trusted
- attempt: 1
- inputs:
- target_coverage_percent: 85
- automation_profile: trusted
- actors:
- strategy: "local/strategist"
- execution: "local/executor"
- estimation: null
- automation:
- profile: trusted
- source: "CLI flag"
- read_only: false
- context:
- resources: 2
- indexed_files: 347
- view: strategize
- hot_token_budget: 12000
- next_steps:
- - "agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- - "agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- - "agents plan tree 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 95
- messages:
- - "Plan created"
- ```
-
-Applying an action to multiple projects simultaneously, with plan-level invariants:
-
-=== "Rich"
-
-
- $ agents plan use local/security-audit local/api-service local/web-app \
- --invariant "Never modify production database schemas" \
- --invariant "All changes must include test coverage" \
- --automation-profile supervised
-
- ╭─ Plan Created ──────────────────────────────────────╮
- │ Plan: 01HXM9D2ZK4Q7C2B3F2R4VYV6J │
- │ Action: local/security-audit │
- │ Phase: strategize (running) │
- │ Automation: supervised │
- ╰─────────────────────────────────────────────────────╯
-
- ╭─ Target Projects ───────────────────╮
- │ 1. local/api-service (3 resources) │
- │ 2. local/web-app (2 resources) │
- ╰─────────────────────────────────────╯
-
- ╭─ Plan Invariants ──────────────────────────────────────────╮
- │ Scope Source Invariant │
- │ ──────── ─────── ────────────────────────────────── │
- │ plan CLI Never modify production DB schemas │
- │ plan CLI All changes must include test coverage │
- │ project config API responses must be backward-compat │
- │ global config Follow Python PEP 8 style guide │
- ╰────────────────────────────────────────────────────────────╯
-
- ✓ OK Plan created — strategize in progress
-
-
-=== "Plain"
-
- ```
- $ agents plan use local/security-audit local/api-service local/web-app \
- --invariant "Never modify production database schemas" \
- --invariant "All changes must include test coverage" \
- --automation-profile supervised
-
- Plan Created
- Plan: 01HXM9D2ZK4Q7C2B3F2R4VYV6J
- Action: local/security-audit
- Phase: strategize (running)
- Automation: supervised
-
- Target Projects
- 1. local/api-service (3 resources)
- 2. local/web-app (2 resources)
-
- Plan Invariants
- Scope Source Invariant
- -------- ------- ----------------------------------
- plan CLI Never modify production DB schemas
- plan CLI All changes must include test coverage
- project config API responses must be backward-compat
- global config Follow Python PEP 8 style guide
-
- [OK] Plan created -- strategize in progress
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan use",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM9D2ZK4Q7C2B3F2R4VYV6J",
- "action": "local/security-audit",
- "phase": "strategize",
- "phase_state": "running",
- "automation_profile": "supervised",
- "target_projects": [
- { "name": "local/api-service", "resources": 3 },
- { "name": "local/web-app", "resources": 2 }
- ],
- "invariants": [
- { "scope": "plan", "source": "CLI", "text": "Never modify production DB schemas" },
- { "scope": "plan", "source": "CLI", "text": "All changes must include test coverage" },
- { "scope": "project", "source": "config", "text": "API responses must be backward-compat" },
- { "scope": "global", "source": "config", "text": "Follow Python PEP 8 style guide" }
- ]
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 130 },
- "messages": ["Plan created -- strategize in progress"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan use
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM9D2ZK4Q7C2B3F2R4VYV6J"
- action: "local/security-audit"
- phase: strategize
- phase_state: running
- automation_profile: supervised
- target_projects:
- - name: "local/api-service"
- resources: 3
- - name: "local/web-app"
- resources: 2
- invariants:
- - scope: plan
- source: CLI
- text: "Never modify production DB schemas"
- - scope: plan
- source: CLI
- text: "All changes must include test coverage"
- - scope: project
- source: config
- text: "API responses must be backward-compat"
- - scope: global
- source: config
- text: "Follow Python PEP 8 style guide"
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 130
- messages:
- - "Plan created -- strategize in progress"
- ```
-
-Using an action with custom actor overrides:
-
-=== "Rich"
-
-
- $ agents plan use local/code-coverage local/api-service \
- --strategy-actor local/senior-planner \
- --execution-actor local/fast-executor \
- --arg target_coverage_percent=95
-
- ╭─ Plan Created ──────────────────────────────────────╮
- │ Plan: 01HXM9E3ZK4Q7C2B3F2R4VYV6J │
- │ Action: local/code-coverage │
- │ Phase: strategize (running) │
- │ Automation: trusted │
- ╰─────────────────────────────────────────────────────╯
-
- ╭─ Actor Overrides ────────────────────╮
- │ Strategy: local/senior-planner │
- │ Execution: local/fast-executor │
- │ (Estimation: action default) │
- ╰──────────────────────────────────────╯
-
- ╭─ Arguments ─────────────────╮
- │ target_coverage_percent: 95 │
- ╰─────────────────────────────╯
-
- ✓ OK Plan created — strategize in progress
-
-
-=== "Plain"
-
- ```
- $ agents plan use local/code-coverage local/api-service \
- --strategy-actor local/senior-planner \
- --execution-actor local/fast-executor \
- --arg target_coverage_percent=95
-
- Plan Created
- Plan: 01HXM9E3ZK4Q7C2B3F2R4VYV6J
- Action: local/code-coverage
- Phase: strategize (running)
- Automation: trusted
-
- Actor Overrides
- Strategy: local/senior-planner
- Execution: local/fast-executor
- (Estimation: action default)
-
- Arguments
- target_coverage_percent: 95
-
- [OK] Plan created -- strategize in progress
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan use",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM9E3ZK4Q7C2B3F2R4VYV6J",
- "action": "local/code-coverage",
- "phase": "strategize",
- "phase_state": "running",
- "automation_profile": "trusted",
- "actor_overrides": {
- "strategy": "local/senior-planner",
- "execution": "local/fast-executor",
- "estimation": null
- },
- "arguments": {
- "target_coverage_percent": 95
- }
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 110 },
- "messages": ["Plan created -- strategize in progress"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan use
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM9E3ZK4Q7C2B3F2R4VYV6J"
- action: "local/code-coverage"
- phase: strategize
- phase_state: running
- automation_profile: trusted
- actor_overrides:
- strategy: "local/senior-planner"
- execution: "local/fast-executor"
- estimation: null
- arguments:
- target_coverage_percent: 95
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 110
- messages:
- - "Plan created -- strategize in progress"
- ```
-
-##### agents plan execute
-
-agents plan execute <PLAN_ID>
-
-**Purpose**
-Start or resume execution for a plan.
-
-**Arguments**
-
-- ``: Plan ID (required).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Execution ──────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: execute │
- │ Sandbox: git_worktree │
- │ Worker: local/executor │
- │ Started: 12:58:10 │
- │ Attempt: 1 │
- ╰──────────────────────────────────╯
-
- ╭─ Sandbox ──────────────────────────────────╮
- │ Strategy: git_worktree │
- │ Path: /repos/api/.worktrees/plan-01HXM8 │
- │ Branch: cleveragents/plan-01HXM8C2 │
- │ Status: active │
- ╰────────────────────────────────────────────╯
-
- ╭─ Strategy Summary ─────────────────────╮
- │ Decisions: 8 │
- │ Invariants: 2 │
- │ Planned Child Plans: 2+ │
- │ Estimated Files: ~12 │
- │ Risk: low │
- ╰────────────────────────────────────────╯
-
- ╭─ Progress ─────────╮
- │ ⏳ Collect context │
- │ • Run tools │
- │ • Build changeset │
- │ • Validate │
- ╰────────────────────╯
-
- ✓ OK Execution started
-
-
-=== "Plain"
-
- ```
- $ agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Execution
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Phase: execute
- Sandbox: git_worktree
- Worker: local/executor
- Started: 12:58:10
- Attempt: 1
-
- Sandbox
- Strategy: git_worktree
- Path: /repos/api/.worktrees/plan-01HXM8
- Branch: cleveragents/plan-01HXM8C2
- Status: active
-
- Strategy Summary
- Decisions: 8
- Invariants: 2
- Planned Child Plans: 2+
- Estimated Files: ~12
- Risk: low
-
- Progress
- ... Collect context
- . Run tools
- . Build changeset
- . Validate
-
- [OK] Execution started
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan execute",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "sandbox": {
- "strategy": "git_worktree",
- "path": "/repos/api/.worktrees/plan-01HXM8",
- "branch": "cleveragents/plan-01HXM8C2",
- "status": "active"
- },
- "worker": "local/executor",
- "started": "12:58:10",
- "attempt": 1,
- "strategy_summary": {
- "decisions": 8,
- "invariants": 2,
- "planned_child_plans": "2+",
- "estimated_files": 12,
- "risk": "low"
- },
- "progress": [
- { "label": "Collect context", "status": "running" },
- { "label": "Run tools", "status": "pending" },
- { "label": "Build changeset", "status": "pending" },
- { "label": "Validate", "status": "pending" }
- ]
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 150 },
- "messages": ["Execution started"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan execute
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- phase: execute
- sandbox:
- strategy: git_worktree
- path: "/repos/api/.worktrees/plan-01HXM8"
- branch: "cleveragents/plan-01HXM8C2"
- status: active
- worker: "local/executor"
- started: "12:58:10"
- attempt: 1
- strategy_summary:
- decisions: 8
- invariants: 2
- planned_child_plans: "2+"
- estimated_files: 12
- risk: low
- progress:
- - label: "Collect context"
- status: running
- - label: "Run tools"
- status: pending
- - label: "Build changeset"
- status: pending
- - label: "Validate"
- status: pending
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 150
- messages:
- - "Execution started"
- ```
-
-Resuming execution of a plan that was previously paused or errored:
-
-=== "Rich"
-
-
- $ agents plan execute 01HXM7K2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Execution Resumed ─────────────────╮
- │ Plan: 01HXM7K2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: execute (resumed) │
- │ Sandbox: git_worktree │
- │ Worker: local/executor │
- │ Checkpoint: cp_01HXM8C2 (loaded) │
- │ Resumed From: step 4 of 6 │
- ╰─────────────────────────────────────╯
-
- ╭─ Previous Progress ──────────────────────╮
- │ ✓ Step 1: Collect context (0.8s) │
- │ ✓ Step 2: Analyze codebase (4.2s) │
- │ ✓ Step 3: Generate migrations (6.1s) │
- │ ✗ Step 4: Apply migrations (errored) │
- │ ○ Step 5: Update models (pending) │
- │ ○ Step 6: Run validations (pending) │
- ╰──────────────────────────────────────────╯
-
- ╭─ Guidance Applied ──────────────────────────────────────────────╮
- │ "Use smaller batch sizes for the migration to avoid timeouts" │
- ╰─────────────────────────────────────────────────────────────────╯
-
- ✓ OK Execution resumed from checkpoint cp_01HXM8C2
-
-
-=== "Plain"
-
- ```
- $ agents plan execute 01HXM7K2ZK4Q7C2B3F2R4VYV6J
-
- Execution Resumed
- Plan: 01HXM7K2ZK4Q7C2B3F2R4VYV6J
- Phase: execute (resumed)
- Sandbox: git_worktree
- Worker: local/executor
- Checkpoint: cp_01HXM8C2 (loaded)
- Resumed From: step 4 of 6
-
- Previous Progress
- v Step 1: Collect context (0.8s)
- v Step 2: Analyze codebase (4.2s)
- v Step 3: Generate migrations (6.1s)
- x Step 4: Apply migrations (errored)
- o Step 5: Update models (pending)
- o Step 6: Run validations (pending)
-
- Guidance Applied
- "Use smaller batch sizes for the migration to avoid timeouts"
-
- [OK] Execution resumed from checkpoint cp_01HXM8C2
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan execute",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM7K2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "resumed": true,
- "sandbox": "git_worktree",
- "worker": "local/executor",
- "checkpoint": "cp_01HXM8C2",
- "resumed_from": "step 4 of 6",
- "progress": [
- { "step": 1, "label": "Collect context", "status": "done", "duration_s": 0.8 },
- { "step": 2, "label": "Analyze codebase", "status": "done", "duration_s": 4.2 },
- { "step": 3, "label": "Generate migrations", "status": "done", "duration_s": 6.1 },
- { "step": 4, "label": "Apply migrations", "status": "errored" },
- { "step": 5, "label": "Update models", "status": "pending" },
- { "step": 6, "label": "Run validations", "status": "pending" }
- ],
- "guidance": "Use smaller batch sizes for the migration to avoid timeouts"
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 180 },
- "messages": ["Execution resumed from checkpoint cp_01HXM8C2"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan execute
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM7K2ZK4Q7C2B3F2R4VYV6J"
- phase: execute
- resumed: true
- sandbox: git_worktree
- worker: "local/executor"
- checkpoint: "cp_01HXM8C2"
- resumed_from: "step 4 of 6"
- progress:
- - step: 1
- label: "Collect context"
- status: done
- duration_s: 0.8
- - step: 2
- label: "Analyze codebase"
- status: done
- duration_s: 4.2
- - step: 3
- label: "Generate migrations"
- status: done
- duration_s: 6.1
- - step: 4
- label: "Apply migrations"
- status: errored
- - step: 5
- label: "Update models"
- status: pending
- - step: 6
- label: "Run validations"
- status: pending
- guidance: "Use smaller batch sizes for the migration to avoid timeouts"
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 180
- messages:
- - "Execution resumed from checkpoint cp_01HXM8C2"
- ```
-
-##### agents plan apply
-
-agents plan apply [--yes|-y] <PLAN_ID>
-
-**Purpose**
-Apply sandboxed changes to real resources.
-
-**Arguments**
-
-- ``: Plan ID.
-- `--yes`: Skip confirmation.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan apply 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Apply changes for plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J? [y/N]: y
-
- ╭─ Apply Summary ─────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Artifacts: 6 files updated │
- │ Changes: 42 insertions, 9 deletions │
- │ Project: local/api-service │
- │ Applied At: 2026-02-08 13:04 │
- ╰─────────────────────────────────────╯
-
- ╭─ Validation (from Execute) ────╮
- │ Tests: passed (24/24) │
- │ Lint: passed (0 warnings) │
- │ Type Check: passed (0 errors) │
- │ Duration: 12.4s │
- ╰────────────────────────────────╯
-
- ╭─ Sandbox Cleanup ─────────╮
- │ Worktree: removed │
- │ Branch: merged to main │
- │ Checkpoint: archived │
- ╰───────────────────────────╯
-
- ╭─ Plan Lifecycle ────────────────────────╮
- │ Phase: apply │
- │ State: applied │
- │ Total Duration: 00:06:14 │
- │ Total Cost: $0.0847 │
- │ Decisions Made: 8 │
- │ Child Plans: 2 (completed) │
- ╰─────────────────────────────────────────╯
-
- ╭─ Next Steps ──────╮
- │ - Review git diff │
- │ - Commit changes │
- ╰───────────────────╯
-
- ✓ OK Changes applied
-
-
-=== "Plain"
-
- ```
- $ agents plan apply 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Apply changes for plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J? [y/N]: y
-
- Apply Summary
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Artifacts: 6 files updated
- Changes: 42 insertions, 9 deletions
- Project: local/api-service
- Applied At: 2026-02-08 13:04
-
- Validation (from Execute)
- Tests: passed (24/24)
- Lint: passed (0 warnings)
- Type Check: passed (0 errors)
- Duration: 12.4s
-
- Sandbox Cleanup
- Worktree: removed
- Branch: merged to main
- Checkpoint: archived
-
- Plan Lifecycle
- Phase: apply
- State: applied
- Total Duration: 00:06:14
- Total Cost: $0.0847
- Decisions Made: 8
- Child Plans: 2 (completed)
-
- Next Steps
- - Review git diff
- - Commit changes
-
- [OK] Changes applied
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan apply",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "artifacts": 6,
- "changes": {
- "insertions": 42,
- "deletions": 9
- },
- "project": "local/api-service",
- "applied_at": "2026-02-08T13:04:00Z",
- "validation": {
- "tests": { "status": "passed", "passed": 24, "total": 24 },
- "lint": { "status": "passed", "warnings": 0 },
- "type_check": { "status": "passed", "errors": 0 },
- "duration_s": 12.4
- },
- "sandbox_cleanup": {
- "worktree": "removed",
- "branch": "merged to main",
- "checkpoint": "archived"
- },
- "lifecycle": {
- "phase": "apply",
- "state": "applied",
- "total_duration": "00:06:14",
- "total_cost": "$0.0847",
- "decisions_made": 8,
- "child_plans": 2
- }
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 1250 },
- "messages": ["Changes applied"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan apply
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- artifacts: 6
- changes:
- insertions: 42
- deletions: 9
- project: "local/api-service"
- applied_at: "2026-02-08T13:04:00Z"
- validation:
- tests:
- status: passed
- passed: 24
- total: 24
- lint:
- status: passed
- warnings: 0
- type_check:
- status: passed
- errors: 0
- duration_s: 12.4
- sandbox_cleanup:
- worktree: removed
- branch: merged to main
- checkpoint: archived
- lifecycle:
- phase: apply
- state: applied
- total_duration: "00:06:14"
- total_cost: "$0.0847"
- decisions_made: 8
- child_plans: 2
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 1250
- messages:
- - "Changes applied"
- ```
-
-When Execute-phase validations failed and were not resolved (e.g., the execution actor exhausted its retry limit or failed outright), the plan cannot be applied. Apply checks the validation record and refuses to proceed:
-
-=== "Rich"
-
-
- $ agents plan apply --yes 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Apply Summary ─────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Artifacts: 6 files updated │
- │ Changes: 42 insertions, 9 deletions │
- │ Project: local/api-service │
- ╰─────────────────────────────────────╯
-
- ╭─ Validation ───────────────────────────────────────────────╮
- │ ✗ Tests: FAILED (22/24 passed, 2 failed) │
- │ FAIL test_auth.py::test_session_refresh — AssertionError │
- │ FAIL test_auth.py::test_token_expiry — TimeoutError │
- │ ✓ Lint: passed (0 warnings) │
- │ ✓ Type Check: passed (0 errors) │
- │ Duration: 14.8s │
- ╰────────────────────────────────────────────────────────────╯
-
- ╭─ Sandbox Status ─────────────────────────────────────────────╮
- │ Worktree: preserved (changes NOT committed) │
- │ Checkpoint: cp_01HXM8C2 (pre-apply state available) │
- │ The sandbox is preserved for correction or manual review. │
- ╰──────────────────────────────────────────────────────────────╯
-
- ╭─ Recovery Options ──────────────────────────────────────────────────╮
- │ - agents plan prompt — provide guidance to fix test failures │
- │ - agents plan correct — revert and re-execute with guidance │
- │ - agents plan rollback — restore to a previous checkpoint │
- │ - agents plan cancel — abort the plan entirely │
- ╰─────────────────────────────────────────────────────────────────────╯
-
- ✗ ERROR Apply refused — 2 required Execute-phase validations did not pass
-
-
-=== "Plain"
-
- ```
- $ agents plan apply --yes 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Apply Summary
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Artifacts: 6 files updated
- Changes: 42 insertions, 9 deletions
- Project: local/api-service
-
- Validation
- x Tests: FAILED (22/24 passed, 2 failed)
- FAIL test_auth.py::test_session_refresh -- AssertionError
- FAIL test_auth.py::test_token_expiry -- TimeoutError
- v Lint: passed (0 warnings)
- v Type Check: passed (0 errors)
- Duration: 14.8s
-
- Sandbox Status
- Worktree: preserved (changes NOT committed)
- Checkpoint: cp_01HXM8C2 (pre-apply state available)
- The sandbox is preserved for correction or manual review.
-
- Recovery Options
- - agents plan prompt -- provide guidance to fix test failures
- - agents plan correct -- revert and re-execute with guidance
- - agents plan rollback -- restore to a previous checkpoint
- - agents plan cancel -- abort the plan entirely
-
- [ERROR] Apply refused -- 2 required Execute-phase validations did not pass
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan apply",
- "status": "error",
- "exit_code": 1,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "artifacts": 6,
- "changes": {
- "insertions": 42,
- "deletions": 9
- },
- "project": "local/api-service",
- "validation": {
- "tests": {
- "status": "failed",
- "passed": 22,
- "total": 24,
- "failures": [
- "test_auth.py::test_session_refresh -- AssertionError",
- "test_auth.py::test_token_expiry -- TimeoutError"
- ]
- },
- "lint": { "status": "passed", "warnings": 0 },
- "type_check": { "status": "passed", "errors": 0 },
- "duration_s": 14.8
- },
- "sandbox": {
- "worktree": "preserved",
- "checkpoint": "cp_01HXM8C2"
- },
- "recovery_options": [
- "agents plan prompt",
- "agents plan correct",
- "agents plan rollback",
- "agents plan cancel"
- ]
- },
- "timing": { "started": "2026-02-09T14:30:00Z", "duration_ms": 320 },
- "messages": ["Apply refused -- 2 required Execute-phase validations did not pass"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan apply
- status: error
- exit_code: 1
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- artifacts: 6
- changes:
- insertions: 42
- deletions: 9
- project: "local/api-service"
- validation:
- tests:
- status: failed
- passed: 22
- total: 24
- failures:
- - "test_auth.py::test_session_refresh -- AssertionError"
- - "test_auth.py::test_token_expiry -- TimeoutError"
- lint:
- status: passed
- warnings: 0
- type_check:
- status: passed
- errors: 0
- duration_s: 14.8
- sandbox:
- worktree: preserved
- checkpoint: "cp_01HXM8C2"
- recovery_options:
- - "agents plan prompt"
- - "agents plan correct"
- - "agents plan rollback"
- - "agents plan cancel"
- timing:
- started: "2026-02-09T14:30:00Z"
- duration_ms: 320
- messages:
- - "Apply refused -- 2 required Execute-phase validations did not pass"
- ```
-
-##### agents plan status
-
-agents plan status <PLAN_ID>
-
-**Purpose**
-Show detailed status for a plan.
-
-**Arguments**
-
-- ``: Plan ID (required).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Plan Status ────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: execute │
- │ State: processing │
- │ Action: local/code-coverage │
- │ Project: local/api-service │
- │ Automation: review │
- │ Attempt: 1 │
- ╰──────────────────────────────────╯
-
- ╭─ Progress ───────╮
- │ ✓ Strategize │
- │ ⏳ Execute │
- │ • Apply (queued) │
- ╰──────────────────╯
-
- ╭─ Timing ──────────╮
- │ Started: 12:57:01 │
- │ Elapsed: 00:01:12 │
- │ ETA: 00:03:45 │
- ╰───────────────────╯
-
- ╭─ Execution Detail ──────────╮
- │ Sandbox: git_worktree │
- │ Tool Calls: 8 │
- │ Files Modified: 3 │
- │ Child Plans: 1/2 complete │
- │ Checkpoints: 2 created │
- ╰─────────────────────────────╯
-
- ╭─ Cost ───────────────╮
- │ Tokens Used: 12,420 │
- │ Cost So Far: $0.041 │
- │ Estimated: $0.085 │
- ╰──────────────────────╯
-
- ✓ OK Status refreshed
-
-
-=== "Plain"
-
- ```
- $ agents plan status 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Plan Status
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Phase: execute
- State: processing
- Action: local/code-coverage
- Project: local/api-service
- Automation: review
- Attempt: 1
-
- Progress
- [OK] Strategize
- ... Execute
- . Apply (queued)
-
- Timing
- Started: 12:57:01
- Elapsed: 00:01:12
- ETA: 00:03:45
-
- Execution Detail
- Sandbox: git_worktree
- Tool Calls: 8
- Files Modified: 3
- Child Plans: 1/2 complete
- Checkpoints: 2 created
-
- Cost
- Tokens Used: 12,420
- Cost So Far: $0.041
- Estimated: $0.085
-
- [OK] Status refreshed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan status",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "state": "processing",
- "action": "local/code-coverage",
- "project": "local/api-service",
- "automation": "review",
- "attempt": 1,
- "progress": [
- { "step": "Strategize", "status": "done" },
- { "step": "Execute", "status": "running" },
- { "step": "Apply", "status": "queued" }
- ],
- "timing": {
- "started": "12:57:01",
- "elapsed": "00:01:12",
- "eta": "00:03:45"
- },
- "execution": {
- "sandbox": "git_worktree",
- "tool_calls": 8,
- "files_modified": 3,
- "child_plans": "1/2 complete",
- "checkpoints": 2
- },
- "cost": {
- "tokens_used": 12420,
- "cost_so_far": 0.041,
- "estimated": 0.085
- }
- },
- "timing": {
- "started": "2026-02-08T12:57:01Z",
- "duration_ms": 120
- },
- "messages": ["Status refreshed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan status
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- phase: execute
- state: processing
- action: local/code-coverage
- project: local/api-service
- automation: review
- attempt: 1
- progress:
- - step: Strategize
- status: done
- - step: Execute
- status: running
- - step: Apply
- status: queued
- timing:
- started: "12:57:01"
- elapsed: "00:01:12"
- eta: "00:03:45"
- execution:
- sandbox: git_worktree
- tool_calls: 8
- files_modified: 3
- child_plans: "1/2 complete"
- checkpoints: 2
- cost:
- tokens_used: 12420
- cost_so_far: 0.041
- estimated: 0.085
- timing:
- started: "2026-02-08T12:57:01Z"
- duration_ms: 120
- messages:
- - "Status refreshed"
- ```
-
-Status of a plan that has completed successfully:
-
-=== "Rich"
-
-
- $ agents plan status 01HXM6R3ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Plan Status ─────────────────────╮
- │ Plan: 01HXM6R3ZK4Q7C2B3F2R4VYV6J │
- │ Phase: apply │
- │ State: applied │
- │ Action: local/add-auth │
- │ Project: local/api-service │
- │ Automation: trusted │
- │ Attempt: 1 │
- ╰───────────────────────────────────╯
-
- ╭─ Progress ───────────╮
- │ ✓ Strategize │
- │ ✓ Execute │
- │ ✓ Apply (committed) │
- ╰──────────────────────╯
-
- ╭─ Timing ─────────────────────────╮
- │ Started: 2026-02-08 12:57:01 │
- │ Finished: 2026-02-08 13:04:15 │
- │ Total Duration: 00:07:14 │
- ╰──────────────────────────────────╯
-
- ╭─ Result ────────────────────────────╮
- │ Decisions Made: 8 │
- │ Child Plans: 2/2 complete │
- │ Artifacts: 6 files updated │
- │ Validations: 3/3 passed │
- │ Total Cost: $0.085 │
- ╰─────────────────────────────────────╯
-
- ✓ OK Plan completed successfully
-
-
-=== "Plain"
-
- ```
- $ agents plan status 01HXM6R3ZK4Q7C2B3F2R4VYV6J
-
- Plan Status
- Plan: 01HXM6R3ZK4Q7C2B3F2R4VYV6J
- Phase: apply
- State: applied
- Action: local/add-auth
- Project: local/api-service
- Automation: trusted
- Attempt: 1
-
- Progress
- [OK] Strategize
- [OK] Execute
- [OK] Apply (committed)
-
- Timing
- Started: 2026-02-08 12:57:01
- Finished: 2026-02-08 13:04:15
- Total Duration: 00:07:14
-
- Result
- Decisions Made: 8
- Child Plans: 2/2 complete
- Artifacts: 6 files updated
- Validations: 3/3 passed
- Total Cost: $0.085
-
- [OK] Plan completed successfully
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan status",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM6R3ZK4Q7C2B3F2R4VYV6J",
- "phase": "apply",
- "state": "applied",
- "action": "local/add-auth",
- "project": "local/api-service",
- "automation": "trusted",
- "attempt": 1,
- "progress": [
- { "step": "Strategize", "status": "done" },
- { "step": "Execute", "status": "done" },
- { "step": "Apply", "status": "committed" }
- ],
- "timing": {
- "started": "2026-02-08T12:57:01Z",
- "finished": "2026-02-08T13:04:15Z",
- "total_duration": "00:07:14"
- },
- "result": {
- "decisions_made": 8,
- "child_plans": "2/2 complete",
- "artifacts": "6 files updated",
- "validations": "3/3 passed",
- "total_cost": 0.085
- }
- },
- "timing": {
- "started": "2026-02-08T12:57:01Z",
- "duration_ms": 434000
- },
- "messages": ["Plan completed successfully"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan status
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM6R3ZK4Q7C2B3F2R4VYV6J"
- phase: apply
- state: applied
- action: local/add-auth
- project: local/api-service
- automation: trusted
- attempt: 1
- progress:
- - step: Strategize
- status: done
- - step: Execute
- status: done
- - step: Apply
- status: committed
- timing:
- started: "2026-02-08T12:57:01Z"
- finished: "2026-02-08T13:04:15Z"
- total_duration: "00:07:14"
- result:
- decisions_made: 8
- child_plans: "2/2 complete"
- artifacts: "6 files updated"
- validations: "3/3 passed"
- total_cost: 0.085
- timing:
- started: "2026-02-08T12:57:01Z"
- duration_ms: 434000
- messages:
- - "Plan completed successfully"
- ```
-
-Status of a plan in the strategize phase:
-
-=== "Rich"
-
-
- $ agents plan status 01HXM9F2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Plan Status ────────────────────╮
- │ Plan: 01HXM9F2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: strategize │
- │ State: processing │
- │ Action: local/refactor-auth │
- │ Project: local/api-service │
- │ Automation: supervised │
- ╰──────────────────────────────────╯
-
- ╭─ Progress ───────────────╮
- │ ⏳ Strategize (running) │
- │ ○ Execute (waiting) │
- │ ○ Apply (waiting) │
- ╰──────────────────────────╯
-
- ╭─ Strategy Progress ────────╮
- │ Decisions Made: 4 │
- │ Invariants Enforced: 2 │
- │ Child Plans Planned: 3 │
- │ Elapsed: 00:00:28 │
- ╰────────────────────────────╯
-
- ✓ OK Strategize in progress
-
-
-=== "Plain"
-
- ```
- $ agents plan status 01HXM9F2ZK4Q7C2B3F2R4VYV6J
-
- Plan Status
- Plan: 01HXM9F2ZK4Q7C2B3F2R4VYV6J
- Phase: strategize
- State: processing
- Action: local/refactor-auth
- Project: local/api-service
- Automation: supervised
-
- Progress
- ... Strategize (running)
- o Execute (waiting)
- o Apply (waiting)
-
- Strategy Progress
- Decisions Made: 4
- Invariants Enforced: 2
- Child Plans Planned: 3
- Elapsed: 00:00:28
-
- [OK] Strategize in progress
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan status",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM9F2ZK4Q7C2B3F2R4VYV6J",
- "phase": "strategize",
- "state": "processing",
- "action": "local/refactor-auth",
- "project": "local/api-service",
- "automation": "supervised",
- "progress": [
- { "step": "Strategize", "status": "running" },
- { "step": "Execute", "status": "waiting" },
- { "step": "Apply", "status": "waiting" }
- ],
- "strategy_progress": {
- "decisions_made": 4,
- "invariants_enforced": 2,
- "child_plans_planned": 3,
- "elapsed": "00:00:28"
- }
- },
- "timing": {
- "started": "2026-02-08T12:57:01Z",
- "duration_ms": 28000
- },
- "messages": ["Strategize in progress"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan status
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM9F2ZK4Q7C2B3F2R4VYV6J"
- phase: strategize
- state: processing
- action: local/refactor-auth
- project: local/api-service
- automation: supervised
- progress:
- - step: Strategize
- status: running
- - step: Execute
- status: waiting
- - step: Apply
- status: waiting
- strategy_progress:
- decisions_made: 4
- invariants_enforced: 2
- child_plans_planned: 3
- elapsed: "00:00:28"
- timing:
- started: "2026-02-08T12:57:01Z"
- duration_ms: 28000
- messages:
- - "Strategize in progress"
- ```
-
-Status of a plan that encountered an error:
-
-=== "Rich"
-
-
- $ agents plan status 01HXM7K2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Plan Status ────────────────────╮
- │ Plan: 01HXM7K2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: execute │
- │ State: errored │
- │ Action: local/migrate-db │
- │ Project: local/api-service │
- │ Automation: supervised │
- │ Attempt: 1 │
- ╰──────────────────────────────────╯
-
- ╭─ Progress ───────────╮
- │ ✓ Strategize │
- │ ✗ Execute │
- │ ○ Apply (skipped) │
- ╰──────────────────────╯
-
- ╭─ Error Detail ──────────────────────────────────────────────────╮
- │ Error: Tool invocation failed: connection refused │
- │ Tool: local/db-migrate │
- │ Step: 4 of 6 │
- │ Checkpoint: cp_01HXM8C2 (sandbox state preserved) │
- │ Recoverable: yes — use "agents plan prompt" to provide guidance │
- ╰─────────────────────────────────────────────────────────────────╯
-
- ╭─ Cost ───────────────╮
- │ Tokens Used: 8,340 │
- │ Cost So Far: $0.028 │
- ╰──────────────────────╯
-
- ✗ ERROR Plan errored — use `agents plan prompt` to resume or `agents plan cancel` to abort
-
-
-=== "Plain"
-
- ```
- $ agents plan status 01HXM7K2ZK4Q7C2B3F2R4VYV6J
-
- Plan Status
- Plan: 01HXM7K2ZK4Q7C2B3F2R4VYV6J
- Phase: execute
- State: errored
- Action: local/migrate-db
- Project: local/api-service
- Automation: supervised
- Attempt: 1
-
- Progress
- [OK] Strategize
- [FAIL] Execute
- o Apply (skipped)
-
- Error Detail
- Error: Tool invocation failed: connection refused
- Tool: local/db-migrate
- Step: 4 of 6
- Checkpoint: cp_01HXM8C2 (sandbox state preserved)
- Recoverable: yes -- use "agents plan prompt" to provide guidance
-
- Cost
- Tokens Used: 8,340
- Cost So Far: $0.028
-
- [ERROR] Plan errored -- use `agents plan prompt` to resume or `agents plan cancel` to abort
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan status",
- "status": "error",
- "exit_code": 1,
- "data": {
- "plan_id": "01HXM7K2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "state": "errored",
- "action": "local/migrate-db",
- "project": "local/api-service",
- "automation": "supervised",
- "attempt": 1,
- "progress": [
- { "step": "Strategize", "status": "done" },
- { "step": "Execute", "status": "failed" },
- { "step": "Apply", "status": "skipped" }
- ],
- "error": {
- "message": "Tool invocation failed: connection refused",
- "tool": "local/db-migrate",
- "step": "4 of 6",
- "checkpoint": "cp_01HXM8C2",
- "recoverable": true
- },
- "cost": {
- "tokens_used": 8340,
- "cost_so_far": 0.028
- }
- },
- "timing": {
- "started": "2026-02-08T12:57:01Z",
- "duration_ms": 72000
- },
- "messages": ["Plan errored — use `agents plan prompt` to resume or `agents plan cancel` to abort"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan status
- status: error
- exit_code: 1
- data:
- plan_id: "01HXM7K2ZK4Q7C2B3F2R4VYV6J"
- phase: execute
- state: errored
- action: local/migrate-db
- project: local/api-service
- automation: supervised
- attempt: 1
- progress:
- - step: Strategize
- status: done
- - step: Execute
- status: failed
- - step: Apply
- status: skipped
- error:
- message: "Tool invocation failed: connection refused"
- tool: local/db-migrate
- step: "4 of 6"
- checkpoint: cp_01HXM8C2
- recoverable: true
- cost:
- tokens_used: 8340
- cost_so_far: 0.028
- timing:
- started: "2026-02-08T12:57:01Z"
- duration_ms: 72000
- messages:
- - "Plan errored — use `agents plan prompt` to resume or `agents plan cancel` to abort"
- ```
-
-##### agents plan cancel
-
-agents plan cancel [(--reason|-r) <REASON>] <PLAN_ID>
-
-!!! warning "Irreversible State Transition"
- Cancel a plan that is not in a terminal state. Cancellation transitions the plan to the `cancelled` state, which is ==terminal==. The sandbox and any child plan artifacts are preserved for inspection but cannot be resumed.
-
- !!! tip "Recovery After Cancel"
- A cancelled plan cannot be resumed, but you can re-execute the same action with `agents plan use` to create a new plan instance.
-
-**Arguments**
-
-- ``: Plan ID.
-- `--reason/-r TEXT`: Optional reason.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan cancel 01HXM8C2ZK4Q7C2B3F2R4VYV6J --reason "blocked on credentials"
-
- ╭─ Plan Cancelled ─────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: execute │
- │ Reason: blocked on credentials │
- │ State: cancelled │
- │ Cancelled At: 13:02:15 │
- ╰──────────────────────────────────╯
-
- ╭─ Sandbox ────────────────╮
- │ Status: preserved │
- │ Files Modified: 3 │
- │ Checkpoints: 2 │
- ╰──────────────────────────╯
-
- ╭─ Child Plans ─────────────╮
- │ Completed: 1 │
- │ Cancelled: 1 │
- │ Artifacts Preserved: yes │
- ╰───────────────────────────╯
-
- ╭─ Recovery ───────────────────────────────────────────╮
- │ - Resolve credentials │
- │ - Run agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- ╰──────────────────────────────────────────────────────╯
-
- ✓ OK Plan cancelled
-
-
-=== "Plain"
-
- ```
- $ agents plan cancel 01HXM8C2ZK4Q7C2B3F2R4VYV6J --reason "blocked on credentials"
-
- Plan Cancelled
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Phase: execute
- Reason: blocked on credentials
- State: cancelled
- Cancelled At: 13:02:15
-
- Sandbox
- Status: preserved
- Files Modified: 3
- Checkpoints: 2
-
- Child Plans
- Completed: 1
- Cancelled: 1
- Artifacts Preserved: yes
-
- Recovery
- - Resolve credentials
- - Run agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- [OK] Plan cancelled
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan cancel",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "reason": "blocked on credentials",
- "state": "cancelled",
- "cancelled_at": "13:02:15",
- "sandbox": {
- "status": "preserved",
- "files_modified": 3,
- "checkpoints": 2
- },
- "child_plans": {
- "completed": 1,
- "cancelled": 1,
- "artifacts_preserved": true
- },
- "recovery": [
- "Resolve credentials",
- "Run agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- ]
- },
- "timing": {
- "started": "2026-02-08T13:02:15Z",
- "duration_ms": 340
- },
- "messages": ["Plan cancelled"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan cancel
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- phase: execute
- reason: "blocked on credentials"
- state: cancelled
- cancelled_at: "13:02:15"
- sandbox:
- status: preserved
- files_modified: 3
- checkpoints: 2
- child_plans:
- completed: 1
- cancelled: 1
- artifacts_preserved: true
- recovery:
- - "Resolve credentials"
- - "Run agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- timing:
- started: "2026-02-08T13:02:15Z"
- duration_ms: 340
- messages:
- - "Plan cancelled"
- ```
-
-##### agents plan tree
-
-agents plan tree [--show-superseded] <PLAN_ID>
-
-**Purpose**
-Render the decision tree for a plan.
-
-**Arguments**
-
-- ``: Plan ID (required).
-- `--show-superseded`: Include superseded decisions.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan tree 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Decision Tree ──────────────────────────────────────────────────────────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ ├─ [prompt_definition] "Increase test coverage to 85%" │
- │ ├─ [invariant_enforced] "Prioritize financial transaction and user mgmt code" │
- │ ├─ [invariant_enforced] "All API calls over TCP must be mocked" │
- │ ├─ [strategy_choice] "Prioritize auth and payments" (confidence: 0.82) │
- │ ├─ [subplan_parallel_spawn] "Implement auth and payment modules, in parallel" │
- │ │ ├─ [subplan_spawn] "Write auth tests" → Plan: 01HXM9F1A │
- │ │ └─ [subplan_spawn] "Write payment tests" → Plan: 01HXM9F2B │
- │ └─ [subplan_parallel_spawn] "Write tests for remaining modules" │
- │ └─ ... │
- ╰──────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Tree Summary ─────────────╮
- │ Nodes: 9 │
- │ Depth: 3 │
- │ Child Plans: 2+ │
- │ Invariants: 2 │
- │ Superseded: 0 (hidden) │
- ╰────────────────────────────╯
-
- ╭─ Child Plans ──────────────────────────────────────╮
- │ ID Phase State │
- │ ────────── ─────── ───────── │
- │ 01HXM9F1A execute processing │
- │ 01HXM9F2B execute queued │
- ╰────────────────────────────────────────────────────╯
-
- ╭─ Decision IDs (for correction) ──────────────────╮
- │ Root: 01HXM9A0B1Q2W3R5G8Z0P4Q1X8 │
- │ Invariant 1: 01HXM9A0C1R3X4S6G9Z1P5Q2Y9 │
- │ Invariant 2: 01HXM9A0D2S4Y5T7H0Z2P6Q3Z0 │
- │ Strategy: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- │ Parallel 1: 01HXM9A1D3R8X5S7H1Z2P5Q2Y0 │
- │ Spawn Auth: 01HXM9A2D3Q8W4R6H9Z1P5Q2X0 │
- │ Spawn Payment: 01HXM9A3E4Q9W5R7I0Z2P6Q3X1 │
- │ Parallel 2: 01HXM9A4F5Q0W6R8J1Z3P7Q4X2 │
- ╰──────────────────────────────────────────────────╯
-
- ✓ OK Decision tree rendered
-
-
-=== "Plain"
-
- ```
- $ agents plan tree 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Decision Tree
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- +-- [prompt_definition] "Increase test coverage to 85%"
- +-- [invariant_enforced] "Prioritize financial transaction and user mgmt code"
- +-- [invariant_enforced] "All API calls over TCP must be mocked"
- +-- [strategy_choice] "Prioritize auth and payments" (confidence: 0.82)
- +-- [subplan_parallel_spawn] "Implement auth and payment modules, in parallel"
- | +-- [subplan_spawn] "Write auth tests" -> Plan: 01HXM9F1A
- | +-- [subplan_spawn] "Write payment tests" -> Plan: 01HXM9F2B
- +-- [subplan_parallel_spawn] "Write tests for remaining modules"
- +-- ...
-
- Tree Summary
- Nodes: 9
- Depth: 3
- Child Plans: 2+
- Invariants: 2
- Superseded: 0 (hidden)
-
- Child Plans
- ID Phase State
- ---------- ------- ---------
- 01HXM9F1A execute processing
- 01HXM9F2B execute queued
-
- Decision IDs (for correction)
- Root: 01HXM9A0B1Q2W3R5G8Z0P4Q1X8
- Invariant 1: 01HXM9A0C1R3X4S6G9Z1P5Q2Y9
- Invariant 2: 01HXM9A0D2S4Y5T7H0Z2P6Q3Z0
- Strategy: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- Parallel 1: 01HXM9A1D3R8X5S7H1Z2P5Q2Y0
- Spawn Auth: 01HXM9A2D3Q8W4R6H9Z1P5Q2X0
- Spawn Payment: 01HXM9A3E4Q9W5R7I0Z2P6Q3X1
- Parallel 2: 01HXM9A4F5Q0W6R8J1Z3P7Q4X2
-
- [OK] Decision tree rendered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan tree",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "tree": {
- "type": "prompt_definition",
- "description": "Increase test coverage to 85%",
- "children": [
- { "type": "invariant_enforced", "description": "Prioritize financial transaction and user mgmt code" },
- { "type": "invariant_enforced", "description": "All API calls over TCP must be mocked" },
- { "type": "strategy_choice", "description": "Prioritize auth and payments", "confidence": 0.82 },
- {
- "type": "subplan_parallel_spawn",
- "description": "Implement auth and payment modules, in parallel",
- "children": [
- { "type": "subplan_spawn", "description": "Write auth tests", "plan_id": "01HXM9F1A" },
- { "type": "subplan_spawn", "description": "Write payment tests", "plan_id": "01HXM9F2B" }
- ]
- },
- {
- "type": "subplan_parallel_spawn",
- "description": "Write tests for remaining modules",
- "children": ["..."]
- }
- ]
- },
- "summary": {
- "nodes": 9,
- "depth": 3,
- "child_plans": "2+",
- "invariants": 2,
- "superseded": 0
- },
- "child_plans": [
- { "id": "01HXM9F1A", "phase": "execute", "state": "processing" },
- { "id": "01HXM9F2B", "phase": "execute", "state": "queued" }
- ],
- "decision_ids": {
- "root": "01HXM9A0B1Q2W3R5G8Z0P4Q1X8",
- "invariant_1": "01HXM9A0C1R3X4S6G9Z1P5Q2Y9",
- "invariant_2": "01HXM9A0D2S4Y5T7H0Z2P6Q3Z0",
- "strategy": "01HXM9A1C2Q7W3R5G8Z0P4Q1X9",
- "parallel_1": "01HXM9A1D3R8X5S7H1Z2P5Q2Y0",
- "spawn_auth": "01HXM9A2D3Q8W4R6H9Z1P5Q2X0",
- "spawn_payment": "01HXM9A3E4Q9W5R7I0Z2P6Q3X1",
- "parallel_2": "01HXM9A4F5Q0W6R8J1Z3P7Q4X2"
- }
- },
- "timing": {
- "started": "2026-02-08T12:58:00Z",
- "duration_ms": 85
- },
- "messages": ["Decision tree rendered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan tree
- status: ok
- exit_code: 0
- data:
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- tree:
- type: prompt_definition
- description: "Increase test coverage to 85%"
- children:
- - type: invariant_enforced
- description: "Prioritize financial transaction and user mgmt code"
- - type: invariant_enforced
- description: "All API calls over TCP must be mocked"
- - type: strategy_choice
- description: "Prioritize auth and payments"
- confidence: 0.82
- - type: subplan_parallel_spawn
- description: "Implement auth and payment modules, in parallel"
- children:
- - type: subplan_spawn
- description: "Write auth tests"
- plan_id: "01HXM9F1A"
- - type: subplan_spawn
- description: "Write payment tests"
- plan_id: "01HXM9F2B"
- - type: subplan_parallel_spawn
- description: "Write tests for remaining modules"
- children:
- - "..."
- summary:
- nodes: 9
- depth: 3
- child_plans: "2+"
- invariants: 2
- superseded: 0
- child_plans:
- - id: "01HXM9F1A"
- phase: execute
- state: processing
- - id: "01HXM9F2B"
- phase: execute
- state: queued
- decision_ids:
- root: "01HXM9A0B1Q2W3R5G8Z0P4Q1X8"
- invariant_1: "01HXM9A0C1R3X4S6G9Z1P5Q2Y9"
- invariant_2: "01HXM9A0D2S4Y5T7H0Z2P6Q3Z0"
- strategy: "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- parallel_1: "01HXM9A1D3R8X5S7H1Z2P5Q2Y0"
- spawn_auth: "01HXM9A2D3Q8W4R6H9Z1P5Q2X0"
- spawn_payment: "01HXM9A3E4Q9W5R7I0Z2P6Q3X1"
- parallel_2: "01HXM9A4F5Q0W6R8J1Z3P7Q4X2"
- timing:
- started: "2026-02-08T12:58:00Z"
- duration_ms: 85
- messages:
- - "Decision tree rendered"
- ```
-
-##### agents plan explain
-
-agents plan explain [--show-context] [--show-reasoning] <DECISION_ID>
-
-**Purpose**
-Show a detailed explanation for a decision.
-
-**Arguments**
-
-- ``: Decision ID.
-- `--show-context`: Include the context snapshot.
-- `--show-reasoning`: Include raw model reasoning if available.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan explain 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --show-context
-
- ╭─ Decision ─────────────────────────────────────╮
- │ ID: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- │ Type: strategy_choice │
- │ Question: Which modules should be prioritized? │
- │ Chosen: Auth and payments │
- │ Confidence: 0.82 │
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Sequence: 2 of 5 │
- │ Created: 2026-02-08 12:58 │
- ╰────────────────────────────────────────────────╯
-
- ╭─ Alternatives Considered ──────────────────────╮
- │ 1. Auth and payments (chosen) │
- │ 2. User module first (coverage 71%, med risk) │
- │ 3. All modules equally (spread thin) │
- ╰────────────────────────────────────────────────╯
-
- ╭─ Impact ──────────────────────╮
- │ Downstream Decisions: 3 │
- │ Downstream Child Plans: 2 │
- │ Artifacts Produced: 5 │
- │ Correction Impact: medium │
- ╰───────────────────────────────╯
-
- ╭─ Context Snapshot ───────────────╮
- │ - Coverage < 70% in auth │
- │ - Payments failures last release │
- │ - Auth: 12 files, 45% coverage │
- │ - Payments: 8 files, 52% cover. │
- │ Hot Context Hash: sha256:4b2e... │
- ╰──────────────────────────────────╯
-
- ╭─ Rationale ───────────────────────────────────────╮
- │ Auth and payment modules have the lowest coverage │
- │ and highest business risk. Auth handles security │
- │ tokens, payments handles money. Both had bugs in │
- │ the last release traceable to missing tests. │
- ╰───────────────────────────────────────────────────╯
-
- ╭─ Correction ──────────────────────────────────────────────╮
- │ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- │ --mode revert --guidance "Prioritize payments first..." │
- ╰───────────────────────────────────────────────────────────╯
-
- ✓ OK Decision explained
-
-
-=== "Plain"
-
- ```
- $ agents plan explain 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --show-context
-
- Decision
- ID: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- Type: strategy_choice
- Question: Which modules should be prioritized?
- Chosen: Auth and payments
- Confidence: 0.82
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Sequence: 2 of 5
- Created: 2026-02-08 12:58
-
- Alternatives Considered
- 1. Auth and payments (chosen)
- 2. User module first (coverage 71%, med risk)
- 3. All modules equally (spread thin)
-
- Impact
- Downstream Decisions: 3
- Downstream Child Plans: 2
- Artifacts Produced: 5
- Correction Impact: medium
-
- Context Snapshot
- - Coverage < 70% in auth
- - Payments failures last release
- - Auth: 12 files, 45% coverage
- - Payments: 8 files, 52% cover.
- Hot Context Hash: sha256:4b2e...
-
- Rationale
- Auth and payment modules have the lowest coverage
- and highest business risk. Auth handles security
- tokens, payments handles money. Both had bugs in
- the last release traceable to missing tests.
-
- Correction
- agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- --mode revert --guidance "Prioritize payments first..."
-
- [OK] Decision explained
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan explain",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "decision_id": "01HXM9A1C2Q7W3R5G8Z0P4Q1X9",
- "type": "strategy_choice",
- "question": "Which modules should be prioritized?",
- "chosen": "Auth and payments",
- "confidence": 0.82,
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "sequence": "2 of 5",
- "created": "2026-02-08T12:58:00Z",
- "alternatives": [
- { "index": 1, "description": "Auth and payments", "chosen": true },
- { "index": 2, "description": "User module first (coverage 71%, med risk)", "chosen": false },
- { "index": 3, "description": "All modules equally (spread thin)", "chosen": false }
- ],
- "impact": {
- "downstream_decisions": 3,
- "downstream_child_plans": 2,
- "artifacts_produced": 5,
- "correction_impact": "medium"
- },
- "context_snapshot": {
- "items": [
- "Coverage < 70% in auth",
- "Payments failures last release",
- "Auth: 12 files, 45% coverage",
- "Payments: 8 files, 52% cover."
- ],
- "hot_context_hash": "sha256:4b2e..."
- },
- "rationale": "Auth and payment modules have the lowest coverage and highest business risk. Auth handles security tokens, payments handles money. Both had bugs in the last release traceable to missing tests.",
- "correction_hint": "agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode revert --guidance "Prioritize payments first...""
- },
- "timing": {
- "started": "2026-02-08T12:58:00Z",
- "duration_ms": 110
- },
- "messages": ["Decision explained"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan explain
- status: ok
- exit_code: 0
- data:
- decision_id: "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- type: strategy_choice
- question: "Which modules should be prioritized?"
- chosen: "Auth and payments"
- confidence: 0.82
- plan_id: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- sequence: "2 of 5"
- created: "2026-02-08T12:58:00Z"
- alternatives:
- - index: 1
- description: "Auth and payments"
- chosen: true
- - index: 2
- description: "User module first (coverage 71%, med risk)"
- chosen: false
- - index: 3
- description: "All modules equally (spread thin)"
- chosen: false
- impact:
- downstream_decisions: 3
- downstream_child_plans: 2
- artifacts_produced: 5
- correction_impact: medium
- context_snapshot:
- items:
- - "Coverage < 70% in auth"
- - "Payments failures last release"
- - "Auth: 12 files, 45% coverage"
- - "Payments: 8 files, 52% cover."
- hot_context_hash: "sha256:4b2e..."
- rationale: >-
- Auth and payment modules have the lowest coverage
- and highest business risk. Auth handles security
- tokens, payments handles money. Both had bugs in
- the last release traceable to missing tests.
- correction_hint: >-
- agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- --mode revert --guidance "Prioritize payments first..."
- timing:
- started: "2026-02-08T12:58:00Z"
- duration_ms: 110
- messages:
- - "Decision explained"
- ```
-
-Including the raw model reasoning with `--show-reasoning`:
-
-=== "Rich"
-
-
- $ agents plan explain --show-reasoning 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
-
- ╭─ Decision ──────────────────────────────╮
- │ ID: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- │ Type: strategy_choice │
- │ Choice: Convert to async/await │
- │ Alternatives: 3 │
- ╰─────────────────────────────────────────╯
-
- ╭─ Alternatives Considered ────────────────────────────────────╮
- │ 1. Convert to async/await patterns (chosen) │
- │ 2. Keep synchronous with thread pool │
- │ 3. Use callback-based approach │
- ╰──────────────────────────────────────────────────────────────╯
-
- ╭─ Rationale ──────────────────────────────────────────────────╮
- │ Async/await is the modern Python standard for I/O-bound │
- │ operations. The project already uses asyncio in 3 modules. │
- │ Thread pools would add complexity without native support. │
- ╰──────────────────────────────────────────────────────────────╯
-
- ╭─ Model Reasoning (raw) ───────────────────────────────────────╮
- │ I need to decide on the concurrency pattern for the payment │
- │ processing module. Let me analyze the current codebase: │
- │ │
- │ 1. src/payments/api.py uses synchronous requests. │
- │ 2. src/core/scheduler.py already uses asyncio. │
- │ 3. The database driver (asyncpg) supports async natively. │
- │ 4. Project invariant says "prefer modern Python patterns". │
- │ │
- │ Given that 3/5 core modules already use asyncio, and the │
- │ database driver supports it, converting to async/await is │
- │ the most consistent choice. Thread pools would work but │
- │ add unnecessary complexity and don't integrate well with │
- │ the existing asyncio event loop in scheduler.py. │
- ╰───────────────────────────────────────────────────────────────╯
-
- ✓ OK Decision explained
-
-
-=== "Plain"
-
- ```
- $ agents plan explain --show-reasoning 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
-
- Decision
- ID: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- Type: strategy_choice
- Choice: Convert to async/await
- Alternatives: 3
-
- Alternatives Considered
- 1. Convert to async/await patterns (chosen)
- 2. Keep synchronous with thread pool
- 3. Use callback-based approach
-
- Rationale
- Async/await is the modern Python standard for I/O-bound
- operations. The project already uses asyncio in 3 modules.
- Thread pools would add complexity without native support.
-
- Model Reasoning (raw)
- I need to decide on the concurrency pattern for the payment
- processing module. Let me analyze the current codebase:
-
- 1. src/payments/api.py uses synchronous requests.
- 2. src/core/scheduler.py already uses asyncio.
- 3. The database driver (asyncpg) supports async natively.
- 4. Project invariant says "prefer modern Python patterns".
-
- Given that 3/5 core modules already use asyncio, and the
- database driver supports it, converting to async/await is
- the most consistent choice. Thread pools would work but
- add unnecessary complexity and don't integrate well with
- the existing asyncio event loop in scheduler.py.
-
- [OK] Decision explained
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan explain",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "decision_id": "01HXM9A1C2Q7W3R5G8Z0P4Q1X9",
- "type": "strategy_choice",
- "choice": "Convert to async/await",
- "alternatives_count": 3,
- "alternatives": [
- { "index": 1, "description": "Convert to async/await patterns", "chosen": true },
- { "index": 2, "description": "Keep synchronous with thread pool", "chosen": false },
- { "index": 3, "description": "Use callback-based approach", "chosen": false }
- ],
- "rationale": "Async/await is the modern Python standard for I/O-bound operations. The project already uses asyncio in 3 modules. Thread pools would add complexity without native support.",
- "model_reasoning": "I need to decide on the concurrency pattern for the payment processing module. Let me analyze the current codebase:\n\n1. src/payments/api.py uses synchronous requests.\n2. src/core/scheduler.py already uses asyncio.\n3. The database driver (asyncpg) supports async natively.\n4. Project invariant says \"prefer modern Python patterns\".\n\nGiven that 3/5 core modules already use asyncio, and the database driver supports it, converting to async/await is the most consistent choice. Thread pools would work but add unnecessary complexity and don't integrate well with the existing asyncio event loop in scheduler.py."
- },
- "timing": {
- "started": "2026-02-08T12:58:00Z",
- "duration_ms": 95
- },
- "messages": ["Decision explained"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan explain
- status: ok
- exit_code: 0
- data:
- decision_id: "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- type: strategy_choice
- choice: "Convert to async/await"
- alternatives_count: 3
- alternatives:
- - index: 1
- description: "Convert to async/await patterns"
- chosen: true
- - index: 2
- description: "Keep synchronous with thread pool"
- chosen: false
- - index: 3
- description: "Use callback-based approach"
- chosen: false
- rationale: >-
- Async/await is the modern Python standard for I/O-bound
- operations. The project already uses asyncio in 3 modules.
- Thread pools would add complexity without native support.
- model_reasoning: >-
- I need to decide on the concurrency pattern for the payment
- processing module. Let me analyze the current codebase:
- 1. src/payments/api.py uses synchronous requests.
- 2. src/core/scheduler.py already uses asyncio.
- 3. The database driver (asyncpg) supports async natively.
- 4. Project invariant says "prefer modern Python patterns".
- Given that 3/5 core modules already use asyncio, and the
- database driver supports it, converting to async/await is
- the most consistent choice.
- timing:
- started: "2026-02-08T12:58:00Z"
- duration_ms: 95
- messages:
- - "Decision explained"
- ```
-
-##### agents plan correct
-
-agents plan correct --mode (revert|append) (--guidance|-g) <GUIDANCE>
- [--dry-run] [--yes|-y] <DECISION_ID>
-
-**Purpose**
-Correct a decision either by reverting and re-executing or by appending a fix.
-
-**Arguments**
-
-- ``: Decision ID.
-- `--mode revert|append`: Correction mode.
-- `--guidance/-g TEXT`: Guidance text.
-- `--dry-run`: Show impact without executing.
-- `--yes`: Skip confirmation for revert mode.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode revert \
- --guidance "Prioritize payments first" --yes
-
- ╭─ Correction ────────────────────────────────────────╮
- │ Mode: revert │
- │ Impact: 3 decisions, 2 child plans, 5 artifacts │
- │ New Decision: 01HXM9B7Z3Q1Q8K2E9H7K3W2M8 │
- │ Corrects: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- │ Attempt: 2 │
- ╰─────────────────────────────────────────────────────╯
-
- ╭─ Affected Subtree ──────────────╮
- │ Decisions Invalidated: 3 │
- │ Child Plans Rolled Back: 2 │
- │ Artifacts Archived: 5 │
- │ Unaffected Decisions: 2 │
- ╰─────────────────────────────────╯
-
- ╭─ Sandbox Rollback ─────────────╮
- │ Checkpoint: cp_01HXM8C2 │
- │ Files Reverted: 5 │
- │ Status: restored │
- ╰────────────────────────────────╯
-
- ╭─ Recompute ──────────────╮
- │ Queued: 2 child plans │
- │ ETA: 4m │
- ╰──────────────────────────╯
-
- ╭─ History ───────────────────────────────────────────╮
- │ - Original decision superseded │
- │ - Prior artifacts archived for comparison │
- │ - agents plan diff --correction 01HXM9B7Z3Q1Q8K2.. │
- ╰─────────────────────────────────────────────────────╯
-
- ✓ OK Correction applied
-
-
-=== "Plain"
-
- ```
- $ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode revert --guidance "Prioritize payments first" --yes
-
- Correction
- Mode: revert
- Impact: 3 decisions, 2 child plans, 5 artifacts
- New Decision: 01HXM9B7Z3Q1Q8K2E9H7K3W2M8
- Corrects: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- Attempt: 2
-
- Affected Subtree
- Decisions Invalidated: 3
- Child Plans Rolled Back: 2
- Artifacts Archived: 5
- Unaffected Decisions: 2
-
- Sandbox Rollback
- Checkpoint: cp_01HXM8C2
- Files Reverted: 5
- Status: restored
-
- Recompute
- Queued: 2 child plans
- ETA: 4m
-
- History
- - Original decision superseded
- - Prior artifacts archived for comparison
- - agents plan diff --correction 01HXM9B7Z3Q1Q8K2..
-
- [OK] Correction applied
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan correct",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "correction": {
- "mode": "revert",
- "impact": "3 decisions, 2 child plans, 5 artifacts",
- "new_decision": "01HXM9B7Z3Q1Q8K2E9H7K3W2M8",
- "corrects": "01HXM9A1C2Q7W3R5G8Z0P4Q1X9",
- "attempt": 2
- },
- "affected_subtree": {
- "decisions_invalidated": 3,
- "child_plans_rolled_back": 2,
- "artifacts_archived": 5,
- "unaffected_decisions": 2
- },
- "sandbox_rollback": {
- "checkpoint": "cp_01HXM8C2",
- "files_reverted": 5,
- "status": "restored"
- },
- "recompute": {
- "queued": "2 child plans",
- "eta": "4m"
- },
- "history": [
- "Original decision superseded",
- "Prior artifacts archived for comparison",
- "agents plan diff --correction 01HXM9B7Z3Q1Q8K2.."
- ]
- },
- "timing": { "started": "2025-06-15T10:24:00Z", "duration_ms": 2350 },
- "messages": ["Correction applied"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan correct
- status: ok
- exit_code: 0
- data:
- correction:
- mode: revert
- impact: "3 decisions, 2 child plans, 5 artifacts"
- new_decision: "01HXM9B7Z3Q1Q8K2E9H7K3W2M8"
- corrects: "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- attempt: 2
- affected_subtree:
- decisions_invalidated: 3
- child_plans_rolled_back: 2
- artifacts_archived: 5
- unaffected_decisions: 2
- sandbox_rollback:
- checkpoint: cp_01HXM8C2
- files_reverted: 5
- status: restored
- recompute:
- queued: "2 child plans"
- eta: "4m"
- history:
- - "Original decision superseded"
- - "Prior artifacts archived for comparison"
- - "agents plan diff --correction 01HXM9B7Z3Q1Q8K2.."
- timing:
- started: "2025-06-15T10:24:00Z"
- duration_ms: 2350
- messages:
- - "Correction applied"
- ```
-
-Using `--mode append` to add a corrective decision without reverting existing work (useful when the original decision was partially correct):
-
-=== "Rich"
-
-
- $ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode append \
- --guidance "Also add rate limiting to the auth endpoints"
-
- ╭─ Correction ─────────────────────────────────────╮
- │ Mode: append │
- │ Impact: adds to existing subtree, no rollback │
- │ New Decision: 01HXM9C3Z5T2Q8K2E9H7K3W2M8 │
- │ Appended After: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- │ Attempt: 2 │
- ╰──────────────────────────────────────────────────╯
-
- ╭─ Append Detail ─────────────────────────────────────────────────╮
- │ Original decision preserved: yes │
- │ Existing artifacts kept: yes │
- │ Additional work: appended as new child plan │
- │ The original 5 artifacts remain; a new child plan will add │
- │ rate-limiting code on top of the existing auth changes. │
- ╰─────────────────────────────────────────────────────────────────╯
-
- ╭─ Queued ──────────╮
- │ New child: 1 │
- │ ETA: 2m │
- ╰───────────────────╯
-
- ✓ OK Append correction queued
-
-
-=== "Plain"
-
- ```
- $ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode append --guidance "Also add rate limiting to the auth endpoints"
-
- Correction
- Mode: append
- Impact: adds to existing subtree, no rollback
- New Decision: 01HXM9C3Z5T2Q8K2E9H7K3W2M8
- Appended After: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
- Attempt: 2
-
- Append Detail
- Original decision preserved: yes
- Existing artifacts kept: yes
- Additional work: appended as new child plan
- The original 5 artifacts remain; a new child plan will add
- rate-limiting code on top of the existing auth changes.
-
- Queued
- New child: 1
- ETA: 2m
-
- [OK] Append correction queued
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan correct",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "correction": {
- "mode": "append",
- "impact": "adds to existing subtree, no rollback",
- "new_decision": "01HXM9C3Z5T2Q8K2E9H7K3W2M8",
- "appended_after": "01HXM9A1C2Q7W3R5G8Z0P4Q1X9",
- "attempt": 2
- },
- "append_detail": {
- "original_decision_preserved": true,
- "existing_artifacts_kept": true,
- "additional_work": "appended as new child plan",
- "note": "The original 5 artifacts remain; a new child plan will add rate-limiting code on top of the existing auth changes."
- },
- "queued": {
- "new_child": 1,
- "eta": "2m"
- }
- },
- "timing": { "started": "2025-06-15T10:26:00Z", "duration_ms": 890 },
- "messages": ["Append correction queued"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan correct
- status: ok
- exit_code: 0
- data:
- correction:
- mode: append
- impact: "adds to existing subtree, no rollback"
- new_decision: "01HXM9C3Z5T2Q8K2E9H7K3W2M8"
- appended_after: "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- attempt: 2
- append_detail:
- original_decision_preserved: true
- existing_artifacts_kept: true
- additional_work: "appended as new child plan"
- note: "The original 5 artifacts remain; a new child plan will add rate-limiting code on top of the existing auth changes."
- queued:
- new_child: 1
- eta: "2m"
- timing:
- started: "2025-06-15T10:26:00Z"
- duration_ms: 890
- messages:
- - "Append correction queued"
- ```
-
-Using `--dry-run` to preview the impact of a correction before committing to it:
-
-=== "Rich"
-
-
- $ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode revert \
- --guidance "Use async/await pattern instead" --dry-run
-
- ╭─ Dry Run — Correction Preview ─────────────────────────────────────╮
- │ ⚠ This is a preview only. No changes will be made. │
- ╰────────────────────────────────────────────────────────────────────╯
-
- ╭─ Would Revert ───────────────────────────────────────╮
- │ Decisions to invalidate: 3 │
- │ 01HXM9A1.. strategy_choice "sync pattern" │
- │ 01HXM9A2.. implementation_choice "requests" │
- │ 01HXM9A3.. tool_invocation write_file ×4 │
- │ Child plans to roll back: 2 │
- │ Artifacts to archive: 5 files │
- │ Unaffected decisions: 2 (will be kept) │
- ╰──────────────────────────────────────────────────────╯
-
- ╭─ Estimated Cost ──────────╮
- │ Re-strategize: ~$0.012 │
- │ Re-execute: ~$0.035 │
- │ Total: ~$0.047 │
- │ ETA: ~4 minutes │
- ╰───────────────────────────╯
-
- To execute this correction, remove --dry-run and add --yes
-
-
-=== "Plain"
-
- ```
- $ agents plan correct 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 --mode revert --guidance "Use async/await pattern instead" --dry-run
-
- Dry Run -- Correction Preview
- WARNING: This is a preview only. No changes will be made.
-
- Would Revert
- Decisions to invalidate: 3
- 01HXM9A1.. strategy_choice "sync pattern"
- 01HXM9A2.. implementation_choice "requests"
- 01HXM9A3.. tool_invocation write_file x4
- Child plans to roll back: 2
- Artifacts to archive: 5 files
- Unaffected decisions: 2 (will be kept)
-
- Estimated Cost
- Re-strategize: ~$0.012
- Re-execute: ~$0.035
- Total: ~$0.047
- ETA: ~4 minutes
-
- To execute this correction, remove --dry-run and add --yes
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan correct",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "dry_run": true,
- "would_revert": {
- "decisions_to_invalidate": [
- { "id": "01HXM9A1..", "type": "strategy_choice", "label": "sync pattern" },
- { "id": "01HXM9A2..", "type": "implementation_choice", "label": "requests" },
- { "id": "01HXM9A3..", "type": "tool_invocation", "label": "write_file x4" }
- ],
- "child_plans_to_roll_back": 2,
- "artifacts_to_archive": 5,
- "unaffected_decisions": 2
- },
- "estimated_cost": {
- "re_strategize": "$0.012",
- "re_execute": "$0.035",
- "total": "$0.047",
- "eta": "~4 minutes"
- }
- },
- "timing": { "started": "2025-06-15T10:28:00Z", "duration_ms": 320 },
- "messages": ["To execute this correction, remove --dry-run and add --yes"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan correct
- status: ok
- exit_code: 0
- data:
- dry_run: true
- would_revert:
- decisions_to_invalidate:
- - id: "01HXM9A1.."
- type: strategy_choice
- label: "sync pattern"
- - id: "01HXM9A2.."
- type: implementation_choice
- label: "requests"
- - id: "01HXM9A3.."
- type: tool_invocation
- label: "write_file x4"
- child_plans_to_roll_back: 2
- artifacts_to_archive: 5
- unaffected_decisions: 2
- estimated_cost:
- re_strategize: "$0.012"
- re_execute: "$0.035"
- total: "$0.047"
- eta: "~4 minutes"
- timing:
- started: "2025-06-15T10:28:00Z"
- duration_ms: 320
- messages:
- - "To execute this correction, remove --dry-run and add --yes"
- ```
-
-##### agents plan diff
-
-agents plan diff (--correction <CORRECTION_ATTEMPT_ID>|<PLAN_ID>)
-
-**Purpose**
-Show diffs for a plan or a correction attempt.
-
-**Arguments**
-
-- ``: Show diff for a plan (positional argument). Mutually exclusive with --correction.
-- `--correction CORRECTION_ATTEMPT_ID`: Show diff for a correction attempt instead.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan diff 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Diff Summary ─────────────────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Project: local/api-service │
- │ Files Changed: 2 │
- │ Insertions: 12 │
- │ Deletions: 4 │
- │ Net Change: +8 lines │
- ╰────────────────────────────────────────────────╯
-
- ╭─ Files ───────────────────────────────╮
- │ Path Change Status │
- │ ─────────────────── ────── ──────── │
- │ src/auth/session.py +8 -2 modified │
- │ src/auth/tokens.py +4 -2 modified │
- ╰───────────────────────────────────────╯
-
- ╭─ Patch Preview ──────────────────────────╮
- │ --- a/src/auth/session.py │
- │ +++ b/src/auth/session.py │
- │ @@ -12,4 +12,10 @@ │
- │ - import jwt │
- │ + import sessionlib │
- │ - def validate_token(...) │
- │ + def validate_session(...) │
- │ --- a/src/auth/tokens.py │
- │ +++ b/src/auth/tokens.py │
- │ @@ -5,3 +5,7 @@ │
- │ - TOKEN_EXPIRY = 3600 │
- │ + TOKEN_EXPIRY = 7200 │
- ╰──────────────────────────────────────────╯
-
- ╭─ Risk Assessment ────────────────╮
- │ API Compatibility: preserved │
- │ Test Coverage: maintained │
- │ Breaking Changes: none detected │
- ╰──────────────────────────────────╯
-
- ✓ OK Diff generated
-
-
-=== "Plain"
-
- ```
- $ agents plan diff 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Diff Summary
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Project: local/api-service
- Files Changed: 2
- Insertions: 12
- Deletions: 4
- Net Change: +8 lines
-
- Files
- Path Change Status
- ------------------- ------ --------
- src/auth/session.py +8 -2 modified
- src/auth/tokens.py +4 -2 modified
-
- Patch Preview
- --- a/src/auth/session.py
- +++ b/src/auth/session.py
- @@ -12,4 +12,10 @@
- - import jwt
- + import sessionlib
- - def validate_token(...)
- + def validate_session(...)
- --- a/src/auth/tokens.py
- +++ b/src/auth/tokens.py
- @@ -5,3 +5,7 @@
- - TOKEN_EXPIRY = 3600
- + TOKEN_EXPIRY = 7200
-
- Risk Assessment
- API Compatibility: preserved
- Test Coverage: maintained
- Breaking Changes: none detected
-
- [OK] Diff generated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan diff",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "diff_summary": {
- "plan": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "project": "local/api-service",
- "files_changed": 2,
- "insertions": 12,
- "deletions": 4,
- "net_change": "+8 lines"
- },
- "files": [
- { "path": "src/auth/session.py", "change": "+8 -2", "status": "modified" },
- { "path": "src/auth/tokens.py", "change": "+4 -2", "status": "modified" }
- ],
- "patch_preview": [
- {
- "file": "src/auth/session.py",
- "hunks": [
- {
- "range": "@@ -12,4 +12,10 @@",
- "deletions": ["import jwt", "def validate_token(...)"],
- "insertions": ["import sessionlib", "def validate_session(...)"]
- }
- ]
- },
- {
- "file": "src/auth/tokens.py",
- "hunks": [
- {
- "range": "@@ -5,3 +5,7 @@",
- "deletions": ["TOKEN_EXPIRY = 3600"],
- "insertions": ["TOKEN_EXPIRY = 7200"]
- }
- ]
- }
- ],
- "risk_assessment": {
- "api_compatibility": "preserved",
- "test_coverage": "maintained",
- "breaking_changes": "none detected"
- }
- },
- "timing": { "started": "2025-06-15T10:30:00Z", "duration_ms": 750 },
- "messages": ["Diff generated"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan diff
- status: ok
- exit_code: 0
- data:
- diff_summary:
- plan: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- project: local/api-service
- files_changed: 2
- insertions: 12
- deletions: 4
- net_change: "+8 lines"
- files:
- - path: src/auth/session.py
- change: "+8 -2"
- status: modified
- - path: src/auth/tokens.py
- change: "+4 -2"
- status: modified
- patch_preview:
- - file: src/auth/session.py
- hunks:
- - range: "@@ -12,4 +12,10 @@"
- deletions:
- - "import jwt"
- - "def validate_token(...)"
- insertions:
- - "import sessionlib"
- - "def validate_session(...)"
- - file: src/auth/tokens.py
- hunks:
- - range: "@@ -5,3 +5,7 @@"
- deletions:
- - "TOKEN_EXPIRY = 3600"
- insertions:
- - "TOKEN_EXPIRY = 7200"
- risk_assessment:
- api_compatibility: preserved
- test_coverage: maintained
- breaking_changes: none detected
- timing:
- started: "2025-06-15T10:30:00Z"
- duration_ms: 750
- messages:
- - "Diff generated"
- ```
-
-Showing the diff for a specific correction attempt, comparing what changed between the original and corrected execution:
-
-=== "Rich"
-
-
- $ agents plan diff --correction 01HXM9B7Z3Q1Q8K2E9H7K3W2M8
-
- ╭─ Correction Diff ───────────────────────────────╮
- │ Correction: 01HXM9B7Z3Q1Q8K2E9H7K3W2M8 │
- │ Original Decision: 01HXM9A1C2Q7W3R5.. │
- │ Mode: revert │
- │ Files Changed: 3 │
- │ New Insertions: 18 │
- │ New Deletions: 6 │
- ╰─────────────────────────────────────────────────╯
-
- ╭─ Comparison ─────────────────────────────────────────────────────╮
- │ File Before (original) After (corrected) │
- │ ──────────────────── ──────────────── ──────────────────── │
- │ src/payments/api.py +12 -4 +18 -6 (expanded) │
- │ src/auth/tokens.py +8 -2 (unchanged) │
- │ tests/test_payments.py (new file) (new file, larger) │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Patch Preview (corrected vs original) ───────────╮
- │ --- a/src/payments/api.py (original) │
- │ +++ b/src/payments/api.py (corrected) │
- │ @@ -1,12 +1,18 @@ │
- │ - # sync payment processing │
- │ + # async payment processing (corrected) │
- │ + import asyncio │
- │ + from aiohttp import ClientSession │
- │ ... │
- ╰───────────────────────────────────────────────────╯
-
- ✓ OK Correction diff generated
-
-
-=== "Plain"
-
- ```
- $ agents plan diff --correction 01HXM9B7Z3Q1Q8K2E9H7K3W2M8
-
- Correction Diff
- Correction: 01HXM9B7Z3Q1Q8K2E9H7K3W2M8
- Original Decision: 01HXM9A1C2Q7W3R5..
- Mode: revert
- Files Changed: 3
- New Insertions: 18
- New Deletions: 6
-
- Comparison
- File Before (original) After (corrected)
- -------------------- ----------------- --------------------
- src/payments/api.py +12 -4 +18 -6 (expanded)
- src/auth/tokens.py +8 -2 (unchanged)
- tests/test_payments.py (new file) (new file, larger)
-
- Patch Preview (corrected vs original)
- --- a/src/payments/api.py (original)
- +++ b/src/payments/api.py (corrected)
- @@ -1,12 +1,18 @@
- - # sync payment processing
- + # async payment processing (corrected)
- + import asyncio
- + from aiohttp import ClientSession
- ...
-
- [OK] Correction diff generated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan diff",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "correction_diff": {
- "correction": "01HXM9B7Z3Q1Q8K2E9H7K3W2M8",
- "original_decision": "01HXM9A1C2Q7W3R5..",
- "mode": "revert",
- "files_changed": 3,
- "new_insertions": 18,
- "new_deletions": 6
- },
- "comparison": [
- { "file": "src/payments/api.py", "before": "+12 -4", "after": "+18 -6 (expanded)" },
- { "file": "src/auth/tokens.py", "before": "+8 -2", "after": "(unchanged)" },
- { "file": "tests/test_payments.py", "before": "(new file)", "after": "(new file, larger)" }
- ],
- "patch_preview": [
- {
- "file": "src/payments/api.py",
- "context": "corrected vs original",
- "hunks": [
- {
- "range": "@@ -1,12 +1,18 @@",
- "deletions": ["# sync payment processing"],
- "insertions": ["# async payment processing (corrected)", "import asyncio", "from aiohttp import ClientSession"]
- }
- ]
- }
- ]
- },
- "timing": { "started": "2025-06-15T10:32:00Z", "duration_ms": 920 },
- "messages": ["Correction diff generated"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan diff
- status: ok
- exit_code: 0
- data:
- correction_diff:
- correction: "01HXM9B7Z3Q1Q8K2E9H7K3W2M8"
- original_decision: "01HXM9A1C2Q7W3R5.."
- mode: revert
- files_changed: 3
- new_insertions: 18
- new_deletions: 6
- comparison:
- - file: src/payments/api.py
- before: "+12 -4"
- after: "+18 -6 (expanded)"
- - file: src/auth/tokens.py
- before: "+8 -2"
- after: "(unchanged)"
- - file: tests/test_payments.py
- before: "(new file)"
- after: "(new file, larger)"
- patch_preview:
- - file: src/payments/api.py
- context: "corrected vs original"
- hunks:
- - range: "@@ -1,12 +1,18 @@"
- deletions:
- - "# sync payment processing"
- insertions:
- - "# async payment processing (corrected)"
- - "import asyncio"
- - "from aiohttp import ClientSession"
- timing:
- started: "2025-06-15T10:32:00Z"
- duration_ms: 920
- messages:
- - "Correction diff generated"
- ```
-
-##### agents plan artifacts
-
-agents plan artifacts <PLAN_ID>
-
-**Purpose**
-List artifacts produced by a plan.
-
-**Arguments**
-
-- ``: Plan ID.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan artifacts 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Artifacts ─────────────────────────────────────────────────╮
- │ Path Type Size Change Child Plan │
- │ ───────────────────── ───── ────── ───────── ─────── │
- │ src/auth/session.py write 2.1 KB +8 -2 root │
- │ tests/test_session.py write 4.7 KB +47 -0 root │
- │ src/auth/tokens.py edit 1.8 KB +4 -2 root │
- │ tests/test_tokens.py write 3.2 KB +32 -0 auth │
- ╰─────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ───────────╮
- │ Total: 4 │
- │ Writes: 2 (new) │
- │ Edits: 2 (modified) │
- │ Deletes: 0 │
- │ Total Size: 11.8 KB │
- ╰─────────────────────╯
-
- ╭─ By Plan ─────────────────╮
- │ Root Plan: 3 artifacts │
- │ auth-tests: 1 artifact │
- │ payment-tests: (pending) │
- ╰───────────────────────────╯
-
- ✓ OK 4 artifacts listed
-
-
-=== "Plain"
-
- ```
- $ agents plan artifacts 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Artifacts
- Path Type Size Change Child Plan
- --------------------- ----- ------ --------- ----------
- src/auth/session.py write 2.1 KB +8 -2 root
- tests/test_session.py write 4.7 KB +47 -0 root
- src/auth/tokens.py edit 1.8 KB +4 -2 root
- tests/test_tokens.py write 3.2 KB +32 -0 auth
-
- Summary
- Total: 4
- Writes: 2 (new)
- Edits: 2 (modified)
- Deletes: 0
- Total Size: 11.8 KB
-
- By Plan
- Root Plan: 3 artifacts
- auth-tests: 1 artifact
- payment-tests: (pending)
-
- [OK] 4 artifacts listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan artifacts",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "artifacts": [
- { "path": "src/auth/session.py", "type": "write", "size": "2.1 KB", "change": "+8 -2", "child_plan": "root" },
- { "path": "tests/test_session.py", "type": "write", "size": "4.7 KB", "change": "+47 -0", "child_plan": "root" },
- { "path": "src/auth/tokens.py", "type": "edit", "size": "1.8 KB", "change": "+4 -2", "child_plan": "root" },
- { "path": "tests/test_tokens.py", "type": "write", "size": "3.2 KB", "change": "+32 -0", "child_plan": "auth" }
- ],
- "summary": {
- "total": 4,
- "writes": 2,
- "edits": 2,
- "deletes": 0,
- "total_size": "11.8 KB"
- },
- "by_plan": {
- "root": 3,
- "auth-tests": 1,
- "payment-tests": "pending"
- }
- },
- "timing": { "started": "2025-06-15T10:33:00Z", "duration_ms": 480 },
- "messages": ["4 artifacts listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan artifacts
- status: ok
- exit_code: 0
- data:
- artifacts:
- - path: src/auth/session.py
- type: write
- size: "2.1 KB"
- change: "+8 -2"
- child_plan: root
- - path: tests/test_session.py
- type: write
- size: "4.7 KB"
- change: "+47 -0"
- child_plan: root
- - path: src/auth/tokens.py
- type: edit
- size: "1.8 KB"
- change: "+4 -2"
- child_plan: root
- - path: tests/test_tokens.py
- type: write
- size: "3.2 KB"
- change: "+32 -0"
- child_plan: auth
- summary:
- total: 4
- writes: 2
- edits: 2
- deletes: 0
- total_size: "11.8 KB"
- by_plan:
- root: 3
- auth-tests: 1
- payment-tests: pending
- timing:
- started: "2025-06-15T10:33:00Z"
- duration_ms: 480
- messages:
- - "4 artifacts listed"
- ```
-
-##### agents plan errors
-
-agents plan errors <PLAN_ID>
-
-**Purpose**
-Show error decisions with recovery hints and retry history for a plan.
-
-**Arguments**
-
-- ``: Plan ID (ULID).
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan errors 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- ╭─ Plan Errors ──────────────────────────────────────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Phase: execute │
- │ State: errored │
- │ Error: Tool execution failed: write_file permission denied │
- │ │
- │ Error Category: tool_execution │
- │ Error Phase: execute │
- │ Retry Count: 2/3 │
- │ Retriable: true │
- │ │
- │ Recovery Suggestions: │
- │ → Check sandbox permissions and retry execution │
- │ $ agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ → Revert to Strategize phase to adjust the plan │
- │ $ agents plan correct --mode revert -g "..." <DECISION_ID> │
- ╰────────────────────────────────────────────────────────────────────╯
-
- ✓ OK
-
-
-=== "Plain"
-
- ```
- $ agents plan errors 01HXM8C2ZK4Q7C2B3F2R4VYV6J
-
- Plan Errors
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Phase: execute
- State: errored
- Error: Tool execution failed: write_file permission denied
- Error Category: tool_execution
- Error Phase: execute
- Retry Count: 2/3
- Retriable: true
-
- Recovery Suggestions
- → Check sandbox permissions and retry execution
- $ agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- → Revert to Strategize phase to adjust the plan
- $ agents plan correct --mode revert -g "..."
-
- [OK]
- ```
-
-=== "JSON"
-
- ```json
- {
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "phase": "execute",
- "state": "errored",
- "error_message": "Tool execution failed: write_file permission denied",
- "error_category": "tool_execution",
- "error_phase": "execute",
- "retry_count": 2,
- "max_retries": 3,
- "is_retriable": true,
- "recovery_hints": [
- {
- "action": "retry",
- "message": "Check sandbox permissions and retry execution",
- "cli_command": "agents plan execute 01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- },
- {
- "action": "revert",
- "message": "Revert to Strategize phase to adjust the plan",
- "cli_command": "agents plan correct --mode revert -g \"...\" "
- }
- ]
- }
- ```
-
-##### agents plan prompt
-
-agents plan prompt <PLAN_ID> <GUIDANCE>
-
-**Purpose**
-Provide additional guidance to a plan, typically when it is errored or awaiting input.
-
-**Arguments**
-
-- ``: Plan ID.
-- `""`: Guidance text.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan prompt 01HXM8C2ZK4Q7C2B3F2R4VYV6J "Use mocks for database tests"
-
- ╭─ Guidance Added ────────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Guidance: Use mocks for database tests │
- │ Scope: next execution step │
- │ Phase: execute │
- │ State: errored → processing │
- ╰─────────────────────────────────────────╯
-
- ╭─ Decision Created ────────────────────────╮
- │ Type: user_intervention │
- │ ID: 01HXM9C5G7R2X8S3K4Z5Q8R6Y3 │
- │ Parent: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9 │
- ╰───────────────────────────────────────────╯
-
- ╭─ Queue ────╮
- │ Pending: 1 │
- │ Applied: 0 │
- ╰────────────╯
-
- ✓ OK Guidance queued
-
-
-=== "Plain"
-
- ```
- $ agents plan prompt 01HXM8C2ZK4Q7C2B3F2R4VYV6J "Use mocks for database tests"
-
- Guidance Added
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Guidance: Use mocks for database tests
- Scope: next execution step
- Phase: execute
- State: errored -> processing
-
- Decision Created
- Type: user_intervention
- ID: 01HXM9C5G7R2X8S3K4Z5Q8R6Y3
- Parent: 01HXM9A1C2Q7W3R5G8Z0P4Q1X9
-
- Queue
- Pending: 1
- Applied: 0
-
- [OK] Guidance queued
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan prompt",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "guidance_added": {
- "plan": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "guidance": "Use mocks for database tests",
- "scope": "next execution step",
- "phase": "execute",
- "state_transition": "errored -> processing"
- },
- "decision_created": {
- "type": "user_intervention",
- "id": "01HXM9C5G7R2X8S3K4Z5Q8R6Y3",
- "parent": "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- },
- "queue": {
- "pending": 1,
- "applied": 0
- }
- },
- "timing": { "started": "2025-06-15T10:35:00Z", "duration_ms": 620 },
- "messages": ["Guidance queued"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan prompt
- status: ok
- exit_code: 0
- data:
- guidance_added:
- plan: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- guidance: "Use mocks for database tests"
- scope: next execution step
- phase: execute
- state_transition: "errored -> processing"
- decision_created:
- type: user_intervention
- id: "01HXM9C5G7R2X8S3K4Z5Q8R6Y3"
- parent: "01HXM9A1C2Q7W3R5G8Z0P4Q1X9"
- queue:
- pending: 1
- applied: 0
- timing:
- started: "2025-06-15T10:35:00Z"
- duration_ms: 620
- messages:
- - "Guidance queued"
- ```
-
-##### agents plan rollback
-
-agents plan rollback [--yes|-y] <PLAN_ID> <CHECKPOINT_ID>
-
-!!! danger "Destructive Operation"
- Rollback a plan sandbox to a previous checkpoint. All changes made ==after== the target checkpoint are **reverted**: files are restored or removed, decisions are discarded, and tool calls are undone. Child plans spawned after the checkpoint are invalidated.
-
-**Arguments**
-
-- ``: Plan ID.
-- ``: Checkpoint ID.
-- `--yes`: Skip confirmation.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents plan rollback 01HXM8C2ZK4Q7C2B3F2R4VYV6J cp_01HXM8C2
-
- Rollback plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J to cp_01HXM8C2? [y/N]: y
-
- ╭─ Rollback Summary ───────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Checkpoint: cp_01HXM8C2 │
- │ Label: before auth refactor │
- │ Files: 6 reverted │
- ╰──────────────────────────────────╯
-
- ╭─ Changes Reverted ──────────────────╮
- │ File Action │
- │ ────────────────────── ────────── │
- │ src/auth/session.py restored │
- │ src/auth/tokens.py restored │
- │ tests/test_session.py removed │
- │ tests/test_tokens.py removed │
- │ src/auth/fixtures.py restored │
- │ src/auth/__init__.py restored │
- ╰─────────────────────────────────────╯
-
- ╭─ Impact ──────────────────────────────╮
- │ Child Plans Invalidated: 2 │
- │ Sandbox: restored to cp_01HXM8C2 │
- │ Decisions After CP: 2 discarded │
- │ Tool Calls After CP: 5 undone │
- ╰───────────────────────────────────────╯
-
- ╭─ Post-Rollback State ──────────╮
- │ Phase: execute │
- │ State: queued (awaiting input) │
- │ Checkpoints Remaining: 2 │
- ╰────────────────────────────────╯
-
- ✓ OK Rollback complete
-
-
-=== "Plain"
-
- ```
- $ agents plan rollback 01HXM8C2ZK4Q7C2B3F2R4VYV6J cp_01HXM8C2
-
- Rollback plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J to cp_01HXM8C2? [y/N]: y
-
- Rollback Summary
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Checkpoint: cp_01HXM8C2
- Label: before auth refactor
- Files: 6 reverted
-
- Changes Reverted
- File Action
- ---------------------- ----------
- src/auth/session.py restored
- src/auth/tokens.py restored
- tests/test_session.py removed
- tests/test_tokens.py removed
- src/auth/fixtures.py restored
- src/auth/__init__.py restored
-
- Impact
- Child Plans Invalidated: 2
- Sandbox: restored to cp_01HXM8C2
- Decisions After CP: 2 discarded
- Tool Calls After CP: 5 undone
-
- Post-Rollback State
- Phase: execute
- State: queued (awaiting input)
- Checkpoints Remaining: 2
-
- [OK] Rollback complete
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "plan rollback",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "rollback_summary": {
- "plan": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "checkpoint": "cp_01HXM8C2",
- "label": "before auth refactor",
- "files_reverted": 6
- },
- "changes_reverted": [
- { "file": "src/auth/session.py", "action": "restored" },
- { "file": "src/auth/tokens.py", "action": "restored" },
- { "file": "tests/test_session.py", "action": "removed" },
- { "file": "tests/test_tokens.py", "action": "removed" },
- { "file": "src/auth/fixtures.py", "action": "restored" },
- { "file": "src/auth/__init__.py", "action": "restored" }
- ],
- "impact": {
- "child_plans_invalidated": 2,
- "sandbox": "restored to cp_01HXM8C2",
- "decisions_after_cp": "2 discarded",
- "tool_calls_after_cp": "5 undone"
- },
- "post_rollback_state": {
- "phase": "execute",
- "state": "queued (awaiting input)",
- "checkpoints_remaining": 2
- }
- },
- "timing": { "started": "2025-06-15T10:37:00Z", "duration_ms": 1850 },
- "messages": ["Rollback complete"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: plan rollback
- status: ok
- exit_code: 0
- data:
- rollback_summary:
- plan: "01HXM8C2ZK4Q7C2B3F2R4VYV6J"
- checkpoint: cp_01HXM8C2
- label: before auth refactor
- files_reverted: 6
- changes_reverted:
- - file: src/auth/session.py
- action: restored
- - file: src/auth/tokens.py
- action: restored
- - file: tests/test_session.py
- action: removed
- - file: tests/test_tokens.py
- action: removed
- - file: src/auth/fixtures.py
- action: restored
- - file: src/auth/__init__.py
- action: restored
- impact:
- child_plans_invalidated: 2
- sandbox: "restored to cp_01HXM8C2"
- decisions_after_cp: "2 discarded"
- tool_calls_after_cp: "5 undone"
- post_rollback_state:
- phase: execute
- state: "queued (awaiting input)"
- checkpoints_remaining: 2
- timing:
- started: "2025-06-15T10:37:00Z"
- duration_ms: 1850
- messages:
- - "Rollback complete"
- ```
-
-#### agents action
-
-!!! info "Purpose"
- Manage ==reusable actions== — named templates that define a complete unit of work including strategy actors, execution actors, definition of done, arguments, and invariants. Actions serve as the entry point to the plan lifecycle.
-
-??? tip "Action vs Plan"
- An **action** is a ==template==; a **plan** is an ==instance==. When you run `agents plan use `, the action template spawns a new plan that progresses through the lifecycle phases. Actions can be reused many times (default) or configured as single-use (`reusable: false`).
-
-##### agents action create
-
-agents action create --config|-c <CFG_FILE>
-
-**Purpose**
-Create a new action template from a YAML configuration file. The `--config` file is required and must fully define the action.
-
-**Arguments**
-
-- `--config/-c FILE`: YAML configuration file defining the action (required). The file must fully define the action, including the `name` field, `strategy-actor`, `execution-actor`, and `definition-of-done`.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents action create --config ./actions/code-coverage.yaml
-
- ╭─ Action Created ────────────────────────╮
- │ Name: local/code-coverage │
- │ State: available │
- │ Strategy Actor: local/strategist │
- │ Execution Actor: local/executor │
- │ Reusable: yes │
- │ Read Only: no │
- │ Config: ./actions/code-coverage.yaml │
- │ Created: 2026-02-08 12:20 │
- ╰─────────────────────────────────────────╯
-
- ╭─ Definition of Done ─╮
- │ Coverage reaches 85% │
- ╰──────────────────────╯
-
- ╭─ Arguments ──────────────────────────────────────────────────────╮
- │ Name Type Required Description │
- │ ─────────────────────── ────── ──────── ───────────────────── │
- │ target_coverage_percent int yes Target coverage % │
- │ test_command string no Test framework to use │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Automation ──────────────────────────╮
- │ Profile: supervised │
- │ Source: default │
- ╰───────────────────────────────────────╯
-
- ✓ OK Action created
-
-
-=== "Plain"
-
- ```
- $ agents action create --config ./actions/code-coverage.yaml
-
- Action Created
- Name: local/code-coverage
- State: available
- Strategy Actor: local/strategist
- Execution Actor: local/executor
- Reusable: yes
- Read Only: no
- Config: ./actions/code-coverage.yaml
- Created: 2026-02-08 12:20
-
- Definition of Done
- Coverage reaches 85%
-
- Arguments
- Name Type Required Description
- ----------------------- ------ -------- ---------------------
- target_coverage_percent int yes Target coverage %
- test_command string no Test framework to use
-
- Automation
- Profile: supervised
- Source: default
-
- [OK] Action created
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "action create",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/code-coverage",
- "state": "available",
- "strategy_actor": "local/strategist",
- "execution_actor": "local/executor",
- "reusable": true,
- "read_only": false,
- "config": "./actions/code-coverage.yaml",
- "created": "2026-02-08T12:20:00Z",
- "definition_of_done": "Coverage reaches 85%",
- "arguments": [
- { "name": "target_coverage_percent", "type": "int", "required": true, "description": "Target coverage %" },
- { "name": "test_command", "type": "string", "required": false, "description": "Test framework to use" }
- ],
- "automation": {
- "profile": "supervised",
- "source": "default"
- }
- },
- "timing": { "started": "2026-02-08T12:20:00Z", "duration_ms": 110 },
- "messages": ["Action created"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: action create
- status: ok
- exit_code: 0
- data:
- name: local/code-coverage
- state: available
- strategy_actor: local/strategist
- execution_actor: local/executor
- reusable: true
- read_only: false
- config: "./actions/code-coverage.yaml"
- created: "2026-02-08T12:20:00Z"
- definition_of_done: "Coverage reaches 85%"
- arguments:
- - name: target_coverage_percent
- type: int
- required: true
- description: "Target coverage %"
- - name: test_command
- type: string
- required: false
- description: "Test framework to use"
- automation:
- profile: supervised
- source: default
- timing:
- started: "2026-02-08T12:20:00Z"
- duration_ms: 110
- messages:
- - "Action created"
- ```
-
-##### agents action list
-
-agents action list [(--namespace|-n) <NS>] [(--state|-s) <STATE>] [<REGEX>]
-
-**Purpose**
-List actions with optional filters.
-
-**Arguments**
-
-- `--namespace/-n NS`: Filter by namespace.
-- `--state/-s STATE`: Filter by state.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents action list
-
- ╭─ Actions ──────────────────────────────────────────────────────────────────────────────────╮
- │ Name State Strategy Actor Execution Actor Reusable Plans │
- │ ─────────────────── ───────── ──────────────── ─────────────── ──────── ───── │
- │ local/code-coverage available local/strategist local/executor ✓ 3 │
- ╰────────────────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Filters ────────╮
- │ State: available │
- │ Namespace: (any) │
- ╰──────────────────╯
-
- ╭─ Summary ──────────────╮
- │ Total: 1 │
- │ Available: 1 │
- │ Archived: 0 │
- │ Total Plans Created: 3 │
- ╰────────────────────────╯
-
- ✓ OK 1 action listed
-
-
-=== "Plain"
-
- ```
- $ agents action list
-
- Actions
- Name State Strategy Actor Execution Actor Reusable Plans
- ------------------- --------- ---------------- --------------- -------- -----
- local/code-coverage available local/strategist local/executor yes 3
-
- Filters
- State: available
- Namespace: (any)
-
- Summary
- Total: 1
- Available: 1
- Archived: 0
- Total Plans Created: 3
-
- [OK] 1 action listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "action list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "actions": [
- {
- "name": "local/code-coverage",
- "state": "available",
- "strategy_actor": "local/strategist",
- "execution_actor": "local/executor",
- "reusable": true,
- "plans": 3
- }
- ],
- "filters": { "state": "available", "namespace": null },
- "summary": { "total": 1, "available": 1, "archived": 0, "total_plans_created": 3 }
- },
- "timing": { "started": "2026-02-08T12:21:00Z", "duration_ms": 45 },
- "messages": ["1 action listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: action list
- status: ok
- exit_code: 0
- data:
- actions:
- - name: local/code-coverage
- state: available
- strategy_actor: local/strategist
- execution_actor: local/executor
- reusable: true
- plans: 3
- filters:
- state: available
- namespace: null
- summary:
- total: 1
- available: 1
- archived: 0
- total_plans_created: 3
- timing:
- started: "2026-02-08T12:21:00Z"
- duration_ms: 45
- messages:
- - "1 action listed"
- ```
-
-##### agents action show
-
-agents action show <ACTION_NAME>
-
-**Purpose**
-Show details for an action.
-
-**Arguments**
-
-- ``: Action name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents action show local/code-coverage
-
- ╭─ Action Details ──────────────────────╮
- │ Name: local/code-coverage │
- │ State: available │
- │ Strategy Actor: local/strategist │
- │ Execution Actor: local/executor │
- │ Reusable: yes │
- │ Read Only: no │
- │ Created: 2026-02-08 12:20 │
- ╰───────────────────────────────────────╯
-
- ╭─ Definition of Done ─╮
- │ Coverage reaches 85% │
- ╰──────────────────────╯
-
- ╭─ Arguments ──────────────────────────────────────────────────────╮
- │ Name Type Required Description │
- │ ─────────────────────── ────── ──────── ───────────────────── │
- │ target_coverage_percent int yes Target coverage % │
- │ test_command string no Test framework to use │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Automation ──────────────────────────╮
- │ Profile: supervised │
- │ Source: default │
- ╰───────────────────────────────────────╯
-
- ╭─ History ────────────────────╮
- │ Plans Created: 3 │
- │ Plans Completed: 2 │
- │ Plans Failed: 0 │
- │ Avg Duration: 00:04:30 │
- │ Avg Cost: $0.072 │
- ╰──────────────────────────────╯
-
- ╭─ Usage ───────────────────────────────────────────────────────────╮
- │ - agents plan use local/code-coverage local/api-service │
- │ --arg target_coverage_percent=85 │
- ╰───────────────────────────────────────────────────────────────────╯
-
- ✓ OK Action loaded
-
-
-=== "Plain"
-
- ```
- $ agents action show local/code-coverage
-
- Action Details
- Name: local/code-coverage
- State: available
- Strategy Actor: local/strategist
- Execution Actor: local/executor
- Reusable: yes
- Read Only: no
- Created: 2026-02-08 12:20
-
- Definition of Done
- Coverage reaches 85%
-
- Arguments
- Name Type Required Description
- ----------------------- ------ -------- ---------------------
- target_coverage_percent int yes Target coverage %
- test_command string no Test framework to use
-
- Automation
- Profile: supervised
- Source: default
-
- History
- Plans Created: 3
- Plans Completed: 2
- Plans Failed: 0
- Avg Duration: 00:04:30
- Avg Cost: $0.072
-
- Usage
- agents plan use local/code-coverage local/api-service
- --arg target_coverage_percent=85
-
- [OK] Action loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "action show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/code-coverage",
- "state": "available",
- "strategy_actor": "local/strategist",
- "execution_actor": "local/executor",
- "reusable": true,
- "read_only": false,
- "created": "2026-02-08T12:20:00Z",
- "definition_of_done": "Coverage reaches 85%",
- "arguments": [
- { "name": "target_coverage_percent", "type": "int", "required": true, "description": "Target coverage %" },
- { "name": "test_command", "type": "string", "required": false, "description": "Test framework to use" }
- ],
- "automation": { "profile": "supervised", "source": "default" },
- "history": {
- "plans_created": 3,
- "plans_completed": 2,
- "plans_failed": 0,
- "avg_duration": "00:04:30",
- "avg_cost": "$0.072"
- }
- },
- "timing": { "started": "2026-02-08T12:21:00Z", "duration_ms": 60 },
- "messages": ["Action loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: action show
- status: ok
- exit_code: 0
- data:
- name: local/code-coverage
- state: available
- strategy_actor: local/strategist
- execution_actor: local/executor
- reusable: true
- read_only: false
- created: "2026-02-08T12:20:00Z"
- definition_of_done: "Coverage reaches 85%"
- arguments:
- - name: target_coverage_percent
- type: int
- required: true
- description: "Target coverage %"
- - name: test_command
- type: string
- required: false
- description: "Test framework to use"
- automation:
- profile: supervised
- source: default
- history:
- plans_created: 3
- plans_completed: 2
- plans_failed: 0
- avg_duration: "00:04:30"
- avg_cost: "$0.072"
- timing:
- started: "2026-02-08T12:21:00Z"
- duration_ms: 60
- messages:
- - "Action loaded"
- ```
-
-##### agents action archive
-
-agents action archive <ACTION_NAME>
-
-**Purpose**
-Archive an action.
-
-**Arguments**
-
-- ``: Action name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents action archive local/old-action
-
- ╭─ Action Archived ───────────╮
- │ Name: local/old-action │
- │ State: available → archived │
- │ Archived: 2026-02-08 12:22 │
- ╰─────────────────────────────╯
-
- ╭─ Impact ───────────────────────╮
- │ Availability: hidden from list │
- │ Existing Plans: unchanged │
- │ Active Plans: 0 affected │
- ╰────────────────────────────────╯
-
- ╭─ History ─────────────────╮
- │ Total Plans: 5 │
- │ Completed: 4 │
- │ Failed: 1 │
- │ Last Used: 2026-02-06 │
- ╰───────────────────────────╯
-
- ✓ OK Action archived
-
-
-=== "Plain"
-
- ```
- $ agents action archive local/old-action
-
- Action Archived
- Name: local/old-action
- State: available -> archived
- Archived: 2026-02-08 12:22
-
- Impact
- Availability: hidden from list
- Existing Plans: unchanged
- Active Plans: 0 affected
-
- History
- Total Plans: 5
- Completed: 4
- Failed: 1
- Last Used: 2026-02-06
-
- [OK] Action archived
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "action archive",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/old-action",
- "state_transition": "available -> archived",
- "archived": "2026-02-08T12:22:00Z",
- "impact": {
- "availability": "hidden from list",
- "existing_plans": "unchanged",
- "active_plans_affected": 0
- },
- "history": {
- "total_plans": 5,
- "completed": 4,
- "failed": 1,
- "last_used": "2026-02-06"
- }
- },
- "timing": { "started": "2026-02-08T12:22:00Z", "duration_ms": 55 },
- "messages": ["Action archived"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: action archive
- status: ok
- exit_code: 0
- data:
- name: local/old-action
- state_transition: "available -> archived"
- archived: "2026-02-08T12:22:00Z"
- impact:
- availability: hidden from list
- existing_plans: unchanged
- active_plans_affected: 0
- history:
- total_plans: 5
- completed: 4
- failed: 1
- last_used: "2026-02-06"
- timing:
- started: "2026-02-08T12:22:00Z"
- duration_ms: 55
- messages:
- - "Action archived"
- ```
-
-#### agents automation-profile
-
-!!! info "Purpose"
- Manage ==automation profiles== — named collections of confidence thresholds (floating-point values from `0.0` to `1.0`) that control which tasks are automated vs. require human approval. Each threshold specifies the minimum confidence level at which the system proceeds automatically; below the threshold, the system drops to manual mode.
-
-!!! tip "Threshold Scale"
- | Value | Meaning |
- | :---: | :------ |
- | `0.0` | ==Always automatic== — no human approval needed |
- | `0.5` | Automatic when confidence ≥ 50% |
- | `1.0` | ==Always manual== — always requires human approval |
-
-??? example "Built-in Profiles"
- The following profiles are always available and cannot be removed:
-
- | Profile | Description |
- | :------ | :---------- |
- | `manual` | All thresholds at `1.0` — everything requires approval |
- | `review` | Automatic strategize and execute, manual apply |
- | `supervised` | Automatic strategize, manual execute and apply |
- | `cautious` | Most operations automatic, manual for risky decisions |
- | `trusted` | Nearly fully automatic, manual only for apply |
- | `auto` | Fully automatic except apply |
- | `ci` | Optimized for CI/CD pipelines |
- | `full-auto` | All thresholds at `0.0` — fully autonomous |
-
- Custom profiles follow the same `/` naming convention as other entities.
-
-##### agents automation-profile add
-
-agents automation-profile add --config|-c <FILE> [--update]
-
-**Purpose**
-Register a new custom automation profile from a YAML configuration file. The profile is fully defined by the config file. If a profile with the same name already exists, the command fails unless the `--update` flag is provided.
-
-**Arguments**
-
-- `--config/-c FILE`: YAML configuration file defining the profile (required). The file must fully define the profile, including the `name` field which determines the profile's registered name.
-- `--update`: Replace an existing profile with the same name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents automation-profile add --config ./profiles/careful-auto.yaml
-
- ╭─ Profile Registered ─────────────────────────────────────────────╮
- │ Name: local/careful-auto │
- │ Description: Autonomous execution with mandatory sandbox │
- │ and manual apply │
- │ Created: 2026-02-08 14:30 │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ╭─ Confidence Thresholds ────────────────╮
- │ decompose_task: 0.0 │
- │ create_tool: 0.0 │
- │ select_tool: 1.0 │
- │ edit_code: 0.0 │
- │ execute_command: 0.0 │
- │ create_file: 0.0 │
- │ delete_content: 1.0 │
- │ access_network: 1.0 │
- │ install_dependency: 0.0 │
- │ modify_config: 0.0 │
- │ approve_plan: 0.0 │
- │ require_sandbox: true │
- │ require_checkpoints: true │
- │ allow_unsafe_tools: false │
- ╰────────────────────────────────────────╯
-
- ✓ OK Profile registered
-
-
-=== "Plain"
-
- ```
- $ agents automation-profile add --config ./profiles/careful-auto.yaml
-
- Profile Registered
- Name: local/careful-auto
- Description: Autonomous execution with mandatory sandbox and manual apply
- Created: 2026-02-08 14:30
-
- Confidence Thresholds
- decompose_task: 0.0
- create_tool: 0.0
- select_tool: 1.0
- edit_code: 0.0
- execute_command: 0.0
- create_file: 0.0
- delete_content: 1.0
- access_network: 1.0
- install_dependency: 0.0
- modify_config: 0.0
- approve_plan: 0.0
- require_sandbox: true
- require_checkpoints: true
- allow_unsafe_tools: false
-
- [OK] Profile registered
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "automation-profile add",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/careful-auto",
- "description": "Autonomous execution with mandatory sandbox and manual apply",
- "created": "2026-02-08T14:30:00Z",
- "thresholds": {
- "decompose_task": 0.0,
- "create_tool": 0.0,
- "select_tool": 1.0,
- "edit_code": 0.0,
- "execute_command": 0.0,
- "create_file": 0.0,
- "delete_content": 1.0,
- "access_network": 1.0,
- "install_dependency": 0.0,
- "modify_config": 0.0,
- "approve_plan": 0.0
- },
- "flags": {
- "require_sandbox": true,
- "require_checkpoints": true,
- "allow_unsafe_tools": false
- }
- },
- "timing": { "started": "2026-02-08T14:30:00Z", "duration_ms": 70 },
- "messages": ["Profile registered"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: automation-profile add
- status: ok
- exit_code: 0
- data:
- name: local/careful-auto
- description: "Autonomous execution with mandatory sandbox and manual apply"
- created: "2026-02-08T14:30:00Z"
- thresholds:
- decompose_task: 0.0
- create_tool: 0.0
- select_tool: 1.0
- edit_code: 0.0
- execute_command: 0.0
- create_file: 0.0
- delete_content: 1.0
- access_network: 1.0
- install_dependency: 0.0
- modify_config: 0.0
- approve_plan: 0.0
- flags:
- require_sandbox: true
- require_checkpoints: true
- allow_unsafe_tools: false
- timing:
- started: "2026-02-08T14:30:00Z"
- duration_ms: 70
- messages:
- - "Profile registered"
- ```
-
-##### agents automation-profile remove
-
-agents automation-profile remove [--yes|-y] <NAME>
-
-!!! warning "Destructive Operation"
- Remove a custom automation profile. ==Built-in profiles cannot be removed.== Plans and projects currently referencing this profile will fall back to their inherited or global default profile.
-
-**Arguments**
-
-- ``: Profile name.
-- `--yes, -y`: Skip confirmation prompt.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents automation-profile remove local/careful-auto
-
- Remove automation profile local/careful-auto? [y/N]: y
-
- ╭─ Profile Removed ──────────╮
- │ Name: local/careful-auto │
- ╰────────────────────────────╯
-
- ✓ OK Profile removed
-
-
-=== "Plain"
-
- ```
- $ agents automation-profile remove local/careful-auto
-
- Remove automation profile local/careful-auto? [y/N]: y
-
- Profile Removed
- Name: local/careful-auto
-
- [OK] Profile removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "automation-profile remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "local/careful-auto"
- },
- "timing": { "started": "2026-02-08T14:31:00Z", "duration_ms": 40 },
- "messages": ["Profile removed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: automation-profile remove
- status: ok
- exit_code: 0
- data:
- name: local/careful-auto
- timing:
- started: "2026-02-08T14:31:00Z"
- duration_ms: 40
- messages:
- - "Profile removed"
- ```
-
-##### agents automation-profile list
-
-agents automation-profile list [<REGEX>]
-
-**Purpose**
-List all available automation profiles (built-in and custom).
-
-**Arguments**
-
-- `[REGEX]`: Optional filter pattern.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents automation-profile list
-
- ╭─ Automation Profiles ──────────────────────────────────────────────────────────╮
- │ Name Source Auto-Apply Sandbox Description │
- │ ────────────────── ──────── ────────── ─────── ──────────────────────── │
- │ manual built-in 1.0 yes Human-driven (default) │
- │ review built-in 1.0 yes Auto-phase, manual decisions │
- │ supervised built-in 1.0 yes Auto-plan, manual exec │
- │ cautious built-in 1.0 yes Confidence-gated automation │
- │ trusted built-in 1.0 yes Auto-exec, manual apply │
- │ auto built-in 1.0 yes Full auto except apply │
- │ ci built-in 0.0 yes Full auto, safe CI/CD │
- │ full-auto built-in 0.0 no Complete automation │
- │ local/careful-auto custom 0.8 yes Custom careful profile │
- ╰────────────────────────────────────────────────────────────────────────────────╯
-
- ╭─ Summary ───────────╮
- │ Built-in: 8 │
- │ Custom: 1 │
- │ Total: 9 │
- ╰─────────────────────╯
-
- ✓ OK 9 profiles listed
-
-
-=== "Plain"
-
- ```
- $ agents automation-profile list
-
- Automation Profiles
- Name Source Auto-Apply Sandbox Description
- ------------------ -------- ---------- ------- ----------------------------
- manual built-in 1.0 yes Human-driven (default)
- review built-in 1.0 yes Auto-phase, manual decisions
- supervised built-in 1.0 yes Auto-plan, manual exec
- cautious built-in 1.0 yes Confidence-gated automation
- trusted built-in 1.0 yes Auto-exec, manual apply
- auto built-in 1.0 yes Full auto except apply
- ci built-in 0.0 yes Full auto, safe CI/CD
- full-auto built-in 0.0 no Complete automation
- local/careful-auto custom 0.8 yes Custom careful profile
-
- Summary
- Built-in: 8
- Custom: 1
- Total: 9
-
- [OK] 9 profiles listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "automation-profile list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "profiles": [
- { "name": "manual", "source": "built-in", "select_tool": 1.0, "sandbox": true, "description": "Human-driven (default)" },
- { "name": "review", "source": "built-in", "select_tool": 1.0, "sandbox": true, "description": "Auto-phase, manual decisions" },
- { "name": "supervised", "source": "built-in", "select_tool": 1.0, "sandbox": true, "description": "Auto-plan, manual exec" },
- { "name": "cautious", "source": "built-in", "select_tool": 1.0, "sandbox": true, "description": "Confidence-gated automation" },
- { "name": "trusted", "source": "built-in", "select_tool": 1.0, "sandbox": true, "description": "Auto-exec, manual apply" },
- { "name": "auto", "source": "built-in", "select_tool": 1.0, "sandbox": true, "description": "Full auto except apply" },
- { "name": "ci", "source": "built-in", "select_tool": 0.0, "sandbox": true, "description": "Full auto, safe CI/CD" },
- { "name": "full-auto", "source": "built-in", "select_tool": 0.0, "sandbox": false, "description": "Complete automation" },
- { "name": "local/careful-auto", "source": "custom", "select_tool": 0.8, "sandbox": true, "description": "Custom careful profile" }
- ],
- "summary": { "built_in": 8, "custom": 1, "total": 9 }
- },
- "timing": { "started": "2026-02-08T14:31:00Z", "duration_ms": 50 },
- "messages": ["9 profiles listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: automation-profile list
- status: ok
- exit_code: 0
- data:
- profiles:
- - name: manual
- source: built-in
- select_tool: 1.0
- sandbox: true
- description: "Human-driven (default)"
- - name: review
- source: built-in
- select_tool: 1.0
- sandbox: true
- description: "Auto-phase, manual decisions"
- - name: supervised
- source: built-in
- select_tool: 1.0
- sandbox: true
- description: "Auto-plan, manual exec"
- - name: cautious
- source: built-in
- select_tool: 1.0
- sandbox: true
- description: "Confidence-gated automation"
- - name: trusted
- source: built-in
- select_tool: 1.0
- sandbox: true
- description: "Auto-exec, manual apply"
- - name: auto
- source: built-in
- select_tool: 1.0
- sandbox: true
- description: "Full auto except apply"
- - name: ci
- source: built-in
- select_tool: 0.0
- sandbox: true
- description: "Full auto, safe CI/CD"
- - name: full-auto
- source: built-in
- select_tool: 0.0
- sandbox: false
- description: "Complete automation"
- - name: local/careful-auto
- source: custom
- select_tool: 0.8
- sandbox: true
- description: "Custom careful profile"
- summary:
- built_in: 8
- custom: 1
- total: 9
- timing:
- started: "2026-02-08T14:31:00Z"
- duration_ms: 50
- messages:
- - "9 profiles listed"
- ```
-
-##### agents automation-profile show
-
-agents automation-profile show <NAME>
-
-**Purpose**
-Show full details for an automation profile, including all flag values.
-
-**Arguments**
-
-- ``: Profile name.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents automation-profile show trusted
-
- ╭─ Automation Profile ───────────────────────────────────────────╮
- │ Name: trusted │
- │ Source: built-in │
- │ Description: Auto-exec, manual apply. Day-to-day development │
- ╰────────────────────────────────────────────────────────────────╯
-
- ╭─ Phase Transitions (thresholds) ─────╮
- │ decompose_task: 0.0 │
- │ create_tool: 0.0 │
- │ select_tool: 1.0 │
- ╰──────────────────────────────────────╯
-
- ╭─ Decision Automation (thresholds) ───╮
- │ edit_code: 0.0 │
- │ execute_command: 0.0 │
- ╰──────────────────────────────────────╯
-
- ╭─ Self-Repair (thresholds) ───────────╮
- │ create_file: 0.0 │
- │ delete_content: 1.0 │
- │ access_network: 1.0 │
- │ modify_config: 0.0 │
- │ approve_plan: 1.0 │
- ╰──────────────────────────────────────╯
-
- ╭─ Execution Controls (thresholds) ────╮
- │ install_dependency: 0.0 │
- │ require_sandbox: true │
- │ require_checkpoints: true │
- │ allow_unsafe_tools: false │
- ╰──────────────────────────────────────╯
-
- ✓ OK Profile loaded
-
-
-=== "Plain"
-
- ```
- $ agents automation-profile show trusted
-
- Automation Profile
- Name: trusted
- Source: built-in
- Description: Auto-exec, manual apply. Day-to-day development
-
- Phase Transitions (thresholds)
- decompose_task: 0.0
- create_tool: 0.0
- select_tool: 1.0
-
- Decision Automation (thresholds)
- edit_code: 0.0
- execute_command: 0.0
-
- Self-Repair (thresholds)
- create_file: 0.0
- delete_content: 1.0
- access_network: 1.0
- modify_config: 0.0
- approve_plan: 1.0
-
- Execution Controls (thresholds)
- install_dependency: 0.0
- require_sandbox: true
- require_checkpoints: true
- allow_unsafe_tools: false
-
- [OK] Profile loaded
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "automation-profile show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "name": "trusted",
- "source": "built-in",
- "description": "Auto-exec, manual apply. Day-to-day development",
- "phase_transitions": {
- "decompose_task": 0.0,
- "create_tool": 0.0,
- "select_tool": 1.0
- },
- "decision_automation": {
- "edit_code": 0.0,
- "execute_command": 0.0
- },
- "self_repair": {
- "create_file": 0.0,
- "delete_content": 1.0,
- "access_network": 1.0,
- "modify_config": 0.0,
- "approve_plan": 1.0
- },
- "execution_controls": {
- "install_dependency": 0.0,
- "require_sandbox": true,
- "require_checkpoints": true,
- "allow_unsafe_tools": false
- }
- },
- "timing": { "started": "2026-02-08T14:31:00Z", "duration_ms": 55 },
- "messages": ["Profile loaded"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: automation-profile show
- status: ok
- exit_code: 0
- data:
- name: trusted
- source: built-in
- description: "Auto-exec, manual apply. Day-to-day development"
- phase_transitions:
- decompose_task: 0.0
- create_tool: 0.0
- select_tool: 1.0
- decision_automation:
- edit_code: 0.0
- execute_command: 0.0
- self_repair:
- create_file: 0.0
- delete_content: 1.0
- access_network: 1.0
- modify_config: 0.0
- approve_plan: 1.0
- execution_controls:
- install_dependency: 0.0
- require_sandbox: true
- require_checkpoints: true
- allow_unsafe_tools: false
- timing:
- started: "2026-02-08T14:31:00Z"
- duration_ms: 55
- messages:
- - "Profile loaded"
- ```
-
-#### agents config
-
-!!! info "Purpose"
- Manage ==global configuration values== that control system-wide defaults. Configuration keys use hierarchical dot-path notation (e.g., `core.automation-profile`, `core.log.level`).
-
-??? tip "Key Configuration Categories"
- | Category | Example Keys | Description |
- | :------- | :----------- | :---------- |
- | **Core** | `core.automation-profile`, `core.format`, `core.log.level` | System-wide defaults |
- | **Actor** | `actor.default.invariant` | Default actor assignments |
- | **Output** | `core.format` | Default rendering format (`rich`, `json`, `yaml`, etc.) |
-
-##### agents config set
-
-agents config set <key> <value>
-
-**Purpose**
-Set a configuration key.
-
-**Arguments**
-
-- ``: Hierarchical dot-path key name (e.g., `core.automation-profile`, `core.log.level`, `actor.default.invariant`, `core.format`). See **Global Configuration Keys** for the complete reference.
-- ``: Value to set.
-
-The `actor.default.invariant` key sets the default Invariant Reconciliation Actor used globally. This actor is used to reconcile invariant conflicts when neither the plan nor the project specifies one.
-
-The `core.format` key sets the default output rendering format used by all commands. Accepted values are `rich`, `color`, `table`, `plain`, `json`, `yaml`. When set, this value is used unless overridden by the `--format` CLI flag. See **Output Rendering Framework** for details.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents config set core.automation-profile trusted
-
- ╭─ Config Updated ──────────────────────╮
- │ Key: core.automation-profile │
- │ Value: trusted │
- │ Previous: manual │
- │ Source: config │
- │ Scope: global │
- ╰───────────────────────────────────────╯
-
- ╭─ Effective ────────────────────────╮
- │ Sessions: new sessions │
- │ Plans: future plans (unless set) │
- │ Existing: unchanged │
- ╰────────────────────────────────────╯
-
- ╭─ Saved To ──────────────────────────╮
- │ File: ~/.cleveragents/config.toml │
- │ Line: 8 │
- ╰─────────────────────────────────────╯
-
- ✓ OK Config updated
-
-
-=== "Plain"
-
- ```
- $ agents config set core.automation-profile trusted
-
- Config Updated
- Key: core.automation-profile
- Value: trusted
- Previous: manual
- Source: config
- Scope: global
-
- Effective
- Sessions: new sessions
- Plans: future plans (unless set)
- Existing: unchanged
-
- Saved To
- File: ~/.cleveragents/config.toml
- Line: 8
-
- [OK] Config updated
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "config set",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "key": "core.automation-profile",
- "value": "trusted",
- "previous": "manual",
- "source": "config",
- "scope": "global",
- "effective": {
- "sessions": "new sessions",
- "plans": "future plans (unless set)",
- "existing": "unchanged"
- },
- "saved_to": { "file": "~/.cleveragents/config.toml", "line": 8 }
- },
- "timing": { "started": "2026-02-08T14:32:00Z", "duration_ms": 30 },
- "messages": ["Config updated"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: config set
- status: ok
- exit_code: 0
- data:
- key: core.automation-profile
- value: trusted
- previous: manual
- source: config
- scope: global
- effective:
- sessions: new sessions
- plans: "future plans (unless set)"
- existing: unchanged
- saved_to:
- file: "~/.cleveragents/config.toml"
- line: 8
- timing:
- started: "2026-02-08T14:32:00Z"
- duration_ms: 30
- messages:
- - "Config updated"
- ```
-
-Setting the default output format:
-
-=== "Rich"
-
-
- $ agents config set core.format table
-
- ╭─ Config Updated ─────────────────╮
- │ Key: core.format │
- │ Previous: rich │
- │ New Value: table │
- │ Scope: user (~/.cleveragents) │
- ╰──────────────────────────────────╯
-
- ✓ OK Set core.format = table
-
-
-=== "Plain"
-
- ```
- $ agents config set core.format table
-
- Config Updated
- Key: core.format
- Previous: rich
- New Value: table
- Scope: user (~/.cleveragents)
-
- [OK] Set core.format = table
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "config set",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "key": "core.format",
- "previous": "rich",
- "value": "table",
- "scope": "user (~/.cleveragents)"
- },
- "timing": { "started": "2026-02-08T14:32:00Z", "duration_ms": 25 },
- "messages": ["Set core.format = table"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: config set
- status: ok
- exit_code: 0
- data:
- key: core.format
- previous: rich
- value: table
- scope: "user (~/.cleveragents)"
- timing:
- started: "2026-02-08T14:32:00Z"
- duration_ms: 25
- messages:
- - "Set core.format = table"
- ```
-
-Setting a global invariant actor:
-
-=== "Rich"
-
-
- $ agents config set actor.default.invariant local/invariant-resolver
-
- ╭─ Config Updated ──────────────────────────────────╮
- │ Key: actor.default.invariant │
- │ Previous: (not set) │
- │ New Value: local/invariant-resolver │
- │ Scope: user (~/.cleveragents) │
- ╰───────────────────────────────────────────────────╯
-
- ✓ OK Set actor.default.invariant = local/invariant-resolver
-
-
-=== "Plain"
-
- ```
- $ agents config set actor.default.invariant local/invariant-resolver
-
- Config Updated
- Key: actor.default.invariant
- Previous: (not set)
- New Value: local/invariant-resolver
- Scope: user (~/.cleveragents)
-
- [OK] Set actor.default.invariant = local/invariant-resolver
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "config set",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "key": "actor.default.invariant",
- "previous": null,
- "value": "local/invariant-resolver",
- "scope": "user (~/.cleveragents)"
- },
- "timing": { "started": "2026-02-08T14:32:00Z", "duration_ms": 28 },
- "messages": ["Set actor.default.invariant = local/invariant-resolver"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: config set
- status: ok
- exit_code: 0
- data:
- key: actor.default.invariant
- previous: null
- value: local/invariant-resolver
- scope: "user (~/.cleveragents)"
- timing:
- started: "2026-02-08T14:32:00Z"
- duration_ms: 28
- messages:
- - "Set actor.default.invariant = local/invariant-resolver"
- ```
-
-##### agents config get
-
-
-
-**Purpose**
-Get a configuration value.
-
-**Arguments**
-
-- ``: Key to read.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents config get core.automation-profile
-
- ╭─ Config ──────────────────────────╮
- │ Key: core.automation-profile │
- │ Value: trusted │
- │ Source: config │
- │ Overridden: no │
- │ Type: string │
- ╰───────────────────────────────────╯
-
- ╭─ Origin ──────────────────────────╮
- │ File: ~/.cleveragents/config.toml │
- │ Line: 8 │
- │ Default: supervised │
- ╰───────────────────────────────────╯
-
- ╭─ Resolution Chain ──────────────╮
- │ 1. CLI flag: (not set) │
- │ 2. Env var: (not set) │
- │ 3. Config file: trusted │
- │ 4. Default: supervised │
- │ Winner: config file (level 3) │
- ╰─────────────────────────────────╯
-
- ✓ OK Config read
-
-
-=== "Plain"
-
- ```
- $ agents config get core.automation-profile
-
- Config
- Key: core.automation-profile
- Value: trusted
- Source: config
- Overridden: no
- Type: string
-
- Origin
- File: ~/.cleveragents/config.toml
- Line: 8
- Default: supervised
-
- Resolution Chain
- 1. CLI flag: (not set)
- 2. Env var: (not set)
- 3. Config file: trusted
- 4. Default: supervised
- Winner: config file (level 3)
-
- [OK] Config read
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "config get",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "key": "core.automation-profile",
- "value": "trusted",
- "source": "config",
- "overridden": false,
- "type": "string",
- "origin": {
- "file": "~/.cleveragents/config.toml",
- "line": 8,
- "default": "supervised"
- },
- "resolution_chain": [
- { "level": 1, "source": "CLI flag", "value": null },
- { "level": 2, "source": "Env var", "value": null },
- { "level": 3, "source": "Config file", "value": "trusted" },
- { "level": 4, "source": "Default", "value": "supervised" }
- ],
- "winner": { "source": "config file", "level": 3 }
- },
- "timing": { "started": "2026-02-08T14:33:00Z", "duration_ms": 20 },
- "messages": ["Config read"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: config get
- status: ok
- exit_code: 0
- data:
- key: core.automation-profile
- value: trusted
- source: config
- overridden: false
- type: string
- origin:
- file: "~/.cleveragents/config.toml"
- line: 8
- default: supervised
- resolution_chain:
- - level: 1
- source: "CLI flag"
- value: null
- - level: 2
- source: "Env var"
- value: null
- - level: 3
- source: "Config file"
- value: trusted
- - level: 4
- source: Default
- value: supervised
- winner:
- source: "config file"
- level: 3
- timing:
- started: "2026-02-08T14:33:00Z"
- duration_ms: 20
- messages:
- - "Config read"
- ```
-
-##### agents config list
-
-agents config list [--filter-values <REGEX>] [<REGEX>]
-
-**Purpose**
-List all configuration values.
-
-**Arguments**
-
-None.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents config list
-
- ╭─ Config ───────────────────────────────────────────────────╮
- │ Key Value Source Modified │
- │ ──────────────── ────────────────── ─────── ──────── │
- │ core.automation-profile trusted config yes │
- │ actor.default.invariant local/reconciler config yes │
- │ core.log.level FATAL default no │
- ╰────────────────────────────────────────────────────────────╯
-
- ╭─ Overrides ─────╮
- │ Env: none │
- │ CLI Flags: none │
- ╰─────────────────╯
-
- ╭─ Config File ───────────────────────╮
- │ Path: ~/.cleveragents/config.toml │
- │ Size: 284 bytes │
- │ Valid: yes │
- ╰─────────────────────────────────────╯
-
- ✓ OK 6 settings listed
-
-
-=== "Plain"
-
- ```
- $ agents config list
-
- Config
- Key Value Source Modified
- ----------------------- ------------------ ------- --------
- core.automation-profile trusted config yes
- actor.default.invariant local/reconciler config yes
- core.log.level FATAL default no
-
- Overrides
- Env: none
- CLI Flags: none
-
- Config File
- Path: ~/.cleveragents/config.toml
- Size: 284 bytes
- Valid: yes
-
- [OK] 6 settings listed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "config list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "settings": [
- { "key": "core.automation-profile", "value": "trusted", "source": "config", "modified": true },
- { "key": "actor.default.invariant", "value": "local/reconciler", "source": "config", "modified": true },
- { "key": "core.log.level", "value": "FATAL", "source": "default", "modified": false }
- ],
- "overrides": { "env": null, "cli_flags": null },
- "config_file": {
- "path": "~/.cleveragents/config.toml",
- "size_bytes": 284,
- "valid": true
- }
- },
- "timing": { "started": "2026-02-08T14:33:00Z", "duration_ms": 25 },
- "messages": ["6 settings listed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: config list
- status: ok
- exit_code: 0
- data:
- settings:
- - key: core.automation-profile
- value: trusted
- source: config
- modified: true
- - key: actor.default.invariant
- value: local/reconciler
- source: config
- modified: true
- - key: core.log.level
- value: FATAL
- source: default
- modified: false
- overrides:
- env: null
- cli_flags: null
- config_file:
- path: "~/.cleveragents/config.toml"
- size_bytes: 284
- valid: true
- timing:
- started: "2026-02-08T14:33:00Z"
- duration_ms: 25
- messages:
- - "6 settings listed"
- ```
-
-#### agents invariant
-
-!!! info "Purpose"
- Manage ==invariants== — named constraints that guide and constrain plan execution. Invariants can be attached to any scope: global (all plans), project (all plans targeting that project), plan (a specific plan and its child plans), or action (carried forward when the action is used).
-
-!!! warning "Scope Requirements"
- Exactly ==one scope flag== is required for `add` and `list`. The available scopes are:
-
- | Scope | Flag | Applies To |
- | :---- | :--- | :--------- |
- | **Global** | `--global` | All plans across all projects |
- | **Project** | `--project ` | All plans targeting that project |
- | **Plan** | `--plan ` | A specific plan and its child plans |
- | **Action** | `--action ` | Carried forward when the action is used |
-
- When multiple scopes apply to a plan, the ==union== of all applicable invariants is enforced.
-
-##### agents invariant add
-
-agents invariant add [--global] [(--project|-p) PROJECT] [--plan PLAN_ID]...
- [--action ACTION]... <INVARIANT_TEXT>
-
-**Purpose**
-Add an invariant at the specified scope.
-
-**Arguments**
-
-- ``: The invariant text (positional argument at end of command).
-- `--global`: Attach as a global invariant (applies to all plans).
-- `--project/-p PROJECT`: Attach to a project (applies to all plans targeting this project).
-- `--plan PLAN_ID`: Attach to a plan (plan-level invariant). Repeatable.
-- `--action ACTION`: Attach to an action (action-level invariant). Repeatable.
-
-At least one scope flag (`--global`, `--project`, `--plan`, or `--action`) must be provided. `--plan` and `--action` can be repeated to attach the same invariant to multiple plans or actions.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents invariant add --global "All public APIs must maintain backward compatibility"
-
- ╭─ Invariant Added ──────────────────────────────────────────────────────╮
- │ Invariant: All public APIs must maintain backward compatibility │
- │ Scope: global │
- │ ID: inv_01HXM9A1B │
- ╰────────────────────────────────────────────────────────────────────────╯
-
- ✓ OK Invariant added
-
- $ agents invariant add --project local/api-service "All endpoints must validate auth tokens"
-
- ╭─ Invariant Added ──────────────────────────────────────────────╮
- │ Project: local/api-service │
- │ Invariant: All endpoints must validate auth tokens │
- │ Scope: project │
- │ ID: inv_01HXM9A2C │
- ╰────────────────────────────────────────────────────────────────╯
-
- ✓ OK Invariant added
-
- $ agents invariant add --plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J "All database queries must use parameterized statements"
-
- ╭─ Invariant Added ─────────────────────────────────────────────────────╮
- │ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
- │ Invariant: All database queries must use parameterized statements │
- │ Scope: plan │
- │ ID: inv_01HXM9G3A │
- ╰───────────────────────────────────────────────────────────────────────╯
-
- ✓ OK Invariant added
-
- $ agents invariant add --action local/code-coverage "Test files must not import production secrets"
-
- ╭─ Invariant Added ──────────────────────────────────────────────────────╮
- │ Action: local/code-coverage │
- │ Invariant: Test files must not import production secrets │
- │ Scope: action │
- │ ID: inv_01HXM9H4B │
- ╰────────────────────────────────────────────────────────────────────────╯
-
- ✓ OK Invariant added
-
-
-=== "Plain"
-
- ```
- $ agents invariant add --global "All public APIs must maintain backward compatibility"
-
- Invariant Added
- Invariant: All public APIs must maintain backward compatibility
- Scope: global
- ID: inv_01HXM9A1B
-
- [OK] Invariant added
-
- $ agents invariant add --project local/api-service "All endpoints must validate auth tokens"
-
- Invariant Added
- Project: local/api-service
- Invariant: All endpoints must validate auth tokens
- Scope: project
- ID: inv_01HXM9A2C
-
- [OK] Invariant added
-
- $ agents invariant add --plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J "All database queries must use parameterized statements"
-
- Invariant Added
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Invariant: All database queries must use parameterized statements
- Scope: plan
- ID: inv_01HXM9G3A
-
- [OK] Invariant added
-
- $ agents invariant add --action local/code-coverage "Test files must not import production secrets"
-
- Invariant Added
- Action: local/code-coverage
- Invariant: Test files must not import production secrets
- Scope: action
- ID: inv_01HXM9H4B
-
- [OK] Invariant added
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "invariant add",
- "status": "ok",
- "exit_code": 0,
- "data": [
- {
- "invariant": "All public APIs must maintain backward compatibility",
- "scope": "global",
- "id": "inv_01HXM9A1B"
- },
- {
- "project": "local/api-service",
- "invariant": "All endpoints must validate auth tokens",
- "scope": "project",
- "id": "inv_01HXM9A2C"
- },
- {
- "plan": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "invariant": "All database queries must use parameterized statements",
- "scope": "plan",
- "id": "inv_01HXM9G3A"
- },
- {
- "action": "local/code-coverage",
- "invariant": "Test files must not import production secrets",
- "scope": "action",
- "id": "inv_01HXM9H4B"
- }
- ],
- "timing": { "started": "2026-02-08T14:35:00Z", "duration_ms": 45 },
- "messages": ["Invariant added"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: invariant add
- status: ok
- exit_code: 0
- data:
- - invariant: "All public APIs must maintain backward compatibility"
- scope: global
- id: inv_01HXM9A1B
- - project: local/api-service
- invariant: "All endpoints must validate auth tokens"
- scope: project
- id: inv_01HXM9A2C
- - plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- invariant: "All database queries must use parameterized statements"
- scope: plan
- id: inv_01HXM9G3A
- - action: local/code-coverage
- invariant: "Test files must not import production secrets"
- scope: action
- id: inv_01HXM9H4B
- timing:
- started: "2026-02-08T14:35:00Z"
- duration_ms: 45
- messages:
- - "Invariant added"
- ```
-
-##### agents invariant list
-
-agents invariant list [--global] [(--project|-p) PROJECT] [--plan PLAN_ID] [--action ACTION]
- [--effective] [<REGEX>]
-
-**Purpose**
-List invariants at a given scope. Use `--effective` with `--plan` to show the final reconciled view of invariants (after precedence resolution) rather than just the invariants directly attached at that scope.
-
-**Arguments**
-
-- `--global`: List global invariants.
-- `--project/-p PROJECT`: List invariants attached to a project.
-- `--plan PLAN_ID`: List invariants attached to a plan.
-- `--action ACTION`: List invariants attached to an action.
-- `--effective`: (Only with `--plan`) Show the reconciled invariant view after precedence resolution across all scopes.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents invariant list --global
-
- ╭─ Global Invariants ──────────────────────────────────────────────────────╮
- │ ID Text │
- │ ────────────── ──────────────────────────────────────────────────── │
- │ inv_01HXM9A1B All public APIs must maintain backward compatibility │
- │ inv_01HXM9A1C Payment processing must be idempotent │
- ╰──────────────────────────────────────────────────────────────────────────╯
-
- ✓ OK 2 invariants
-
- $ agents invariant list --plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J --effective
-
- ╭─ Effective Invariants (Plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J) ──────────────────────────────────╮
- │ ID Source Text │
- │ ────────────── ─────── ────────────────────────────────────────────────────── │
- │ inv_01HXM9A1B global All public APIs must maintain backward compatibility │
- │ inv_01HXM9A2C project All endpoints must validate auth tokens │
- │ inv_01HXM9G3A plan All database queries must use parameterized statements │
- ╰───────────────────────────────────────────────────────────────────────────────────────────╯
-
- │ Conflicts Resolved: 1 │
- │ Global "Use shared DB pool" overridden by plan "All database queries must use │
- │ parameterized statements" │
-
- ✓ OK 3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)
-
-
-=== "Plain"
-
- ```
- $ agents invariant list --global
-
- Global Invariants
- ID Text
- -------------- --------------------------------------------------------
- inv_01HXM9A1B All public APIs must maintain backward compatibility
- inv_01HXM9A1C Payment processing must be idempotent
-
- [OK] 2 invariants
-
- $ agents invariant list --plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J --effective
-
- Effective Invariants (Plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J)
- ID Source Text
- -------------- ------- --------------------------------------------------
- inv_01HXM9A1B global All public APIs must maintain backward compatibility
- inv_01HXM9A2C project All endpoints must validate auth tokens
- inv_01HXM9G3A plan All database queries must use parameterized statements
-
- Conflicts Resolved: 1
- Global "Use shared DB pool" overridden by plan "All database queries must use
- parameterized statements"
-
- [OK] 3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "invariant list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "scope": "plan",
- "plan_id": "01HXM8C2ZK4Q7C2B3F2R4VYV6J",
- "effective": true,
- "invariants": [
- { "id": "inv_01HXM9A1B", "source": "global", "text": "All public APIs must maintain backward compatibility" },
- { "id": "inv_01HXM9A2C", "source": "project", "text": "All endpoints must validate auth tokens" },
- { "id": "inv_01HXM9G3A", "source": "plan", "text": "All database queries must use parameterized statements" }
- ],
- "conflicts_resolved": [
- {
- "overridden": { "source": "global", "text": "Use shared DB pool" },
- "by": { "source": "plan", "text": "All database queries must use parameterized statements" }
- }
- ]
- },
- "timing": { "started": "2026-02-08T14:35:00Z", "duration_ms": 35 },
- "messages": ["3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: invariant list
- status: ok
- exit_code: 0
- data:
- scope: plan
- plan_id: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- effective: true
- invariants:
- - id: inv_01HXM9A1B
- source: global
- text: "All public APIs must maintain backward compatibility"
- - id: inv_01HXM9A2C
- source: project
- text: "All endpoints must validate auth tokens"
- - id: inv_01HXM9G3A
- source: plan
- text: "All database queries must use parameterized statements"
- conflicts_resolved:
- - overridden:
- source: global
- text: "Use shared DB pool"
- by:
- source: plan
- text: "All database queries must use parameterized statements"
- timing:
- started: "2026-02-08T14:35:00Z"
- duration_ms: 35
- messages:
- - "3 effective invariants (1 global, 1 project, 1 plan; 1 conflict resolved)"
- ```
-
-##### agents invariant remove
-
-agents invariant remove [--yes|-y] <INVARIANT_ID>
-
-!!! warning "Constraint Removal"
- Remove an invariant by ID. The invariant is removed from whichever scope it was originally attached to. ==Active plans== that have already incorporated this invariant into their decision trees are not retroactively affected, but future plans will no longer enforce this constraint.
-
-**Arguments**
-
-- ``: Invariant ID to remove.
-- `--yes`: Skip confirmation.
-
-**Examples**
-
-=== "Rich"
-
-
- $ agents invariant remove inv_01HXM9A1C
-
- Remove invariant inv_01HXM9A1C ("Payment processing must be idempotent", scope: global)? [y/N]: y
-
- ╭─ Invariant Removed ──────────────────────────────────────────────╮
- │ Removed: Payment processing must be idempotent │
- │ Scope: global │
- │ ID: inv_01HXM9A1C │
- ╰──────────────────────────────────────────────────────────────────╯
-
- ✓ OK Invariant removed
-
-
-=== "Plain"
-
- ```
- $ agents invariant remove inv_01HXM9A1C
-
- Remove invariant inv_01HXM9A1C ("Payment processing must be idempotent", scope: global)? [y/N]: y
-
- Invariant Removed
- Removed: Payment processing must be idempotent
- Scope: global
- ID: inv_01HXM9A1C
-
- [OK] Invariant removed
- ```
-
-=== "JSON"
-
- ```json
- {
- "command": "invariant remove",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "removed": "Payment processing must be idempotent",
- "scope": "global",
- "id": "inv_01HXM9A1C"
- },
- "timing": { "started": "2026-02-08T14:36:00Z", "duration_ms": 30 },
- "messages": ["Invariant removed"]
- }
- ```
-
-=== "YAML"
-
- ```yaml
- command: invariant remove
- status: ok
- exit_code: 0
- data:
- removed: "Payment processing must be idempotent"
- scope: global
- id: inv_01HXM9A1C
- timing:
- started: "2026-02-08T14:36:00Z"
- duration_ms: 30
- messages:
- - "Invariant removed"
- ```
-
-## Core Concepts
-
-### Plan
-
-!!! adr "Architecture Decision"
- The plan lifecycle, phase transitions, and plan hierarchy are defined in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md).
-
-A **plan** is the fundamental unit of orchestration and traceability.
-
-#### Plan Lifecycle Phases
-
-A plan progresses through four phases:
-
-**Action → Strategize → Execute → Apply**
-
-In this spec:
-
-* **Action** is the first phase. An action serves as a reusable plan template — it defines the work to be done (description, definition of done, actors, arguments, invariants) without being bound to any project. No significant processing occurs during the Action phase. When an action is used (via `agents plan use`), it spawns a new plan entity that enters the Strategize phase. By default, the original action remains available for reuse; single-use actions (created with `reusable: false`) are deleted after first use. Although Action is formally a phase in the lifecycle, it is unique in that it functions primarily as a template from which plans are instantiated.
-* **Strategize** is the second phase and the first where active processing occurs (the output is a **strategy**).
-* **Execute** is the third phase (the output is a **changeset**).
-* **Apply** is the fourth and final phase. Apply merges the sandbox changeset into real project resources. Upon completion, the plan reaches one of several terminal states: `applied` (success — changes committed), `constrained` (cannot complete within the current strategy's constraints — may trigger reversion to Strategize), `errored` (failed), or `cancelled`.
-
-The normal phase progression is forward, but both Execute and Apply may revert to Strategize when the current strategy's constraints are too restrictive (see *Phase Reversion* below).
-
-#### Phase Transition Verbs (CLI / UX Contract)
-
- Verbs that trigger phase transitions. CleverAgents should standardize these verbs as the **public API** (CLI, TUI, web):
-
-| Current Phase | Command Verb | Next Phase |
-| ------------- | ------------ | ---------- |
-| (none) | `create` | Action |
-| Action | `use` | Strategize |
-| Strategize | `execute` | Execute |
-| Execute | `apply` | Apply |
-
-!!! note "Important behavioral rules"
- * CleverAgents uses **automation profiles** to control which of these phase transitions happen automatically. The profile determines whether each transition requires explicit user action or proceeds autonomously, but the verbs remain the conceptual contract.
- * **There is no `strategize` command.** The phase transition verbs are used in CLI commands — not the phase names. The `use` verb (as in `agents plan use`) is the command that transitions a plan from the Action phase into Strategize. This is by design: ==`use` describes the user's intent== (using an action template on a project), and the system responds by entering the Strategize phase.
-
-#### Phase Reversion (→ Strategize)
-
-!!! adr "Architecture Decision"
- Phase reversion rules and the decision tree model are detailed in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md) and [ADR-007: Decision Tree and Correction](adr/ADR-007-decision-tree-and-correction.md).
-
-While the normal phase progression is forward (Action → Strategize → Execute → Apply), both the Execute and Apply phases may **revert to Strategize** under specific conditions. In all cases, the reversion target is always Strategize — there is no reversion to Execute or any other intermediate phase.
-
-##### Execute → Strategize
-
-* **Trigger:** During execution, the execution actor discovers that constraints established during Strategize are too restrictive to complete the work. For example, a strategy decision may have mandated an approach that proves infeasible once actual resources are examined, dependencies are resolved, or implementation details are encountered.
-* **Behavior:** Rather than overriding or silently violating Strategize-phase decisions, the plan reverts to the Strategize phase so the strategy actor can adjust the decision tree. Execute-phase decisions must always be constrained by Strategize-phase decisions — if those constraints cannot be honored, the correct response is reversion, not violation.
-* **After reversion:** The strategy actor receives the execution actor's findings (the reason for reversion, the specific constraints that were too restrictive) and produces an updated decision tree. The plan then re-enters the Execute phase with the revised strategy.
-* **Automation:** Controlled by the `delete_content` automation profile flag.
-
-##### Apply → Strategize
-
-* **Trigger:** During the Apply phase, the system determines that the changeset cannot be successfully applied within the current strategy's constraints. Examples include: merge conflicts that violate invariants, validation failures at apply time that cannot be resolved within the strategy's scope, or resource state drift that contradicts strategy assumptions.
-* **Behavior:** The plan enters the `constrained` terminal state within the Apply phase. From this state, the plan may revert to Strategize either automatically (if the `access_network` automation profile flag allows it) or after manual user approval.
-* **After reversion:** The strategy actor receives the Apply phase's findings (the constraint violations, the specific issues encountered) and produces an updated decision tree. The plan then progresses forward again through Execute and Apply with the revised strategy.
-* **Automation:** Controlled by the `access_network` automation profile flag (separate from `delete_content`, which governs Execute → Strategize reversion).
-
-#### Plan States (Per Phase)
-
-A plan's ==phase== indicates "what step of the lifecycle it is in." Separately, the plan has a ==processing state== indicating "what is happening right now."
-
-=== "Action Phase"
-
- | State | Description |
- | :---- | :---------- |
- | `available` | Action exists and can be used |
- | `archived` | Soft-deleted or hidden (optional) |
-
-=== "Strategize / Execute Phases"
-
- | State | Terminal? | Description |
- | :---- | :-------: | :---------- |
- | `queued` | No | Waiting for compute/worker |
- | `processing` | No | Currently running |
- | `errored` | Yes | Failed; includes error metadata |
- | `complete` | Yes | Finished successfully |
- | `cancelled` | Yes | User/system cancelled; safe terminal |
-
-=== "Apply Phase"
-
- | State | Terminal? | Description |
- | :---- | :-------: | :---------- |
- | `queued` | No | Waiting for compute/worker |
- | `processing` | No | Currently running — diff review, conflict resolution, validation |
- | `errored` | Yes | Failed; includes error metadata |
- | `applied` | Yes | ==Changes successfully committed== to real resources |
- | `constrained` | Yes | Cannot complete within current strategy's constraints; may trigger reversion to Strategize |
- | `cancelled` | Yes | User/system cancelled; safe terminal |
-
-#### Plan Identity and Traceability
-
-Every plan should have:
-
-| Field | Type | Description |
-| :---- | :--- | :---------- |
-| `plan_id` | ULID | ==Unique, immutable== identifier |
-| `parent_plan_id` | ULID? | Nullable; present for child plans |
-| `root_plan_id` | ULID | The top-most plan in the tree |
-| `attempt` | Integer | Attempt counter (increments on phase re-run) |
-| `created_at` | Timestamp | When the plan was created |
-| `updated_at` | Timestamp | Last modification time |
-| `completed_at` | Timestamp? | When the plan reached a terminal state |
-| `created_by` | Identity | User or session identity |
-
-#### Plan Hierarchy and Parallelism
-
-!!! adr "Architecture Decision"
- Plan hierarchy, child plan spawning, and parallel execution are covered in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md).
-
-A single plan should usually represent the smallest "complete" unit of work (similar to what would fit in one git commit). However:
-
-* **Plans are hierarchical.** A child plan is simply a Plan with a parent — it follows the same lifecycle, has the same data model, and is functionally identical to a root plan except that it has a `parent_plan_id`.
-* **Decisions about child plans are made during Strategize** (as `subplan_spawn` decision types). Multiple child plans that should execute concurrently are grouped under a `subplan_parallel_spawn` decision.
-* **Child plans are actually spawned during Execute** (based on those decisions).
-* Child plans can run **in parallel** (via `subplan_parallel_spawn`) or **sequentially** (via individual `subplan_spawn` decisions). Without a `subplan_parallel_spawn` wrapper, each `subplan_spawn` decision results in sequential execution.
-* **Applicable invariants are enforced** during Strategize by adding `invariant_enforced` decisions to the tree, which constrain downstream decisions and child plans.
-* The parent plan is responsible for **merging results**.
-
-This is core to the long-term objective: tackling large tasks while only recomputing parts of the decision tree when corrected.
-
-##### Hierarchical Decomposition for Scale
-
-??? example "Example: Converting Firefox to Rust"
- When handling massive tasks, the system uses hierarchical decomposition. Each level spawns child plans (which are themselves full Plans with their own decision trees):
-
- **1. Root Plan** — High-level architectural decisions and invariants
-
- : - "Convert Firefox Renderer to Rust"
- - Invariant: "Maintain API compatibility with existing C++ callers"
- - Decision: "Start with leaf modules, work inward"
- - Context: Module dependency graph (2,847 modules)
-
- **2. Subsystem-Level Plans** — Major component decisions (`subplan_parallel_spawn`)
-
- : - "Phase 1: Convert utility libraries (no external deps)"
- - Each subsystem plan gets its own bounded context and inherits parent invariants
-
- **3. Module-Level Plans** — Individual module conversions
-
- : - "Convert string_utils module"
- - Context: Only the 47 functions and 12 dependent files
- - Decision: "Use Rust's String type"
-
- **4. File-Level Plans** — Specific file changes
-
- : - Actual code transformations
- - Minimal context needed
-
- !!! tip
- At each level, only the ==relevant context== is loaded. The persistent decision graph means we can always reconstruct why we're converting a particular module and what constraints apply from higher-level decisions.
-
-##### Child Plan Spawning Mechanism
-
-In the actor definition for the execution actor, tool nodes can directly invoke registered tools to trigger child plans. The `local/create-subplan` tool is independently registered and referenced by name in the actor graph node. During execution, `subplan_spawn` decisions are realized as actual child plans, and `subplan_parallel_spawn` groups trigger concurrent spawning of all enclosed child plans.
-
-
-# Example: Execution actor with subplan spawning capability.
-# The graph uses a tool node referencing a named registered tool.
-actors:
- code_executor:
- type: graph
- config:
- actor: anthropic/claude-3-opus
- skills:
- - local/plan-tools # Skill containing create_subplan for LLM tool-calling
- - local/file-ops
- routes:
- execute_workflow:
- nodes:
- - name: spawn_test_subplan
- type: tool
- tool: local/create-subplan # Named tool from Tool Registry
-
-
-The `local/create-subplan` tool is independently registered via its own YAML configuration file:
-
-
-# File: tools/create-subplan.yaml
-cleveragents:
- version: "3.0"
-
-tool:
- name: local/create-subplan
- description: "Spawn a subplan for a given action"
- source: custom
-
- input_schema:
- type: object
- properties:
- action: { type: string }
- target_files: { type: array, items: { type: string } }
- required: [action]
-
- capability:
- writes: true
- checkpointable: false
- side_effects: [spawn_subplan]
-
- code: |
- subplan = ctx.spawn_subplan(
- action=params["action"],
- target_files=params.get("target_files", [])
- )
- return {"subplan_id": subplan.id}
-
-
-The `local/plan-tools` skill references this tool (and others) by name:
-
-
-# File: skills/plan-tools.yaml
-skill:
- name: local/plan-tools
- description: "Tools for spawning and managing subplans"
- tools:
- - local/create-subplan
-
-
-##### Child Plan Execution Modes
-
-=== "Sequential"
-
- Individual `subplan_spawn` decisions without a `subplan_parallel_spawn` wrapper execute one after another. If one fails, subsequent child plans are ==not started==.
-
-=== "Parallel"
-
- Multiple `subplan_spawn` decisions grouped under a `subplan_parallel_spawn` decision execute ==concurrently==. If one fails, others can continue. The `subplan_parallel_spawn` decision acts as a container that signals the system to spawn all enclosed child plans simultaneously.
-
- Parallel execution is bounded by `SubplanConfig.max_parallel` (default: `5`, range: 1–50). This cap prevents runaway resource consumption when a large number of child plans are spawned simultaneously. The runtime uses a `ThreadPoolExecutor` with `min(max_parallel, len(subplans))` workers. The `SubplanConfig` model also controls `merge_strategy` (default: `git_three_way`), `fail_fast` (default: `false`), `timeout_per_subplan_seconds` (default: `null`), `retry_failed` (default: `true`), and `max_retries` (default: `2`).
-
-=== "Dependency-Ordered"
-
- When child plans have explicit dependencies on each other, the `DEPENDENCY_ORDERED` execution mode respects those dependencies while maximizing concurrency. The dependency graph is provided as a `dependency_graph: dict[str, list[str]]` mapping each `subplan_id` to the list of `subplan_ids` it depends on.
-
- The runtime performs a topological sort to determine execution order, then executes independent subplans (those whose dependencies are all satisfied) concurrently in "waves". Subsequent waves wait for the previous wave to complete. Circular dependencies are detected and raise a `ValueError`.
-
- This mode is useful when child plans produce artifacts that other child plans consume — for example, a code generation plan that must complete before a test plan can run.
-
-##### Child Plan Failure Handling
-
-!!! note "Failure Semantics"
- | Execution Mode | On Failure | Behavior |
- | :------------- | :--------- | :------- |
- | **Parallel** | One child fails | Other child plans ==continue== |
- | **Sequential** | One child fails | Subsequent child plans ==not started== |
- | **Dependency-Ordered** | One child fails | Dependent child plans ==not started==; independent plans ==continue== |
-
- !!! tip
- An "error" only occurs if an exception is thrown by the application (a bug). Plan failures (e.g., tests don't pass) are handled within the plan's logic, not as application errors.
-
-##### Child Plan Result Merging
-
-The way child plan results are merged depends on the resource type:
-
-* **Git-compatible resources** (source code, text files): Git-style merge
-* **Databases**: Transaction coordination or sequential application
-* **Other resources**: Pluggable merge strategies based on resource type
-* **Non-mergeable resources**: May require sequential execution only
-
-##### Selective Subtree Recomputation for Decision Correction
-
-When a decision in the decomposition tree is found to be incorrect, the system
-supports **selective subtree recomputation**: only the subtree rooted at the
-target node is re-evaluated, while sibling branches and ancestor nodes are
-preserved unchanged.
-
-This is implemented by `DecompositionService.recompute_subtree()`, which:
-
-1. Accepts a `node_id` identifying the root of the subtree to recompute and
- an `existing_result` (`DecompositionResult`) containing the current tree.
-2. Performs a breadth-first search over `children_ids` to collect all nodes
- in the subtree (the target node and all its descendants).
-3. Partitions the nodes into two groups:
- - **Recomputed nodes** — the target node and all its descendants.
- - **Preserved nodes** — all other nodes (siblings, ancestors, and unrelated
- branches).
-4. Returns a `DecisionCorrectionResult` with both groups, the configuration
- used, and diagnostic metrics (`recomputed_count`, `preserved_count`,
- `subtree_size`).
-
-**Acceptance criteria:**
-
-| # | Criterion | Behaviour |
-| :- | :-------- | :-------- |
-| 1 | Leaf recomputation | Only the target leaf is recomputed; all other nodes preserved |
-| 2 | Middle-node recomputation | Target node and all its descendants recomputed; ancestors and siblings preserved |
-| 3 | Root recomputation | All nodes recomputed; no nodes preserved |
-| 4 | Unknown node | `ValueError` raised when `node_id` is not found in the result |
-| 5 | Custom config | Caller-supplied `DecompositionConfig` is attached to the result |
-| 6 | Metrics | `recomputed_count`, `preserved_count`, and `subtree_size` always present |
-
-#### The Plan "Decision Tree" and Visualization
-
-!!! adr "Architecture Decision"
- The decision tree's dual structure (structural tree and influence DAG), versioning model, and historical reconstruction are defined in [ADR-034: Decision Tree Versioning and History](adr/ADR-034-decision-tree-versioning-and-history.md).
-
-CleverAgents records enough information to render:
-
-* an **ASCII tree** in the TUI, and
-* optionally a GUI tree via visualization tools (D3/Cytoscape) once the data exists.
-
-This implies each plan should persist:
-
-* decisions made,
-* the rationale (or at least the prompt/context snapshot that produced it),
-* dependencies ("this decision influenced these child plans").
-
-This is required for "correcting plans" (see Behavior section).
-
-##### Dual Structure: Structural Tree and Influence DAG
-
-A plan's decisions form two overlapping structures that serve different purposes:
-
-**Structural Tree** (`parent_decision_id`): Defines the hierarchical rendering order. Each decision has at most one parent. The `prompt_definition` decision is the root. This tree determines how `agents plan tree` renders the hierarchy.
-
-**Influence DAG** (`decision_dependencies` table): Captures which decisions constrained or influenced which other decisions. A single decision may be influenced by multiple upstream decisions. For example, an `implementation_choice` might be influenced by both a `strategy_choice` (which set the approach) and a `resource_selection` (which determined the files to modify).
-
-| Structure | Storage | Purpose | Used For |
-|---|---|---|---|
-| Structural tree | `parent_decision_id` column | Rendering, navigation, tree visualization | `agents plan tree`, `agents plan explain` |
-| Influence DAG | `decision_dependencies` table | Dependency tracking, impact analysis | `agents plan correct` (affected subtree computation) |
-
-A decision's parent in the structural tree may differ from its dependencies in the influence DAG. The tree answers "what is this decision nested under?"; the DAG answers "what decisions caused this one to exist?"
-
-##### Current Tree vs. Superseded Branches
-
-The **current tree** for a plan is the set of active, non-superseded decisions:
-
-
-SELECT * FROM decisions
-WHERE plan_id = :plan_id
- AND superseded_by IS NULL
-ORDER BY sequence_number;
-
-
-When a decision is corrected, the original and all its descendants are marked `superseded_by = `. **Superseded decisions are never deleted** — they remain in the database as permanent records, forming an append-only history. `agents plan tree --show-superseded` renders both current and historical branches, with superseded decisions displayed dimmed and annotated.
-
-##### Structural Invariants
-
-The current tree always satisfies:
-
-1. **Single root**: Exactly one `prompt_definition` decision with `parent_decision_id IS NULL`.
-2. **Reachability**: Every non-root decision is reachable from the root via `parent_decision_id` links.
-3. **Acyclicity**: No circular references in `parent_decision_id` chains.
-4. **Monotonic ordering**: `sequence_number` is monotonically increasing per plan. New decisions (including corrections) always receive higher sequence numbers than existing ones. Gaps in the current tree's sequence numbers indicate where superseded decisions once existed.
-
-#### Decision Data Model
-
-!!! adr "Architecture Decision"
- The decision data model, decision types, and decision tree semantics are defined in [ADR-007: Decision Tree and Correction](adr/ADR-007-decision-tree-and-correction.md).
-
-##### Relationship Between Plan Description and Decisions
-
-Each plan has a **description field** (inherited from the action's description, potentially with argument substitutions). This description acts as the **primary component of the prompt** fed to the strategy actor during the Strategize phase.
-
-**Decisions are choices that are NOT explicitly defined by the plan description.** They represent the gaps, ambiguities, or implementation details that must be resolved to execute the plan.
-
-For example:
-- **Plan description**: "Increase test coverage to 85%"
-- **Decisions that emerge**:
- - "Which modules should be prioritized?" (not specified in description)
- - "Should we use mocks or integration tests for the database layer?" (not specified)
- - "Should we refactor the auth module to make it more testable, or write tests around it as-is?" (not specified)
-
-##### Decision Making Based on Autonomy Level
-
-Who makes decisions depends on the plan's **automation profile**:
-
-| Profile Flag | Who Makes Decisions |
-|-------------|---------------------|
-| `edit_code = 1.0` (always manual) | User is prompted for each decision point during Strategize |
-| `edit_code = 0.0` (always automatic) | Strategy actor makes decisions autonomously, records reasoning |
-| `execute_command = 1.0` (always manual) | User is prompted for each decision point during Execute |
-| `execute_command = 0.0` (always automatic) | Execution actor makes decisions autonomously |
-
-Intermediate thresholds (e.g., `edit_code = 0.7`) cause the system to auto-decide only when the Semantic Escalation confidence score meets or exceeds the threshold; otherwise the user is prompted.
-
-When **automation allows automatic decisions**, the strategy actor uses its best judgment based on context, and records its reasoning in the decision's `rationale` field.
-
-When **user input is required**, the system pauses and prompts the user:
-
-
-Decision required: Which modules should be prioritized for test coverage?
-
-Options identified by the strategy actor:
- 1. auth module (currently 45% coverage, high risk)
- 2. payment module (currently 52% coverage, high risk)
- 3. user module (currently 71% coverage, medium risk)
-
-Your choice (or provide custom guidance): _
-
-
-##### The Prompt as the Root Decision
-
-**The prompt passed to the strategize actor is itself a decision node** in the decision tree—specifically, it's the **root decision** of type `prompt_definition`.
-
-This is important because:
-
-1. **Every plan has its own prompt**: The root plan's prompt comes from the action description + user arguments. Child plan prompts are created by parent plans during their execution.
-
-2. **Parent plans create child plan prompts**: When a parent plan spawns a child plan, it decides what prompt to give that child plan. This is recorded as a `prompt_definition` decision in the parent's tree, and becomes the root decision of the child plan's tree.
-
-3. **Invariants flow into the decision tree**: During Strategize, applicable invariants (from global, project, action, and plan scopes) are reconciled via the **Invariant Reconciliation Actor** and recorded as `invariant_enforced` decisions, making them explicit constraints that influence downstream decisions and child plans.
-
-4. **Unified correction mechanism**: Since the prompt, invariants, and all other decisions are part of the same tree, correcting any of them uses the same `agents plan correct` command.
-
-
-Plan: 01KH29QDEE6DZTXKWNKCV8VP0F
-├── [prompt_definition] "Increase test coverage to 85% for the whole project."
-├── [invariant_enforced] "Prioritize all functionality related to financial transactions and user management"
-├── [invariant_enforced] "All API calls over TCP must be mocked"
-├── [strategy_choice] "Prioritize auth and payment modules, implement them in parallel before the rest"
-├── [subplan_parallel_spawn] "Implement auth and payment modules, in parallel"
-│ ├── [subplan_spawn] "Write tests for auth module"
-│ │ └── Plan: 01KH29R8WPKPBHRY7Q0NA9XW86
-│ │ ├── [prompt_definition] "Write unit tests for auth module using mocks for the remote API calls"
-│ │ ├── [implementation_choice] "Test login flow first"
-│ │ └── ...
-│ └── [subplan_spawn] "Write tests for payment module"
-│ └── Plan: 01KH29RN2YKSXMTBDG82AKRHRA
-│ ├── [prompt_definition] "Write unit tests for payment module using"
-│ └── ...
-└── [subplan_parallel_spawn] "Write tests for all modules except the auth and payment modules"
- └── ...
-
-
-##### Correcting Decisions (Including Prompts)
-
-All corrections use the same unified command:
-
-
-agents plan correct <decision_id> --mode=<mode> --guidance "<corrected decision text>"
-
-
-**Parameters:**
-* ``: The ULID of the decision to correct
-* `--mode`: Either `revert` (rollback and re-run) or `append` (add fix at end)
-* `--guidance`: Free-form text specifying what the correct decision should be
-
-**Examples:**
-
-
-# Correct a strategy choice
-agents plan correct 01ARZ3NDEKTSV4RRFFQ69G5FAV --mode=revert \
- --guidance "Prioritize the payment module first, not auth, due to upcoming deadline"
-
-# Correct the root prompt to be more specific
-agents plan tree <plan_id>
-# Shows: [prompt_definition] id=01ARZ3NDEKTSV4RRFFQ69G5FAV "Increase test coverage to 85%"
-
-agents plan correct 01ARZ3NDEKTSV4RRFFQ69G5FAV --mode=revert \
- --guidance "Increase test coverage to 85%, prioritizing auth and payment modules. Use mocks for database tests, not integration tests."
-
-# Correct a subplan's prompt (originally created by parent plan)
-agents plan correct 01BRZ4PDFLUTW5SSGR70H6GBW --mode=revert \
- --guidance "Write unit tests for auth module, focusing on edge cases for token expiration"
-
-# Append a fix rather than rewriting history
-agents plan correct 01ARZ3NDEKTSV4RRFFQ69G5FAV --mode=append \
- --guidance "The previous approach missed error handling tests - add comprehensive error path coverage"
-
-# Remove an invariant that shouldn't apply
-agents plan correct 01CRZ5QEHMVUX6TTHR81I7HCX --mode=revert \
- --guidance "Remove this invariant - TCP mocking is not needed for this module since it has no network calls"
-
-# Add a missing invariant to the plan
-agents invariant add --plan 01HXM8C2ZK4Q7C2B3F2R4VYV6J "All database queries must use parameterized statements"
-
-
-**Note:** CLI commands should not require interactive input. The `--guidance` parameter provides the correction inline.
-
-**When to correct the prompt vs. a specific decision:**
-
-| Situation | Correction Approach |
-|-----------|---------------------|
-| Original request was too vague | Correct the `prompt_definition` decision |
-| Strategy actor made a bad choice on a specific question | Correct that specific decision |
-| Parent plan gave a child plan a bad prompt | Correct the child plan's `prompt_definition` |
-| An invariant should not apply to this plan | Correct (remove) the `invariant_enforced` decision |
-| A missing constraint should be added | Add a new `invariant_enforced` decision via `agents invariant add --plan` or correct the plan's strategy |
-| Sequential child plans should run in parallel | Correct the relevant decisions to use a `subplan_parallel_spawn` grouping |
-
-Because the prompt is part of the decision tree, the system automatically knows that correcting it invalidates all downstream decisions in that plan (and its child plans).
-
-**Decisions are created during both the Strategize and Execute phases.** The Strategize phase produces the initial decision tree — strategy choices, invariant enforcement, resource selections, and child plan blueprints. The Execute phase may create additional decisions constrained by those made during Strategize, reflecting discoveries and adjustments that arise during execution. If Execute finds that Strategize-phase constraints are too restrictive to proceed, the plan reverts to Strategize for adjustment (see *Phase Reversion* below). The decision tree captures what choices were made and why, enabling correction and replay.
-
-##### Decision Recording Protocol
-
-!!! adr "Architecture Decision"
- The decision recording protocol, tool-based recording mechanism, and context snapshot capture are defined in [ADR-033: Decision Recording Protocol](adr/ADR-033-decision-recording-protocol.md). Decision-aligned checkpointing during Execute is defined in [ADR-035: Decision Tree Rollback and Replay](adr/ADR-035-decision-tree-rollback-and-replay.md).
-
-Actors record decisions by calling a **built-in `record_decision` tool**. This tool is automatically included in every actor's skill set for plan-related invocations. Decision types are partitioned into three creation categories:
-
-| Category | Decision Types | Creator | Mechanism |
-|---|---|---|---|
-| **System-created** | `prompt_definition`, `user_intervention` | Plan lifecycle engine | Created automatically at plan instantiation (prompt) and when user provides guidance (intervention) |
-| **Reconciliation-actor-recorded** | `invariant_enforced` | Invariant Reconciliation Actor | The actor evaluates applicable invariants, resolves conflicts using precedence rules, and calls `record_decision` for each enforced invariant |
-| **Actor-recorded** | `strategy_choice`, `resource_selection`, `subplan_spawn`, `subplan_parallel_spawn`, `implementation_choice`, `tool_invocation`, `error_recovery`, `validation_response` | Strategy or Execution actor | Actor identifies a choice point and calls `record_decision` |
-
-The `record_decision` tool accepts the decision type, question, chosen option, alternatives considered, confidence score, and rationale. The system automatically captures the **context snapshot** at the moment of the call — the hot context hash, resource references, and a LangGraph checkpoint of the actor's complete state (`actor_state_ref`). This snapshot enables replay from the exact decision point during correction.
-
-**Strategize-phase recording loop**: The strategy actor's system prompt instructs it to identify ambiguities and choice points in the plan description. For each choice point, the actor gathers context, evaluates options, and calls `record_decision`. Each recorded decision becomes part of the actor's context for subsequent reasoning.
-
-
-# Pseudocode: Strategy actor decision recording loop
-while unresolved_ambiguities_remain(plan, context):
- choice_point = analyze_context_for_ambiguity(context)
- options = generate_and_evaluate_options(choice_point, context, invariants)
-
- # Record via tool call — system auto-captures context snapshot
- decision_id = record_decision(
- decision_type = choice_point.type,
- question = choice_point.question,
- chosen_option = best_option.description,
- alternatives_considered = [o.description for o in rejected_options],
- confidence_score = best_option.confidence,
- rationale = best_option.reasoning
- )
-
- context.add_decision(decision_id) # Decision informs subsequent reasoning
-
-
-**Execute-phase recording pattern**: The execution actor sees Strategize-phase decisions as read-only constraints. When it encounters a choice point not already resolved by the strategy (implementation detail, error handling, tool selection), it calls `record_decision`. Execute-phase decisions must be consistent with Strategize-phase constraints — if they cannot be, the plan reverts to Strategize rather than recording a contradictory decision.
-
-!!! warning "Execute-Phase Checkpoint Trigger"
- In the Execute phase, `record_decision` is treated as a **write operation** for checkpoint purposes. The system automatically creates a **coordinated checkpoint group** — one checkpoint per modified sandbox resource — at every Execute-phase decision point. This creates a 1:1 mapping between decisions and resource states, enabling fine-grained rollback to any Execute-phase decision (see *Correcting Plans* in the Behavior section).
-
-**Automation profile integration**: When `record_decision` is called, the system checks the confidence score against the applicable threshold (`edit_code` or `execute_command`). If confidence is below the threshold, execution pauses and the decision is presented to the user for approval or override.
-
-##### Decision Record Structure
-
-
-Decision:
- # Identity
- decision_id: ULID # Unique identifier
- plan_id: ULID # Parent plan this decision belongs to
- parent_decision_id: ULID | null # Parent decision (for tree structure)
- sequence_number: int # Order within the plan's decisions
-
- # Classification
- decision_type: enum
- - prompt_definition # The prompt/description for this plan (root decision)
- - invariant_enforced # An invariant (from global, project, action, or plan scope) applicable to this plan, added as a constraint
- - strategy_choice # High-level approach decision during Strategize
- - implementation_choice # How to implement a specific task
- - resource_selection # Which resources to read/modify
- - subplan_spawn # Decision to create a child plan (spawned later in Execute)
- - subplan_parallel_spawn # Decision to spawn a group of child plans in parallel (contains subplan_spawn children)
- - tool_invocation # Which skill/tool to use
- - error_recovery # How to handle a failure
- - validation_response # Response to validation failure
- - user_intervention # User provided guidance/correction
-
- # The Decision Itself
- question: str # What question was being answered
- chosen_option: str # What was decided
- alternatives_considered: list[str] # Other options that were evaluated
- confidence_score: float | null # 0.0-1.0 if the actor provided confidence
-
- # Context Snapshot (for replay)
- context_snapshot:
- hot_context_hash: str # Cryptographic hash of the exact context
- hot_context_ref: str # Pointer to the full stored snapshot
- relevant_resources: list[ResourceRef] # Every file/symbol that influenced this decision
- actor_state_ref: str # Complete LangGraph checkpoint
-
- # When the system decides "refactor the authentication module to use async patterns,"
- # it permanently records:
- # - Which files were examined to make that decision
- # - What symbols and dependencies were traced
- # - The exact code state that was analyzed
- # - The reasoning chain that led to this choice
- # - Alternative approaches that were considered but rejected
-
- # Rationale
- rationale: str # Why this option was chosen
- actor_reasoning: str | null # Raw LLM reasoning if available
-
- # Downstream Impact (populated during Execute phase)
- downstream_decision_ids: list[ULID] # Decisions that depend on this one
- downstream_plan_ids: list[ULID] # Child plans spawned because of this decision
- artifacts_produced: list[ArtifactRef] # Files/outputs created under this decision
-
- # Timestamps
- created_at: datetime
-
- # Correction Metadata
- is_correction: bool # Was this decision a correction of another?
- corrects_decision_id: ULID | null # If correction, which decision was replaced
- correction_reason: str | null # Why the correction was made
- superseded_by: ULID | null # If this decision was later corrected
-
-
-##### Decision Timing
-
-| Phase | Decision Activity |
-|-------|-------------------|
-| **Strategize** | Initial decisions are **created**, including `invariant_enforced` decisions for applicable invariants, `strategy_choice` decisions, `subplan_spawn` decisions, and `subplan_parallel_spawn` decisions grouping parallel child plans. `downstream_plan_ids` is empty. The system aims to make reasonable, comprehensive decisions at this stage to guide execution. |
-| **Execute** | Child plans are **spawned** and `downstream_plan_ids` is **populated** based on `subplan_spawn` decisions. **Additional decisions may be created** during execution — these are constrained by Strategize-phase decisions and arise from discoveries made during execution (e.g., `implementation_choice`, `resource_selection`, `tool_invocation`, `error_recovery`). If Execute determines that Strategize-phase constraints are too restrictive, the plan **reverts to Strategize** for adjustment rather than overriding those constraints. |
-| **Apply** | No new decisions. History can be flagged for cleanup after successful apply. |
-
-##### Decision Tree Storage Schema
-
-
--- Core decision table
-CREATE TABLE decisions (
- decision_id TEXT PRIMARY KEY, -- ULID
- plan_id TEXT NOT NULL,
- parent_decision_id TEXT,
- sequence_number INTEGER NOT NULL,
- decision_type TEXT NOT NULL, -- prompt_definition, invariant_enforced, strategy_choice,
- -- implementation_choice, resource_selection, subplan_spawn,
- -- subplan_parallel_spawn, tool_invocation, error_recovery,
- -- validation_response, user_intervention
- question TEXT,
- chosen_option TEXT NOT NULL,
- alternatives_considered TEXT, -- JSON array
- confidence_score REAL,
- rationale TEXT,
- actor_reasoning TEXT,
- context_snapshot TEXT NOT NULL, -- JSON blob
- is_correction BOOLEAN DEFAULT FALSE,
- corrects_decision_id TEXT,
- correction_reason TEXT,
- superseded_by TEXT,
- created_at TEXT NOT NULL,
-
- FOREIGN KEY (plan_id) REFERENCES plans(plan_id),
- FOREIGN KEY (parent_decision_id) REFERENCES decisions(decision_id),
- FOREIGN KEY (corrects_decision_id) REFERENCES decisions(decision_id),
- FOREIGN KEY (superseded_by) REFERENCES decisions(decision_id)
-);
-
--- Downstream relationships (many-to-many for DAG)
-CREATE TABLE decision_dependencies (
- upstream_decision_id TEXT NOT NULL,
- downstream_decision_id TEXT NOT NULL,
- dependency_type TEXT NOT NULL, -- 'decision', 'plan', 'artifact'
- downstream_ref TEXT NOT NULL, -- The actual ID of decision/plan/artifact
-
- PRIMARY KEY (upstream_decision_id, downstream_decision_id, downstream_ref),
- FOREIGN KEY (upstream_decision_id) REFERENCES decisions(decision_id)
-);
-
--- Correction history
-CREATE TABLE correction_attempts (
- attempt_id TEXT PRIMARY KEY, -- ULID
- plan_id TEXT NOT NULL,
- original_decision_id TEXT NOT NULL,
- new_decision_id TEXT,
- original_subtree_snapshot TEXT, -- Reference to archived state
- correction_reason TEXT,
- status TEXT NOT NULL, -- 'pending', 'executing', 'completed', 'failed'
- created_at TEXT NOT NULL,
- completed_at TEXT,
-
- FOREIGN KEY (plan_id) REFERENCES plans(plan_id),
- FOREIGN KEY (original_decision_id) REFERENCES decisions(decision_id),
- FOREIGN KEY (new_decision_id) REFERENCES decisions(decision_id)
-);
-
-
-### Action
-
-!!! adr "Architecture Decision"
- Actions as reusable plan templates and the action-to-plan transition are defined in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md).
-
-#### What an Action Is
-
-An **action** is a reusable plan template that is not associated with any projects yet.
-
-**Actions are created via CLI commands with a required `--config` YAML file** that fully defines the action. Any CLI options supplied alongside the config file act as optional overrides for values in the YAML.
-
-Examples:
-
-* "Increase test coverage to 80%"
-* "Refactor module X to be async-safe"
-* "Write an RFC for feature Y"
-* "Provision an infra cluster and validate access" (non-code)
-
-Actions are **intentionally project-agnostic** so they can be reused across projects.
-
-An action is the first stage of a plan — before it is used. Because of this, **invariants can be attached to actions**. When an action is used (via `agents plan use`), any invariants attached to the action are carried forward as plan-level invariants on the resulting plan. This allows teams to bake constraints directly into reusable templates. Invariants can also be added to a plan after the action is used, via `agents invariant add --plan` or `--invariant` flags on `agents plan use`.
-
-#### Action Creation (CLI)
-
-Actions are created using the CLI. The action is fully defined by the YAML configuration file:
-
-
-agents action create --config ./actions/code-coverage.yaml
-
-
-The YAML file provides the complete action definition, including the name, strategy-actor, execution-actor, definition-of-done, arguments, invariants, and all other properties.
-
-**Required parameters:**
-* `--config`: YAML configuration file that fully defines the action (name, strategy-actor, execution-actor, definition-of-done, etc.)
-
-Arguments defined in the YAML's `args` section are values that will be:
-* Injected into the description and/or definition of done (via templating)
-* Passed into the context of the actors
-* Required when using the action on projects
-
-#### Action Data Model (Expanded)
-
-A plan in the Action phase has:
-
-##### 1) `name` (namespaced)
-
-Format:
-
-* `[server:][namespace/]`
-
-Rules:
-
-* If server is omitted, default server is assumed unless namespace is `local`.
-* If namespace is omitted, default is `local`.
-* Names should be stable identifiers (kebab-case recommended).
-
-Examples:
-
-* `local/code-coverage`
-* `myusername/code-coverage`
-* `myorgname/code-coverage`
-* `prod:myorgname/code-coverage` (server-qualified)
-
-##### 2) `short_description`
-
-Optional at creation; auto-filled if blank.
-
-##### 3) `long_description`
-
-Optional but recommended for reusable actions.
-
-##### 4) `definition_of_done` (DoD)
-
-Required. Must be explicit and testable.
-
-##### 5) `actors`
-
-Two actors minimum, two optional:
-
-* **strategy_actor** (planner/architect) — required
-* **execution_actor** (builder/implementer) — required
-* **estimation_actor** (cost/risk estimator) — optional
-* **invariant_actor** (Invariant Reconciliation Actor) — optional; resolves invariant conflicts when the plan enters Strategize. Lookup falls back to project, then global config.
-
-Actors can be:
-
-* an LLM agent (built-in),
-* a graph (custom yaml, or built-in),
-
-Note: graphs are hierarchical allowing them to reference other actors as nodes.
-
-Actor abstraction is central: an actor may be a single agent or an entire graph.
-
-##### 6) `reusable` (boolean)
-
-* Default: `true`.
-* If `true`: using the action creates a *new* plan in Strategize while leaving the action available.
-* If `false`: action self-deletes (or auto-archives) after first use.
-
-##### 7) `read_only` (boolean)
-
-* Default: `false`.
-* If `true`: the plan must only use read-only tools (tools with `read_only: true` in their capability metadata) and must never modify resources (even in sandbox).
-* Read-only actions are still useful for "investigation reports," architecture reviews, or dry-run planning.
-
-##### 8) `inputs_schema` (recommended addition)
-
-To make actions genuinely reusable, actions should declare their inputs:
-
-* required args (e.g., target coverage percent),
-* optional args (e.g., test framework),
-* validation rules (types, bounds).
-
-Example:
-
-* `target_coverage_percent`: integer 0–100
-
-##### 9) `automation_profile`
-
-The resolved automation profile name for this plan (e.g., `trusted`, `auto`, `local/careful-auto`). Determined at `plan use` time using the profile precedence rules (plan > action > project > global). Once set, it is locked to the plan.
-
-### Strategy (Strategize Phase)
-
-!!! adr "Architecture Decision"
- The Strategize phase, strategy actors, and decision generation are defined in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md).
-
-#### Using an Action (Transition to Strategize)
-
-The `use` command transitions an Action into the Strategize phase by applying it to one or more projects:
-
-
-# Basic usage
-agents plan use local/code-coverage my-api-service
-
-# Multiple projects
-agents plan use local/schema-update \
- api-service \
- web-frontend \
- mobile-app
-
-# With action arguments
-agents plan use local/code-coverage \
- my-api-service \
- --arg target_coverage_percent=85 \
- --arg test_framework=pytest
-
-# With explicit automation profile
-agents plan use local/deploy-action \
- staging-env \
- --automation-profile manual
-
-# With invariants attached at use time
-agents plan use local/code-coverage \
- my-api-service \
- --arg target_coverage_percent=85 \
- --invariant "All API calls over TCP must be mocked" \
- --invariant "Do not modify the payments module"
-
-
-**Parameters:**
-* ``: Project to apply the action to (positional, can be repeated for multi-project plans)
-* `--arg`: Action argument values (format: `name=value`)
-* `--automation-profile`: Override automation profile for this plan
-* `--invariant`: Invariant to attach to the created plan (can be repeated). These are added as plan-level invariants in addition to any inherited from the action, project, or global scope.
-
-When the action is used:
-1. A new plan is created with a unique ULID
-2. The plan's automation profile is resolved (plan > action > project > global precedence)
-3. Any invariants from the action are carried forward as plan-level invariants, combined with any `--invariant` flags provided
-4. The plan enters the **Strategize** phase
-5. The **Invariant Reconciliation Actor** computes the effective invariant view (resolving conflicts using plan > action > project > global precedence)
-6. The `strategy_actor` begins analyzing the project(s)
-
-#### What Strategize Does
-
-When an action is **used** on projects, it becomes a **plan in Strategize**.
-
-Strategize is:
-
-* **read-only**, producing a plan of attack,
-* responsible for gathering context from project resources,
-* responsible for collecting applicable invariants (from global, project, action, and plan scopes), computing the effective invariant view via the **Invariant Reconciliation Actor** (applying plan > action > project > global precedence), and recording them as `invariant_enforced` decisions,
-* responsible for generating a strategy and child plan blueprint (using `subplan_spawn` and `subplan_parallel_spawn` decisions),
-* not allowed to execute child plans or modify resources.
-
-This "architect vs coder" separation is explicitly described as a core motivation.
-
-**Resource-aware dependency analysis**:
-During the Strategize phase, the strategy actor employs specialized mechanisms to compute precise dependency closures:
-
-
-# Pseudocode of what happens inside a strategy actor
-def compute_closure_for_refactoring(target_module):
- closure = ResourceClosure()
-
- # Direct file dependencies
- closure.add_files(find_imports(target_module))
- closure.add_files(find_includes(target_module))
-
- # Symbol dependencies
- for symbol in extract_exported_symbols(target_module):
- closure.add_files(find_symbol_usage(symbol, scope='project'))
-
- # Test dependencies
- closure.add_files(find_tests_for_module(target_module))
-
- # Build system dependencies
- closure.add_files(find_build_references(target_module))
-
- return closure
-
-
-The system leverages several key insights:
-- **Modular boundaries exist**: Even in legacy codebases, there are natural boundaries
-- **Changes are incremental**: We don't convert 50,000 files atomically
-- **Dependencies are sparse**: Most modules depend on a small fraction of the codebase
-- **Interfaces are narrow**: Public APIs are much smaller than implementations
-
-#### Strategize Data Model
-
-A plan in Strategize contains all Action fields plus:
-
-##### 1) `projects`
-
-A list of projects the plan is used on.
-
-Important: A strategy plan may target **multiple projects**. Multi-project work in one "window" is considered a major usability advantage over tools that require being run from a single directory.
-
-##### 2) `strategy_context`
-
-A structured object describing:
-
-* what resources were considered,
-* how they were retrieved,
-* what filtering/limits were applied,
-* what the actor saw.
-
-This matters because a plan must be debuggable and correctable later.
-
-Recommended fields:
-
-* `resource_refs`: IDs of resources used
-* `queries`: search queries performed
-* `selected_chunks`: chunk IDs + sources + reasons
-* `constraints`: context window limits, file ignore patterns
-* `generated_summaries`: if summarization occurred
-
-##### 3) `strategy`
-
-The output plan:
-
-* steps (ordered and/or DAG),
-* conditions/branches ("if tests fail, do X"),
-* child plans to spawn (including which action templates to use, and whether they should run in parallel via `subplan_parallel_spawn`),
-* evaluation criteria (how to know success),
-* risk assessment.
-
-##### 4) `execution_blueprint` (recommended addition)
-
-Strategize should output not only narrative text but also a machine-usable blueprint:
-
-* list of tasks,
-* required skills,
-* expected outputs,
-* dependencies between tasks.
-
-This blueprint becomes the input to Execute.
-
-##### 5) `cost_estimate` and `risk_estimate` (optional)
-
-**Cost and risk estimation is optional** but recommended for production use.
-
-When enabled, a specialized **estimation actor** analyzes:
-
-* The initial prompt/request
-* The strategy produced by the Strategize phase
-* Historical data from similar plans (if available)
-
-And produces estimates for:
-
-* LLM tokens/cost range
-* Number of steps/child plans expected
-* Expected risk of rollbacks
-* Estimated execution time
-
-**Implementation**: Similar to how there's a `strategy_actor` and `execution_actor` for each action, there can be an optional `estimation_actor` whose entire job is cost/risk estimation. This actor runs after Strategize completes (before Execute) and its output is informational only. Estimation failures are logged but never block the Execute transition.
-
-**Estimation actor resolution** follows a 4-level fallback chain (highest priority first):
-
-1. CLI `--estimation-actor` override (applied post-creation by the CLI layer)
-2. Action YAML `estimation_actor` field
-3. *(project-scoped key — reserved for future use)*
-4. `actor.default.estimation` global config key (`CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR`)
-
-When the resolved actor is set, `PlanLifecycleService.complete_strategize()` invokes `_run_estimation()` and emits a `PLAN_ESTIMATION_COMPLETE` event on success. The result is stored on the plan and `plan.cost_estimate_usd` is populated from the midpoint of the estimated cost range.
-
-
-# Example: Action with estimation actor (defined in the YAML config file)
-agents action create --config ./actions/expensive-refactor.yaml
-
-
-This becomes critical in server/multi-user usage and cost controls.
-
-### Execution (Execute Phase)
-
-!!! adr "Architecture Decision"
- The Execute phase, sandbox model, and execution safety mechanisms are defined in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md) and [ADR-015: Sandbox and Checkpoint](adr/ADR-015-sandbox-and-checkpoint.md).
-
-#### What Execute Does
-
-Execute is where the plan actually performs work, but **in a sandboxed environment** that can later be reviewed and applied.
-
-Key properties:
-
-1. **Work happens in a sandbox**
- All file modifications, generated artifacts, and intermediate outputs live in an isolated "execution workspace" until Apply.
-
-2. **Execute may spawn child plans**
- Child plan spawning is a first-class behavior of Execute: a parent plan can distribute work to child plans (sequentially via `subplan_spawn` or concurrently via `subplan_parallel_spawn`) and merge results.
-
-3. **Execute must support checkpointing / rollback (when enabled)**
- Checkpointable tools allow rolling back to a checkpoint ID to recover from partial failure or wrong turns.
-
-4. **Execute produces a "reviewable diff"**
- Diff review sandbox is described as a differentiating feature: users can inspect changes before applying.
-
-#### Execution Workspace / Sandbox Model (Detailed)
-
-!!! adr "Architecture Decision"
- Sandbox isolation, lazy sandboxing, and resource-type-specific sandbox strategies are detailed in [ADR-015: Sandbox and Checkpoint](adr/ADR-015-sandbox-and-checkpoint.md).
-
-A sandbox isolates plan execution from the real project resources until Apply.
-
-!!! tip "Key Sandbox Principles"
- - [x] **Lazy Sandboxing** — Resources are sandboxed ==only when accessed==, not upfront
- - [x] **Per-Plan Sandboxes** — Each plan and child plan has its own isolated sandbox
- - [x] **Resource-Defined Strategy** — The sandbox strategy is defined on each **resource**, not globally
- - [x] **Cleanup Behavior** — Automatic cleanup on exit, crash recovery on next run, retention-based archival
-
-??? info "Why Lazy Sandboxing?"
- A project may have many resources (git repo + 10 databases + cloud accounts), but a plan may only modify one resource. Only accessed resources are sandboxed, making this efficient for large projects with many linked resources.
-
-##### Sandbox Implementation Strategies
-
-Different resource types require different sandbox strategies:
-
-| Resource Type | Strategy | Rollback Mechanism |
-|--------------|----------|-------------------|
-| `git-checkout` | `git_worktree` | Git reset/checkout |
-| `git` | `none` | N/A (represents a repo instance — not directly sandboxable) |
-| `fs-mount` | `copy_on_write` or `overlay` | Restore from snapshot |
-| `fs-directory` | `copy_on_write` | Restore from snapshot |
-| Custom database types | `transaction_rollback` | Transaction rollback |
-| Custom API types | `none` | Often not sandboxable |
-
-**1. Git worktree / branch sandbox (preferred for code)**
-
-* Create a worktree or temporary branch
-* All modifications are commits or staged changes
-* Apply merges/cherry-picks
-
-Pros: natural rollback, diff support, efficient
-Cons: requires git
-
-**2. Filesystem copy sandbox**
-
-* Copy project directory to a sandbox directory
-* Execute modifies sandbox copy
-* Apply syncs diff back
-
-Pros: simple
-Cons: expensive for huge repos
-
-**3. Overlay filesystem sandbox**
-
-* Use overlayfs-style "copy-on-write" to avoid full copies
-
-Pros: efficient
-Cons: more complex, OS-dependent
-
-**4. Transaction-based sandbox (for databases)**
-
-* Begin transaction at sandbox creation
-* All operations within transaction
-* Rollback on failure, commit on apply
-
-Pros: native to databases
-Cons: long-running transactions can cause issues
-
-**5. No sandbox (for non-sandboxable resources)**
-
-* Some resources cannot be sandboxed (certain APIs, cloud services)
-* User proceeds at their own risk
-* Plan should warn about non-sandboxable resources
-
-##### Multi-Resource Sandboxing
-
-When a plan accesses multiple resources:
-
-* Each resource gets its own sandbox (based on its defined strategy)
-* Sandboxes are independent
-* Apply commits each sandbox separately
-* If any sandbox Apply fails, others may still succeed (partial apply)
-
-**Complete isolation during execution prevents compound errors**:
-Each plan executes in its own sandbox, which means:
-
-Plan A (refactoring auth module):
-- Sandbox A1: Contains only auth/*.cpp, auth_tests/*.cpp
-- Cannot see Plan B's intermediate states
-- Cannot accidentally depend on Plan B's half-done work
-
-Plan B (updating API endpoints):
-- Sandbox B1: Contains only api/*.cpp, api_tests/*.cpp
-- Makes changes assuming current auth interface
-- Protected from Plan A's intermediate refactoring
-
-
-**Hierarchical merge resolution**:
-When child plans complete, the parent plan performs intelligent merging:
-
-def merge_subplan_results(subplan_results):
- # Group by resource type
- by_resource = group_by_resource_type(subplan_results)
-
- # Apply resource-specific merge strategies
- for resource_type, changes in by_resource:
- if resource_type == 'git-checkout':
- merge_git_changes(changes) # Three-way merge
- elif resource_type == 'fs-mount':
- merge_fs_changes(changes) # Copy-on-write reconciliation
- elif resource_type.startswith('database'):
- merge_db_changes(changes) # Sequential application
-
- # Validate merged state
- run_integration_tests()
-
-
-#### Execution Data Model
-
-A plan in Execute contains:
-
-##### 1) `execution_context`
-
-The context used for execution (often smaller/more tactical than strategy context).
-
-##### 2) `execution_log`
-
-Structured timeline of:
-
-* tool calls (with parent skill noted),
-* actor calls,
-* outputs,
-* errors and retries,
-* checkpoints created.
-
-This log is essential for debugging.
-
-##### 3) `artifacts`
-
-Outputs produced:
-
-* changed files,
-* generated files,
-* reports,
-* diagrams,
-* test outputs,
-* diffs.
-
-##### 4) `sandbox_ref`
-
-Pointer to the sandbox location/state:
-
-* path, branch name, workspace ID, container ID, etc.
-
-##### 5) `checkpoint_graph` (if enabled)
-
-A record of checkpoints:
-
-* checkpoint ID
-* timestamp
-* tool responsible (and its parent skill)
-* resources affected
-* rollback instructions / metadata
-
-#### Checkpointing in Execute (Core Safety Mechanism)
-
-!!! adr "Architecture Decision"
- Checkpointing, rollback, and transaction safety are defined in [ADR-015: Sandbox and Checkpoint](adr/ADR-015-sandbox-and-checkpoint.md).
-
-The intended user-level behavior is:
-
-* "Give me a checkpoint ID."
-* Perform additional operations.
-* "Roll back to checkpoint X."
-
-Not all tools can support this; checkpointing must be declared per tool (in its capability metadata).
-
-##### Tool-level checkpointability
-
-Each tool declares (via its capability metadata):
-
-* `checkpointable: true|false`
-* `checkpoint_scope`: what granularity of rollback is supported (file, transaction, commit, snapshot)
-* `rollback_mechanism`: how rollback occurs
-
-Examples:
-
-* File tools (from a file-ops skill): snapshot file states pre-modification
-* Git tools (from a git-ops skill): create commit or stash; rollback is reset/checkout
-* Shell/CLI tools (running inside a container): rollback by restoring filesystem snapshot or reloading base image state
-
-It should be noted that checkpointing is easier when tool scope is constrained (e.g., "only files within a docker image + git").
-
-##### Plan-level rollback policy
-
-Plans should have an option:
-
-* `rollback_enabled: true|false`
-
-If disabled, the plan may use more generic/unsafe tools with fewer restrictions (useful for low-stakes tasks).
-
-##### CheckpointService Operations
-
-The `CheckpointService` provides the following key operations for checkpoint lifecycle management:
-
-- **`create_checkpoint(plan_id, sandbox_ref, reason, source_tool, phase, decision_id, checkpoint_type, size_bytes)`** — Creates a standard checkpoint record. The `sandbox_ref` is a git commit hash of the current HEAD.
-
-- **`create_workspace_snapshot(plan_id, sandbox_ref, decision_id, *, reason, phase)`** — Creates a diff-based workspace snapshot before decision execution. Captures only files that differ from the previous checkpoint (or the initial sandbox state when no prior checkpoints exist). The diff manifest is stored in checkpoint metadata under `"diff_paths"`, `"diff_based"`, and `"diff_hash"` keys. Returns the new `Checkpoint`.
-
-- **`selective_rollback(plan_id, checkpoint_id)`** — Rolls back to a specific checkpoint with atomic (all-or-nothing) semantics. If the rollback fails partway through, a best-effort recovery attempt restores the sandbox to its pre-rollback HEAD. Raises `BusinessRuleViolation` if recovery also fails. Raises `ResourceNotFoundError` if the checkpoint does not exist.
-
-- **`archive_artifacts(sandbox_path, artifact_paths, archive_dir)`** — Physically moves artifact files to an archive directory, preserving them outside the sandbox for later retrieval.
-
-The service supports both database-backed persistence (via `CheckpointRepository`) and in-memory fallback for tests. Guard checks (whether a plan has been applied, whether a sandbox exists) are resolved via `PlanLifecycleService` when wired, querying persistent plan state rather than relying on in-memory flags.
-
-##### Automatic Checkpoint Triggers
-
-The execution engine supports four automatic checkpoint triggers, configurable via `core.checkpoints.auto_create_on` (default: all four enabled):
-
-| Trigger | When | Component |
-|---------|------|-----------|
-| `on_tool_write` | Before each write-tool execution | `ToolRunner` |
-| `on_tool_write_complete` | After each write-tool execution | `ToolRunner` |
-| `on_subplan_spawn` | Before first subplan execution attempt | `SubplanExecutionService` |
-| `on_error` | When the Execute phase fails | `PlanExecutor` |
-
-Configuration:
-
-```toml
-[core.checkpoints]
-auto_create_on = ["on_tool_write", "on_tool_write_complete", "on_subplan_spawn", "on_error"]
-```
-
-To disable a specific trigger, remove it from the list. To disable all automatic checkpoints, set the list to empty (`auto_create_on = []`).
-
-The `CheckpointService` is injected as an optional parameter into `ToolRunner`, `SubplanExecutionService`, and `PlanExecutor`. When `checkpoint_service` is `None`, all automatic checkpointing is skipped (backward-compatible no-op).
-
-#### Execution as Transactions (Recommended)
-
-Execution should be treated like a transactional pipeline:
-
-* Each step either:
-
- * commits a checkpoint on success, or
- * rolls back to the previous checkpoint on failure.
-
-This is explicitly motivated by "partial failure leaves codebase inconsistent" and the need for transaction rollback.
-
-#### Execution Environment Routing
-
-!!! adr "Architecture Decision"
- Execution environment routing, devcontainer integration, and the 6-level precedence chain are defined in [ADR-043: Devcontainer Integration](adr/ADR-043-devcontainer-integration.md). Container resource types are defined in [ADR-039: Container Resource Types](adr/ADR-039-container-resource-types.md).
-
-When a plan enters the **Execute** phase, the runtime must determine _where_ each tool invocation runs: on the host, or inside a container. This decision is called **execution environment routing**. The router evaluates a 6-level precedence chain and selects the first matching environment.
-
-**Precedence Chain (highest → lowest):**
-
-| Priority | Source | Condition |
-| :------: | :----- | :-------- |
-| 1 | Plan-level `execution_environment` with `priority: override` | Always wins when set. Configured via `agents plan use --execution-environment … --execution-env-priority override`. |
-| 2 | Project-level `execution_environment` with `priority: override` | Wins unless a plan-level override exists. Configured via `agents project context set --execution-environment … --execution-env-priority override`. |
-| 3 | Nearest-ancestor devcontainer | Auto-detected `devcontainer-instance` resource that is a child (or descendant) of a resource linked to the project. Lazy-built on first access. |
-| 4 | Plan-level `execution_environment` with `priority: fallback` | Used only when no devcontainer is detected and no override exists above. |
-| 5 | Project-level `execution_environment` with `priority: fallback` | Used only when no closer-scoped environment exists. |
-| 6 | Host | The local operating system. Default when no container environment is configured or detected. |
-
-**Routing Algorithm:**
-
-```
-function resolve_execution_environment(plan, project):
- # Level 1: plan override
- if plan.execution_environment AND plan.execution_env_priority == "override":
- return plan.execution_environment
-
- # Level 2: project override
- if project.execution_environment AND project.execution_env_priority == "override":
- return project.execution_environment
-
- # Level 3: nearest-ancestor devcontainer
- for resource in project.linked_resources (ordered by DAG depth, shallowest first):
- devcontainer = find_child_of_type(resource, "devcontainer-instance")
- if devcontainer:
- if devcontainer.state == "detected":
- build_and_start(devcontainer) # lazy activation
- return devcontainer
-
- # Level 4: plan fallback
- if plan.execution_environment AND plan.execution_env_priority == "fallback":
- return plan.execution_environment
-
- # Level 5: project fallback
- if project.execution_environment AND project.execution_env_priority == "fallback":
- return project.execution_environment
-
- # Level 6: host
- return HOST_ENVIRONMENT
-```
-
-**Tool-Level Environment Preferences:**
-
-Individual tools may declare environment preferences via the `environment` field in their capability metadata (see §Tool Capability Metadata):
-
-- `environment.required`: Tool _must_ run in this environment type (`container` or `host`). If the resolved environment doesn't match, the tool invocation fails with an error rather than silently running in the wrong environment.
-- `environment.preferred`: Tool _prefers_ this environment type but will run wherever the router places it.
-- `environment.specific`: Tool targets a specific named resource (e.g., `local/api-dev`). If the named resource is available and running, the tool is routed there regardless of the general precedence chain.
-
-When a tool declares `environment.required: container` but the router resolves to `host`, the runtime MUST raise an error. The operator can then either: (a) add a container resource to the project, or (b) change the tool's environment requirement.
-
-**Lazy Activation:**
-
-Devcontainers detected during auto-discovery are created in `detected (not built)` state. They are built and started _only_ when the execution environment router first selects them. This avoids unnecessary container builds when the user never executes a plan that needs container isolation. Once built, the container remains available for subsequent plan executions until explicitly stopped or the resource is removed.
-
-#### Tool-Based Resource Modification (Modern Architecture)
-
-!!! adr "Architecture Decision"
- The tool-based resource modification approach and tool execution model are defined in [ADR-011: Tool System](adr/ADR-011-tool-system.md).
-
-**IMPORTANT: CleverAgents does NOT parse LLM output to extract code.** Instead, it uses the modern tool-based approach pioneered by Claude Code, Cursor, and Aider where:
-
-1. **LLMs call tools directly** (`edit_file()`, `write_file()`, `delete_file()`, etc.) — tools provided by referenced skills
-2. **Tools operate on the sandbox** - each tool invocation modifies sandbox state directly
-3. **ChangeSet is built from tool invocations** - not by parsing LLM text output
-4. **Validation runs on sandbox state** - after tools execute, not on parsed output
-
-This architecture provides:
-
-* **Atomic operations**: Each tool call is a discrete, trackable change
-* **No parsing ambiguity**: Tools have structured parameters (path, content, etc.)
-* **Resource-agnostic**: Same pattern works for files, databases, APIs, any resource type
-* **Safety by design**: Tools run in sandbox with defined capabilities and restrictions
-* **MCP compatibility**: Tools from MCP-based skills map directly to MCP tools for external integrations
-
-##### How It Works
-
-```kroki-mermaid
-sequenceDiagram
- participant LLM as LLM Agent
- participant Router as Tool Router
- participant Sandbox as Sandbox
- participant CS as ChangeSet
- participant Val as Validator
-
- LLM->>Router: Tool call (with parameters)
- Router->>Router: Validate parameters
- Router->>Router: Enforce capability restrictions
- Router->>Sandbox: Execute tool in sandbox
- Sandbox->>Sandbox: Operate on sandboxed state
- Sandbox->>Sandbox: Record invocation
- Sandbox->>Sandbox: Create checkpoint (if needed)
- Sandbox->>CS: Emit Change record
- CS->>CS: Accumulate into ChangeSet
- CS->>Val: Submit for validation
- Val->>Val: Run validators on sandbox state
- Val->>Val: Generate diff from ChangeSet
- Val-->>LLM: Present for review before Apply
-```
-
-##### Built-in Resource Tools
-
-CleverAgents provides these core tools (via built-in skills) for resource manipulation:
-
-| Tool | Description | Creates Change? |
-|-------|-------------|-----------------|
-| `read_file(path)` | Read file contents | No |
-| `write_file(path, content)` | Create/overwrite file | Yes |
-| `edit_file(path, changes)` | Apply targeted edits | Yes |
-| `delete_file(path)` | Remove file | Yes |
-| `move_file(src, dst)` | Rename/move file | Yes |
-| `create_directory(path)` | Create directory | Yes |
-| `list_files(pattern)` | List files matching glob | No |
-| `search_files(pattern, content)` | Search file contents | No |
-| `get_file_info(path)` | Get file metadata | No |
-
-Each built-in tool automatically:
-* Operates within sandbox boundaries
-* Records changes to the ChangeSet
-* Validates parameters against project configuration
-* Enforces deny-list patterns (`.git/`, `node_modules/`, etc.)
-
-##### Why Not Parse LLM Output?
-
-The obsolete approach of parsing markdown code fences has fundamental problems:
-
-1. **Ambiguity**: Is text explanation or code? Where does one file end and another begin?
-2. **Fragility**: Models output varying formats; regex parsing is brittle
-3. **Loss of semantics**: You lose the intent (create vs modify vs delete)
-4. **No atomicity**: Can't rollback individual operations
-5. **Resource-limited**: Only works for files, not databases or other resources
-
-The tool-based approach solves all of these by making each operation explicit, typed, and trackable.
-
-### Semantic Error Prevention
-
-!!! adr "Architecture Decision"
- The multi-layer error prevention strategy and guardrail architecture are defined in [ADR-018: Semantic Error Prevention](adr/ADR-018-semantic-error-prevention.md).
-
-CleverAgents provides multiple layers of proactive error prevention that catch semantic errors before they can propagate through the system.
-
-#### Layer 1: Decision-time Validation During Strategize
-
-Every decision includes semantic validation:
-
-Decision: Refactor payment module to async
-alternatives_considered:
- - "Convert to async/await patterns" (chosen)
- - "Use thread pool with channels" (rejected: doesn't integrate with async ecosystem)
- - "Keep synchronous with timeout" (rejected: doesn't solve core latency issue)
-confidence_score: 0.85
-validation_performed:
- - Checked all payment API consumers can handle async
- - Verified database driver supports async operations
- - Confirmed no regulatory requirement for sync processing
-
-
-#### Layer 2: Execution-time Semantic Guards
-
-The execution actor uses a tool node that references the independently registered `local/validate-api-compat` tool:
-
-
-# Actor graph uses a named tool node for semantic validation
-actors:
- code_executor:
- type: graph
- skills:
- - local/semantic-validators # Skill containing validation tools for LLM tool-calling
- nodes:
- - name: semantic_validator
- type: tool
- tool: local/validate-api-compat # Named tool from Tool Registry
-
-
-The `local/validate-api-compat` tool is independently registered via its own YAML:
-
-
-# File: tools/validate-api-compat.yaml
-cleveragents:
- version: "3.0"
-
-tool:
- name: local/validate-api-compat
- description: "Check for breaking API changes and attempt auto-migration"
- source: custom
-
- capability:
- writes: true
- checkpointable: true
-
- code: |
- # Not just syntax checking - semantic validation
- old_api = extract_api_signature(previous_version)
- new_api = extract_api_signature(current_version)
-
- breaking_changes = find_breaking_changes(old_api, new_api)
- if breaking_changes:
- affected_consumers = find_api_consumers(breaking_changes)
- migration_plan = generate_migration(breaking_changes)
-
- if can_auto_migrate(affected_consumers, migration_plan):
- apply_migration(migration_plan)
- else:
- raise SemanticError(
- "Breaking API changes require manual review",
- changes=breaking_changes,
- affected=affected_consumers
- )
-
-
-The `local/semantic-validators` skill references this tool by name:
-
-
-# File: skills/semantic-validators.yaml
-skill:
- name: local/semantic-validators
- description: "Semantic validation tools for API compatibility and code invariants"
- tools:
- - local/validate-api-compat
-
-
-#### Layer 3: Invariant Enforcement
-
-!!! adr "Architecture Decision"
- Invariant scoping, enforcement mechanisms, and inheritance rules are defined in [ADR-016: Invariant System](adr/ADR-016-invariant-system.md).
-
-Invariants are named constraints that guide and constrain plan execution. They can be attached at four scopes, all managed through the unified `agents invariant` command:
-
-* **Global invariants**: Apply to all plans across all projects. Added via `agents invariant add --global`.
-* **Project invariants**: Apply to all plans targeting a specific project. Added via `agents invariant add --project`. Can also be attached at creation time via `agents project create --invariant`.
-* **Action invariants**: Attached to an action and carried forward as plan-level invariants when the action is used. Added via `agents invariant add --action`. Can also be attached at creation time via `agents action create --invariant`.
-* **Plan invariants**: Apply to a specific plan and its child plans. Added via `agents invariant add --plan`. Can also be attached at creation time via `agents plan use --invariant`.
-
-**Precedence and conflict resolution**: When invariants from different scopes conflict, narrower scopes override broader scopes:
-
-* **Plan-level** invariants override **action-level**, **project-level**, and **global-level** invariants.
-* **Action-level** invariants override **project-level** and **global-level** invariants.
-* **Project-level** invariants override **global-level** invariants.
-
-Exception: **Non-overridable global invariants** (marked `non_overridable: true`) always take precedence over all other scopes, including plan-level invariants. See below.
-
-The full precedence chain (highest to lowest): `plan > action > project > global`.
-
-Conflict resolution is performed by the **Invariant Reconciliation Actor** — a dedicated actor responsible for comparing invariants across scopes, identifying conflicts, and producing the final **effective invariant view** for a plan. The Invariant Reconciliation Actor is set at three levels via `--invariant-actor`:
-
-1. **Global config**: Set via `agents config set actor.default.invariant `. Defines the default Invariant Reconciliation Actor used when neither the project nor the plan specifies one.
-2. **Project-level**: Set via `--invariant-actor` on `agents project create`. If a project defines an Invariant Reconciliation Actor, it is used to reconcile that project's invariants against global invariants.
-3. **Plan-level**: Set via `--invariant-actor` on `agents action create` (carried forward when the action is used) or `agents plan use` (which overrides whatever was set on the action). If a plan has an Invariant Reconciliation Actor, it reconciles invariants from all scopes (plan, project, and global) and produces the final effective view for that plan.
-
-The lookup order is: plan → project → global config. The first Invariant Reconciliation Actor found is used.
-
-**Invariant view calculation**: When an action is used and a plan enters the Strategize phase, the Invariant Reconciliation Actor computes the effective invariant view by:
-
-1. Collecting all invariants from global, project, plan, and action scopes.
-2. Identifying conflicts (invariants from different scopes that contradict each other).
-3. Applying precedence rules (plan > action > project > global) to resolve conflicts, with non-overridable global invariants taking absolute precedence.
-4. Producing the final set of effective invariants.
-
-Each effective invariant is then recorded as an `invariant_enforced` decision in the plan's decision tree. This makes invariants visible, auditable, and correctable through the standard decision correction mechanism.
-
-**Non-overridable global invariants**: A global invariant may be marked `non_overridable: true`. When set, this invariant takes precedence over all lower-scope invariants regardless of the normal precedence chain -- even plan-level invariants cannot override it. This is intended for system-wide safety constraints that must never be relaxed (e.g., "Never commit secrets to version control"). Non-overridable invariants are set via `agents invariant add --global --non-overridable ""`. The `non_overridable` flag is only meaningful on `GLOBAL`-scoped invariants; it is ignored on project, action, and plan invariants.
-
-**Child plan inheritance**: When a top-level plan spawns child plans, the parent's effective invariant view (already reconciled) is passed down to each child plan. Child plans do not re-run reconciliation — they inherit the parent's resolved view.
-
-**Correcting invariants**: The correction mechanism for `invariant_enforced` decisions supports two operations:
-* **Remove**: Remove an existing invariant from the plan's decision tree (the invariant remains defined at its scope but is no longer enforced for this plan).
-* **Add**: Add a new invariant to the plan. When adding, the user can select from invariants already accessible to the plan (those defined at the plan, action, project, or global scope), or provide free-form text to create a new ad-hoc invariant.
-
-
-# Add invariants at different scopes
-agents invariant add --global "All public APIs must maintain backward compatibility"
-agents invariant add --global "Payment processing must be idempotent"
-agents invariant add --project local/api-service \
- "Database transactions must complete within 5 seconds"
-agents invariant add --project local/api-service \
- "Authentication must always use OAuth2"
-agents invariant add --plan <PLAN_ID> "All API calls over TCP must be mocked"
-agents invariant add --action local/code-coverage "Test files must not import production secrets"
-
-# List invariants
-agents invariant list --global
-agents invariant list --project local/api-service
-agents invariant list --plan <PLAN_ID> --effective # Shows reconciled view
-
-# Remove an invariant
-agents invariant remove <INVARIANT_ID>
-
-# Attach invariants at creation time (convenience)
-agents project create --invariant "All endpoints must validate auth tokens" local/api-service
-agents action create --config ./actions/code-coverage.yaml
-agents plan use local/code-coverage local/api-service --invariant "Mock all network calls"
-
-# Correct an invariant decision (remove or replace via standard correction)
-agents plan correct <DECISION_ID> --mode=revert \
- --guidance "Remove this invariant - it does not apply to this module"
-
-
-The system collects, reconciles, and checks invariants:
-
-class InvariantEnforcer:
- def compute_effective_invariants(self, plan):
- """Compute the effective invariant view for a plan using the Invariant Reconciliation Actor."""
- # 1. Collect raw invariants from all scopes
- raw = self.collect_all_invariants(plan)
-
- # 2. Find the Invariant Reconciliation Actor (plan -> project -> global config)
- reconciler = (
- self.get_plan_invariant_actor(plan)
- or self.get_project_invariant_actor(plan)
- or self.get_global_invariant_actor()
- )
-
- # 3. Reconcile: apply precedence (plan > project > global), resolve conflicts
- effective = reconciler.reconcile(raw, precedence=['plan', 'project', 'global'])
- return effective
-
- def collect_all_invariants(self, plan):
- """Collect invariants from all scopes accessible to this plan."""
- invariants = []
- invariants.extend(self.get_global_invariants())
- for project in plan.projects:
- invariants.extend(self.get_project_invariants(project))
- invariants.extend(self.get_action_invariants(plan.action))
- invariants.extend(self.get_plan_invariants(plan))
- return invariants
-
- def check_invariant_preservation(self, changes, enforced_invariants):
- """Check that changes respect all enforced invariants."""
- for invariant in enforced_invariants:
- if not self.verify_invariant(invariant, changes):
- return InvariantViolation(invariant, changes)
- return Success()
-
-
-#### Layer 4: Predictive Error Prevention
-
-The system learns from past failures:
-
-Error Pattern Database:
- - pattern: "Async conversion in payment module"
- historical_failures:
- - "Race condition in payment confirmation"
- - "Timeout handling breaks idempotency"
- preventive_checks:
- - "Add explicit transaction boundaries"
- - "Verify idempotency keys are preserved"
- - "Check distributed lock acquisition"
-
-
-### Apply Phase
-
-!!! adr "Architecture Decision"
- The Apply phase, conflict resolution, and apply strategies are defined in [ADR-006: Plan Lifecycle](adr/ADR-006-plan-lifecycle.md).
-
-#### What Apply Does
-
-Apply takes the sandboxed work product and makes it "real" in the project.
-
-Core properties:
-
-1. **Apply is a controlled commit step**
- Apply exists specifically to separate "generated work" from "committed work," enabling review and safer automation.
-
-2. **Apply is often the highest-risk step**
- It changes real systems. This is where approvals and checks matter most.
-
-3. **Apply produces a terminal 'applied' state**
- After successful apply, the plan reaches the `applied` terminal state within the Apply phase.
-
-#### Apply Responsibilities (Recommended Checklist)
-
-Apply should perform (configurable) validations before committing:
-
-* **Diff review gate**
-
- * If the `select_tool` threshold is not met (i.e., confidence < threshold, or threshold is `1.0`) in the automation profile, show:
-
- * changed files summary,
- * full diff,
- * risk warnings.
-* **Conflict resolution**
-
- * If applying to a git repo, handle rebase/merge conflicts safely.
-* **Audit log**
-
- * Record who applied, what changed, when, and why.
-
-#### Validation in Apply
-
-Validation runs during **Execute**, not during Apply. By the time a plan reaches the Apply phase, all required validations have already passed. Apply commits the sandbox changes to the real resources and does not re-run validations.
-
-For full details on validation — including the Validation type system, modes, attachment scoping, failure handling, fix-then-revalidate loops, and data model — see the **Validation** section under Core Concepts.
-
-#### Apply Data Model
-
-A plan in Apply includes:
-
-* `apply_summary`
-* `applied_artifacts` (final commit hash, merged PR link, file list)
-* `final_validation_results` (per-validation tool invocation results: `passed`, `message`, and `data` for each)
-* `approval_record` (if human approvals are required)
-* `deployment_record` (optional, if apply triggers deploy)
-
-#### Apply Terminal States
-
-Apply is the final phase. It does not transition to another phase — instead, the plan reaches one of several terminal states within the Apply phase:
-
-**When Apply succeeds:**
-
-* plan.phase = `apply`
-* plan.state = `applied`
-* the sandbox may be cleaned up or archived depending on retention policy
-* changes have been committed to real project resources
-
-**When Apply cannot complete within constraints:**
-
-* plan.phase = `apply`
-* plan.state = `constrained`
-* the Apply phase has determined that the current strategy's constraints prevent successful application (e.g., merge conflicts that violate invariants, validation failures that cannot be resolved within the strategy's scope, resource state drift that contradicts strategy assumptions)
-* depending on the `access_network` automation profile flag, this may automatically trigger a reversion to Strategize, or the system may pause for user decision
-* sandbox remains intact pending reversion or user action
-
-**When Apply fails:**
-
-* plan.phase = `apply`
-* plan.state = `errored`
-* sandbox remains intact for inspection/retry
-
-**When Apply is cancelled:**
-
-* plan.phase = `apply`
-* plan.state = `cancelled`
-* sandbox remains intact for inspection
-
-### Project
-
-!!! adr "Architecture Decision"
- The project concept, resource linking, and project-level configuration are defined in [ADR-009: Project Model](adr/ADR-009-project-model.md).
-
-A **project** is the boundary that answers:
-
-* "Where is the work happening?"
-* "What can this plan read and write?"
-* "What skills (and their tools) can this plan use?"
-* "What context is available?"
-
-A project is a **collection of linked resources and configuration**. Projects link to independently registered resources from the **Resource Registry** — they do not define resources inline. A resource can be linked to multiple projects, enabling shared resources across teams and workflows.
-
-**Important: Projects are created via CLI commands, NOT YAML configuration files.**
-
-#### Project Types: Local vs Remote
-
-Projects are classified based on their resources:
-
-| Type | Definition | Where Plans Can Execute |
-|------|------------|------------------------|
-| **Local** | Contains at least one local-only resource | Client only |
-| **Remote** | All resources are remotely accessible | Client or Server |
-
-This distinction matters for server mode: the server can only execute plans on **remote** projects because it needs network access to all resources.
-
-#### Project Creation (CLI)
-
-
-# Step 1: Register resources independently
-agents resource add git-checkout local/api-repo \
- --path /repos/api-service \
- --branch main
-
-agents resource add local/database local/staging-db \
- --connection-string "postgresql://staging.example.com/mydb" \
- --read-only
-
-# Step 2: Create the project
-agents project create "my-api-service"
-
-# Step 3: Link resources to the project
-agents project link-resource "my-api-service" local/api-repo
-
-agents project link-resource "my-api-service" local/staging-db --read-only
-
-
-Resources are registered once and can be linked to multiple projects. The resource's type, sandbox strategy, and capabilities are defined by its resource type in the Resource Registry — not by the project.
-
-#### Project Data Model
-
-A project includes:
-
-##### 1) Identity
-
-* `name` — the namespaced project name (e.g., `local/api-service`). This serves as the project's globally unique identifier; no separate ULID or ID is generated. The namespacing scheme (`[[server:]namespace/]name`) ensures global uniqueness across systems.
-* `namespace` (follows same rules as actors: `local/`, `/`, `/`)
-* `is_remote` (boolean, derived from resources)
-
-##### 2) Linked Resources
-
-Resources are the "things you can act on." Projects **link** to independently registered resources from the Resource Registry rather than defining them inline. This means:
-
-* A resource can be linked to multiple projects (shared resources).
-* The resource's type, capabilities, sandbox strategy, and DAG relationships are defined by the resource itself — not by the project.
-* Projects can apply project-level overrides when linking (e.g., marking a writable resource as read-only within a specific project context).
-
-Each linked resource reference has:
-
-* `resource_id` (ULID reference to a Resource Registry entry). Resources can be referenced by name or ULID in CLI commands; name is resolved to `resource_id` at command time.
-* `project_read_only` (boolean — project-level read-only override)
-* `alias` (optional short name for referencing within the project)
-
-The full resource details (type, location, sandbox strategy, capabilities, parent/child DAG, etc.) are stored in the Resource Registry. See the **Resources** section for details.
-
-##### 3) Context configuration
-
-Project-level defaults:
-
-* ignore patterns (like `.gitignore` semantics)
-* max file size
-* indexing strategy
-* preferred chunking/summarization policy (even if evolving)
-* context retention policy
-
-##### 4) Execution Environment
-
-!!! adr "Architecture Decision"
- Execution environment routing is defined in [ADR-043: Devcontainer Integration and Container-Project Association](adr/ADR-043-devcontainer-integration.md).
-
-Projects can configure a default execution environment — a container in which tools execute instead of on the host. This is set via `agents project context set`:
-
-
-execution_environment:
- default: local/dev-container # Resource name of the default container
- priority: fallback # fallback | override
-
-
-**Priority semantics:**
-
-* `fallback` (default): Use this execution environment only when no devcontainer is auto-detected for the current resource or its ancestors. If a resource (or ancestor) has a `.devcontainer/`, the devcontainer wins.
-* `override`: Always use this execution environment, ignoring any auto-detected devcontainers.
-
-When a project has multiple containers linked as resources, the `execution_environment.default` field specifies which one to use. Without this setting, the system relies on auto-detected devcontainers or falls back to host execution.
-
-Plans can override the project-level execution environment via `--execution-environment` on `agents plan use` (see [Execution Environment Routing](#execution-environment-routing)).
-
-#### Multi-Project Operations
-
-A single plan may target multiple projects (e.g., updating shared schemas across services). This is considered a key UX advantage over "run in one directory" systems. Because resources are independently registered and can be linked to multiple projects, shared resources across projects are a natural part of the architecture.
-
-In multi-project execution:
-
-* Strategize must clarify which steps affect which projects.
-* Execution must isolate sandboxes per project OR define a composite sandbox. When multiple projects share the same resource, a single sandbox for that resource is used.
-* Apply must commit changes to each project separately, with separate approval records if necessary.
-* Tool resource bindings are resolved per-project — the same tool may bind to different resources depending on which project context it runs in.
-
-### Namespaces
-
-!!! adr "Architecture Decision"
- The namespace system, resolution rules, and ownership model are defined in [ADR-002: Namespace System](adr/ADR-002-namespace-system.md).
-
-Namespaces define **ownership, scoping, and discoverability** of actors, tools, skills, resources, resource types, actions, projects, and plans.
-
-**All named entities use the format `/`.**
-
-#### Namespace Types
-
-| Namespace | Scope | Storage | Examples |
-|-----------|-------|---------|----------|
-| `local/` | Current machine only | Local database | `local/my-reviewer`, `local/test-action` |
-| `/` | Personal server namespace | Server database | `freemo/code-analyzer`, `jsmith/deploy-script` |
-| `/` | Organization namespace | Server database | `cleverthis/standard-review`, `acme/deploy-action` |
-| `openai/`, `anthropic/`, etc. | Built-in LLM actors | N/A (built-in) | `openai/gpt-4`, `anthropic/claude-3-opus` |
-
-#### Namespace Rules
-
-* **`local/`**
-
- * Reserved namespace for local-only items
- * Exists only on the current machine
- * Stored in local database
- * Fast iteration, no sharing
- * Default namespace when none specified
-
-* **`/`** (e.g., `freemo/`, `jsmith/`)
-
- * Personal namespace on the server
- * Created when user registers an account
- * Stored on server, synced when connected
- * Used for reusable entities (actions, actors, tools, skills, resources) a user wants across machines
- * Only the owning user can create/modify items
-
-* **`/`** (e.g., `cleverthis/`, `acme/`)
-
- * Organization namespace on the server
- * Created when organization is registered
- * Shared across team members
- * All namespaced entities (actions, actors, tools, skills, resources, projects) can be centrally managed
-
-* **Built-in Provider Namespaces** (`openai/`, `anthropic/`, `google/`, etc.)
-
- * Reserved for built-in LLM actors
- * Automatically available when API keys are configured
- * In server mode: available if logged in and server has keys
- * In local mode: requires environment variables or app configuration
- * Cannot be used for custom actors
-
-#### Server-qualified Names
-
-To disambiguate between servers (when connected to multiple):
-
-* `dev:freemo/code-coverage` (personal namespace on dev server)
-* `prod:cleverthis/deploy-action` (org namespace on prod server)
-
-This enables a pattern where:
-
-* local machine runs a lightweight client
-* server stores canonical definitions
-* multiple servers can coexist
-
-### Actor
-
-!!! adr "Architecture Decision"
- The actor abstraction, actor types, and actor graph composition are defined in [ADR-010: Actor and Agent Architecture](adr/ADR-010-actor-and-agent-architecture.md).
-
-#### What an Actor Is
-
-!!! adr "Architecture Decision"
- The canonical definition of an actor — anything conversational, actor-as-graph principle, hierarchical composition, and the actor/agent distinction — is formalized in [ADR-031: Actor Abstraction Definition](adr/ADR-031-actor-abstraction-definition.md).
-
-An **actor** is the abstraction that generalizes "agent" into "anything conversational."
-
-!!! abstract "Actor at a Glance"
- * It can be as small as a ==single LLM agent==.
- * It can also be an ==entire graph== that itself calls other actors/tools.
- * Actors can be nested/hierarchical, enabling "orchestrator of orchestrators."
-
- **Every custom actor IS a graph** (a LangGraph defined via YAML configuration). Even a simple actor wrapping a single LLM is technically a graph with one node.
-
-#### Actor Naming
-
-Actors are **always named using `/` format**:
-
-??? example "Naming Examples"
- | Name | Namespace | Description |
- | :--- | :-------- | :---------- |
- | `local/my-reviewer` | `local` | Local actor on this machine |
- | `freemo/code-analyzer` | `freemo` | Personal server actor |
- | `cleverthis/deploy-specialist` | `cleverthis` | Organization actor |
- | `openai/gpt-4` | `openai` | Built-in LLM actor |
-
-#### Actor Definition (YAML Configuration)
-
-Actors are defined via **YAML configuration files**. Tools and skills are also defined via their own YAML configuration files. YAML configuration is used for actors, tools, and skills (not for actions or projects).
-
-Example actor configuration (see `examples/` directory for full examples):
-
-
-name: local/my-workflow
-
-cleveragents:
- version: "3.0"
- default_actor: workflow_controller
-
-actors:
- # Simple LLM actor with skills referenced by name
- my_assistant:
- type: llm
- config:
- actor: openai/gpt-4 # Reference to built-in actor
- temperature: 0.7
- system_prompt: |
- You are a helpful assistant.
- Current task: {{ context.task_description }}
- skills:
- - local/file-ops # Grants access to all tools in this skill
- - local/git-ops
-
- # LLM actor with a composite skill (includes many sub-skills)
- data_processor:
- type: llm
- config:
- actor: anthropic/claude-3-opus
- system_prompt: |
- You are a data processing assistant.
- skills:
- - local/data-toolkit # A skill containing analysis + transformation tools
-
- # Actor referencing another actor
- reviewer:
- type: llm
- config:
- actor: local/code-reviewer # Reference to another custom actor
- memory_enabled: true
- max_history: 20
- skills:
- - local/file-ops
- - local/git-ops
-
-routes:
- main_workflow:
- type: graph
- entry_point: start
- nodes:
- - name: analyze
- type: agent
- agent: my_assistant
- - name: process
- type: agent
- agent: data_processor
- edges:
- - source: start
- target: analyze
- - source: analyze
- target: process
- - source: process
- target: end
-
-context:
- global:
- task_description: "Default task"
-
-
-#### Jinja2 Template Preprocessing
-
-!!! adr "Architecture Decision"
- The two-phase Jinja2 + environment variable preprocessing pipeline for actor YAML files is defined in [ADR-032: Jinja2 YAML Template Preprocessing](adr/ADR-032-jinja2-yaml-template-preprocessing.md).
-
-Actor configuration YAML files are processed through a **two-phase pipeline** before the resulting data structure is validated and loaded:
-
-1. **Phase 1 — Jinja2 Template Rendering**: The raw file content is run through a sandboxed Jinja2 template engine, resolving `{{ }}` expressions, `{% %}` control structures, and `{# #}` comments into static YAML text.
-2. **Phase 2 — Environment Variable Interpolation**: After YAML parsing, all string values matching `${VAR}` or `${VAR:default}` are recursively replaced with OS environment variable values, with automatic type coercion.
-
-!!! warning "Execution Order"
- Jinja2 templates are evaluated **before** YAML parsing. Environment variables are interpolated **after** YAML parsing. The two phases are never interleaved.
-
-##### Jinja2 Template Syntax
-
-The engine uses standard Jinja2 delimiters inside the YAML file:
-
-| Delimiter | Purpose | Example |
-|-----------|---------|---------|
-| `{{ ... }}` | Variable expression | `{{ context.paper_details.topic }}` |
-| `{% ... %}` | Block statement (`if`, `for`, `block`, etc.) | `{% if context.auto_finish_active %}` |
-| `{# ... #}` | Comment (stripped from output) | `{# This is ignored #}` |
-
-**Variable expressions** are used to inject dynamic values into prompts and configuration fields:
-
-```yaml
-system_prompt: |
- You are writing a paper on {{ context.paper_details.topic | tojson }}.
- Target length: {{ context.paper_details.length | tojson }} words.
- Audience: {{ context.paper_details.audience | tojson }}.
-```
-
-**Conditional blocks** enable a single configuration to define behavior for multiple modes:
-
-```yaml
-system_prompt: |
- You are a research assistant.
- {% if context.auto_finish_active %}
- Auto-finish mode is active. Do not ask questions. Proceed autonomously.
- {% else %}
- Engage in interactive conversation to refine the output.
- {% endif %}
-```
-
-**For loops** generate repetitive YAML structure from data:
-
-```yaml
-system_prompt: |
- Available sections:
- {% for section in context.section_paths %}
- - {{ section }}
- {% endfor %}
-```
-
-##### Sandboxed Execution
-
-All template rendering uses `jinja2.sandbox.SandboxedEnvironment`, which prevents templates from:
-
-- Executing arbitrary Python code
-- Accessing the filesystem
-- Calling `os.system`, `eval`, `exec`, or similar unsafe operations
-- Accessing private attributes of objects
-
-##### Custom Jinja2 Filters
-
-The engine registers four custom filters in addition to all standard Jinja2 built-in filters:
-
-| Filter | Purpose | Example |
-|--------|---------|---------|
-| `yaml` | Serializes any value to a YAML-formatted string | `{{ my_dict \| yaml }}` |
-| `indent` | Indents text by N spaces (default 2) | `{{ content \| indent(4) }}` |
-| `sum` | Sums a numeric iterable | `{{ values \| sum }}` |
-| `selectattr` | Selects a named attribute from each item in a sequence | `{{ items \| selectattr('name') }}` |
-
-All standard Jinja2 built-in filters are also available, including: `tojson`, `default`, `lower`, `upper`, `trim`, `join`, `replace`, `length`, `first`, `last`, `sort`, `unique`, `map`, `reject`, `select`, `batch`, `slice`, `int`, `float`, `string`, `list`, `dictsort`, `escape`, `safe`, `truncate`, `wordwrap`, `center`, `format`, `title`, `capitalize`, `striptags`, `urlencode`, `abs`, `round`, `pprint`, `groupby`, `max`, `min`, `random`, `filesizeformat`, `wordcount`, `reverse`.
-
-##### Exposed Built-in Functions
-
-The following safe Python built-in functions are exposed in the template context and can be called directly in expressions:
-
-| Function | Purpose | Example |
-|----------|---------|---------|
-| `range()` | Generates integer sequences | `{% for i in range(5) %}` |
-| `abs()` | Absolute value | `{{ abs(score) }}` |
-| `round()` | Rounds a number | `{{ round(value, 2) }}` |
-| `len()` | Length of a collection | `{{ len(items) }}` |
-| `min()` | Minimum value | `{{ min(scores) }}` |
-| `max()` | Maximum value | `{{ max(scores) }}` |
-| `sum()` | Sum of values | `{{ sum(counts) }}` |
-
-##### Template Context Resolution
-
-Template variables are resolved from a context dictionary. The context supports a nested `context` key convention:
-
-- `{{ context.paper_details.topic }}` → resolves `context["paper_details"]["topic"]`
-- `{{ context.brainstorming_summary }}` → resolves `context["brainstorming_summary"]`
-
-The `global_context` top-level key in the actor configuration file populates this dictionary at load time. At runtime, the actor invocation context, plan context, and session context are merged with the following precedence: **runtime context > plan context > session context > global_context from YAML**.
-
-##### Template Detection and Bypass
-
-The engine detects Jinja2 content by scanning for `{%` or `{{` markers in the raw text. Files without these markers bypass Jinja2 processing entirely and are parsed as plain YAML with zero template overhead.
-
-##### Deferred Rendering
-
-When Jinja2 markers are present but no context is available at load time, the engine performs **deferred rendering**: it parses the YAML with template markers intact as literal strings. Templates are preserved in the parsed structure and rendered later when runtime context becomes available. This is the mechanism by which `system_prompt` fields retain their Jinja2 templates for runtime evaluation.
-
-##### Template Protection for `system_prompt` Fields
-
-A special protection mechanism ensures Jinja2 syntax inside `system_prompt` fields survives the YAML loading process:
-
-1. During loading, all Jinja2 delimiters in the raw file are temporarily replaced with sentinel markers:
- - `{{` → `<<>>`
- - `}}` → `<<>>`
- - `{%` → `<<>>`
- - `%}` → `<<>>`
-
-2. The protected text is parsed as YAML.
-
-3. After parsing, the sentinels are restored to Jinja2 syntax **only within `system_prompt` fields** (recursively through all nested dictionaries and lists).
-
-This allows system prompts to contain Jinja2 templates that are evaluated at **runtime** (when the actor's full context is available) rather than at file-load time.
-
-##### YAML Post-Processing
-
-After Jinja2 rendering, the engine applies automatic post-processing to fix common issues:
-
-1. **Blank line cleanup**: Removes extraneous blank lines generated by `{% %}` block tags between YAML keys.
-2. **Multi-colon line splitting**: Detects and splits lines where template expansion produces multiple `key: value` pairs on a single line.
-3. **Indentation correction**: Inserts indentation hints for `{% for %}` loops to ensure generated YAML maintains correct structure.
-
-##### Environment Variable Interpolation
-
-After YAML parsing, all string values are recursively scanned for environment variable references:
-
-| Pattern | Behavior |
-|---------|----------|
-| `${VAR}` | Replaced with `os.environ["VAR"]`. Raises `ValueError` if not set. |
-| `${VAR:default}` | Replaced with `os.environ.get("VAR", "default")`. Uses default if not set. |
-
-**Automatic type coercion** is applied after substitution:
-
-| Substituted Value | Coerced Type | Example |
-|------------------|-------------|---------|
-| `"true"` / `"false"` (case-insensitive) | `bool` | `True` / `False` |
-| Digits only (with optional leading `-`) | `int` | `42`, `-7` |
-| Digits with single `.` | `float` | `3.14`, `-0.5` |
-| Anything else | `str` | Unchanged |
-
-This enables configurations like:
-
-```yaml
-env_vars:
- WORK_DIR: ${HOME}/workspace # String: /home/user/workspace
- LOG_LEVEL: ${LOG_LEVEL:info} # String: info (default)
- MAX_RETRIES: ${MAX_RETRIES:3} # Integer: 3 (coerced from default)
- DEBUG: ${DEBUG_MODE:false} # Boolean: False (coerced from default)
-```
-
-Environment variable interpolation is applied recursively to all nested dictionaries and lists, ensuring resolution at any depth.
-
-#### Actor Arguments
-
-**All actors can receive arguments when invoked**, including built-in actors. Arguments are passed when:
-
-1. An action is used on projects (arguments flow to strategy/execution actors)
-2. An actor is directly invoked
-
-Arguments are injected into the actor's context and can be used in Jinja2 templates within prompts.
-
-For built-in actors (like `openai/gpt-4`), common arguments include:
-* `temperature`
-* `max_tokens`
-* `system_prompt`
-
-#### Actor Composition (Hierarchical References)
-
-Actors can reference other actors **by name**:
-
-```yaml
-actors:
- complex_workflow:
- type: llm
- config:
- actor: local/base-analyzer # References another registered actor
-```
-
-**Load order matters**: Referenced actors must be loaded/defined before actors that depend on them.
-
-This enables hierarchical composition where:
-* Actor A's graph can include nodes that call Actor B (by name)
-* Actor B itself is a graph that might call Actor C
-* And so on (no depth limit)
-
-Circular actor references are **prohibited** and detected at registration time.
-
-#### Actor vs Agent (Relationship)
-
-!!! adr "Architecture Decision"
- The formal actor/agent distinction — actors as the general abstraction, agents as a specialized subset — is defined in [ADR-031: Actor Abstraction Definition](adr/ADR-031-actor-abstraction-definition.md).
-
-* **Agent**: an actor that is specifically an LLM with tools and reasoning behaviors.
-* **Actor**: may be an agent, but may also be:
-
- * a composite workflow,
- * a multi-step graph,
- * a wrapper around a third-party system (as long as it's "text in → text out" conversationally).
-
-#### Actor Definition Fields (Complete Reference)
-
-The complete set of fields available in an actor definition. For the formal JSON Schema and additional annotated examples, see [Actor Configuration Files](#actor-configuration-files) in the Configuration section.
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `name` | string | Yes | Namespaced actor name in `/` format. Used as the registered identity. |
-| `type` | string | Yes | Actor type: `llm` (language model), `tool` (tool collection), or `graph` (multi-node workflow). |
-| `description` | string | Yes | Human-readable description of what the actor does. |
-| `version` | string | No | Schema version (default: `"1.0"`). |
-| `model` | string | Yes (LLM/GRAPH) | LLM model identifier (e.g., `gpt-4`, `claude-3.5-sonnet`). |
-| `system_prompt` | string | No | System prompt text. Supports Jinja2 templates for dynamic content. |
-| `tools` | list | Yes (TOOL) | List of tool references (strings) and/or inline tool definitions. |
-| `context_view` | string | No | Role-based context filtering: `strategist`, `executor`, `reviewer`, or `full`. |
-| `memory` | object | No | Conversation history settings (see Memory Configuration below). |
-| `context` | object | No | File inclusion and context window settings (see Context Configuration below). |
-| `route` | object | Yes (GRAPH) | Graph topology (see Route Configuration below). |
-| `env_vars` | object | No | Environment variable key-value mappings. |
-| `skills` | list[string] | No | List of skill names this actor can use. Each entry is a namespaced skill name (e.g., `local/file-ops`). Skills provide tool capabilities to the actor. See [Actor References to Skills and Tools](#actor-references-to-skills-and-tools). |
-| `lsp` | list\|object | No | LSP server bindings for language intelligence. Can be a list of namespaced LSP server names (explicit binding), an object with `languages:` list (language-based binding), or an object with `auto: true` (resource-auto binding). See [LSP Integration](#lsp-integration). |
-| `lsp_capabilities` | list[string]\|`"all"` | No | Controls which LSP capabilities are exposed as tools. When omitted or `"all"`, all capabilities from bound servers are available. When a list, only the named capabilities are exposed (e.g., `[diagnostics, hover, definitions]`). |
-| `lsp_context_enrichment` | object | No | Controls automatic LSP context enrichment. Keys: `diagnostics` (bool, default `true`), `type_annotations` (bool, default `false`), `max_diagnostics_per_file` (int, default `50`). |
-
-**Additional fields available in the v2/runtime actor definition format** (within the `config:` block of actors defined inside the `actors:` top-level key):
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `config.provider` | string | Yes (LLM) | LLM provider identifier: `openai`, `anthropic`, `google`, `azure`, `openrouter`, etc. |
-| `config.model` | string | Yes (LLM) | Model identifier within the provider. |
-| `config.actor` | string | No | Combined `provider/model` format (alternative to separate `provider` + `model`). |
-| `config.system_prompt` | string | No | System prompt text with Jinja2 template support. |
-| `config.temperature` | float | No | Sampling temperature (0.0 to 2.0). Lower = more deterministic. |
-| `config.max_tokens` | integer | No | Maximum tokens in the generated response. |
-| `config.memory_enabled` | boolean | No | Enable conversation memory (default: `false`). |
-| `config.max_history` | integer | No | Maximum conversation turns retained in memory (default: `50`). |
-| `config.unsafe` | boolean | No | Allow this actor to perform unsafe operations (default: `false`). |
-| `config.options` | object | No | Provider-specific options passed through to the underlying LLM API. |
-| `config.tools` | list | Yes (tool) | List of inline tool definitions (each with `name` and `code`). |
-| `config.response_format` | object | No | JSON schema for structured output from the LLM. |
-
-##### Memory Configuration
-
-| Field | Type | Default | Description |
-|-------|------|---------|-------------|
-| `enabled` | boolean | `true` | Whether to maintain conversation history. |
-| `max_messages` | integer | `null` (unlimited) | Maximum number of messages to retain. |
-| `max_tokens` | integer | `null` (unlimited) | Maximum tokens in retained history. |
-| `summarize_old` | boolean | `false` | Whether to summarize old messages instead of discarding them. |
-
-##### Context Configuration
-
-| Field | Type | Default | Description |
-|-------|------|---------|-------------|
-| `include_files` | list[string] | `[]` | File paths to include in the actor's context. |
-| `include_dirs` | list[string] | `[]` | Directory paths to include in the actor's context. |
-| `exclude_patterns` | list[string] | `[]` | Glob patterns to exclude from context (e.g., `"**/__pycache__/**"`). |
-| `max_context_tokens` | integer | `null` (model default) | Maximum size of the context window in tokens. |
-
-##### Context View
-
-The `context_view` field controls role-based context filtering:
-
-| Value | Purpose | Includes |
-|-------|---------|----------|
-| `strategist` | High-level planning view | Project structure, goals, constraints, architectural summaries |
-| `executor` | Implementation view | Source code, file contents, specific task details |
-| `reviewer` | Validation view | Changes, diffs, test results, review criteria |
-| `full` | Complete view (use sparingly) | All available context from all categories |
-
-##### Type-Specific Requirements
-
-| Actor Type | Required Fields | Optional Fields |
-|-----------|----------------|-----------------|
-| `llm` | `model` | `system_prompt`, `tools`, `context_view`, `memory`, `context`, `env_vars`, `lsp`, `lsp_capabilities`, `lsp_context_enrichment` |
-| `tool` | `tools` (at least one) | `context_view`, `env_vars` |
-| `graph` | `model`, `route` | `system_prompt`, `tools`, `context_view`, `memory`, `context`, `env_vars`, `lsp`, `lsp_capabilities`, `lsp_context_enrichment` |
-
-##### Tool Definitions (Inline)
-
-Tools in an actor can be either **string references** to registered tools or **inline definitions**:
-
-```yaml
-tools:
- # String reference to a registered tool
- - files/read_file
- - files/list_directory
-
- # Inline tool definition
- - name: utils/count_lines
- description: Count the number of lines in a file
- parameters:
- - name: file_path
- type: str
- description: Path to the file
- required: true
- default: null
- code: |
- def count_lines(file_path: str) -> int:
- with open(file_path, 'r', encoding='utf-8') as f:
- return len(f.readlines())
-```
-
-Each inline tool parameter supports:
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `name` | string | Yes | Parameter name (must be a valid Python identifier). |
-| `type` | string | Yes | Python type annotation as string (e.g., `str`, `int`, `list[str]`). |
-| `description` | string | Yes | Human-readable description. |
-| `required` | boolean | No | Whether the parameter must be provided (default: `true`). |
-| `default` | any | No | Default value if not provided (only for optional parameters). |
-
-Inline tool `name` must follow the `namespace/tool_name` format. The `code` field contains Python source code that defines a callable function.
-
-##### Route Configuration (Graph Topology)
-
-For `type: graph` actors, the `route` field defines the graph structure:
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `nodes` | list[NodeDefinition] | Yes | All nodes in the graph. |
-| `edges` | list[EdgeDefinition] | Yes | All edges connecting nodes. |
-| `entry_node` | string | Yes | ID of the starting node. |
-| `exit_nodes` | list[string] | Yes | IDs of terminal nodes. |
-
-**Node Definition:**
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `id` | string | Yes | Unique node identifier (alphanumeric with underscores/hyphens). |
-| `type` | string | Yes | Node type: `agent`, `tool`, `conditional`, or `subgraph`. |
-| `name` | string | Yes | Human-readable node name. |
-| `description` | string | Yes | Node purpose and behavior. |
-| `config` | object | No | Type-specific configuration (see below). |
-
-**Node type-specific config:**
-
-| Node Type | Config Fields | Description |
-|-----------|---------------|-------------|
-| `agent` | `model`, `prompt`, `tools` | LLM agent with optional tools |
-| `tool` | `tool_name`, `parameters` | Deterministic tool execution |
-| `conditional` | `conditions[].check`, `conditions[].route_to` | Routes based on state conditions (Python expressions) |
-| `subgraph` | `actor_path` | Embeds another actor as a nested workflow |
-
-**Edge Definition:**
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `from_node` | string | Yes | Source node ID. |
-| `to_node` | string | Yes | Target node ID. |
-| `condition` | string | No | Python expression for conditional routing. |
-| `priority` | integer | No | Edge priority for multiple outgoing edges (higher = evaluated first, default: `0`). |
-
-**Graph Validation:**
-
-- All node IDs must be unique within the graph.
-- The `entry_node` must reference an existing node ID.
-- All `exit_nodes` must reference existing node IDs.
-- All edge `from_node` and `to_node` must reference existing node IDs.
-- The graph must be **acyclic** — cycles are detected via DFS and rejected at validation time.
-- All nodes must be reachable from the entry node.
-
-#### Actor Composition and Graphs
-
-!!! adr "Architecture Decision"
- Hierarchical actor composition, the actor-as-graph principle, and graph node types are defined in [ADR-031: Actor Abstraction Definition](adr/ADR-031-actor-abstraction-definition.md).
-
-Actors can reference:
-
-* other actors (by namespaced name)
-* skills (by namespaced name — all tools from referenced skills become available)
-* subgraphs
-
-This is central to enabling both:
-
-* multi-agent orchestration, and
-* modular reuse of workflows.
-
-#### Nodes in the Graph: Actors and Tools
-
-!!! adr "Architecture Decision"
- The two graph node types (actor nodes and tool nodes) and their relationship to the skill and tool systems are defined in [ADR-031: Actor Abstraction Definition](adr/ADR-031-actor-abstraction-definition.md) and [ADR-030: Skill Abstraction Definition](adr/ADR-030-skill-abstraction-definition.md).
-
-Graph nodes can be any of:
-
-* an **actor** (another LLM agent or composite workflow, referenced by name),
-* a **tool node** — a deterministic, non-LLM step that directly invokes a tool. Tool nodes can:
- * **Reference a named registered tool** by its fully-qualified name (e.g., `tool: local/run-migrations`). The tool must be registered in the Tool Registry via `agents tool add`. Metadata can optionally be overridden at the point of use.
- * **Define an anonymous inline tool** using the same format as a tool YAML body (with `anonymous: true`). This is useful for one-off, workflow-specific operations that don't warrant separate registration.
-
-This is a powerful simplification: actors provide intelligence, tools provide capability (both as graph nodes and through skills for LLM tool-calling), and skills organize tools into reusable collections. Everything participates in the same graph.
-
-**Tool node with named tool reference:**
-
-
-nodes:
- - name: run_db_migrate
- type: tool
- tool: local/run-migrations # Named tool from Tool Registry
- override: # Optional metadata override
- capability:
- human_approval_required: true
-
- - name: spawn_tests
- type: tool
- tool: local/create-subplan # Another named tool
-
-
-**Tool node with anonymous inline tool:**
-
-
-nodes:
- - name: custom_validation
- type: tool
- anonymous: true
- description: "Validate output format before proceeding"
- input_schema:
- type: object
- properties:
- data: { type: object }
- capability:
- read_only: true
- code: |
- # Inline Python — same format as a named tool YAML body
- if not params["data"].get("status"):
- raise ValueError("Missing status field")
- return {"valid": True}
-
-
-#### LSP Integration
-
-!!! adr "Architecture Decision"
- The Language Server Protocol integration architecture — LSP Registry, actor LSP binding, capability exposure, and server lifecycle — is defined in [ADR-027: Language Server Protocol (LSP) Integration](adr/ADR-027-language-server-protocol.md).
-
-Actors that perform software development tasks — writing code, refactoring, reviewing, debugging — benefit from **language intelligence**: the ability to understand types, navigate symbol definitions, discover references, identify compilation errors, and comprehend the structural relationships within a codebase. The **Language Server Protocol (LSP)** is the standard for this kind of intelligence, and CleverAgents integrates LSP servers directly into the actor runtime so that agents gain the same semantic code understanding that human developers enjoy in their IDEs.
-
-!!! abstract "LSP at a Glance"
- * LSP servers are registered in a global **LSP Registry** (namespaced like tools, skills, and actors).
- * Actors bind LSP servers via their YAML configuration — explicitly by name, by language, or automatically based on project resources.
- * Different nodes in an actor's graph can have different LSP bindings.
- * LSP capabilities are exposed as **tools** (via `LSPToolAdapter`) and as **context enrichment** (diagnostics/type info injected into ACMS hot context).
- * The **LSP Runtime** in the Infrastructure layer manages server lifecycle, workspace mapping, and file synchronization.
-
-##### LSP Registry
-
-Language servers are registered as first-class entities in the global **LSP Registry**, following the same patterns as the Tool Registry, Skill Registry, and Actor Registry. Each entry defines a language server — its command, the languages it covers, its capabilities, and any initialization options.
-
-LSP entries are:
-
-- **Namespaced** as `[[server:]namespace/]name` (e.g., `local/pyright`, `local/clangd`, `cleverthis/rust-analyzer`).
-- **Defined via YAML configuration** and registered with `agents lsp add --config `.
-- **Managed** via `agents lsp list`, `agents lsp show`, `agents lsp remove`.
-
-Example LSP configuration:
-
-
-name: local/pyright
-description: "Pyright language server for Python type checking and intelligence"
-
-command: pyright-langserver
-args: ["--stdio"]
-transport: stdio
-
-languages:
- - python
-
-capabilities:
- - diagnostics
- - hover
- - completions
- - definitions
- - references
- - rename
- - code_actions
- - formatting
- - signature_help
- - document_symbols
- - workspace_symbols
-
-initialization:
- python:
- pythonPath: "${PYTHON_PATH:/usr/bin/python3}"
- analysis:
- typeCheckingMode: "basic"
- autoSearchPaths: true
-
-
-LSP configuration fields:
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `name` | string | Yes | Namespaced identifier (`/`). |
-| `description` | string | No | Human-readable description of the language server. |
-| `command` | string | Yes | Executable command to launch the language server process. |
-| `args` | list[string] | No | Command-line arguments for the server process. |
-| `transport` | string | No | Communication transport: `stdio` (default) or `tcp`. |
-| `languages` | list[string] | Yes | Programming languages this server provides intelligence for (e.g., `python`, `typescript`, `rust`). |
-| `capabilities` | list[string] | No | Explicit list of LSP capabilities this server provides. When omitted, capabilities are auto-discovered from the server's `initialize` response. |
-| `initialization` | object | No | LSP `initializationOptions` sent during the `initialize` handshake. Supports `${ENV_VAR}` interpolation. |
-| `workspace_settings` | object | No | LSP workspace configuration sent via `workspace/didChangeConfiguration`. |
-
-##### Resource Language Discovery
-
-Resources attached to projects represent codebases, file trees, and repositories that contain source code in one or more programming languages. The system determines what languages a resource contains through a layered discovery process:
-
-1. **File extension analysis** — File extensions (`.py`, `.ts`, `.rs`, `.go`, `.cpp`, etc.) are mapped to language identifiers using a built-in extension-to-language table. This is the fastest and most common method.
-2. **Content analysis** — For files without extensions or with ambiguous extensions, content markers are inspected: shebang lines (`#!/usr/bin/env python3`), magic comments, and structural patterns.
-3. **UKO classification** — The Universal Knowledge Ontology classifies resources at the technology-specific layer (Python, TypeScript, Rust, etc.), providing semantic language identification that persists across sessions.
-4. **Explicit project-level declaration** — Projects may explicitly declare their languages via configuration, overriding or supplementing automatic discovery.
-
-Language discovery results are cached per resource and invalidated when content changes.
-
-##### Actor LSP Binding
-
-Actors declare LSP dependencies in their YAML configuration via the `lsp:` field. Three binding modes are supported, from fully explicit to fully automatic:
-
-**Explicit binding** (by server name):
-
-
-actors:
- code_analyst:
- type: llm
- config:
- actor: anthropic/claude-3-opus
- system_prompt: |
- You are a Python code analyst. Use LSP tools to understand
- type information and identify issues in the codebase.
- skills:
- - local/file-ops
- lsp:
- - local/pyright
- - local/ruff-lsp
-
-
-**Language-based binding** (runtime resolves servers from registry):
-
-
-actors:
- polyglot_reviewer:
- type: llm
- config:
- actor: openai/gpt-4
- lsp:
- languages:
- - python
- - typescript
- - rust
-
-
-**Resource-auto binding** (auto-discover from project resources):
-
-
-actors:
- universal_developer:
- type: llm
- config:
- actor: anthropic/claude-3-opus
- system_prompt: |
- You are a software developer.
- lsp:
- auto: true
-
-
-When `auto: true` is set, the runtime inspects the project's bound resources via language discovery, determines which languages are present, and binds the appropriate LSP servers automatically. This is the most reusable pattern — an actor configured with `lsp: { auto: true }` works correctly regardless of the language of the project it is assigned to.
-
-**Jinja2 dynamic binding** (template-driven resolution):
-
-
-actors:
- dynamic_analyst:
- type: llm
- config:
- actor: openai/gpt-4
- lsp:
- {% for lang in context.project_languages %}
- - {{ lsp_registry.for_language(lang) | first }}
- {% endfor %}
-
-
-Template variables available during LSP resolution:
-
-| Variable | Type | Description |
-|----------|------|-------------|
-| `lsp_registry` | object | The LSP Registry. Supports `.for_language(lang)` returning matching server names and `.all()` returning all entries. |
-| `context.project_languages` | list[string] | Languages detected in the current project's resources. |
-| `context.resource_languages` | list[string] | Languages detected in the specific resource being processed. |
-
-##### Per-Node LSP Binding
-
-Different nodes in an actor's graph can have different LSP configurations. This allows fine-grained control — for example, giving a strategy actor read-only diagnostics while giving an execution actor full LSP capabilities:
-
-
-actors:
- strategy_planner:
- type: llm
- config:
- actor: openai/gpt-4
- system_prompt: |
- Plan the implementation strategy. Use LSP diagnostics
- to assess codebase health before proposing changes.
- lsp:
- - local/pyright
- lsp_capabilities: # Restrict to read-only
- - diagnostics
- - hover
- - definitions
- - references
-
- code_implementer:
- type: llm
- config:
- actor: anthropic/claude-3-opus
- system_prompt: |
- Implement code changes. Use full LSP capabilities
- for navigation, diagnostics, and refactoring.
- lsp:
- auto: true
- lsp_capabilities: all # Full capabilities (default)
-
-routes:
- dev_workflow:
- type: graph
- entry_point: plan
- nodes:
- - name: plan
- type: agent
- agent: strategy_planner
- - name: implement
- type: agent
- agent: code_implementer
- edges:
- - source: plan
- target: implement
- - source: implement
- target: end
-
-
-The `lsp_capabilities` field controls which LSP features are exposed to the actor as tools. When omitted or set to `all`, every capability declared by the bound LSP servers is available.
-
-##### LSP Capability Exposure
-
-LSP capabilities reach actors through two complementary mechanisms:
-
-**As Tools (via LSPToolAdapter)**
-
-The `LSPToolAdapter` is an Infrastructure-layer adapter (analogous to `MCPToolAdapter` for MCP) that translates LSP server capabilities into CleverAgents tools. When an actor with LSP bindings activates, the adapter generates tool definitions for each exposed capability and injects them into the actor's tool surface alongside skill-provided tools.
-
-Available LSP tools:
-
-| Capability | LSP Method | Tool Name | Description |
-|-----------|-----------|-----------|-------------|
-| `diagnostics` | `textDocument/publishDiagnostics` | `lsp/diagnostics` | Retrieve compilation errors, warnings, and hints for a file |
-| `hover` | `textDocument/hover` | `lsp/hover` | Get type information and documentation at a position |
-| `completions` | `textDocument/completion` | `lsp/completions` | Get code completion suggestions at a position |
-| `definitions` | `textDocument/definition` | `lsp/definition` | Go to the definition of a symbol |
-| `references` | `textDocument/references` | `lsp/references` | Find all references to a symbol |
-| `rename` | `textDocument/rename` | `lsp/rename` | Compute a rename refactoring across files |
-| `code_actions` | `textDocument/codeAction` | `lsp/code-actions` | Get available code actions (quick fixes, refactors) |
-| `formatting` | `textDocument/formatting` | `lsp/format` | Format a document according to language conventions |
-| `signature_help` | `textDocument/signatureHelp` | `lsp/signature` | Get function signature information at a call site |
-| `document_symbols` | `textDocument/documentSymbol` | `lsp/symbols` | List all symbols (classes, functions, variables) in a file |
-| `workspace_symbols` | `workspace/symbol` | `lsp/workspace-symbols` | Search for symbols across the entire workspace |
-
-When multiple LSP servers are bound to an actor (e.g., `local/pyright` for Python and `local/typescript-lsp` for TypeScript), the tool adapter routes requests to the appropriate server based on the file's detected language. The tool names remain the same — routing is transparent to the actor.
-
-**As Context Enrichment**
-
-In addition to explicit tool calls, LSP servers can automatically enrich the actor's context:
-
-- **Diagnostic injection**: When a source file enters the actor's hot context, the LSP server's diagnostics for that file are appended as structured annotations. The actor "sees" type errors, unused imports, and other issues without explicitly calling `lsp/diagnostics`.
-- **Type annotation overlay**: Hover information for key symbols (function signatures, class hierarchies, variable types) can be pre-fetched and included as context metadata.
-
-Context enrichment is controlled per actor:
-
-
-actors:
- enriched_reviewer:
- type: llm
- config:
- actor: openai/gpt-4
- lsp:
- auto: true
- lsp_context_enrichment:
- diagnostics: true # Auto-inject diagnostics (default: true)
- type_annotations: false # Auto-inject type info (default: false)
- max_diagnostics_per_file: 50 # Limit to avoid context bloat
-
-
-##### LSP Server Lifecycle
-
-LSP servers are managed by the **LSP Runtime** in the Infrastructure layer:
-
-1. **Startup** — When an actor with LSP bindings activates (for a plan phase or `agents actor run`), the LSP Runtime starts the required language server processes. Each server is initialized with the `initialize` LSP handshake, passing `initializationOptions` from the registry entry and workspace root paths mapped from bound resources.
-
-2. **Workspace Mapping** — LSP workspace roots correspond to registered resource physical paths. When the actor operates within a sandbox (Execute phase), the sandbox's working directory is used as the workspace root, ensuring the language server analyzes sandboxed code — not the original.
-
-3. **File Synchronization** — As the actor reads and modifies files (via tools), the LSP Runtime sends `textDocument/didOpen`, `textDocument/didChange`, and `textDocument/didClose` notifications to keep the language server's view synchronized with the actor's mutations.
-
-4. **Shared Instances** — If multiple actors in the same plan or session require the same language server for the same workspace, the LSP Runtime shares a single server instance. Reference counting ensures the server stays alive as long as at least one actor needs it.
-
-5. **Shutdown** — When the actor deactivates (plan phase completes, session ends), the LSP Runtime sends `shutdown` and `exit` lifecycle messages. Shared instances shut down only when the last referencing actor deactivates.
-
-6. **Crash Recovery** — If a language server process crashes, the LSP Runtime restarts it automatically, re-sends the `initialize` handshake, re-opens tracked documents, and resumes operations without disrupting the actor's execution.
-
-##### LSP in the Plan Lifecycle
-
-LSP integration enhances each phase of the plan lifecycle:
-
-| Phase | LSP Role | Example Use |
-|-------|---------|-------------|
-| **Strategize** | Read-only intelligence — diagnostics, type information, and symbol navigation inform strategy decisions | Strategy actor calls `lsp/diagnostics` to assess codebase health, `lsp/symbols` to understand module structure, `lsp/references` to gauge impact of proposed changes |
-| **Execute** | Full intelligence — all capabilities available during code generation and modification | Execution actor calls `lsp/definition` to understand APIs before using them, `lsp/diagnostics` to verify changes compile, `lsp/rename` to perform safe refactorings |
-| **Apply** | Validation intelligence — diagnostics confirm the final changeset is clean | Apply-phase validations invoke `lsp/diagnostics` on all modified files to ensure no regressions before merge |
-
-##### Comparison with MCP
-
-LSP and MCP are both standard protocols for external capability servers integrated into the actor runtime:
-
-| Aspect | MCP (Model Context Protocol) | LSP (Language Server Protocol) |
-|--------|------------------------------|-------------------------------|
-| **Purpose** | General-purpose tool discovery and invocation | Language-specific code intelligence |
-| **Scope** | Any callable operation (file I/O, API calls, data queries) | Code analysis capabilities (diagnostics, navigation, completions) |
-| **Registry** | Tool Registry (via `MCPToolAdapter`) | LSP Registry (via `LSPToolAdapter`) |
-| **Binding** | Skills compose MCP tools; actors acquire via skill references | Actors bind LSP servers directly via `lsp:` configuration |
-| **Tool generation** | Tools pre-defined by MCP server, registered at discovery | Tools generated dynamically from LSP server capabilities at activation |
-| **Lifecycle** | Managed by MCP SDK connection lifecycle | Managed by LSP Runtime with workspace mapping and file synchronization |
-
-Both adapters follow the same architectural pattern: a standard protocol server in the Infrastructure layer is bridged into the actor's tool surface through a typed adapter. The key difference is that MCP tools are general-purpose and explicitly authored, while LSP tools are language-specific and automatically derived from the protocol's capability model.
-
-#### Multi-Actor Configuration File (Complete Structure)
-
-A single actor configuration YAML file can define an entire multi-actor system — multiple actors, graph routing, stream processing, context sharing, and message routing — all in one file. This is the format used for complex workflows like the scientific paper writer.
-
-##### Top-Level Keys
-
-| Key | Type | Required | Description |
-|-----|------|----------|-------------|
-| `name` | string | Yes | Namespaced actor name (`/`). |
-| `cleveragents` | object | No | Metadata: version, logging, template engine, safety, default actor. |
-| `actors` (or `agents`) | object | Yes | Map of actor names to definitions. Both key names are accepted. |
-| `routes` | object | No | Map of route names to stream or graph topology definitions. |
-| `merges` | list | No | Stream merge operations combining multiple sources into one target. |
-| `splits` | list | No | Stream split operations dividing one source into multiple targets. |
-| `publications` | list | No | Output stream names (e.g., `["__output__"]`). |
-| `templates` | object | No | Reusable template definitions for Jinja2 inheritance. |
-| `instances` | object | No | Instantiated templates with bound parameters. |
-| `global_context` | object | No | Key-value pairs accessible to all actors via `{{ context.key }}`. |
-| `context` | object | No | Alternative context block with `global:` sub-key. |
-| `prompts` | object | No | Named prompt templates referenceable by actors. |
-| `pipelines` | object | No | Hybrid pipeline definitions combining stream and graph stages. |
-
-##### `cleveragents` Metadata Block
-
-```yaml
-cleveragents:
- version: "3.0" # Schema version (default: "3.0")
- logging:
- level: "INFO" # DEBUG, INFO, WARNING, ERROR (default: INFO)
- template_engine: "JINJA2" # JINJA2 or NONE (default: JINJA2)
- unsafe: false # Allow unsafe operations (default: false)
- default_actor: my_actor # Default actor when multiple defined
-```
-
-##### Route Definitions
-
-Routes connect actors via **stream** or **graph** topologies:
-
-**Stream Routes** — reactive processing pipelines:
-
-```yaml
-routes:
- chat_stream:
- type: stream
- stream_type: cold # cold (default), hot, or replay
- operators:
- - type: map # map or graph_execute
- params:
- agent: chat_agent # Actor name for map operators
- publications:
- - __output__ # Output stream name
- subscriptions:
- - __input__ # Input stream name
- buffer_size: 10 # Stream buffer size (default: 10)
- initial_value: null # Initial value (optional)
-```
-
-**Graph Routes** — LangGraph-based directed graph workflows:
-
-```yaml
-routes:
- main:
- type: graph
- entry_point: start # Entry node name (required)
- nodes:
- start:
- type: START # Special start node
- end:
- type: END # Special end node
- router:
- type: message_router # Message-based routing node
- rules: # Routing rules (see below)
- - ...
- my_actor_node:
- type: agent # Actor-backed node
- agent: my_actor # References actor by name
- metadata: {} # Optional metadata
- edges:
- - source: start
- target: router
- - source: router
- target: my_actor_node
- condition:
- context_value: next_node
- equals: my_actor_node
- - source: my_actor_node
- target: end
- checkpointing: false # Enable checkpointing (default: false)
- checkpoint_dir: null # Checkpoint storage directory
- enable_time_travel: false # Enable time travel debugging (default: false)
- parallel_execution: false # Allow parallel node execution (default: false)
- state_class: null # Custom state class name
-```
-
-##### Graph Node Types
-
-| Type | Purpose | Key Fields |
-|------|---------|------------|
-| `agent` | Node backed by an actor | `agent: ` |
-| `tool` | Node invoking tools | `tools: [, ...]` |
-| `function` | Node backed by a Python function | `function: ` |
-| `conditional` | Branching node | `condition: { ... }` |
-| `subgraph` | Delegates to another graph route | `subgraph: ` |
-| `start` / `START` | Explicit start node | (none) |
-| `end` / `END` | Terminal node | (none) |
-| `message_router` | Content-based message routing | `rules: [...]` |
-
-##### Message Router Node
-
-The `message_router` node type routes messages to different actors based on message content. It uses a rules-based system:
-
-```yaml
-router:
- type: message_router
- rules:
- # Prefix-based routing
- - type: prefix
- match: "GOTO_BRAINSTORMING"
- target: brainstorming
- strip_match: true # Remove the prefix before forwarding
-
- # Contains-based routing
- - type: contains
- match: "SET_TOPIC:"
- target: discovery
-
- # Suffix-based routing (catch-all)
- - type: suffix
- match: "" # Empty string matches everything
- target: workflow_controller
-```
-
-Each rule specifies:
-
-| Field | Type | Description |
-|-------|------|-------------|
-| `type` | string | Match type: `prefix`, `contains`, or `suffix`. |
-| `match` | string | Pattern to match against the message content. |
-| `target` | string | Node name to route the message to. |
-| `strip_match` | boolean | Whether to strip the matched pattern from the message (default: `false`). |
-
-Rules are evaluated in order; the first matching rule determines the target node.
-
-##### Routing Prefixes (Inter-Actor Communication)
-
-Actors communicate with each other and the routing system via **routing prefixes** — special string prefixes prepended to output text that the message router interprets:
-
-| Prefix Pattern | Purpose | Example |
-|----------------|---------|---------|
-| `GOTO_:` | Route to a specific node | `GOTO_BRAINSTORMING:Start the brainstorm` |
-| `SET_:` | Set a context field value | `SET_TOPIC:Quantum computing` |
-| `ROUTE_:` | Route to a sub-target | `ROUTE_ASK_TOPIC:What topic?` |
-| `COMMAND_OUTPUT:` | Display output directly to user | `COMMAND_OUTPUT:Help text here` |
-| `DISCOVERY_RESPONSE:` | Response from discovery stage | `DISCOVERY_RESPONSE:Topic set` |
-
-Tool actors return these prefixes as their `result` variable. The message router parses the prefix and routes accordingly. The message content after the colon is forwarded to the target node.
-
-##### Conditional Edges
-
-Graph edges can include conditions that control routing based on graph state:
-
-```yaml
-edges:
- # Unconditional edge
- - source: start
- target: router
-
- # Conditional edge — routes based on context value
- - source: router
- target: brainstorming
- condition:
- context_value: next_node
- equals: brainstorming
-
- # Conditional edge — routes based on boolean flag
- - source: passthrough
- target: auto_driver
- condition:
- context_value: auto_finish_active
- equals: true
-```
-
-##### Merges and Splits
-
-**Merges** combine multiple input streams into a single stream:
-
-```yaml
-merges:
- - sources: [__input__] # Special __input__ = user input
- target: main # Route name to send merged input to
-```
-
-**Splits** divide a single stream into multiple output streams:
-
-```yaml
-splits:
- - source: main_output
- targets: [log_stream, display_stream]
-```
-
-Special stream names:
-- `__input__` — the user's input
-- `__output__` — the final output displayed to the user
-
-##### Inline Tool Code Model
-
-Tool-type actors define their behavior entirely in inline Python code within the `code:` field:
-
-```yaml
-my_tool_actor:
- type: tool
- config:
- tools:
- - name: my_tool
- code: |
- import sys
- # Available variables:
- # input_data — the input text/message passed to this tool
- # context — shared mutable context dictionary
- # result — set this variable to define the tool's output
-
- msg = input_data or ''
- context['last_input'] = msg
-
- if msg.startswith('!help'):
- result = "COMMAND_OUTPUT:Available commands: !help, !next"
- else:
- result = f"GOTO_PROCESSOR:{msg}"
-
- print(f"DEBUG: {result}", file=sys.stderr)
-```
-
-The inline code execution model provides three implicit variables:
-
-| Variable | Type | Description |
-|----------|------|-------------|
-| `input_data` | string | The input text/message passed to the tool. |
-| `context` | dict | Shared mutable context dictionary. Changes persist across invocations. |
-| `result` | string | **Set this variable** to define the tool's output. |
-
-The `context` dictionary is the primary mechanism for inter-actor state sharing. All actors in the same configuration share the same context, enabling data flow between stages.
-
-##### Context Sharing
-
-The `context` dictionary (accessible in tool code and Jinja2 templates) serves as shared state:
-
-```yaml
-# Set via global_context in YAML:
-global_context:
- writing_stage: intro
- paper_details:
- topic: null
- length: null
- audience: null
-
-# Or via context.global:
-context:
- global:
- conversation_mode: true
- default_actor: openai/gpt-4
-```
-
-At runtime, tool actors read and modify context freely:
-
-```python
-# In tool code:
-context['writing_stage'] = 'brainstorming' # Update stage
-topic = context.get('paper_details', {}).get('topic') # Read nested value
-context.setdefault('history', []).append(msg) # Append to list
-```
-
-In Jinja2 templates (system prompts):
-
-```yaml
-system_prompt: |
- Paper topic: {{ context.paper_details.topic | tojson }}
- {% if context.auto_finish_active %}
- Proceed autonomously.
- {% endif %}
-```
-
-##### Stream-to-Graph Bridge
-
-Routes can include bridge configuration for dynamic topology changes:
-
-```yaml
-routes:
- adaptive:
- type: stream
- bridge:
- upgrade_conditions:
- message_count_threshold: 5
- downgrade_conditions:
- idle_timeout: 30
- state_extractor: "extract_graph_state"
- state_flattener: "flatten_to_stream"
- preserve_subscriptions: true
- preserve_checkpointing: true
-```
-
-##### Publications
-
-The `publications` key defines output streams at the route or top level:
-
-```yaml
-# Route-level publications
-routes:
- chat_stream:
- type: stream
- publications:
- - __output__
-
-# Top-level publications
-publications:
- - __output__
-```
-
-#### Actor Configuration File Loading
-
-Actor configuration files can be loaded from either JSON or YAML format:
-
-1. The loader first attempts JSON parsing (`json.loads`)
-2. If JSON parsing fails, it falls back to the YAML pipeline (Jinja2 preprocessing + `yaml.safe_load` + environment variable interpolation)
-
-The resolution order for `provider` and `model` values when loading:
-
-1. CLI override (`--provider`, `--model`)
-2. Top-level `provider` / `model` keys
-3. Top-level `provider_type` / `model_id` aliases
-4. v2-extracted values from `actors..config.provider` / `.model`
-
-For `unsafe` flag: the result is `true` if **any** of the following is `true`: the top-level `unsafe` key, the v2-extracted `unsafe` flag, or the CLI `--unsafe` flag.
-
-### Agent
-
-!!! adr "Architecture Decision"
- The agent specialization and its relationship to the actor abstraction are defined in [ADR-010: Actor and Agent Architecture](adr/ADR-010-actor-and-agent-architecture.md).
-
-#### Agent Definition
-
-In CleverAgents, an **agent** is a specialized actor with:
-
-* a conversational interface,
-* tool-calling capability,
-* potentially memory, planning heuristics, and role identity.
-
-Examples of agent roles:
-
-* planner/architect (strategy actor)
-* coder/implementer (execution actor)
-* reviewer/qa agent
-* release/apply agent
-
-The transcript explicitly discusses role separation like planner/coder/reviewer in context views/memory proposals.
-
-#### Agent Behavior Configuration
-
-Agents should be configurable without code changes:
-
-* prompt templates
-* tool sets
-* safety constraints
-* style constraints (verbosity, code style)
-* reliability controls (self-checks, validations)
-
-A design goal is user empowerment: "users customize LLM behavior without modifying core code."
-
-### Tools
-
-!!! adr "Architecture Decision"
- The tool system, tool adapter layer, and tool lifecycle are defined in [ADR-011: Tool System](adr/ADR-011-tool-system.md).
-
-#### What a Tool Is
-
-A **tool** is a namespaced, independently registered, callable operation. It is the ==atomic unit of execution== in CleverAgents — the smallest piece of functionality that can read, write, or transform resources. Tools are defined in their own YAML configuration files, managed through the `agents tool` CLI commands, and registered in the **Tool Registry**.
-
-Tools follow the same `/` naming convention as actors, skills, and other entities (e.g., `local/run-migrations`, `cleverthis/validate-api`, `local/create-subplan`). They support optional server-qualified prefixes for multi-server disambiguation (e.g., `dev:freemo/custom-analysis`).
-
-**Validation as a Tool subtype**: A **Validation** is a specialized subtype of Tool that extends the Tool class with validation-specific metadata (`mode`: required/informational) and a structured JSON return format (`{ "passed": bool, "message": string, "data": object }`). Because Validation extends Tool via standard class inheritance, it inherits all base properties and behaviors — registration, resource bindings, lifecycle hooks, capability metadata, source types (custom, MCP, agent_skill, builtin, and the validation-specific `wrapped` source for Validations that delegate to an existing Tool), and the ability to exist as a tool node in an actor graph. A Validation can also **wrap** an existing plain Tool via the `wraps` field, reusing the Tool's implementation and interpreting its output through a `transform` function — see the **Tool Wrapping** subsection under Core Concepts > Validation for details.
-
-!!! note "Key Constraints on Validations"
- - **Always read-only**: Validations observe and report but ==never modify resources==. `writes` is always `false` and `checkpointable` is always `false`.
- - **Shared namespace**: Validations and plain Tools share the same naming namespace in the Tool Registry. A name conflict results in an error.
- - **Superset/subset semantics**: A Validation can be used anywhere a Tool is expected (since it IS a Tool), but not vice versa.
- - **Unified management**: Listed via `agents tool list --type validation`, inspected via `agents tool show`, removed via `agents tool remove`. Only `add`, `attach`, and `detach` have validation-specific CLI commands.
-
-Validations can be attached to resources directly, or to resources through projects or plans. The same mechanisms used to determine what tools can operate on what resources carry over to determining what validations apply to a particular resource. See the **Validation** section (immediately following this Tools section) for full details on the Validation type system, modes, attachment scoping, failure handling, and data model.
-
-#### The Dual Role of Tools
-
-Tools serve two distinct roles in CleverAgents:
-
-1. **As components of a Skill**: A skill references tools by name to assemble a reusable capability collection. When an actor references a skill, all of that skill's tools (including those from included child skills) become available to the actor's LLM agent for tool-calling.
-
-2. **As tool nodes in an Actor graph**: An actor's graph definition can include `type: tool` nodes that directly invoke a specific tool. This is used for deterministic, non-LLM steps in a workflow — e.g., spawning a child plan, running validation, or executing a migration. The tool node either references a named registered tool or defines an anonymous inline tool.
-
-```kroki-mermaid
-block-beta
- columns 3
- space:3
- block:header:3
- A["Tool: Dual Role"]
- end
- space:3
- block:role1:1
- B["Role 1: In a Skill"]
- C["Skill: local/devops"]
- D["tools:"]
- E[" - local/run-migrations"]
- F[" - local/validate-schema"]
- G["(tool-calling by LLM)"]
- end
- space:1
- block:role2:1
- H["Role 2: In an Actor Graph"]
- I["Actor Graph node:"]
- J[" name: run_db"]
- K[" type: tool"]
- L[" tool: local/run-migrations"]
- M["(deterministic invoke)"]
- end
-```
-
-#### Tool Configuration (YAML)
-
-Tools are defined in their own YAML configuration files, separate from skills and actors. A tool YAML file declares the tool's identity, schema, capability metadata, and implementation:
-
-
-# File: tools/run-migrations.yaml
-cleveragents:
- version: "3.0"
-
-tool:
- name: local/run-migrations
- description: "Run database migrations for the API service"
-
- source: custom # mcp | agent_skill | builtin | custom
-
- # Resource bindings — what resources this tool needs access to
- resources:
- db:
- type: local/database
- access: read_write
- required: true
- description: "Target database for migrations"
-
- input_schema:
- type: object
- properties:
- direction:
- type: string
- enum: [up, down]
- count:
- type: integer
- default: 1
- required: [direction]
-
- capability:
- writes: true
- write_scope:
- resource_slots: [db] # References the "db" resource slot
- checkpointable: true
- checkpoint_scope: transaction
- side_effects: [schema_mutation]
-
- code: |
- import subprocess
- direction = params["direction"]
- count = params.get("count", 1)
- db = ctx.resources["db"] # Access the bound database resource
- result = subprocess.run(
- ["alembic", direction, str(count)],
- capture_output=True, text=True, cwd=db.sandbox.root
- )
- return {"stdout": result.stdout, "returncode": result.returncode}
-
-
-Another example — a tool that wraps an MCP server endpoint:
-
-
-# File: tools/create-github-issue.yaml
-cleveragents:
- version: "3.0"
-
-tool:
- name: local/create-github-issue
- description: "Create a GitHub issue via MCP"
-
- source: mcp
- mcp_server:
- command: "npx @anthropic/mcp-github"
- env:
- GITHUB_TOKEN: "${GITHUB_TOKEN}"
- tool_name: create_issue # The tool name as exposed by the MCP server
-
- capability:
- writes: true
- write_scope: [github:issues]
- checkpointable: false
-
-
-And an Agent Skill tool:
-
-
-# File: tools/deploy-staging.yaml
-cleveragents:
- version: "3.0"
-
-tool:
- name: local/deploy-staging
- description: "Deploy the current branch to the staging environment"
-
- source: agent_skill
- agent_skill:
- path: ./skills/deploy-to-staging
- sandbox_policy: container
- allowed_tools: ["Bash(docker:*)", "Bash(kubectl:*)", "Read"]
-
- capability:
- writes: true
- checkpointable: false
- side_effects: [deploy, infrastructure]
-
-
-#### Tool Registration and Management
-
-Tools are managed through the `agents tool` CLI commands:
-
-
-# Register a new tool from its YAML configuration
-agents tool add --config ./tools/run-migrations.yaml
-
-# Update an existing tool (re-reads the config file, overwrites registration)
-agents tool add --config ./tools/run-migrations.yaml --update
-
-# List all registered tools
-agents tool list
-
-# Show details for a tool (schema, capability, references)
-agents tool show local/run-migrations
-
-# Remove a tool
-agents tool remove local/run-migrations
-
-
-Once registered, a tool is available to be referenced by skills (in their `tools` list) and by actor graphs (as `type: tool` nodes). Tools persist in the database (local or server) and follow the same namespace rules as actors and skills.
-
-#### Anonymous Tools
-
-An **anonymous tool** is an inline tool definition that appears directly in a skill YAML or an actor graph node. Anonymous tools use the **same format** as a named tool's YAML definition (same `input_schema`, `capability`, and `code` fields) but lack a namespaced name. They are:
-
-* **Not registered** in the Tool Registry
-* **Not reusable** — they exist only within the YAML file where they are defined
-* **Useful for one-off operations** that are too specific to warrant separate registration
-
-Anonymous tools in a skill YAML:
-
-
-skill:
- name: local/my-skill
- tools:
- - local/run-migrations # Named tool reference
- - local/validate-api-compat # Named tool reference
-
- anonymous_tools: # Inline definitions, same format as tool YAML
- - description: "One-off data cleanup for this project"
- input_schema:
- type: object
- properties:
- table: { type: string }
- capability:
- writes: true
- checkpointable: true
- code: |
- # ... Python code ...
- return {"cleaned": count}
-
-
-Anonymous tools in an actor graph node:
-
-
-nodes:
- - name: custom_step
- type: tool
- anonymous: true
- description: "Inline validation specific to this workflow"
- input_schema:
- type: object
- properties:
- data: { type: object }
- capability:
- read_only: true
- code: |
- # ... Python code ...
- return {"valid": True}
-
-
-The anonymous tool format is intentionally identical to the body of a named tool YAML — this means promoting an anonymous tool to a named, registered tool is a simple copy-paste into its own YAML file and `agents tool add`.
-
-#### Metadata Overrides
-
-When referencing a named tool in a skill or actor graph, its registered metadata can optionally be **overridden** at the point of use. This allows context-specific adjustments without modifying the tool's global registration.
-
-**Overriding tool metadata in a skill:**
-
-
-skill:
- name: local/strict-devops
- tools:
- - name: local/run-migrations
- override:
- capability:
- human_approval_required: true # Override: require approval in this skill
- write_scope: [database:staging] # Override: restrict scope for this context
-
- - local/validate-api-compat # No overrides, use as registered
-
-
-**Overriding tool metadata in an actor graph node:**
-
-
-nodes:
- - name: safe_migrate
- type: tool
- tool: local/run-migrations
- override:
- capability:
- human_approval_required: true
-
-
-**Overriding tool metadata when including a sub-skill:**
-
-When a skill includes another skill (importing all its tools), individual tools from the included skill can have their metadata overridden:
-
-
-skill:
- name: local/production-ops
- includes:
- - name: local/devops-toolkit
- tool_overrides:
- - tool: local/run-migrations
- override:
- capability:
- human_approval_required: true # In this context, require human approval
- write_scope: [database:production]
-
- - tool: local/create-github-issue
- override:
- capability:
- human_approval_required: true # Require approval in this context
-
-
-Override rules:
-1. Overrides are **shallow-merged** — only the specified fields are replaced; unspecified fields retain their registered values.
-2. Overrides **never persist** back to the Tool Registry — they apply only at the point of use.
-3. Built-in tool metadata **cannot be overridden** (it is authoritative from the implementation).
-4. The override scope is limited to `capability` and `description` fields. Schema (`input_schema`, `output_schema`) cannot be overridden because it would break callers' expectations.
-
-#### Resource Bindings
-
-!!! adr "Architecture Decision"
- Resource binding resolution, slot declarations, and project-specific binding are defined in [ADR-008: Resource System](adr/ADR-008-resource-system.md) and [ADR-011: Tool System](adr/ADR-011-tool-system.md).
-
-Tools operate on **resources** — git repositories, filesystems, databases, and more. The **resource binding** system declares and resolves the relationship between a tool and the resources it needs access to.
-
-##### Resource Slots
-
-A tool declares one or more **resource slots** in its YAML configuration. Each slot is a typed placeholder that specifies:
-
-* **Slot name**: A logical name used to reference the resource within the tool's code and parameters.
-* **Resource type**: The resource type required (e.g., `git`, `fs-mount`, `local/database`). The bound resource must be of this type (or a compatible subtype).
-* **Access mode**: `read_only`, `write_only`, or `read_write`.
-* **Description**: Human-readable explanation of what the tool uses this resource for.
-* **Required/optional**: Whether the slot must be bound for the tool to function.
-
-Example tool YAML with resource slots:
-
-
-tool:
- name: local/run-migrations
- description: "Run database migrations"
- source: custom
-
- resources:
- db:
- type: local/database
- access: read_write
- required: true
- description: "Target database for migrations"
-
- capability:
- writes: true
- write_scope: [db:migrations] # References the "db" slot
- checkpointable: true
-
- code: |
- direction = params["direction"]
- db_resource = ctx.resources["db"] # Access the bound resource
- result = db_resource.handler.execute_migration(direction, db_resource.sandbox)
- return {"status": "ok"}
-
-
-A tool that works with multiple resources:
-
-
-tool:
- name: local/cross-repo-diff
- description: "Compare files across two git repositories"
- source: custom
-
- resources:
- source_repo:
- type: git-checkout
- access: read_only
- required: true
- description: "Source repository to compare from"
- target_repo:
- type: git-checkout
- access: read_only
- required: true
- description: "Target repository to compare against"
-
- capability:
- read_only: true
-
- code: |
- source = ctx.resources["source_repo"]
- target = ctx.resources["target_repo"]
- # ... compare files across repos ...
-
-
-##### Three Binding Modes
-
-Resource slots are resolved to actual resources through one of three binding modes:
-
-**1. Contextual Binding (default)**
-
-The slot declares a resource type requirement, and the system resolves it from the plan's project context at activation time. This is the most common mode — the tool says "I need a git-checkout resource" and the system finds one among the project's linked resources.
-
-
-resources:
- repo:
- type: git-checkout
- access: read_write
- # No `bind` field → contextual binding
-
-
-Resolution rules for contextual binding:
-* The system searches the plan's project for linked resources matching the slot's type.
-* If exactly one resource of the right type exists, it is automatically bound.
-* If multiple resources match, the system uses the slot name as a hint (e.g., a slot named `repo` prefers a resource with alias `repo`). If ambiguous, the plan execution raises an error requiring explicit binding.
-* If no resource matches, the tool cannot be activated for this plan (a validation error is raised during plan creation).
-
-**2. Static Binding**
-
-The slot is hardcoded to a specific registered resource by name. This is useful for tools that always operate on the same resource, regardless of project context.
-
-
-resources:
- docs:
- type: fs-mount
- access: read_only
- bind: local/company-docs # Static: always this resource
- description: "Company documentation corpus"
-
-
-Static bindings are resolved at registration time and validated — the named resource must exist and be of the correct type.
-
-**3. Parameter Binding**
-
-The resource reference is passed as a tool argument at invocation time. This is useful for tools that operate on user-specified resources.
-
-
-resources:
- target:
- type: git-checkout
- access: read_only
- from_param: repository # Bound from the "repository" input parameter
- description: "Repository to analyze"
-
-input_schema:
- type: object
- properties:
- repository:
- type: string
- description: "Name of the registered resource to analyze"
- required: [repository]
-
-
-The `from_param` field links a resource slot to an input parameter. At invocation time, the system resolves the parameter value as a resource name from the Resource Registry and validates type compatibility.
-
-##### Binding Resolution Flow
-
-```kroki-mermaid
-stateDiagram-v2
- [*] --> ToolActivation: Actor references skill or tool node
-
- state "For Each Resource Slot" as ForEach {
- state binding_check <>
- [*] --> binding_check: Check binding type
-
- binding_check --> StaticBinding: has bind field
- binding_check --> ContextualBinding: no bind, no from_param
- binding_check --> ParameterBinding: has from_param
-
- state "Static Binding" as StaticBinding {
- [*] --> ResolveByName: Resolve from Resource Registry
- ResolveByName --> ValidateType: Validate type compatibility
- }
-
- state "Contextual Binding" as ContextualBinding {
- [*] --> SearchProject: Search plan's project resources
- SearchProject --> FilterByType: Filter by resource type
- state match_check <>
- FilterByType --> match_check
- match_check --> AutoBind: One match
- match_check --> TryAlias: Multiple matches
- match_check --> ValidationError: No matches
- TryAlias --> AliasMatch: Try alias/name match
- AliasMatch --> AutoBind: Match found
- AliasMatch --> ValidationError: No match
- }
-
- state "Parameter Binding" as ParameterBinding {
- [*] --> DeferBinding: Defer to invocation time
- }
-
- StaticBinding --> StoreBindings
- AutoBind --> StoreBindings
- ParameterBinding --> StoreBindings
- state "Store in ToolActivationContext" as StoreBindings
- }
-
- state "Tool Invocation" as Invocation {
- [*] --> ResolveParams: Resolve parameter-bound slots\nfrom invocation params
- [*] --> ValidateAccess: Ensure sandbox exists\nValidate access mode
- ResolveParams --> Execute
- ValidateAccess --> Execute
- state "Execute tool with bound resources" as Execute
- }
-
- ForEach --> Invocation
- Invocation --> [*]
-```
-
-##### Built-in Tool Resource Bindings
-
-Built-in tools have **implicit resource slots** that do not need to be declared in YAML (they are hardcoded in the implementation):
-
-| Built-in Tool Group | Implicit Slot | Slot Type | Access |
-|---------------------|--------------|-----------|--------|
-| `file_operations` (read_file, write_file, edit_file, etc.) | `directory` | `fs-directory` or `git-checkout` | `read_write` |
-| `directory_operations` (create_directory, list_directory, etc.) | `directory` | `fs-directory` or `git-checkout` | `read_write` |
-| `search_operations` (search_files, find_definition, etc.) | `directory` | `fs-directory` or `git-checkout` | `read_only` |
-| `git_operations` (git_status, git_diff, git_log, etc.) | `repo` | `git-checkout` | `read_only` |
-
-Built-in tools accept both `fs-directory` and `git-checkout` types for file operations because a `git-checkout` resource's worktree root is an `fs-directory`. When binding to a `git-checkout`, the resource router automatically resolves to the worktree root `fs-directory` child for file operations. A standalone `fs-mount` resource also works — the router resolves through the `fs-mount` → root `fs-directory` chain.
-
-##### Resource Discovery via Bindings
-
-The binding system enables powerful resource discovery queries:
-
-* **"What tools can modify this resource?"** → Find all tools with resource slots matching the resource's type and `access: read_write` or `access: write_only`.
-* **"What tools can read this virtual file?"** → Find the virtual file's physical children, then find tools with slots matching each physical resource's type.
-* **"What resources does this tool need?"** → Inspect the tool's declared resource slots.
-* **"Is this tool compatible with this project?"** → Check if the project's linked resources can satisfy all of the tool's required resource slots.
-
-##### Transitive Reachability
-
-!!! adr "Architecture Decision"
- Tool reachability, access projection, and read/write routing are defined in [ADR-037: Tool Reachability and Access Projection](adr/ADR-037-tool-reachability-and-access-projection.md).
-
-Tool reachability extends beyond direct binding. A tool bound to a `git-checkout` can transitively reach every descendant `fs-file` through the DAG's `contains` edges.
-
-**Forward reachability**: Given a tool `T` bound to resource `R`, the set of all resources `T` can access is `{R} ∪ {all descendants of R via contains edges}`.
-
-**Inverse reachability**: Given a resource `r`, the set of tools that can reach it is found by walking **up** the containment hierarchy from `r`, collecting all ancestors, and finding tools with resource slots compatible with any ancestor's type.
-
-**Cross-equivalence reachability**: If resource `r` has a virtual parent, the system also finds tools that can reach any sibling physical manifestation of the same virtual resource. This answers: "What tools can reach the same logical resource through any physical path?"
-
-Example: `fs-file` at `/repo/src/main.py` is reachable by:
-* `write_file` (bound to `git-checkout` ancestor → forward reach)
-* `lsp_hover` (bound to `lsp-workspace` → reaches equivalent `lsp-document` sibling)
-* `docker_exec` (bound to `container-instance` → reaches equivalent `fs-file` in container mount)
-
-##### Access Projection
-
-When a tool bound to ancestor resource `R` accesses descendant resource `d`, the **access projection** computes how `d` is identified within `R`'s access space. Each resource type handler implements a `project_access` method that returns an `AccessProjection`:
-
-* **`access_path`**: The path in the binding resource's namespace (e.g., `src/main.py` for filesystem, `file:///repo/src/main.py` for LSP).
-* **`protocol`**: The access mechanism (`filesystem`, `lsp-textdocument`, `container-exec`, `sql`, etc.).
-* **`crosses_sandbox`**: Whether this projection crosses a sandbox boundary (important: an LSP server reading from the real filesystem crosses the sandbox and sees pre-sandbox content).
-* **`read_richness`**: A score indicating how much information this access path provides (LSP: 10, filesystem: 1). Used for read routing.
-
-##### Read/Write Routing
-
-When a virtual resource has multiple physical manifestations reachable through different tools, the system **routes reads and writes through different paths**:
-
-**For writes**: Route to the **canonical write target** — the physical manifestation in the strongest sandbox domain (preference: `git_worktree` > `snapshot` > `copy_on_write` > `transaction_rollback`). This ensures writes are sandbox-tracked and checkpointable.
-
-**For reads**: Route to the **richest available source**, ranked by `read_richness`:
-
-| Source | Richness | Provides |
-|--------|----------|----------|
-| `lsp-document` | 10 | Type info, symbols, diagnostics, go-to-def, references, completions |
-| Semantic index | 5 | Pre-computed symbol index, dependency graph |
-| `fs-file` via git-checkout | 1 | Raw file content, git history |
-| `fs-file` via container mount | 1 | Raw file content |
-| `git-tree-entry` | 1 | File content at specific commit |
-
-The routing algorithm selects the highest-richness source that is available, current (coherence checks pass), and compatible with the query type.
-
-#### Tool Registry
-
-CleverAgents maintains a **Tool Registry** — a persistent catalog of all independently registered tools:
-
-```kroki-plantuml
-@startuml
-skinparam classAttributeIconSize 0
-skinparam classFontSize 13
-skinparam noteFontSize 11
-skinparam defaultFontSize 12
-
-class ToolRegistry {
- - toolIndex : Map
- --
- + add(config_path) : ToolRecord
- + update(name, config_path) : ToolRecord
- + remove(name) : void
- + lookup(name) : ToolRecord
- + list(filters) : ToolRecord[]
-}
-
-class ToolRecord {
- + name : String
- + description : String
- + source : String {mcp|agent_skill|builtin|custom}
- + config_path : String
- + input_schema : JSONSchema
- + output_schema : JSONSchema
- + capability_metadata : CapabilityMetadata
- + resource_slots : List
- + code : String
-}
-
-ToolRegistry "1" *-- "0..*" ToolRecord : indexes >
-
-note right of ToolRegistry
- **Populated by:**
- - agents tool add CLI command
- - Dynamic refresh on MCP notifications
-
- **Consumed by:**
- - Skill registration
- - Actor graph construction
- - Resource binding resolution
- - Plan validation
-end note
-@enduml
-```
-
-The Tool Registry works alongside the Skill Registry (described in the Skills section). Skills reference tools by name from the Tool Registry; the Skill Registry's flattened tool sets are composed from Tool Registry entries plus any anonymous inline tools.
-
-#### Tool Interface and Architecture
-
-Each individual tool — whether independently registered or defined as an anonymous inline tool — conforms to a uniform interface regardless of its source:
-
-```kroki-plantuml
-@startuml
-skinparam classAttributeIconSize 0
-skinparam classFontSize 13
-skinparam defaultFontSize 12
-skinparam linetype ortho
-
-class Tool {
-}
-
-class Identity {
- + name : String
- + qualified_name : String
- + source : ToolSource
-}
-
-class Schema {
- + input_schema : JSONSchema
- + output_schema : JSONSchema
-}
-
-class CapabilityMetadata {
- + read_only : Boolean
- + writes : Boolean
- + write_scope : String
- + idempotent : Boolean
- + checkpointable : Boolean
- + side_effects : List
- + cost_profile : String
- + human_approval_required : Boolean
-}
-
-class ResourceBindings {
- + slots : Map
-}
-
-class ResourceSlot {
- + type : String
- + access : String
- + required : Boolean
- + bind : String
- + from_param : String
- + description : String
-}
-
-interface Lifecycle <> {
- + discover() : ToolDescriptor
- + activate() : void
- + execute(params, ctx) : Result
- + deactivate() : void
-}
-
-class ExecutionContext {
- + sandbox : Sandbox
- + plan : Plan
- + changes : List
- + resources : Map
-}
-
-enum ToolSource {
- mcp
- agent_skill
- builtin
- custom
-}
-
-Tool *-- Identity
-Tool *-- Schema
-Tool *-- CapabilityMetadata
-Tool *-- ResourceBindings
-Tool *-- Lifecycle
-Tool o-- ExecutionContext : uses at runtime >
-ResourceBindings *-- "0..*" ResourceSlot
-Identity --> ToolSource
-@enduml
-```
-
-Every tool implements the same four lifecycle methods. The **tool adapter layer** is responsible for translating source-specific behavior into these methods.
-
-#### Tool Adapter Layer
-
-!!! adr "Architecture Decision"
- The adapter pattern for tool sources and the uniform tool interface are defined in [ADR-011: Tool System](adr/ADR-011-tool-system.md).
-
-Each tool source has a corresponding **adapter** that translates source-specific protocols into the uniform tool interface:
-
-```kroki-plantuml
-@startuml
-skinparam classAttributeIconSize 0
-skinparam classFontSize 13
-skinparam defaultFontSize 12
-
-interface "ToolInterface" as UTI <> {
- + discover() : ToolDescriptor
- + activate() : void
- + execute(params, ctx) : Result
- + deactivate() : void
-}
-
-class MCPToolAdapter {
- + discover() : ToolDescriptor
- .. tools/list RPC → descriptors ..
- + activate() : void
- .. spawn server, init JSON-RPC ..
- + execute(params, ctx) : Result
- .. tools/call RPC → result ..
- + deactivate() : void
- .. shutdown server ..
-}
-
-class AgentSkillAdapter {
- + discover() : ToolDescriptor
- .. parse SKILL.md frontmatter ..
- + activate() : void
- .. load SKILL.md body into agent context ..
- + execute(params, ctx) : Result
- .. agent follows instructions, runs scripts ..
- + deactivate() : void
- .. remove from context ..
-}
-
-class BuiltinAdapter {
- + discover() : ToolDescriptor
- .. return hardcoded descriptors ..
- + activate() : void
- .. no-op ..
- + execute(params, ctx) : Result
- .. call native Python impl ..
- + deactivate() : void
- .. no-op ..
-}
-
-MCPToolAdapter .up.|> UTI
-AgentSkillAdapter .up.|> UTI
-BuiltinAdapter .up.|> UTI
-@enduml
-```
-
-##### MCPToolAdapter
-
-Bridges external MCP servers into the tool model:
-
-1. **discover()**: Spawns the MCP server process (or connects to a remote Streamable HTTP endpoint), performs the MCP `initialize` handshake, negotiates capabilities, then calls `tools/list` to enumerate available tools. Each MCP tool becomes a separate `ToolDescriptor` with its `inputSchema` and inferred capability metadata.
-
-2. **activate()**: Ensures the MCP server process is running and the JSON-RPC connection is healthy. For remote servers, validates the authentication token. Registers for `notifications/tools/list_changed` so CleverAgents can dynamically update available tools.
-
-3. **execute()**: Translates a `Tool.execute(params, ctx)` call into an MCP `tools/call` JSON-RPC request. Before dispatching:
- - Rewrites file paths to sandbox-relative paths
- - Validates params against `inputSchema`
- - Checks capability metadata against plan access policy
- - Creates a checkpoint if the tool is marked checkpointable
-
- After the MCP tool returns its `content[]` response, the adapter:
- - **Error detection**: If `isError: true` is present in the response, the error message is extracted from `content[0].text` per the MCP 1.4.0 protocol (the non-standard top-level `error` key is not used). Falls back to `"unknown error"` when `content` is absent or malformed.
- - Parses the result into the CleverAgents `Result` format
- - Records any resource mutations as `Change` objects in the plan's `ChangeSet`
-
-4. **deactivate()**: Sends a clean shutdown to the MCP server process and closes the JSON-RPC connection.
-
-**Capability inference**: MCP tools expose limited metadata (name, description, inputSchema). The adapter infers extended capability metadata using heuristics:
-- Tools whose names contain `read`, `get`, `list`, `search`, `find` → `read_only: true`
-- Tools whose names contain `write`, `create`, `update`, `delete`, `set` → `writes: true`
-- All inferences can be overridden via the `overrides` block in tool or skill YAML
-
-##### AgentSkillAdapter
-
-Bridges Agent Skills Standard (`SKILL.md` folders) into the tool model. Agent Skills are fundamentally different from MCP tools — they are **instruction-driven** rather than **schema-driven**. An Agent Skill is not a single function call; it is a bundle of procedural knowledge that an LLM agent loads into its context and follows.
-
-1. **discover()**: Scans the configured skill directory for a `SKILL.md` file. Parses only the YAML frontmatter (`name`, `description`, optional `compatibility`, `metadata`, `allowed-tools`) to produce a lightweight `ToolDescriptor`. This metadata is injected into the agent's system prompt in a structured format so the LLM can decide when the skill is relevant:
-
-
- <style="color: cyan; font-weight: 600;">available_agent_skills>
- <style="color: cyan; font-weight: 600;">agent_skill>
- <style="color: cyan; font-weight: 600;">name>deploy-to-staging</style="color: cyan; font-weight: 600;">name>
- <style="color: cyan; font-weight: 600;">description>Deploy the current branch to the staging environment.</style="color: cyan; font-weight: 600;">description>
- <style="color: cyan; font-weight: 600;">tool>local/deploy-staging</style="color: cyan; font-weight: 600;">tool>
- </style="color: cyan; font-weight: 600;">agent_skill>
- </style="color: cyan; font-weight: 600;">available_agent_skills>
-
-
- Discovery is **low-cost** — only ~50–100 tokens per Agent Skill for metadata. The full instructions are not loaded until activation.
-
-2. **activate()**: When the LLM agent determines (or is instructed) that a task matches the skill's description, the adapter loads the full `SKILL.md` Markdown body into the agent's active context. This injects step-by-step instructions, examples, edge cases, and references to bundled scripts. The tool is now "active" — the agent has the procedural knowledge to execute it.
-
- If the skill references additional files (`references/*.md`, `scripts/*.py`, `assets/*`), these are made available on demand — the agent can read them as needed, following the Agent Skills Standard's **progressive disclosure** model.
-
-3. **execute()**: Unlike MCP tools (which are single RPC calls), Agent Skill execution is **agent-mediated**. The LLM agent follows the loaded instructions, potentially:
- - Running bundled scripts via shell execution (sandboxed)
- - Reading reference files for additional context
- - Using other available tools (e.g., built-in file operations) as part of the procedure
- - Making multiple tool calls in sequence to accomplish the workflow
-
- The adapter wraps this execution in a tool execution context so that all mutations are tracked, sandboxed, and checkpointable. Script execution respects the `allowed_tools` and `sandbox_policy` declared in the tool's YAML.
-
-4. **deactivate()**: Removes the skill's instructions from the agent's active context to free up token budget. The skill's metadata remains available for re-activation.
-
-**Key design principle**: Agent Skills extend the agent's *knowledge*, not just its *toolset*. An Agent Skill can teach an agent a multi-step workflow that involves calling multiple other tools, making decisions based on intermediate results, and following domain-specific best practices — something a single MCP tool call cannot express.
-
-##### BuiltinToolAdapter
-
-Wraps CleverAgents' native resource operations as tools:
-
-1. **discover()**: Returns hardcoded `ToolDescriptor` objects for each built-in operation. These descriptors have fully specified capability metadata since the implementation is first-party.
-
-2. **activate()**: No-op. Built-in tools are always available.
-
-3. **execute()**: Calls the native Python implementation directly. Built-in tools operate through the resource abstraction layer, automatically integrating with sandbox path mapping, change tracking, and checkpointing.
-
-4. **deactivate()**: No-op.
-
-**Built-in tool groups:**
-
-**File Operations (`file_operations`):**
-
-read_file(path: str) -> str
-write_file(path: str, content: str) -> None
-edit_file(path: str, edits: list[Edit]) -> None
-delete_file(path: str) -> None
-move_file(source: str, destination: str) -> None
-copy_file(source: str, destination: str) -> None
-
-
-**Directory Operations (`directory_operations`):**
-
-create_directory(path: str) -> None
-list_directory(path: str, pattern: str = "*") -> list[str]
-delete_directory(path: str, recursive: bool = False) -> None
-
-
-**Search Operations (`search_operations`):**
-
-search_files(pattern: str, content_pattern: str = None) -> list[Match]
-find_definition(symbol: str) -> list[Location]
-find_references(symbol: str) -> list[Location]
-
-
-**Git Operations (`git_operations`, when resource is a git repository):**
-
-git_status() -> GitStatus
-git_diff(path: str = None) -> str
-git_log(count: int = 10) -> list[Commit]
-git_blame(path: str) -> list[BlameLine]
-
-
-Each built-in tool:
-* Has fully defined capability metadata
-* Operates through the resource abstraction layer
-* Automatically tracks changes to the ChangeSet
-* Respects sandbox boundaries and deny-lists
-
-#### Tool Capability Metadata (Critical for Safety)
-
-MCP's metadata is not sufficient (read-only/idempotent is not enough; write scope is unclear). CleverAgents extends every tool — regardless of source — with a uniform capability metadata schema:
-
-
-capability:
- read_only: bool # Whether tool only performs read operations
- writes: bool # Whether tool can modify resources
- write_scope: # What the tool is allowed to mutate
- - file_paths: ["src/**", "tests/**"] # Path patterns within bound resources
- - resource_slots: ["repo", "db"] # Resource slot names (from resource bindings)
- - environment: # Execution environment compatibility
- required: container | host | any # Where the tool CAN run (default: any)
- preferred: container | host # Where the tool PREFERS to run (optional)
- specific: <resource-name> # A specific container required (optional)
- idempotent: bool # Whether repeated calls produce same result
- checkpointable: bool # Whether tool supports checkpoint/rollback
- checkpoint_scope: str # What can be rolled back (file, transaction, commit, snapshot)
- side_effects: # Non-reversible effects
- - install_packages
- - mutate_infra
- - send_email
- cost_profile: # Usage constraints
- rate_limit: "10/min"
- estimated_cost: "$0.01/call"
- human_approval_required: bool # Whether a human must approve invocation
-
-
-**Where metadata comes from per source:**
-
-| Source | Metadata origin | Override mechanism |
-|--------|-----------------|--------------------|
-| Built-in | Hardcoded in implementation | Not overridable (authoritative) |
-| MCP | Inferred from tool name/description + MCP annotations | `overrides` block in tool or skill YAML; `override` at skill/actor reference point |
-| Agent Skill | Declared in SKILL.md frontmatter `metadata` + inferred from `allowed-tools` | Tool YAML `capability` block; `override` at skill/actor reference point |
-| Custom | Manually declared in tool YAML `capability` block | `override` at skill/actor reference point (author is the source of truth for registered values) |
-
-#### Read-Only Actions and Tool Access Control
-
-When an action is marked `read_only: true`, it can **only use tools that have `read_only: true`** in their capability metadata. This is enforced at runtime by the tool execution context — any attempt to invoke a tool with `writes: true` from a read-only plan raises a `AccessDeniedError`.
-
-#### Tool Execution Flow
-
-When an LLM agent decides to use a tool (regardless of source), the following flow occurs through the unified execution pipeline:
-
-
-1. LLM generates tool call
- e.g., edit_file(path="src/main.py", changes=[...])
- or: local/github.create_issue(title="Bug fix", body="...")
- or: (activates Agent Skill "deploy-to-staging" via instructions)
- ↓
-2. Tool Router receives call
- - Resolves tool by name from the Tool Registry or actor's skill tool sets
- - Validates parameters against inputSchema
- - Checks capability metadata against plan's access policy:
- • Is this tool in allowed skill categories?
- • Does the plan allow writes?
- • Is human approval required?
- - If denied → return AccessDeniedError to LLM
- ↓
-3. Resource Binding Resolution & Sandbox Context
- - Resolve resource bindings for this tool:
- • Static bindings: already resolved at registration
- • Contextual bindings: resolve from plan's project resources
- • Parameter bindings: resolve from invocation arguments
- - Validate resource type compatibility for each slot
- - Validate access mode (e.g., read_write tool on read_only resource → error)
- - Ensure sandbox exists for each bound resource (lazy sandboxing)
- - Maps logical paths to sandbox-relative paths via bound resource handlers
- - Inject bound resources into ctx.resources[slot_name]
- - If tool is checkpointable → create pre-execution checkpoint
- ↓
-4. Adapter-Specific Execution
- - MCP: sends tools/call JSON-RPC to server process
- - Agent Skill: agent follows loaded SKILL.md instructions,
- running scripts and tools in sandboxed shell
- - Built-in: calls native Python implementation directly
- - Custom: executes inline code with sandboxed context
- ↓
-5. Change Recording
- - If tool modified resources → create Change record(s)
- - Append Change(s) to plan's ChangeSet
- - Update sandbox state
- - If checkpointable → record checkpoint for rollback
- ↓
-6. Result Return
- - Normalize result to uniform Result type
- - Return to LLM agent for continued reasoning
-
-
-#### Change Tracking from Tool Invocations
-
-**Critical Architecture Point:** The ChangeSet is NOT built by parsing LLM output. It is built by recording the effects of tool invocations:
-
-
-class ToolExecutionContext:
- """Context provided to every tool execution, regardless of source."""
-
- def __init__(self, plan: Plan, sandbox: Sandbox,
- resources: dict[str, BoundResource]):
- self.plan = plan
- self.sandbox = sandbox
- self.resources = resources # slot_name → BoundResource
- self.changes: list[Change] = []
-
- def record_change(self, change: Change) -> None:
- """Record a change made by a tool."""
- self.changes.append(change)
- self.plan.changeset.add_change(change)
-
-
-class WriteFileTool:
- """Example: built-in tool for writing files."""
-
- def execute(self, path: str, content: str, ctx: ToolExecutionContext) -> None:
- handler = ctx.sandbox.get_handler(path)
- change = handler.write(path, content, ctx.sandbox)
- ctx.record_change(change)
-
-
-This approach means:
-* Every resource modification is explicit and tracked
-* The ChangeSet accurately reflects what was done, not what was said
-* Rollback is precise (replay inverse of recorded changes)
-* Audit logs show exactly which tool invocation produced each change
-
-#### MCP Integration Details
-
-!!! adr "Architecture Decision"
- MCP adoption, tool-to-skill mapping, and actor-graph usage are defined in [ADR-029: Model Context Protocol (MCP) Adoption](adr/ADR-029-model-context-protocol.md).
-
-CleverAgents integrates with the Model Context Protocol (MCP) to discover and invoke external tools, then normalizes them into the Tool Registry with extended capability metadata and sandbox-aware execution. MCP tools are composed into skills and appear as tool nodes in actor graphs, giving them the same lifecycle, change-tracking, and checkpoint semantics as built-in tools.
-
-##### MCP Concepts Mapping
-
-| MCP Concept | CleverAgents Equivalent | Extension |
-|------------|------------------------|-----------|
-| Tool | Independently registered Tool (source: mcp), referenced by skills | Extended capability metadata (write_scope, checkpointable, side_effects) |
-| Resource | Resource | Extended to support both read AND write operations |
-| Prompt | Action template | Full plan lifecycle (Strategize → Execute → Apply) |
-| Server | MCP Server connection (declared in tool or skill YAML) | Managed by MCPToolAdapter with lifecycle and reconnection |
-| JSON-RPC | Internal adapter protocol | Abstracted behind Tool.execute() |
-
-##### MCP Server Lifecycle Management
-
-CleverAgents manages MCP server processes as part of the tool/skill/actor lifecycle:
-
-```kroki-mermaid
-sequenceDiagram
- participant CLI as CLI
- participant Reg as Registry
- participant ActorRT as Actor Runtime
- participant Adapter as MCPToolAdapter
- participant MCP as MCP Server
-
- note over CLI,Reg: Phase 1 - Registration
- CLI->>Reg: agents tool add or skill add
- Reg->>Reg: Validate server command or endpoint
- Reg->>Reg: Store server config in record
-
- note over ActorRT,MCP: Phase 2 - Actor Activation
- ActorRT->>Adapter: Activate (for each MCP server)
- Adapter->>MCP: Spawn process (stdio) or connect (HTTP)
- Adapter->>MCP: MCP initialize handshake
- MCP-->>Adapter: Capabilities
- Adapter->>MCP: tools list
- MCP-->>Adapter: Tool descriptors
- Adapter->>MCP: Subscribe notifications tools list_changed
-
- note over ActorRT,MCP: Phase 3 - Execution
- ActorRT->>Adapter: LLM generates tool call
- Adapter->>MCP: tools call (JSON-RPC)
- MCP-->>Adapter: Result
- Adapter->>ActorRT: Result + Change tracking
-
- note over ActorRT,MCP: Phase 4 - Deactivation
- ActorRT->>Adapter: Deactivate
- Adapter->>MCP: Clean shutdown
-```
-
-##### Sandbox Path Rewriting for MCP Tools
-
-MCP servers operate on real filesystem paths, but CleverAgents executes plans in sandboxes. The MCPToolAdapter transparently rewrites paths:
-
-
-# Before sending to MCP server:
-# Logical path: "src/main.py"
-# Sandbox path: "/tmp/sandbox-01HXM/worktree/src/main.py"
-# The adapter rewrites the tool arguments so the MCP server
-# operates on sandboxed state without knowing about the sandbox.
-
-
-This ensures MCP tools respect sandbox boundaries even though they have no awareness of the CleverAgents sandbox model.
-
-#### Agent Skills Integration Details
-
-!!! adr "Architecture Decision"
- The Agent Skills standard integration is defined in [ADR-028: Agent Skills Standard (AgentSkills.io)](adr/ADR-028-agent-skills-standard.md).
-
-Agent Skills follow the Agent Skills standard from [https://AgentSkills.io](https://AgentSkills.io), which defines the `SKILL.md` structure and the progressive disclosure model used by the runtime. Within actor graphs, Agent Skills appear as tool nodes — the actor runtime loads the skill's instructions into the LLM context when the node activates, enabling the agent to follow multi-step procedures that may invoke MCP tools, built-in tools, or other Agent Skills during execution.
-
-##### Discovery and Progressive Disclosure
-
-Agent Skills follow a three-tier progressive disclosure model that maps directly to the tool lifecycle:
-
-| Tier | What loads | When | Token cost |
-|------|-----------|------|------------|
-| **Metadata** | `name` + `description` from SKILL.md frontmatter | Tool registration / actor activation | ~50–100 tokens per Agent Skill |
-| **Instructions** | Full SKILL.md Markdown body | When LLM determines task matches the skill (activate phase) | Recommended < 5000 tokens |
-| **Resources** | `scripts/`, `references/`, `assets/` | On demand during execution | Variable |
-
-This means an actor can have dozens of Agent Skill tools available but only pay the token cost for their metadata at startup. Full instructions load only when relevant.
-
-##### Agent Skills vs. MCP Tools: When to Use Which
-
-| Dimension | MCP Tools | Agent Skills |
-|-----------|-----------|--------------|
-| **Interaction model** | Single function call with JSON params/result | Multi-step procedure with instructions the agent follows |
-| **Knowledge type** | "Here is a function you can call" | "Here is how to accomplish a complex task" |
-| **Statefulness** | Stateless per-call | Stateful across multiple tool calls within a procedure |
-| **Authoring** | Implement an MCP server (code) | Write a SKILL.md file (prose + optional scripts) |
-| **Portability** | Any MCP-compatible host | Any Agent Skills-compatible agent |
-| **Best for** | Atomic operations (CRUD, queries, API calls) | Complex workflows (code review processes, deployment procedures, data analysis pipelines) |
-
-Both can coexist in the same skill. A common pattern is an Agent Skill tool that teaches the agent a workflow which involves calling multiple MCP tools:
-
-
-Agent Skill Tool: "local/deploy-staging"
- SKILL.md instructions:
- 1. Run tests using the built-in shell tool
- 2. Create a PR using the GitHub MCP tool (create_pull_request)
- 3. Wait for CI using the GitHub MCP tool (get_check_runs)
- 4. Deploy using the AWS MCP tool (ecs_update_service)
- 5. Verify deployment using the HTTP MCP tool (fetch_url)
-
-
-#### Tool-Level Checkpointability
-
-Each tool declares whether it supports checkpoint/rollback via its capability metadata. Checkpointing behavior varies by source:
-
-| Source | Checkpoint mechanism |
-|--------|---------------------|
-| **Built-in file ops** | Snapshot file state pre-modification; rollback restores file content |
-| **Built-in git ops** | Create commit or stash; rollback via `git reset` / `git checkout` |
-| **MCP tools** | Adapter-created checkpoints of affected resources; rollback replays inverse operations where possible |
-| **Agent Skills** | Composite — each sub-tool-call within the skill's execution is individually checkpointed |
-| **Custom (containerized)** | Filesystem snapshot or container image layer; rollback restores snapshot |
-
-Checkpointing is easier when tool scope is constrained (e.g., "only files within a sandbox worktree + git"). The capability metadata's `checkpoint_scope` field communicates what granularity of rollback is supported.
-
-When `require_checkpoints` is enabled on a plan, the plan may **only** use tools that have `checkpointable: true`. If disabled, the plan may use more generic/unsafe tools with fewer restrictions (useful for low-stakes tasks).
-
-### Validation
-
-!!! adr "Architecture Decision"
- The validation system, gate types, and validation lifecycle are defined in [ADR-013: Validation Abstraction](adr/ADR-013-validation-abstraction.md).
-
-#### What a Validation Is
-
-!!! abstract "Validation in Brief"
- A **Validation** is a specialized subtype of Tool designed to verify that work performed during plan execution meets specified quality, correctness, or compliance criteria. A Validation observes the current state of resources, evaluates a condition, and returns a structured ==pass/fail result==. It never modifies resources — it only reads and reports.
-
-Because Validation extends Tool via standard class inheritance, it is not a separate concept bolted onto the system — it *is* a tool, with additional constraints and metadata. This means validation benefits from the entire tool infrastructure: source types, resource bindings, lifecycle hooks, input/output schemas, registry management, skill composition, and actor graph integration. No parallel system is required.
-
-!!! success "Safety Guarantee"
- Validations are ==always safe to run==. They cannot cause side effects, corrupt state, or require rollback. This enables aggressive parallelization, speculative validation, and retry without concern.
-
-#### Relationship to Tool
-
-A Validation inherits **all** base Tool properties:
-
-| Inherited from Tool | Additional in Validation |
-|---------------------|--------------------------|
-| `name` (namespaced) | `mode` (`required` or `informational`) |
-| `description` | Structured return format enforcement |
-| `source` (custom, mcp, agent_skill, builtin, wrapped) | Read-only enforcement (`writes: false`, `checkpointable: false`) |
-| `input_schema` (JSON Schema) | Attachment scoping (resource-centric, with optional project/plan scope) |
-| `output_schema` (JSON Schema) | Attachment ULID (system-assigned per attachment) |
-| `capability` metadata | `wraps` (optional reference to an existing Tool) |
-| `resource_slots` (resource bindings) | `transform` (Python function to convert wrapped Tool output to validation format) |
-| `lifecycle` hooks (discover/activate/execute/deactivate) | |
-| `code` (inline implementation) | |
-| `mcp_server` / `mcp_tool_name` (MCP source) | |
-| `timeout` | |
-| `idempotent` | |
-
-**Shared namespace**: Validations and plain Tools share the same naming namespace in the Tool Registry. A name like `local/run-tests` can refer to either a Tool or a Validation — but never both simultaneously. Attempting to register a Validation with a name already taken by a plain Tool (or vice versa) results in a conflict error. This shared namespace enables unified management: `agents tool list` shows both types, `agents tool show` works for both, and `agents tool remove` removes either type.
-
-**Superset/subset semantics**: Because Validation extends Tool, a Validation can be used anywhere a Tool is expected — it can appear in a skill's tool list, serve as a tool node in an actor graph, or be invoked directly by an LLM agent. However, a plain Tool **cannot** be used where a Validation is specifically required. For example, `agents validation attach` rejects a name that resolves to a plain Tool rather than a Validation. This distinction is enforced by the `type` discriminator stored in the Tool Registry: each entry is tagged as either `tool` or `validation`.
-
-#### Read-Only Enforcement
-
-!!! danger "Hard Constraint — Not a Convention"
- Validations are **always read-only**:
-
- | Property | Value | Reason |
- | :------- | :---: | :----- |
- | `writes` | `false` | Must never modify, create, or delete resources |
- | `checkpointable` | `false` | No state changes → nothing to checkpoint |
- | `read_only` | `true` | Implicit inverse of `writes` |
-
-This constraint is enforced at ==multiple levels==:
-
-1. **Registration time**: The `agents validation add` command does not accept `--writes`/`--no-writes` or `--checkpointable`/`--no-checkpointable` flags. Any such values in the validation YAML are silently overridden to `false`.
-2. **Runtime enforcement**: The execution runtime treats validation invocations as read-only operations. Resource bindings are resolved with `access: read_only` semantics. If a validation's implementation attempts to write, the sandbox enforces the constraint and the invocation fails.
-3. **Sandbox interaction**: When a validation executes within a plan's sandbox, it reads the sandbox state but cannot modify it — verifying work-in-progress without risk of corruption.
-
-The read-only guarantee has an important architectural consequence: validations are **always safe to run**. They cannot cause side effects, corrupt state, or require rollback. This enables aggressive parallelization, speculative validation (running validations before all work is complete to provide early feedback), and retry without concern for accumulated state changes.
-
-#### Validation Mode
-
-Each Validation has a `mode` that determines how the system responds to failure:
-
-=== "Required (`mode: required`)"
-
- !!! danger "Hard Gate"
- Required validations ==must pass== for execution to proceed to the Apply phase. They define the "definition of done" for a plan.
-
- - When a required validation fails, the execution actor attempts to **fix the underlying issue** (e.g., fix failing tests, correct lint errors) within the bounds of the current strategy, then re-runs the validation.
- - This fix-then-revalidate loop continues up to the configured retry limit.
- - If self-fix is exhausted, the actor may request a strategy revision or escalate to the user, depending on the automation profile.
-
-=== "Informational (`mode: informational`)"
-
- !!! info "Advisory Check"
- Informational validations are ==recorded but do not block== execution. Useful for advisory checks where failure is noteworthy but not blocking.
-
- - When an informational validation fails, the result (including `message` and `data`) is included in the plan's validation summary for human review, but the plan continues normally.
- - Use cases: bundle size reports, code complexity metrics, deprecation warnings, performance benchmarks.
-
-??? tip "Gradual Promotion Pattern"
- The distinction between required and informational allows teams to introduce new validations gradually — start as ==informational== to measure impact, then promote to ==required== once the codebase is clean.
-
-The mode is set at registration time (in the validation YAML or via `--required`/`--informational` on `agents validation add`) and applies globally to that validation. The mode cannot be overridden per-attachment — if different scopes need different enforcement levels for the same check, register separate validations with different names and modes.
-
-#### Structured Return Format
-
-Every Validation must return a JSON object conforming to this structure:
-
-{
- "passed": true,
- "message": "All 247 tests passed, 94% coverage",
- "data": {
- "tests_run": 247,
- "tests_passed": 247,
- "tests_failed": 0,
- "coverage_percent": 94.2,
- "coverage_threshold": 80,
- "duration_seconds": 12.4
- }
-}
-
-
-| Field | Type | Required | Description |
-|-------|------|----------|-------------|
-| `passed` | boolean | **Yes** | Whether the validation passed (`true`) or failed (`false`). This is the only field that drives system behavior (gating for required, recording for informational). |
-| `message` | string | No | Human-readable summary of the result. Displayed in CLI output, plan summaries, and used by the execution actor to understand failures. Should be concise but actionable (e.g., "3 lint errors in src/api/handler.py" rather than just "failed"). |
-| `data` | object | No | Arbitrary structured data in any format the validation chooses. This is the validation's primary output channel for rich, machine-readable results. Examples: test coverage reports, lint error lists with file/line/column, security vulnerability details, performance measurement data. The `data` field has no required schema — each validation defines its own structure. |
-
-**Return format enforcement**: If a validation returns output that is not valid JSON, or valid JSON that lacks the `passed` boolean field, the system treats the invocation as an error (distinct from a validation failure). The validation result is recorded as `"passed": false` with a system-generated `message` indicating the malformed return, and the original output is preserved in `data.raw_output` for debugging.
-
-The structured return format serves multiple consumers:
-- **The execution actor** reads `message` and `data` to understand failures and attempt fixes. A well-structured `data` field (e.g., with file paths and line numbers) enables more targeted fix attempts.
-- **The plan summary** records all validation results for human review and auditing.
-- **Downstream automation** (CI scripts, dashboards) can parse `data` programmatically via `agents --format json plan show`.
-
-#### Attachment Scoping
-
-Validations are not globally active — they must be explicitly **attached** to one or more scopes to take effect. This attachment model provides fine-grained control over which validations run for which work.
-
-##### Attachment Model
-
-A validation is always attached to a resource. The optional `--project` or `--plan` flag controls the scope under which the validation is active for that resource:
-
-1. **Direct attachment** (`agents validation attach [args...]`)
-
- The validation is always active when that resource is accessed by any plan, regardless of which project or plan is involved. This scope is for invariants that must hold for a resource in all contexts — e.g., a lint check that must pass for a repository no matter what project is using it.
-
- Use cases:
- - Repository-wide lint/format checks
- - Schema validation on database resources
- - Security scanning on any codebase resource
- - License compliance checks
-
-2. **Project-scoped attachment** (`agents validation attach --project [args...]`)
-
- The validation is active only for that resource when it is being interacted with through the specified project. Different projects using the same resource can have different validation requirements. This is the most common attachment scope.
-
- Use cases:
- - Unit test suites specific to a project
- - Type checking for a TypeScript project (not relevant for a Python project using the same repo)
- - API compatibility checks for a microservice project
- - Bundle size checks for a frontend project
-
-3. **Plan-scoped attachment** (`agents validation attach --plan [args...]`)
-
- The validation is active only for that resource when it is being interacted with through the specified plan. This is the most targeted scope, useful for one-off or experimental validations.
-
- Use cases:
- - Temporary extra checks during a risky migration
- - One-time regression validation for a specific bug fix
- - Experimental validations being tested before promoting to project scope
- - User-added ad hoc checks during an interactive session
-
-Since validations accept arguments, the same validation can be attached to the same resource multiple times with different arguments. For example, `local/run-tests` might be attached to `local/api-repo` through project `local/api-service` with `--coverage-threshold 90` and also through project `local/staging` with `--coverage-threshold 70`.
-
-##### Attachment Resolution
-
-When a plan executes, the system collects all applicable validations for each resource the plan accesses. The resolution algorithm:
-
-1. **Collect direct validations**: For every resource the plan accesses, collect all validations directly attached to that resource (no scope flag).
-2. **Collect project-scoped validations**: For every resource the plan accesses, collect all validations attached to that resource with a `--project` scope matching the plan's target project.
-3. **Collect plan-scoped validations**: For every resource the plan accesses, collect all validations attached to that resource with a `--plan` scope matching the plan itself.
-4. **Union**: Take the union of all collected validations per resource. If the same validation name appears from multiple scopes for the same resource (e.g., attached both directly and through a project), each attachment is treated as a distinct invocation — they may have different arguments and thus produce different results. When the same validation name appears from multiple scopes with identical arguments, the most specific scope wins (plan > project > direct) and the validation runs once.
-5. **Child plan inheritance**: Child plans (spawned via `subplan_spawn` or `subplan_parallel_spawn`) inherit their parent plan's project-scoped and plan-scoped resource/validation associations by default. Direct validations are collected independently based on which resources the child plan accesses (which may differ from the parent).
-
-##### Attachment Identity
-
-Each attachment is identified by a system-assigned **ULID**. This ULID is:
-- Returned by `agents validation attach` when the attachment is created.
-- Displayed by `agents tool show ` in the "Attached To" section and by `agents project show` in the validations list.
-- Required by `agents validation detach ` to remove a specific attachment.
-
-The ULID is necessary because the same validation can be attached to the same resource multiple times — directly, through different projects, through different plans, and even to the same resource and scope with different arguments. The ULID uniquely identifies which specific attachment to remove.
-
-##### Attachment Arguments
-
-When attaching a validation, optional arguments can be provided after the validation name:
-
-
-$ agents validation attach --project local/api-service local/api-repo local/run-tests --coverage-threshold 90
-$ agents validation attach --project local/staging-api local/api-repo local/run-tests --coverage-threshold 70
-
-
-These arguments are stored with the attachment and passed to the validation tool's `input_schema` at execution time. This enables a single validation definition to be reused across scopes with different thresholds or configurations. If no arguments are provided, the validation uses its `input_schema` defaults.
-
-#### Validation Lifecycle in Plan Execution
-
-Validation participates in the plan lifecycle at well-defined points:
-
-##### During Strategize
-
-Validations are **not executed** during Strategize. However, the strategy actor is aware of which validations are attached (via the attachment resolution described above) and factors them into the strategy:
-- The strategy may allocate time/tokens for validation fix-up loops.
-- The strategy may note that certain validations are informational and thus non-blocking.
-- The decision tree may include `validation_checkpoint` decisions that mark points where validation should be run.
-
-##### During Execute
-
-Validation is the **final step** of the Execute phase. The execution actor's workflow proceeds as follows:
-
-1. **Perform work**: The actor executes the strategy — writing code, modifying resources, running tools — all within the sandbox.
-2. **Collect applicable validations**: The system resolves all validations from the resource-direct, project, and plan scopes (as described in Attachment Resolution above).
-3. **Execute validations**: Each applicable validation is invoked as a standard tool call. The validation reads the sandbox state and returns its structured result. Validations may be run in parallel since they are read-only and cannot interfere with each other.
-4. **Process results**:
- - **All required validations pass**: Execution is complete. The plan transitions to the review/Apply phase.
- - **Any required validation fails**: The execution actor enters the fix-then-revalidate loop (see Validation Failure Handling below).
- - **Informational validations fail**: Results are recorded in the plan's validation summary. No fix attempts are made.
-
-##### Validation is Not Run During Apply
-
-!!! warning "Apply is the Point of No Return"
- Validation runs during Execute, **not** during Apply. By the time a plan reaches Apply, all required validations have already passed. Apply commits the sandbox changes to the real resources.
-
- If post-apply verification is needed (e.g., integration tests against the real system), implement it as a separate plan or external CI pipeline — ==not as a validation attachment==.
-
- **Rationale**: Introducing validation during Apply would create situations where committed changes might need to be rolled back, defeating the purpose of the sandbox model.
-
-#### Validation Failure Handling
-
-Because validations are tools, their execution follows the standard tool invocation flow. Each validation returns a structured JSON result with `{ "passed": true/false, "message": "...", "data": {...} }`. The execution actor interprets these results based on the validation's `mode`.
-
-##### Required Validation Failure
-
-When a **required** validation returns `"passed": false` during Execute:
-
-1. **Diagnosis**: The execution actor examines the validation's `message` and `data` fields to understand the nature of the failure. A well-structured `data` field (e.g., with specific file paths, line numbers, error messages) enables more targeted fix attempts.
-
-2. **Self-fix attempt**: The execution actor attempts to fix the issue within the bounds of the current strategy. For example:
- - A failing test: the actor reads the test output, identifies the broken assertion, and fixes the code.
- - A lint error: the actor reads the lint report and corrects the formatting or style violation.
- - A type error: the actor reads the type checker output and fixes the type mismatch.
-
-3. **Re-validation**: After each fix attempt, the actor re-invokes the failing validation. If it passes, the loop ends. If it still fails, the actor examines the new `message` and `data` for the updated failure state.
-
-4. **Retry limit**: The fix-then-revalidate loop runs up to the configured retry limit (default: 3 attempts, configurable per plan or in the automation profile). After the limit is reached, self-fix stops.
-
-5. **Strategy revision**: If the actor determines that the failure cannot be resolved within the current strategy's constraints (e.g., the strategy says "modify only `handler.py`" but the test failure requires changes to `model.py`), it may request a **strategy revision**. This triggers a re-run of the Strategize phase for the affected subtree of the decision tree. Whether this happens automatically or requires user approval depends on the automation profile's `delete_content` flag.
-
-6. **Escalation**: If strategy revision also fails, or if the automation profile requires human approval for strategy changes, the plan pauses and requests user guidance via `agents plan prompt`:
-
-
- agents plan prompt <plan_id> "Try using mock objects for the database tests"
-
-
-7. **Terminal failure**: If the user does not intervene (or explicitly cancels), the plan fails with `state: failed`. The sandbox is preserved for inspection.
-
-The flow can be summarized as:
-
-
-validate → fail → fix → re-validate → fail → fix → re-validate → ... → retry limit
- → request strategy revision → re-strategize → re-execute → validate
- → still failing → escalate to user → user provides guidance → resume
- → still failing → plan fails
-
-
-##### Informational Validation Failure
-
-When an **informational** validation returns `"passed": false`:
-
-1. The result (including `message` and `data`) is recorded in the plan's `validation_summary`.
-2. Execution continues normally — no fix attempts, no blocking, no escalation.
-3. The informational failure is visible in `agents plan show`, plan summaries, and any rendering format.
-4. Informational failures may trigger notifications (if configured) but never block plan progression.
-
-##### Validation Error vs. Validation Failure
-
-!!! note "Important Distinction"
- | Condition | Meaning | Handling |
- | :-------- | :------ | :------- |
- | **Validation failure** (`passed: false`) | Validation ran successfully, condition not met | Mode-specific (fix loop for required, record for informational) |
- | **Validation error** | Validation itself failed to execute (runtime exception, timeout, malformed return) | ==Always treated as required failure== regardless of mode |
-
-When a validation error occurs:
-- The result is recorded with `passed: false`, a system-generated `message` describing the error, and the raw error details in `data`.
-- If the validation is required, the fix-then-revalidate loop attempts to resolve the error (e.g., by fixing a broken test configuration).
-- If the validation is informational, the error is still recorded but does not block.
-- Repeated validation errors (e.g., the validation tool itself is misconfigured) are surfaced prominently in the plan summary.
-
-#### Validation in Actor Graphs
-
-Because Validations are Tools, they can appear as **tool nodes** in actor graphs. This enables explicit, deterministic validation steps within workflows:
-
-
-# Actor graph with explicit validation nodes
-graph:
- nodes:
- - name: implement
- type: agent
- actor: local/code-writer
- - name: run_tests
- type: tool
- tool: local/run-tests # This is a Validation (subtype of Tool)
- - name: lint_check
- type: tool
- tool: local/lint-check # Also a Validation
- - name: fix_issues
- type: agent
- actor: local/code-fixer
- edges:
- - [implement, run_tests]
- - [implement, lint_check]
- - condition: "not run_tests.passed or not lint_check.passed"
- from: [run_tests, lint_check]
- to: fix_issues
- - [fix_issues, run_tests] # Retry loop
- - [fix_issues, lint_check]
-
-
-When a Validation appears as a tool node, its return value is available to downstream nodes via the standard graph data flow. The `passed`, `message`, and `data` fields can be used in edge conditions, passed as input to subsequent nodes, or logged for the plan summary.
-
-This graph-based approach complements the attachment model: attached validations run automatically at the end of Execute (the system handles collection and invocation), while graph-embedded validations run at explicitly defined points in the workflow (the actor author controls placement). Both approaches can coexist — a plan may have attached validations that run at the end plus graph-embedded validations that run at intermediate checkpoints.
-
-#### Validation and Skills
-
-Validations can be **included in skills** just like any other tool. Since a Validation is a Tool, a skill YAML can reference it by name:
-
-
-# Skill: local/python-quality
-skill:
- name: local/python-quality
- description: "Python code quality tools and validations"
- tools:
- - local/run-tests # Validation (required)
- - local/lint-check # Validation (required)
- - local/type-check # Validation (required)
- - local/format-code # Plain Tool (writes)
- - local/run-benchmarks # Validation (informational)
-
-
-When an actor references this skill, the Validations are available as tools that the LLM agent can call. This is distinct from validation attachment — being included in a skill makes the validation *callable* by the actor's LLM, but does not make it a *required gate*. Attachment determines gating; skill inclusion determines availability.
-
-A common pattern: a team's skill includes their validations for on-demand use by the LLM (the actor can run tests proactively during development), while the same validations are also attached to the project (ensuring they run as a mandatory gate at the end of Execute even if the LLM forgot to run them).
-
-#### Tool Wrapping
-
-A Validation can **wrap an existing Tool**, reusing its implementation without duplicating code. This is the recommended approach when a plain Tool already performs the work a Validation needs (e.g., running tests, generating a report, scanning for vulnerabilities) and the Validation only needs to interpret the Tool's output as pass/fail.
-
-##### The Problem
-
-Consider a team that already has a registered Tool called `local/run-tests` — it runs the test suite and returns a structured report (test counts, coverage data, output logs). Now they want a Validation that gates execution on all tests passing. Without wrapping, they would need to duplicate the entire test-running implementation inside a new Validation YAML, differing only in the final pass/fail interpretation. This duplication creates maintenance burden: if the test runner configuration changes, both the Tool and the Validation must be updated.
-
-##### The Solution: `wraps` + `transform`
-
-A Validation YAML can declare a `wraps` field that references an existing registered Tool by name. At execution time, the system invokes the wrapped Tool, captures its output, and passes that output through a `transform` function that produces the Validation's structured return format (`{ "passed", "message", "data" }`).
-
-
-# validations/tests-pass.yaml
-# Wraps the existing local/run-tests tool — no test logic duplicated
-
-name: local/tests-pass
-description: "Validate that all unit tests pass (wraps local/run-tests)"
-
-wraps: local/run-tests
-
-transform: |
- def transform(tool_output):
- passed = tool_output.get("returncode") == 0
- return {
- "passed": passed,
- "message": "All tests passed" if passed else f"Tests failed (exit {tool_output.get('returncode')})",
- "data": tool_output
- }
-
-validation:
- mode: required
-
-timeout: 600
-
-
-When `local/tests-pass` is invoked (either by attachment or direct call):
-1. The system resolves `wraps: local/run-tests` to the registered Tool.
-2. The Validation's input arguments are mapped to the wrapped Tool's input arguments using the `argument_mapping` (see below). If no `argument_mapping` is defined, the Validation's input arguments are passed through to the wrapped Tool as-is.
-3. The wrapped Tool is invoked with the mapped arguments.
-4. The wrapped Tool's output is captured (whatever it returns — JSON, text, etc.).
-5. The `transform` function is called with the captured output.
-6. The `transform` function returns the Validation's structured result (`{ "passed", "message", "data" }`).
-
-This is opaque to the consumer — the caller sees only a standard Validation with its structured return format. The wrapping is an implementation detail.
-
-##### What Gets Inherited
-
-When a Validation uses `wraps`, the following properties are **inherited from the wrapped Tool** unless explicitly overridden in the Validation YAML:
-
-| Property | Inherited? | Override behavior |
-|----------|-----------|-------------------|
-| `input_schema` | Yes | If the Validation YAML defines `input_schema`, it replaces the wrapped Tool's schema entirely. If omitted, the Validation accepts the same inputs as the wrapped Tool. When a custom `input_schema` is defined, an `argument_mapping` should also be provided to map the Validation's inputs to the wrapped Tool's expected inputs. |
-| `argument_mapping` | No | Not inherited. When present, maps the Validation's input arguments to the wrapped Tool's input arguments. When absent, input arguments are passed through unchanged. See the Argument Mapping section. |
-| `resource_slots` | Yes | If the Validation YAML defines `resource_slots`, they replace the wrapped Tool's slots. If omitted, the Validation inherits the same resource bindings. |
-| `timeout` | Yes | If the Validation YAML specifies `timeout`, it overrides. If omitted, the wrapped Tool's timeout is used. |
-| `description` | No | The Validation must provide its own description (it serves a different purpose than the wrapped Tool). |
-| `source` | No | Ignored — the source is implicitly `wrapped`. The Validation does not declare `source` or `code`. |
-| `capability` | No | Overridden — `writes` and `checkpointable` are forced to `false` regardless of the wrapped Tool's values. |
-
-##### The `transform` Function
-
-The `transform` field contains a Python function that converts the wrapped Tool's output to the Validation's return format. The function signature is:
-
-
-def transform(tool_output) -> dict:
- """
- Args:
- tool_output: The wrapped Tool's return value. The type depends on the
- Tool's implementation — typically a dict (for JSON-returning
- tools) but may be a string or other type.
- Returns:
- A dict with at minimum {"passed": bool}. May also include
- "message" (str) and "data" (any).
- """
-
-
-The `transform` function runs in a sandboxed Python environment with no write access to the filesystem or network. It is a pure data transformation — it receives the Tool's output and produces the Validation's result. If the `transform` function raises an exception, the Validation is treated as an error (see Validation Error vs. Validation Failure).
-
-If `transform` is omitted, the system applies a **default transform** that expects the wrapped Tool's output to already contain a `passed` field:
-- If the output is a dict with a `passed` boolean, it is used as-is (pass-through).
-- If the output is a dict without `passed`, the validation errors with a message indicating the wrapped tool's output is not in validation format and a `transform` function is required.
-- If the output is not a dict, the validation errors similarly.
-
-##### Argument Mapping (`argument_mapping`)
-
-When a Validation wraps a Tool, the Validation may accept different input arguments than the wrapped Tool. The `argument_mapping` field specifies how the Validation's input arguments map to the wrapped Tool's expected input arguments. This is necessary when:
-
-- The Validation's `input_schema` defines different field names than the wrapped Tool's `input_schema`.
-- The Validation accepts a subset of the wrapped Tool's arguments and wants to provide fixed values for the rest.
-- The Validation renames arguments for clarity in the validation context.
-
-The `argument_mapping` is a dictionary where keys are the wrapped Tool's input parameter names and values are either:
-- A string referencing a Validation input parameter name (forwarded as-is).
-- A fixed literal value (string, number, boolean) that is always passed to the wrapped Tool regardless of the Validation's inputs.
-
-
-# Example: Validation wraps local/run-tests but renames arguments
-name: local/tests-pass
-wraps: local/run-tests
-
-argument_mapping:
- test_directory: source_dir # Forward Validation's "source_dir" → Tool's "test_directory"
- coverage_enabled: true # Always pass true for coverage_enabled
- verbose: false # Always pass false for verbose
-
-transform: |
- def transform(tool_output):
- return {"passed": tool_output.get("returncode") == 0, "message": "Tests completed"}
-
-validation:
- mode: required
-
-
-When `argument_mapping` is **omitted**, the Validation's input arguments are passed through to the wrapped Tool unchanged. This is the common case when the Validation inherits the wrapped Tool's `input_schema` without modification (i.e., the Validation YAML does not define its own `input_schema`).
-
-When `argument_mapping` is **present**, only the mapped arguments are forwarded to the wrapped Tool. Any Validation input arguments not referenced in the mapping are not passed to the wrapped Tool. Any wrapped Tool arguments not listed as keys in the mapping receive no value (and must either be optional in the Tool's schema or have defaults).
-
-##### Read-Only Semantics for Wrapped Tools
-
-Validations are always read-only, but the wrapped Tool may not be. The wrapping enforces read-only semantics:
-
-- The wrapped Tool is invoked within the Validation's read-only execution context. Resource bindings are resolved with `access: read_only` regardless of what the wrapped Tool's `resource_slots` specify.
-- If the wrapped Tool's implementation attempts to write (e.g., mutate files, insert database rows), the sandbox enforces the read-only constraint and the invocation fails as a validation error.
-- At registration time, if the wrapped Tool has `writes: true`, the system emits a **warning** (not an error) advising the user that the wrapped Tool is marked as writing and may fail at runtime under read-only enforcement. This allows wrapping tools that are conservatively marked `writes: true` but whose actual behavior for the given inputs is read-only.
-
-This design means wrapping is always safe from the Validation perspective — the worst case is a runtime error, never an unintended write.
-
-##### Multiple Validations Wrapping the Same Tool
-
-The same Tool can be wrapped by multiple Validations with different `transform` functions and different modes. This is a common pattern:
-
-
-# The base tool runs tests and produces a comprehensive report
-# Tool: local/run-tests (already registered)
-
-# Validation 1: All tests must pass (required)
-# validations/tests-pass.yaml
-name: local/tests-pass
-description: "All unit tests must pass"
-wraps: local/run-tests
-transform: |
- def transform(tool_output):
- return {
- "passed": tool_output.get("returncode") == 0,
- "message": f"{tool_output.get('tests_passed', 0)}/{tool_output.get('tests_run', 0)} tests passed",
- "data": tool_output
- }
-validation:
- mode: required
-
-
-
-# Validation 2: Coverage must exceed threshold (informational for now)
-# validations/coverage-check.yaml
-name: local/coverage-check
-description: "Coverage must exceed threshold (advisory)"
-wraps: local/run-tests
-transform: |
- def transform(tool_output):
- coverage = tool_output.get("coverage_percent", 0)
- threshold = 80
- return {
- "passed": coverage >= threshold,
- "message": f"Coverage: {coverage}% (threshold: {threshold}%)",
- "data": {"coverage_percent": coverage, "threshold": threshold}
- }
-validation:
- mode: informational
-
-
-Both validations wrap the same `local/run-tests` tool but extract different signals. When both are attached to the same project, each Validation independently invokes the wrapped Tool and applies its own `transform` function. A future optimization may deduplicate these invocations when the forwarded arguments are identical (see Validation Ordering and Parallelism).
-
-##### When to Wrap vs. When to Write From Scratch
-
-| Scenario | Approach |
-|----------|----------|
-| An existing Tool already does the work; you just need pass/fail | **Wrap it** — use `wraps` + `transform` |
-| Multiple Validations need different interpretations of the same Tool's output | **Wrap it** multiple times with different transforms |
-| The validation logic is simple and self-contained (e.g., run a shell command, check exit code) | **Write from scratch** — use `source: custom` with inline `code` |
-| The validation needs logic that the existing Tool doesn't provide (different inputs, different execution) | **Write from scratch** — the Tool's implementation isn't relevant |
-| The existing Tool has side effects that are incompatible with read-only enforcement | **Write from scratch** — wrapping would fail at runtime |
-
-#### Validation Data Model
-
-The validation-related fields stored in the plan data model:
-
-| Field | Location | Description |
-|-------|----------|-------------|
-| `validation_summary` | `plan.execution` | Array of validation results collected during Execute. Each entry includes the validation name, mode, `passed`, `message`, `data`, execution duration, and attempt number. |
-| `final_validation_results` | `plan.apply` | Snapshot of the final validation state at the time execution completed (all required validations passing). Identical to the last state of `validation_summary` but stored separately for quick reference. |
-| `validation_attempts` | `plan.execution` | Total number of validation invocations across all fix-then-revalidate loops. Useful for understanding how much effort was spent on validation remediation. |
-| `validation_fix_history` | `plan.execution` | Per-validation log of fix attempts. Each entry records: the validation that failed, the fix the actor applied, and whether the subsequent re-validation passed. Enables auditing of the fix-then-revalidate process. |
-
-A validation result entry in `validation_summary`:
-
-
-{
- "validation": "local/run-tests",
- "mode": "required",
- "passed": true,
- "message": "All 247 tests passed, 94% coverage",
- "data": {
- "tests_run": 247,
- "tests_passed": 247,
- "coverage_percent": 94.2
- },
- "duration_ms": 12400,
- "attempt": 2,
- "attachment_id": "01HXM5A1B2C3D4E5F6G7H8J9K0",
- "attachment_resource": "local/api-repo",
- "attachment_scope": "project",
- "attachment_scope_target": "local/api-service"
-}
-
-
-#### Validation Ordering and Parallelism
-
-Since validations are read-only, they are inherently safe to run in parallel. The execution runtime may parallelize validation invocations subject to:
-
-- **Resource constraints**: Validations that require significant compute (e.g., full test suites) may be serialized to avoid resource exhaustion.
-- **Timeout budgets**: Each validation has its own `timeout` (from the tool configuration). The total validation phase has an implicit budget derived from the sum of individual timeouts, but the runtime may use parallelism to finish faster.
-- **Dependency hints**: A future extension may allow declaring ordering dependencies between validations (e.g., "run lint before tests" to fail fast on formatting issues). Currently, all validations run independently.
-
-**Wrapped Tool deduplication (deferred)**: When multiple Validations wrap the same Tool (via `wraps`), a future optimization could invoke the wrapped Tool once and fan out its output to each Validation's `transform` function. However, deduplication is only valid when multiple Validations wrap the same Tool **and** receive the exact same forwarded arguments (after `argument_mapping` resolution) **and** are evaluated in the same calling chain. This complexity — particularly around argument equivalence and cache invalidation during fix-then-revalidate loops — means deduplication is **deferred for future design**. The current implementation invokes the wrapped Tool separately for each Validation that wraps it.
-
-The recommended execution strategy is:
-1. Run all validations in parallel (each Validation independently invokes its wrapped Tool if applicable).
-2. Collect results.
-3. If any required validation fails, fix and re-run only the failing validations (not all of them).
-4. Repeat until all pass or retry limit is reached.
-
-#### Registering and Managing Validations
-
-Validations are **registered** via `agents validation add` and **attached** via `agents validation attach`. These are the only validation-specific CLI commands. All other management operations use the standard `agents tool` commands:
-
-| Operation | Command | Notes |
-|-----------|---------|-------|
-| **Register** | `agents validation add --config ` | Validation-specific. Config file defines all properties including mode (`required`/`informational`). |
-| **Update** | `agents validation add --config --update` | Uses the `--update` flag to overwrite existing registration. |
-| **Attach** | `agents validation attach [--project\|--plan] [args...]` | Returns an attachment ULID. Resource is always required; project/plan scope is optional. |
-| **Detach** | `agents validation detach [--yes] ` | Uses the attachment ULID, not the validation name. |
-| **List** | `agents tool list --type validation` | Shared with tools. Use `--type validation` to filter. |
-| **Show** | `agents tool show ` | Shows validation-specific fields when the entry is a Validation. |
-| **Remove** | `agents tool remove ` | Shared with tools. Automatically detaches from all scopes. |
-
-See the **agents validation** and **agents tool** CLI Reference sections for full command details and examples.
-
-#### Typical Validation Workflow
-
-A typical workflow for setting up validations on a project:
-
-
-# 1. Define validation YAML files
-# (see Configuration > Validation Configuration Files for schema and examples)
-
-# 2. Register validations
-agents validation add --config ./validations/run-tests.yaml
-agents validation add --config ./validations/lint-check.yaml
-agents validation add --config ./validations/type-check.yaml
-agents validation add --config ./validations/check-bundle-size.yaml
-
-# 3. Attach to resource through a project (active only when this resource is accessed through this project)
-agents validation attach --project local/api-service local/api-repo local/run-tests
-agents validation attach --project local/api-service local/api-repo local/type-check
-agents validation attach --project local/api-service local/api-repo local/check-bundle-size
-
-# 4. Attach directly to a resource (always active for any plan accessing this resource)
-agents validation attach local/api-repo local/lint-check
-
-# 5. Verify setup
-agents tool list --type validation --namespace local
-agents tool show local/run-tests
-
-# 6. Run a plan — validations execute automatically at end of Execute phase
-agents plan use local/implement-feature local/api-service
-
-
-#### Design Rationale
-
-**Why Validation extends Tool rather than being a separate concept**:
-- Reuses the entire tool infrastructure (registry, bindings, lifecycle, sources, schemas) without duplication.
-- Validations can be composed into skills, used in actor graphs, and invoked by LLM agents — all for free.
-- A single namespace and registry avoids the complexity of managing two parallel systems.
-- Tool-aware features (resource bindings, MCP integration, Agent Skills) apply to validations automatically.
-
-**Why read-only is enforced rather than advisory**:
-- Validations that modify state defeat the purpose of the sandbox model.
-- Read-only guarantees enable safe parallelization and retry without side effects.
-- It makes validations categorically safe — no risk analysis needed for running a validation.
-
-**Why attachments use ULIDs rather than name+scope pairs**:
-- A validation may be attached to the same scope multiple times with different arguments.
-- ULIDs provide an unambiguous handle for removal without complex composite keys.
-- Consistent with the ULID-based identity model used for plans, resources, and decisions.
-
-**Why validation runs during Execute, not Apply**:
-- Apply is a controlled commit step. Validation failures during Apply would require rolling back committed changes.
-- The sandbox model ensures all verification occurs before the point of no return.
-- Post-apply verification (integration tests, smoke tests) is a separate concern best handled by external CI or follow-up plans.
-
-### Skills
-
-!!! adr "Architecture Decision"
- The skill composition model, skill inclusion, and tool bundling are defined in [ADR-012: Skill System](adr/ADR-012-skill-system.md).
-
-#### What a Skill Is
-
-!!! adr "Architecture Decision"
- The canonical definition of a skill — its four tool sources, flattening model, and role as the unit of capability assignment — is formalized in [ADR-030: Skill Abstraction Definition](adr/ADR-030-skill-abstraction-definition.md).
-
-A **skill** is a namespaced, reusable **collection of tools** that is registered in the system via its own YAML configuration file and managed through `agents skill` CLI commands. Skills are the unit of capability composition in CleverAgents — they define *what an actor can do* by assembling tools into coherent, reusable bundles.
-
-A skill is **not** a single tool. It is a **container** that references one or more tools (by name from the Tool Registry) and/or defines anonymous inline tools, along with metadata describing the collection's purpose, capabilities, and safety characteristics. Tools are independently registered, callable operations (see the **Tools** section above). Skills organize them into reusable groups.
-
-**Key properties of a skill:**
-
-* **Named and namespaced**: Skills follow the same `/` naming convention as actors, tools, actions, and plans (e.g., `local/github-ops`, `cleverthis/file-management`, `local/deploy-tools`).
-* **Defined in their own YAML files**: Skills are NOT defined inline in actor configurations. They have their own configuration files and are managed as independent, reusable entities.
-* **A collection of tools**: Each skill references named tools from the Tool Registry and/or defines anonymous inline tools. Skills can also expose tools from MCP servers, Agent Skills Standard folders, and built-in tool groups.
-* **Hierarchically composable**: A skill can include other skills by reference, inheriting all of their tools. This enables layered composition — a "full-stack" skill might include a "file-ops" skill, a "git-ops" skill, and a "github" skill. When including a sub-skill, individual tool metadata can optionally be overridden.
-* **Referenced by actors**: Actors reference skills by fully-qualified name. The actor's graph gains access to all tools within the referenced skills.
-
-#### The Skill / Tool Distinction
-
-!!! adr "Architecture Decision"
- The formal distinction between skills (containers) and tools (atomic operations), and the source-agnostic flattening model, are defined in [ADR-030: Skill Abstraction Definition](adr/ADR-030-skill-abstraction-definition.md).
-
-```kroki-plantuml
-@startuml
-skinparam packageStyle rectangle
-skinparam defaultFontSize 12
-skinparam componentFontSize 12
-
-package "Skill: local/devops-toolkit" as Skill {
- package "builtin: file_operations" as FileOps {
- component [read_file()] as T1
- component [write_file()] as T2
- component [edit_file()] as T3
- }
-
- package "builtin: git_operations" as GitOps {
- component [git_status()] as T4
- component [git_diff()] as T5
- }
-
- package "mcp: github-server" as GH {
- component [create_issue()] as T6
- component [create_pr()] as T7
- component [list_repos()] as T8
- }
-
- package "custom" as Custom {
- component [run_migrations()] as T9
- }
-
- package "Included Skills" as Includes {
- component [local/pdf-processing\n(adds pdf tools)] as I1
- component [local/data-analysis\n(adds analysis tools)] as I2
- }
-}
-@enduml
-```
-
-**Tools** are independently registered, atomic units of execution (see the **Tools** section above for full details). Each tool has:
-* A namespaced name, description, and JSON Schema for inputs/outputs
-* Its own YAML configuration file, registered via `agents tool add`
-* A source type (mcp, agent_skill, builtin, custom)
-* Capability metadata (read_only, writes, checkpointable, etc.)
-* A lifecycle: `discover()`, `activate()`, `execute(params, ctx)`, `deactivate()`
-
-**Skills** are the organizational units. Each skill has:
-* A namespaced name
-* A YAML configuration file defining its tool composition
-* Zero or more **named tool references** (pointing to independently registered tools in the Tool Registry)
-* Zero or more **anonymous inline tools** (one-off tools defined directly in the skill YAML)
-* Zero or more included child skills (whose tools are merged in, with optional per-tool metadata overrides)
-* Tool sources: MCP servers, Agent Skills folders, built-in tool groups
-* Metadata (description, capability summary)
-
-When an actor references a skill, it gains access to the **flattened set of all tools** — named tool references, anonymous tools, tools from MCP/Agent Skills/builtins, and those inherited from included child skills.
-
-#### Skill Configuration (YAML)
-
-Skills are defined in their own YAML configuration files, separate from tool and actor configurations. A skill YAML file declares which registered tools it includes (by name), which other skills it includes, and optionally defines anonymous inline tools:
-
-
-# File: skills/devops-toolkit.yaml
-cleveragents:
- version: "3.0"
-
-skill:
- name: local/devops-toolkit
- description: "Full-stack development tools for file ops, git, GitHub, and deployment"
-
- # ── Named Tool References ───────────────────────────────
- # Reference independently registered tools by name.
- # These tools must already be registered via `agents tool add`.
- # Optional metadata overrides can be applied per tool.
- tools:
- - local/run-migrations # Simple reference, use as registered
- - name: local/deploy-staging # Reference with metadata override
- override:
- capability:
- human_approval_required: true # Require approval in this skill context
-
- # ── Include other skills ─────────────────────────────────
- # All tools from included skills become part of this skill.
- # Included skills must already be registered in the system.
- # Individual tools from included skills can have metadata overridden.
- includes:
- - local/file-ops # built-in file + directory + search tools
- - local/git-ops # built-in git tools
- - name: local/github # MCP-based GitHub tools, with per-tool overrides
- tool_overrides:
- - tool: local/create-github-issue
- override:
- capability:
- write_scope: [github:issues:org-only]
-
- # ── MCP Server Tools ─────────────────────────────────────
- # Connect to MCP servers and expose their tools.
- # Tools discovered from MCP servers are auto-registered in the
- # Tool Registry if not already present.
- mcp_servers:
- - name: linear
- command: "npx @anthropic/mcp-linear"
- env:
- LINEAR_API_KEY: "${LINEAR_API_KEY}"
- # Optional: override inferred capability metadata per tool
- overrides:
- - tool: create_issue
- writes: true
- write_scope: [linear:issues]
- - tool: list_issues
- read_only: true
-
- # ── Agent Skills (SKILL.md folders) ──────────────────────
- # Each Agent Skill folder is loaded as a composite tool.
- # The agent discovers it via metadata, activates it by
- # loading SKILL.md instructions, and follows them.
- agent_skills:
- - path: ./skills/code-review-checklist
- sandbox_policy: none
-
- # ── Built-in Tool Groups ─────────────────────────────────
- # Opt-in to built-in tool groups provided by CleverAgents.
- builtins:
- - group: shell_operations
-
- # ── Anonymous Tools ──────────────────────────────────────
- # Inline tool definitions for one-off, skill-specific operations.
- # Same format as a named tool YAML body but without a name.
- # These are NOT registered in the Tool Registry and are NOT reusable.
- anonymous_tools:
- - description: "One-off cleanup for legacy migration artifacts"
- input_schema:
- type: object
- properties:
- directory: { type: string }
- capability:
- writes: true
- checkpointable: true
- checkpoint_scope: file
- code: |
- import os, glob
- directory = params["directory"]
- removed = []
- for f in glob.glob(os.path.join(ctx.sandbox.root, directory, "*.legacy")):
- os.remove(f)
- removed.append(f)
- return {"removed": removed, "count": len(removed)}
-
-
-Here is an example of a simpler skill that wraps only built-in tools, suitable for common reuse:
-
-
-# File: skills/file-ops.yaml
-cleveragents:
- version: "3.0"
-
-skill:
- name: local/file-ops
- description: "File and directory operations"
-
- builtins:
- - group: file_operations # read, write, edit, delete, move, copy
- - group: directory_operations # create, list, delete dirs
-
-
-And an example of a skill that is purely MCP-based:
-
-
-# File: skills/github.yaml
-cleveragents:
- version: "3.0"
-
-skill:
- name: local/github
- description: "GitHub operations via MCP"
-
- mcp_servers:
- - name: github
- command: "npx @anthropic/mcp-github"
- env:
- GITHUB_TOKEN: "${GITHUB_TOKEN}"
- overrides:
- - tool: create_issue
- writes: true
- write_scope: [github:issues]
- checkpointable: false
- - tool: create_pull_request
- writes: true
- write_scope: [github:pulls]
- checkpointable: false
- - tool: list_repos
- read_only: true
- - tool: get_file_contents
- read_only: true
-
-
-#### Skill Hierarchy and Composition
-
-Skills can include other skills via the `includes` field. When a skill includes another, all tools from the child skill (and transitively, all tools from any skills *it* includes) become part of the parent skill's flattened tool set.
-
-
-local/full-stack-dev
- ├── includes: local/file-ops
- │ └── builtins: file_operations, directory_operations
- ├── includes: local/git-ops
- │ └── builtins: git_operations
- ├── includes: local/github
- │ └── mcp_servers: github (create_issue, create_pr, list_repos, ...)
- ├── agent_skills: code-review-checklist
- └── tools: local/run-migrations, local/deploy-staging (named tool refs)
-
- Flattened tool set available to actors referencing local/full-stack-dev:
- read_file, write_file, edit_file, delete_file, move_file, copy_file,
- create_directory, list_directory, delete_directory,
- git_status, git_diff, git_log, git_blame,
- create_issue, create_pr, list_repos, get_file_contents,
- code-review-checklist (agent skill),
- local/run-migrations, local/deploy-staging (named tools)
-
-
-**Rules for skill composition:**
-
-1. **Circular includes are forbidden.** The system validates the include graph at registration time and rejects cycles.
-2. **Tool name conflicts**: If two included skills provide tools with the same name, the conflict is resolved by qualification — the tool must be referenced as `.` (e.g., `local/github.create_issue` vs `local/linear.create_issue`). Direct tools (defined in the skill itself) take precedence over included tools.
-3. **Included skills must be registered** before the including skill can be added. The `agents skill add` command validates this.
-4. **Depth is unlimited** but the flattened tool set is computed at registration time and cached. Deep hierarchies do not incur runtime overhead.
-
-#### Skill Registration and Management
-
-Skills are managed through the `agents skill` CLI commands. Named tools referenced by skills must first be registered via `agents tool add` (see the **Tools** section):
-
-
-# First, register any named tools the skill will reference
-agents tool add --config ./tools/run-migrations.yaml
-agents tool add --config ./tools/deploy-staging.yaml
-
-# Then register the skill (which references those tools by name)
-agents skill add --config ./skills/devops-toolkit.yaml
-
-# Update an existing skill (re-reads the config file, overwrites registration)
-agents skill add --config ./skills/devops-toolkit.yaml --update
-
-# List all registered skills
-agents skill list
-
-# Show details for a skill (tools, includes, metadata)
-agents skill show local/devops-toolkit
-
-# List all tools provided by a skill (flattened, including from child skills)
-agents skill tools local/devops-toolkit
-
-# Remove a skill
-agents skill remove local/devops-toolkit
-
-
-Once registered, a skill is available to be referenced by any actor configuration. Skills persist in the database (local or server) and follow the same namespace rules as actors, tools, and actions.
-
-#### Actor References to Skills and Tools
-
-Actors reference skills **by name** to make collections of tools available for LLM tool-calling. Additionally, actor graphs can include **tool nodes** that directly reference named tools or define anonymous inline tools (see **Nodes in the Graph** in the Actor section).
-
-The actor's configuration lists which skills it should have access to:
-
-
-# File: actors/code-assistant.yaml
-cleveragents:
- version: "3.0"
- default_actor: code_assistant
-
-actors:
- code_assistant:
- type: llm
- config:
- actor: anthropic/claude-3-opus
- temperature: 0.3
- system_prompt: |
- You are a code assistant with access to file, git, and GitHub tools.
- Current task: {{ context.task_description }}
-
- # Reference skills by fully-qualified name.
- # All tools from these skills become available to this actor.
- skills:
- - local/file-ops
- - local/git-ops
- - local/github
-
- # Or reference a single composite skill that includes all of the above
- full_stack_assistant:
- type: llm
- config:
- actor: anthropic/claude-3-opus
- system_prompt: |
- You are a full-stack development assistant.
-
- skills:
- - local/full-stack-dev # includes file-ops, git-ops, github, etc.
-
-
-**Server-qualified skill references**: When connected to multiple servers, skills can be disambiguated with a server prefix, same as actors:
-
-
-skills:
- - dev:freemo/custom-analysis # from dev server, personal namespace
- - prod:cleverthis/deploy-tools # from prod server, org namespace
- - local/file-ops # local skill
-
-
-#### Skill Registry
-
-To enable plan validation and discovery at scale, CleverAgents maintains two registries that work together:
-
-1. **Tool Registry** — a persistent catalog of all independently registered tools (described in the **Tools** section above). Managed via `agents tool add/remove/list/show`.
-
-2. **Skill Registry** — a persistent catalog of all registered skills and their flattened tool sets. The Skill Registry composes its tool sets by resolving named tool references from the Tool Registry, incorporating anonymous inline tools, and merging tools from included child skills.
-
-```kroki-plantuml
-@startuml
-skinparam classAttributeIconSize 0
-skinparam classFontSize 13
-skinparam defaultFontSize 12
-
-class SkillRegistry {
- - skillIndex : Map
- --
- + add(config_path) : SkillRecord
- + update(name, config_path) : SkillRecord
- + remove(name) : void
- + lookup(name) : SkillRecord
- + list(filters) : SkillRecord[]
- + tools(name) : ToolDescriptor[]
- + validate_plan(plan) : ValidationResult
- + refresh(name) : void
-}
-
-class SkillRecord {
- + name : String
- + description : String
- + config_path : String
- + includes : List
- + tool_refs : List
- + anonymous_tools : List
- + flattened_tools : List
- + overrides : Map
- + capability_summary : CapabilitySummary
-}
-
-SkillRegistry "1" *-- "0..*" SkillRecord : indexes >
-
-note right of SkillRegistry
- **Populated by:**
- - agents skill add CLI command
- - Dynamic refresh on MCP notifications
-
- **Depends on:**
- - Tool Registry (resolve named tool references)
-
- **Consumed by:**
- - Actor activation
- - Plan validation
- - Agent context injection
-end note
-@enduml
-```
-
-Both registries persist in the database (local SQLite or server). MCP server tools are refreshed dynamically when `notifications/tools/list_changed` events are received.
-
-### Session
-
-!!! adr "Architecture Decision"
- Session persistence, session lifecycle, and session-plan relationships are defined in [ADR-020: Session Model](adr/ADR-020-session-model.md).
-
-#### What a Session Is
-
-A **session** is a user's interactive thread with CleverAgents across time.
-
-!!! abstract "Session Responsibilities"
- - [x] Maintain ==conversational continuity== across interactions
- - [x] Store plan references for active and past plans
- - [x] Persist memory (if enabled) across CLI invocations
- - [x] Provide a UI anchor (CLI invocation, TUI workspace, web session)
-
-#### Session and Memory Persistence
-
-The notes include a known issue: conversation history can be lost between CLI invocations depending on connection string configuration, implying the system needs a stable memory service backend.
-
-!!! warning "Persistence Requirements"
- - Sessions must have ==stable IDs==
- - Sessions must be ==resumable== across CLI invocations
- - Session storage backend must be ==configured explicitly==
- - If session persistence is disabled, the UX must be explicit about it — ==no silent history loss==
-
-### Server
-
-!!! adr "Architecture Decision"
- The server architecture, multi-user support, and local/server mode duality are defined in [ADR-023: Server Mode](adr/ADR-023-server-mode.md). The server application architecture is defined in [ADR-048: Server Application Architecture](adr/ADR-048-server-application-architecture.md). The A2A standard adoption is defined in [ADR-047: A2A Standard Adoption](adr/ADR-047-acp-standard-adoption.md).
-
-#### What a Server Is
-
-A server is an **optional, separate application** that enables:
-
-* multi-user access
-* shared org namespaces (`/` and `/`)
-* persistent plan records (PostgreSQL)
-* remote plan execution (via LangGraph Platform)
-* governance and auditing
-* entity synchronization across devices and team members
-
-The server shares the same **Domain and Application layers** as the client (per ADR-001), differing only in Infrastructure and Presentation layers. Its sole client-facing interface is an **A2A JSON-RPC 2.0 endpoint** — there is no REST API.
-
-**Single-user local mode is the default** (so setup is easy), but the architecture anticipates server mode for shared skills, org-level actions, and collaborative workflows.
-
-#### Client-Only vs Server Mode
-
-| Mode | Description | Protocol | Plan Execution |
-|------|-------------|----------|----------------|
-| **Client-only** | No server connection. All data in local database. Agent runs as local subprocess. | A2A over stdio | Always local |
-| **Server mode** | Connected to a CleverAgents server. Namespaced items sync. | A2A over HTTP | Local or server (via LangGraph Platform RemoteGraph) |
-
-**It is possible to run a client with no server at all.** Server is optional.
-
-#### Server Configuration and Connection
-
-Connecting to a server requires two configuration keys:
-
-| Key | Env Var | Purpose |
-|-----|---------|---------|
-| `server.url` | `CLEVERAGENTS_SERVER_URL` | URL of the CleverAgents A2A server endpoint |
-| `server.token` | `CLEVERAGENTS_SERVER_TOKEN` | Authentication token (obtained via server registration or team invite) |
-
-When `server.url` is set, the client switches to server mode: A2A methods flow over HTTP instead of stdio, and server namespaces become available. The connection lifecycle follows the A2A standard: the client discovers the server's Agent Card (capability exchange), authenticates via the declared HTTP auth scheme, and begins sending `message/send` or `message/stream` requests.
-
-#### Cloud Plan Execution
-
-In server mode, actor graphs are deployed to **LangGraph Platform** and invoked via **RemoteGraph**. This means different actors for different plan phases (strategy, execution, estimation) each deploy as separate RemoteGraphs, enabling independent scaling without limiting plan capabilities.
-
-When an agent executing on the server needs to access **client-local resources** (files, terminals), it uses `_cleveragents/` extension methods (`fs/read_text_file`, `fs/write_text_file`, `terminal/*`) which the client handles locally via the A2A multi-turn interaction pattern (Task enters `input-required` state). This enables server-hosted plan execution even when some resources exist only on the client machine.
-
-#### Entity Sync and Sharing
-
-Entity synchronization between client and server uses A2A extension methods (`_cleveragents/sync/*`):
-
-* **Auto-sync** (`server.sync.auto`): Entities sync on connection and at `server.sync.interval` (default: 300s)
-* **Pull**: Server namespace entities are downloaded to local cache
-* **Push**: Local entity definitions can be explicitly pushed to a server namespace
-* **Status**: Compare local and server entity versions to detect drift
-* The `local/` namespace is **never** synced — it exists only on the client
-
-#### Multi-Device Experience
-
-With server mode, a user can:
-
-* Start a plan on their laptop, close the lid, and monitor progress from another device
-* Share entity definitions (actors, skills, actions) across team members via server namespaces
-* Run long-running plans on server infrastructure without keeping a client connected
-* Access the same session history from CLI, TUI, or IDE plugin on different machines
-
-#### IDE Integration via A2A
-
-IDE plugins (e.g., VS Code, JetBrains) communicate with CleverAgents exclusively through A2A — the same protocol used by CLI and TUI. The IDE plugin can operate in either local mode (spawning an agent subprocess over stdio) or server mode (connecting to a remote CleverAgents server over HTTP). The `_cleveragents/` extension methods for file and terminal operations (`fs/*`, `terminal/*`) allow the agent to interact with the IDE's workspace and integrated terminal.
-
-#### Agent-to-Agent Protocol (A2A)
-
-!!! adr "Architecture Decision"
- The Agent-to-Agent Protocol is defined in [ADR-026: Agent-to-Agent Protocol (A2A)](adr/ADR-026-agent-client-protocol.md). The adoption of the A2A standard is defined in [ADR-047: A2A Standard Adoption](adr/ADR-047-acp-standard-adoption.md).
-
-CleverAgents adopts the **Agent-to-Agent Protocol** standard ([a2a-protocol.org](https://a2a-protocol.org)) as the **sole** communication protocol for all client-server interaction. A2A is built on **JSON-RPC 2.0** and serves as the **fundamental boundary between the Presentation and Application layers** — every client operation flows through A2A regardless of deployment mode. No client ever bypasses A2A to touch storage, repositories, or internal domain services directly.
-
-A2A solves a fundamental architectural problem: CleverAgents has *multiple presentation surfaces* (CLI, TUI, IDE plugin) and *multiple deployment modes* (local and server), but every client must observe identical behavior regardless of how or where it connects. The A2A standard provides a mature, ecosystem-aligned protocol surface that third parties can implement against.
-
-!!! tip "For the complete architectural deep-dive — transport modes, method catalog, extension methods, wire format, authentication, and error handling — see the [Server and Client Architecture](#server-and-client-architecture) section under Architecture."
-
-##### A2A Standard Operations
-
-The A2A standard defines operations for the core agent interaction lifecycle. These map directly to CleverAgents concepts:
-
-| A2A Operation | Direction | CleverAgents Mapping |
-| :------------ | :-------- | :------------------- |
-| Agent Card discovery | Client → Server | Capability negotiation — advertises supported `_cleveragents/` extensions, automation profiles, tool registries |
-| HTTP auth (OAuth2 / API key) | Client → Server | Token-based authentication (`server.token`) via auth schemes declared in Agent Card |
-| `message/send` | Client → Server | `SessionWorkflow.tell()` — send user message to orchestrator actor; creates or updates a Task |
-| `message/stream` | Client → Server | `SessionWorkflow.tell()` with streaming — returns `TaskStatusUpdateEvent` / `TaskArtifactUpdateEvent` via SSE |
-
-A2A uses a **Task-centric model**: each `message/send` or `message/stream` creates or updates a Task that tracks the lifecycle of the interaction. Tasks transition through states: `submitted` → `working` → `completed` (or `failed`, `canceled`, `input-required`).
-
-##### A2A Streaming Events
-
-The A2A standard defines Server-Sent Events (SSE) for real-time streaming from server to client during `message/stream`:
-
-| Event Type | CleverAgents Mapping |
-| :--------- | :------------------- |
-| `TaskStatusUpdateEvent` | Task state transitions, streaming agent response tokens during plan execution |
-| `TaskArtifactUpdateEvent` | Plan artifacts, tool invocation results, generated outputs |
-
-Events within a single plan lifecycle preserve **causal ordering**: a phase transition event always arrives after the corresponding prior phase completion.
-
-##### Multi-Turn Interactions (Server → Client)
-
-A2A supports multi-turn interactions for operations that require client-side input. When the server-hosted agent needs client-local resources or human approval, the Task enters `input-required` state:
-
-| Interaction Pattern | Purpose |
-| :------------------ | :------ |
-| Task `input-required` state | Human-in-the-loop approval — maps to automation profile gates |
-| `_cleveragents/fs/read_text_file` | Agent reads a file on the client machine (local project resources) |
-| `_cleveragents/fs/write_text_file` | Agent writes a file on the client machine |
-| `_cleveragents/terminal/create` | Agent requests a terminal on the client machine (sandbox execution) |
-| `_cleveragents/terminal/output` | Terminal output streaming |
-| `_cleveragents/terminal/release` / `wait_for_exit` / `kill` | Terminal lifecycle management |
-
-These multi-turn interactions enable a server-hosted agent to access client-local resources without requiring the server to have direct access to the user's filesystem or terminal.
-
-##### CleverAgents Extension Methods
-
-Platform operations beyond the core agent conversation use A2A **extension methods** — declared in the Agent Card's extensions section per the A2A extensibility mechanism. All CleverAgents extensions use the `_cleveragents/` namespace:
-
-| Extension Group | Methods | Service(s) |
-| :-------------- | :------ | :--------- |
-| **Plan lifecycle** | `_cleveragents/plan/use`, `execute`, `apply`, `cancel`, `status`, `tree`, `explain`, `correct`, `diff`, `artifacts`, `prompt`, `rollback`, `list` | `PlanService`, `PlanLifecycle`, `CorrectionFlow` |
-| **Registries** | `_cleveragents/registry/{entity}/list`, `show`, `add`, `update`, `remove` (for each entity type: actor, skill, tool, validation, resource, resource_type, project, action, automation_profile, invariant, lsp) | `ActorService`, `ToolService`, `SkillService`, `ResourceService`, `ProjectService` |
-| **Context** | `_cleveragents/context/show`, `inspect`, `simulate`, `set` | `ContextService` |
-| **Sync** | `_cleveragents/sync/pull`, `push`, `status` | `SyncService` |
-| **Namespace** | `_cleveragents/namespace/list`, `show`, `members` | `NamespaceService` |
-| **Health** | `_cleveragents/health/check`, `_cleveragents/diagnostics/run` | Health/diagnostic services |
-
-Every CLI command listed in the [CLI Commands](#cli-commands) section maps to either a standard A2A operation or a `_cleveragents/` extension method. When a user runs `agents plan status `, the CLI sends a `_cleveragents/plan/status` JSON-RPC request through the active transport and renders the response. The CLI is a thin rendering layer — it contains no business logic.
-
-##### Transport Modes
-
-A2A operates over two transports provided by the A2A Python SDK:
-
-| Mode | Transport | How It Works | Authentication |
-| :--- | :-------- | :----------- | :------------- |
-| **Local** | A2A over **stdio** | Client spawns agent as subprocess; JSON-RPC messages flow over stdin/stdout. Platform extension methods are resolved in-process via `A2aLocalFacade`. | Bypassed (local user permissions) |
-| **Server** | A2A over **HTTP** | Client connects to CleverAgents server via A2A SDK HTTP transport. All methods (standard + extensions) flow through the single A2A endpoint. | HTTP auth schemes declared in Agent Card (OAuth2, API key) + `Authorization: Bearer` header |
-
-In **local mode**, the agent runs as a subprocess. Standard A2A operations (`message/send`, `message/stream`) drive the conversation. Extension methods (`_cleveragents/*`) are intercepted by `A2aLocalFacade` and routed to in-process Application-layer services. No serialization beyond JSON-RPC framing, no network, no authentication overhead.
-
-In **server mode**, the client connects to the CleverAgents server. All communication — both agent conversations and platform operations — flows through the single A2A JSON-RPC 2.0 endpoint. The server delegates actor execution to LangGraph Platform via RemoteGraph.
-
-A third configuration supports **external A2A agents**: standard A2A operations go to the external agent's server, while `_cleveragents/` extension methods go to the CleverAgents server. This enables interoperability with any A2A-compliant agent.
-
-```kroki-mermaid
-sequenceDiagram
- participant U as User
- participant C as CLI / TUI / IDE
- participant A2A as A2A Client (SDK)
- participant S as A2A Server
- participant LG as LangGraph Platform
-
- rect rgb(220, 240, 255)
- Note over C,A2A: Local Mode (stdio)
- U->>C: agents plan status
- C->>A2A: _cleveragents/plan/status {JSON-RPC 2.0}
- A2A->>A2A: A2aLocalFacade → PlanService.get_status()
- A2A-->>C: JSON-RPC result
- C-->>U: Rendered output
- end
-
- rect rgb(255, 235, 220)
- Note over C,LG: Server Mode (HTTP)
- U->>C: agents session tell "Refactor auth"
- C->>A2A: message/send {JSON-RPC 2.0}
- A2A->>S: HTTP POST (JSON-RPC)
- S->>LG: RemoteGraph.invoke(actor_graph)
- LG-->>S: Actor result
- S-->>A2A: TaskStatusUpdateEvent / TaskArtifactUpdateEvent (SSE)
- A2A-->>C: Streaming response
- C-->>U: Rendered output
- end
-```
-
-##### Wire Format
-
-All A2A communication uses **JSON-RPC 2.0** framing as defined by the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification). The internal `A2aRequest` and `A2aResponse` domain objects use the **standard JSON-RPC 2.0 field names** — `jsonrpc`, `method`, `id`, `params`, `result`, and `error` — ensuring full protocol compliance and interoperability with any JSON-RPC 2.0 client or tooling.
-
-###### Envelope Field Reference
-
-| Field | Appears In | Type | Description |
-| :---- | :--------- | :--- | :---------- |
-| `jsonrpc` | Request & Response | `"2.0"` (string literal) | Always `"2.0"`. Identifies the JSON-RPC protocol version. |
-| `method` | Request, Notification | string | The A2A operation name (e.g. `message/send`) or `_cleveragents/` extension method. |
-| `id` | Request & Response | integer \| string \| null | Correlates a response to its request. Omitted in notifications (fire-and-forget). |
-| `params` | Request, Notification | object \| array | Method-specific input parameters. Always an object for CleverAgents methods. |
-| `result` | Success Response | any | Present on success; mutually exclusive with `error`. |
-| `error` | Error Response | object | Present on failure; mutually exclusive with `result`. Contains `code` (integer), `message` (string), and optional `data`. |
-
-**Request:**
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "method": "message/send",
- "params": {
- "message": { "role": "user", "parts": [{ "kind": "text", "text": "Refactor the auth module" }] },
- "taskId": "task_01HXR..."
- }
-}
-```
-
-**Success response:**
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": { "status": "accepted" }
-}
-```
-
-**Streaming event (SSE notification via `message/stream`):**
-```json
-{
- "jsonrpc": "2.0",
- "method": "task/statusUpdate",
- "params": {
- "taskId": "task_01HXR...",
- "status": { "state": "working" },
- "message": { "role": "agent", "parts": [{ "kind": "text", "text": "I'll start by..." }] }
- }
-}
-```
-
-**Extension method request:**
-```json
-{
- "jsonrpc": "2.0",
- "id": 42,
- "method": "_cleveragents/plan/status",
- "params": { "plan_id": "01HXRCF1..." }
-}
-```
-
-**Error response:**
-```json
-{
- "jsonrpc": "2.0",
- "id": 42,
- "error": { "code": -32001, "message": "Plan not found", "data": { "plan_id": "01HXRCF1..." } }
-}
-```
-
-###### A2aVersionNegotiator
-
-The `A2aVersionNegotiator` component handles backward compatibility when a client and server are running different versions of the CleverAgents A2A extension protocol. On connection establishment, the negotiator:
-
-1. Reads the `_cleveragents.version` field from the server's Agent Card.
-2. Compares it against the client's supported version range.
-3. Selects the highest mutually supported minor version.
-4. Downgrades the request envelope shape if the server is on an older minor version (e.g. omitting fields added in a later minor version).
-
-This ensures that a newer CLI can still communicate with an older server (and vice versa) within the same major version, without requiring simultaneous upgrades of all components.
-
-##### Authentication
-
-Authentication uses HTTP auth schemes declared in the server's Agent Card:
-
-1. Client fetches the server's Agent Card (via `/.well-known/agent.json` or configured URL)
-2. Agent Card declares supported authentication schemes (OAuth2, API key, Bearer token)
-3. Client authenticates using the declared scheme — typically `Authorization: Bearer ` header
-4. All subsequent requests carry the authentication credentials
-
-Local mode (stdio) bypasses authentication entirely — the agent subprocess runs with the user's local permissions.
-
-##### Versioning
-
-- The JSON-RPC protocol version is always `"2.0"` (in the `jsonrpc` field)
-- A2A protocol version is declared in the Agent Card and sent via the `A2A-Version` HTTP header
-- CleverAgents extension version is declared in the Agent Card's extensions section under `_cleveragents.version`
-- Servers support the current extension version plus one prior minor version
-- Backward-compatible additions (new optional params, new extension methods) are permitted within a major version; breaking changes require a major version bump
-
-#### Plan Execution Location
-
-Where a plan executes depends on the project type:
-
-| Project Type | Client Execution | Server Execution |
-|--------------|-----------------|------------------|
-| **Local** (has local-only resources) | ✅ Yes | ❌ No (server can't access local resources) |
-| **Remote** (all resources remotely accessible) | ✅ Yes | ✅ Yes |
-
-When acting on **local projects**, the client must be running because only the client can access local resources.
-
-**Remote projects** can execute on either:
-- The client (if user prefers local execution)
-- The server (for long-running plans, since client may be transient)
-
-#### Server Execution Benefits
-
-Server execution is useful when:
-
-* Plans take a long time to execute
-* Client may disconnect (laptop closes, network issues)
-* Multiple team members need to monitor plan progress
-* Centralized logging and auditing required
-
-#### No Plan Queuing
-
-**Plans are not queued.** When a plan is used on projects and executed, it runs immediately. There is no worker queue or delayed execution model.
-
-#### Multi-user Risks and Prompt Injection
-
-Prompt injection isn't critical in single-user mode but becomes important for multi-user server environments.
-
-Server mode must include:
-
-* access boundaries
-* prompt sanitization / safe templating
-* resource access controls
-* auditing
-
-### Resources
-
-!!! adr "Architecture Decision"
- The resource model, resource types, DAG structure, and resource lifecycle are defined in [ADR-008: Resource System](adr/ADR-008-resource-system.md).
-
-A **resource** is an independently registered entity representing anything that a plan can reason about or manipulate — git repositories, filesystems, databases, APIs, documents, and more. Resources are **first-class citizens** in CleverAgents, managed through the `agents resource` CLI commands and stored in the **Resource Registry**.
-
-**CleverAgents extends the MCP resource concept** to support both read AND write operations (MCP resources are read-only). Unlike MCP's flat resource model, CleverAgents resources form a **directed acyclic graph (DAG)** with parent/child relationships, support **physical vs virtual** distinction for content identity tracking, and are governed by a **resource type system** that constrains their structure and behavior.
-
-Resources are registered independently of projects. Projects **link** to resources from the Resource Registry — a resource can be linked to multiple projects, enabling shared resources across teams and workflows.
-
-#### What a Resource Is
-
-A resource has:
-
-* **Name and namespace**: User-added resources follow the same `/` naming convention as actors, tools, skills, and other entities (e.g., `local/api-repo`, `cleverthis/staging-db`). Auto-discovered child resources do not have names — they are identified by ULID only. Every resource (whether user-added or auto-discovered) always has a system-assigned ULID.
-* **Resource type**: Every resource has a type (e.g., `git`, `fs-mount`, `git-branch`, `fs-file`) that determines its properties, CLI arguments, allowed parent/child relationships, sandbox strategy, and handler implementation.
-* **Physical or virtual nature**: Resources are either **physical** (a specific, concrete manifestation) or **virtual** (an abstract identity linking equivalent physical resources). This is determined by the resource type.
-* **Value/properties**: Type-specific properties (a file path, a URL, a connection string, a commit hash, etc.).
-* **Parent/child relationships**: Resources form a DAG. A resource can have multiple parents and multiple children, subject to type constraints.
-* **Capabilities**: Whether the resource is readable, writable, sandboxable, and checkpointable.
-
-#### Resource Types
-
-A **resource type** is a schema-level definition that constrains a category of resources. Resource types define:
-
-* **CLI arguments**: What arguments `agents resource add ` accepts (for user-addable types), including which are required vs optional and validation rules.
-* **Physical or virtual**: Whether instances of this type are physical or virtual resources.
-* **Allowed parent types**: What resource types are valid parents.
-* **Allowed child types**: What resource types are valid children, and whether they are auto-discovered or manually linkable.
-* **Auto-discovery behavior**: What child resources are automatically created when an instance of this type is registered (e.g., registering a `git-checkout` resource auto-discovers a `git` child and an `fs-directory` child for the worktree root; the `git` child in turn auto-discovers remotes, branches, commits, and tree entries).
-* **User addable**: Whether users can create instances of this type directly via `agents resource add `. Types with `user_addable: false` are only generated as auto-discovered children of other resources.
-* **Sandbox strategy**: The default sandboxing approach for instances of this type.
-* **Handler**: The resource handler implementation that provides read/write/sandbox/checkpoint operations.
-* **Inheritance**: Optionally, a parent type from which this type inherits all of the above via the `inherits` field.
-
-##### Resource Type Inheritance
-
-!!! adr "Architecture Decision"
- Resource type inheritance is defined in [ADR-042: Resource Type Inheritance](adr/ADR-042-resource-type-inheritance.md).
-
-Resource types support **single-inheritance specialization** via an `inherits` field. A subtype inherits all properties, capabilities, child type constraints, sandbox strategy, and handler behavior from its parent type, and can selectively override or extend any inherited field.
-
-**Core polymorphism guarantee:** Tools bound to a parent type automatically work with all subtypes. Auto-discovery child type matching and DAG queries that reference a parent type automatically include subtypes.
-
-**Field resolution:** When the system resolves a field for a resource type, it walks the inheritance chain from the most specific type to the root. If the subtype declares the field, the subtype's value is used (override). If omitted, the parent's value is inherited.
-
-**Collection field merging:** Fields that are collections (`cli_args`, `child_types`, `parent_types`) use additive merging by default — the subtype's entries are appended to the parent's, with same-name entries replaced. A subtype can use `_replace: true` to replace a collection entirely.
-
-**Inheritance rules:**
-
-1. Single inheritance only (no diamond).
-2. Maximum chain depth of 5 levels.
-3. No circular inheritance (validated at registration time).
-4. Built-in types may not inherit from custom (namespaced) types.
-5. Removing a parent type is prohibited while subtypes exist.
-
-Example:
-
-
-# A subtype that inherits from container-instance
-name: devcontainer-instance
-inherits: container-instance
-description: "A container provisioned from a devcontainer.json configuration"
-
-# Only fields that differ from or extend container-instance need to be declared.
-# All other fields (capabilities, sandbox_strategy, child_types, etc.) are inherited.
-cli_args:
- # Inherited args from container-instance remain available.
- # Additional args specific to devcontainer:
- - name: config-path
- type: path
- required: false
- description: "Path to .devcontainer/devcontainer.json or .devcontainer/ directory"
-
-handler:
- class: DevcontainerHandler
- module: cleveragents.resource.handlers.devcontainer
-
-
-##### Built-in Resource Types
-
-Built-in types are organized into four layers: **git** (version control structure), **git-checkout** (a composition that bridges git metadata with a local directory), **filesystem** (physical files on disk), and **container** (containerized execution environments). Virtual types link equivalent physical resources across these layers through content/identity matching. There are 34 built-in types total (24 physical + 1 subtype + 9 virtual), of which 4 are user-addable as top-level resources (`git-checkout`, `git`, `fs-mount`, `fs-directory`), plus container types documented in [ADR-039](adr/ADR-039-container-resource-types.md) and the `devcontainer-instance` subtype documented in [ADR-043](adr/ADR-043-devcontainer-integration.md).
-
-Each table below includes the full parent/child relationship constraints. **Allowed Parents** lists what types may be a parent of this type, with cardinality (how many parents of that type are allowed) and whether the relationship is required or optional. **Allowed Children** lists what types may be children, with cardinality and whether they are required or optional. `0..*` means zero or more, `1` means exactly one (required), `0..1` means zero or one (optional).
-
-**Physical types — Git layer** (version control structure — every instance is a concrete manifestation in a specific repository):
-
-| Type | User Addable | Sandbox | Allowed Parents | Allowed Children | Description |
-|------|-------------|---------|-----------------|------------------|-------------|
-| `git` | yes | `none` | `git-checkout` (0..1, optional) | `git-remote` (0..*, optional), `git-branch` (0..*, optional), `git-tag` (0..*, optional), `git-commit` (0..*, optional), `git-stash` (0..*, optional), `git-submodule` (0..*, optional) | A git repository — the object database, refs, and full history. Accessible via a local `.git` directory path or a remote URL. Every `git` resource is a specific, concrete repo instance (local or hosted on a remote server). |
-| `git-remote` | no | `none` | `git` (1, required) | (none) | A remote URL configured on a git repo (e.g., `origin → https://github.com/org/repo`). Auto-discovered child of `git`. Optionally linked as a child of a `remote` virtual resource when the same URL appears in multiple repos. |
-| `git-branch` | no | (inherits) | `git` (1, required) | `git-commit` (0..*, optional) | A named branch ref (e.g., `main`, `feature/auth`). Auto-discovered child of `git`. Optionally linked as a child of a `branch` virtual resource when the same branch name + HEAD exists in multiple repos. |
-| `git-tag` | no | (inherits) | `git` (1, required) | (none) | A tag ref — lightweight or annotated (e.g., `v1.0.0`). Auto-discovered child of `git`. Optionally linked as a child of a `tag` virtual resource when the same tag name + target exists in multiple repos. |
-| `git-commit` | no | (inherits) | `git-branch` (1..*, required), `git` (1, required) | `git-tree` (1, required) | A specific commit object. Auto-discovered child of `git-branch` (a commit can belong to multiple branches). Each commit contains exactly one root `git-tree`. Also a direct child of `git` for ancestry traversal. Optionally linked as a child of a `commit` virtual resource when the same commit hash exists in multiple repos (e.g., shared history between fork and upstream). |
-| `git-tree` | no | (inherits) | `git-commit` (1..*, required) | `git-tree-entry` (0..*, optional), `git-tree` (0..*, optional) | A tree object — a directory listing at a specific commit. Each tree contains entries (blobs and subtrees). Auto-discovered child of `git-commit`. Trees are recursive: a tree can contain subtrees as children. Optionally linked as a child of a `tree` virtual resource when the same tree hash exists across commits/repos. |
-| `git-tree-entry` | no | (inherits) | `git-tree` (1, required) | (none) | A blob entry in a tree — a specific file's content at a specific path and mode. Auto-discovered child of `git-tree`. Represents the leaf of git's content-addressable storage. Optionally linked as a child of a `file` virtual resource when byte-identical content with the same name and permissions exists in the filesystem layer. |
-| `git-stash` | no | (inherits) | `git` (1, required) | (none) | A stash entry (e.g., `stash@{0}`). Auto-discovered child of `git`. Represents work-in-progress saved via `git stash`. |
-| `git-submodule` | no | (inherits) | `git` (1, required) | (none) | A submodule reference — a pointer to another git repository at a specific commit and path. Auto-discovered child of `git`. Optionally linked as a child of a `submodule` virtual resource when the same submodule URL + path exists in multiple repos. |
-
-**Physical types — Git checkout** (composition: git metadata + local worktree directory):
-
-| Type | User Addable | Sandbox | Allowed Parents | Allowed Children | Description |
-|------|-------------|---------|-----------------|------------------|-------------|
-| `git-checkout` | yes | `git_worktree` | (none — always a top-level resource) | `git` (1, required), `fs-directory` (1, required) | A locally checked-out git repository. The **composition type** — auto-discovers a `git` child (the repo's object database, branches, tags, commits, trees, and remotes) and an `fs-directory` child (the worktree root directory, e.g., `/home/user/projects/my-app`). Most users register this type. The worktree root IS a directory, not a mount point, so git-checkout composes with `fs-directory` directly. |
-
-**Physical types — Filesystem layer** (files on disk, used by git checkouts and standalone directories alike):
-
-| Type | User Addable | Sandbox | Allowed Parents | Allowed Children | Description |
-|------|-------------|---------|-----------------|------------------|-------------|
-| `fs-mount` | yes | `copy_on_write` | (none — always a top-level resource) | `fs-directory` (1, required) | A physical mount point on the local system (e.g., `/mnt/data`, `/home`). Represents the mount itself — the filesystem type (ext4, btrfs, etc.) is a property. The root directory is a required auto-discovered `fs-directory` child. Used for registering entire mount points or storage volumes. |
-| `fs-directory` | yes | `copy_on_write` | `git-checkout` (0..1, optional), `fs-mount` (0..1, optional), `fs-directory` (0..1, optional) | `fs-directory` (0..*, optional), `fs-file` (0..*, optional), `fs-symlink` (0..*, optional), `fs-hardlink` (0..*, optional) | A directory on the filesystem. Can be the root child of `fs-mount` (mount point root), the worktree root child of `git-checkout`, a subdirectory child of another `fs-directory`, or a standalone user-registered directory. Optionally linked as a child of a `directory` virtual resource when equivalent directory content exists elsewhere. When user-addable, accepts `--path` flag. |
-| `fs-file` | no | (inherits) | `fs-directory` (1, required) | (none) | A regular file on the local filesystem. Auto-discovered child of `fs-directory`. Optionally linked as a child of a `file` virtual resource when byte-identical content with the same name and permissions exists elsewhere (in another `fs-file` or a `git-tree-entry`). |
-| `fs-symlink` | no | (inherits) | `fs-directory` (1, required) | (none) | A symbolic link on the local filesystem. Auto-discovered child of `fs-directory`. Optionally linked as a child of a `symlink` virtual resource when a symlink with the same name and target exists elsewhere. |
-| `fs-hardlink` | no | (inherits) | `fs-directory` (1, required) | (none) | A hard link on the local filesystem — a file with link count > 1. Auto-discovered child of `fs-directory`. The system tracks hard link relationships by inode to avoid treating the same underlying data as distinct resources. |
-
-**Virtual types** (abstract identity types that link equivalent physical resources — never user-addable, no sandbox):
-
-Virtual types use simple names that mirror their physical counterparts. A virtual resource answers the question: "where else does this same thing exist?" Two physical resources share a virtual parent when they are equivalent by the virtual type's criteria (same content, same name, same permissions, same hash, etc.).
-
-| Type | Allowed Children | Description |
-|------|-----------------|-------------|
-| `file` | `fs-file` (0..*, optional), `git-tree-entry` (0..*, optional) | Cross-layer file identity. Links physical `fs-file` and `git-tree-entry` resources that represent the same file — identical content bytes, filename, and permissions. Answers: "this file in the working tree and this blob in git's tree are the same file." |
-| `directory` | `fs-directory` (0..*, optional), `git-tree` (0..*, optional) | Cross-layer directory identity. Links physical `fs-directory` and `git-tree` resources whose recursive contents are equivalent. Answers: "this directory on disk matches this tree object in git." |
-| `symlink` | `fs-symlink` (0..*, optional), `git-tree-entry` (0..*, optional) | Cross-layer symlink identity. Links physical `fs-symlink` and `git-tree-entry` (mode 120000) resources with the same name and target. |
-| `commit` | `git-commit` (0..*, optional) | Cross-repo commit identity. Links `git-commit` resources across different repos that share the same commit hash — typically a fork and its upstream. Answers: "this commit exists in both repos." |
-| `branch` | `git-branch` (0..*, optional) | Cross-repo branch identity. Links `git-branch` resources across different repos with the same branch name and HEAD commit hash. |
-| `tag` | `git-tag` (0..*, optional) | Cross-repo tag identity. Links `git-tag` resources across different repos with the same tag name and target object. |
-| `remote` | `git-remote` (0..*, optional) | Cross-repo remote identity. Links `git-remote` resources across different repos that point to the same URL. Answers: "these repos share the same upstream." |
-| `submodule` | `git-submodule` (0..*, optional) | Cross-repo submodule identity. Links `git-submodule` resources across different repos with the same submodule URL and path. |
-| `tree` | `git-tree` (0..*, optional) | Cross-repo/cross-commit tree identity. Links `git-tree` resources across different commits or repos that have the same tree hash — identical directory structure and contents. |
-
-**Key design notes:**
-
-* Virtual types are **never user-addable** — they are created and maintained automatically by the system when equivalent physical resources are detected.
-* Virtual types have **no sandbox strategy** because they represent abstract identities, not concrete locations. Tools always operate on the physical children.
-* **Physical types list virtual parents in their Allowed Parents column** (via the "optionally linked" descriptions). For example, an `fs-file` can be linked as a child of a `file` virtual resource when its content matches a `git-tree-entry`. This is how the DAG connects physical and virtual layers.
-* `git` represents a specific git repository instance — whether hosted remotely (e.g., on GitHub's servers) or locally (a `.git` directory on disk). It is **physical** because it is a concrete manifestation that exists somewhere, not an abstract identity. A `git` resource can be created from a remote URL alone (accessing the object database via the git protocol) or from a local `.git` directory.
-* `git-checkout` is the type most users register for repos they've cloned. It composes a `git` child (repo metadata) and an `fs-directory` child (the worktree root directory). The worktree root is a directory on an existing filesystem — NOT a separate mount point — so `git-checkout` links directly to `fs-directory`, not `fs-mount`. This means the worktree's files use the **same `fs-directory` and `fs-file` types** regardless of how they were created.
-* `git-commit` has a `git-tree` child (the root tree object), which in turn has `git-tree-entry` and nested `git-tree` children. This properly models git's internal object structure: commits point to trees, trees contain entries (blobs) and subtrees.
-* `fs-mount` represents a physical mount point, not a directory. The filesystem type (ext4, btrfs, etc.) is a property on the mount. The root directory is an auto-discovered `fs-directory` child. Use `fs-mount` for registering mount points and storage volumes. Use `fs-directory` (user-addable) for registering arbitrary directories.
-* `fs-directory` is user-addable, allowing users to register standalone directories (e.g., a build output folder, a config directory) without wrapping them in an `fs-mount`. An `fs-directory` registered standalone or as a child of `fs-mount`/`git-checkout` uses the same type and auto-discovers the same `fs-file`, `fs-symlink`, `fs-hardlink`, and nested `fs-directory` children.
-* `git-tree-entry` represents a blob in git's tree — a specific file's content at a specific path and mode. The corresponding file on disk (if checked out) is an `fs-file`. The `file` virtual type bridges these two when their content, name, and permissions are identical.
-* **4 user-addable types**: `git-checkout` (local repo), `git` (remote or local metadata-only), `fs-mount` (mount point), `fs-directory` (arbitrary directory).
-
-##### Built-in Type Hierarchy
-
-The parent-child relationships between built-in resource types form three layers — git structure, git checkout (composition), and filesystem — bridged by virtual identity types:
-
-```kroki-plantuml
-@startuml
-skinparam defaultFontSize 11
-skinparam objectFontSize 11
-skinparam packageStyle rectangle
-
-package "GIT-CHECKOUT (composition)" as GC #LightBlue {
- object "git-checkout" as gc {
- /home/user/projects/myapp
- }
-}
-
-package "GIT STRUCTURE" as GS #LightYellow {
- object "git" as git {
- repo object DB
- }
- object "git-remote" as remote {
- origin
- }
- object "git-tag" as tag {
- v1.0.0
- }
- object "git-submodule" as submod {
- lib/shared
- }
- object "git-branch" as branch {
- main
- }
- object "git-stash" as stash {
- stash@0
- }
- object "git-commit" as commit {
- a1b2c3d
- }
- object "git-tree" as tree {
- e8f1... root
- }
- object "git-tree-entry" as entry1 {
- README.md
- }
- object "git-tree" as subtree {
- src/ subtree
- }
- object "git-tree-entry" as entry2 {
- src/app.ts
- }
- object "git-tree-entry" as entry3 {
- src/main.ts
- }
-}
-
-package "FILESYSTEM (worktree)" as FS #LightGreen {
- object "fs-directory" as fsroot {
- worktree root
- }
- object "fs-directory" as srcdir {
- src/
- }
- object "fs-file" as readme {
- README.md
- }
- object "fs-file" as app {
- app.ts
- }
- object "fs-file" as main {
- main.ts
- }
-}
-
-package "STANDALONE FS-DIRECTORY" as SFS #Wheat {
- object "fs-directory" as sfs {
- /opt/deploy/myapp
- }
- object "fs-directory" as ssrcdir {
- src/
- }
- object "fs-file" as sreadme {
- README.md
- }
- object "fs-file" as sapp {
- app.ts
- }
- object "fs-file" as smain {
- main.ts
- }
- object "fs-symlink" as symlink {
- link.txt
- }
-}
-
-package "STANDALONE FS-MOUNT" as SM #LightCoral {
- object "fs-mount" as mount {
- /mnt/data
- }
- object "fs-directory" as mountroot {
- root: /
- }
-}
-
-package "VIRTUAL LAYER (abstract identities)" as VL #Lavender {
- object "file" as vfile {
- app.ts @ sha256:9f8e...
- }
- object "directory" as vdir {
- src/ @ merkle:3d4f...
- }
- object "commit" as vcommit {
- a1b2c3d
- }
- object "branch" as vbranch {
- main @ a1b2c3d
- }
- object "remote" as vremote {
- github.com/org/repo
- }
- object "tree" as vtree {
- e8f1...9d2a
- }
-}
-
-gc --> git
-gc --> fsroot
-
-mount --> mountroot
-
-git --> remote
-git --> tag
-git --> submod
-git --> branch
-git --> stash
-
-branch --> commit
-commit --> tree
-tree --> entry1
-tree --> subtree
-subtree --> entry2
-subtree --> entry3
-
-fsroot --> srcdir
-fsroot --> readme
-srcdir --> app
-srcdir --> main
-
-sfs --> ssrcdir
-sfs --> sreadme
-sfs --> symlink
-ssrcdir --> sapp
-ssrcdir --> smain
-
-app ..> vfile : equivalent
-sapp ..> vfile : equivalent
-entry2 ..> vfile : equivalent
-srcdir ..> vdir : equivalent
-ssrcdir ..> vdir : equivalent
-subtree ..> vdir : equivalent
-commit ..> vcommit : equivalent
-branch ..> vbranch : equivalent
-remote ..> vremote : equivalent
-tree ..> vtree : equivalent
-@enduml
-```
-
-**Reading the diagram:**
-
-* **Top left**: A `git-checkout` resource decomposes into a `git` child (left — the repository's full structure) and an `fs-directory` child (center — the worktree root directory at `/home/user/projects/myapp`). The worktree root is a directory, not a mount point.
-* **Git structure** (left column): The `git` child contains `git-remote` (origin), `git-tag` (v1.0.0), `git-submodule` (lib/shared), `git-stash` (stash@{0}), and `git-branch` (main). The branch contains `git-commit` objects, each commit contains a root `git-tree`, and trees contain `git-tree-entry` (blobs) and nested `git-tree` (subtrees). This properly models git's internal object structure.
-* **Filesystem** (center/right): The worktree's `fs-directory` contains `src/` (an `fs-directory`), `README.md` (an `fs-file`), and files including `fs-symlink` resources. A standalone `fs-directory` (`/opt/deploy/myapp`) with the same structure. A standalone `fs-mount` (`/mnt/data`) with a root `fs-directory` child.
-* **Virtual layer** (boxed area): Shows how virtual types link equivalent physical resources:
- - A `file` virtual resource links `fs-file` and `git-tree-entry` resources that have the same content, filename, and permissions — bridging the filesystem and git layers.
- - A `directory` virtual resource links `fs-directory` and `git-tree` resources with the same recursive content.
- - A `commit` virtual resource links `git-commit` resources across repos with the same commit hash.
- - A `branch` virtual resource links `git-branch` resources across repos with the same name and HEAD.
- - A `remote` virtual resource links `git-remote` resources across repos with the same URL.
- - A `tree` virtual resource links `git-tree` resources across repos/commits with the same tree hash.
-
-**Key separations:**
-
-* **`git` vs `git-checkout`**: A `git` resource represents a specific repository instance (local or remote). It can exist without any local directory (created from a remote URL — the repo exists on the remote server). A `git-checkout` always has both a `git` child and an `fs-directory` child — it represents a locally cloned repo with files on disk.
-* **`git-tree-entry` vs `fs-file`**: A `git-tree-entry` is a blob entry in git's tree (path + content hash + mode). An `fs-file` is a physical file on disk. When a repo is checked out, both exist and typically have matching content — the `file` virtual type links them when content, name, and permissions match.
-* **`git-tree` vs `fs-directory`**: A `git-tree` is a tree object in git's object database (a directory listing at a commit). An `fs-directory` is a physical directory on disk. The `directory` virtual type links them when their recursive contents match.
-* **`git-commit` → `git-tree` → `git-tree-entry`**: This chain properly models git internals. Commits point to a root tree, trees contain entries (blobs) and subtrees. The old design skipped the tree level; the current design preserves it.
-* **`fs-mount` vs `fs-directory`**: An `fs-mount` is a mount point (e.g., `/mnt/data`). The filesystem type (ext4, btrfs, etc.) is a property. The root directory is an `fs-directory` child. An `fs-directory` is a directory — it can be a child of `fs-mount`, `git-checkout`, or another `fs-directory`, or it can be registered standalone by the user.
-* **`git-checkout` composes with `fs-directory`, not `fs-mount`**: A git checkout's worktree is a directory on an existing filesystem, not a separate mount point. This is why `git-checkout`'s required child is `fs-directory` (the worktree root), not `fs-mount`.
-* **Virtual types bridge physical equivalents**: `file` bridges `fs-file` + `git-tree-entry` (cross-layer). `directory` bridges `fs-directory` + `git-tree` (cross-layer). `commit`, `branch`, `tag`, `remote`, `submodule`, and `tree` link the same git structural element across different repos.
-
-##### Concrete Example: A Made-Up Project
-
-Consider a web application called "Acme Dashboard" with three registered resources:
-
-1. **`local/acme-app`** — a checked-out git repo at `/home/alice/projects/acme-dashboard` (type: `git-checkout`)
-2. **`local/acme-upstream`** — a git repo accessed via remote URL, not cloned (type: `git`)
-3. **`local/acme-deploy`** — a standalone directory at `/opt/deploy/acme-dashboard` containing a production build snapshot (type: `fs-directory`)
-
-**Registration:**
-
-
-# 1) Checked-out git repo (has local files on disk)
-agents resource add git-checkout local/acme-app \
- --path /home/alice/projects/acme-dashboard --branch main
-
-# 2) Git repo via remote URL (no local checkout — metadata only)
-agents resource add git local/acme-upstream \
- --url git@github.com:acmecorp/dashboard.git
-
-# 3) Standalone directory (not a git repo — just files on disk)
-agents resource add fs-directory local/acme-deploy \
- --path /opt/deploy/acme-dashboard
-
-
-**What gets auto-discovered for each:**
-
-**`local/acme-app`** (type: `git-checkout`) discovers two children — a `git` and an `fs-directory` (the worktree root):
-
-```kroki-plantuml
-@startwbs
-* local/acme-app\n(git-checkout / physical)
-** local/acme-app:repo\n(git / physical)
-*** acme-app:repo:origin\n(git-remote)\ngit@github.com:acmecorp/dashboard.git
-*** acme-app:repo:v1.0.0\n(git-tag)
-*** acme-app:repo:lib/shared\n(git-submodule @ c4d5e6f)
-*** acme-app:repo:stash@0\n(git-stash)
-*** acme-app:repo:main\n(git-branch)
-**** main:a7f3e21\n(git-commit)
-***** main:a7f3e21:tree\n(git-tree / root)
-****** a7f3e21:README.md\n(git-tree-entry)
-****** a7f3e21:package.json\n(git-tree-entry)
-****** a7f3e21:src/\n(git-tree / subtree)
-******* a7f3e21:src/app.ts\n(git-tree-entry)
-******* a7f3e21:src/api.ts\n(git-tree-entry)
-******* a7f3e21:src/utils.ts\n(git-tree-entry)
-*** acme-app:repo:develop\n(git-branch)
-**** develop:b2c4d8e\n(git-commit)
-***** develop:b2c4d8e:tree\n(git-tree)
-****** b2c4d8e:src/\n(git-tree)
-******* b2c4d8e:src/app.ts\n(git-tree-entry)
-******* b2c4d8e:src/api.ts\n(git-tree-entry / modified)
-** local/acme-app:worktree\n(fs-directory / physical)\n/home/alice/projects/acme-dashboard/
-*** worktree:src/\n(fs-directory)
-**** worktree:src/app.ts\n(fs-file)
-**** worktree:src/api.ts\n(fs-file)
-**** worktree:src/utils.ts\n(fs-file)
-*** worktree:package.json\n(fs-file)
-*** worktree:README.md\n(fs-file)
-*** worktree:docs -> ../docs\n(fs-symlink)
-@endwbs
-```
-
-When the `git-checkout` contains a `.devcontainer/devcontainer.json`, an additional `devcontainer-instance` child is auto-discovered:
-
-```kroki-plantuml
-@startwbs
-* local/acme-app\n(git-checkout / physical)
-** local/acme-app:repo\n(git / physical)
-*** (branches, commits, trees, ...)
-** local/acme-app:worktree\n(fs-directory / physical)
-*** worktree:.devcontainer/\n(fs-directory)
-**** worktree:.devcontainer/devcontainer.json\n(fs-file)
-*** worktree:src/\n(fs-directory)
-**** worktree:src/app.ts\n(fs-file)
-*** worktree:package.json\n(fs-file)
-** local/acme-app:devcontainer\n(devcontainer-instance / discovered)
-*** [container-mount — pending activation]
-*** [container-exec-env — pending activation]
-*** [container-port — pending activation]
-@endwbs
-```
-
-The `devcontainer-instance` is in `discovered` state — its container-mount, container-exec-env, and container-port children are only created when the container is activated during plan execution. This is consistent with lazy sandboxing: no container is built until a tool actually needs to execute inside it.
-
-The `git-checkout` cleanly separates two concerns: the `git` child contains version control structure (remotes, branches, tags, stashes, submodules, commits, trees, and tree entries — git's full object model), while the `fs-directory` child is the worktree root directory containing the actual files on disk. Note how git's internal structure is fully modeled: `git-commit` → `git-tree` (root tree object) → `git-tree-entry` (blobs) and nested `git-tree` (subtrees). The worktree root is a directory (`fs-directory`), not a mount point — `git-checkout` does not own an `fs-mount` resource because a git checkout's worktree is just a directory on an existing filesystem. When content matches (as it does for a clean checkout), virtual types link the `fs-file` and `git-tree-entry` resources.
-
-**`local/acme-upstream`** (type: `git`, remote URL — NOT checked out) discovers:
-
-```kroki-plantuml
-@startwbs
-* local/acme-upstream\n(git / physical)\ngit@github.com:acmecorp/dashboard.git
-** acme-upstream:origin\n(git-remote)
-** acme-upstream:v1.0.0\n(git-tag)
-** acme-upstream:main\n(git-branch)
-*** main:a7f3e21\n(git-commit)
-**** main:a7f3e21:tree\n(git-tree)
-***** a7f3e21:src/\n(git-tree)
-****** a7f3e21:src/app.ts\n(git-tree-entry)
-****** a7f3e21:src/api.ts\n(git-tree-entry)
-** acme-upstream:develop\n(git-branch)
-*** ...\n(remaining structure)
-@endwbs
-```
-
-A standalone `git` resource has **full access to branches, tags, commits, trees, and tree entries** — everything in the git object database — but **no `fs-directory` child** and **no `fs-file` resources**. There are no files on the local disk (the repo exists on GitHub's servers). Tools that need local file access cannot bind to it.
-
-This is the key difference from `git-checkout`: a `git` resource represents a specific repo instance. Plans can reason about history, diffs between branches, remote relationships — without a local clone. A `git-checkout` adds the local worktree directory on top.
-
-**`local/acme-deploy`** (type: `fs-directory`, standalone) discovers:
-
-```kroki-plantuml
-@startwbs
-* local/acme-deploy\n(fs-directory / physical)\n/opt/deploy/acme-dashboard/
-** acme-deploy:src/\n(fs-directory)
-*** acme-deploy:src/app.ts\n(fs-file)
-*** acme-deploy:src/api.ts\n(fs-file)
-*** acme-deploy:src/utils.ts\n(fs-file)
-** acme-deploy:package.json\n(fs-file)
-** acme-deploy:README.md\n(fs-file)
-@endwbs
-```
-
-A standalone `fs-directory` — no git metadata, no branches, no commits, no tree entries. Just a directory containing files and subdirectories. Uses the **same `fs-directory` and `fs-file` types** as the git checkout's worktree root.
-
-**Virtual resource linking across all three:**
-
-After all three resources are registered, the system detects equivalent physical resources and creates virtual parents to link them:
-
-```kroki-plantuml
-@startuml
-skinparam defaultFontSize 10
-skinparam objectFontSize 10
-skinparam packageStyle rectangle
-left to right direction
-
-package "PHYSICAL: local/acme-app" as P1 #LightBlue {
- object "fs-directory" as acmeWtSrc {
- worktree:src/
- }
- object "fs-file" as acmeWtApp {
- worktree:src/app.ts
- }
- object "fs-file" as acmeWtUtils {
- worktree:src/utils.ts
- }
- object "fs-file" as acmeWtApi {
- worktree:src/api.ts
- }
- object "git-tree" as acmeGitSrc {
- main:a7f3e21:src/
- }
- object "git-tree-entry" as acmeGitApp {
- main:src/app.ts
- }
- object "git-tree-entry" as acmeGitUtils {
- main:src/utils.ts
- }
- object "git-tree-entry" as acmeGitApi {
- main:src/api.ts
- }
- object "git-commit" as acmeCommit {
- main:a7f3e21
- }
- object "git-branch" as acmeBranch {
- main
- }
- object "git-tag" as acmeTag {
- v1.0.0
- }
- object "git-remote" as acmeRemote {
- origin
- }
- object "git-tree" as acmeTree {
- main:a7f3e21:tree
- }
- object "git-submodule" as acmeSubmod {
- lib/shared
- }
-}
-
-package "PHYSICAL: local/acme-deploy" as P2 #LightGreen {
- object "fs-directory" as deploySrc {
- src/
- }
- object "fs-file" as deployApp {
- src/app.ts
- }
- object "fs-file" as deployUtils {
- src/utils.ts
- }
- object "fs-file" as deployApi {
- src/api.ts
- }
-}
-
-package "PHYSICAL: local/acme-upstream" as P3 #LightYellow {
- object "git-tree" as upstreamSrc {
- main:a7f3e21:src/
- }
- object "git-tree-entry" as upstreamApp {
- main:src/app.ts
- }
- object "git-tree-entry" as upstreamUtils {
- main:src/utils.ts
- }
- object "git-tree-entry" as upstreamApi {
- main:src/api.ts
- }
- object "git-commit" as upstreamCommit {
- main:a7f3e21
- }
- object "git-branch" as upstreamBranch {
- main
- }
- object "git-tag" as upstreamTag {
- v1.0.0
- }
- object "git-remote" as upstreamRemote {
- origin
- }
- object "git-tree" as upstreamTree {
- main:a7f3e21:tree
- }
-}
-
-package "VIRTUAL LAYER\n(auto-created by equivalence)" as VL #Lavender {
- object "directory" as vDir {
- src/ (merkle:3d4f...)
- }
- object "file" as vAppTs {
- app.ts (sha256:9f8e...)
- }
- object "file" as vUtilsTs {
- utils.ts (sha256:a2b1...)
- }
- object "file" as vApiTs {
- api.ts (sha256:e1d3...)
- }
- object "commit" as vCommit {
- a7f3e21
- }
- object "branch" as vBranch {
- main @ a7f3e21
- }
- object "tag" as vTag {
- v1.0.0
- }
- object "remote" as vRemote {
- github.com:acmecorp/dashboard.git
- }
- object "tree" as vTree {
- e8f1...9d2a
- }
- object "submodule" as vSubmod {
- lib/shared
- }
-}
-
-acmeWtSrc ..> vDir
-deploySrc ..> vDir
-acmeGitSrc ..> vDir
-upstreamSrc ..> vDir
-
-acmeWtApp ..> vAppTs
-deployApp ..> vAppTs
-acmeGitApp ..> vAppTs
-upstreamApp ..> vAppTs
-
-acmeWtUtils ..> vUtilsTs
-deployUtils ..> vUtilsTs
-acmeGitUtils ..> vUtilsTs
-upstreamUtils ..> vUtilsTs
-
-acmeWtApi ..> vApiTs
-deployApi ..> vApiTs
-acmeGitApi ..> vApiTs
-upstreamApi ..> vApiTs
-
-note "NOT linked: develop:b2c4d8e:src/api.ts\n(different content on develop branch)" as N1
-
-acmeCommit ..> vCommit
-upstreamCommit ..> vCommit
-
-acmeBranch ..> vBranch
-upstreamBranch ..> vBranch
-
-acmeTag ..> vTag
-upstreamTag ..> vTag
-
-acmeRemote ..> vRemote
-upstreamRemote ..> vRemote
-
-acmeTree ..> vTree
-upstreamTree ..> vTree
-
-acmeSubmod ..> vSubmod
-@enduml
-```
-
-**How the `directory` virtual type works:**
-
-The `directory` virtual resource for `src/` exists because the `src/` directory has identical recursive content across multiple physical locations. Its children include both `fs-directory` resources (physical directories on disk) and `git-tree` resources (tree objects in git's object database). The system detects directory equivalence by computing a Merkle hash over the sorted child content hashes. If someone adds a file to the deploy directory but not the git checkout's worktree, the Merkle hashes diverge, and `local/acme-deploy:src/` is unlinked from the `directory` virtual parent.
-
-**How the `file` virtual type works:**
-
-The `file` virtual type links physical resources that represent the same file — identical content bytes, filename, and permissions. It bridges across layers: an `fs-file` on disk and a `git-tree-entry` in git's tree are linked when they have matching content. This is the primary cross-layer bridge. When content diverges (e.g., an uncommitted edit), the virtual link is broken.
-
-**How `commit` works across repos:**
-
-When two `git` resources share history (e.g., a fork and its upstream), the same commit hash will appear in both repos' branches. The `commit` virtual type links these — the commit object `a7f3e21` in the local repo and `a7f3e21` in the upstream repo are the same commit, and the virtual parent captures this identity.
-
-**Divergence scenario:**
-
-If a developer edits `src/api.ts` in the deploy directory (`/opt/deploy/acme-dashboard/src/api.ts`), the system detects the content hash change and:
-
-1. Unlinks `local/acme-deploy:src/api.ts` from `file: api.ts (sha256:e1d3...8a9b)` (content no longer matches).
-2. Unlinks `local/acme-deploy:src/` from `directory: src/ (merkle:3d4f...a2b1)` (directory contents no longer identical — the Merkle hash has changed).
-3. The git checkout's worktree files and git-tree-entry resources remain linked (their content hasn't changed).
-4. If the edit makes the deploy file match some *other* known content hash, a new virtual link may be created.
-
-Additional resource types (databases, APIs, cloud infrastructure, etc.) can be added as **custom resource types** via `agents resource type add`.
-
-##### Cloud Infrastructure Resource Types
-
-Cloud infrastructure types follow a hierarchical model with two layers:
-
-1. **Generic cloud base types** (`cloud-*`) — provider-agnostic abstractions for common cloud concepts (compute, network, storage, IAM, observability, messaging, containers). These are abstract (not user-addable) and serve as inheritance roots.
-2. **Provider-specific types** (e.g., `aws-*`) — concrete types that inherit from the generic base layer and model a specific provider's resource hierarchy.
-
-**Generic Cloud Base Types** (19 types — abstract, not user-addable):
-
-| Type | Category | Description |
-|------|----------|-------------|
-| `cloud-account` | Structure | Cloud provider account or subscription |
-| `cloud-region` | Structure | Geographic region within an account |
-| `cloud-network` | Network | Virtual network (VPC, VNet, etc.) |
-| `cloud-subnet` | Network | Subnet within a virtual network |
-| `cloud-security-group` | Network | Network security rules / firewall group |
-| `cloud-load-balancer` | Network | Network load balancer |
-| `cloud-compute-instance` | Compute | Virtual machine or compute instance |
-| `cloud-object-store` | Storage | Object / blob storage bucket |
-| `cloud-block-storage` | Storage | Block storage volume |
-| `cloud-identity-principal` | IAM | IAM user or service principal |
-| `cloud-role` | IAM | IAM role |
-| `cloud-policy` | IAM | IAM or access policy document |
-| `cloud-log-group` | Observability | Log aggregation group |
-| `cloud-alarm` | Observability | Monitoring alarm or alert |
-| `cloud-queue` | Messaging | Message queue |
-| `cloud-topic` | Messaging | Pub/sub notification topic |
-| `cloud-container-repo` | Containers | Container image registry / repository |
-| `cloud-container-cluster` | Containers | Container orchestration cluster |
-| `cloud-container-service` | Containers | Container workload / service |
-
-**AWS Provider Types** (39 types — inheriting from generic base where applicable):
-
-| Type | Inherits | User Addable | Parent Types | Category |
-|------|----------|-------------|--------------|----------|
-| `aws-account` | `cloud-account` | **yes** | (root) | Account |
-| `aws-region` | `cloud-region` | no | `aws-account` | Structure |
-| `aws-vpc` | `cloud-network` | no | `aws-region` | Network |
-| `aws-subnet` | `cloud-subnet` | no | `aws-vpc` | Network |
-| `aws-igw` | — | no | `aws-vpc` | Network |
-| `aws-nat-gw` | — | no | `aws-subnet`, `aws-vpc` | Network |
-| `aws-route-table` | — | no | `aws-vpc` | Network |
-| `aws-nacl` | — | no | `aws-vpc` | Network |
-| `aws-security-group` | `cloud-security-group` | no | `aws-vpc` | Network |
-| `aws-alb` | `cloud-load-balancer` | no | `aws-vpc` | Network |
-| `aws-nlb` | `cloud-load-balancer` | no | `aws-vpc` | Network |
-| `aws-target-group` | — | no | `aws-vpc` | Network |
-| `aws-listener` | — | no | `aws-alb`, `aws-nlb` | Network |
-| `aws-ec2-instance` | `cloud-compute-instance` | no | `aws-subnet`, `aws-region` | Compute |
-| `aws-ami` | — | no | `aws-region` | Compute |
-| `aws-launch-template` | — | no | `aws-region` | Compute |
-| `aws-asg` | — | no | `aws-region` | Compute |
-| `aws-s3-bucket` | `cloud-object-store` | no | `aws-region` | Storage |
-| `aws-ebs-volume` | `cloud-block-storage` | no | `aws-region` | Storage |
-| `aws-efs-filesystem` | — | no | `aws-region` | Storage |
-| `aws-iam-user` | `cloud-identity-principal` | no | `aws-account` | IAM |
-| `aws-iam-role` | `cloud-role` | no | `aws-account` | IAM |
-| `aws-iam-policy` | `cloud-policy` | no | `aws-account` | IAM |
-| `aws-iam-instance-profile` | — | no | `aws-account` | IAM |
-| `aws-cloudwatch-log-group` | `cloud-log-group` | no | `aws-region` | Observability |
-| `aws-cloudwatch-alarm` | `cloud-alarm` | no | `aws-region` | Observability |
-| `aws-cloudwatch-metric` | — | no | `aws-region` | Observability |
-| `aws-eventbridge-bus` | — | no | `aws-region` | Observability |
-| `aws-eventbridge-rule` | — | no | `aws-eventbridge-bus` | Observability |
-| `aws-eventbridge-target` | — | no | `aws-eventbridge-rule` | Observability |
-| `aws-sqs-queue` | `cloud-queue` | no | `aws-region` | Messaging |
-| `aws-sns-topic` | `cloud-topic` | no | `aws-region` | Messaging |
-| `aws-sns-subscription` | — | no | `aws-sns-topic` | Messaging |
-| `aws-ecr-repo` | `cloud-container-repo` | no | `aws-region` | Containers |
-| `aws-ecs-cluster` | `cloud-container-cluster` | no | `aws-region` | Containers |
-| `aws-ecs-service` | `cloud-container-service` | no | `aws-ecs-cluster` | Containers |
-| `aws-ecs-task-def` | — | no | `aws-region` | Containers |
-| `aws-eks-cluster` | `cloud-container-cluster` | no | `aws-region` | Containers |
-| `aws-eks-nodegroup` | — | no | `aws-eks-cluster` | Containers |
-
-**GCP and Azure** are registered as flat provider-level types inheriting from `cloud-account`. Full hierarchies for these providers are deferred to future PRs.
-
-Only `aws-account` is user-addable — it is the top-level entry point carrying credential CLI args (`--access-key-id`, `--secret-access-key`, `--session-token`, `--region`, `--profile`). All other AWS types are children discovered or created within the account/region/VPC containment hierarchy.
-
-Cloud resource execution is **stubbed** — the handler validates configuration and resolves credentials but raises `NotImplementedError` for actual sandbox provisioning. Cloud SDK integration is planned for a future milestone.
-
-##### Database Resource Types
-
-Built-in database types use the `transaction_rollback` sandbox strategy:
-
-| Type | User Addable | Sandbox | Description |
-|------|-------------|---------|-------------|
-| `postgres` | yes | `transaction_rollback` | PostgreSQL database connection |
-| `mysql` | yes | `transaction_rollback` | MySQL database connection |
-| `sqlite` | yes | `transaction_rollback` | SQLite database file |
-| `duckdb` | yes | `transaction_rollback` | DuckDB database (file-based or in-memory) |
-
-Networked databases (`postgres`, `mysql`) accept `--connection-string`, `--host`, `--port`, `--dbname`, `--user`, `--password` CLI args. File-based databases (`sqlite`, `duckdb`) accept `--path`. Database hierarchy restructuring (inheritance from a generic `database` base type) is deferred to a separate effort.
-
-##### Custom Resource Types
-
-Custom resource types are defined in YAML configuration files and registered via `agents resource type add`. Once registered, a custom type automatically becomes available as a new subcommand under `agents resource add`.
-
-
-# File: resource-types/database.yaml
-cleveragents:
- version: "3.0"
-
-resource_type:
- name: local/database
- description: "A SQL database (PostgreSQL, MySQL, SQLite, etc.)"
- physical_or_virtual: physical
- user_addable: true
-
- # CLI arguments for `agents resource add local/database`
- cli_arguments:
- - name: connection-string
- type: string
- required: true
- description: "Database connection string (e.g., postgresql://host/dbname)"
- validation:
- pattern: "^(postgresql|mysql|sqlite)://"
- - name: schema
- type: string
- required: false
- description: "Default schema to use"
- - name: read-only
- type: boolean
- required: false
- default: false
- description: "Whether the database should be treated as read-only"
-
- # Sandbox and handler
- sandbox_strategy: transaction_rollback
- handler: DatabaseHandler
- checkpointable: true
-
- # Allowed parent types (empty means can be top-level)
- allowed_parent_types: []
-
- # Child types
- child_types:
- - type: local/db-schema
- auto_discover: true
- manual_link: false
- description: "Discovered database schemas"
- - type: local/db-table
- auto_discover: true
- manual_link: false
- description: "Discovered tables within schemas"
-
- # Capabilities
- capabilities:
- readable: true
- writable: true
- sandboxable: true
- checkpointable: true
-
-
-When this type is registered:
-
-agents resource type add --config ./resource-types/database.yaml
-# Now available: agents resource add local/database <NAME> --connection-string CONN [--schema SCHEMA] [--read-only]
-
-
-The `user_addable` field determines whether the type appears as a subcommand. Types with `user_addable: false` are only auto-generated as children — for example, `git-remote`, `git-branch`, `git-commit`, and `git-tree-entry` are never created directly by users but are discovered when a `git` (or `git-checkout`) resource is registered.
-
-#### The Resource DAG
-
-Resources form a **directed acyclic graph** (DAG), not a simple tree. A resource can have **multiple parents** and **multiple children**, subject to type constraints. The diagram below shows how a `git-checkout`, a standalone `git` repo (remote), a standalone `fs-directory`, and virtual resources interconnect:
-
-```kroki-plantuml
-@startuml
-skinparam defaultFontSize 10
-skinparam objectFontSize 10
-skinparam packageStyle rectangle
-
-package "GIT-CHECKOUT: local/app" as GCO #LightBlue {
- object "git-checkout" as gco {
- local/app
- }
- object "git" as gcoGit {
- local/app:repo
- }
- object "git-remote" as gcoRemote {
- origin
- }
- object "git-tag" as gcoTag {
- v1.0.0
- }
- object "git-branch" as gcoBranch {
- main
- }
- object "git-commit" as gcoCommit {
- a1b2c3d
- }
- object "git-tree" as gcoTree {
- e8f1... root
- }
- object "git-tree-entry" as gcoEntry1 {
- README.md
- }
- object "git-tree" as gcoSubtree {
- src/
- }
- object "git-tree-entry" as gcoEntry2 {
- src/app.ts
- }
- object "git-tree-entry" as gcoEntry3 {
- src/main.ts
- }
- object "fs-directory" as gcoFs {
- local/app:worktree
- }
- object "fs-directory" as gcoSrcDir {
- src/
- }
- object "fs-file" as gcoReadme {
- README.md
- }
- object "fs-file" as gcoApp {
- app.ts
- }
- object "fs-file" as gcoMain {
- main.ts
- }
-}
-
-package "GIT (remote): local/upstream" as GR #LightYellow {
- object "git" as gr {
- local/upstream
- }
- object "git-remote" as grRemote {
- origin
- }
- object "git-tag" as grTag {
- v1.0.0
- }
- object "git-branch" as grBranch {
- main
- }
- object "git-commit" as grCommit {
- a1b2c3d
- }
- object "git-tree" as grTree {
- e8f1... root
- }
- object "git-tree-entry" as grEntry1 {
- README.md
- }
- object "git-tree" as grSubtree {
- src/
- }
- object "git-tree-entry" as grEntry2 {
- src/app.ts
- }
- object "git-tree-entry" as grEntry3 {
- src/main.ts
- }
-}
-
-package "STANDALONE FS-DIRECTORY: local/deploy" as SFD #LightGreen {
- object "fs-directory" as sfd {
- /opt/deploy/myapp
- }
- object "fs-directory" as sfdSrcDir {
- src/
- }
- object "fs-file" as sfdReadme {
- README.md
- }
- object "fs-file" as sfdApp {
- app.ts
- }
- object "fs-file" as sfdMain {
- main.ts
- }
-}
-
-package "VIRTUAL LAYER" as VL #Lavender {
- object "file" as vFile {
- app.ts@v1
- }
- object "directory" as vDir {
- src/@v1
- }
- object "commit" as vCommit {
- a1b2c3d
- }
- object "branch" as vBranch {
- main@a1b...
- }
- object "tag" as vTag {
- v1.0.0
- }
- object "remote" as vRemote {
- github.com/org/repo
- }
- object "tree" as vTree {
- e8f1...9d2a
- }
-}
-
-' Physical hierarchy
-gco --> gcoGit
-gco --> gcoFs
-gcoGit --> gcoRemote
-gcoGit --> gcoTag
-gcoGit --> gcoBranch
-gcoBranch --> gcoCommit
-gcoCommit --> gcoTree
-gcoTree --> gcoEntry1
-gcoTree --> gcoSubtree
-gcoSubtree --> gcoEntry2
-gcoSubtree --> gcoEntry3
-gcoFs --> gcoSrcDir
-gcoFs --> gcoReadme
-gcoSrcDir --> gcoApp
-gcoSrcDir --> gcoMain
-
-gr --> grRemote
-gr --> grTag
-gr --> grBranch
-grBranch --> grCommit
-grCommit --> grTree
-grTree --> grEntry1
-grTree --> grSubtree
-grSubtree --> grEntry2
-grSubtree --> grEntry3
-
-sfd --> sfdSrcDir
-sfd --> sfdReadme
-sfdSrcDir --> sfdApp
-sfdSrcDir --> sfdMain
-
-' Virtual equivalence links
-gcoApp ..> vFile
-sfdApp ..> vFile
-gcoEntry2 ..> vFile
-grEntry2 ..> vFile
-gcoSrcDir ..> vDir
-sfdSrcDir ..> vDir
-gcoSubtree ..> vDir
-grSubtree ..> vDir
-gcoCommit ..> vCommit
-grCommit ..> vCommit
-gcoBranch ..> vBranch
-grBranch ..> vBranch
-gcoTag ..> vTag
-grTag ..> vTag
-gcoRemote ..> vRemote
-grRemote ..> vRemote
-gcoTree ..> vTree
-grTree ..> vTree
-@enduml
-```
-
-**Key properties of the DAG:**
-
-1. **Multiple parents**: A `git-tree-entry` has a `git-tree` parent (git structure) and potentially a `file` virtual parent (content identity). An `fs-file` has an `fs-directory` parent (filesystem hierarchy) and potentially a `file` virtual parent. An `fs-directory` can be a child of `git-checkout` (as its worktree root), a child of `fs-mount` (as the mount root), a child of another `fs-directory` (as a subdirectory), a child of a `directory` virtual (identity), or a standalone user-registered resource.
-2. **Multiple children**: A `git-checkout` has a `git` child and an `fs-directory` child. A `git` resource has `git-remote`, `git-branch`, `git-tag`, `git-stash`, `git-submodule`, and `git-commit` children. A `git-commit` has a `git-tree` child. A `git-tree` has `git-tree-entry` and nested `git-tree` children.
-3. **Cycles are forbidden**: The graph is always a DAG. The system validates this when links are created.
-4. **Type constraints**: Not any resource can be a child of any other — the parent's resource type defines which child types are allowed (see the Allowed Parents / Allowed Children columns in the built-in types tables).
-5. **Cross-layer bridge**: Virtual resources link equivalent physical resources from different layers (git structure, filesystem, different repos). The `file` virtual type bridges `fs-file` + `git-tree-entry`. The `directory` virtual type bridges `fs-directory` + `git-tree`. The `commit`, `branch`, `tag`, `remote`, `submodule`, and `tree` virtual types link the same git structural element across different repositories.
-
-##### Purpose of the Resource DAG
-
-!!! adr "Architecture Decision"
- The operational semantics of the resource DAG — what the DAG is for at runtime — are defined in [ADR-036: Resource DAG Operational Semantics](adr/ADR-036-resource-dag-operational-semantics.md). Tool reachability and access projection are defined in [ADR-037](adr/ADR-037-tool-reachability-and-access-projection.md). Cross-mechanism coordination is defined in [ADR-038](adr/ADR-038-cross-mechanism-sandbox-coordination.md).
-
-The DAG is not just a structural record of resource relationships — it is the **topology of the system's operational world**. Every runtime decision about how to reach a resource, how to safely change it, and what else is affected flows through the DAG. The DAG answers five fundamental questions:
-
-| Question | DAG Feature | Runtime Operation |
-|----------|-------------|-------------------|
-| **What is this?** | Virtual resource identity (hub node linking equivalents) | Equivalence class queries, divergence detection |
-| **Where does it live?** | Physical manifestations and containment hierarchy | Auto-discovery, resource registration |
-| **How do I reach it?** | Tool binding → containment edges → access projection | Forward/inverse reachability, read/write routing |
-| **How do I safely change it?** | Sandbox boundaries and cross-mechanism coordination | Sandbox boundary algebra, coherence-aware commit |
-| **What else is affected?** | Descendant invalidation, ancestor propagation, sibling sync | Change propagation, access control propagation |
-
-These decompose into ten specific operational purposes:
-
-1. **Tool reachability**: Knowing which tools can reach a resource transitively through containment. A tool bound to a `git-checkout` can reach every `fs-file` descendant. The inverse query — given a file, what tools can reach it — requires walking up containment edges.
-
-2. **Equivalence and alternative paths**: Virtual resources link physical resources that represent the same logical identity. When one path is unavailable, the system finds alternatives through equivalence.
-
-3. **Read/write routing**: Different physical manifestations of the same virtual resource offer different access richness. An `lsp-document` provides semantic reads (types, diagnostics); an `fs-file` via `git-checkout` provides sandbox-tracked writes. The DAG enables routing reads through the richest path and writes through the canonical sandbox-tracked path.
-
-4. **Sandbox boundary algebra**: Not every resource is independently sandboxable. A file's sandbox boundary is its containing `git-checkout` or `fs-directory`. All resources sharing a sandbox boundary share one sandbox instance. The function `sandbox_boundary(r)` walks up containment edges to find the nearest sandboxable ancestor.
-
-5. **Cross-mechanism sandbox coordination**: When the same virtual resource has physical manifestations in different sandbox domains (e.g., git-checkout and container mount), writes through one path must be coordinated with the other at commit time. The coherence property (`transparent`, `cached`, `independent`) on physical-to-virtual edges determines what coordination is needed.
-
-6. **Dependency ordering**: The DAG provides topological orderings for lifecycle operations — sandbox creation (top-down), commit (bottom-up), rollback (top-down), cleanup (bottom-up), auto-discovery (top-down).
-
-7. **Change propagation**: When a file changes, the DAG determines what else is affected: parent directories need status updates, virtual parents need identity re-evaluation, equivalent physical siblings need cache invalidation.
-
-8. **Access control propagation**: A `read_only` constraint on a `git-checkout` propagates to all descendant files. The effective writability of a resource is the conjunction of its own writability and all its containment ancestors' writability.
-
-9. **Auto-discovery scope**: The DAG defines the cascade structure for resource auto-discovery — directories before files, git repos before branches, containers before mounts.
-
-10. **Tool capability inference**: A tool's effective write scope is bounded by the sandbox domain of its bound resource. A tool bound to an `fs-file` cannot create sibling directories; a tool bound to a `git-checkout` can reach the entire worktree.
-
-#### Physical vs Virtual Resources
-
-Resources are either **physical** or **virtual**, a distinction determined by their resource type.
-
-**Physical resources** are specific, concrete manifestations. Each physical resource is a particular instance that exists somewhere — a file at a particular path on a particular machine, a git repository at a particular URL on a particular server, a commit in a particular repo. Physical resources can be directly read and written by tools. Most resources are physical.
-
-**Virtual resources** represent an abstract identity that links equivalent physical resources. They answer the question: "where else does this same thing exist?" A `file` virtual resource links all the physical `fs-file` and `git-tree-entry` resources that have the same content, filename, and permissions. A `commit` virtual resource links `git-commit` resources across repos that share the same commit hash. Virtual resources have no location of their own and cannot be directly read or written.
-
-**Rules for the physical/virtual boundary:**
-
-1. The **children of a virtual resource** can be physical resources, other virtual resources, or a combination of both.
-2. A **physical resource's parents** can be either physical or virtual resources.
-3. **Not all physical resources need a virtual parent**. Virtual resource linking is optional and only applies when equivalence tracking is meaningful.
-
-**Equivalence linking:**
-
-Two physical resources share a virtual parent when they are equivalent by the virtual type's criteria. Each virtual type has its own equivalence semantics:
-
-* **`file`**: Physical files (`fs-file` or `git-tree-entry`) share a `file` parent when they have the same content bytes (SHA-256), the same filename, and the same permissions. This is the primary cross-layer bridge — it links filesystem files with git blob entries. Example: `local/app:worktree:src/main.py` (an `fs-file`) and `local/app:repo:main:a1b...:src/main.py` (a `git-tree-entry`) both have the same content in a clean checkout, so they share a `file` virtual parent.
-
-* **`directory`**: Physical directories (`fs-directory`) and git trees (`git-tree`) share a `directory` parent when their full recursive contents are equivalent. This bridges the filesystem and git layers — the `src/` directory on disk and the `src/` subtree in git's tree object can be linked when their contents match.
-
-* **`symlink`**: Physical symlinks (`fs-symlink`) and git tree entries with symlink mode (`git-tree-entry` mode 120000) share a `symlink` parent when they have the same name and target.
-
-* **`commit`**: Physical commits (`git-commit`) in different repos share a `commit` parent when they have the same commit hash. This is common when repos share history (e.g., a fork and its upstream).
-
-* **`branch`**: Physical branches (`git-branch`) in different repos share a `branch` parent when they have the same name and the same HEAD commit hash. A push or local commit on one repo causes divergence.
-
-* **`tag`**: Physical tags (`git-tag`) in different repos share a `tag` parent when they have the same tag name and target object.
-
-* **`remote`**: Physical remotes (`git-remote`) in different repos share a `remote` parent when they point to the same URL. Answers: "these repos share the same upstream."
-
-* **`submodule`**: Physical submodules (`git-submodule`) in different repos share a `submodule` parent when they have the same submodule URL and path.
-
-* **`tree`**: Physical tree objects (`git-tree`) in different commits or repos share a `tree` parent when they have the same tree hash — identical directory structure and contents.
-
-**Divergence detection:**
-
-When a physical resource's content changes (e.g., a file is edited, a directory gains a new file, a branch advances), the system detects that it may no longer match its virtual parent's identity. At that point:
-
-* If the edit causes the physical resource to diverge from all other physical siblings under the same virtual parent, the physical resource is unlinked from that virtual parent.
-* If the edit makes it match a *different* virtual resource's identity, it may be re-linked.
-* Content equivalence is tracked via content hashing: SHA-256 for files, Merkle hashes for directories, tree hashes for git trees, commit hashes for commits, HEAD+name for branches, name+target for tags, URL for remotes.
-* **Cascading divergence**: When a `file` link breaks, the parent `directory` virtual resource is also re-evaluated (since its identity depends on all child identities).
-
-This enables powerful queries like:
-
-* "What physical locations exist for this file content?" → Find all physical resources sharing the `file` virtual parent.
-* "What tools can edit this file?" → Find all tools with resource bindings compatible with the physical resource types.
-* "Has this file been modified in any location?" → Check if all physical siblings still share the same `file` virtual parent.
-* "Are these two repos in sync?" → Check if their branches share a `branch` virtual parent.
-* "Which directories are identical across deployments?" → Find `directory` virtual resources with multiple physical children.
-* "What submodules are shared across projects?" → Find `submodule` virtual resources with multiple physical children.
-
-##### Lazy Virtual Node Materialization
-
-!!! adr "Architecture Decision"
- Lazy virtual node materialization is defined in [ADR-038: Cross-Mechanism Sandbox Coordination](adr/ADR-038-cross-mechanism-sandbox-coordination.md).
-
-Virtual resource nodes are **not created eagerly** for every physical resource. They are materialized lazily when a second physical manifestation sharing the same identity is discovered.
-
-**Lifecycle:**
-
-1. **Single manifestation**: A physical resource exists with no virtual parent. It has a content hash but no equivalence link. This is the common case — most files exist in only one location.
-
-2. **Second manifestation discovered**: When a new physical resource is registered (or auto-discovered) and its identity matches an existing physical resource's identity (per the virtual type's equivalence rule), a virtual node is created and both physical resources are linked as children.
-
-3. **Additional manifestations**: Subsequent physical resources matching the same identity are linked to the existing virtual node.
-
-4. **Manifestation removed**: When a physical resource is deregistered or diverges, its edge to the virtual parent is removed. If only one physical child remains, the virtual node is removed (collapsed back to single manifestation). If zero remain, the virtual node is removed entirely.
-
-Each virtual type defines an **identity function** mapping physical resources to canonical identity keys:
-
-| Virtual Type | Identity Key |
-|-------------|--------------|
-| `file` | SHA-256(content) + filename + permissions |
-| `directory` | Merkle hash of recursive child identities |
-| `commit` | Commit hash |
-| `branch` | Branch name + HEAD commit hash |
-| `tag` | Tag name + target object |
-| `remote` | Normalized URL |
-| `submodule` | Submodule URL + path |
-| `tree` | Tree hash |
-| `symlink` | Symlink name + target path |
-
-Materialization is triggered by: resource registration, auto-discovery, content change detection, and on-demand refresh.
-
-##### Coherence Property
-
-!!! adr "Architecture Decision"
- The coherence property and cross-mechanism coordination protocol are defined in [ADR-038: Cross-Mechanism Sandbox Coordination](adr/ADR-038-cross-mechanism-sandbox-coordination.md).
-
-Every edge from a physical resource to its virtual parent carries a **coherence** property describing how changes to this physical manifestation relate to other manifestations of the same virtual identity:
-
-| Coherence | Meaning | Sync Action at Commit |
-|-----------|---------|----------------------|
-| `transparent` | Changes are immediately visible in sibling manifestations (shared storage). | No action — verify by content hash. |
-| `cached` | The sibling caches content; changes require an explicit refresh signal. | Send invalidation signal (e.g., LSP `workspace/didChangeWatchedFiles`). |
-| `independent` | Siblings are fully independent copies; changes are invisible until explicit sync. | Copy content from canonical target, or unlink the sibling (accept divergence). |
-
-Common coherence assignments:
-
-| Scenario | Coherence |
-|----------|-----------|
-| `fs-file` via git-checkout ↔ `fs-file` via container bind mount | `transparent` (same inode through bind mount) |
-| `fs-file` via git-checkout ↔ `fs-file` via devcontainer workspace bind mount | `transparent` (default devcontainer behavior: bind mount) |
-| `fs-file` via git-checkout ↔ `fs-file` via devcontainer workspace volume mount | `independent` (configurable via `workspaceMount` in devcontainer.json) |
-| `fs-file` ↔ `lsp-document` | `cached` (LSP buffers file content) |
-| `fs-file` via git-checkout ↔ `fs-file` via container volume mount | `independent` (separate copy) |
-| `git-commit` in repo A ↔ `git-commit` in repo B | `independent` (same hash but separate stores) |
-
-##### Cross-Mechanism Write Coordination
-
-When a plan modifies a physical resource that has siblings under the same virtual parent (i.e., equivalent physical resources in different sandbox domains), the system coordinates at **sandbox commit time** using a write-then-sync protocol:
-
-1. **During execution**: Tools write through their bound physical resource into its sandbox domain. No cross-domain propagation occurs. Other manifestations see pre-sandbox content.
-
-2. **At commit time**: The system identifies dirty virtual resources (virtual resources with at least one modified physical child), checks for conflicts (multiple dirty children of the same virtual), and propagates changes based on coherence.
-
-3. **Conflict resolution**: If multiple physical manifestations of the same virtual resource were modified during the same plan:
- - **canonical-wins** (default): The canonical write target's changes are accepted; others are discarded with a warning.
- - **merge**: Three-way merge for text content.
- - **fail**: Reject the commit; surface the conflict for human resolution.
- - **last-writer-wins**: Accept the most recent modification.
-
-The **canonical write target** for a virtual resource is the physical manifestation in the strongest sandbox domain (`git_worktree` > `snapshot` > `copy_on_write` > `transaction_rollback`), with user override available. Writes should be routed to the canonical target whenever possible to avoid conflicts.
-
-#### Resource Registration (CLI)
-
-Resources are created via `agents resource add ` with type-specific arguments. Auto-discovered children are created automatically:
-
-
-# Register a checked-out git repository (most common)
-agents resource add git-checkout local/api-repo --path /home/user/projects/api-service --branch main
-# Auto-discovers: git child (repo metadata, remotes, branches, commits, tree entries)
-# + fs-directory child (worktree root directory, subdirectories, files)
-
-# Register a git repo via remote URL (no local checkout — exists on remote server)
-agents resource add git local/upstream --url git@github.com:org/upstream.git
-# Auto-discovers: remotes, branches, tags, commits, trees, tree entries, stashes, submodules
-# (no fs-directory — not checked out locally)
-
-# Register a standalone directory (not a git repo — just files on disk)
-agents resource add fs-directory local/docs --path /opt/docs/api-reference
-# Auto-discovers: subdirectories, files, symlinks, hardlinks
-
-# Register a standalone filesystem mount (entire volume)
-agents resource add fs-mount local/data-volume --mount-path /mnt/data
-# Auto-discovers: root fs-directory, subdirectories, files, symlinks, hardlinks
-
-# Link resources to projects (resources must be registered first)
-agents project link-resource local/api-service local/api-repo
-agents project link-resource local/api-service local/docs --read-only
-
-
-#### Auto-Discovery
-
-When a resource is registered, its resource type's handler **auto-discovers child resources**. This process:
-
-1. **Scans** the resource to identify children (e.g., a `git-checkout` handler creates a `git` child and an `fs-directory` child for the worktree root; a `git` handler lists remotes, branches, tags, commits, stashes, and submodules; a `git-commit` handler creates a root `git-tree` child; a `git-tree` handler lists tree entries and subtrees; an `fs-mount` handler creates a root `fs-directory` and discovers its contents; an `fs-directory` handler discovers subdirectories, files, symlinks, and hardlinks; a `git-checkout` or `fs-directory` handler additionally detects `.devcontainer/devcontainer.json` and creates a `devcontainer-instance` child in `discovered` state — see [ADR-043](adr/ADR-043-devcontainer-integration.md)).
-2. **Creates** child resource records in the Resource Registry identified by auto-generated ULIDs. Auto-discovered children do not receive names — they are identified by ULID only, even if their resource type is user-addable.
-3. **Reuses existing resources**: If a discovered child matches an already-registered resource (same type + same value/location), the existing resource is **linked** as a child rather than creating a duplicate. For example, if `local/docs` (an `fs-directory` resource at `/home/user/projects/api-service`) is already registered and the `git-checkout` handler discovers its worktree root at the same path, it links to the existing `local/docs` resource instead of creating a new one.
-4. **Links virtual resources**: When auto-discovery detects that a physical resource's content matches an existing virtual resource (via content hashing), it links the physical resource as a child of the virtual resource.
-
-Auto-discovered children are marked as `auto: true` in the DAG, distinguishing them from manually linked children. Auto-discovered links cannot be manually unlinked (they are managed by the handler), while manually created links can be freely managed.
-
-Auto-discovery runs:
-* At registration time (`agents resource add`)
-* On refresh (when the system detects changes, e.g., new commits, new files)
-* On demand (when a tool accesses the resource and the handler detects staleness)
-
-##### Devcontainer Auto-Discovery
-
-!!! adr "Architecture Decision"
- Devcontainer auto-discovery is defined in [ADR-043: Devcontainer Integration and Container-Project Association](adr/ADR-043-devcontainer-integration.md).
-
-When `git-checkout` or `fs-directory` auto-discovery scans the filesystem tree, if a `.devcontainer/devcontainer.json` file is found, a `devcontainer-instance` child resource is created with `provisioning_state: discovered`. The devcontainer.json is parsed to populate configuration properties (image, features, workspace mount, ports), but **no container is built or started** — consistent with the system's lazy sandboxing philosophy.
-
-Key behaviors:
-
-* **Lazy activation**: The container is only built when a plan first needs to execute a tool inside it. Child resources (`container-mount`, `container-exec-env`, `container-port`) are created on activation, not at discovery time.
-* **Multiple devcontainers**: Nested `.devcontainer/` directories (e.g., per-service devcontainers in a monorepo) each produce separate `devcontainer-instance` resources. The devcontainer spec supports [multiple named configurations](https://containers.dev/implementors/spec/#devcontainerjson) via `.devcontainer//devcontainer.json`.
-* **Workspace mount**: The devcontainer's workspace mount defaults to the parent `git-checkout` path (or `fs-directory` path). The `container-mount` relationship is recorded at discovery time but not materialized until activation.
-* **Auto-detected execution environment**: The discovered devcontainer automatically becomes the default execution environment for tools operating on the parent resource, subject to execution environment precedence rules (see [Execution Environment Routing](#execution-environment-routing)).
-
-#### Resource Capabilities
-
-Each resource declares its capabilities, derived from its resource type:
-
-| Capability | Description |
-|-----------|-------------|
-| `readable` | Whether the resource can be read |
-| `writable` | Whether the resource can be modified |
-| `sandboxable` | Whether the resource supports sandbox isolation |
-| `checkpointable` | Whether the resource supports checkpoint/rollback |
-
-These capabilities are used by the **tool execution flow** to validate that a tool's resource binding is compatible — a tool declaring `access: read_write` on a resource slot cannot be bound to a read-only resource.
-
-#### Resource Registry
-
-CleverAgents maintains a **Resource Registry** — a persistent catalog of all registered resources and their DAG relationships:
-
-```kroki-plantuml
-@startuml
-skinparam classAttributeIconSize 0
-skinparam classFontSize 13
-skinparam defaultFontSize 12
-
-class ResourceRegistry {
- - resourceIndex : Map
- - typeIndex : Map
- --
- + add(type, name, properties) : ResourceRecord
- + update(name, properties) : ResourceRecord
- + remove(name) : void
- + lookup(name) : ResourceRecord
- + list(filters) : ResourceRecord[]
- + tree(name, depth) : DAG_subtree
- + link_child(parent, child) : void
- + unlink_child(parent, child) : void
- + refresh(name) : void
- + find_by_content(hash) : ResourceRecord[]
- + find_virtual_parent(resource) : ResourceRecord
-}
-
-class ResourceRecord {
- + name : String
- + type : String
- + physical_or_virtual : PhysVirt
- + properties : Map
- + capabilities : Capabilities
- + parents : List
- + children : List
- + content_hash : String
- + linked_projects : List
- + created_at : DateTime
- + updated_at : DateTime
-}
-
-class ResourceTypeRecord {
- + name : String
- + description : String
- + source : String
- + physical_or_virtual : PhysVirt
- + user_addable : Boolean
- + cli_arguments : List
- + allowed_parent_types : List
- + child_types : Map
- + sandbox_strategy : String
- + handler : String
- + capabilities : Capabilities
- + config_path : String
-}
-
-enum PhysVirt {
- physical
- virtual
-}
-
-ResourceRegistry "1" *-- "0..*" ResourceRecord : indexes resources >
-ResourceRegistry "1" *-- "0..*" ResourceTypeRecord : indexes types >
-ResourceRecord --> PhysVirt
-ResourceTypeRecord --> PhysVirt
-
-note right of ResourceRegistry
- **Populated by:**
- - agents resource add CLI
- - Auto-discovery during registration
- - Content-identity linking
-
- **Consumed by:**
- - Tool binding resolution
- - Sandbox creation
- - Change tracking
- - Project linking
- - Plan validation
-end note
-@enduml
-```
-
-The Resource Registry persists in the database (local SQLite or server). It works alongside the Tool Registry and Skill Registry.
-
-#### Resource Sandbox Strategy
-
-**Each resource defines its own sandbox strategy**, determined by its resource type. This is critical because:
-
-1. The same resource may be accessed through different tools and skills
-2. Different resource types require different sandboxing approaches
-3. Some resources cannot be sandboxed at all
-
-| Resource Type | Sandbox Strategy | Rollback Mechanism |
-|--------------|------------------|-------------------|
-| `git-checkout` | `git_worktree` | Git reset/checkout |
-| `git` | `none` | N/A (represents a repo instance — not directly sandboxable) |
-| `fs-mount` | `copy_on_write`, `filesystem_copy`, or `overlay` | Restore from snapshot or delete copy |
-| `fs-directory` | `copy_on_write` or `filesystem_copy` | Restore from snapshot or delete copy |
-| Custom database types | `transaction_rollback` | Transaction rollback |
-| Custom API types | `none` (often not sandboxable) | N/A |
-
-**Filesystem sandbox strategies** differ in their prerequisites and tradeoffs:
-
-- **`copy_on_write`**: Leverages the filesystem's native copy-on-write capability (e.g., BTRFS, ZFS). The filesystem preserves original data blocks when edits occur, creating lightweight snapshots without duplicating data upfront. Only available on CoW-capable filesystems.
-- **`filesystem_copy`**: Performs an explicit full copy of the resource directory (e.g., via `cp`). Works on all writable filesystems regardless of CoW support, at the cost of duplicating data upfront.
-- **`overlay`**: Uses an overlay filesystem (e.g., OverlayFS) to layer changes on top of the original directory. Writes go to the upper layer while the lower layer remains untouched. Requires OS-level overlay mount support.
-
-The sandbox strategy is inherited by child resources from their parent unless the child type defines its own. For example, `git-branch`, `git-commit`, `git-tree`, and `git-tree-entry` all inherit from their `git` ancestor. `fs-file`, `fs-symlink`, and `fs-hardlink` inherit from their `fs-directory` parent.
-
-| Resource Type | Sandbox Strategy | Rollback Mechanism |
-|--------------|------------------|-------------------|
-| `container-instance` | `snapshot` | Container commit/checkpoint |
-| `devcontainer-instance` (inherits `container-instance`) | `snapshot` (inherited) | Container commit/checkpoint (inherited) |
-| `container-volume` | `snapshot` | Volume snapshot |
-| `container-mount` | (inherits from `container-instance`) | (inherits) |
-| `container-exec-env` | (inherits from `container-instance`) | (inherits) |
-| `lsp-server` | `none` | N/A (server process, not directly sandboxable) |
-| `lsp-workspace` | `none` (delegates to backing resource) | N/A |
-| `lsp-document` | `none` (delegates to backing file) | N/A |
-
-##### Sandbox Boundary Algebra
-
-!!! adr "Architecture Decision"
- The sandbox boundary algebra is defined in [ADR-036: Resource DAG Operational Semantics](adr/ADR-036-resource-dag-operational-semantics.md).
-
-Not every resource in the DAG is independently sandboxable — a file cannot be sandboxed in isolation. Instead, the DAG has **sandbox boundaries**: specific nodes at which sandboxing is physically implementable. All resources within a sandbox boundary's domain share one sandbox instance.
-
-**Definitions:**
-
-* **Sandbox boundary**: A resource `b` where `b.capabilities.sandboxable == true` and `b.sandbox_strategy != none`. Examples: `git-checkout` (git_worktree), `fs-directory` (copy_on_write), `container-instance` (snapshot).
-
-* **`sandbox_boundary(r)`**: The nearest ancestor of `r` (inclusive) along `contains` edges that is a sandbox boundary. If `r` itself is a boundary, returns `r`. If no boundary exists in `r`'s ancestor chain, returns `None` (unsandboxable).
-
-* **Sandbox domain**: The set of all resources `{r : sandbox_boundary(r) == b}` — resources whose nearest sandbox boundary is `b`. All resources in a domain share the same sandbox instance during plan execution.
-
-**Properties:**
-
-1. Sandbox domains **partition** all sandboxable resources into disjoint groups.
-2. The `SandboxManager` keys sandboxes by `(plan_id, sandbox_boundary_id)`, not by individual resource ID.
-3. Multiple files in the same git checkout share one git_worktree sandbox.
-4. When a virtual resource has physical manifestations in **different sandbox domains** (e.g., a file in both a git-checkout domain and a container-instance domain), cross-mechanism coordination is needed at commit time (see Cross-Mechanism Write Coordination above).
-
-**Dependency ordering for lifecycle operations:**
-
-| Operation | Traversal Direction | Rationale |
-|-----------|-------------------|-----------|
-| Sandbox creation | Top-down (parent before child) | Parent must be sandboxed before children can be accessed within it |
-| Sandbox commit | Bottom-up (child before parent) | Child changes finalized before parent incorporates them |
-| Sandbox rollback | Top-down (parent before child) | Rolling back parent implicitly rolls back children |
-| Sandbox cleanup | Bottom-up (child before parent) | Clean up children before removing parent |
-
-#### Lazy Sandboxing
-
-Resources are **sandboxed lazily when accessed**, not upfront. This is different from indexing — resources are indexed immediately when registered, but sandboxes are only created when execution needs to modify a resource:
-
-1. A project may link many resources (e.g., git repo + databases + cloud accounts)
-2. A plan may only need to modify one resource
-3. Only the accessed resources are sandboxed
-4. Each plan/child plan has its own sandbox containing only edited resources
-
-This is efficient for large projects where most resources remain untouched.
-
-#### Resource Access Tracking
-
-The system tracks **which tools access which resources** through the tool-resource binding system. This tracking happens at multiple levels:
-
-1. **Declaration-time**: Tool YAML declares resource slots with type and access mode (see **Resource Bindings** in the Tools section).
-2. **Activation-time**: When a tool is activated for a plan, its resource slots are bound to specific resources. The system records these bindings.
-3. **Execution-time**: Every tool invocation logs which bound resources were actually accessed, what operations were performed (read/write/delete), and what paths or objects were touched.
-
-This enables:
-
-* **Accurate sandbox scoping**: Only sandbox resources that will actually be modified.
-* **Rollback feasibility analysis**: Know exactly which resources were modified and whether they support rollback.
-* **Security auditing**: Complete record of which tools accessed which resources and how.
-* **Cross-resource impact analysis**: Determine if changes to a resource affect tools bound to sibling or child resources.
-* **Virtual resource consistency**: Detect when a physical resource diverges from its virtual parent.
-
-#### Unified Resource Abstraction Layer
-
-CleverAgents provides a unified abstraction that allows tools to work with any resource type through a consistent interface. This enables:
-
-1. **Resource-agnostic tools**: A tool like `read_content(path)` works whether the path refers to a file, database record, or API endpoint.
-2. **Consistent sandbox semantics**: All resources support the same sandbox lifecycle (create, read, write, checkpoint, rollback).
-3. **Pluggable resource handlers**: New resource types can be added by registering custom resource types without modifying existing tools.
-4. **Unified change tracking**: All resource modifications flow into the same ChangeSet model.
-
-##### Resource Handler Interface
-
-Every resource type provides a handler that implements this interface:
-
-
-class ResourceHandler(Protocol):
- """Handler for a specific resource type."""
-
- def read(self, path: str, sandbox: Sandbox) -> Content:
- """Read content from the sandboxed resource."""
- ...
-
- def write(self, path: str, content: Content, sandbox: Sandbox) -> Change:
- """Write content and return the Change record."""
- ...
-
- def delete(self, path: str, sandbox: Sandbox) -> Change:
- """Delete resource and return the Change record."""
- ...
-
- def list(self, pattern: str, sandbox: Sandbox) -> list[str]:
- """List paths matching pattern."""
- ...
-
- def diff(self, path: str, sandbox: Sandbox) -> str:
- """Generate diff between sandbox and original state."""
- ...
-
- def supports_operation(self, operation: OperationType) -> bool:
- """Check if this resource supports the given operation."""
- ...
-
- def discover_children(self, resource: ResourceRecord) -> list[ResourceRecord]:
- """Auto-discover child resources (called at registration and refresh)."""
- ...
-
- def content_hash(self, path: str, sandbox: Sandbox) -> str:
- """Compute content hash for identity tracking."""
- ...
-
- def create_sandbox(self, resource: ResourceRecord) -> Sandbox:
- """Create a sandbox for this resource using its type's strategy."""
- ...
-
- def create_checkpoint(self, sandbox: Sandbox) -> Checkpoint:
- """Create a checkpoint within the sandbox."""
- ...
-
- def rollback_to(self, sandbox: Sandbox, checkpoint: Checkpoint) -> None:
- """Roll back sandbox state to a checkpoint."""
- ...
-
- def project_access(
- self,
- binding_resource: ResourceRecord,
- target_resource: ResourceRecord,
- containment_path: list[ResourceRecord],
- sandbox: Sandbox | None,
- ) -> AccessProjection | None:
- """Compute how to reach target_resource from binding_resource.
-
- Returns an AccessProjection with access_path, protocol,
- crosses_sandbox flag, and read_richness score. Returns None
- if this handler cannot project access to the target type.
- Used by the tool reachability and read/write routing system.
- """
- ...
-
-
-##### Built-in Resource Handlers
-
-| Resource Type | Handler | Read | Write | Delete | Sandbox Strategy |
-|--------------|---------|------|-------|--------|------------------|
-| `git-checkout` | `GitCheckoutHandler` | ✓ | ✓ | ✓ | `git_worktree` |
-| `git` | `GitHandler` | ✓ | ✗ | ✗ | `none` |
-| `git-commit`, `git-tree`, `git-tree-entry` | `GitObjectHandler` | ✓ | ✗ | ✗ | (inherits) |
-| `git-branch`, `git-tag`, `git-stash` | `GitRefHandler` | ✓ | ✓ | ✓ | (inherits) |
-| `git-remote`, `git-submodule` | `GitConfigHandler` | ✓ | ✗ | ✗ | (inherits) |
-| `fs-mount` | `FilesystemHandler` | ✓ | ✓ | ✓ | `copy_on_write` |
-| `fs-directory` | `FilesystemHandler` | ✓ | ✓ | ✓ | `copy_on_write` |
-| `fs-file`, `fs-symlink`, `fs-hardlink` | `FilesystemHandler` | ✓ | ✓ | ✓ | (inherits) |
-| `container-runtime` | `ContainerRuntimeHandler` | ✓ | ✗ | ✗ | `none` |
-| `container-image` | `ContainerImageHandler` | ✓ | ✗ | ✗ | `none` |
-| `container-instance` | `ContainerInstanceHandler` | ✓ | ✓ | ✓ | `snapshot` |
-| `devcontainer-instance` (inherits `container-instance`) | `DevcontainerHandler` | ✓ | ✓ | ✓ | `snapshot` (inherited) |
-| `container-mount`, `container-exec-env`, `container-port` | `ContainerChildHandler` | ✓ | varies | ✗ | (inherits) |
-| `container-volume` | `ContainerVolumeHandler` | ✓ | ✓ | ✓ | `snapshot` |
-| `container-network` | `ContainerNetworkHandler` | ✓ | ✗ | ✗ | `none` |
-| `executable` | `ExecutableHandler` | ✓ | ✗ | ✗ | `none` |
-| `lsp-server` | `LSPServerHandler` | ✓ | ✗ | ✗ | `none` |
-| `lsp-workspace` | `LSPWorkspaceHandler` | ✓ | ✗ | ✗ | `none` |
-| `lsp-document` | `LSPDocumentHandler` | ✓ | ✓ | ✗ | `none` |
-
-Additional handlers are provided by custom resource types when they are registered.
-
-!!! adr "Architecture Decision"
- Container resource types are defined in [ADR-039: Container and Execution Environment Resource Types](adr/ADR-039-container-resource-types.md). The `devcontainer-instance` subtype, container-project association patterns, and execution environment routing are defined in [ADR-043: Devcontainer Integration and Container-Project Association](adr/ADR-043-devcontainer-integration.md). Resource type inheritance (the `inherits` mechanism) is defined in [ADR-042: Resource Type Inheritance](adr/ADR-042-resource-type-inheritance.md). LSP resource types are defined in [ADR-040: LSP Resource Types](adr/ADR-040-lsp-resource-types.md).
-
-##### Resource Path Resolution
-
-Paths in tool invocations are resolved through a resource routing system that uses tool-resource bindings to determine the target resource:
-
-```kroki-mermaid
-sequenceDiagram
- participant Tool as Tool Invocation
- participant Router as Resource Router
- participant Handler as GitCheckoutHandler
-
- Tool->>Router: edit_file(path='src/main.py', ...)
- Router->>Router: Check tool's resource bindings
- Note right of Router: slot 'repo' bound to
local/api-repo (git-checkout)
- Router->>Router: Resolve path within bound resource
- Note right of Router: local/api-repo:worktree:src/main.py
- Router->>Handler: Route to resource handler
- Handler->>Handler: Resolve path to sandbox worktree
- Handler->>Handler: Operate on sandboxed state
- Handler-->>Tool: Return Change record
-```
-
-When a tool has multiple resource slots bound, the path scheme or slot name disambiguates:
-
-
-# Explicit slot reference
-path://repo/src/main.py → routes to the "repo" slot's bound resource
-path://docs/api/readme.md → routes to the "docs" slot's bound resource
-
-# Default: unqualified paths route to the tool's primary resource slot
-src/main.py → routes to the first (or only) resource slot
-
-
-
-
-### Context
-
-!!! adr "Architecture Decision"
- The Advanced Context Management System, UKO ontology, CRP protocol, and context strategies are defined in [ADR-014: Context Management (ACMS)](adr/ADR-014-context-management-acms.md).
-
-The Advanced Context Management System (ACMS) is CleverAgents' fully pluggable, strategy-driven framework for assembling context for actors. It replaces and subsumes the basic context tier system with a comprehensive architecture built around three core innovations:
-
-1. **A Universal Knowledge Ontology (UKO)** -- an inheritance-based RDF ontology hierarchy that represents *any* resource (source code, documents, databases, infrastructure) at multiple levels of abstraction, with full provenance back to the originating resource and temporal versioning across revisions.
-
-2. **A Context Request Protocol (CRP)** -- a structured vocabulary through which actors (via skills) declare what information they need, at what level of detail, and with what scope, while they are reasoning. This replaces static "context view" approaches with a dynamic, demand-driven model.
-
-3. **A Context Assembly Pipeline** -- a pluggable, 10-component pipeline that replaces the former monolithic Strategy Coordinator and Fusion Engine. Multiple independent context strategies can be registered, each working with different data backends and different abstraction levels of the UKO. The pipeline orchestrates strategy selection, budget allocation, parallel execution, fragment deduplication, depth resolution, scoring, budget packing, ordering, preamble generation, and skeleton compression -- each step backed by a replaceable Protocol implementation configurable at global, project, or plan scope.
-
-The system is designed around the hierarchical nature of plans: parent plans see wide, shallow context (breadth); child plans see narrow, deep context (depth). Context inheritance flows parent-to-child with progressive focusing, and every context assembly respects a dynamically-changing token budget. This architecture is domain-agnostic: the same breadth/depth/DetailDepth mechanics work identically whether the underlying resources are source code repositories, technical documents, database schemas, or infrastructure configurations.
-
-**Critical Design Decision**: All indexing happens immediately when resources are added to projects or when code changes. There is no "on-demand" indexing during agent execution. This ensures that agents always have instant access to search capabilities without any indexing delays. The computational cost is paid once upfront, not repeatedly during agent operations.
-
-> The full architectural design of the ACMS -- including the UKO ontology hierarchy, backend abstraction layer, Context Assembly Pipeline (the 10-component pluggable pipeline that replaced the former Strategy Coordinator and Fusion Engine), index synchronization, performance characteristics, and plugin architecture -- is specified in the **Architecture > ACMS Architecture** section.
-
-#### Core Data Types
-
-The ACMS defines several data types that are used throughout the system by actors, skills, strategies, and the plan lifecycle.
-
-##### DetailDepth and DetailLevelMap
-
-At the most general level (UKO Layer 0), detail depth is simply a **non-negative integer** — 0 being the most minimal representation and each increment revealing more. There is no fixed upper bound; the maximum meaningful depth depends on the domain and the complexity of the information unit. This is the `DetailDepth` type.
-
-Each UKO domain extension then registers a **DetailLevelMap** — a table of named labels mapped to specific integer depths. This allows domain users to work with meaningful names (like `MODULE_LISTING` or `TABLE_OF_CONTENTS`) rather than raw integers, while the underlying system always operates on the universal integer scale. Maps are inherited: a language-specific map includes all levels from its parent paradigm map, which includes all levels from the general code map.
-
-
-DetailDepth = int # Non-negative integer, 0 = most minimal, no upper bound
-
-@dataclass
-class DetailLevelMap:
- """Maps named detail levels to integer depths for a UKO domain.
- Inherited: a child map includes all entries from its parent map,
- and may insert additional levels at any integer position."""
- domain: str # UKO namespace (e.g., "uko-code:", "uko-py:")
- parent: DetailLevelMap | None # Parent map to inherit from
- levels: dict[str, int] # Named level -> integer depth
- max_depth: int # Maximum meaningful depth for this domain
-
- def resolve(self, depth: int | str) -> int:
- """Resolve a named level or integer to an integer depth."""
- if isinstance(depth, int):
- return min(depth, self.max_depth)
- # Look up named level in this map, then parent maps
- if depth in self.levels:
- return self.levels[depth]
- if self.parent:
- return self.parent.resolve(depth)
- raise ValueError(f"Unknown detail level: {depth}")
-
-
-**Universal (Layer 0) Semantics:**
-
-At the universal level, each integer depth has a domain-agnostic meaning. The principle is that depth 0 answers *"what exists?"*, and each subsequent depth answers progressively more detailed questions:
-
-| Depth | Universal Question Answered | What Gets Included |
-|-------|-----------------------------|--------------------|
-| 0 | *What exists?* | Just the name/identifier of the information unit. |
-| 1 | *How is it organized?* | Names of immediate children (structural skeleton). |
-| 2 | *What are the key relationships?* | Children + dependency/reference edges to other units. |
-| 3 | *What is each thing's purpose?* | + Short descriptions/summaries for each child. |
-| 4 | *What is the structural shape?* | + Type information, size/count metadata, categories. |
-| 5+ | *How does it work? What does it say?* | Progressively more content, up to complete verbatim content at max depth. |
-| max | *Everything.* | Complete content — nothing omitted. |
-
-The exact number of meaningful depths varies by domain (source code may have 12+ levels, a flat config file may only have 4). The system never forces content into a fixed number of buckets.
-
-**Source Code DetailLevelMap (`uko-code:`, extended by `uko-oo:`, `uko-py:`, etc.):**
-
-The general software domain defines a base set of named levels. Paradigm-specific and language-specific extensions insert additional levels where their semantics provide meaningful distinctions.
-
-| Depth | `uko-code:` Name | Content Shown |
-|-------|-------------------|---------------|
-| 0 | `MODULE_LISTING` | Module/package names only, no internal structure. |
-| 1 | `MODULE_GRAPH` | Module names + inter-module dependency edges (imports graph). |
-| 2 | `MEMBER_LISTING` | + Names of top-level members within each module (classes, functions, constants) — no signatures. |
-| 3 | `MEMBER_SUMMARY` | + One-line docstring or LLM-generated summary for each member. |
-| 4 | `SIGNATURES` | + Full type signatures (parameter names, types, return types) for all callables and type definitions. |
-| 5 | `SIGNATURES_WITH_DOCS` | + Complete docstrings/comments attached to each member. |
-| 6 | `STRUCTURAL_OUTLINE` | + Control flow structure within callable bodies (branches, loops, try/except) shown as outline, no expressions. |
-| 7 | `KEY_LOGIC` | + Key expressions: return statements, assertions, assignments to important variables. |
-| 8 | `NEAR_COMPLETE` | + All statements except comments, logging, and boilerplate (imports, `__all__`, etc.). |
-| 9 | `FULL_SOURCE` | Complete source code — nothing omitted. |
-
-*Object-Oriented effective map (`uko-oo:`) — inherits from `uko-code:`, inserts `CLASS_HIERARCHY` and `VISIBILITY_ANNOTATED`:*
-
-When the `uko-oo:` extension is active, the effective DetailLevelMap is re-numbered with consecutive integers. The two inserted levels shift all subsequent depths upward:
-
-| Depth | Name | Origin | Content Shown |
-|-------|------|--------|---------------|
-| 0 | `MODULE_LISTING` | `uko-code:` | Module/package names only, no internal structure. |
-| 1 | `MODULE_GRAPH` | `uko-code:` | Module names + inter-module dependency edges (imports graph). |
-| 2 | `MEMBER_LISTING` | `uko-code:` | + Names of top-level members within each module (classes, functions, constants) — no signatures. |
-| 3 | `CLASS_HIERARCHY` | **`uko-oo:`** | **Inheritance chains and interface implementation relationships between classes.** |
-| 4 | `MEMBER_SUMMARY` | `uko-code:` | + One-line docstring or LLM-generated summary for each member. |
-| 5 | `SIGNATURES` | `uko-code:` | + Full type signatures (parameter names, types, return types) for all callables and type definitions. |
-| 6 | `SIGNATURES_WITH_DOCS` | `uko-code:` | + Complete docstrings/comments attached to each member. |
-| 7 | `VISIBILITY_ANNOTATED` | **`uko-oo:`** | **Public/protected/private modifiers on all members + abstract/final markers.** |
-| 8 | `STRUCTURAL_OUTLINE` | `uko-code:` | + Control flow structure within callable bodies (branches, loops, try/except) shown as outline, no expressions. |
-| 9 | `KEY_LOGIC` | `uko-code:` | + Key expressions: return statements, assertions, assignments to important variables. |
-| 10 | `NEAR_COMPLETE` | `uko-code:` | + All statements except comments, logging, and boilerplate (imports, `__all__`, etc.). |
-| 11 | `FULL_SOURCE` | `uko-code:` | Complete source code — nothing omitted. |
-
-*Python-specific effective map (`uko-py:`) — inherits from `uko-oo:`, inserts `DECORATED_SIGNATURES`, `TYPE_STUBS`, and appends `WITH_TESTS`:*
-
-When the `uko-py:` extension is active, the effective map builds on `uko-oo:` and re-numbers again:
-
-| Depth | Name | Origin | Content Shown |
-|-------|------|--------|---------------|
-| 0 | `MODULE_LISTING` | `uko-code:` | Module/package names only, no internal structure. |
-| 1 | `MODULE_GRAPH` | `uko-code:` | Module names + inter-module dependency edges (imports graph). |
-| 2 | `MEMBER_LISTING` | `uko-code:` | + Names of top-level members within each module (classes, functions, constants) — no signatures. |
-| 3 | `CLASS_HIERARCHY` | `uko-oo:` | Inheritance chains and interface implementation relationships between classes. |
-| 4 | `MEMBER_SUMMARY` | `uko-code:` | + One-line docstring or LLM-generated summary for each member. |
-| 5 | `SIGNATURES` | `uko-code:` | + Full type signatures (parameter names, types, return types) for all callables and type definitions. |
-| 6 | `SIGNATURES_WITH_DOCS` | `uko-code:` | + Complete docstrings/comments attached to each member. |
-| 7 | `DECORATED_SIGNATURES` | **`uko-py:`** | **`@property`, `@staticmethod`, `@classmethod`, custom decorator chains shown on each member.** |
-| 8 | `VISIBILITY_ANNOTATED` | `uko-oo:` | Public/protected/private modifiers on all members + abstract/final markers. |
-| 9 | `STRUCTURAL_OUTLINE` | `uko-code:` | + Control flow structure within callable bodies (branches, loops, try/except) shown as outline, no expressions. |
-| 10 | `KEY_LOGIC` | `uko-code:` | + Key expressions: return statements, assertions, assignments to important variables. |
-| 11 | `TYPE_STUBS` | **`uko-py:`** | **Type annotations from `.pyi` stub files merged with source, `typing` module usage.** |
-| 12 | `NEAR_COMPLETE` | `uko-code:` | + All statements except comments, logging, and boilerplate (imports, `__all__`, etc.). |
-| 13 | `FULL_SOURCE` | `uko-code:` | Complete source code — nothing omitted. |
-| 14 | `WITH_TESTS` | **`uko-py:`** | **Full source + associated test cases for each callable (from `uko-code:testsCallable` edges).** |
-
-**Document DetailLevelMap (`uko-doc:`):**
-
-| Depth | `uko-doc:` Name | Content Shown |
-|-------|-------------------|---------------|
-| 0 | `TITLE_ONLY` | Document title / section heading only. |
-| 1 | `TABLE_OF_CONTENTS_L1` | Title + top-level (depth-1) section/chapter headings. |
-| 2 | `TABLE_OF_CONTENTS_L2` | + Second-level subsection headings. |
-| 3 | `FULL_TOC` | Complete table of contents to all heading depths. |
-| 4 | `TOC_WITH_SUMMARIES` | Full TOC + one-sentence abstract per section (LLM-generated or extracted from first paragraph). |
-| 5 | `SECTION_OVERVIEWS` | + Topic keywords per section + cross-reference targets (which other sections this section discusses). |
-| 6 | `TOPIC_SENTENCES` | + First sentence of every paragraph within each section. |
-| 7 | `PARAGRAPH_SUMMARIES` | + LLM-generated summary for each paragraph (2-3 sentences compressed to 1). |
-| 8 | `STRUCTURAL_DETAIL` | + All figure/table captions + code block headers + list item first lines + blockquote sources. |
-| 9 | `NEAR_COMPLETE` | + Full paragraph text, but with inline formatting stripped and code blocks truncated to first/last 3 lines. |
-| 10 | `FULL_CONTENT` | Complete document content — all text, formatting, code blocks, figures, footnotes. |
-
-**Database DetailLevelMap (`uko-data:`):**
-
-| Depth | `uko-data:` Name | Content Shown |
-|-------|-------------------|---------------|
-| 0 | `SCHEMA_LISTING` | Schema/database names only. |
-| 1 | `TABLE_LISTING` | + Table and view names within each schema. |
-| 2 | `COLUMN_LISTING` | + Column names within each table (no types). |
-| 3 | `TYPED_COLUMNS` | + Column data types + nullability. |
-| 4 | `CONSTRAINTS` | + Primary keys, unique constraints, check constraints, defaults. |
-| 5 | `RELATIONSHIPS` | + Foreign key relationships (full referential graph between tables). |
-| 6 | `INDEXES_AND_STATS` | + Index definitions + estimated row counts + basic statistics (cardinality, avg row size). |
-| 7 | `DDL` | Full CREATE TABLE / CREATE VIEW DDL (reconstructed from metadata). |
-| 8 | `DDL_WITH_TRIGGERS` | + Trigger definitions + stored procedure signatures that reference each table. |
-| 9 | `FULL_PROCEDURES` | + Complete stored procedure and function bodies. |
-| 10 | `WITH_SAMPLE_DATA` | + Sample rows (configurable N, default 5) for each table. |
-| 11 | `FULL_CATALOG` | Complete catalog: DDL + all procedure bodies + triggers + sample data + value distribution histograms + query plan statistics. |
-
-**Infrastructure DetailLevelMap (`uko-infra:`):**
-
-| Depth | `uko-infra:` Name | Content Shown |
-|-------|---------------------|---------------|
-| 0 | `SERVICE_LISTING` | Service/component names only. |
-| 1 | `SERVICE_GRAPH` | + Service dependency edges (which services connect to which). |
-| 2 | `ENDPOINT_LISTING` | + Endpoint paths/ports for each service. |
-| 3 | `ENDPOINT_DETAIL` | + HTTP methods, parameters, authentication requirements per endpoint. |
-| 4 | `CONFIG_KEYS` | + Configuration key names and their sections. |
-| 5 | `CONFIG_VALUES` | + Configuration values (with secrets masked). |
-| 6 | `RESOURCE_LIMITS` | + Resource allocations (CPU, memory, replicas, storage). |
-| 7 | `FULL_CONFIG` | Complete configuration files for each service. |
-| 8 | `WITH_DEPLOYMENT` | + Deployment descriptors (Dockerfiles, Kubernetes manifests, Compose files). |
-
-**How depth resolution works in practice**: When a context request specifies `depth="SIGNATURES"` and the target node is a `uko-py:Module`, the system looks up `SIGNATURES` in the `uko-py:` DetailLevelMap first. If found, it uses that integer. If not, it walks up to `uko-oo:`, then `uko-code:`, then `uko:` until it finds a match. If the request specifies `depth=4` (a raw integer), it is used directly — the system renders the target node at integer depth 4 regardless of what named level that corresponds to.
-
-##### ContextRequest
-
-A structured request for context, issued by an actor or skill via the CRP.
-
-
-@dataclass
-class ContextRequest:
- """A structured request for context, issued by an actor or skill."""
-
- # === What to find ===
- query: str | None = None # Natural language query
- entities: list[str] = field(default_factory=list) # Named entities to focus on
- uko_types: list[str] = field(default_factory=list) # UKO types to filter
-
- # === Scope control ===
- focus: list[str] = field(default_factory=list)
- # URIs or identifiers of specific items to focus on
-
- breadth: int = 2
- # How many hops outward in the dependency/reference graph.
-
- depth: int | str = 3
- # How much detail to include for each item found.
- # May be a raw integer (0-N) or a named level string (e.g., "SIGNATURES")
- # resolved via the active DetailLevelMap for the target node's UKO type.
-
- # === Focus depth gradient ===
- depth_gradient: bool = True
- # When True, items closer to the focus get more detail.
-
- # === Temporal scope ===
- temporal: TemporalScope = TemporalScope.CURRENT
-
- # === Budget ===
- max_tokens: int | None = None
-
- # === Strategy hints ===
- preferred_strategies: list[str] = field(default_factory=list)
- required_backends: list[str] = field(default_factory=list)
-
- # === Priority and purpose ===
- priority: float = 0.5 # 0.0 = background, 1.0 = critical
- purpose: str = "" # Why is this context needed?
-
-
-##### ContextFragment
-
-The atomic unit of context returned by strategies and consumed by the Context Assembly Pipeline's fusion phase (FragmentDeduplicator, DetailDepthResolver, FragmentScorer, BudgetPacker, FragmentOrderer).
-
-
-@dataclass
-class ContextFragment:
- """A single piece of context assembled by a strategy."""
- uko_node: str # UKO URI of the source node
- content: str # Rendered text content
- detail_depth: int # Resolved integer depth of this fragment
- token_count: int # Token count of content
- relevance_score: float # 0.0-1.0 relevance to the request
- provenance: FragmentProvenance # Trace back to resource + location
- metadata: dict = field(default_factory=dict)
-
-
-##### AssembledContext
-
-The output of a context assembly cycle -- the final, budget-respecting payload delivered to an actor.
-
-
-@dataclass
-class AssembledContext:
- """The fused, budget-respecting context payload."""
- fragments: list[ContextFragment] # Ordered context fragments
- total_tokens: int # Total token count
- budget_used: float # Fraction of budget consumed (0.0-1.0)
- strategies_used: list[str] # Which strategies contributed
- context_hash: str # Cryptographic hash for snapshot
- preamble: str | None # Optional structure summary
- provenance_map: dict # Fragment -> resource/location mapping
- skeleton_fragments: tuple[ContextFragment, ...] = () # Compressed parent context for child plan inheritance
-
-
-#### Context Request Protocol (CRP)
-
-Instead of static context views, actors (through their skills) **actively request** context as they reason. The CRP defines a structured vocabulary for these requests.
-
-This is fundamentally different from existing approaches where context is assembled once before the actor runs. With CRP:
-
-1. The actor starts with an **initial context** (assembled from the plan's context view, parent context inheritance, and strategy defaults).
-2. As the actor reasons, skills can issue **refinement requests** to pull in additional context dynamically.
-3. Each request triggers a new context assembly cycle with the remaining token budget.
-
-##### The `builtin/context` Skill
-
-Actors issue context requests through a **context skill** that is automatically injected into every actor's skill set:
-
-# Built-in skill, always available
-skill:
- name: builtin/context
- description: "Request additional context during reasoning"
-
- anonymous_tools:
- - name: request_context
- description: "Request specific context to be added to the conversation"
- input_schema:
- type: object
- properties:
- query: { type: string, description: "What information do you need?" }
- focus: { type: array, items: { type: string },
- description: "Specific files, classes, or functions to focus on" }
- breadth: { type: integer, default: 2,
- description: "How many dependency hops outward (0-5)" }
- depth: { oneOf: [{ type: integer, minimum: 0 }, { type: string }],
- default: 3,
- description: "Detail depth — integer (0-N) or named level from the active DetailLevelMap (e.g., 'SIGNATURES', 'FULL_SOURCE')" }
- purpose: { type: string, description: "Why do you need this context?" }
- required: [purpose]
-
- - name: query_history
- description: "Query historical context about past decisions and changes"
- input_schema:
- type: object
- properties:
- query: { type: string }
- scope: { type: string, enum: ["current_plan", "plan_tree", "all_plans"],
- default: "plan_tree" }
- required: [query]
-
- - name: get_context_budget
- description: "Check remaining context token budget"
- input_schema:
- type: object
- properties: {}
-
-
-#### Context Strategy Protocol
-
-Every context strategy implements this protocol. Strategies are pluggable -- built-in strategies ship with CleverAgents, and custom strategies can be registered via configuration.
-
-@runtime_checkable
-class ContextStrategy(Protocol):
- """A pluggable context assembly strategy."""
-
- @property
- def name(self) -> str: ...
-
- @property
- def capabilities(self) -> StrategyCapabilities: ...
-
- def can_handle(self, request: ContextRequest,
- backends: BackendSet) -> float:
- """Returns 0.0-1.0 confidence that this strategy can usefully
- contribute to this request."""
- ...
-
- def assemble(self, request: ContextRequest,
- backends: BackendSet,
- budget: int,
- plan_context: PlanContext) -> list[ContextFragment]:
- """Execute the strategy. Must respect the budget."""
- ...
-
- def explain(self) -> str: ...
-
-
-@dataclass
-class StrategyCapabilities:
- """Declares what a strategy is capable of."""
- uses_text: bool = False
- uses_vector: bool = False
- uses_graph: bool = False
- uses_temporal: bool = False
- uko_levels: list[str] = field(default_factory=list)
- resource_types: list[str] = field(default_factory=list)
- supports_depth_breadth: bool = False
- supports_plan_hierarchy: bool = False
- supports_temporal: bool = False
- quality_score: float = 0.5
-
-
-##### Built-in Strategies
-
-| Strategy | Quality | Backends Required | Description |
-|----------|---------|------------------|-------------|
-| `simple-keyword` | 0.3 | Text only | Basic keyword/regex text search. Universal fallback. |
-| `semantic-embedding` | 0.6 | Vector | Vector similarity search for semantically related content. |
-| `breadth-depth-navigator` | 0.85 | Graph | Graph-aware UKO traversal with depth/breadth projection. Primary strategy for code-aware context. |
-| `arce` | 0.95 | All | Multi-modal pipeline combining text, vector, and graph with intent analysis. Highest quality. |
-| `temporal-archaeology` | 0.5 | Graph + Cold tier | Historical pattern discovery from past decisions and archived context. |
-| `plan-decision-context` | 0.7 | Warm/Cold tiers | Retrieves context from parent/ancestor plan decisions. |
-
-##### Strategy Registration
-
-Strategies are registered through configuration. The context assembly pipeline itself is also fully pluggable — see **Architecture > ACMS > Context Assembly Pipeline** for the ten pluggable pipeline components.
-
-[context.strategies]
-enabled = ["simple-keyword", "semantic-embedding", "arce", "breadth-depth-navigator"]
-
-[context.strategies.custom]
-"my-domain-strategy" = "my_package.strategies.DomainStrategy"
-
-# Pipeline component overrides (see Architecture > ACMS > Context Assembly Pipeline)
-[context.pipeline]
-strategy-selector = "builtin:ConfidenceWeightedSelector" # default
-budget-allocator = "builtin:ProportionalBudgetAllocator" # default
-fragment-scorer = "my_extensions.scorers:DomainAwareScorer" # custom override
-
-
-#### Hierarchical Plan Context
-
-In a plan hierarchy, each level sees a different slice of the project's resources. Context inheritance flows parent-to-child with progressive focusing. This applies universally across all UKO domains — the same breadth/depth mechanics work for codebases, documents, databases, and infrastructure.
-
-**Source Code Example:**
-
-| Level | Breadth | Depth | Example Content |
-|-------|---------|-------|-----------------|
-| Root | Entire project | 0 (`MODULE_LISTING`) | Module names, dependency graph edges |
-| Subplan A | `src/auth/` module + direct deps | 4 (`SIGNATURES`) | Function signatures with types, class inheritance chains |
-| Sub-subplan A1 | `AuthManager` class + 2-hop deps | 9 (`FULL_SOURCE`) | Complete function bodies, all parameters, all call sites |
-
-**Document Example** (e.g., a technical specification):
-
-| Level | Breadth | Depth | Example Content |
-|-------|---------|-------|-----------------|
-| Root | Entire document | 1 (`TABLE_OF_CONTENTS_L1`) | Document title + top-level chapter headings |
-| Subplan A | "Architecture" chapter + sections that `discussesTopic` it | 5 (`SECTION_OVERVIEWS`) | Section headings + topic keywords + cross-reference targets + one-sentence abstracts |
-| Sub-subplan A1 | "ACMS Architecture" section + 2-hop topic references | 10 (`FULL_CONTENT`) | Complete section text with all paragraphs, figures, code blocks |
-
-**Database Example** (e.g., schema migration planning):
-
-| Level | Breadth | Depth | Example Content |
-|-------|---------|-------|-----------------|
-| Root | Entire database | 1 (`TABLE_LISTING`) | Schema names + table and view names |
-| Subplan A | `auth` schema + tables with foreign keys into it | 5 (`RELATIONSHIPS`) | Table names + typed columns + constraints + foreign key graph |
-| Sub-subplan A1 | `users` table + dependent views and stored procedures | 9 (`FULL_PROCEDURES`) | Complete DDL + triggers + stored procedure bodies + sample data |
-
-The **skeleton** is a compact, low-depth representation (typically depth 0-1) of the parent's context window that is passed to every child. This ensures children always have the "big picture" available, even though they focus on a narrow area. The skeleton typically consumes 5-15% of the child's token budget (controlled by `skeleton_ratio`). For a source code resource, the skeleton is a `MODULE_LISTING` (depth 0) — just module names. For a document resource, the skeleton is a `TABLE_OF_CONTENTS_L1` (depth 1) — the table of contents. For a database resource, it is a `TABLE_LISTING` (depth 1) — schema and table names.
-
-#### Depth/Breadth Projection
-
-The depth/breadth projection system allows fine-grained control over how much of the knowledge graph is materialized into context. It operates on the UKO graph structure.
-
-- **Breadth** (integer, 0-N): How many hops in the `uko:references` / `uko:dependsOn` / `uko:contains^-1` graph to traverse from the focus items.
-- **Depth** (integer or named level): How much content to include for each item found. Specified as a raw integer or a named level resolved via the active DetailLevelMap.
-- **Depth gradient**: When enabled, detail decreases with distance from focus.
-
-**Source Code Projection Example:**
-
-
-Request: focus=["class://AuthManager"], breadth=2, depth=9 (FULL_SOURCE), gradient=True
-
-Result (token costs approximate):
-
-Distance 0 — depth 9 (FULL_SOURCE):
- class AuthManager: # 800 tokens
- """Manages user authentication..."""
- def authenticate(self, username, password):
- ...full body...
- def validate_token(self, token):
- ...full body...
-
-Distance 1 — depth 4 (SIGNATURES):
- class BaseManager: # 120 tokens
- def connect(self) -> Connection: ...
- def disconnect(self) -> None: ...
- class CryptoUtils: # 80 tokens
- def hash_password(pwd: str) -> str: ...
- def verify_hash(pwd: str, hash: str) -> bool: ...
- class UserDB: # 100 tokens
- def find_user(username: str) -> User | None: ...
- def create_user(user: User) -> None: ...
-
-Distance 2 — depth 0 (MODULE_LISTING):
- class Connection # 20 tokens
- class User # 15 tokens
- class DatabasePool # 15 tokens
-
-Total: ~1,150 tokens (vs ~15,000 if everything were depth 9)
-
-
-**Document Projection Example:**
-
-
-Request: focus=["uko-doc:section/security-architecture"], breadth=2, depth=10 (FULL_CONTENT), gradient=True
-
-Result (token costs approximate):
-
-Distance 0 — depth 10 (FULL_CONTENT):
- ## 5. Security Architecture # 2,400 tokens
- Complete section text including all paragraphs,
- code examples, diagrams, and subsections:
- 5.1 Authentication Flow
- 5.2 Authorization Model
- 5.3 Token Management
-
-Distance 1 — depth 6 (TOPIC_SENTENCES — sections that discuss security topics):
- ## 3. API Design # 180 tokens
- Section headings + first sentence of each paragraph:
- "The API uses JWT tokens for authentication..."
- "Rate limiting is enforced per-client..."
- ## 8. Deployment # 120 tokens
- "TLS termination occurs at the load balancer..."
- "Secrets are injected via Vault..."
-
-Distance 2 — depth 0 (TITLE_ONLY — sections referenced by distance-1 sections):
- ## 2. System Overview # 30 tokens
- ## 9. Monitoring # 25 tokens
- ## Appendix A: Threat Model # 20 tokens
-
-Total: ~2,775 tokens (vs ~18,000 if the entire document were depth 10)
-
-
-**Database Projection Example:**
-
-
-Request: focus=["uko-data:table/auth.users"], breadth=2, depth=11 (FULL_CATALOG), gradient=True
-
-Result (token costs approximate):
-
-Distance 0 — depth 11 (FULL_CATALOG):
- CREATE TABLE auth.users ( # 650 tokens
- id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
- email VARCHAR(255) UNIQUE NOT NULL,
- password_hash VARCHAR(60) NOT NULL,
- ...complete DDL + triggers + sample rows + statistics...
- );
-
-Distance 1 — depth 7 (DDL — tables with foreign keys to/from users):
- CREATE TABLE auth.sessions ( # 180 tokens
- id UUID PRIMARY KEY,
- user_id UUID REFERENCES auth.users(id),
- ...DDL with constraints...
- );
- CREATE TABLE auth.roles ( # 120 tokens
- ...DDL with constraints...
- );
- CREATE VIEW auth.active_users AS ... # 90 tokens
-
-Distance 2 — depth 1 (TABLE_LISTING — tables referenced by distance-1 tables):
- auth.permissions # 20 tokens
- auth.audit_log # 15 tokens
- public.organizations # 15 tokens
-
-Total: ~1,090 tokens (vs ~8,500 if the entire schema were depth 11)
-
-
-#### Integration with Plan Lifecycle
-
-
-Plan Lifecycle ACMS Actions
-───────────────── ────────────────────────────
-Plan created (agents plan use) ResourceScope resolved.
- ScopedBackendViews created.
-
-Strategize phase begins InitialContextAssembler runs:
- - Inherits parent context (if subplan)
- - Runs Context Assembly Pipeline
- - Produces AssembledContext
- - Injects into actor's system prompt
-
-Strategy actor reasons Actor may issue ContextRequests via
- builtin/context skill.
- Each request triggers re-assembly
- with remaining budget.
-
-Strategy actor produces decisions Each Decision's context_snapshot
- captures AssembledContext hash +
- provenance map.
-
-Execute phase begins New InitialContextAssembler run
- with execute-phase view.
- Decisions from Strategize are in
- warm tier.
-
-Execution actor works Dynamic ContextRequests as needed.
-
-Subplan spawned PlanContextInheritance computes
- child context from parent.
- SkeletonCompressor propagates parent
- context as skeleton.
- New ResourceScope (possibly narrower).
-
-Apply phase Minimal context assembly
- (validation results, diff summary).
-
-Plan completes Hot context archived to warm.
- Warm context ages to cold based
- on retention policy.
-
-
-### Output Rendering Framework
-
-!!! adr "Architecture Decision"
- The output rendering framework, format system, and reactive output sessions are defined in [ADR-021: CLI and Output Rendering](adr/ADR-021-cli-and-output-rendering.md).
-
-#### Overview
-
-CleverAgents uses a unified **Output Rendering Framework** to decouple command output data from its visual presentation. Every CLI command produces structured output through a common abstraction layer, and the active **format** determines how that output is rendered to the terminal (or piped to external consumers). The format is set via the global `--format` flag, the `format` config key, or defaults to `rich`.
-
-The framework is **reactive-first**: commands do not build a static data structure and hand it to a renderer. Instead, commands open an **output session**, create **element handles** for each piece of output (a panel, a table, a progress indicator), and write data to those handles — potentially from multiple concurrent producers. The session coordinates with a **materialization strategy** selected by the active format, which decides *when* and *how* each element's content reaches the terminal. A `rich` session renders updates in-place as they arrive; a `plain` session buffers each element and flushes sequentially; a `json` session accumulates everything and serializes once at the end. **Producer code is format-agnostic** — it writes to handles without knowing which format is active.
-
-This architecture is designed for modularity, extensibility, and future-proofing — the same session-based output can be consumed by the CLI, a future TUI, a web frontend, or programmatic integrations. The design uses a pipeline of composable stages: **session lifecycle management**, **typed element handles**, **event-driven materialization**, and **format-specific element rendering**.
-
-#### Architecture
-
-##### Rendering Pipeline
-
-All CLI output flows through a five-stage reactive pipeline:
-
-```kroki-mermaid
-flowchart LR
- A["Command Logic"] --> B["OutputSession\n(lifecycle)"]
- B --> C["ElementHandles\n(typed producers)"]
- C --> D["MaterializationStrategy\n(format-driven policy)"]
- D --> E["Terminal / Pipe\n(stdout/stderr)"]
-```
-
-1. **Command Logic** opens an `OutputSession` and creates typed **element handles** — `PanelHandle`, `TableHandle`, `ProgressHandle`, etc. — for each piece of output the command will produce. Handles are created in **declaration order**, which determines the canonical order in which elements appear in sequential formats.
-
-2. **OutputSession** is the central coordinator. It owns the set of active handles, tracks their lifecycle (open → writing → closed), emits `ElementEvent` objects to the active materialization strategy, and provides a `snapshot()` method that returns a static `StructuredOutput` representing the accumulated state at any point in time.
-
-3. **ElementHandles** are the producer-facing API. Each handle is typed for a specific element kind (panel, table, tree, etc.) and exposes write methods appropriate to that kind (`add_row()`, `set_entry()`, `set_step_status()`, etc.). Handles are **thread-safe** — multiple concurrent coroutines or threads can write to different handles simultaneously. Handles are **format-agnostic** — the producer never knows or cares which format is active.
-
-4. **MaterializationStrategy** is a polymorphic observer selected by the active format. It receives `ElementEvent` notifications from the session and decides *when* and *how* to render content. Each strategy delegates the actual visual rendering of an element's accumulated state to a paired **ElementRenderer**.
-
-5. **Terminal/Pipe** receives the final byte stream. The framework auto-detects whether stdout is a TTY and degrades gracefully (e.g., `rich` falls back to `table` when piped to a non-TTY unless `--format rich` was explicitly set).
-
-##### OutputSession
-
-The `OutputSession` is the core abstraction that replaces direct construction of static output objects. Commands receive a session (typically injected by the CLI framework) and interact with it throughout their execution:
-
-
-class OutputSession:
- """A live output document that coordinates element production and materialization.
-
- The session manages the lifecycle of all output elements for a single command
- invocation. It is the bridge between format-agnostic producer code and the
- format-specific materialization strategy.
-
- Thread Safety:
- The session is thread-safe. Multiple producers may create and write to
- handles concurrently. The session serializes event delivery to the
- materialization strategy using an internal event queue.
-
- Lifecycle:
- session = OutputSession.open(command, strategy)
- handle_a = session.panel("Title") # create handles
- handle_b = session.table("Results", ...)
- handle_a.set_entry(...) # write to handles (concurrent OK)
- handle_b.add_row(...)
- handle_a.close() # close handles when done
- handle_b.close()
- session.close() # finalize the session
- """
-
- # --- Session lifecycle ---
-
- command: str # The command that owns this session
- session_id: str # Unique session identifier (ULID)
- created_at: datetime # Session creation timestamp
-
- _strategy: MaterializationStrategy # The active materialization strategy
- _handles: OrderedDict[str, ElementHandle] # handle_id → handle, in declaration order
- _event_queue: asyncio.Queue[ElementEvent] # Internal event queue for serialization
- _state: SessionState # "open" | "closing" | "closed"
- _lock: threading.Lock # Protects handle creation/removal
-
- @classmethod
- def open(cls, command: str, strategy: MaterializationStrategy,
- metadata: dict | None = None) -> "OutputSession":
- """Open a new output session.
-
- Called by the CLI framework before command execution. The strategy is
- selected based on the resolved format (see Format Resolution).
-
- Args:
- command: The command string (e.g., "project show").
- strategy: The materialization strategy for the active format.
- metadata: Optional command metadata (user, timestamp, etc.).
-
- Returns:
- A new OutputSession ready for element creation.
- """
- ...
-
- # --- Element handle factories ---
- # Each factory creates a typed handle, registers it with the session in
- # declaration order, and emits an ElementCreated event to the strategy.
-
- def panel(self, title: str, *,
- border_style: str = "rounded",
- priority: str = "normal",
- collapse_hint: str = "auto",
- metadata: dict | None = None) -> "PanelHandle":
- """Create a panel element handle for key-value pair output."""
- ...
-
- def table(self, title: str | None, *,
- columns: list["ColumnDef"],
- summary: dict | None = None,
- max_rows_hint: int | None = None,
- sort_key: str | None = None,
- priority: str = "normal",
- collapse_hint: str = "auto",
- metadata: dict | None = None) -> "TableHandle":
- """Create a table element handle for tabular data."""
- ...
-
- def tree(self, root_label: str, *,
- root_style: str | None = None,
- max_depth_hint: int | None = None,
- show_guides: bool = True,
- priority: str = "normal",
- collapse_hint: str = "auto",
- metadata: dict | None = None) -> "TreeHandle":
- """Create a tree element handle for hierarchical data."""
- ...
-
- def progress(self, label: str, *,
- total: int | None = None,
- indeterminate: bool = False,
- steps: list[str] | None = None,
- priority: str = "normal",
- metadata: dict | None = None) -> "ProgressHandle":
- """Create a progress indicator handle.
-
- Args:
- label: Display label for the progress indicator.
- total: Total units of work (None for indeterminate).
- indeterminate: If True, show a spinner instead of a progress bar.
- steps: Named steps to track (creates ProgressStep objects with
- initial status "pending").
- """
- ...
-
- def status(self, message: str, *,
- level: str = "info",
- detail: str | None = None,
- priority: str = "normal",
- metadata: dict | None = None) -> "StatusHandle":
- """Create a status message handle."""
- ...
-
- def text(self, content: str = "", *,
- wrap: bool = True,
- indent: int = 0,
- priority: str = "normal",
- metadata: dict | None = None) -> "TextHandle":
- """Create a text block handle."""
- ...
-
- def code(self, content: str = "", *,
- language: str | None = None,
- line_numbers: bool = False,
- highlight_lines: list[int] | None = None,
- priority: str = "normal",
- metadata: dict | None = None) -> "CodeHandle":
- """Create a code block handle."""
- ...
-
- def diff(self, *,
- file_a: str | None = None,
- file_b: str | None = None,
- priority: str = "normal",
- metadata: dict | None = None) -> "DiffHandle":
- """Create a diff block handle."""
- ...
-
- def separator(self, style: str = "line") -> "SeparatorHandle":
- """Create a visual separator. Separators are auto-closed on creation."""
- ...
-
- def action_hint(self, commands: list[str],
- description: str | None = None) -> "ActionHintHandle":
- """Create an action hint. Action hints are auto-closed on creation."""
- ...
-
- # --- Session operations ---
-
- def snapshot(self) -> "StructuredOutput":
- """Return a static snapshot of all elements accumulated so far.
-
- The snapshot captures the current state of every handle (open or closed)
- as a StructuredOutput object. This is used by accumulate-mode strategies
- (json/yaml) at session end, and is available at any time for logging,
- debugging, or programmatic inspection.
- """
- ...
-
- def close(self, *, exit_code: int = 0) -> "StructuredOutput":
- """Close the session and finalize all output.
-
- Any handles still open are force-closed (with a warning logged).
- Emits a SessionEnd event to the strategy. Returns the final
- StructuredOutput snapshot.
-
- Args:
- exit_code: The command's exit code (included in the snapshot).
-
- Returns:
- The final StructuredOutput snapshot.
- """
- ...
-
- # --- Context manager support ---
-
- def __enter__(self) -> "OutputSession":
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb) -> None:
- """Auto-close session on context exit.
-
- If exiting due to an exception, sets exit_code to 1 and emits an
- error status element before closing.
- """
- ...
-
-
-##### Element Handles
-
-Element handles are the producer-facing API. Each handle type wraps a specific element kind and provides methods appropriate to that kind. All handles share a common base:
-
-
-class ElementHandle(Generic[E]):
- """Base class for all element handles.
-
- An element handle is a write-only view of an output element. Producers use
- handles to incrementally build element content without knowledge of the
- active format or materialization strategy.
-
- Type Parameter:
- E: The OutputElement subclass this handle wraps (e.g., Panel, Table).
-
- Thread Safety:
- Individual handle methods are thread-safe. Multiple threads may call
- methods on *different* handles concurrently. Concurrent writes to the
- *same* handle are serialized via an internal lock.
-
- Lifecycle:
- handle = session.table(...) # Created by session factory
- handle.add_row(...) # Write operations (zero or more)
- handle.close() # Finalize (required unless auto-closed)
-
- Closed Handle Behavior:
- Calling any write method on a closed handle raises ElementClosedError.
- """
-
- handle_id: str # Unique handle identifier (ULID)
- element_type: str # Semantic type ("panel", "table", etc.)
- declaration_index: int # Position in session's declaration order
-
- _session: OutputSession # Owning session (for event emission)
- _element: E # The accumulated element state
- _state: HandleState # "open" | "closed"
- _lock: threading.Lock # Serializes writes to this handle
-
- def close(self) -> None:
- """Close this handle, signaling that no more data will be written.
-
- Emits an ElementClosed event to the materialization strategy.
- For buffered strategies, this triggers rendering of the element.
- """
- ...
-
- @property
- def is_open(self) -> bool:
- """Whether this handle is still accepting writes."""
- ...
-
- @property
- def element(self) -> E:
- """The accumulated element state (read-only snapshot)."""
- ...
-
- def __enter__(self) -> Self:
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb) -> None:
- """Auto-close handle on context exit."""
- if self.is_open:
- self.close()
-
-
-class PanelHandle(ElementHandle[Panel]):
- """Handle for building a Panel element incrementally.
-
- Panels are titled groups of key-value pairs. Entries can be added,
- updated, or removed after creation.
- """
-
- def set_entry(self, key: str, value: str, *,
- style_hint: str | None = None,
- icon: str | None = None) -> None:
- """Set or update a key-value entry in the panel.
-
- If an entry with the given key already exists, it is updated.
- Otherwise, a new entry is appended.
-
- Emits an ElementUpdated event.
- """
- ...
-
- def set_entries(self, entries: dict[str, str], *,
- style_hints: dict[str, str] | None = None) -> None:
- """Set multiple entries at once (batch update). Emits a single event."""
- ...
-
- def remove_entry(self, key: str) -> None:
- """Remove an entry by key. Emits an ElementUpdated event."""
- ...
-
-
-class TableHandle(ElementHandle[Table]):
- """Handle for building a Table element incrementally.
-
- Tables are the primary element for streamed data. Rows can be added
- one at a time or in batches as data becomes available from queries,
- API calls, or concurrent operations.
- """
-
- def add_row(self, row: dict) -> None:
- """Append a single row to the table.
-
- The row dict maps column names to cell values. Missing columns
- are filled with None. Extra columns not in the schema are ignored.
-
- Emits an ElementUpdated event (type=row_added).
- """
- ...
-
- def add_rows(self, rows: list[dict]) -> None:
- """Append multiple rows in a batch. Emits a single ElementUpdated event."""
- ...
-
- def set_summary(self, summary: dict) -> None:
- """Set or update the summary/aggregation row. Emits an ElementUpdated event."""
- ...
-
- def set_sort_key(self, column: str, *, descending: bool = False) -> None:
- """Change the sort key. Emits an ElementUpdated event."""
- ...
-
-
-class TreeHandle(ElementHandle[Tree]):
- """Handle for building a Tree element incrementally.
-
- Trees are built by adding child nodes to existing nodes. The root node
- is created with the handle. Subtrees can be constructed incrementally
- as hierarchical data is discovered.
- """
-
- def add_child(self, parent_path: str | None, label: str, *,
- style_hint: str | None = None,
- collapsed: bool = False,
- metadata: dict | None = None) -> str:
- """Add a child node to the tree.
-
- Args:
- parent_path: Slash-separated path to the parent node (None = root).
- label: Display label for the new node.
- style_hint: Optional color/style hint.
- collapsed: Whether this node starts collapsed in interactive renderers.
- metadata: Arbitrary data attached to the node.
-
- Returns:
- The full path to the newly created node (for use as parent_path
- in subsequent add_child calls).
-
- Emits an ElementUpdated event.
- """
- ...
-
- def set_node_style(self, path: str, style_hint: str) -> None:
- """Update the style of an existing node. Emits an ElementUpdated event."""
- ...
-
-
-class ProgressHandle(ElementHandle[ProgressIndicator]):
- """Handle for updating a ProgressIndicator element.
-
- Progress handles are unique in that they are expected to receive many
- rapid updates. The materialization strategy may throttle update events
- to avoid overwhelming the terminal (e.g., limiting redraws to 10/sec).
- """
-
- def set_progress(self, current: int, total: int | None = None) -> None:
- """Update the progress counter.
-
- Args:
- current: Current progress value.
- total: Total value (can change, e.g., when total is discovered late).
-
- Emits an ElementUpdated event (may be throttled by the strategy).
- """
- ...
-
- def set_step_status(self, step_label: str, status: str) -> None:
- """Update the status of a named step.
-
- Args:
- step_label: The label of the step to update.
- status: New status — "pending" | "active" | "done" | "error" | "skipped".
-
- Emits an ElementUpdated event.
- """
- ...
-
- def set_label(self, label: str) -> None:
- """Update the progress label text. Emits an ElementUpdated event."""
- ...
-
- def increment(self, delta: int = 1) -> None:
- """Increment progress by delta. Convenience wrapper around set_progress."""
- ...
-
-
-class StatusHandle(ElementHandle[StatusMessage]):
- """Handle for a status message.
-
- Status handles are typically created and immediately closed (fire-and-forget
- messages). However, they can be kept open for messages that may be revised
- (e.g., a "Working..." status that becomes "Done" or "Failed").
- """
-
- def set_message(self, message: str) -> None:
- """Update the status message text. Emits an ElementUpdated event."""
- ...
-
- def set_level(self, level: str) -> None:
- """Change the status level. Emits an ElementUpdated event."""
- ...
-
- def set_detail(self, detail: str | None) -> None:
- """Set or clear the detail text. Emits an ElementUpdated event."""
- ...
-
-
-class TextHandle(ElementHandle[TextBlock]):
- """Handle for a text block. Supports appending text incrementally."""
-
- def append(self, text: str) -> None:
- """Append text to the block. Emits an ElementUpdated event."""
- ...
-
- def set_content(self, content: str) -> None:
- """Replace the entire content. Emits an ElementUpdated event."""
- ...
-
-
-class CodeHandle(ElementHandle[CodeBlock]):
- """Handle for a code block."""
-
- def set_content(self, content: str) -> None:
- """Set the code content. Emits an ElementUpdated event."""
- ...
-
- def set_language(self, language: str) -> None:
- """Set the language for syntax highlighting. Emits an ElementUpdated event."""
- ...
-
- def set_highlight_lines(self, lines: list[int]) -> None:
- """Set lines to highlight. Emits an ElementUpdated event."""
- ...
-
-
-class DiffHandle(ElementHandle[DiffBlock]):
- """Handle for a diff block. Hunks can be added incrementally."""
-
- def add_hunk(self, header: str, lines: list["DiffLine"]) -> None:
- """Add a diff hunk. Emits an ElementUpdated event."""
- ...
-
- def set_stats(self, insertions: int, deletions: int, **extra: int) -> None:
- """Set diff statistics. Emits an ElementUpdated event."""
- ...
-
-
-##### Element Events
-
-Element handles communicate with the materialization strategy through a typed event system. Events are the sole interface between production (handles) and consumption (strategy) — this indirection is what enables format-agnostic producer code:
-
-
-class ElementEvent:
- """Base class for all events emitted by element handles."""
- event_type: str # "created" | "updated" | "closed"
- handle_id: str # The handle that emitted this event
- element_type: str # The element kind ("panel", "table", etc.)
- timestamp: datetime # When the event occurred
- session_id: str # The owning session
-
-
-class ElementCreated(ElementEvent):
- """Emitted when a new element handle is created via a session factory."""
- event_type = "created"
- declaration_index: int # Position in session declaration order
- initial_state: OutputElement # The element's initial state
-
-
-class ElementUpdated(ElementEvent):
- """Emitted when data is written to an element handle."""
- event_type = "updated"
- update_type: str # Kind-specific: "entry_set", "row_added",
- # "progress_changed", "step_status_changed", etc.
- delta: dict # The change payload (what was added/modified)
- element_snapshot: OutputElement # The full element state after this update
-
-
-class ElementClosed(ElementEvent):
- """Emitted when an element handle is closed (no more data will arrive)."""
- event_type = "closed"
- final_state: OutputElement # The element's final accumulated state
-
-
-class SessionEnd(ElementEvent):
- """Emitted when the session itself is closed."""
- event_type = "session_end"
- exit_code: int
- snapshot: "StructuredOutput" # The complete accumulated output
-
-
-##### Element Data Model (Snapshot Types)
-
-Each element handle accumulates state into a typed **snapshot object**. These are the data classes that represent a fully-built element — they are what the `ElementRenderer` receives when it is time to paint. They are also the building blocks of the `StructuredOutput` returned by `session.snapshot()`:
-
-
-class OutputElement:
- """Base class for all output element snapshot types."""
- element_type: str # Semantic type identifier
- metadata: dict # Arbitrary metadata (timestamps, IDs, etc.)
- priority: str = "normal" # "critical" | "normal" | "supplementary"
- collapse_hint: str = "auto" # "always" | "auto" | "never" — guidance for renderers
- # on whether this element can be collapsed/hidden
-
-class Panel(OutputElement):
- """A titled group of key-value pairs."""
- element_type = "panel"
- title: str
- entries: list[PanelEntry] # Each entry: key, value, style_hint (color, icon, etc.)
- border_style: str = "rounded" # "rounded" | "square" | "heavy" | "none"
-
-class PanelEntry:
- """A single key-value pair within a Panel."""
- key: str
- value: str
- style_hint: str | None = None # Color/style for the value (e.g., "success", "warning")
- icon: str | None = None # Optional icon/prefix character
-
-class Table(OutputElement):
- """A tabular data set with typed columns."""
- element_type = "table"
- title: str | None
- columns: list[ColumnDef] # name, type, alignment, width_hint, sortable
- rows: list[dict] # Column name → cell value
- summary: dict | None # Optional aggregation row (totals, counts)
- max_rows_hint: int | None # Suggest truncation for large datasets
- sort_key: str | None # Default sort column
-
-class ColumnDef:
- """Schema for a single table column."""
- name: str # Column display name
- type: str = "string" # "string" | "number" | "boolean" | "datetime" | "id"
- alignment: str = "left" # "left" | "right" | "center"
- width_hint: int | None = None # Suggested character width (None = auto)
- sortable: bool = False # Whether this column can be sorted
- style_hint: str | None = None # Default style for cells in this column
-
-class Tree(OutputElement):
- """A hierarchical tree structure."""
- element_type = "tree"
- root: TreeNode # Recursive node structure
- max_depth_hint: int | None # Suggest depth truncation
- show_guides: bool = True # Whether to show tree guide lines
-
-class TreeNode:
- """A node in a tree structure."""
- label: str
- style_hint: str | None # Color/style for this node
- children: list["TreeNode"]
- collapsed: bool = False # Hint: start collapsed in interactive renderers
- metadata: dict # Arbitrary data attached to the node
-
-class StatusMessage(OutputElement):
- """A status line (success, warning, error, info)."""
- element_type = "status"
- level: str # "ok" | "warn" | "error" | "info"
- message: str
- detail: str | None # Optional detail text
-
-class ProgressIndicator(OutputElement):
- """A progress bar or spinner for long-running operations."""
- element_type = "progress"
- label: str
- current: int | None
- total: int | None
- indeterminate: bool = False # Spinner mode vs. progress bar mode
- steps: list[ProgressStep] | None # Named steps with status (pending/active/done)
-
-class ProgressStep:
- """A named step within a progress indicator."""
- label: str
- status: str # "pending" | "active" | "done" | "error" | "skipped"
-
-class CodeBlock(OutputElement):
- """A block of source code with optional syntax highlighting."""
- element_type = "code"
- content: str
- language: str | None # For syntax highlighting
- line_numbers: bool = False
- highlight_lines: list[int] | None # Lines to emphasize
-
-class DiffBlock(OutputElement):
- """A unified diff display."""
- element_type = "diff"
- hunks: list[DiffHunk]
- file_a: str | None
- file_b: str | None
- stats: dict | None # insertions, deletions, etc.
-
-class DiffHunk:
- """A single hunk within a diff."""
- header: str # @@ line range @@
- lines: list[DiffLine]
-
-class DiffLine:
- """A single line in a diff hunk."""
- type: str # "context" | "add" | "remove"
- content: str
- line_number_old: int | None
- line_number_new: int | None
-
-class TextBlock(OutputElement):
- """A free-form text block (descriptions, rationale, etc.)."""
- element_type = "text"
- content: str
- wrap: bool = True
- indent: int = 0
-
-class Separator(OutputElement):
- """A visual separator between logical groups."""
- element_type = "separator"
- style: str = "line" # "line" | "blank" | "double"
-
-class ActionHint(OutputElement):
- """A suggested next-step action for the user."""
- element_type = "action_hint"
- commands: list[str] # Suggested CLI commands
- description: str | None
-
-class StructuredOutput:
- """Static snapshot of a complete command output.
-
- This is the accumulated state of all elements at a point in time.
- It is produced by OutputSession.snapshot() and OutputSession.close().
-
- Uses:
- - Final serialization for json/yaml formats
- - Logging and audit trails
- - Programmatic inspection and testing
- - TUI widget data binding (initial state)
- """
- command: str # The command that produced this output
- session_id: str # The session that produced this output
- elements: list[OutputElement] # Ordered list of element snapshots
- exit_code: int = 0
- timing: dict | None # start_time, end_time, duration
- metadata: dict # command-specific metadata
-
-
-##### Materialization Strategies
-
-The materialization strategy is the format-side counterpart to the output session. It receives element events and decides *when* and *how* to render content. Each strategy is paired with an `ElementRenderer` that handles the actual visual formatting of individual elements.
-
-The strategy pattern creates a clean separation between **timing/ordering policy** (when to render) and **visual formatting** (how to render). This means the same `PlainElementRenderer` can be used whether elements arrive all-at-once or are streamed concurrently — the strategy handles the coordination.
-
-
-class MaterializationStrategy(Protocol):
- """Interface for format-driven output materialization.
-
- A materialization strategy receives element lifecycle events from the
- OutputSession and decides when to render element content to the output
- stream. Strategies do not render elements themselves — they delegate
- to a paired ElementRenderer at the appropriate time.
-
- The strategy is the mechanism by which format-agnostic producer code
- produces correct output regardless of format. The producer writes to
- handles; the strategy decides what reaches the terminal and when.
- """
-
- strategy_name: str # "live" | "sequential_buffer" | "accumulate"
-
- def bind(self, renderer: "ElementRenderer",
- terminal_caps: "TerminalCapabilities") -> None:
- """Bind this strategy to a renderer and terminal capabilities.
-
- Called once during format resolution, before the session opens.
- The strategy retains a reference to the renderer for use during
- event handling. The output stream is provided separately via
- on_session_begin, since the session owns the stream.
- """
- ...
-
- def on_session_begin(self, session: OutputSession, stream: IO) -> None:
- """Called when the session opens. The strategy receives the output
- stream and may write preamble (e.g., opening JSON bracket)."""
- ...
-
- def on_element_created(self, event: ElementCreated) -> None:
- """Called when a new element handle is created."""
- ...
-
- def on_element_updated(self, event: ElementUpdated) -> None:
- """Called when data is written to an element handle."""
- ...
-
- def on_element_closed(self, event: ElementClosed) -> None:
- """Called when an element handle is closed."""
- ...
-
- def on_session_end(self, event: SessionEnd) -> None:
- """Called when the session closes. The strategy may write epilogue."""
- ...
-
-
-class LiveMaterializer(MaterializationStrategy):
- """Materialization strategy for the `rich` format.
-
- Renders element updates in real-time using terminal cursor movement.
- Multiple elements can be visually active and updating simultaneously.
- The terminal display is a live document that is rewritten in place.
-
- Behavior:
- - on_element_created: Allocates screen region for the element, renders
- initial (possibly empty) visual state.
- - on_element_updated: Re-renders the element in place using cursor
- movement. For progress indicators, updates may be throttled to a
- maximum refresh rate (default: 15 fps) to avoid terminal flooding.
- - on_element_closed: Renders the final state and freezes the screen
- region (no further updates). May apply a visual transition (e.g.,
- spinner resolves to a checkmark).
- - on_session_end: Finalizes the display, moves cursor to end, and
- restores normal terminal scrolling.
-
- Screen Layout:
- Elements are arranged vertically in declaration order. Each element
- occupies a contiguous block of terminal lines. The materializer tracks
- the line offset and height of each element's region. When an element's
- height changes (e.g., a table gains rows), subsequent elements are
- shifted down.
-
- Concurrent Updates:
- Updates from multiple handles are coalesced into a single frame refresh
- at the target frame rate. The materializer maintains a dirty-element set
- and redraws all dirty elements in a single pass per frame.
- """
- strategy_name = "live"
-
- _frame_rate: float = 15.0 # Maximum redraws per second
- _element_regions: OrderedDict[str, ScreenRegion] # handle_id → screen region
- _dirty_set: set[str] # handle_ids that need redraw
- _frame_timer: asyncio.TimerHandle # Coalescing timer for frame redraws
-
-
-class SequentialBufferMaterializer(MaterializationStrategy):
- """Materialization strategy for `plain`, `color`, and `table` formats.
-
- Buffers element content and renders elements sequentially in declaration
- order. An element's content is rendered to the output stream only when
- its handle is closed. If handles are closed out of declaration order,
- the out-of-order element's rendered content is held in a buffer until
- all preceding elements have been rendered.
-
- This strategy ensures that static, scrolling output formats produce
- coherent sequential output even when producers write to handles
- concurrently and close them in arbitrary order.
-
- Behavior:
- - on_element_created: Records the element's declaration index. No output.
- - on_element_updated: Buffers the update internally. No output.
- - on_element_closed: If this element is the next in declaration order,
- renders it immediately (and any buffered subsequent elements that are
- also closed). Otherwise, buffers the rendered content.
- - on_session_end: Force-renders any remaining buffered elements (handles
- that were never closed, in declaration order).
-
- Example (two tables populated concurrently):
- 1. Handle A (index 0) created — table "Resources"
- 2. Handle B (index 1) created — table "Validations"
- 3. Handle B receives rows, Handle A receives rows (interleaved)
- 4. Handle B closes (index 1) — rendered content buffered (waiting for A)
- 5. Handle A closes (index 0) — A is rendered to stream, then buffered B
- is rendered to stream
-
- Result: Output shows table A followed by table B, regardless of the
- order in which data arrived or handles closed.
- """
- strategy_name = "sequential_buffer"
-
- _next_render_index: int = 0 # The declaration index to render next
- _rendered_buffers: dict[int, str] # index → pre-rendered content (waiting)
- _closed_set: set[int] # Declaration indices of closed elements
-
-
-class AccumulateMaterializer(MaterializationStrategy):
- """Materialization strategy for `json` and `yaml` formats.
-
- Accumulates all element data silently until the session ends, then
- serializes the complete StructuredOutput as a single JSON or YAML
- document.
-
- Behavior:
- - on_element_created: No output.
- - on_element_updated: No output.
- - on_element_closed: No output.
- - on_session_end: Calls session.snapshot() to get the final
- StructuredOutput, then delegates to the ElementRenderer's
- serialize() method for complete document serialization.
-
- This strategy is the simplest — it ignores all intermediate events and
- only acts on session_end. It exists as a distinct strategy (rather than
- a special case) to maintain the uniform strategy interface.
- """
- strategy_name = "accumulate"
-
-
-##### ElementRenderer Protocol
-
-While the `MaterializationStrategy` controls *when* elements are rendered, the `ElementRenderer` controls *how* each element type is visually formatted. Each format has a paired `ElementRenderer` implementation:
-
-
-class ElementRenderer(Protocol):
- """Interface for format-specific element rendering.
-
- An ElementRenderer knows how to paint each element type for a specific
- output format. It is called by the MaterializationStrategy when it is
- time to render an element.
-
- Implementations:
- - PlainElementRenderer: ASCII text, no escapes
- - ColorElementRenderer: ANSI-colored text, same layout as plain
- - TableElementRenderer: Unicode box-drawing with color
- - RichElementRenderer: Advanced terminal features (cursor, animation)
- - JsonElementRenderer: JSON serialization
- - YamlElementRenderer: YAML serialization
- """
-
- format_name: str # "plain", "color", "table", "rich", "json", "yaml"
-
- def render_panel(self, panel: Panel, stream: IO) -> None:
- """Render a panel element to the stream."""
- ...
-
- def render_table(self, table: Table, stream: IO) -> None:
- """Render a table element to the stream."""
- ...
-
- def render_tree(self, tree: Tree, stream: IO) -> None:
- """Render a tree element to the stream."""
- ...
-
- def render_status(self, status: StatusMessage, stream: IO) -> None:
- """Render a status message to the stream."""
- ...
-
- def render_progress(self, progress: ProgressIndicator, stream: IO) -> None:
- """Render a progress indicator to the stream."""
- ...
-
- def render_code(self, code: CodeBlock, stream: IO) -> None:
- """Render a code block to the stream."""
- ...
-
- def render_diff(self, diff: DiffBlock, stream: IO) -> None:
- """Render a diff block to the stream."""
- ...
-
- def render_text(self, text: TextBlock, stream: IO) -> None:
- """Render a text block to the stream."""
- ...
-
- def render_separator(self, separator: Separator, stream: IO) -> None:
- """Render a visual separator to the stream."""
- ...
-
- def render_action_hint(self, hint: ActionHint, stream: IO) -> None:
- """Render an action hint to the stream."""
- ...
-
- def render_element(self, element: OutputElement, stream: IO) -> None:
- """Dispatch to the appropriate render method based on element type.
-
- This is the primary entry point used by materialization strategies.
- It uses a dispatch table to route to the correct typed method.
- """
- dispatch = {
- "panel": self.render_panel,
- "table": self.render_table,
- "tree": self.render_tree,
- "status": self.render_status,
- "progress": self.render_progress,
- "code": self.render_code,
- "diff": self.render_diff,
- "text": self.render_text,
- "separator": self.render_separator,
- "action_hint": self.render_action_hint,
- }
- handler = dispatch.get(element.element_type)
- if handler:
- handler(element, stream)
-
- def serialize(self, output: StructuredOutput, stream: IO) -> None:
- """Serialize a complete StructuredOutput to the stream.
-
- Used by AccumulateMaterializer for json/yaml formats. For visual
- formats (plain/color/table/rich), this method iterates over
- output.elements and calls render_element for each.
- """
- ...
-
- def can_render(self, terminal_caps: "TerminalCapabilities") -> bool:
- """Whether this renderer can operate in the given terminal environment."""
- ...
-
-
-##### Format Resolution
-
-The active format is resolved using a precedence chain:
-
-1. **CLI flag**: `--format ` on the command line (highest priority).
-2. **Environment variable**: `CLEVERAGENTS_FORMAT=`.
-3. **Config file**: The `core.format` key in the global config (`agents config set core.format `).
-4. **TTY detection**: If stdout is not a TTY and no explicit format was set, fall back to `plain` (not `rich`), since non-TTY consumers cannot interpret ANSI codes or cursor movement.
-5. **Default**: `rich`.
-
-Once the format is resolved, the CLI framework selects the corresponding `(MaterializationStrategy, ElementRenderer)` pair from the `RendererRegistry`, opens an `OutputSession` bound to that strategy, and passes the session to the command implementation.
-
-#### Format Specifications
-
-##### `plain` — Plain Text
-
-**Philosophy**: Maximum portability. Output is pure ASCII text with no escape codes, no box-drawing characters, and no color. Suitable for piping to files, logs, grep, awk, or any non-terminal consumer.
-
-**Rendering rules**:
-
-- **Panels**: Rendered as indented key-value pairs with a header line.
-- **Tables**: Rendered as aligned columns separated by whitespace (no box drawing). Column headers are separated from data by a dashed line.
-- **Trees**: Rendered with ASCII indentation using `+--` and `|` characters.
-- **Status messages**: Prefixed with `[OK]`, `[WARN]`, `[ERROR]`, `[INFO]`.
-- **Progress**: Rendered as static status lines (no animation). Steps shown as `[x]` (done), `[ ]` (pending), `[>]` (active).
-- **Diffs**: Standard unified diff format.
-- **Code blocks**: Raw text with optional line numbers.
-- **No ANSI escape codes** of any kind.
-- **No Unicode characters** beyond basic ASCII (no box drawing, no checkmarks, no arrows).
-
-**Example** (`agents --format plain project show local/api-service`):
-
-
-$ agents --format plain project show local/api-service
-
-Project Details
- Name: local/api-service
- Description: Backend API
- Resources: 2
- Remote: no
- Created: 2026-02-08 12:46
-
-Linked Resources
- Resource Type Sandbox Read-Only
- ---------------- -------------- -------------------- ---------
- local/api-repo git-checkout git_worktree no
- local/staging-db local/database transaction_rollback yes
-
-Validations (3)
- local/run-tests pytest --cov=src --cov-fail-under=80 required
- local/lint-check ruff check . required
- local/check-bundle-size node scripts/check-bundle-size.js informational
-
-Context
- Include: repo
- Exclude: **/node_modules/**
- Max File Size: 1 MB
-
-Indexing Status
- Text Index: ready
- Vector Index: ready
- Graph Store: disabled
- Indexed Files: 347
- Last Indexed: 12:48
-
-Active Plans
- Plan ID Action Phase
- -------- ------------------- -------
- 01HXM7A9 local/code-coverage execute
-
-[OK] Project loaded
-
-
-**Example** (`agents --format plain plan list`):
-
-
-$ agents --format plain plan list --phase execute
-
-Plans
- ID Phase State Action Project Elapsed
- -------- ------- ---------- ------------------- ----------------- ---------
- 01HXM7A9 execute processing local/code-coverage local/api-service 00:01:12
-
-Filters
- Phase: execute
- State: (any)
- Project: (any)
- Action: (any)
-
-Summary
- Total: 1
- Processing: 1
- Completed: 0
- Errored: 0
-
-[OK] 1 plan listed
-
-
-##### `color` — Colored Plain Text
-
-**Philosophy**: Same structural layout as `plain`, but with ANSI color codes applied to improve readability. No box-drawing characters, no cursor movement, no animation.
-
-**Rendering rules**:
-
-- **Identical layout to `plain`**, but with color applied:
- - **Headers/titles**: Bold cyan.
- - **Keys**: Bold blue.
- - **Values**: Default color, with semantic coloring:
- - Success/positive: Green.
- - Warnings/attention: Yellow.
- - Errors/failures: Red.
- - Identifiers/names: Cyan.
- - Counts/numbers: Default (white).
- - **Table headers**: Bold cyan with underlines rendered as dim dashes.
- - **Status prefixes**: `[OK]` in green, `[WARN]` in yellow, `[ERROR]` in red, `[INFO]` in blue.
- - **Diff lines**: `+` lines green, `-` lines red, `@@` headers cyan.
-- **No box-drawing characters** — uses the same whitespace/dash layout as `plain`.
-- **No cursor movement or animation** — pure scrolling output.
-- **Respects `NO_COLOR` environment variable**: If `NO_COLOR` is set, `color` format falls back to `plain`.
-
-**Example** (`agents --format color project show local/api-service`):
-
-
-$ agents --format color project show local/api-service
-
-Project Details
- Name: local/api-service
- Description: Backend API
- Resources: 2
- Remote: no
- Created: 2026-02-08 12:46
-
-Linked Resources
- Resource Type Sandbox Read-Only
- ---------------- -------------- -------------------- ---------
- local/api-repo git-checkout git_worktree no
- local/staging-db local/database transaction_rollback yes
-
-Validations (3)
- local/run-tests pytest --cov=src --cov-fail-under=80 required
- local/lint-check ruff check . required
- local/check-bundle-size node scripts/check-bundle-size.js info
-
-Context
- Include: repo
- Exclude: **/node_modules/**
- Max File Size: 1 MB
-
-Indexing Status
- Text Index: ready
- Vector Index: ready
- Graph Store: disabled
- Indexed Files: 347
- Last Indexed: 12:48
-
-Active Plans
- Plan ID Action Phase
- -------- ------------------- -------
- 01HXM7A9 local/code-coverage execute
-
-[OK] Project loaded
-
-
-##### `table` — ASCII Box-Drawing Tables
-
-**Philosophy**: Structured, visually distinct panels and tables using Unicode box-drawing characters (╭──────────────────╮╰╯│─). Uses color. This is the style shown in the existing CLI examples throughout this document.
-
-**Rendering rules**:
-
-- **Panels**: Rendered as bordered boxes with title in the top border. Uses `╭─╮│╰──────────────────╯` characters for rounded corners.
-- **Tables**: Rendered inside bordered boxes with column-aligned headers and separator lines using `─` and `│`.
-- **Trees**: Rendered inside a bordered box using `├──`, `└──`, `│` tree guide characters.
-- **Status messages**: Use Unicode indicators: `✓` (green) for OK, `⚠` (yellow) for WARN, `✗` (red) for ERROR, `ℹ` (blue) for INFO.
-- **Progress**: Rendered as a step list inside a panel with `✓`, `⏳`, `•` markers.
-- **Color scheme**: Same semantic coloring as `color` format, applied within box structures.
-- **No animation or cursor movement** — the boxes are static, scrolling output.
-
-**Distinction from `rich`**: The `table` format uses the same box-drawing panels and color as `rich` for static content, but it does **not** use any dynamic or interactive terminal features. There are no animated spinners, no live-updating progress bars, no cursor movement, and no in-place redraws. All output is static and scrolls sequentially. Where `rich` would show a spinning `⠋` and a live progress bar, `table` renders a static snapshot using fixed markers (`✓`, `⏳`, `•`). This makes `table` suitable for terminals without advanced capabilities, and for output that will be reviewed after the fact (e.g., scrollback buffers).
-
-**Example** (`agents --format table project show local/api-service`):
-
-
-$ agents --format table project show local/api-service
-
-╭─ Project Details ──────────────╮
-│ Name: local/api-service │
-│ Description: Backend API │
-│ Resources: 2 │
-│ Remote: no │
-│ Created: 2026-02-08 12:46 │
-╰────────────────────────────────╯
-
-╭─ Linked Resources ──────────────────────────────────────────────────────╮
-│ Resource Type Sandbox Read-Only │
-│ ──────────────── ────────────── ──────────────────── ───────── │
-│ local/api-repo git-checkout git_worktree no │
-│ local/staging-db local/database transaction_rollback yes │
-╰─────────────────────────────────────────────────────────────────────────╯
-
-╭─ Validations (3) ───────────────────────────────────────────────────────────────╮
-│ local/run-tests pytest --cov=src --cov-fail-under=80 required │
-│ local/lint-check ruff check . required │
-│ local/check-bundle-size node scripts/check-bundle-size.js informational │
-╰─────────────────────────────────────────────────────────────────────────────────╯
-
-╭─ Context ───────────────────╮
-│ Include: repo │
-│ Exclude: **/node_modules/** │
-│ Max File Size: 1 MB │
-╰─────────────────────────────╯
-
-╭─ Indexing Status ──────────╮
-│ Text Index: ready │
-│ Vector Index: ready │
-│ Graph Store: disabled │
-│ Indexed Files: 347 │
-│ Last Indexed: 12:48 │
-╰────────────────────────────╯
-
-╭─ Active Plans ──────────────────────────╮
-│ Plan ID Action Phase │
-│ ──────── ─────────────────── ─────── │
-│ 01HXM7A9 local/code-coverage execute │
-╰─────────────────────────────────────────╯
-
-✓ OK Project loaded
-
-
-**Example** (`agents --format table plan execute 01HXM8C2ZK`):
-
-Unlike `rich` mode which would show animated spinners and a live progress bar, the `table` format renders a static snapshot of execution state:
-
-
-$ agents --format table plan execute 01HXM8C2ZK
-
-╭─ Execution ──────────────────────╮
-│ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
-│ Phase: execute │
-│ Sandbox: git_worktree │
-│ Worker: local/executor │
-│ Started: 12:58:10 │
-│ Attempt: 1 │
-╰──────────────────────────────────╯
-
-╭─ Strategy Summary ─────────────────────╮
-│ Decisions: 8 │
-│ Invariants: 2 │
-│ Planned Child Plans: 2+ │
-│ Estimated Files: ~12 │
-│ Risk: low │
-╰────────────────────────────────────────╯
-
-╭─ Progress ─────────╮
-│ ✓ Collect context │
-│ ✓ Run tools │
-│ ⏳ Build changeset │
-│ • Validate │
-╰────────────────────╯
-
-✓ OK Execution started
-
-
-##### `rich` — Modern Rich CLI Elements
-
-**Philosophy**: The premium interactive terminal experience. Uses advanced terminal capabilities: cursor movement, inline updates, animated spinners, live-updating progress bars, collapsible sections, syntax highlighting, and dynamic layout. This is the default format.
-
-**Rendering rules**:
-
-- **Panels**: Rich bordered panels with rounded corners, title bars, and optional collapse/expand behavior. Panels may animate into view.
-- **Tables**: Full-featured tables with automatic column sizing, truncation with ellipsis, sortable column indicators, alternating row shading, and horizontal scrolling for wide tables.
-- **Trees**: Interactive collapsible trees. Nodes expand/collapse with visual animation. Color-coded by node type. Depth guides use dotted lines.
-- **Status messages**: Use animated checkmarks/spinners that resolve to final state. Success messages may briefly flash or highlight.
-- **Progress**: Live-updating progress bars with:
- - Animated spinners (Braille, dots, or bars depending on terminal capability).
- - Elapsed time and ETA.
- - Per-step status with animated transitions (pending → active → done).
- - Multi-line progress for parallel operations.
-- **Diffs**: Syntax-highlighted side-by-side or unified diffs with line numbers, change highlighting at the character level (not just line level), and navigable hunks.
-- **Code blocks**: Full syntax highlighting using terminal colors (256-color or truecolor when available). Line numbers in dim color. Highlighted lines with background color.
-- **Dynamic layout**: Adapts to terminal width. Narrow terminals get a stacked layout; wide terminals get side-by-side panels.
-- **Live updates**: Long-running commands (plan execute, plan status) use live-updating displays that redraw in place rather than scrolling.
-- **Graceful degradation**: If the terminal does not support required capabilities (e.g., no truecolor, no cursor movement), the renderer automatically falls back to `table` rendering for those elements.
-
-**Example** (`agents --format rich plan execute 01HXM8C2ZK`):
-
-The `rich` format produces output that cannot be fully represented in static documentation — animated spinners cycle in place, progress bars fill smoothly, and elements update without scrolling. The rendering below is a static snapshot of what the terminal would display at a given moment:
-
-
-$ agents --format rich plan execute 01HXM8C2ZK
-
-╭─ Execution ──────────────────────╮
-│ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
-│ Phase: execute │
-│ Sandbox: git_worktree │
-│ Worker: local/executor │
-│ Started: 12:58:10 │
-╰──────────────────────────────────╯
-
-⠋ Collecting context... (⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ animates in place)
- ├── repo: local/api-repo ✓
- └── db: local/staging-db ✓
-
-╭─ Strategy Summary ──────────────────────────────────────────────────────╮
-│ 8 decisions │ 2 invariants │ 2+ child plans │ ~12 files │ risk: low │
-╰─────────────────────────────────────────────────────────────────────────╯
-
-Progress ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42% elapsed 0:01:12 ETA 0:01:40
- ✓ Collect context .................. 0.8s
- ✓ Run tools (8 calls) ............. 12.4s
- ⠙ Build changeset ................. (running) (animates in place)
- ○ Validate ........................ (pending)
-
-╭─ Live Tool Calls ───────────────────────────────────────╮
-│ #6 read_file src/auth/__init__.py ✓ 0.1s │
-│ #7 write_file tests/test_auth.py ✓ 0.2s │
-│ #8 edit_file src/auth/session.py ⠙ ... │
-╰─────────────────────────────────────────────────────────╯
-
-
-In `rich` mode:
-- The Braille spinner characters (`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`) animate in real-time, cycling in place without scrolling.
-- The progress bar (`━━━`) fills smoothly as work completes.
-- Completed steps appear with a green `✓` via in-place line update (the line rewrites, it does not scroll).
-- The "Live Tool Calls" panel scrolls its content internally, showing only the most recent N calls.
-- The terminal is not flooded with scrolling text — elements update in place using cursor movement.
-
-**Example** (`agents --format rich version`):
-
-
-$ agents --format rich version
-
-╭─────────────────────────────────────╮
-│ CleverAgents CLI v1.0.0 │
-│ channel: stable │
-╰─────────────────────────────────────╯
-
-╭─ Build ─────────────────────────────╮
-│ Build Date: 2026-02-08 │
-│ Commit: a17c3f9 │
-│ Schema: v3 │
-│ Platform: linux-x86_64 │
-│ Python: 3.13.1 │
-╰─────────────────────────────────────╯
-
-╭─ Dependencies ─────────────────────────────────────────────────────────╮
-│ LangGraph 0.2.60 │ LangChain 0.3.18 │ MCP SDK 1.4.0 │ Pydantic 2.10.4 │
-╰────────────────────────────────────────────────────────────────────────╯
-
-✓ OK Version reported
-
-
-In `rich` mode, the version card may use background colors, bold gradients, or subtle box shadows (depending on terminal truecolor support). Elements may animate into view with a brief slide or fade transition.
-
-##### `json` — JSON Data Structure
-
-**Philosophy**: Machine-readable output for programmatic consumption. Every command produces a well-defined JSON object. No ANSI color codes in the structural data. Color codes may appear only **within** text values that represent verbatim content (such as code blocks or diff output where the original text contained ANSI sequences), but all structural keys, labels, and metadata are plain strings.
-
-**Rendering rules**:
-
-- **Top-level structure**: Always a JSON object with a standard envelope:
-
- {
- "command": "project show",
- "status": "ok",
- "exit_code": 0,
- "data": { ... },
- "timing": { "duration_ms": 42 },
- "metadata": { ... }
- }
-
-- **Panels**: Rendered as nested objects within `data`.
-- **Tables**: Rendered as arrays of objects within `data`.
-- **Trees**: Rendered as nested objects with `children` arrays.
-- **Status messages**: Included in a `messages` array within the envelope.
-- **Progress**: Not rendered (JSON output is non-interactive; progress is omitted).
-- **Diffs**: Rendered as structured objects with `hunks` arrays.
-- **No ANSI codes** in any structural element. Raw ANSI codes are preserved only in string values that represent verbatim terminal output.
-- **Pretty-printed** by default (indented). Compact mode available via `--json-compact` (future option).
-- **Consistent schema per command**: Each command's JSON schema is stable and documented, enabling reliable programmatic parsing.
-
-**Example** (`agents --format json project show local/api-service`):
-
-
-{
- "command": "project show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "project": {
- "name": "local/api-service",
- "description": "Backend API",
- "type": "local",
- "remote": false,
- "created_at": "2026-02-08T12:46:00Z"
- },
- "linked_resources": [
- {
- "name": "local/api-repo",
- "type": "git-checkout",
- "sandbox_strategy": "git_worktree",
- "read_only": false
- },
- {
- "name": "local/staging-db",
- "type": "local/database",
- "sandbox_strategy": "transaction_rollback",
- "read_only": true
- }
- ],
- "validations": [
- {
- "name": "local/run-tests",
- "command": "pytest --cov=src --cov-fail-under=80",
- "mode": "required",
- "timeout": 600,
- "resource": "repo"
- },
- {
- "name": "local/lint-check",
- "command": "ruff check .",
- "mode": "required",
- "timeout": 300,
- "resource": null
- },
- {
- "name": "local/check-bundle-size",
- "command": "node scripts/check-bundle-size.js",
- "mode": "informational",
- "timeout": 300,
- "resource": null
- }
- ],
- "context": {
- "include_resources": ["repo"],
- "exclude_paths": ["**/node_modules/**"],
- "max_file_size_bytes": 1048576
- },
- "indexing": {
- "text_index": "ready",
- "vector_index": "ready",
- "graph_store": "disabled",
- "indexed_files": 347,
- "last_indexed_at": "2026-02-08T12:48:00Z"
- },
- "active_plans": [
- {
- "plan_id": "01HXM7A9",
- "action": "local/code-coverage",
- "phase": "execute"
- }
- ]
- },
- "timing": {
- "duration_ms": 42
- },
- "messages": [
- { "level": "ok", "text": "Project loaded" }
- ]
-}
-
-
-**Example** (`agents --format json plan list --phase execute`):
-
-
-{
- "command": "plan list",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plans": [
- {
- "id": "01HXM7A9",
- "phase": "execute",
- "state": "processing",
- "action": "local/code-coverage",
- "project": "local/api-service",
- "elapsed": "00:01:12"
- }
- ],
- "filters": {
- "phase": "execute",
- "state": null,
- "project": null,
- "action": null
- },
- "summary": {
- "total": 1,
- "processing": 1,
- "completed": 0,
- "errored": 0
- }
- },
- "timing": {
- "duration_ms": 18
- },
- "messages": [
- { "level": "ok", "text": "1 plan listed" }
- ]
-}
-
-
-##### `yaml` — YAML Data Structure
-
-**Philosophy**: Same data as `json` but in YAML format. Preferred by users who find YAML more readable for configuration and scripting workflows. Follows the same structural conventions as `json`.
-
-**Rendering rules**:
-
-- **Same data envelope** as JSON (`command`, `status`, `exit_code`, `data`, `timing`, `messages`).
-- **YAML 1.2 compliant** output.
-- **Multi-line strings** use YAML block scalars (`|` for literal, `>` for folded) when appropriate.
-- **No ANSI codes** in structural elements (same rule as JSON).
-- **Sorted keys** for deterministic output.
-
-**Example** (`agents --format yaml project show local/api-service`):
-
-
-command: project show
-status: ok
-exit_code: 0
-data:
- project:
- name: local/api-service
- description: Backend API
- type: local
- remote: false
- created_at: "2026-02-08T12:46:00Z"
- linked_resources:
- - name: local/api-repo
- type: git-checkout
- sandbox_strategy: git_worktree
- read_only: false
- - name: local/staging-db
- type: local/database
- sandbox_strategy: transaction_rollback
- read_only: true
- validations:
- - name: local/run-tests
- command: "pytest --cov=src --cov-fail-under=80"
- mode: required
- timeout: 600
- resource: repo
- - name: local/lint-check
- command: "ruff check ."
- mode: required
- timeout: 300
- resource: null
- - name: local/check-bundle-size
- command: "node scripts/check-bundle-size.js"
- mode: informational
- timeout: 300
- resource: null
- context:
- include_resources:
- - repo
- exclude_paths:
- - "**/node_modules/**"
- max_file_size_bytes: 1048576
- indexing:
- text_index: ready
- vector_index: ready
- graph_store: disabled
- indexed_files: 347
- last_indexed_at: "2026-02-08T12:48:00Z"
- active_plans:
- - plan_id: 01HXM7A9
- action: local/code-coverage
- phase: execute
-timing:
- duration_ms: 42
-messages:
- - level: ok
- text: Project loaded
-
-
-#### Format Comparison Matrix
-
-| Capability | `plain` | `color` | `table` | `rich` | `json` | `yaml` |
-|---|---|---|---|---|---|---|
-| Color codes | No | Yes | Yes | Yes | No | No |
-| Box drawing | No | No | Yes | Yes | No | No |
-| Animation/spinners | No | No | No | Yes | No | No |
-| Live updates | No | No | No | Yes | No | No |
-| Cursor movement | No | No | No | Yes | No | No |
-| Syntax highlighting | No | No | No | Yes | No | No |
-| Collapsible sections | No | No | No | Yes | No | No |
-| Machine-parseable | Partially | Partially | No | No | Yes | Yes |
-| Pipe-safe | Yes | No* | No | No | Yes | Yes |
-| Unicode required | No | No | Yes | Yes | No | No |
-| TTY required | No | No | No | Yes** | No | No |
-
-\* `color` output can be piped if the consumer understands ANSI codes (e.g., `less -R`).
-\** `rich` gracefully degrades to `table` when stdout is not a TTY.
-
-#### Renderer Registration and Extension
-
-The framework uses a **registry pattern** for format renderers, enabling third-party or plugin renderers. Each format is registered as a `(MaterializationStrategy, ElementRenderer)` pair — the strategy controls timing/ordering, and the renderer controls visual formatting:
-
-
-@dataclass
-class FormatRegistration:
- """A registered format: its strategy factory, renderer factory, and fallback."""
- strategy_factory: Callable[[TerminalCapabilities], MaterializationStrategy]
- renderer_factory: Callable[[TerminalCapabilities], ElementRenderer]
- fallback: str | None # Format name to fall back to, or None
-
-
-class RendererRegistry:
- """Central registry for format (strategy, renderer) pairs.
-
- Formats are registered by name and resolved at runtime based on the
- active format and terminal capabilities. The registry supports dynamic
- registration, enabling plugins to add custom formats (e.g., 'html',
- 'csv', 'markdown').
-
- Built-in registrations:
- "rich" → (LiveMaterializer, RichElementRenderer), fallback="table"
- "table" → (SequentialBufferMaterializer, TableElementRenderer), fallback="color"
- "color" → (SequentialBufferMaterializer, ColorElementRenderer), fallback="plain"
- "plain" → (SequentialBufferMaterializer, PlainElementRenderer), fallback=None
- "json" → (AccumulateMaterializer, JsonElementRenderer), fallback=None
- "yaml" → (AccumulateMaterializer, YamlElementRenderer), fallback=None
- """
-
- _formats: dict[str, FormatRegistration] = {}
-
- @classmethod
- def register(cls, format_name: str,
- strategy_factory: Callable[[TerminalCapabilities], MaterializationStrategy],
- renderer_factory: Callable[[TerminalCapabilities], ElementRenderer],
- fallback: str | None = None) -> None:
- """Register a format.
-
- Args:
- format_name: The format identifier (e.g., 'rich', 'json').
- strategy_factory: Callable that creates a MaterializationStrategy,
- given terminal capabilities.
- renderer_factory: Callable that creates an ElementRenderer,
- given terminal capabilities.
- fallback: Optional fallback format name if this format cannot
- operate in the current terminal environment.
- """
- cls._formats[format_name] = FormatRegistration(
- strategy_factory=strategy_factory,
- renderer_factory=renderer_factory,
- fallback=fallback,
- )
-
- @classmethod
- def resolve(cls, format_name: str,
- terminal_caps: TerminalCapabilities
- ) -> tuple[MaterializationStrategy, ElementRenderer]:
- """Resolve the best (strategy, renderer) pair for the given format.
-
- Walks the fallback chain if the requested format's renderer cannot
- operate in the current terminal environment. Returns the first pair
- where the renderer reports can_render(terminal_caps) == True.
-
- Raises:
- ValueError: If no usable format is found (should never happen
- since 'plain' has no fallback and always works).
- """
- current = format_name
- visited: set[str] = set()
-
- while current and current not in visited:
- visited.add(current)
- registration = cls._formats.get(current)
- if registration is None:
- break
-
- renderer = registration.renderer_factory(terminal_caps)
- if renderer.can_render(terminal_caps):
- strategy = registration.strategy_factory(terminal_caps)
- strategy.bind(renderer, terminal_caps=terminal_caps)
- return strategy, renderer
-
- current = registration.fallback
-
- # Ultimate fallback is always plain
- plain = cls._formats["plain"]
- renderer = plain.renderer_factory(terminal_caps)
- strategy = plain.strategy_factory(terminal_caps)
- strategy.bind(renderer, terminal_caps=terminal_caps)
- return strategy, renderer
-
- @classmethod
- def available_formats(cls) -> list[str]:
- """Return all registered format names."""
- return sorted(cls._formats.keys())
-
- @classmethod
- def is_registered(cls, format_name: str) -> bool:
- """Check if a format is registered."""
- return format_name in cls._formats
-
-
-##### Terminal Capability Detection
-
-The framework detects terminal capabilities to guide format resolution, strategy selection, and renderer fallback:
-
-
-@dataclass
-class TerminalCapabilities:
- """Detected capabilities of the output terminal.
-
- This dataclass is populated once at CLI startup and passed to the
- RendererRegistry for format resolution. It is also available to
- individual strategies and renderers for fine-grained adaptation
- (e.g., adjusting column widths to terminal width, choosing between
- 256-color and truecolor palettes).
- """
- is_tty: bool # Is stdout a TTY?
- width: int # Terminal width in columns
- height: int # Terminal height in rows
- supports_ansi: bool # Supports basic ANSI escape codes?
- supports_256_color: bool # Supports 256-color palette?
- supports_truecolor: bool # Supports 24-bit truecolor?
- supports_unicode: bool # Supports Unicode (box-drawing, etc.)?
- supports_cursor_movement: bool # Supports cursor repositioning?
- supports_alternate_screen: bool # Supports alternate screen buffer?
- no_color: bool # Is NO_COLOR environment variable set?
- term_program: str | None # TERM_PROGRAM value (e.g., "iTerm2", "vscode")
-
- @classmethod
- def detect(cls) -> "TerminalCapabilities":
- """Auto-detect terminal capabilities from the environment.
-
- Detection logic:
- - is_tty: os.isatty(sys.stdout.fileno())
- - width/height: os.get_terminal_size() with fallback to (80, 24)
- - supports_ansi: True if is_tty and not Windows legacy console
- - supports_256_color: True if TERM contains "256color" or COLORTERM is set
- - supports_truecolor: True if COLORTERM is "truecolor" or "24bit"
- - supports_unicode: True if locale encoding is UTF-8
- - supports_cursor_movement: True if is_tty and TERM is not "dumb"
- - supports_alternate_screen: True if supports_cursor_movement
- - no_color: True if NO_COLOR environment variable is set (any value)
- - term_program: Value of TERM_PROGRAM environment variable
- """
- ...
-
-
-##### Plugin Format Registration
-
-Third-party plugins can register custom formats using the registry:
-
-
-# Example: Registering a custom 'csv' format plugin
-from cleveragents.output import RendererRegistry, SequentialBufferMaterializer
-
-class CsvElementRenderer(ElementRenderer):
- """Renders tables as CSV, other elements as plain text."""
- format_name = "csv"
-
- def render_table(self, table: Table, stream: IO) -> None:
- writer = csv.writer(stream)
- writer.writerow([col.name for col in table.columns])
- for row in table.rows:
- writer.writerow([row.get(col.name, "") for col in table.columns])
-
- def can_render(self, terminal_caps: TerminalCapabilities) -> bool:
- return True # CSV works everywhere
-
-# Register at plugin load time
-RendererRegistry.register(
- format_name="csv",
- strategy_factory=lambda caps: SequentialBufferMaterializer(),
- renderer_factory=lambda caps: CsvElementRenderer(),
- fallback="plain",
-)
-
-
-#### Edge Cases and Special Behaviors
-
-##### Error Output
-
-Errors are rendered through the same framework. When a command raises an exception or signals an error, the session's context manager (`__exit__`) catches the exception, creates a `StatusMessage` with `level="error"` and an optional `TextBlock` with details, and closes the session with `exit_code=1`. In `json`/`yaml` formats, errors produce:
-
-
-{
- "command": "project show",
- "status": "error",
- "exit_code": 1,
- "error": {
- "code": "NOT_FOUND",
- "message": "Project 'local/nonexistent' not found",
- "detail": "No project with name 'local/nonexistent' exists. Run 'agents project list' to see available projects.",
- "suggestions": [
- "agents project list",
- "agents project create local/nonexistent"
- ]
- },
- "timing": { "duration_ms": 5 }
-}
-
-
-##### Empty Results
-
-When a list command returns no results, all formats handle it gracefully:
-
-- **plain/color**: Prints a message like `No projects found.`
-- **table**: Renders an empty table with headers and a `(empty)` message.
-- **rich**: Renders a dimmed panel with an empty-state message and suggested actions.
-- **json/yaml**: Returns an empty array in the appropriate data field.
-
-##### Large Data Sets
-
-For commands that may return large result sets (e.g., `resource list` with thousands of resources):
-
-- **plain/color/table** (SequentialBufferMaterializer): The table handle accumulates rows as the producer adds them. Since the buffer is in-memory, very large result sets benefit from the `max_rows_hint` — the renderer truncates display at N rows with a `(... and N more rows)` indicator. The full data is still available in the snapshot for json/yaml.
-- **rich** (LiveMaterializer): Uses a virtual-scrolling table that renders only visible rows. Shows a count indicator (e.g., "Showing 1-50 of 2,847"). New rows animate into view as they are added.
-- **json/yaml** (AccumulateMaterializer): Accumulates and emits a complete array at session end. Streaming JSON lines (one JSON object per row) for very large sets is a future consideration.
-
-##### Nested/Recursive Structures
-
-Tree-like data (resource trees, decision trees, plan hierarchies) may be arbitrarily deep. Renderers respect `max_depth_hint`:
-
-- **plain/color**: Truncate at depth N with a `... (N more levels)` indicator.
-- **table**: Same truncation, rendered inside a box.
-- **rich**: Collapsible tree nodes — deep levels start collapsed. User can expand interactively if the terminal supports it.
-- **json/yaml**: Full depth — no truncation (programmatic consumers need complete data).
-
-##### Mixed Content
-
-Some commands produce mixed output (e.g., `plan status` has panels, tables, progress bars, and status messages). Each element is created via its own handle on the session, and the materialization strategy renders them in declaration order. The `ElementRenderer` is responsible for visual spacing and grouping between heterogeneous elements (e.g., inserting blank lines between a panel and a table in `plain` format, or adding visual margins in `rich` format).
-
-##### Producer Error Mid-Stream
-
-When a producer encounters an error while writing to a handle (e.g., an API call fails while populating a table), the framework handles it as follows:
-
-1. **The handle is closed with partial data** — the producer catches its exception, optionally calls `handle.close()` (or lets the context manager close it), and then creates a `StatusMessage` handle with `level="error"` to report the failure.
-
-2. **The materialization strategy renders whatever was accumulated** — a table with 3 of an expected 10 rows is rendered with those 3 rows, followed by the error message. This is better than rendering nothing.
-
-3. **The session's exit code is set to 1** — indicating partial failure.
-
-4. **For `json`/`yaml` formats**, the accumulated snapshot includes both the partial data and the error message in the `messages` array, giving programmatic consumers full visibility.
-
-Example of producer error handling:
-
-
-async def list_resources(session: OutputSession, client: ApiClient) -> None:
- table = session.table("Resources", columns=[
- ColumnDef(name="Name"), ColumnDef(name="Type"), ColumnDef(name="Status"),
- ])
-
- try:
- async for resource in client.list_resources():
- table.add_row({
- "Name": resource.name,
- "Type": resource.type,
- "Status": resource.status,
- })
- except ApiError as e:
- table.close() # Close with partial data
- session.status(f"Error fetching resources: {e}", level="error")
- return
-
- table.close()
- session.status(f"{table.element.row_count} resources listed", level="ok")
-
-
-##### Abandoned Handles
-
-If a handle is never explicitly closed and the session ends (either normally via `session.close()` or via the context manager's `__exit__`), the session force-closes all remaining open handles:
-
-1. A warning is logged (not rendered to the user): `"Handle {handle_id} ({element_type}) was not explicitly closed; force-closing at session end."`
-2. The handle is closed with its current accumulated state.
-3. The materialization strategy processes the `ElementClosed` event normally.
-
-This ensures that no data is silently lost, even if producer code forgets to close a handle due to an unhandled code path.
-
-##### Back-Pressure and Throttling
-
-The `LiveMaterializer` (used by `rich` format) limits terminal redraws to its configured frame rate (default 15 fps). When handles emit updates faster than the frame rate:
-
-1. Updates are coalesced — the materializer tracks a **dirty set** of handle IDs that have been updated since the last frame.
-2. On each frame tick, all dirty elements are redrawn in a single pass, and the dirty set is cleared.
-3. The event queue between session and strategy uses bounded capacity. If the queue fills (producer is vastly faster than rendering), the session's `_emit_event` method drops `ElementUpdated` events for handles that are already in the dirty set (since the next frame will redraw them anyway). `ElementCreated` and `ElementClosed` events are never dropped.
-
-For `SequentialBufferMaterializer` and `AccumulateMaterializer`, there is no back-pressure concern — updates are buffered in memory and never rendered incrementally.
-
-##### Cancellation Semantics
-
-When a command is cancelled (e.g., user presses Ctrl+C):
-
-1. The session receives a cancellation signal and enters the `"closing"` state.
-2. All open handles are force-closed with their current state.
-3. A `StatusMessage` with `level="warn"` and message `"Operation cancelled"` is emitted.
-4. The session closes with `exit_code=130` (standard SIGINT exit code).
-5. **For `rich` format**: The `LiveMaterializer` freezes the display, resolves any active spinners to a cancellation indicator (e.g., yellow `⚠`), and moves the cursor to the end of the output.
-6. **For buffered formats**: Any elements that have been rendered stay on screen. Pending buffered elements are flushed in order, followed by the cancellation message.
-7. **For `json`/`yaml`**: The accumulated snapshot is serialized with `"status": "cancelled"` and the appropriate exit code.
-
-##### Interleaved Status Messages During Concurrent Production
-
-When multiple producers are running concurrently (e.g., populating two tables), status messages may be created at any time by any producer. The materialization strategy handles these based on format:
-
-- **`rich`** (LiveMaterializer): Status messages are rendered immediately in a dedicated status region at the bottom of the display (below all element regions). Multiple concurrent status messages stack vertically.
-- **`plain`/`color`/`table`** (SequentialBufferMaterializer): Status messages created during concurrent production are treated as elements in declaration order, just like tables and panels. A status message created between two table creations will be rendered between those tables. Status messages created *after* all tables will render after all tables are flushed.
-- **`json`/`yaml`** (AccumulateMaterializer): All status messages are collected in the `messages` array of the final snapshot, ordered by timestamp.
-
-#### Integration with Future TUI
-
-The reactive `OutputSession` architecture is intentionally designed to serve as the data layer for a future TUI (text user interface). The session's event-driven model maps directly to TUI widget patterns:
-
-1. **Element handles become observable data sources.** A TUI `MaterializationStrategy` (e.g., `TuiMaterializer`) would subscribe to element events and route them to TUI widgets. The producer code (command logic) is completely unaware of whether it is driving a CLI, TUI, or web frontend — it writes to handles identically in all cases.
-
-2. **Element types map to TUI widgets:**
- - `PanelHandle` → info pane or detail card widget
- - `TableHandle` → sortable, filterable data grid widget (rows arrive incrementally via `add_row` events)
- - `TreeHandle` → collapsible tree view widget (nodes arrive incrementally via `add_child` events)
- - `ProgressHandle` → animated progress bar or step-list widget
- - `StatusHandle` → toast notification or status bar message
- - `CodeHandle` → syntax-highlighted code viewer widget
- - `DiffHandle` → side-by-side diff viewer widget
-
-3. **Interactive features are additive.** The TUI can offer features that the CLI cannot — sorting table columns, filtering rows, collapsing/expanding tree nodes, searching within code blocks — without any changes to producer code. These features are implemented in the TUI's `ElementRenderer` and widget layer.
-
-4. **Concurrent updates are native.** Because the session already supports multiple concurrent producers writing to different handles, the TUI naturally displays multiple simultaneously-updating widgets (e.g., two tables being populated in parallel by concurrent operations). The `TuiMaterializer` routes events to widgets, and each widget redraws independently using the TUI framework's event loop.
-
-5. **The `StructuredOutput` snapshot** provides the initial state when navigating to a completed session in the TUI (e.g., reviewing a past command's output), while live sessions use the event stream.
-
-The separation between production (element handles), timing (materialization strategy), and presentation (element renderer) ensures that the same command logic supports CLI, TUI, and web frontends without modification — only the `(MaterializationStrategy, ElementRenderer)` pair changes.
-
-#### Programmatic Usage Examples
-
-This section demonstrates how command implementations use the Output Rendering Framework through the `OutputSession` API, and how the same producer code produces correct output across all formats.
-
-##### Example 1: Simple Static Command Output
-
-The simplest usage — a command that creates elements, populates them synchronously, and closes them. No concurrency, no streaming.
-
-**Producer code** (`agents project show`):
-
-
-async def cmd_project_show(session: OutputSession, project_name: str) -> None:
- """Implementation of 'agents project show <project>'."""
- project = await api.get_project(project_name)
- resources = await api.list_project_resources(project.name)
- validations = await api.list_project_validations(project.name)
-
- # --- Build output elements ---
-
- # Panel: Project details
- with session.panel("Project Details") as panel:
- panel.set_entries({
- "Name": project.name,
- "Description": project.description,
- "Resources": str(len(resources)),
- "Remote": "yes" if project.remote else "no",
- "Created": project.created_at.strftime("%Y-%m-%d %H:%M"),
- }, style_hints={
- "Name": "identifier",
- "Resources": "number",
- "Remote": "success" if not project.remote else "info",
- "Created": "success",
- })
-
- # Table: Linked resources
- with session.table("Linked Resources", columns=[
- ColumnDef(name="Resource", type="string", style_hint="identifier"),
- ColumnDef(name="Type"),
- ColumnDef(name="Sandbox"),
- ColumnDef(name="Read-Only"),
- ]) as table:
- for r in resources:
- table.add_row({
- "Resource": r.name,
- "Type": r.type,
- "Sandbox": r.sandbox_strategy,
- "Read-Only": "yes" if r.read_only else "no",
- })
-
- # Table: Validations
- with session.table(f"Validations ({len(validations)})", columns=[
- ColumnDef(name="ID", type="id", style_hint="identifier"),
- ColumnDef(name="Command"),
- ColumnDef(name="Mode"),
- ]) as table:
- for v in validations:
- table.add_row({
- "ID": v.id,
- "Command": v.command,
- "Mode": v.mode,
- })
-
- # Status: Final message
- session.status("Project loaded", level="ok")
-
-
-**What this produces in `plain` format:**
-
-
-Project Details
- Name: local/api-service
- Description: Backend API
- Resources: 2
- Remote: no
- Created: 2026-02-08 12:46
-
-Linked Resources
- Resource Type Sandbox Read-Only
- ---------------- -------------- -------------------- ---------
- local/api-repo git-checkout git_worktree no
- local/staging-db local/database transaction_rollback yes
-
-Validations (3)
- Name Command Mode
- ----------------------- ------------------------------------- -----------
- local/run-tests pytest --cov=src --cov-fail-under=80 required
- local/lint-check ruff check . required
- local/check-bundle-size node scripts/check-bundle-size.js informational
-
-[OK] Project loaded
-
-
-**What this produces in `rich` format:**
-
-
-╭─ Project Details ──────────────╮
-│ Name: local/api-service │
-│ Description: Backend API │
-│ Resources: 2 │
-│ Remote: no │
-│ Created: 2026-02-08 12:46 │
-╰────────────────────────────────╯
-
-╭─ Linked Resources ──────────────────────────────────────────────────────╮
-│ Resource Type Sandbox Read-Only │
-│ ──────────────── ────────────── ──────────────────── ───────── │
-│ local/api-repo git-checkout git_worktree no │
-│ local/staging-db local/database transaction_rollback yes │
-╰─────────────────────────────────────────────────────────────────────────╯
-
-╭─ Validations (3) ──────────────────────────────────────────────────────────────╮
-│ Name Command Mode │
-│ ─────────────────────── ───────────────────────────────────── ─────────── │
-│ local/run-tests pytest --cov=src --cov-fail-under=80 required │
-│ local/lint-check ruff check . required │
-│ local/check-bundle-size node scripts/check-bundle-size.js informational │
-╰────────────────────────────────────────────────────────────────────────────────╯
-
-✓ OK Project loaded
-
-
-**What this produces in `json` format:**
-
-
-{
- "command": "project show",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "project_details": {
- "Name": "local/api-service",
- "Description": "Backend API",
- "Resources": "2",
- "Remote": "no",
- "Created": "2026-02-08 12:46"
- },
- "linked_resources": [
- {
- "Resource": "local/api-repo",
- "Type": "git-checkout",
- "Sandbox": "git_worktree",
- "Read-Only": "no"
- },
- {
- "Resource": "local/staging-db",
- "Type": "local/database",
- "Sandbox": "transaction_rollback",
- "Read-Only": "yes"
- }
- ],
- "validations": [
- {
- "Name": "local/run-tests",
- "Command": "pytest --cov=src --cov-fail-under=80",
- "Mode": "required"
- },
- {
- "Name": "local/lint-check",
- "Command": "ruff check .",
- "Mode": "required"
- },
- {
- "Name": "local/check-bundle-size",
- "Command": "node scripts/check-bundle-size.js",
- "Mode": "informational"
- }
- ]
- },
- "timing": { "duration_ms": 42 },
- "messages": [
- { "level": "ok", "text": "Project loaded" }
- ]
-}
-
-
-In all three formats, the producer code is **identical**. The `OutputSession` and its materialization strategy handle the differences transparently.
-
-##### Example 2: Streaming Rows into a Table
-
-A command that streams rows into a table as results arrive from a paginated API. The table handle stays open while the producer fetches pages.
-
-**Producer code** (`agents resource list`):
-
-
-async def cmd_resource_list(session: OutputSession, project: str | None) -> None:
- """Implementation of 'agents resource list'."""
-
- # Create the table handle — it will accumulate rows as we stream them
- table = session.table("Resources", columns=[
- ColumnDef(name="Name", type="string", style_hint="identifier"),
- ColumnDef(name="Type"),
- ColumnDef(name="Project"),
- ColumnDef(name="Sandbox"),
- ColumnDef(name="Status"),
- ], sort_key="Name")
-
- # Create a progress indicator for the fetch operation
- progress = session.progress("Fetching resources...", indeterminate=True)
-
- # Stream pages from the API
- count = 0
- async for page in api.list_resources_paginated(project=project):
- for resource in page.items:
- table.add_row({
- "Name": resource.name,
- "Type": resource.type,
- "Project": resource.project,
- "Sandbox": resource.sandbox_strategy,
- "Status": resource.status,
- })
- count += 1
-
- # Update progress label with count so far
- progress.set_label(f"Fetching resources... ({count} found)")
-
- # Close the progress indicator (it has served its purpose)
- progress.close()
-
- # Set summary and close the table
- table.set_summary({"total": count})
- table.close()
-
- # Final status
- session.status(f"{count} resources listed", level="ok")
-
-
-**What this looks like in `plain` format** (SequentialBufferMaterializer):
-
-The progress indicator is rendered as a static line. The table is buffered until `table.close()` is called, then rendered in full. The user sees nothing until the fetch is complete — then the entire result appears at once:
-
-
-Fetching resources... (47 found) [done]
-
-Resources
- Name Type Project Sandbox Status
- -------------------- -------------- ----------------- -------------------- --------
- local/api-repo git-checkout local/api-service git_worktree active
- local/staging-db local/database local/api-service transaction_rollback active
- local/docs-repo git-checkout local/docs-site git_worktree active
- ... (44 more rows)
-
- Total: 47
-
-[OK] 47 resources listed
-
-
-**What this looks like in `rich` format** (LiveMaterializer):
-
-The progress spinner animates in real-time. The table updates in-place as rows arrive — each new row appears at the bottom of the table, the row count updates, and the terminal display is rewritten without scrolling. This is a static snapshot of the live display mid-fetch:
-
-
-⠙ Fetching resources... (23 found)
-
-╭─ Resources ────────────────────────────────────────────────────────────────────────────╮
-│ Name Type Project Sandbox Status │
-│ ──────────────────── ────────────── ───────────────── ──────────────────── ────── │
-│ local/api-repo git-checkout local/api-service git_worktree active │
-│ local/staging-db local/database local/api-service transaction_rollback active │
-│ local/docs-repo git-checkout local/docs-site git_worktree active │
-│ ... │
-│ local/test-fixtures git-checkout local/api-service git_worktree active │
-│ │
-│ Showing 1-23 of 23 (fetching...) │
-╰────────────────────────────────────────────────────────────────────────────────────────╯
-
-
-In `rich` mode, the spinner animates, the table grows as rows arrive, and the row count updates — all in-place without scrolling. When the fetch completes, the spinner resolves to `✓`, and the table shows its final state.
-
-##### Example 3: Concurrent Parallel Operations (Two Tables Simultaneously)
-
-This is the key motivating example for the reactive architecture. Two tables are populated simultaneously by parallel workers, and the producer code is completely format-agnostic.
-
-**Producer code** (`agents plan status` — showing resources and active tool calls concurrently):
-
-
-async def cmd_plan_status(session: OutputSession, plan_id: str) -> None:
- """Implementation of 'agents plan status <plan_id>'.
-
- This command fetches plan metadata, then concurrently streams two data
- sources: resource statuses and active tool call logs. Both data sources
- are long-running — they produce results over several seconds as the
- backend resolves each item.
- """
- plan = await api.get_plan(plan_id)
-
- # Panel: Plan metadata (created and closed synchronously)
- with session.panel("Plan") as panel:
- panel.set_entries({
- "Plan ID": plan.id,
- "Phase": plan.phase,
- "State": plan.state,
- "Action": plan.action,
- "Project": plan.project,
- "Started": plan.started_at.strftime("%H:%M:%S"),
- }, style_hints={
- "Plan ID": "identifier",
- "Phase": "info",
- "State": "warning" if plan.state == "processing" else "success",
- })
-
- # Create both table handles BEFORE starting concurrent producers.
- # Declaration order determines rendering order in sequential formats.
- resource_table = session.table("Resource Status", columns=[
- ColumnDef(name="Resource", style_hint="identifier"),
- ColumnDef(name="Type"),
- ColumnDef(name="Status"),
- ColumnDef(name="Latency", type="string", alignment="right"),
- ])
-
- tool_table = session.table("Tool Call Log", columns=[
- ColumnDef(name="#", type="number", alignment="right"),
- ColumnDef(name="Tool"),
- ColumnDef(name="Target"),
- ColumnDef(name="Result"),
- ColumnDef(name="Duration", type="string", alignment="right"),
- ])
-
- # --- Run two producers concurrently ---
- # Each producer writes to its own handle. Neither producer knows
- # which format is active. The materialization strategy handles
- # the coordination.
-
- async def stream_resources():
- """Producer A: streams resource status checks."""
- async for status in api.stream_resource_statuses(plan.id):
- resource_table.add_row({
- "Resource": status.resource_name,
- "Type": status.resource_type,
- "Status": status.status,
- "Latency": f"{status.latency_ms}ms",
- })
- resource_table.close()
-
- async def stream_tool_calls():
- """Producer B: streams tool call results."""
- async for call in api.stream_tool_calls(plan.id):
- tool_table.add_row({
- "#": call.sequence_number,
- "Tool": call.tool_name,
- "Target": call.target,
- "Result": call.result_summary,
- "Duration": f"{call.duration_ms}ms",
- })
- tool_table.close()
-
- # Launch both producers concurrently
- await asyncio.gather(stream_resources(), stream_tool_calls())
-
- # Final status
- session.status(f"Plan {plan_id} status retrieved", level="ok")
-
-
-**What this produces in `plain` format** (SequentialBufferMaterializer):
-
-Both tables are populated concurrently, but the materializer buffers each one and renders them in **declaration order** when their handles close. The user sees nothing until the first-declared table (Resource Status) closes, then it prints. Then when the second table (Tool Call Log) closes, it prints. Data may have arrived interleaved across both tables, but the output is perfectly sequential:
-
-
-Plan
- Plan ID: 01HXM7A9
- Phase: execute
- State: processing
- Action: local/code-coverage
- Project: local/api-service
- Started: 12:58:10
-
-Resource Status
- Resource Type Status Latency
- ---------------- -------------- ------- -------
- local/api-repo git-checkout ready 42ms
- local/staging-db local/database ready 128ms
-
-Tool Call Log
- # Tool Target Result Duration
- -- ---------- ---------------------- ------------- --------
- 1 read_file src/auth/__init__.py 200 lines 0.1s
- 2 read_file src/auth/session.py 340 lines 0.1s
- 3 write_file tests/test_auth.py created 0.2s
- 4 edit_file src/auth/session.py 12 lines +/- 0.3s
- 5 run_tests pytest tests/test_auth 3 passed 2.1s
-
-[OK] Plan 01HXM7A9 status retrieved
-
-
-**What this produces in `rich` format** (LiveMaterializer):
-
-Both tables are visible simultaneously and update in-place as data arrives. This snapshot shows the display mid-stream — the resource table has two rows and the tool call table has three so far:
-
-
-╭─ Plan ──────────────────────────────╮
-│ Plan ID: 01HXM7A9 │
-│ Phase: execute │
-│ State: processing │
-│ Action: local/code-coverage │
-│ Project: local/api-service │
-│ Started: 12:58:10 │
-╰─────────────────────────────────────╯
-
-╭─ Resource Status ⠙ ───────────────────────────────────────────╮
-│ Resource Type Status Latency │
-│ ──────────────── ────────────── ─────── ─────── │
-│ local/api-repo git-checkout ready 42ms │
-│ local/staging-db local/database ready 128ms │
-│ │
-│ 2 resources (streaming...) │
-╰───────────────────────────────────────────────────────────────╯
-
-╭─ Tool Call Log ⠙ ────────────────────────────────────────────────────╮
-│ # Tool Target Result Duration │
-│ ── ────────── ────────────────────── ───────────── ──────── │
-│ 1 read_file src/auth/__init__.py 200 lines 0.1s │
-│ 2 read_file src/auth/session.py 340 lines 0.1s │
-│ 3 write_file tests/test_auth.py created 0.2s │
-│ │
-│ 3 calls (streaming...) │
-╰──────────────────────────────────────────────────────────────────────╯
-
-
-In `rich` mode, both tables have animated spinners in their titles indicating active streaming. As new rows arrive from either producer, the corresponding table's display is updated in-place. When a producer finishes and closes its handle, the spinner resolves to a `✓` and the "(streaming...)" indicator is removed. The other table continues updating independently.
-
-**What this produces in `json` format** (AccumulateMaterializer):
-
-Nothing is printed until the session closes. Then the complete accumulated state is serialized:
-
-
-{
- "command": "plan status",
- "status": "ok",
- "exit_code": 0,
- "data": {
- "plan": {
- "Plan ID": "01HXM7A9",
- "Phase": "execute",
- "State": "processing",
- "Action": "local/code-coverage",
- "Project": "local/api-service",
- "Started": "12:58:10"
- },
- "resource_status": [
- { "Resource": "local/api-repo", "Type": "git-checkout", "Status": "ready", "Latency": "42ms" },
- { "Resource": "local/staging-db", "Type": "local/database", "Status": "ready", "Latency": "128ms" }
- ],
- "tool_call_log": [
- { "#": 1, "Tool": "read_file", "Target": "src/auth/__init__.py", "Result": "200 lines", "Duration": "0.1s" },
- { "#": 2, "Tool": "read_file", "Target": "src/auth/session.py", "Result": "340 lines", "Duration": "0.1s" },
- { "#": 3, "Tool": "write_file", "Target": "tests/test_auth.py", "Result": "created", "Duration": "0.2s" },
- { "#": 4, "Tool": "edit_file", "Target": "src/auth/session.py", "Result": "12 lines +/-", "Duration": "0.3s" },
- { "#": 5, "Tool": "run_tests", "Target": "pytest tests/test_auth", "Result": "3 passed", "Duration": "2.1s" }
- ]
- },
- "timing": { "duration_ms": 3200 },
- "messages": [
- { "level": "ok", "text": "Plan 01HXM7A9 status retrieved" }
- ]
-}
-
-
-The critical point: **the producer code in all three formats is exactly the same**. The `asyncio.gather` call runs both producers concurrently regardless of format. The materialization strategy — `LiveMaterializer`, `SequentialBufferMaterializer`, or `AccumulateMaterializer` — transparently decides how that concurrent data reaches the user.
-
-##### Example 4: Progress with Concurrent Sub-Operations
-
-A command that executes a multi-step process with a progress indicator, where some steps involve parallel sub-operations.
-
-**Producer code** (`agents plan execute`):
-
-
-async def cmd_plan_execute(session: OutputSession, plan_id: str) -> None:
- """Implementation of 'agents plan execute <plan_id>'."""
- plan = await api.get_plan(plan_id)
-
- # Panel: Execution metadata
- with session.panel("Execution") as panel:
- panel.set_entries({
- "Plan": plan.id,
- "Phase": "execute",
- "Sandbox": plan.sandbox_strategy,
- "Worker": plan.worker,
- "Started": datetime.now().strftime("%H:%M:%S"),
- })
-
- # Progress indicator with named steps
- progress = session.progress("Executing plan", total=4, steps=[
- "Collect context",
- "Run tools",
- "Build changeset",
- "Validate",
- ])
-
- # Step 1: Collect context
- progress.set_step_status("Collect context", "active")
- context = await api.collect_context(plan.id)
- progress.set_step_status("Collect context", "done")
- progress.set_progress(1, 4)
-
- # Step 2: Run tools (parallel sub-operations)
- progress.set_step_status("Run tools", "active")
- tool_results = await api.run_tools(plan.id, context)
- progress.set_step_status("Run tools", "done")
- progress.set_progress(2, 4)
-
- # Step 3: Build changeset
- progress.set_step_status("Build changeset", "active")
- changeset = await api.build_changeset(plan.id, tool_results)
- progress.set_step_status("Build changeset", "done")
- progress.set_progress(3, 4)
-
- # Step 4: Validate
- progress.set_step_status("Validate", "active")
- validation = await api.validate_changeset(plan.id, changeset)
- progress.set_step_status("Validate", "done")
- progress.set_progress(4, 4)
-
- progress.close()
-
- # Summary panel
- with session.panel("Strategy Summary") as panel:
- panel.set_entries({
- "Decisions": str(changeset.decision_count),
- "Invariants": str(changeset.invariant_count),
- "Planned Child Plans": f"{changeset.child_plan_count}+",
- "Estimated Files": f"~{changeset.file_count}",
- "Risk": changeset.risk_level,
- })
-
- # Final status
- if validation.passed:
- session.status("Execution complete — all validations passed", level="ok")
- else:
- session.status(
- f"Execution complete — {validation.failure_count} validation(s) failed",
- level="warn",
- detail=validation.summary,
- )
-
-
-**What this looks like in `plain` format:**
-
-The progress indicator renders as a static step list. Since `SequentialBufferMaterializer` buffers each element until its handle closes, the progress indicator is not visible during execution — it appears as a completed snapshot after the fact:
-
-
-Execution
- Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J
- Phase: execute
- Sandbox: git_worktree
- Worker: local/executor
- Started: 12:58:10
-
-Executing plan [4/4]
- [x] Collect context
- [x] Run tools
- [x] Build changeset
- [x] Validate
-
-Strategy Summary
- Decisions: 8
- Invariants: 2
- Planned Child Plans: 2+
- Estimated Files: ~12
- Risk: low
-
-[OK] Execution complete — all validations passed
-
-
-**What this looks like in `rich` format:**
-
-The progress indicator is live — the spinner animates, the progress bar fills, and steps transition from pending to active to done in real-time. This snapshot shows the display mid-execution (step 3 active):
-
-
-╭─ Execution ──────────────────────╮
-│ Plan: 01HXM8C2ZK4Q7C2B3F2R4VYV6J │
-│ Phase: execute │
-│ Sandbox: git_worktree │
-│ Worker: local/executor │
-│ Started: 12:58:10 │
-╰──────────────────────────────────╯
-
-Executing plan ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 50% elapsed 0:00:13
- ✓ Collect context .................. 0.8s
- ✓ Run tools ...................... 12.4s
- ⠙ Build changeset ................. (running)
- ○ Validate ........................ (pending)
-
-
-When execution completes, the progress indicator resolves to its final state (all steps `✓`), the Strategy Summary panel appears below it, and the final status message is displayed.
-
-##### Example 5: Error Mid-Stream with Partial Output
-
-A command where one of multiple concurrent producers fails, demonstrating graceful partial output.
-
-**Producer code** (hypothetical `agents resource verify`):
-
-
-async def cmd_resource_verify(session: OutputSession, project: str) -> None:
- """Verify all resources in a project. Some verifications may fail."""
- resources = await api.list_project_resources(project)
-
- # Create a table that will be populated concurrently
- results_table = session.table("Verification Results", columns=[
- ColumnDef(name="Resource", style_hint="identifier"),
- ColumnDef(name="Type"),
- ColumnDef(name="Check"),
- ColumnDef(name="Status"),
- ColumnDef(name="Detail"),
- ])
-
- # Progress indicator
- progress = session.progress(
- "Verifying resources",
- total=len(resources),
- steps=[r.name for r in resources],
- )
-
- # Verify each resource concurrently
- async def verify_one(resource):
- progress.set_step_status(resource.name, "active")
- try:
- result = await api.verify_resource(resource.id)
- results_table.add_row({
- "Resource": resource.name,
- "Type": resource.type,
- "Check": result.check_name,
- "Status": "pass" if result.passed else "fail",
- "Detail": result.detail,
- })
- progress.set_step_status(
- resource.name,
- "done" if result.passed else "error",
- )
- except ApiError as e:
- results_table.add_row({
- "Resource": resource.name,
- "Type": resource.type,
- "Check": "connection",
- "Status": "error",
- "Detail": str(e),
- })
- progress.set_step_status(resource.name, "error")
- progress.increment()
-
- # Launch all verifications concurrently
- await asyncio.gather(
- *[verify_one(r) for r in resources],
- return_exceptions=True, # Don't fail fast — collect all results
- )
-
- progress.close()
- results_table.close()
-
- # Summarize
- snapshot = results_table.element
- pass_count = sum(1 for r in snapshot.rows if r["Status"] == "pass")
- fail_count = sum(1 for r in snapshot.rows if r["Status"] in ("fail", "error"))
-
- if fail_count == 0:
- session.status(f"All {pass_count} resources verified", level="ok")
- else:
- session.status(
- f"{fail_count} of {pass_count + fail_count} resources failed verification",
- level="error",
- )
-
-
-**What this produces in `plain` format** (after all concurrent verifications complete):
-
-
-Verifying resources [3/3]
- [x] local/api-repo
- [!] local/staging-db
- [x] local/docs-repo
-
-Verification Results
- Resource Type Check Status Detail
- ---------------- -------------- ---------- ------ ----------------------------------
- local/api-repo git-checkout integrity pass All refs valid
- local/staging-db local/database connection error Connection refused (port 5432)
- local/docs-repo git-checkout integrity pass All refs valid
-
-[ERROR] 1 of 3 resources failed verification
-
-
-**What this produces in `color` format:**
-
-
-Verifying resources [3/3]
- [x] local/api-repo
- [!] local/staging-db
- [x] local/docs-repo
-
-Verification Results
- Resource Type Check Status Detail
- ---------------- -------------- ---------- ------ ----------------------------------
- local/api-repo git-checkout integrity pass All refs valid
- local/staging-db local/database connection error Connection refused (port 5432)
- local/docs-repo git-checkout integrity pass All refs valid
-
-[ERROR] 1 of 3 resources failed verification
-
-
-**What this produces in `yaml` format:**
-
-
-command: resource verify
-status: error
-exit_code: 1
-data:
- verification_results:
- - Resource: local/api-repo
- Type: git-checkout
- Check: integrity
- Status: pass
- Detail: All refs valid
- - Resource: local/staging-db
- Type: local/database
- Check: connection
- Status: error
- Detail: "Connection refused (port 5432)"
- - Resource: local/docs-repo
- Type: git-checkout
- Check: integrity
- Status: pass
- Detail: All refs valid
-timing:
- duration_ms: 2840
-messages:
- - level: error
- text: "1 of 3 resources failed verification"
-
-
-In all formats, the concurrent verification produces a complete result set with partial failures clearly visible. The producer code uses `return_exceptions=True` on `asyncio.gather` to ensure all verifications complete even if some fail, and the error handling within each `verify_one` coroutine ensures that failures are recorded as table rows rather than causing the entire command to abort.
-
-## Behavior
-
-### Automation Profiles
-
-!!! adr "Architecture Decision"
- The automation profile system, confidence thresholds, and built-in profiles are defined in [ADR-017: Automation Profiles](adr/ADR-017-automation-profiles.md).
-
-Automation profiles determine which phase transitions happen automatically and which require human approval.
-
-#### Overview
-
-An **automation profile** is a named collection of **confidence thresholds** — floating-point values from 0.0 to 1.0 inclusive — that controls which tasks are automated vs. require human approval. Each threshold specifies the minimum confidence score (as computed by the Semantic Escalation system) at which the system proceeds automatically. When the computed confidence for a given operation falls below the profile's threshold for that flag, the system drops to manual mode and requests human input. A threshold of **0.0** means "always automatic" (proceed regardless of confidence), while **1.0** means "always manual" (always require human approval). Profiles follow the same `/` naming convention as actors, tools, skills, and other entities. Profiles are managed via the `agents automation-profile` CLI commands.
-
-#### Automatable Tasks
-
-Each automation profile specifies a **confidence threshold** (a floating-point value from 0.0 to 1.0 inclusive) for each of the following automatable tasks. The threshold determines the minimum confidence level at which the system proceeds automatically. When the computed confidence (from Semantic Escalation) falls below the threshold, the system drops to manual mode for that task. Setting a threshold to **0.0** makes the task always automatic; setting it to **1.0** makes it always manual.
-
-| Flag | Type | Description | Behavior |
-|------|------|-------------|----------|
-| `decompose_task` | float (0.0–1.0) | Automatically enter Strategize after `plan use` | When confidence >= threshold, Strategize begins immediately. Below threshold, system pauses after plan creation for user confirmation before entering Strategize. |
-| `create_tool` | float (0.0–1.0) | Automatically proceed from Strategize to Execute | When confidence >= threshold, Execute begins when Strategize completes. Below threshold, system pauses for user review. |
-| `select_tool` | float (0.0–1.0) | Automatically proceed from Execute to Apply | When confidence >= threshold, Apply begins when Execute completes. Below threshold, system pauses for user diff review. |
-| `edit_code` | float (0.0–1.0) | Automatically make decisions during Strategize | When confidence >= threshold, the strategy actor makes the decision autonomously. Below threshold, system pauses at the decision point for user input. |
-| `execute_command` | float (0.0–1.0) | Automatically make decisions during Execute | When confidence >= threshold, the execution actor makes the decision autonomously. Below threshold, system pauses at the decision point for user input. |
-| `create_file` | float (0.0–1.0) | Automatically attempt to fix validation failures | When confidence >= threshold, execution actor self-fixes failing validations. Below threshold, system pauses for user guidance. |
-| `delete_content` | float (0.0–1.0) | Automatically revise strategy when Execute hits constraints | When confidence >= threshold, system re-runs Strategize for affected subtree. Below threshold, system pauses and asks user. |
-| `access_network` | float (0.0–1.0) | Automatically revert from Apply (`constrained` state) to Strategize | When confidence >= threshold, a `constrained` Apply automatically triggers reversion to Strategize. Below threshold, system pauses and asks user whether to revert or cancel. |
-| `install_dependency` | float (0.0–1.0) | Automatically spawn and execute child plans | When confidence >= threshold, child plans are created and executed without pausing. Below threshold, each spawn requires approval. |
-| `modify_config` | float (0.0–1.0) | Automatically retry on transient failures (network, timeout, rate-limit) | When confidence >= threshold, system retries with backoff. Below threshold, system pauses and asks user. |
-| `approve_plan` | float (0.0–1.0) | Automatically restore from checkpoint on failure | When confidence >= threshold, system rolls back and retries. Below threshold, user decides whether to restore. |
-
-#### Safety Profile (Composed Sub-Model)
-
-!!! adr "Architecture Decision"
- The extraction of safety constraints into a composed SafetyProfile sub-model is defined in [ADR-041: Safety Profile Extraction](adr/ADR-041-safety-profile-extraction.md).
-
-Each automation profile composes a **`safety`** sub-model (`SafetyProfile`) that groups all hard safety constraints. These are binary constraints rather than confidence-dependent behaviors — they enforce invariant safety guarantees regardless of the system's confidence level. The `SafetyProfile` is the **single source of truth** for safety constraints; the `AutomationProfile` accesses them via its `safety` field.
-
-A `SafetyProfile` may also be attached directly to an `Action` (via the `safety_profile` field) when only safety constraints are needed without full autonomy thresholds.
-
-| Flag | Type | Default | Description | Behavior |
-|------|------|---------|-------------|----------|
-| `require_sandbox` | boolean | `true` | Require sandbox isolation for Execute phase | When `true`, Execute must run in a sandbox. When `false`, sandbox is optional. |
-| `require_checkpoints` | boolean | `true` | Require checkpointing during Execute | When `true`, tools must create checkpoints before writes. When `false`, checkpointing is optional. |
-| `allow_unsafe_tools` | boolean | `false` | Allow execution of tools marked as unsafe | When `true`, unsafe tools can be invoked. When `false`, unsafe tools are blocked. |
-| `require_human_approval` | boolean | `false` | Require human approval before each action step | When `true`, every action step pauses for explicit human approval before execution. |
-| `allowed_skill_categories` | list[string] | `[]` (all) | Skill categories permitted for execution | When non-empty, only skills in the listed categories may be used. Empty list means all categories are allowed. |
-| `max_cost_per_plan` | float \| null | `null` | Maximum cost in USD per plan execution | When set, the plan is paused or terminated if the cost limit is reached. `null` means no limit. Must be <= `max_total_cost` when both are set. |
-| `max_total_cost` | float \| null | `null` | Maximum total cost in USD across all plans | When set, execution is paused or terminated if the aggregate cost limit is reached. `null` means no limit. |
-| `max_retries_per_step` | integer | `3` | Maximum retry attempts per action step | Limits the number of retries for a single step before escalating to the user. Range: 0–100. |
-
-**Relationship to Automation Guards**: The `SafetyProfile.max_total_cost` field sets a **plan-level** budget cap (broad scope), while `AutomationGuard.max_total_cost` sets a **per-invocation** budget cap (narrow scope). These operate at different granularities and both may be active simultaneously — the tighter constraint takes precedence at any given point.
-
-#### Automation Guard Sub-Model
-
-An `AutomationProfile` may optionally compose an `AutomationGuard` sub-model (via the `guards` field) that provides runtime enforcement hooks beyond the phase-transition thresholds. Guards gate individual tool invocations based on call counts, budgets, allowlists/denylists, and write/apply semantics.
-
-| Field | Type | Default | Description |
-|-------|------|---------|-------------|
-| `max_tool_calls_per_step` | integer \| null | `null` | Maximum tool invocations per step before requiring approval. `null` means unlimited. Must be >= 0. |
-| `max_total_cost` | float \| null | `null` | Per-invocation budget cap (cumulative cost) before requiring approval. `null` means unlimited. Must be >= 0.0. |
-| `tool_allowlist` | list[string] \| null | `null` | Only these tools may be called automatically. `null` means all tools are allowed. |
-| `tool_denylist` | list[string] \| null | `null` | These tools always require human approval. `null` means no tools are denied. |
-| `require_approval_for_writes` | boolean | `false` | Require human approval for write operations. |
-| `require_approval_for_apply` | boolean | `false` | Require human approval before the apply phase. |
-
-Guard evaluation is performed via `AutomationProfile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope)`. The `scope` parameter is a `GuardScope` enum (`PLAN` or `SUBPLAN`) that distinguishes plan-level from subplan-level enforcement — error messages include the scope name for clarity. The method returns a `GuardResult` with fields `allowed` (bool), `reason` (str | None), and `requires_approval` (bool). Evaluation order: denylist → allowlist → tool call limit → budget cap → write approval → apply approval.
-
-#### Built-in Automation Profiles
-
-CleverAgents ships with eight built-in automation profiles. Built-in profiles use no namespace prefix.
-
-Threshold values are shown for each flag. A value of **0.0** means always automatic, **1.0** means always manual, and intermediate values (e.g., 0.5, 0.7) mean "automatic when confidence is at or above that level."
-
-| Flag | `manual` | `review` | `supervised` | `cautious` | `trusted` | `auto` | `ci` | `full-auto` |
-|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
-| `decompose_task` | 1.0 | 0.0 | 0.0 | 0.7 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `create_tool` | 1.0 | 0.0 | 1.0 | 0.7 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `select_tool` | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 | 0.0 |
-| `edit_code` | 1.0 | 1.0 | 0.0 | 0.6 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `execute_command` | 1.0 | 1.0 | 1.0 | 0.8 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `create_file` | 1.0 | 1.0 | 1.0 | 0.7 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `delete_content` | 1.0 | 1.0 | 1.0 | 0.8 | 1.0 | 0.0 | 0.0 | 0.0 |
-| `access_network` | 1.0 | 1.0 | 1.0 | 0.9 | 1.0 | 1.0 | 0.0 | 0.0 |
-| `install_dependency` | 1.0 | 0.0 | 1.0 | 0.7 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `modify_config` | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
-| `approve_plan` | 1.0 | 1.0 | 1.0 | 0.6 | 1.0 | 0.0 | 0.0 | 0.0 |
-| **Safety Profile** | | | | | | | | |
-| `safety.require_sandbox` | true | true | true | true | true | true | true | false |
-| `safety.require_checkpoints` | true | true | true | true | true | true | true | false |
-| `safety.allow_unsafe_tools` | false | false | false | false | false | false | false | true |
-| `safety.require_human_approval` | false | false | false | false | false | false | false | false |
-| `safety.allowed_skill_categories` | [] | [] | [] | [] | [] | [] | [] | [] |
-| `safety.max_cost_per_plan` | null | null | null | null | null | null | null | null |
-| `safety.max_total_cost` | null | null | null | null | null | null | null | null |
-| `safety.max_retries_per_step` | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
-
-**`manual`**: Maximum human control. All thresholds set to 1.0 — every phase transition, every decision, every child plan requires explicit human approval regardless of confidence. Sandbox and checkpoints are mandatory. Unsafe tools are blocked. This is the default starting point. Use for: new users learning the system, critical production systems, first-time exploration of an unfamiliar codebase, sensitive projects, regulatory environments.
-
-**`review`**: Phases run automatically (Strategize and Execute proceed without pausing), and most decisions within those phases require human approval (thresholds set to 1.0), except transient retries and child plan spawning which are automatic (thresholds 0.0). Apply is manual. The system does the work but consults you on every choice point. Use for: teams that want to stay in the decision loop without manually triggering each phase, code reviews where architectural choices matter more than execution mechanics.
-
-**`supervised`**: Strategize thresholds set to 0.0 (always automatic), but Execute and Apply thresholds set to 1.0 (always manual). The system plans autonomously and retries transient failures automatically, but pauses before Execute for human review of the strategy. Use for: projects where you trust the planning but want to review before execution begins.
-
-**`cautious`**: Uses intermediate confidence thresholds (0.6–0.8) instead of binary 0.0/1.0 values. The system proceeds automatically only when the Semantic Escalation system reports high confidence, and escalates to the user when uncertain. Apply is always manual (1.0). Higher thresholds (0.8) are applied to riskier operations like strategy revision and execution decisions, while lower thresholds (0.6) are used for safer operations like checkpoint restores and strategy decisions. Transient retries are always automatic. Use for: teams adopting automation gradually, projects with mixed complexity where some tasks are routine but others need oversight, situations where you want the system to self-assess rather than follow rigid rules.
-
-**`trusted`**: Strategize and Execute thresholds set to 0.0 (always automatic). Validation fixes, child plan spawning, and transient retries proceed automatically. Strategy revision and checkpoint restores remain manual (thresholds 1.0) to preserve human oversight over plan-level course corrections. The system pauses only before Apply (threshold 1.0) for human review of the final diffs. Use for: day-to-day feature development, routine refactoring, test generation.
-
-**`auto`**: All thresholds set to 0.0 except Apply (1.0). The system can revise its own strategy, restore from checkpoints, and handle all decisions automatically. Only Apply requires human approval. Use for: well-understood projects, batch operations, tasks with strong invariant coverage.
-
-**`ci`**: All thresholds set to 0.0 — complete end-to-end automation including Apply — but sandbox and checkpoints remain mandatory and unsafe tools are blocked. Designed for non-interactive environments where full automation is needed but safety nets must be preserved. Use for: CI/CD pipelines, automated testing workflows, scheduled batch jobs, any headless execution where rollback capability is essential.
-
-**`full-auto`**: All thresholds set to 0.0 — complete end-to-end automation including Apply. No sandbox or checkpoint requirements. Unsafe tools are allowed. Use for: low-risk routine tasks (dependency updates, documentation generation, formatting), trusted batch operations with rollback capabilities, environments where external safety mechanisms exist.
-
-#### Profile Precedence
-
-Automation profiles are determined using this precedence (highest to lowest):
-
-1. **Plan-level**: Explicitly set via `--automation-profile` on `agents plan use`
-2. **Action-level**: Set on the action via `--automation-profile` on `agents action create`
-3. **Project-level**: Set via `agents config set core.automation-profile --project `
-4. **Global-level**: Set via `agents config set core.automation-profile `
-
-The **effective profile** for a plan is resolved at the moment of `agents plan use`. Once resolved, the profile is **locked to that plan** — subsequent changes to project or global profiles do not affect running plans.
-
-#### Child Plan Profile Inheritance
-
-Child plans inherit the parent plan's effective automation profile. If the parent's profile is changed explicitly after creation, new child plans use the new profile while already-running child plans retain their original profile.
-
-#### Custom Automation Profiles
-
-Custom profiles are created via YAML configuration files and registered with `agents automation-profile add`. Each automatable task flag takes a confidence threshold (0.0–1.0) instead of a boolean. A threshold of 0.0 means "always automatic" and 1.0 means "always manual." Intermediate values (e.g., 0.5, 0.7) enable fine-grained control where the system proceeds automatically only when the Semantic Escalation confidence score meets or exceeds the threshold:
-
-
-# File: profiles/careful-auto.yaml
-name: local/careful-auto
-description: "Autonomous execution with mandatory sandbox and manual apply"
-
-# Confidence thresholds (0.0 = always auto, 1.0 = always manual)
-decompose_task: 0.0
-create_tool: 0.0
-select_tool: 1.0
-edit_code: 0.0
-execute_command: 0.0
-create_file: 0.0
-delete_content: 1.0
-access_network: 1.0
-install_dependency: 0.0
-modify_config: 0.0
-approve_plan: 0.0
-
-# Safety profile (composed sub-model)
-safety:
- require_sandbox: true
- require_checkpoints: true
- allow_unsafe_tools: false
-
-
-A profile with intermediate thresholds provides nuanced control. For example, `execute_command: 0.7` means decisions during Execute proceed automatically when confidence >= 0.7, but drop to manual review when confidence is below 0.7:
-
-
-# File: profiles/nuanced-auto.yaml
-name: local/nuanced-auto
-description: "Nuanced automation with graduated confidence thresholds"
-
-decompose_task: 0.0 # Always auto-strategize
-create_tool: 0.5 # Auto-execute when confidence >= 0.5
-select_tool: 1.0 # Always require manual apply
-edit_code: 0.3 # Low bar for strategy decisions
-execute_command: 0.7 # Higher bar for execution decisions
-create_file: 0.5 # Auto-fix when reasonably confident
-delete_content: 0.8 # High confidence needed for auto-revision
-access_network: 0.9 # Very high bar for late-stage reversion
-install_dependency: 0.5 # Auto-spawn when moderately confident
-modify_config: 0.0 # Always auto-retry transient errors
-approve_plan: 0.6 # Auto-restore when fairly confident
-
-# Safety profile (composed sub-model)
-safety:
- require_sandbox: true
- require_checkpoints: true
- allow_unsafe_tools: false
-
-
-
-agents automation-profile add --config ./profiles/careful-auto.yaml
-
-
-#### Semantic Escalation
-
-Semantic Escalation is the system that computes a **confidence score** (0.0–1.0) for each operation, and it is the mechanism through which automation profile thresholds take effect. The confidence score reflects the system's assessment of how likely an autonomous action is to succeed without human guidance. This score is then compared against the profile's threshold for the relevant flag to determine whether to proceed automatically or escalate to the user.
-
-The confidence score is computed from multiple factors:
-
-
-class AutonomyController:
- def should_proceed_automatically(self, decision, context, profile):
- """Determine whether to proceed automatically or escalate to user."""
- factors = {
- 'past_success_rate': self.get_historical_success(decision.type),
- 'codebase_familiarity': self.get_familiarity_score(context.project),
- 'risk_assessment': self.evaluate_risk(decision),
- 'invariant_complexity': self.analyze_invariants(decision)
- }
-
- confidence = self.compute_confidence(factors) # Returns 0.0–1.0
- threshold = profile.get_threshold(decision.flag) # e.g., execute_command
-
- if confidence >= threshold:
- # Confidence meets or exceeds the profile threshold — proceed
- return ProceedAutonomously(decision, confidence)
- else:
- # Confidence below threshold — escalate to human
- return RequestHumanGuidance(decision, confidence, threshold, factors)
-
-
-**How thresholds and confidence interact**: A profile with `execute_command: 0.7` means the system will make execution decisions automatically when confidence >= 0.7, but will pause for human input when confidence < 0.7. This is more nuanced than a binary on/off: a profile can set a high bar (0.9) for risky operations while being permissive (0.2) for low-risk ones.
-
-**Special cases**: A threshold of **0.0** means "always automatic" — even zero confidence passes the threshold. A threshold of **1.0** means "always manual" — no confidence level (which tops out below 1.0 in practice) is high enough to pass. This means the old boolean behavior is a strict subset: `true` maps to `0.0` and `false` maps to `1.0`.
-
-#### Progressive Trust Building
-
-New users typically follow this progression:
-
-1. Start with `manual` to understand system behavior
-1. Move to `review` to let phases run automatically while staying in the decision loop
-1. Adopt `supervised` as confidence in the planning phase builds
-1. Try `cautious` for confidence-gated automation that escalates only when uncertain
-1. Adopt `trusted` for routine development tasks
-1. Enable `auto` for well-understood projects with strong invariant coverage
-1. Use `ci` for headless CI/CD pipelines with safety nets intact
-1. Use `full-auto` for low-risk batch operations where external safety mechanisms exist
-
-### Guardrails
-
-!!! adr "Architecture Decision"
- System-level guardrails, pre-flight checks, and runtime limits are defined in [ADR-018: Semantic Error Prevention](adr/ADR-018-semantic-error-prevention.md).
-
-System-level guardrails are pre-flight checks and runtime limits that prevent plans from executing in invalid or unsafe conditions. These are distinct from **Validations** (the Tool subtype described in Core Concepts > Validation) — guardrails operate at the system/infrastructure level before and during plan execution, whereas Validations verify the *quality of the work produced* by a plan at the end of the Execute phase.
-
-#### Plan Generation Guardrails
-
-Before a plan begins execution, the system performs pre-flight validation to ensure the plan is well-formed and its dependencies are satisfiable. These checks must be implemented:
-
-* **Action schema validation**: Verify the action referenced by the plan exists, is well-formed, and its configuration conforms to the expected schema.
-* **Actor availability**: Confirm that all actors required by the plan (strategy actor, execution actor, estimation actor, invariant reconciliation actor) are registered and reachable. For remote actors, verify network connectivity.
-* **Skill and tool existence**: Verify that all skills and tools referenced by the action's actor configuration exist in the registry. This includes both named tools and tools referenced via skills (transitively resolved).
-* **Automation policy**: Verify that the automation profile allows the requested level of autonomy for the target project, resources, and actions.
-* **Rollback feasibility**: If `require_checkpoints` is enabled on the plan, verify that all tools in the actor's skill set have `checkpointable: true`. Reject plans that would use non-checkpointable tools under a checkpoint-required policy.
-* **Resource accessibility**: Verify that the project's linked resources are accessible — git repos are cloneable, databases are connectable, file system paths exist, etc. This is a shallow connectivity check, not a full resource health assessment.
-* **Validation attachment resolution**: Pre-resolve the validations that will apply to this plan (from resource-direct, project, and plan attachment scopes) and verify they are all registered and their tool definitions are valid. This ensures validation failures during Execute are due to the work product, not misconfigured validations.
-
-These pre-flight checks prevent "plan runs with fake providers," missing tool errors mid-execution, and other surprises that waste compute and user time. If any pre-flight check fails, the plan is rejected before entering the Strategize phase, with a clear error message identifying the failing check.
-
-#### Cost and Rate Limits
-
-Runtime guardrails to prevent runaway resource consumption:
-
-* **Per-plan budgets**: Maximum API token spend, maximum wall-clock time, maximum number of tool invocations per plan. When a budget is exceeded, the plan pauses and requests user approval to continue or is terminated.
-* **Per-session budgets**: Aggregate limits across all plans in a session. Prevents a single interactive session from consuming excessive resources.
-* **Per-org budgets**: Server-enforced limits for multi-user deployments. Administrators set organization-wide spend caps that cannot be overridden by individual users.
-* **Per-actor limits**: Maximum tool calls per actor invocation, maximum retries per tool failure, maximum tokens per LLM call. Prevents individual actors from looping indefinitely.
-* **Validation retry limits**: Maximum number of fix-then-revalidate iterations when a required Validation fails during Execute. This is a specific application of per-actor limits — the default is 3 attempts, configurable per plan or in the automation profile.
-
-Cost and rate limits are future concerns that require integration with LLM provider billing APIs and internal metering. The system should define configuration surfaces for these limits but may initially implement only the per-plan and per-actor limits, with per-session, per-org, and billing integration added later.
-
-### Correcting Plans (Core Feature)
-
-!!! adr "Architecture Decision"
- Plan correction, decision revision, and the edit-replay model are defined in [ADR-007: Decision Tree and Correction](adr/ADR-007-decision-tree-and-correction.md).
-
-Correcting plans is where CleverAgents becomes more than "a fancy prompt runner."
-
-#### The Goal
-
-When a plan makes a wrong decision early, we want to:
-
-* correct the decision,
-* recompute only the affected subtree,
-* preserve unaffected work.
-
-This is explicitly described: "redo everything below that decision, not the entire code base."
-
-#### Decision Tree Representation
-
-Every plan records (see Decision Data Model section):
-
-* decisions (choice points) - created during Strategize, including `invariant_enforced`, `subplan_spawn`, and `subplan_parallel_spawn` decisions
-* dependencies (which later work depended on that decision)
-* child plans spawned because of that decision - populated during Execute
-* artifacts generated under that branch
-
-This makes plan runs auditable and correctable.
-
-#### Two Correction Modes
-
-=== "Revert (`--mode=revert`)"
-
- !!! warning "Potentially Expensive"
- Find the decision point in the tree, roll back all changes (code and non-code) to that point, and re-run from that decision point forward. Old execution artifacts are kept for comparison.
-
- - [x] Roll back all changes to the decision point
- - [x] Re-run from that decision point forward
- - [x] Keep old execution artifacts for comparison
- - [ ] ==Potentially expensive== if high up in the tree
-
-=== "Append (`--mode=append`)"
-
- !!! success "Safer and Cheaper"
- Leave history intact and append a new plan at the end that fixes the outcome. Does not rewrite history.
-
- - [x] Leave history intact
- - [x] Append a new corrective plan at the end
- - [x] Cheaper and safer in many cases
- - [x] Does ==not rewrite history==
-
-#### Correction Flow (Revert Mode)
-
-!!! adr "Architecture Decision"
- The detailed rollback and replay mechanics, including mid-phase correction flows and cross-sandbox coordination, are defined in [ADR-035: Decision Tree Rollback and Replay](adr/ADR-035-decision-tree-rollback-and-replay.md).
-
-Correction operates on **two independent rollback dimensions**:
-
-| Dimension | What It Restores | Mechanism | Applicable Phase |
-|---|---|---|---|
-| **Resource rollback** | Sandbox contents (files, database state, filesystem) | Checkpoint restoration via sandbox-strategy-specific handlers | Execute only |
-| **Reasoning rollback** | Actor's conversation history, intermediate reasoning, graph state | LangGraph checkpoint restoration from `actor_state_ref` | Strategize and Execute |
-
-##### Mid-Strategize Correction
-
-When the target decision was created during Strategize (e.g., a `strategy_choice` or `subplan_spawn`), **only reasoning rollback is needed** because Strategize is read-only — no resource modifications exist to undo:
-
-1. **Restore actor state**: Load the target decision's `context_snapshot.actor_state_ref` (LangGraph checkpoint). This restores the strategy actor to the exact reasoning state it was in when the decision was made.
-2. **Supersede affected subtree**: Mark the target decision and all its descendants as superseded (cascading via ADR-034). Decisions above the target remain active and unchanged.
-3. **Inject guidance**: Create a `user_intervention` decision containing the user's `--guidance` text.
-4. **Resume strategy actor**: The actor continues reasoning from the restored state, informed by the correction guidance. New decisions replace the superseded ones, with `is_correction: true, corrects_decision_id: `.
-5. **Record correction**: Create a `correction_attempts` record linking old and new decisions.
-
-If the plan was already in Execute when this correction is requested, all Execute-phase work is rolled back (via checkpoint groups — see below) and the plan reverts to Strategize at the corrected decision point.
-
-##### Mid-Execute Correction
-
-When the target decision was created during Execute (e.g., an `implementation_choice` or `error_recovery`), **both resource and reasoning rollback are needed**:
-
-1. **Load checkpoint group**: Every Execute-phase decision has a corresponding **checkpoint group** — one per-resource checkpoint for each sandbox resource that had been modified at the time the decision was recorded. These are stored in `checkpoint_metadata` linked by `decision_id`.
-
-2. **Classify resources**:
- - *Rollbackable*: resources with sandbox strategies that support checkpointing (`git_worktree`, `filesystem_copy`, `overlay`, `transaction_rollback`)
- - *Non-rollbackable*: resources with `sandbox.strategy: none` (tracked with marker records)
- - *Unaffected*: resources not yet modified at the decision point (no checkpoint row — no rollback needed)
-
-3. **Warn about limitations**: If non-rollbackable resources exist, the user is warned and must confirm. If downstream decisions triggered tools with irreversible `side_effects`, the user is warned that external effects cannot be undone.
-
-4. **Resource rollback**: For each rollbackable checkpoint, dispatch to the strategy-specific handler:
-
- | Strategy | Rollback Operation |
- |---|---|
- | `git_worktree` | `git reset --hard ` in the worktree |
- | `filesystem_copy` | Restore from archived snapshot |
- | `overlay` | Discard overlay writes since checkpoint |
- | `transaction_rollback` | `ROLLBACK TO SAVEPOINT ` |
-
- If any individual resource rollback fails, the correction is marked `'failed'` and the plan enters `errored` state.
-
-5. **Reasoning rollback**: Restore the execution actor's LangGraph state from `context_snapshot.actor_state_ref`.
-6. **Supersede affected subtree**: Cascade superseding through the target and all descendants.
-7. **Inject guidance and resume**: The execution actor continues from the restored state.
-
-!!! note "Decision-Aligned Checkpointing"
- The 1:1 mapping between Execute-phase decisions and resource checkpoints is created automatically by the `record_decision` tool (see Decision Recording Protocol in the Core Concepts section). Every `record_decision` call during Execute triggers a coordinated checkpoint group across all modified sandbox resources. This is what enables fine-grained rollback to any individual Execute-phase decision rather than reverting the entire Execute phase.
-
-##### Affected Subtree Computation
-
-The "affected subtree" — all decisions and child plans invalidated by a correction — is computed by walking the influence DAG (not just the structural tree):
-
-
-def compute_affected_subtree(target_decision_id):
- affected_decisions = {target_decision_id}
- affected_plans = set()
- queue = [target_decision_id]
-
- while queue:
- current = queue.pop(0)
-
- # Follow structural tree children
- children = query("SELECT decision_id FROM decisions "
- "WHERE parent_decision_id = :current AND superseded_by IS NULL")
-
- # Follow influence DAG dependents
- dependents = query("SELECT downstream_ref FROM decision_dependencies "
- "WHERE upstream_decision_id = :current AND dependency_type = 'decision'")
-
- for d in children | dependents:
- if d not in affected_decisions:
- affected_decisions.add(d)
- queue.append(d)
-
- # Collect affected child plans
- child_plans = query("SELECT downstream_ref FROM decision_dependencies "
- "WHERE upstream_decision_id = :current AND dependency_type = 'plan'")
- affected_plans.update(child_plans)
-
- return affected_decisions, affected_plans
-
-
-##### Cross-Plan Correction Cascading
-
-When the affected subtree includes child plans (via `subplan_spawn` or `subplan_parallel_spawn` decisions), the child plan's state determines the behavior:
-
-| Child Plan State | Action |
-|---|---|
-| Not yet started | Cancel the child plan |
-| In progress (Strategize or Execute) | Cancel the child plan, roll back its sandbox |
-| Completed but not applied | Cancel the child plan, roll back its sandbox |
-| **Already applied** | **Correction rejected** — applied changes cannot be unilaterally reverted; correct the child plan independently or use `--mode=append` on the parent |
-
-##### Rollback Tiers
-
-The system's rollback capability depends on the plan's checkpoint and sandbox configuration:
-
-| Tier | Prerequisites | Capability |
-|---|---|---|
-| **Full decision-level** | Checkpointing enabled + sandboxable resources | Roll back to any individual Execute-phase decision |
-| **Phase-level** | Checkpointing disabled or unsupported resources | Revert entire Execute phase → Strategize; re-execute from scratch |
-| **No rollback** | `sandbox.strategy: none` + checkpointing disabled | Only `--mode=append` corrections available |
-
-The system detects the available tier automatically and informs the user when a requested correction exceeds the available capability.
-
-##### Phase Boundary Interaction
-
-`agents plan correct` is **orthogonal** to phase reversion (Execute → Strategize):
-
-- **Phase reversion** is *actor-triggered* when execution constraints are too tight — the actor signals that the strategy needs adjustment.
-- **Decision correction** is *user-triggered* via `plan correct` — the user identifies a wrong decision.
-
-They can interact: correcting a Strategize-phase decision while the plan is in Execute causes both resource rollback (of Execute-phase work) and phase reversion to Strategize. Correcting an Execute-phase decision while still in Execute performs resource rollback within Execute without a phase change.
-
-##### Long-Running Database Transactions
-
-The `transaction_rollback` sandbox strategy uses SAVEPOINTs for decision-aligned checkpoints within a single transaction spanning Execute. For plans with extended execution times, this may exceed database transaction timeouts. Recommended mitigations:
-
-- **Decompose into child plans**: Each child plan gets a shorter transaction (aligns with hierarchical decomposition).
-- **Use `none` strategy with `--mode=append`**: Accept non-rollbackable database changes; fix issues via append corrections.
-- **Implement a custom snapshot-based strategy**: A custom `database-snapshot` resource type using point-in-time snapshots instead of long transactions.
-
-#### History Cleanup
-
-**History can only be flagged for cleanup after a plan reaches the `applied` state.**
-
-Once a plan is applied:
-- It can no longer be rolled back
-- Old correction artifacts can be archived or deleted based on retention policy
-- The decision tree is preserved for audit purposes (superseded decisions are never deleted, per ADR-034)
-
-#### CLI Commands for Correction
-
-
-# View decision tree
-agents plan tree <plan_id>
-agents --format=json plan tree <plan_id> # For visualization tools
-
-# View decision tree including superseded branches
-agents plan tree --show-superseded <plan_id>
-
-# Inspect a specific decision
-agents plan explain <decision_id>
-# Shows: question, chosen option, alternatives, rationale, downstream impact
-
-# Correct via revert-and-replay
-agents plan correct <decision_id> --mode=revert --guidance "<what the decision should be>"
-# Re-executes from that point with the new guidance
-
-# Correct via append (add fix at end)
-agents plan correct <decision_id> --mode=append --guidance "<description of the fix>"
-# Creates a new child plan to fix the outcome without rewriting history
-
-# Compare old vs new after correction
-agents plan diff --correction <correction_attempt_id>
-
-
-#### Correction Safety
-
-!!! success "Safety Guarantees"
- Corrections always:
-
- - [x] Create a new attempt revision (increment `plan.attempt`)
- - [x] Preserve old artifacts for diff/compare
- - [x] Run execute in sandbox again
- - [x] Require apply gating again
- - [x] ==Never modify already-applied changes==
- - [x] Warn about irreversible side effects before proceeding
- - [x] Reject correction of decisions whose affected subtree includes applied child plans
-
- This keeps history reproducible and prevents accidental destructive edits.
-
-### Human-in-the-Loop Collaboration
-
-!!! adr "Architecture Decision"
- Human-in-the-loop controls, interruptibility, and approval gates are defined in [ADR-017: Automation Profiles](adr/ADR-017-automation-profiles.md).
-
-Even though the direction is "more autonomous," the transcript explicitly recognizes that real workflows require engineers to collaborate with the system, editing code while it works, and using better UX integration (TUI/web/IDE).
-
-!!! tip "Design Principles for Human-in-the-Loop"
- | Principle | Description |
- | :-------- | :---------- |
- | **Visibility** | What is the system doing ==right now==? |
- | **Interruptibility** | Pause / cancel / retry at any point |
- | **Editability** | Allow user to modify strategy before execute |
- | **Reconciliation** | Detect if user changed sandbox files mid-run and handle it |
-
-### UI / Interaction Model
-
-!!! adr "Architecture Decision"
- The CLI-first interaction model, TUI, and output rendering are defined in [ADR-021: CLI and Output Rendering](adr/ADR-021-cli-and-output-rendering.md).
-
-#### CLI-first + TUI + Web App + IDE
-
-!!! abstract "Multi-Frontend Architecture"
- The system is ==CLI-first==, with a single UI codebase powering multiple frontends:
-
- - [x] **CLI** — Primary interface for all operations
- - [x] **TUI** — Built using Textual for rich terminal experiences
- - [x] **Web App** — Generated from TUI "for free"
- - [ ] **IDE Plugin** — Future: embeds the TUI in the IDE
-
-#### Plan Tree Visualization
-
-The TUI should show:
-
-* plan list
-* plan details
-* plan tree (ASCII)
-* diff view
-* approvals
-
-And should later allow exporting the tree as image (PNG) or JSON for other visualization tools.
-
-
-
-## TUI
-
-### TUI Architecture Overview
-
-!!! adr "Architecture Decision"
- The TUI architecture, framework selection (Textual >= 1.0), screen hierarchy, TuiMaterializer integration, and A2A event subscription model are defined in [ADR-044: TUI Architecture and Framework](adr/ADR-044-tui-architecture-and-framework.md).
-
-The TUI (Terminal User Interface) is the second Presentation-layer surface for CleverAgents, built on **Textual** (>= 1.0). It provides real-time plan monitoring, multi-session management, interactive decision tree navigation, and rich conversation with actors — capabilities impractical in the stateless CLI.
-
-The TUI communicates with the Application layer exclusively through A2A (ADR-026). It subscribes to A2A events for real-time updates and uses the existing Output Rendering Framework (ADR-021) via a `TuiMaterializer` that maps `ElementHandle` events to Textual widget operations — enabling all CLI command producers to render in the TUI without modification.
-
-Key architectural principles:
-
-- **Direct-to-chat launch** — no launcher screen; opens directly to the main chat interface
-- **Right-side collapsible sidebar** — three states cycled by `shift+tab`: hidden → visible → fullscreen
-- **Multi-session tabs** — independent sessions with separate personas, conversations, and A2A bindings
-- **Escape-cascading navigation** — `escape` always moves toward the main screen from any state
-- **Keyboard-first** — every operation achievable without a mouse; mouse is supplementary
-- **Single UI codebase** — the same Textual widget tree serves standalone TUI, Web (via Textual Web), and IDE plugin
-
-
-#### MainScreen Layout — Sidebar Hidden
-
-When the sidebar is hidden, the conversation takes the full terminal width:
-
-
-┌──────────────────────────────────────────────────────────────────────────────────────────────┐
-│═══════════════════════════════════════════ ◆ ═══════════════════════════════════════════ │
-│ Session 1 ┃ Session 2 ┃ Session 3 │
-│ ┗━━━━━━━━━━━━┛ │
-├──────────────────────────────────────────────────────────────────────────────────────────────┤
-│ │
-│ ┃ You 14:01 │
-│ ┃ Can you review the auth module in the │
-│ ┃ API service? │
-│ ┃ @project:api-service:src/auth/handler.py │
-│ ┃ │
-│ │ │
-│ │ Actor 14:02 │
-│ │ I'll review the authentication handler. │
-│ │ Let me analyze the code structure and │
-│ │ identify potential issues. │
-│ │ │
-│ │ 🔧 local/code-analysis ✔ ▶ │
-│ │ │
-│ │ Found 3 issues in the auth module: │
-│ │ │
-│ │ 1. **Missing rate limiting** │
-│ │ 2. **JWT token** not validated │
-│ │ 3. **Session cleanup** missing │
-│ │ │
-│ │ 🔧 local/file-read ✔ ▼ │
-│ │ ┌─ src/auth/handler.py ─────────────┐ │
-│ │ │ 45 │ def login(self, req): │ │
-│ │ │ 46 │ creds = extract(req) │ │
-│ │ │ 47 │ return auth(creds) │ │
-│ │ └──────────────────────────────────┘ │
-│ │
-│──────────────────────────────────────────────────────────────────────────────────────────────│
-│ Agent connected │
-│──────────────────────────────────────────────────────────────────────────────────────────────│
-│ ┌─────────────────────────────────────────────────────────────────────────────────────┐ │
-│ │ ❯ What would you like to do? │ │
-│ │ ▌@▐ refs ▌/▐ commands ▌!▐ shell │ │
-│ └─────────────────────────────────────────────────────────────────────────────────────┘ │
-│ feature-dev │ claude-4-sonnet │ think: high │ 2 projects │ $0.12 │
-├──────────────────────────────────────────────────────────────────────────────────────────────┤
-│ F1 Help │ shift+tab Sidebar │ tab Persona │ ctrl+tab Preset │ ctrl+s Sessions │ ctrl+q Quit │
-└──────────────────────────────────────────────────────────────────────────────────────────────┘
-
-Key elements in this layout:
-
-- **Throbber** (top edge): rainbow gradient bar, visible only when the actor is processing. Collapses to zero height when idle.
-- **Session Tabs** (below throbber): tab bar with underline indicator on the active session. Hidden when only one session exists. Session labels show state icons: `⌛` (actor working), `❯` (awaiting input), plain (idle).
-- **Conversation** (center): scrollable message stream with block cursor navigation.
-- **Prompt** (bottom): PromptTextArea with mode-dependent symbol (❯ normal, $ shell, ☰ multi-line), overlays for @ references and / commands, and the PersonaBar.
-- **Footer**: context-sensitive hotkey reference, always visible.
-
-
-#### MainScreen Layout — Sidebar Visible
-
-When the sidebar is visible (shift+tab from hidden), it docks to the right at 32-40 chars wide:
-
-
-┌──────────────────────────────────────────────────────────────────────────────────────────────┐
-│═══════════════════════════════════════════ ◆ ═══════════════════════════════════════════ │
-│ Session 1 ┃ Session 2 ┃ Session 3 │
-│ ┗━━━━━━━━━━━━┛ │
-├─────────────────────────────────────────────────────────────┬────────────────────────────────┤
-│ │ ▼ PLANS │
-│ ┃ You 14:01 │ ┌────────────────────────────┐ │
-│ ┃ Can you review the auth module in the │ │ ► fix-auth-bug │ │
-│ ┃ API service? │ │ Phase: Execute ●●●○ │ │
-│ ┃ @project:api-service:src/auth/handler.py │ │ Profile: trusted │ │
-│ ┃ │ │ Actor: claude-4-sonnet │ │
-│ │ │ │ Cost: $0.08 │ │
-│ │ Actor 14:02 │ │ │ │
-│ │ I'll review the authentication handler. │ │ ► refactor-models │ │
-│ │ Let me analyze the code structure and │ │ Phase: Strategize ●○○○ │ │
-│ │ identify potential issues. │ │ Profile: cautious │ │
-│ │ │ │ Depth: 2 (3 subplans) │ │
-│ │ 🔧 local/code-analysis ✔ ▶ │ │ Actor: gpt-4o │ │
-│ │ │ │ ├─ users (execute) │ │
-│ │ Found 3 issues in the auth module: │ │ ├─ orders (strategize) │ │
-│ │ │ │ └─ auth (pending) │ │
-│ │ 1. **Missing rate limiting** │ │ │ │
-│ │ 2. **JWT token** not validated │ │ ◌ update-deps │ │
-│ │ 3. **Session cleanup** missing │ │ Phase: Idle │ │
-│ │ │ │ Profile: auto │ │
-│ │ 🔧 local/file-read ✔ ▼ │ └────────────────────────────┘ │
-│ │ ┌─ src/auth/handler.py ─────────────┐ │ │
-│ │ │ 45 │ def login(self, req): │ │ ▼ PROJECTS │
-│ │ │ 46 │ creds = extract(req) │ │ ┌────────────────────────────┐ │
-│ │ │ 47 │ return auth(creds) │ │ │ ◆ cleveragents [2p] │ │
-│ │ └───────────────────────────────────┘ │ │ ◆ api-service [1p] │ │
-│ │ │ frontend-app [0p] │ │
-│─────────────────────────────────────────────────────────────│ │ infra-terraform [0p] │ │
-│ Agent connected │ └────────────────────────────┘ │
-│─────────────────────────────────────────────────────────────│ │
-│ ┌────────────────────────────────────────────────────────┐ │ │
-│ │ ❯ What would you like to do? │ │ │
-│ │ ▌@▐ refs ▌/▐ commands ▌!▐ shell │ │ │
-│ └────────────────────────────────────────────────────────┘ │ │
-│ feature-dev │ claude-4-sonnet │ think: med │ 2 proj │ $0.12 │ │
-├─────────────────────────────────────────────────────────────┴────────────────────────────────┤
-│ F1 Help │ shift+tab Sidebar │ tab Persona │ ctrl+tab Preset │ ctrl+s Sessions │ ctrl+q Quit │
-└──────────────────────────────────────────────────────────────────────────────────────────────┘
-
-Key elements in this layout:
-
-- **Throbber** (top edge): rainbow gradient bar, visible only when the actor is processing. Collapses to zero height when idle.
-- **Session Tabs** (below throbber): tab bar with underline indicator on the active session. Hidden when only one session exists. Session labels show state icons: `⌛` (actor working), `❯` (awaiting input), plain (idle).
-- **Conversation** (center): scrollable message stream with block cursor navigation.
-- **Sidebar** (right, 32-40 chars wide): Plans panel and Projects panel in collapsible containers.
-- **Prompt** (bottom of left panel): same prompt components as hidden mode, constrained to the conversation column width.
-- **PersonaBar** (below prompt): shows persona name, actor, preset, scope, and cost.
-
-
-#### MainScreen Layout — Sidebar Fullscreen
-
-Fullscreen mode (shift+tab from visible) covers the entire terminal for plan/project/persona management:
-
-
-┌──────────────────────────────────────────────────────────────────────────────────────────────┐
-│ PLANS & PROJECTS BROWSER │
-│──────────────────────────────────────────────────────────────────────────────────────────────│
-│ PLANS │ PROJECTS │
-│ ┌───────────────────────────────────────────┐ │ ┌──────────────────────────────────────────┐ │
-│ │ │ │ │ │ │
-│ │ [x] ► fix-auth-bug │ │ │ [x] cleveragents │ │
-│ │ Phase: Execute ●●●○ │ │ │ Namespace: local/ │ │
-│ │ State: in_progress │ │ │ Resources: 5 │ │
-│ │ Profile: trusted │ │ │ Plans: 2 active │ │
-│ │ Actor: anthropic/claude-4-sonnet │ │ │ Invariants: 3 │ │
-│ │ Started: 2m ago Cost: $0.08 │ │ │ Validations: 2 │ │
-│ │ Decisions: 6 (4 done, 2 pending) │ │ │ │ │
-│ │ │ │ │ [ ] api-service │ │
-│ │ [ ] refactor-models │ │ │ Namespace: local/ │ │
-│ │ Phase: Strategize ●○○○ │ │ │ Resources: 3 │ │
-│ │ State: in_progress │ │ │ Plans: 1 active │ │
-│ │ Profile: cautious │ │ │ Invariants: 1 │ │
-│ │ Actor: openai/gpt-4o │ │ │ Validations: 4 │ │
-│ │ Started: 5m ago Cost: $0.03 │ │ │ │ │
-│ │ Decisions: 3 (2 done, 1 active) │ │ │ [ ] frontend-app │ │
-│ │ Subplans: 3 (depth 2) │ │ │ Namespace: local/ │ │
-│ │ ├─ users Execute ●●●○ │ │ │ Resources: 2 │ │
-│ │ ├─ orders Strategize ●○○○ │ │ │ Plans: 0 │ │
-│ │ └─ auth Pending │ │ │ │ │
-│ │ │ │ │ [ ] infra-terraform │ │
-│ │ [ ] update-deps │ │ │ Namespace: local/ │ │
-│ │ Phase: Idle │ │ │ Resources: 8 │ │
-│ │ Profile: auto │ │ │ Plans: 0 │ │
-│ │ │ │ │ │ │
-│ └───────────────────────────────────────────┘ │ └──────────────────────────────────────────┘ │
-│──────────────────────────────────────────────────────────────────────────────────────────────│
-│ PERSONA CYCLE LIST (tab order) │
-│ ┌──────────────────────────────────────────────────────────────────────────────────────┐ │
-│ │ 1. feature-dev (claude-4-sonnet, 2 projects) │ │
-│ │ 2. reviewer (gpt-4o, 1 project) │ │
-│ │ 3. infra-admin (claude-4-opus, 1 project) │ │
-│ │ [+] Add current selection as persona... │ │
-│ └──────────────────────────────────────────────────────────────────────────────────────┘ │
-│──────────────────────────────────────────────────────────────────────────────────────────────│
-│ Selected: 1 plan, 1 project │
-│ space Select │ enter Details │ ctrl+p Create Persona │ / Search │ d Delete │ esc Back │
-└──────────────────────────────────────────────────────────────────────────────────────────────┘
-
-In fullscreen mode:
-
-- **Selection mode**: `space` toggles selection on the highlighted plan or project. Selected items show `[x]`, deselected show `[ ]`.
-- **Persona creation**: `ctrl+p` opens the PersonaEditorModal with the selected plans and projects pre-populated as the scope.
-- **Detail inspection**: `enter` on a plan opens the PlanDetailModal; `enter` on a project opens the ProjectDetailModal.
-- **Persona cycle list**: The bottom panel shows the ordered list of personas that `tab` cycles through. Users can reorder (`ctrl+up`/`ctrl+down`), remove (`d`), or add new personas from the current selection.
-
-
-#### Sidebar State Transitions
-
-| State | Layout | Input Focus | Content |
-|-------|--------|-------------|---------|
-| **Hidden** | Sidebar `display: none`; conversation full width | Prompt retains focus | No sidebar content visible |
-| **Visible** | Sidebar docked right, 32-40 chars wide | Prompt retains focus; `ctrl+b` focuses sidebar | Plans and Projects panels in collapsible containers |
-| **Fullscreen** | Covers entire screen | Sidebar takes input focus | Extended details, selection mode, persona management |
-
-State transitions:
-```
-Hidden ──shift+tab──► Visible ──shift+tab──► Fullscreen
- ▲ │
- └──────────────── escape (×1-2) ───────────────┘
-```
-
-
-### Persona System
-
-!!! adr "Architecture Decision"
- The persona abstraction, argument preset cycling, scope behavior, and persona lifecycle are defined in [ADR-045: TUI Persona System](adr/ADR-045-tui-persona-system.md).
-
-A **persona** is a TUI-only abstraction that bundles:
-
-1. **Actor reference** — a namespaced actor name (e.g., `anthropic/claude-4-sonnet`)
-2. **Base arguments** — default arguments passed to the actor on every invocation
-3. **Scoped projects** — projects always included in the session's context
-4. **Scoped plans** — plans always included in the session's context
-5. **Argument presets** — named argument overrides cycled with `ctrl+tab`
-6. **Display metadata** — short name, accent color, description
-
-Personas are stored as YAML files in `~/.config/cleveragents/personas/` and are strictly a Presentation-layer concept — they never appear in the domain model, A2A protocol, or database schema.
-
-
-#### PersonaBar
-
-The PersonaBar always shows the current state:
-
-
-┌──────────────────────────────────────────────────────────────────────┐
-│ ❯ What would you like to do? │
-│ ▌@▐ refs ▌/▐ commands ▌!▐ shell │
-└──────────────────────────────────────────────────────────────────────┘
- feature-dev │ claude-4-sonnet │ think: high │ 2 projects │ $0.12
- ─────────── ─ ─────────────── ─ ─────────── ─ ──────────────── ─ ─────
- persona actor preset scope cost
-
-| PersonaBar Segment | Style | Updates When |
-|--------------------|-------|--------------|
-| Persona name | `$text-primary` on `$primary 10%` bg | `tab` cycle |
-| Actor name | `$text-secondary` | `tab` cycle |
-| Preset label | `$text-warning` (non-default) / `$text-muted` (default) | `ctrl+tab` cycle |
-| Scope indicator | `$text-muted` | Persona change or `/scope:add/remove` |
-| Session cost | `$secondary 70%`, right-aligned | After each actor response |
-
-
-#### Persona Cycling
-
-`tab` cycles through personas in the configured cycle list. `ctrl+tab` cycles through the current persona's argument presets:
-
-```
-tab: persona_1 → persona_2 → persona_3 → persona_1 → ...
-ctrl+tab: default → think: high → think: max → quick → default → ...
-```
-
-When cycling, the PersonaBar updates immediately. The actor binding for the session is updated — subsequent prompts use the new persona's actor and scope.
-
-
-#### First-Run Experience
-
-On first launch (no personas configured), a centered overlay guides actor selection:
-
-
-┌──────────────────────────────────────────────────────────────────────┐
-│ Welcome to CleverAgents │
-│ │
-│ Select an actor to get started: │
-│ │
-│ ❯ anthropic/claude-4-sonnet (recommended) │
-│ anthropic/claude-4-opus │
-│ openai/gpt-4o │
-│ openai/o3 │
-│ google/gemini-2 │
-│ / to search... │
-│ │
-│ A default persona will be created with this actor. │
-│ You can add more actors and personas later. │
-│ │
-│──────────────────────────────────────────────────────────────────────│
-│ enter Select │ j/k Navigate │ / Search │
-└──────────────────────────────────────────────────────────────────────┘
-
-Selection creates a `"default"` persona with the chosen actor and auto-generated argument presets (thinking effort levels are auto-detected from the actor's argument schema). Subsequent launches restore the last active persona.
-
-
-### Reference and Command System
-
-!!! adr "Architecture Decision"
- The @ reference notation grammar, fuzzy search algorithm, / command system, ! shell mode, and ACMS integration are defined in [ADR-046: TUI Reference and Command System](adr/ADR-046-tui-reference-and-command-system.md).
-
-The TUI prompt supports three input modes, each activated by a distinct prefix:
-
-| First Character | Mode | Prompt Symbol | Sent To | Overlay |
-|-----------------|------|---------------|---------|---------|
-| *(any other)* | Normal | `❯` | Actor via A2A | — |
-| `@` *(inline)* | Normal + Reference | `❯` | Actor (with CRP directives) | ReferencePickerOverlay |
-| `/` | Command | `/` | TUI command processor | SlashCommandOverlay |
-| `!` | Shell | `$` | Host OS subprocess | — |
-
-
-#### Reference Picker (@)
-
-Typing `@` anywhere in a normal-mode prompt activates the Reference Picker — a fuzzy-search overlay for projects, plans, and resources:
-
-
-┌─ Reference Picker ───────────────────────────────────────────────────┐
-│ @hand │
-│ ──────────────────────────────────────────────────────────────────── │
-│ PROJECT api-service:src/auth/handler.py │
-│ local/api-service • Python • 245 lines │
-│ │
-│ PROJECT cleveragents:git_dir/src/cli/commands/handler.py │
-│ local/cleveragents • Python • 189 lines │
-│ │
-│ PROJECT api-service:src/auth/middleware/handler_base.py │
-│ local/api-service • Python • 67 lines │
-│ │
-│ PLAN fix-auth-handler (01HXM8C2...) │
-│ Phase: Execute • Actor: claude-4-sonnet │
-│ │
-│ ──────────────────────────────────────────────────────────────────── │
-│ enter Select │ tab Tree │ ctrl+p Projects │ ctrl+l Plans │
-└──────────────────────────────────────────────────────────────────────┘
-
-Resolved references use a canonical notation: `@project:local/api-service:src/auth/handler.py`. Fuzzy input like `@handler.py` auto-expands to the canonical form on selection.
-
-Resolved `@` references are translated into CRP (Context Request Protocol) directives before the prompt reaches the actor — they semantically direct the ACMS to prioritize referenced resources in context assembly.
-
-
-#### Reference Picker — Tree Browser Mode
-
-Pressing `tab` in the Reference Picker switches to tree browser mode for hierarchical navigation:
-
-
-┌─ Reference Picker (Tree) ────────────────────────────────────────────┐
-│ │
-│ ▼ Projects │
-│ ▼ local/cleveragents │
-│ ▼ git_dir (git-checkout) │
-│ ▸ src/ │
-│ ▸ tests/ │
-│ ▸ docs/ │
-│ ─ pyproject.toml │
-│ ─ README.md │
-│ ▸ database (sqlite-db) │
-│ ▸ local/api-service │
-│ ▸ local/frontend-app │
-│ ▼ Plans │
-│ ▸ fix-auth-bug (01HXM8C2) │
-│ ▸ refactor-models (01HXM9D3) │
-│ │
-│ enter Select │ tab Search │ space Expand │ / Filter │
-└──────────────────────────────────────────────────────────────────────┘
-
-
-#### Slash Command Overlay (/)
-
-Typing `/` as the first character activates command mode. Commands are TUI operations executed locally — they are **not** sent to the actor.
-
-
-##### Slash Command Overlay
-
-
-┌─ Commands ─────────────────────────────────────────────────────────────┐
-│ /se │
-│ ───────────────────────────────────────────────────────────────────────│
-│ /session:create Create a new session tab │
-│ /session:list Show all sessions │
-│ /session:show Show session details │
-│ /session:switch Switch to session by ID │
-│ /session:close Close current session │
-│ /session:delete Delete a saved session │
-│ /session:rename Rename current session │
-│ /session:export Export session to file │
-│ /session:import Import session from file │
-│ /settings Open settings screen │
-│ │
-│ enter Execute │ tab Complete │ escape Dismiss │
-└────────────────────────────────────────────────────────────────────────┘
-
-TUI slash commands mirror CLI command patterns where applicable. The CLI uses `agents `; the TUI uses `/:`. Commands that exist in both CLI and TUI use the same verb names. TUI-only commands (persona, scope, TUI utilities) have no CLI equivalent.
-
-
-##### Complete Command Reference
-
-**Session Commands** — *mirrors CLI `agents session `*
-
-| Command | Arguments | Description |
-|---------|-----------|-------------|
-| `/session:create` | `[--persona ]` | Create a new session tab |
-| `/session:list` | — | Display all sessions |
-| `/session:show ` | `` | Show session details |
-| `/session:switch ` | `` | Switch to session by ID or tab index |
-| `/session:close` | `[--force]` | Close the current session tab |
-| `/session:delete ` | ``, `[--yes/-y]` | Delete a saved session |
-| `/session:rename ` | `` | Rename the current session |
-| `/session:export [path]` | `[path]` | Export session to JSON |
-| `/session:import ` | `` | Import session from JSON |
-
-**Persona Commands** — *TUI-only*
-
-| Command | Arguments | Description |
-|---------|-----------|-------------|
-| `/persona:list` | — | Display all personas |
-| `/persona:set ` | `` | Switch to persona |
-| `/persona:create` | — | Open PersonaEditorModal |
-| `/persona:edit [name]` | `[name]` | Edit persona |
-| `/persona:delete ` | `` | Delete persona |
-| `/persona:export ` | `` | Export persona YAML |
-| `/persona:import ` | `` | Import persona YAML |
-
-**Scope Commands** — *TUI-only*
-
-| Command | Arguments | Description |
-|---------|-----------|-------------|
-| `/scope:add [` | `][` | Add project/plan to session scope |
-| `/scope:remove ][` | `][` | Remove from session scope |
-| `/scope:clear` | — | Clear session-level scope additions |
-| `/scope:show` | — | Show effective scope |
-
-**Plan Commands** — *mirrors CLI `agents plan `*
-
-| Command | Arguments | Description |
-|---------|-----------|-------------|
-| `/plan:use ` | ``, `[projects...]`, `[--arg/-a ]` | Start a new plan |
-| `/plan:list` | `[--phase]` `[--state]` `[--project]` `[--action]` | List plans |
-| `/plan:status [id]` | `[id]` | Show plan status |
-| `/plan:tree ` | ``, `[--show-superseded]` `[--depth]` | Show decision tree |
-| `/plan:execute [id]` | `[id]` | Execute a plan |
-| `/plan:apply [id]` | `[id]` | Apply a completed plan |
-| `/plan:cancel ` | ``, `[--reason/-r]` | Cancel a plan |
-| `/plan:diff ` | ``, `[--correction]` | Show plan diff |
-| `/plan:correct ` | ``, `--mode`, `--guidance` | Correct a decision |
-| `/plan:resume ` | ``, `[--dry-run]` | Resume a plan |
-| `/plan:revert ` | `]