Files
cleveragents-core/docs/specification.md
T

2.0 MiB
Raw Blame History

CleverAgents Documentation (Detailed Spec)

Key Themes

Key themes include:

  • A four-phase plan lifecycle (Action → Strategize → Execute → Apply).
  • Actors as a unifying abstraction (an LLM/agent or a whole graph).
  • A sandbox + diff review workflow and CLI-first interaction model.
  • A scalable context/memory architecture (hot/warm/cold tiers, 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.

Big Picture: What CleverAgents is

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.

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.

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:

CleverAgents provides:

  • A first-class plan lifecycle (Action/Strategize/Execute/Apply) for breaking down and tracking complex work,
  • A project + resource model for grounding tasks in real codebases, databases, documents, and infrastructure,
  • A consistent actor abstraction for defining and composing intelligent agents,
  • An independently registered resource abstraction for representing anything that can be read, written, or queried,
  • An independently registered tool abstraction for reusable, callable operations with resource bindings,
  • A consistent skill abstraction for organizing tools into composable capability collections,
  • A sandbox + checkpoint safety model for safe, reversible execution,
  • A CLI/TUI/Web UX for controlling and monitoring large multi-step autonomous work.

Glossary (Terms Used Precisely)

  • Plan: A hierarchical, stateful unit of work that progresses through four phases (Action → Strategize → Execute → Apply). Plans persist a decision tree, can spawn child plans, and are identified by ULID. Namespaced as [[server:]namespace/]name.
  • Action: A reusable, project-agnostic plan template defined via a YAML configuration file. Specifies a description, definition of done, strategy and execution actors, typed arguments, and optional invariants. Bound to one or more projects via agents plan use to produce a plan. Namespaced as [[server:]namespace/]name.
  • Strategize: The read-only planning phase of the plan lifecycle. The strategy actor produces all decisions — strategy choices, invariant enforcement, resource selections, and child plan blueprints — that govern subsequent execution. No resources are modified.
  • Execute: The sandboxed implementation phase of the plan lifecycle. The execution actor realizes the decisions from Strategize: invoking tools, spawning child plans, producing artifacts, and creating checkpoints. All changes are confined to the sandbox.
  • Apply: The commit phase of the plan lifecycle. Merges the sandbox changeset into real project resources after validations pass, transitioning the plan to terminal applied state.
  • Project: A named collection of linked resources, validation commands, context policies, and invariants that defines the scope of where plans operate. The project's namespaced name ([[server:]namespace/]name) serves as its globally unique identifier — no separate ID is generated. Projects reference resources from the Resource Registry (they do not own them); a single resource can be linked to multiple projects. May be local or remote.
  • Resource: An independently registered entity representing anything that can be read, written, or queried (git repos, filesystems, databases, etc.). Classified as either physical or virtual, typed by a resource type (which is namespaced), and organized in a DAG of parent/child relationships. Registered in the Resource Registry and linked to projects. Extends the MCP resource concept with write support. Every resource is identified by a system-assigned ULID. User-added resources also have a namespaced name ([[server:]namespace/]name) specified at creation time; auto-discovered child resources are identified by ULID only. They have a type and may have a description.
  • Resource Type: A schema-level definition constraining a category of resources. Specifies accepted CLI arguments, physical/virtual classification, allowed parent/child type relationships, auto-discovery rules, sandbox strategy, and handler implementation. Built-in types (git-checkout, fs-mount, etc.) are unnamespaced; custom types are defined in YAML and namespaced as [[server:]namespace/]name.
  • Physical Resource: A resource representing a specific, concrete, located artifact — a particular file at a particular path, a particular git repo at a particular URL. Directly readable and writable by tools. Distinct instances even when content-identical.
  • 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 are updated when the underlying physical resources diverge.
  • Resource Binding: The association between a tool and the resources it operates on, declared via typed resource slots. Slots are resolved 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 three core registries alongside the Tool Registry and Skill Registry.
  • Skill: A namespaced, composable collection of tools assembled by referencing named tools, defining inline anonymous tools, including other skills, or exposing MCP server / Agent Skills Standard tools. Actors reference skills by name to acquire capabilities. Namespaced as [[server:]namespace/]name.
  • Tool: A namespaced, independently registered callable operation — the atomic unit of execution. Defined by a JSON Schema for inputs/outputs, capability metadata (read-only, writes, checkpointable), and a discover/activate/execute/deactivate lifecycle. Sources: MCP servers, Agent Skills Standard folders, built-in operations, or custom Python. Can be grouped into skills or used directly as tool nodes in actor graphs. Namespaced as [[server:]namespace/]name.
  • Anonymous Tool: An inline tool definition embedded directly in a skill YAML or actor graph node. Uses the same format as a named tool but is unregistered, unnamespaced, and scoped only to its defining context.
  • Actor: A conversational unit that may be a single LLM/agent or a composed LangGraph of actors and tool nodes. Defined via YAML configuration files. Specialized roles include strategy actor, execution actor, estimation actor, and invariant reconciliation actor. Namespaced as [[server:]namespace/]name.
  • Session: A persistent user conversation thread tied to an orchestrator actor. Maintains message history across multiple plans and serves as the interface for natural-language interaction.
  • Server: An optional shared service providing multi-user storage, namespace resolution, permissions, and remote plan execution.
  • Namespace: The scoping component in the full name format [[server:]namespace/]name, controlling ownership and visibility. When namespace is omitted, it defaults to local/. When server is omitted and namespace is local/, server is not applicable. When server is omitted and namespace is something other than local/, the default configured server is assumed. local/ is reserved for local-only items; <username>/ and <orgname>/ are server-stored. Built-in LLM actors use provider prefixes (openai/, anthropic/). Built-in resource types are unnamespaced.
  • Decision: A persisted choice point in a plan's decision tree, created during Strategize. Records the question, chosen option, alternatives, confidence score, rationale, context snapshot, and downstream dependencies. Types include prompt_definition, invariant_enforced, strategy_choice, subplan_spawn, subplan_parallel_spawn, and others. Supports targeted correction and selective subtree recomputation.
  • Invariant: A natural-language constraint on plan execution, scoped to global, project, action, or plan level. Precedence flows plan > project > global. Reconciled by the Invariant Reconciliation Actor at the start of Strategize and recorded as invariant_enforced decisions that propagate to child plans.
  • Automation Profile: A named set of confidence thresholds (0.01.0) controlling which plan operations proceed automatically vs. require human approval. Thresholds gate phase transitions, decision autonomy, self-repair, child plan spawning, and safety requirements. 0.0 = always automatic; 1.0 = always manual. Eight built-in profiles range from manual to full-auto. Custom profiles follow [[server:]namespace/]name.
  • ULID: Universally Unique Lexicographically Sortable Identifier. Used for plan, decision, resource, and correction attempt IDs. Preferred over UUID for time-sortability. Note: Projects, actions, skills, and tools do not use ULIDs — their namespaced name is their unique identifier. Resources use both: a ULID (always) and a namespaced name (for user-added resources only; auto-discovered child resources have ULID only).

CLI Commands

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 validation add [(--description|-d) <DESC>] [--required|--informational] [--timeout <SECONDS>] [--resource <RESOURCE>] <PROJECT> <COMMAND> agents project validation remove [--yes|-y] <PROJECT> <VALIDATION_ID> agents project validation list <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>] [--clear] <PROJECT> agents project context show [--view (strategize|execute|apply|default)] <PROJECT>

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> [--unsafe] [(--option|-o) <key>=<value>]... [--type (graph|agent)] [--update] [--skill <SKILL>]... [(--description|-d) <DESC>] [<NAME>] # NAME is optional — the config file's required "name" field is used. # When provided, overrides the config file's name. 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> [(--description|-d) <DESC>] [--update] [--tool <TOOL>]... [--include-skill <INCLUDE_SKILL>]... [--mcp-server <SPEC>]... [<NAME>] 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> [(--description|-d) <DESC>] [--update] [--source <SOURCE>] [--input-schema <JSON>] [--code <CODE>] [--writes|--no-writes] [--checkpointable|--no-checkpointable] [<NAME>] agents tool remove [--yes|-y] <NAME> agents tool list [(--namespace|-n) <NS>] [--source <SOURCE>] [<REGEX>] agents tool show <NAME>

agents resource type add (--config|-c) <FILE> [--update] [--physical|--virtual] [--user-addable|--no-user-addable] [--sandbox-strategy <STRATEGY>] [--handler <NAME>] [--child-type spec]... [--cli-arg spec]... [<NAME>] 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 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>] [--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 action create (--config|-c) <CFG_FILE> [--strategy-actor <STRATEGY_ACTOR>] [--execution-actor <EXEC_ACTOR>] [--definition-of-done <DOD>] [(--description|-d) <DESC>] [--long-description <LONG_DESC>] [--reusable|--no-reusable] [--read-only] [--available] [--estimation-actor <EST_ACTOR>] [--invariant-actor <INV_ACTOR>] [--automation-profile <PROFILE>] [--invariant <INVARIANT>]... [--arg <ARG_SPEC>]... [<NAME>] agents action list [(--namespace|-n) <NS>] [(--state|-s) <STATE>] [--available] [<REGEX>] agents action show <ACTION_NAME> agents action available <ACTION_NAME> agents action archive <ACTION_NAME>

agents automation-profile add (--config|-c) <FILE> [--update] [<NAME>] 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

Global Options

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. The available formats are:
    • rich (default): Uses modern rich CLI elements with dynamic effects, animated spinners, progress bars, and generous color. Best for interactive terminal use.
    • color: Plain scrolling text with ANSI color codes. Good for terminals that support color but not advanced rendering.
    • table: ASCII box-drawing characters to create structured tables and panels with color. Similar to the examples shown throughout this document.
    • plain: Plain text with no color codes or non-ASCII characters. Suitable for piping into files, logs, or non-terminal consumers.
    • json: Structured JSON output for programmatic consumption. No color except within verbatim text values.
    • yaml: Structured YAML output for programmatic consumption. No color except within verbatim text values.
  • --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). Each additional -v raises the logging level one notch above the configured default. No -v uses the default level (typically WARNING for terminal output). -v = INFO, -vv = DEBUG, -vvv = TRACE, -vvvv = the most granular logging level available. This flag does not persist — it only affects the current invocation.

Examples


$ 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

agents version

agents version

Purpose Print the current CLI version.

Arguments

None.

Examples


$ 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

agents info

agents info

Purpose Show configuration and runtime information useful for debugging or support.

Arguments

None.

Examples


$ 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

agents diagnostics

agents diagnostics

Purpose Run health checks for configuration, providers, and filesystem permissions.

Arguments

None.

Examples


$ agents diagnostics

╭─ Checks ────────────────────────────────╮ │ Check Status Details │ │ ─────────────── ────── ────────────── │ │ Config file OK readable │ │ Database OK writable │ │ OPENAI_API_KEY WARN missing │ │ Anthropic key OK configured │ │ 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: 10 total │ │ Warnings: 2 │ │ Errors: 0 │ │ Duration: 0.6s │ ╰───────────────────╯

╭─ Recommendations ─────────────────────────────────────────────╮ │ - Set OPENAI_API_KEY to enable OpenAI models │ │ - Configure a graph store backend for structural code queries │ │ - Verify provider credentials via config │ ╰───────────────────────────────────────────────────────────────╯

⚠ WARN 2 warnings require attention

When critical checks fail, diagnostics reports errors:


$ agents diagnostics

╭─ Checks ────────────────────────────────────────────╮ │ Check Status Details │ │ ─────────────── ─────── ──────────────────── │ │ Config file OK readable │ │ Database ERROR locked by another process │ │ OPENAI_API_KEY OK configured │ │ Anthropic key ERROR invalid key format │ │ 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: 10 total │ │ Warnings: 1 │ │ 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. Anthropic key starts with "pk-" — expected "sk-ant-" prefix │ │ Run: agents config set provider.anthropic.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

agents init

agents init [--yes|-y]

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


$ 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

Non-interactive initialization using --yes (useful in scripts and CI):


$ 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)

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


$ 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

agents session list
agents session list

Purpose List sessions available on the local machine.

Arguments

None.

Examples


$ 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

agents session show
agents session show <SESSION_ID>

Purpose Show details and recent messages for a session.

Arguments

  • <SESSION_ID>: The session identifier.

Examples


$ 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

agents session delete
agents session delete [--yes|-y] <SESSION_ID>

Purpose Delete a session and its stored conversation history.

Arguments

  • <SESSION_ID>: The session identifier.
  • --yes, -y: Skip the confirmation prompt.

Examples


$ 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

agents session export
agents session export [(--output|-o) <FILE>] <SESSION_ID>

Purpose Export a session as a portable JSON file.

Arguments

  • <SESSION_ID>: The session identifier.
  • --output/-o FILE: Output file path (optional).

Examples


$ 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

agents session import
agents session import (--input|-i) <FILE>

Purpose Import a session JSON file.

Arguments

  • --input/-i FILE: Input JSON file.

Examples


$ 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

agents session tell
agents session tell --session <SESSION_ID> [--actor <ACTOR>] [--stream] <PROMPT>

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

  • <PROMPT>: 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


$ 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 local/refresh-locks │ │ - 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 (draft) │ │ 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

Using --stream to see the response as it is generated (token by token):


$ 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

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

  • <NAME>: 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


$ 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

Creating a project with resources and invariants in one 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

╭─ 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

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>: Project name (positional argument).
  • <RESOURCE>: 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


$ 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 │ ╰─────────────────────────────────────────╯

╭─ Permissions ────────────╮ │ 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

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>: Project name (positional argument).
  • <RESOURCE_NAME>: Resource name (positional argument). Only user-added (named) resources can be unlinked.
  • --yes, -y: Skip confirmation prompt.

Examples


$ 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

agents project list
agents project list [(--namespace|-n) NS] [<REGEX>]

Purpose List projects with optional filters.

Arguments

  • --namespace/-n NS: Filter by namespace.

Examples


$ 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

agents project show
agents project show <PROJECT>

Purpose Show full project details.

Arguments

  • <NAME>: Project name.

Examples


$ 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) ───────────────────────────────────────────╮ │ val_01HXM5A pytest --cov=src --cov-fail-under=80 required │ │ val_01HXM5B ruff check . required │ │ val_01HXM5C 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

agents project validation

Purpose Manage validations for a project. Validations are commands that run during the Execute phase to verify the correctness of changes. Each validation has an optional description, a command to execute, and a mode (required or informational). Required validations must pass for execution to proceed; informational validations are included in the summary but do not block execution.

agents project validation add
agents project validation add [(--description|-d) <DESC>] [--required|--informational]
                              [--timeout <SECONDS>] [--resource <RESOURCE>] <PROJECT> <COMMAND>

Purpose Add a validation to a project.

Arguments

  • <PROJECT>: Project name (positional argument).
  • <COMMAND>: The shell command to run (positional argument, quoted string).
  • --description/-d TEXT: Optional description of what this validation checks.
  • --required/--informational: Whether the validation must pass (default: --required). Required validations block execution on failure; informational validations report results without blocking.
  • --timeout SECONDS: Timeout for this validation command (default: 300).
  • --resource RESOURCE: Scope this validation to a specific linked resource (name or ULID).

Examples


$ agents project validation add --description "Run unit tests with coverage" \
  --required --timeout 600 --resource local/api-repo local/api-service "pytest --cov=src --cov-fail-under=80"

╭─ Validation Added ───────────────────────────────────────────╮ │ ID: val_01HXM5A │ │ Project: local/api-service │ │ Command: pytest --cov=src --cov-fail-under=80 │ │ Description: Run unit tests with coverage │ │ Mode: required │ │ Resource: 01HXR1A1...B2C3 │ │ Timeout: 600s │ ╰──────────────────────────────────────────────────────────────╯

✓ OK Validation added


$ agents project validation add --description "Lint check" \
  --required local/api-service "ruff check ."

╭─ Validation Added ───────────────────╮ │ ID: val_01HXM5B │ │ Project: local/api-service │ │ Command: ruff check . │ │ Description: Lint check │ │ Mode: required │ │ Timeout: 300s │ ╰──────────────────────────────────────╯

✓ OK Validation added


$ agents project validation add --description "Check bundle size (advisory)" \
  --informational local/api-service "node scripts/check-bundle-size.js"

╭─ Validation Added ───────────────────────────────╮ │ ID: val_01HXM5C │ │ Project: local/api-service │ │ Command: node scripts/check-bundle-size.js │ │ Description: Check bundle size (advisory) │ │ Mode: informational │ │ Timeout: 300s │ ╰──────────────────────────────────────────────────╯

✓ OK Validation added

agents project validation remove
agents project validation remove [--yes|-y] <PROJECT> <VALIDATION_ID>

Purpose Remove a validation from a project.

Arguments

  • <PROJECT>: Project name (positional argument).
  • <VALIDATION_ID>: Validation identifier (positional argument).
  • --yes, -y: Skip confirmation prompt.

Examples


$ agents project validation remove local/api-service val_01HXM5C

Remove validation val_01HXM5C from local/api-service? [y/N]: y

╭─ Validation Removed ──────────────────────────────╮ │ ID: val_01HXM5C │ │ Command: node scripts/check-bundle-size.js │ │ Description: Check bundle size (advisory) │ ╰───────────────────────────────────────────────────╯

✓ OK Validation removed

agents project validation list
agents project validation list <PROJECT>

Purpose List all validations for a project.

Arguments

  • <PROJECT>: Project name (positional argument).

Examples


$ agents project validation list local/api-service

╭─ Validations ─────────────────────────────────────────────────────────────────────────╮ │ ID Command Mode Timeout Resource │ │ ─────────── ─────────────────────────────────── ──────────── ─────── ──────── │ │ val_01HXM5A pytest --cov=src --cov-fail-under=80 required 600s repo │ │ val_01HXM5B ruff check . required 300s (all) │ │ val_01HXM5C node scripts/check-bundle-size.js informational 300s (all) │ ╰───────────────────────────────────────────────────────────────────────────────────────╯

╭─ Summary ──────────────╮ │ Total: 3 │ │ Required: 2 │ │ Informational: 1 │ ╰────────────────────────╯

✓ OK 3 validations listed

agents project delete
agents project delete [--force|-f] [--yes|-y] <NAME>

Purpose Delete a project and unlink all associated resources. The resources themselves remain in the Resource Registry.

Arguments

  • <NAME>: Project name.
  • --force/-f: Delete even if active plans exist.
  • --yes: Skip confirmation prompt.

Examples


$ 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

Attempting to delete a project that has active plans (without --force):


$ 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

Force-deleting a project with active plans:


$ 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 Removed: 3 │ │ Plans Cancelled: 2 │ │ Context Policies: cleared │ ╰──────────────────────────────╯

✓ OK Project force-deleted

agents project context

Purpose Manage context policies for the hot/warm/cold tiers and per-view context selection.

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>]
                          [--clear] <PROJECT>

Purpose Set the context policy for a project and (optionally) a specific view.

Arguments

  • <PROJECT>: 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.
  • --clear: Clear the policy for the selected view.

Examples


$ 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

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>: Project name (positional argument, at end of command).
  • --view strategize|execute|apply|default: View to display.

Examples


$ 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

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

  • <NAME>: The name of the actor to run (required).
  • <PROMPT>: Prompt text (positional argument).
  • --output/-o FILE: Output file path.
  • --verbose/-v: Increase verbosity (repeatable).
  • --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


$ 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

Running an actor with a custom temperature and skill attachment:


$ 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

Saving actor output to a file:


$ 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)

agents actor add
agents actor add (--config|-c) <FILE> [--unsafe] [(--option|-o) <key>=<value>]...
                [--type (graph|agent)] [--update]
                [--skill <SKILL>]... [(--description|-d) <DESC>] [<NAME>]

Purpose Add a new actor configuration, or replace an existing one with --update. An actor can be defined via a YAML configuration file, entirely from CLI options, or a combination of both. When both a --config file and CLI options are provided, the CLI options act as overrides for values defined in the configuration file. If a local actor with the same name already exists, the command fails unless the --update flag is provided, which replaces the existing actor.

Name Resolution

The actor's registered name is determined by the following precedence:

  1. CLI NAME argument (highest priority): When provided on the command line, this value is used as the actor's registered name, overriding any name field in the config file.
  2. Config file name field (fallback): When the CLI NAME argument is omitted, the name field from the YAML configuration file is used. This field is required in the config file and must follow the <namespace>/<name> naming convention.

This design allows config files to be self-describing (carrying their own identity) while still permitting per-invocation name overrides for reuse scenarios (e.g., registering the same config under different namespaces).

Arguments

  • [<NAME>]: Actor name (optional). When omitted, the name field from the config file is used. When provided, overrides the config file's name field. Must follow <namespace>/<name> format.
  • --config/-c FILE: Actor config file. When provided, values from the file serve as defaults. When omitted, the actor is defined entirely from CLI options.
  • --type graph|agent: Actor type.
  • --skill NAME: Skill to attach to the actor (repeatable).
  • --description/-d TEXT: Actor description.
  • --unsafe: Mark actor as unsafe.
  • --option/-o key=value: Option override (repeatable).
  • --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.

When --config is provided alongside CLI options, the CLI options override the corresponding values from the config file.

Examples


$ 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

Attempting to register an actor that already exists (without --update). Since the config file already contains name: local/reviewer, no CLI name argument is needed:


$ 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

Updating an existing actor with --update and adding a skill:


$ agents actor add --config ./actors/reviewer.yaml --update --skill local/code-analysis

# The name 'local/reviewer' is read from the config file's 'name' field. # To override it: agents actor add --config ./actors/reviewer.yaml --update --skill local/code-analysis myorg/reviewer

╭─ Actor Updated ─────────────────────╮ │ Name: local/reviewer │ │ Type: agent │ │ Status: updated │ ╰─────────────────────────────────────╯

╭─ Changes ────────────────────────────╮ │ Skills: +1 (local/code-analysis) │ │ Model: unchanged │ │ Graph: updated │ ╰──────────────────────────────────────╯

✓ OK Actor updated

agents actor remove
agents actor remove <NAME>

Purpose Remove a custom actor.

Arguments

  • <NAME>: Actor name.

Examples


$ 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

agents actor list
agents actor list

Purpose List all actors.

Arguments

None.

Examples


$ 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

agents actor show
agents actor show <NAME>

Purpose Show details for a single actor.

Arguments

  • <NAME>: Actor name.

Examples


$ 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 │ ╰────────────────────────────────╯

╭─ Permissions ───────╮ │ 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

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>)

Purpose Remove files or directories from an actor context.

Arguments

  • <NAME>: 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


$ 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

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


$ 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

agents actor context show
agents actor context show <NAME>

Purpose Show content of a file in an actor context.

Arguments

  • <NAME>: Context name (positional argument).

Examples


$ 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

agents actor context export
agents actor context export (--output|-o) <FILE> <NAME>

Purpose Export a context as JSON.

Arguments

  • <NAME>: Context name (positional argument).
  • --output/-o FILE: Output file path (required).

Examples


$ 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

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


$ 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

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

  • <NAME>: 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


$ 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

agents skill

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> [(--description|-d) <DESC>] [--update]
                [--tool <TOOL>]... [--include-skill <INCLUDE_SKILL>]... [--mcp-server <SPEC>]... [<NAME>]

Purpose Register a new skill. A skill can be defined via a YAML configuration file, entirely from CLI options, or a combination of both. When both a --config file and CLI options are provided, the CLI options act as overrides for values defined in the configuration file. 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

  • [<NAME>]: Namespaced skill name (optional). When provided via a config file, the name can be omitted from the command line.
  • --config/-c FILE: Path to the skill YAML configuration file. When provided, values from the file serve as defaults. When omitted, the skill is defined entirely from CLI options.
  • --description/-d TEXT: Optional description (overrides what's in the YAML when both are provided).
  • --tool NAME: Named tool to include in the skill (repeatable). References tools from the Tool Registry.
  • --include-skill NAME: Include another skill's tools (repeatable). References skills by fully-qualified name.
  • --mcp-server spec: MCP server specification to expose tools from (repeatable).
  • --update: Allow overwriting an existing skill registration. Without this flag, attempting to add a skill whose name is already registered will fail.

When --config is provided alongside CLI options (--tool, --include-skill, --mcp-server, --description), the CLI options override or extend the corresponding values from the config file.

Examples

Registering a new skill:


$ agents skill add --config ./skills/devops-toolkit.yaml local/devops-toolkit

╭─ 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

Attempting to add a skill that already exists (without --update):


$ agents skill add --config ./skills/devops-toolkit-v2.yaml local/devops-toolkit

✗ 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 local/devops-toolkit

Updating an existing skill with --update:


$ agents skill add --config ./skills/devops-toolkit-v2.yaml --update local/devops-toolkit

╭─ 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)

agents skill remove
agents skill remove [--yes|-y] <NAME>

Purpose Remove a registered skill.

Arguments

  • <NAME>: Skill name to remove.
  • --yes: Skip confirmation prompt.

Examples


$ 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

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


$ 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

agents skill show
agents skill show  <NAME>

Purpose Show full details for a registered skill, including its includes, tool sources, and capability summary.

Arguments

  • <NAME>: Skill name.

Examples


$ 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

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

  • <NAME>: Skill name.

Examples


$ 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

agents tool

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).

agents tool add
agents tool add (--config|-c) <FILE> [(--description|-d) <DESC>] [--update]
               [--source <SOURCE>] [--input-schema <JSON>] [--code <CODE>]
               [--writes|--no-writes] [--checkpointable|--no-checkpointable] [<NAME>]

Purpose Register a new tool. A tool can be defined via a YAML configuration file, entirely from CLI options, or a combination of both. When both a --config file and CLI options are provided, the CLI options act as overrides for values defined in the configuration file. 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

  • <NAME>: Namespaced tool name (appears at the end of the command).
  • --config/-c FILE: Path to the tool YAML configuration file. When provided, values from the file serve as defaults. When omitted, the tool is defined entirely from CLI options.
  • --description/-d TEXT: Optional description (overrides what's in the YAML when both are provided).
  • --source SOURCE: Tool source type (custom, mcp, agent_skill, builtin).
  • --input-schema JSON: JSON Schema for tool inputs.
  • --code TEXT: Inline Python code for custom tools.
  • --writes/--no-writes: Whether the tool performs write operations.
  • --checkpointable/--no-checkpointable: Whether the tool supports checkpointing.
  • --update: Allow overwriting an existing tool registration. Without this flag, attempting to add a tool whose name is already registered will fail.

When --config is provided alongside CLI options, the CLI options override the corresponding values from the config file.

Examples

Registering a new tool:


$ agents tool add --config ./tools/run-migrations.yaml local/run-migrations

╭─ 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

Attempting to add a tool that already exists (without --update):


$ agents tool add --config ./tools/run-migrations-v2.yaml local/run-migrations

✗ 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 local/run-migrations

Updating an existing tool with --update:


$ 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

agents tool remove
agents tool remove [--yes|-y] <NAME>

Purpose Remove a registered tool.

Arguments

  • <NAME>: Tool name to remove.
  • --yes: Skip confirmation prompt.

Examples


$ 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

agents tool list
agents tool list [(--namespace|-n) <NS>] [--source <SOURCE>] [<REGEX>]

Purpose List registered tools with optional filters.

Arguments

  • --namespace/-n NS: Filter by namespace.
  • --source SOURCE: Filter by tool source type (mcp, agent_skill, builtin, custom).

Examples


$ agents tool list --namespace local

╭─ Tools ──────────────────────────────────────────────────╮ │ Name Source Read-Only Writes │ │ ───────────────────────── ─────── ───────── ────── │ │ local/run-migrations custom — ✓ │ │ local/validate-api-compat custom — ✓ │ │ local/create-subplan custom — ✓ │ │ local/deploy-staging agent — ✓ │ ╰──────────────────────────────────────────────────────────╯

╭─ Summary ────────╮ │ Total: 4 │ │ Read-Only: 0 │ │ Writes: 4 │ ╰──────────────────╯

✓ OK 4 tools listed

agents tool show
agents tool show <NAME>

Purpose Show full details for a registered tool, including its schema, capability metadata, and where it is referenced.

Arguments

  • <NAME>: Tool name.

Examples


$ 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

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 <type> 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]
                       [--physical|--virtual] [--user-addable|--no-user-addable]
                       [--sandbox-strategy <STRATEGY>] [--handler <NAME>]
                       [--child-type spec]... [--cli-arg spec]... [<NAME>]

Purpose Register a new custom resource type. A resource type can be defined via a YAML configuration file, entirely from CLI options, or a combination of both. When both a --config file and CLI options are provided, the CLI options act as overrides for values defined in the configuration file.

Arguments

  • [<NAME>]: Namespaced resource type name (e.g., local/svn, cleverthis/s3-bucket). Optional when provided via a config file.
  • --config/-c FILE: Path to the resource type YAML configuration file. When provided, values from the file serve as defaults. When omitted, the resource type is defined entirely from CLI options.
  • --physical/--virtual: Whether instances of this type are physical or virtual.
  • --user-addable/--no-user-addable: Whether instances can be created directly by users.
  • --sandbox-strategy NAME: Sandbox strategy for instances of this type (e.g., copy_on_write, transaction_rollback, none).
  • --handler NAME: Resource handler implementation.
  • --child-type spec: Allowed child resource type specification (repeatable).
  • --cli-arg spec: CLI argument definition for agents resource add <type> (repeatable).
  • --update: If the type name already exists, overwrite it. Without this flag, adding a duplicate name fails with an error.

When --config is provided alongside CLI options, the CLI options override the corresponding values from the config file.

Examples


$ agents resource type add --config ./resource-types/svn.yaml local/svn

╭─ 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

agents resource type remove
agents resource type remove [--yes|-y] <NAME>

Purpose Remove a custom resource type. Built-in types cannot be removed. Fails if any registered resources use this type.

Arguments

  • <NAME>: Resource type name.
  • --yes: Skip confirmation prompt.

Examples


$ 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

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


$ 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

agents resource type show
agents resource type show <NAME>

Purpose Show detailed information about a resource type, including its full schema.

Arguments

  • <NAME>: Resource type name.

Examples


$ 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

agents resource

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.

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

  • <TYPE>: Resource type name (e.g., git-checkout, git, fs-mount, fs-directory, local/svn). Determines type-specific flags.
  • <NAME>: 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 <TYPE> for available arguments.

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


$ 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 remove
agents resource remove [--yes|-y] <NAME>

Purpose Remove a registered resource and all its auto-discovered child resources. Only user-added (named) resources can be removed. Fails if the resource is linked to any project (unlink first).

Arguments

  • <NAME>: Resource name (only user-added resources can be removed).
  • --yes: Skip confirmation prompt.

Examples


$ 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

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


$ 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

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>: Resource name or ULID.

Examples


$ 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

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>: Resource name or ULID.
  • --tree: Show the resource's file/content tree.
  • --file PATH: Show contents of a specific file within the resource.

Examples


$ 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


$ 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 │ ╰──────────────────────────────────────────────────────────╯

1from fastapi import Request, HTTPException 2from .token_service import validate_token 3 4async def auth_middleware(request: Request): 5 │ token = request.headers.get("Authorization") 6if not token: 7raise HTTPException(status_code=401) 8 │ user = await validate_token(token) 9 │ request.state.user = user 10return user ... (24 more lines)

✓ OK 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>: 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


$ 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

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>: Parent resource name or ULID.
  • <CHILD>: Child resource name or ULID.

Examples


$ 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

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>: Parent resource name or ULID.
  • <CHILD>: Child resource name or ULID.
  • --yes: Skip confirmation prompt.

Examples


$ 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

agents plan

Purpose Manage plans through the Action -> Strategize -> Execute -> Apply lifecycle.

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


$ 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

Listing all plans without filters shows plans across all phases and states:


$ agents plan list

╭─ Plans ──────────────────────────────────────────────────────────────────────────────────────╮ │ ID Phase State Action Project Elapsed │ │ ──────── ────────── ────────── ─────────────────── ───────────────── ───────── │ │ 01HXM7A9 execute processing local/code-coverage local/api-service 00:01:12 │ │ 01HXM6R3 applied complete 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

Filtering by project with --project:


$ 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

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>]
                [--arg/-a name=value]...
                <ACTION> <PROJECT>...

Purpose Apply an action to one or more projects and start the Strategize phase.

Arguments

  • <ACTION_NAME>: Action name.
  • <PROJECT>: 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.

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


$ 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

Applying an action to multiple projects simultaneously, with plan-level invariants:


$ 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

Using an action with custom actor overrides:


$ 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

agents plan execute
agents plan execute <PLAN_ID>

Purpose Start or resume execution for a plan.

Arguments

  • <PLAN_ID>: Plan ID (required).

Examples


$ 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

Resuming execution of a plan that was previously paused or errored:


$ 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

agents plan apply
agents plan apply [--yes|-y] <PLAN_ID>

Purpose Apply sandboxed changes to real resources.

Arguments

  • <PLAN_ID>: Plan ID.
  • --yes: Skip confirmation.

Examples


$ 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: applied │ │ State: complete │ │ 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

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:


$ 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

agents plan status
agents plan status <PLAN_ID>

Purpose Show detailed status for a plan.

Arguments

  • <PLAN_ID>: Plan ID (required).

Examples


$ 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

Status of a plan that has completed successfully:


$ agents plan status 01HXM6R3ZK4Q7C2B3F2R4VYV6J

╭─ Plan Status ─────────────────────╮ │ Plan: 01HXM6R3ZK4Q7C2B3F2R4VYV6J │ │ Phase: applied │ │ State: complete │ │ 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

Status of a plan in the strategize phase:


$ 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

Status of a plan that encountered an error:


$ 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

agents plan cancel
agents plan cancel [(--reason|-r) <REASON>] <PLAN_ID>

Purpose Cancel a plan that is not terminal.

Arguments

  • <PLAN_ID>: Plan ID.
  • --reason/-r TEXT: Optional reason.

Examples


$ 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

agents plan tree
agents plan tree [--show-superseded] <PLAN_ID>

Purpose Render the decision tree for a plan.

Arguments

  • <PLAN_ID>: Plan ID (required).
  • --show-superseded: Include superseded decisions.

Examples


$ 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 Name Phase State │ │ ────────── ───────────── ─────── ───────── │ │ 01HXM9F1A auth-tests execute processing │ │ 01HXM9F2B payment-tests 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

agents plan explain
agents plan explain [--show-context] [--show-reasoning] <DECISION_ID>

Purpose Show a detailed explanation for a decision.

Arguments

  • <DECISION_ID>: Decision ID.
  • --show-context: Include the context snapshot.
  • --show-reasoning: Include raw model reasoning if available.

Examples


$ 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

Including the raw model reasoning with --show-reasoning:


$ 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

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>: 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


$ 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

Using --mode append to add a corrective decision without reverting existing work (useful when the original decision was partially correct):


$ 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

Using --dry-run to preview the impact of a correction before committing to it:


$ 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

agents plan diff
agents plan diff (--correction <CORRECTION_ATTEMPT_ID>|<PLAN_ID>)

Purpose Show diffs for a plan or a correction attempt.

Arguments

  • <PLAN_ID>: Show diff for a plan (positional argument). Mutually exclusive with --correction.
  • --correction CORRECTION_ATTEMPT_ID: Show diff for a correction attempt instead.

Examples


$ 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

Showing the diff for a specific correction attempt, comparing what changed between the original and corrected execution:


$ 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

agents plan artifacts
agents plan artifacts <PLAN_ID>

Purpose List artifacts produced by a plan.

Arguments

  • <PLAN_ID>: Plan ID.

Examples


$ 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

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>: Plan ID.
  • "<GUIDANCE>": Guidance text.

Examples


$ 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

agents plan rollback
agents plan rollback [--yes|-y] <PLAN_ID> <CHECKPOINT_ID>

Purpose Rollback a plan sandbox to a checkpoint.

Arguments

  • <PLAN_ID>: Plan ID.
  • <CHECKPOINT_ID>: Checkpoint ID.
  • --yes: Skip confirmation.

Examples


$ 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

agents action

Purpose Manage reusable actions.

agents action create
agents action create (--config|-c) <CFG_FILE>
                     [--strategy-actor <STRATEGY_ACTOR>]
                     [--execution-actor <EXEC_ACTOR>]
                     [--definition-of-done <DOD>]
                     [(--description|-d) <DESC>]
                     [--long-description <LONG_DESC>]
                     [--reusable|--no-reusable]
                     [--read-only]
                     [--available]
                     [--estimation-actor <EST_ACTOR>]
                     [--invariant-actor <INV_ACTOR>]
                     [--automation-profile <PROFILE>]
                     [--invariant <INVARIANT>]...
                     [--arg <ARG_SPEC>]...
                     [<NAME>]

Purpose Create a new action template from a YAML configuration file. The --config file is required and must fully define the action. CLI options provided alongside --config act as optional overrides for values defined in the configuration file.

Arguments

  • [<NAME>]: Namespaced action name (optional when provided in config file).
  • --config/-c FILE: YAML configuration file defining the action (required). The file must fully define the action. Any CLI options provided alongside --config override the corresponding values in the file.
  • --strategy-actor ACTOR: Override the Strategize actor from config.
  • --execution-actor ACTOR: Override the Execution actor from config.
  • --definition-of-done TEXT: Override the completion criteria from config.
  • --description TEXT: Short description.
  • --long-description TEXT: Long description.
  • --arg/-a spec: Argument definition (repeatable).
  • --reusable/--no-reusable: Keep action after use.
  • --read-only: Read-only action.
  • --available: Make action available immediately.
  • --estimation-actor ACTOR: Optional estimation actor.
  • --invariant-actor ACTOR: Invariant Reconciliation Actor for this action. Carried forward to plans created from this action (can be overridden via agents plan use --invariant-actor).
  • --automation-profile PROFILE: Default automation profile for plans created from this action.
  • --invariant TEXT: Invariant to attach to this action (repeatable). These invariants are carried forward as plan-level invariants when the action is used.

The --config file must define strategy-actor, execution-actor, and definition-of-done. Any of these can be overridden via CLI flags.

Examples


$ agents action create --config ./actions/code-coverage.yaml \
  --available local/code-coverage

╭─ Action Created ──────────────────────╮ │ 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 │ ╰───────────────────────────────────────╯

╭─ Usage ──────────────────────────────────────────────────────────────────╮ │ agents plan use local/code-coverage local/api-service │ │ --arg target_coverage_percent=85 │ ╰──────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Creating an action entirely from a YAML configuration file:


$ agents action create local/code-coverage --config ./actions/code-coverage.yaml

╭─ Action Created ────────────────────────╮ │ Name: local/code-coverage │ │ State: draft │ │ 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

Creating an action from a config file with CLI overrides (the --execution-actor overrides the value from the YAML, and --available is added):


$ agents action create local/code-coverage \
  --config ./actions/code-coverage.yaml \
  --execution-actor local/fast-executor \
  --available

╭─ Action Created ────────────────────────╮ │ Name: local/code-coverage │ │ State: available │ │ Strategy Actor: local/strategist │ │ Execution Actor: local/fast-executor │ │ Reusable: yes │ │ Read Only: no │ │ Config: ./actions/code-coverage.yaml │ │ Created: 2026-02-08 12:20 │ ╰─────────────────────────────────────────╯

╭─ Overrides Applied ──────────────────────────────────────╮ │ execution_actor: local/executor → local/fast-executor │ │ available: false → true │ ╰──────────────────────────────────────────────────────────╯

╭─ Definition of Done ─╮ │ Coverage reaches 85% │ ╰──────────────────────╯

✓ OK Action created

agents action list
agents action list [(--namespace|-n) <NS>] [(--state|-s) <STATE>] [--available] [<REGEX>]

Purpose List actions with optional filters.

Arguments

  • --namespace/-n NS: Filter by namespace.
  • --state/-s STATE: Filter by state.
  • --available: Show only available actions.

Examples


$ agents action list --available

╭─ 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 │ │ Draft: 0 │ │ Archived: 0 │ │ Total Plans Created: 3 │ ╰────────────────────────╯

✓ OK 1 action listed

agents action show
agents action show <ACTION_NAME>

Purpose Show details for an action.

Arguments

  • <ACTION_NAME>: Action name.

Examples


$ 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

agents action available
agents action available <ACTION_NAME>

Purpose Mark a draft action as available.

Arguments

  • <ACTION_NAME>: Action name.

Examples


$ agents action available local/code-coverage

╭─ Action Available ─────────────╮ │ Name: local/code-coverage │ │ State: draft → available │ ╰────────────────────────────────╯

╭─ Visibility ─────╮ │ Namespace: local │ │ Listed: yes │ │ Usable: yes │ ╰──────────────────╯

╭─ Validation ────────────────────────╮ │ Strategy Actor: resolved │ │ Execution Actor: resolved │ │ Definition of Done: present │ │ Arguments: valid schema │ ╰─────────────────────────────────────╯

✓ OK Action marked available

agents action archive
agents action archive <ACTION_NAME>

Purpose Archive an action.

Arguments

  • <ACTION_NAME>: Action name.

Examples


$ 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

agents automation-profile

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. A threshold of 0.0 means "always automatic" and 1.0 means "always manual." Built-in profiles (manual, review, supervised, cautious, trusted, auto, ci, full-auto) are always available. Custom profiles follow the same <namespace>/<name> naming convention as other entities.

agents automation-profile add
agents automation-profile add (--config|-c) <FILE> [--update] [<NAME>]

Purpose Register a new custom automation profile from a YAML configuration file. If a profile with the same name already exists, the command fails unless the --update flag is provided.

Arguments

  • [<NAME>]: Profile name (optional when provided in config file).
  • --config/-c FILE: YAML configuration file defining the profile (required).
  • --update: Replace an existing profile with the same name.

Examples


$ 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 ────────────────╮ │ auto_strategize: 0.0 │ │ auto_execute: 0.0 │ │ auto_apply: 1.0 │ │ auto_decisions_strategize: 0.0 │ │ auto_decisions_execute: 0.0 │ │ auto_validation_fix: 0.0 │ │ auto_strategy_revision: 1.0 │ │ auto_child_plans: 0.0 │ │ auto_retry_transient: 0.0 │ │ auto_checkpoint_restore: 0.0 │ │ require_sandbox: true │ │ require_checkpoints: true │ │ allow_unsafe_tools: false │ ╰────────────────────────────────────────╯

✓ OK Profile registered

agents automation-profile remove
agents automation-profile remove [--yes|-y] <NAME>

Purpose Remove a custom automation profile. Built-in profiles cannot be removed.

Arguments

  • <NAME>: Profile name.
  • --yes, -y: Skip confirmation prompt.

Examples


$ 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

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


$ 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

agents automation-profile show
agents automation-profile show <NAME>

Purpose Show full details for an automation profile, including all flag values.

Arguments

  • <NAME>: Profile name.

Examples


$ agents automation-profile show trusted

╭─ Automation Profile ───────────────────────────────────────────╮ │ Name: trusted │ │ Source: built-in │ │ Description: Auto-exec, manual apply. Day-to-day development │ ╰────────────────────────────────────────────────────────────────╯

╭─ Phase Transitions (thresholds) ─────╮ │ auto_strategize: 0.0 │ │ auto_execute: 0.0 │ │ auto_apply: 1.0 │ ╰──────────────────────────────────────╯

╭─ Decision Automation (thresholds) ───╮ │ auto_decisions_strategize: 0.0 │ │ auto_decisions_execute: 0.0 │ ╰──────────────────────────────────────╯

╭─ Self-Repair (thresholds) ───────────╮ │ auto_validation_fix: 0.0 │ │ auto_strategy_revision: 1.0 │ │ auto_retry_transient: 0.0 │ │ auto_checkpoint_restore: 1.0 │ ╰──────────────────────────────────────╯

╭─ Execution Controls (thresholds) ────╮ │ auto_child_plans: 0.0 │ │ require_sandbox: true │ │ require_checkpoints: true │ │ allow_unsafe_tools: false │ ╰──────────────────────────────────────╯

✓ OK Profile loaded

agents config

Purpose Manage global configuration values.

agents config set
agents config set <key> <value>

Purpose Set a configuration key.

Arguments

  • <key>: 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>: 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


$ 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

Setting the default output format:


$ agents config set core.format table

╭─ Config Updated ─────────────────╮ │ Key: core.format │ │ Previous: rich │ │ New Value: table │ │ Scope: user (~/.cleveragents) │ ╰──────────────────────────────────╯

✓ OK Set core.format = table

Setting a global invariant actor:


$ 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

agents config get
agents config get <key>

Purpose Get a configuration value.

Arguments

  • <key>: Key to read.

Examples


$ 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

agents config list
agents config list [--filter-values <REGEX>] [<REGEX>]

Purpose List all configuration values.

Arguments

None.

Examples


$ agents config list

╭─ Config ───────────────────────────────────────────────────╮ │ Key Value Source Modified │ │ ──────────────── ────────────────── ─────── ──────── │ │ core.automation-profile trusted config yes │ │ actor.default.invariant local/reconciler config yes │ │ core.log.level INFO default no │ ╰────────────────────────────────────────────────────────────╯

╭─ Overrides ─────╮ │ Env: none │ │ CLI Flags: none │ ╰─────────────────╯

╭─ Config File ───────────────────────╮ │ Path: ~/.cleveragents/config.toml │ │ Size: 284 bytes │ │ Valid: yes │ ╰─────────────────────────────────────╯

✓ OK 6 settings listed

agents invariant

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). Exactly one scope flag is required for add and list.

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

  • <INVARIANT_TEXT>: 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


$ 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

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


$ 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)

agents invariant remove
agents invariant remove [--yes|-y] <INVARIANT_ID>

Purpose Remove an invariant by ID. The invariant is removed from whichever scope it was originally attached to.

Arguments

  • <INVARIANT_ID>: Invariant ID to remove.
  • --yes: Skip confirmation.

Examples


$ 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

Core Concepts

Plan

A plan is the fundamental unit of orchestration and traceability.

Plan Lifecycle Phases

A plan always moves through the following phases, in order:

Action → Strategize → Execute → Apply → Applied (terminal)

In this spec:

  • Strategize is the phase name (the output is a strategy).
  • Execute is the phase name (the output is a changeset).
  • Apply is the phase name (the output is an applied change).
  • Applied is the resulting terminal state after Apply succeeds.

This four-stage model is explicitly called out as the new architecture replacing a prior linear pipeline.

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 Applied

Important behavioral rule: 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.

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."

Recommended state model:

  • Action phase states

    • available (action exists and can be used)
    • draft (action is being authored/edited)
    • archived (soft-deleted or hidden, optional)
  • Strategize / Execute / Apply phase states

    • queued (waiting for compute/worker)
    • processing (currently running)
    • errored (failed; includes error metadata)
    • complete (finished successfully)
    • cancelled (user/system cancelled; safe terminal for that phase)

Plan Identity and Traceability

Every plan should have:

  • plan_id: Unique, immutable ID (UUID or ULID).
  • parent_plan_id: Nullable; present for child plans.
  • root_plan_id: The top-most plan in the tree.
  • attempt: An integer attempt counter that increments when re-running a phase (e.g., re-executing after a fix).
  • created_at / updated_at / completed_at timestamps.
  • created_by (user identity / session identity).

Plan Hierarchy and Parallelism

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

When handling massive tasks (e.g., converting Firefox to Rust), 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 (spawned via subplan_parallel_spawn for independent subsystems)

    • "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

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 (including inherited invariants) 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.
Child Plan Failure Handling
  • Parallel execution (via subplan_parallel_spawn): Other parallel child plans continue even if one fails.
  • Sequential execution: Subsequent child plans are not started if a prior one fails.
  • Note: 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

The Plan "Decision Tree" and Visualization

CleverAgents intends to record 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).

Decision Data Model

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
auto_decisions_strategize = 1.0 (always manual) User is prompted for each decision point during Strategize
auto_decisions_strategize = 0.0 (always automatic) Strategy actor makes decisions autonomously, records reasoning
auto_decisions_execute = 1.0 (always manual) User is prompted for each decision point during Execute
auto_decisions_execute = 0.0 (always automatic) Execution actor makes decisions autonomously

Intermediate thresholds (e.g., auto_decisions_strategize = 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:

  • <decision_id>: 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 </span> --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 </span> --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 </span> --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 </span> --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 only created during the Strategize phase. The decision tree captures what choices were made and why, enabling correction and replay.

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 Decisions are created, including invariant_enforced decisions for applicable invariants, subplan_spawn decisions, and subplan_parallel_spawn decisions grouping parallel child plans. downstream_plan_ids is empty.
Execute Child plans are spawned. downstream_plan_ids is populated when child plans are created based on subplan_spawn decisions (both standalone and those within subplan_parallel_spawn groups).
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,
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (plan_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> plans(plan_id),
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (parent_decision_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> decisions(decision_id),
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (corrects_decision_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> decisions(decision_id),
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (superseded_by) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> 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

<span style="color: #5599ff; font-weight: 600;">PRIMARY</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (upstream_decision_id, downstream_decision_id, downstream_ref),
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (upstream_decision_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> 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,

<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (plan_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> plans(plan_id),
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (original_decision_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> decisions(decision_id),
<span style="color: #5599ff; font-weight: 600;">FOREIGN</span> <span style="color: #5599ff; font-weight: 600;">KEY</span> (new_decision_id) <span style="color: #5599ff; font-weight: 600;">REFERENCES</span> decisions(decision_id)

);

Action

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. There are two modes of creation:

1. Config-only (all values from YAML):


agents action create "local/code-coverage" \
  --config ./actions/code-coverage.yaml

2. Config with CLI overrides:


agents action create "local/code-coverage" \
  --config ./actions/code-coverage.yaml \
  --execution-actor "local/fast-executor" \
  --available

In both modes, the YAML file provides the full action definition. Any CLI options provided alongside --config override the corresponding values from the file.

Required parameters:

  • --config: YAML configuration file that fully defines the action (strategy-actor, execution-actor, definition-of-done, etc.)

Optional parameters (overrides):

  • [<NAME>]: Namespaced name (positional, e.g., local/code-coverage, myorg/deploy-action). When provided, overrides the name in the config file.
  • --strategy-actor: Override the Strategize actor from config
  • --execution-actor: Override the Execution actor from config
  • --definition-of-done: Override the completion criteria from config

Optional parameters:

  • --description: Human-readable description
  • --arg: Argument definitions (can be repeated). Format: name:type:required|optional:description
  • --invariant: Invariant to attach to this action (can be repeated). These are carried forward as plan-level invariants when the action is used.
  • --invariant-actor: Invariant Reconciliation Actor for plans created from this action. Can be overridden at use time via agents plan use --invariant-actor.
  • --reusable: Whether action remains available after use (default: true)
  • --read-only: Whether action only performs read operations (default: false)

Arguments defined with --arg 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/]<name>

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.

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 0100
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)

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 </span> api-service </span> web-frontend </span> mobile-app

# With action arguments agents plan use local/code-coverage </span> my-api-service </span> --arg target_coverage_percent=85 </span> --arg test_framework=pytest

# With explicit automation profile agents plan use local/deploy-action </span> staging-env </span> --automation-profile manual

# With invariants attached at use time agents plan use local/code-coverage </span> my-api-service </span> --arg target_coverage_percent=85 </span> --invariant "All API calls over TCP must be mocked" </span> --invariant "Do not modify the payments module"

Parameters:

  • <PROJECT>: 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 > 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 > 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()
<span style="opacity: 0.7;"># Direct file dependencies</span>
closure.add_files(find_imports(target_module))
closure.add_files(find_includes(target_module))

<span style="opacity: 0.7;"># Symbol dependencies</span>
<span style="color: magenta; font-weight: 600;">for</span> symbol <span style="color: magenta; font-weight: 600;">in</span> extract_exported_symbols(target_module):
    closure.add_files(find_symbol_usage(symbol, scope=<span style="color: #66cc66;">&#x27;project&#x27;</span>))

<span style="opacity: 0.7;"># Test dependencies</span>
closure.add_files(find_tests_for_module(target_module))

<span style="opacity: 0.7;"># Build system dependencies</span>
closure.add_files(find_build_references(target_module))

<span style="color: magenta; font-weight: 600;">return</span> 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.

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.


# Example: Action with estimation actor (estimation-actor overrides config)
agents action create --config ./actions/expensive-refactor.yaml \
  --estimation-actor "local/cost-estimator" \
  "local/expensive-refactor"

This becomes critical in server/multi-user usage and cost controls.

Execution (Execute Phase)

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)

A sandbox isolates plan execution from the real project resources until Apply.

Key Sandbox Principles
  1. Lazy Sandboxing: Resources are sandboxed only when accessed, not upfront.

    • A project may have many resources (git repo + 10 databases + cloud accounts)
    • A plan may only modify one resource
    • Only accessed resources are sandboxed
    • Efficient for large projects
  2. Per-Plan Sandboxes: Each plan and child plan has its own sandbox containing only the resources it edits.

  3. Resource-Defined Strategy: The sandbox strategy is defined on each resource, not by skills or globally.

  4. Cleanup Behavior:

    • Sandboxes are cleaned up before application exit when possible
    • Abandoned sandboxes (from crashes, etc.) are cleaned up on next application run
    • Completed plan sandboxes are cleaned or archived based on retention policy
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)
<span style="opacity: 0.7;"># Apply resource-specific merge strategies</span>
<span style="color: magenta; font-weight: 600;">for</span> resource_type, changes <span style="color: magenta; font-weight: 600;">in</span> by_resource:
    <span style="color: magenta; font-weight: 600;">if</span> resource_type == <span style="color: #66cc66;">&#x27;git-checkout&#x27;</span>:
        merge_git_changes(changes)  <span style="opacity: 0.7;"># Three-way merge</span>
    <span style="color: magenta; font-weight: 600;">elif</span> resource_type == <span style="color: #66cc66;">&#x27;fs-mount&#x27;</span>:
        merge_fs_changes(changes)   <span style="opacity: 0.7;"># Copy-on-write reconciliation</span>
    <span style="color: magenta; font-weight: 600;">elif</span> resource_type.startswith(<span style="color: #66cc66;">&#x27;database&#x27;</span>):
        merge_db_changes(changes)   <span style="opacity: 0.7;"># Sequential application</span>

<span style="opacity: 0.7;"># Validate merged state</span>
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)

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).

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.

Tool-Based Resource Modification (Modern Architecture)

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
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

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)
    <span style="color: cyan; font-weight: 600;">else</span>:
        raise SemanticError(
            &quot;Breaking API changes require manual review&quot;,
            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

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 project-level and global-level invariants.
  • Project-level invariants override global-level invariants.

Note: Action invariants are carried forward as plan-level invariants when the action is used (see Action invariants above), so they participate in precedence at the plan tier — there is no separate action tier in the precedence chain.

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 <ACTOR>. 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 > project > global) to resolve conflicts.
  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.

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 --invariant "Test files must not import production secrets" local/code-coverage 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 </span> --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)
    <span style="opacity: 0.7;"># 2. Find the Invariant Reconciliation Actor (plan -&gt; project -&gt; global config)</span>
    reconciler = (
        self.get_plan_invariant_actor(plan)
        <span style="color: magenta; font-weight: 600;">or</span> self.get_project_invariant_actor(plan)
        <span style="color: magenta; font-weight: 600;">or</span> self.get_global_invariant_actor()
    )
    
    <span style="opacity: 0.7;"># 3. Reconcile: apply precedence (plan &gt; project &gt; global), resolve conflicts</span>
    effective = reconciler.reconcile(raw, precedence=[<span style="color: #66cc66;">&#x27;plan&#x27;</span>, <span style="color: #66cc66;">&#x27;project&#x27;</span>, <span style="color: #66cc66;">&#x27;global&#x27;</span>])
    <span style="color: magenta; font-weight: 600;">return</span> effective

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">collect_all_invariants</span>(self, plan):
    <span style="color: #66cc66;">&quot;&quot;&quot;Collect invariants from all scopes accessible to this plan.&quot;&quot;&quot;</span>
    invariants = []
    invariants.extend(self.get_global_invariants())
    <span style="color: magenta; font-weight: 600;">for</span> project <span style="color: magenta; font-weight: 600;">in</span> plan.projects:
        invariants.extend(self.get_project_invariants(project))
    invariants.extend(self.get_action_invariants(plan.action))
    invariants.extend(self.get_plan_invariants(plan))
    <span style="color: magenta; font-weight: 600;">return</span> invariants

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">check_invariant_preservation</span>(self, changes, enforced_invariants):
    <span style="color: #66cc66;">&quot;&quot;&quot;Check that changes respect all enforced invariants.&quot;&quot;&quot;</span>
    <span style="color: magenta; font-weight: 600;">for</span> invariant <span style="color: magenta; font-weight: 600;">in</span> enforced_invariants:
        <span style="color: magenta; font-weight: 600;">if</span> <span style="color: magenta; font-weight: 600;">not</span> self.verify_invariant(invariant, changes):
            <span style="color: magenta; font-weight: 600;">return</span> InvariantViolation(invariant, changes)
    <span style="color: magenta; font-weight: 600;">return</span> 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"

Applied (Apply Phase)

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 permissions, approvals, and checks matter most.

  3. Apply produces a terminal 'applied' plan After successful apply, the plan becomes Applied.

Apply should perform (configurable) validations before committing:

  • Diff review gate

    • If the auto_apply 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 Configuration

Validation is defined by the actor configuration and project settings, not hardcoded.

Actor-defined validation: Validation is always the final step of the Execute phase — it does not run during Apply. The execution actor's workflow should include validation nodes at the end of execution that:

  1. Read project-defined validations from context
  2. Execute each validation command and collect results
  3. For required validations that fail: attempt to fix the issue within the bounds of the strategy, retrying up to the configured limit. If the actor determines it cannot solve the problem within the restrictions given by the strategy phase, it may request a change to the decision tree, causing the Strategize phase to be re-run for the affected subtree (whether this happens automatically depends on the automation profile's auto_strategy_revision flag). If the actor determines the problem is not due to strategy restrictions and it simply cannot solve the issue, it fails outright.
  4. For informational validations that fail: record the result in the plan summary without blocking execution.

The plan cannot proceed to the Apply phase until all required validations pass during Execute.

Project-defined validation: Each project defines its validations via agents project validation add:


# Add required validations
agents project validation add --description "Run unit tests with coverage" \
  --required --resource repo local/api-service "pytest --cov=src --cov-fail-under=80"
agents project validation add --description "Lint check" \
  --required local/api-service "ruff check ."
agents project validation add --description "Type checking" \
  --required local/api-service "pyright"

# Add informational (non-blocking) validations agents project validation add --description "Check bundle size (advisory)" </span> --informational local/api-service "node scripts/check-bundle-size.js"

This information is passed into the actor's context, allowing generic actors (not specific to any project) to execute appropriate validation. Each validation is run independently, and results are collected into the plan's validation summary.

Validation Failure Handling

When a required validation fails during Execute:

  1. Self-fix: The execution actor attempts to fix the issue within the bounds of the strategy (e.g., fix failing tests, correct lint errors). The actor iterates, re-running the validation after each fix attempt.
  2. Retry limit: After the configured number of failed attempts, self-fix stops.
  3. Strategy recalculation: If the actor determines it cannot solve the problem within the restrictions given by the strategy phase, it may request a change to the decision tree. This causes the Strategize phase to be re-run for the affected subtree. Whether this happens automatically or requires user approval depends on the automation profile (the auto_strategy_revision flag).
  4. User intervention: If the automation profile requires approval, or if strategy recalculation also fails, the system pauses and requests user guidance.
  5. Resume: Plan continues with new guidance after user input.

When an informational validation fails, the result is recorded in the plan's validation summary but execution continues normally.

The user can prompt the plan with additional instructions when stuck:


agents plan prompt <plan_id> "Try using mock objects for the database tests"

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 command outputs and pass/fail status)
  • approval_record (if human approvals are required)
  • deployment_record (optional, if apply triggers deploy)

"Applied" Terminal State

When Apply succeeds:

  • plan.phase = applied
  • plan.state = complete
  • the sandbox may be cleaned up or archived depending on retention policy

When Apply fails:

  • plan.phase remains Apply
  • plan.state = errored
  • sandbox remains intact for inspection/retry

Project

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 </span> --connection-string "postgresql://staging.example.com/mydb" </span> --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/, <username>/, <orgname>/)
  • 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) Security / permissions defaults
  • who can run write plans
  • which skill categories are allowed or denied
  • whether apply requires approvals

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

Namespaces define ownership, scoping, and discoverability of actors, tools, skills, resources, resource types, actions, projects, and plans.

All named entities use the format <namespace>/<name>.

Namespace Types

Namespace Scope Storage Examples
local/ Current machine only Local database local/my-reviewer, local/test-action
<username>/ Personal server namespace Server database freemo/code-analyzer, jsmith/deploy-script
<orgname>/ 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
  • <username>/ (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
  • <orgname>/ (e.g., cleverthis/, acme/)

    • Organization namespace on the server
    • Created when organization is registered
    • Shared across team members
    • Permissions and approvals managed at org level
    • 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

What an Actor Is

An actor is the abstraction that generalizes "agent" into "anything conversational."

  • 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 <namespace>/<name> format:

  • local/my-reviewer - Local actor
  • freemo/code-analyzer - Personal server actor
  • cleverthis/deploy-specialist - Organization actor
  • openai/gpt-4 - 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"

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:


actors:
  complex_workflow:
    type: llm
    config:
      actor: local/base-analyzer # References another 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...

Actor vs Agent (Relationship)

  • 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 (From Notes + Extended)

A robust actor schema should include:

  • name (namespaced, required in the YAML config file — defines the actor's registered identity; can be overridden by the CLI NAME argument at registration time)
  • provider (LLM provider or runtime target)
  • model
  • system_prompt (or prompt template)
  • skill_access_policy (which skill categories/names are allowed or denied)
  • graph_descriptor (for composite actors)
  • memory_policy (per-plan/per-actor—see memory section)
  • context_view_policy (what context this actor sees)
  • limits (token limits, tool call limits, retries)
  • cost_policy (caps, budgets)
  • metadata (use cases, version)

Actor Composition and Graphs

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

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}

Agent

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

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 <namespace>/<name> 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).

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.

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 local/run-migrations

# Update an existing tool (re-reads the config file, overwrites registration) agents tool add --config ./tools/run-migrations.yaml --update local/run-migrations

# 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]
    - <span style="color: cyan;">tool</span>: local/create-github-issue
      <span style="color: cyan; font-weight: 600;">override</span>:
        <span style="color: cyan; font-weight: 600;">capability</span>:
          <span style="color: cyan; font-weight: 600;">required_permissions</span>: [org:write] <span style="opacity: 0.7;"># Stricter permissions in this context</span>

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

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
stateDiagram-v2
    [*] --> ToolActivation: Actor references skill or tool node

    state "For Each Resource Slot" as ForEach {
        state binding_check <<choice>>
        [*] --> 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 <<choice>>
            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.

Tool Registry

CleverAgents maintains a Tool Registry — a persistent catalog of all independently registered tools:

@startuml
skinparam classAttributeIconSize 0
skinparam classFontSize 13
skinparam noteFontSize 11
skinparam defaultFontSize 12

class ToolRegistry {
  - toolIndex : Map<String, ToolRecord>
  --
  + 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<ResourceSlot>
  + 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
  - Permission enforcement
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:

@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<String>
  + required_permissions : List<String>
  + cost_profile : String
  + human_approval_required : Boolean
}

class ResourceBindings {
  + slots : Map<String, ResourceSlot>
}

class ResourceSlot {
  + type : String
  + access : String
  + required : Boolean
  + bind : String
  + from_param : String
  + description : String
}

interface Lifecycle <<interface>> {
  + discover() : ToolDescriptor
  + activate() : void
  + execute(params, ctx) : Result
  + deactivate() : void
}

class ExecutionContext {
  + sandbox : Sandbox
  + plan : Plan
  + changes : List<Change>
  + resources : Map<String, BoundResource>
}

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

Each tool source has a corresponding adapter that translates source-specific protocols into the uniform tool interface:

@startuml
skinparam classAttributeIconSize 0
skinparam classFontSize 13
skinparam defaultFontSize 12

interface "ToolInterface" as UTI <<interface>> {
  + 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 permissions
    • Creates a checkpoint if the tool is marked checkpointable

    After the MCP tool returns its content[] response, the adapter:

    • 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, findread_only: true
  • Tools whose names contain write, create, update, delete, setwrites: 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 ~50100 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: container | host
  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
  required_permissions:    # Permissions needed to invoke
    - resource:write
    - sandbox:shell
  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 Permissions

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 PermissionDeniedError.

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 permission policy:
     • Is this tool in allowed skill categories?
     • Does the plan allow writes?
     • Is human approval required?
   - If denied → return PermissionDeniedError 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."""
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">__init__</span>(self, plan: Plan, sandbox: Sandbox,
             resources: <span style="color: cyan;">dict</span>[<span style="color: cyan;">str</span>, BoundResource]):
    self.plan = plan
    self.sandbox = sandbox
    self.resources = resources    <span style="opacity: 0.7;"># slot_name → BoundResource</span>
    self.changes: <span style="color: cyan;">list</span>[Change] = []

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">record_change</span>(self, change: Change) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Record a change made by a tool.&quot;&quot;&quot;</span>
    self.changes.append(change)
    self.plan.changeset.add_change(change)

class WriteFileTool: """Example: built-in tool for writing files."""

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">execute</span>(self, path: <span style="color: cyan;">str</span>, content: <span style="color: cyan;">str</span>, ctx: ToolExecutionContext) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    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

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:

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

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 ~50100 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).

Skills

What a Skill Is

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 <namespace>/<name> 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

@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 <skill_name>.<tool_name> (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 local/run-migrations
agents tool add --config ./tools/deploy-staging.yaml local/deploy-staging

# Then register the skill (which references those tools by name) agents skill add --config ./skills/devops-toolkit.yaml local/devops-toolkit

# Update an existing skill (re-reads the config file, overwrites registration) agents skill add --config ./skills/devops-toolkit.yaml --update local/devops-toolkit

# 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.

<span style="color: cyan; font-weight: 600;">skills</span>:
  - 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, permission enforcement, 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.

@startuml
skinparam classAttributeIconSize 0
skinparam classFontSize 13
skinparam defaultFontSize 12

class SkillRegistry {
  - skillIndex : Map<String, SkillRecord>
  --
  + 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<String>
  + tool_refs : List<String>
  + anonymous_tools : List<ToolDef>
  + flattened_tools : List<ToolDescriptor>
  + overrides : Map<String, Object>
  + 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
  - Permission enforcement
  - 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

What a Session Is

A session is a user's interactive thread with CleverAgents across time.

A session should:

  • maintain conversational continuity,
  • store plan references,
  • persist memory (if enabled),
  • 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.

Therefore, CleverAgents should specify:

  • sessions have stable IDs
  • sessions can be resumed
  • session storage backend is configured explicitly
  • if session persistence is disabled, the UX should be explicit about it (no silent history loss)

Server

What a Server Is

A server is an optional mode that enables:

  • multi-user access
  • shared org namespaces (<username>/ and <orgname>/)
  • persistent plan records
  • remote plan execution
  • permissioning and governance

Single-user local mode is the default (so setup is easy), but the architecture anticipates server mode for shared skills and org-level actions.

Client-Only vs Server Mode

Mode Description Plan Execution
Client-only No server connection. All data in local database. Always local
Server mode Connected to a CleverAgents server. Namespaced items sync. Local or server

It is possible to run a client with no server at all. Server is optional.

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:

  • permission boundaries
  • prompt sanitization / safe templating
  • resource access controls
  • auditing

Permissions

Permissions exist at multiple layers:

1) Namespace-level permissions

  • Who can create/edit org entities (actions, actors, tools, skills, resources, projects)?
  • Who can run them?

2) Project-level permissions

  • Who can modify project resources?
  • Who can apply changes?

3) Plan-level permissions

  • Can this plan write?
  • Does it require approvals?
  • Can it access restricted skills?

4) Skill-level permissions

  • Some skills should require:

    • explicit user approval per call, or
    • elevated role membership.

5) Resource-level permissions

  • Who can register/modify/remove resources in a namespace?

  • Who can link a resource to a project?

  • Per-resource access control:

    • Some resources may be restricted to specific roles (e.g., production databases)
    • Read-only vs. read-write access can be enforced per resource per project (via project-level overrides)
    • Sensitive resources can require explicit approval before sandbox creation or tool binding

A simple and powerful governance model:

  • Strategize: generally safe, read-only → minimal restrictions
  • Execute: writes occur but sandboxed → moderate restrictions
  • Apply: writes are real → strict restrictions + optional mandatory review

This aligns with the four-phase model's safety rationale.

Resources

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 <namespace>/<name> 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 <type> 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 <type>. 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.
Built-in Resource Types

Built-in types are organized into three layers: git (version control structure), git-checkout (a composition that bridges git metadata with a local directory), and filesystem (physical files on disk). Virtual types link equivalent physical resources across these layers through content/identity matching. There are 24 built-in types total (15 physical + 9 virtual), of which 4 are user-addable (git-checkout, git, fs-mount, fs-directory).

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:

@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-commitgit-treegit-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 </span> --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 </span> --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):

@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

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-commitgit-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:

@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:

@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:

@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.

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 local/database
# 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:

@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.

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.

Resource Registration (CLI)

Resources are created via agents resource add <type> 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).
  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)

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:

@startuml
skinparam classAttributeIconSize 0
skinparam classFontSize 13
skinparam defaultFontSize 12

class ResourceRegistry {
  - resourceIndex : Map<String, ResourceRecord>
  - typeIndex : Map<String, ResourceTypeRecord>
  --
  + 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<String, Object>
  + capabilities : Capabilities
  + parents : List<ResourceRecord>
  + children : List<ResourceRecord>
  + content_hash : String
  + linked_projects : List<String>
  + created_at : DateTime
  + updated_at : DateTime
}

class ResourceTypeRecord {
  + name : String
  + description : String
  + source : String
  + physical_or_virtual : PhysVirt
  + user_addable : Boolean
  + cli_arguments : List<CLIArgument>
  + allowed_parent_types : List<String>
  + child_types : Map<String, ChildTypeConfig>
  + 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 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) N/A

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.

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."""
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">read</span>(self, path: <span style="color: cyan;">str</span>, sandbox: Sandbox) -&gt; Content:
    <span style="color: #66cc66;">&quot;&quot;&quot;Read content from the sandboxed resource.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">write</span>(self, path: <span style="color: cyan;">str</span>, content: Content, sandbox: Sandbox) -&gt; Change:
    <span style="color: #66cc66;">&quot;&quot;&quot;Write content and return the Change record.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">delete</span>(self, path: <span style="color: cyan;">str</span>, sandbox: Sandbox) -&gt; Change:
    <span style="color: #66cc66;">&quot;&quot;&quot;Delete resource and return the Change record.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;"><span style="color: cyan;">list</span></span>(self, pattern: <span style="color: cyan;">str</span>, sandbox: Sandbox) -&gt; <span style="color: cyan;">list</span>[<span style="color: cyan;">str</span>]:
    <span style="color: #66cc66;">&quot;&quot;&quot;List paths matching pattern.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">diff</span>(self, path: <span style="color: cyan;">str</span>, sandbox: Sandbox) -&gt; <span style="color: cyan;">str</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Generate diff between sandbox and original state.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">supports_operation</span>(self, operation: OperationType) -&gt; <span style="color: cyan;">bool</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Check if this resource supports the given operation.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">discover_children</span>(self, resource: ResourceRecord) -&gt; <span style="color: cyan;">list</span>[ResourceRecord]:
    <span style="color: #66cc66;">&quot;&quot;&quot;Auto-discover child resources (called at registration and refresh).&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">content_hash</span>(self, path: <span style="color: cyan;">str</span>, sandbox: Sandbox) -&gt; <span style="color: cyan;">str</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Compute content hash for identity tracking.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">create_sandbox</span>(self, resource: ResourceRecord) -&gt; Sandbox:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a sandbox for this resource using its type&#x27;s strategy.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">create_checkpoint</span>(self, sandbox: Sandbox) -&gt; Checkpoint:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a checkpoint within the sandbox.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">rollback_to</span>(self, sandbox: Sandbox, checkpoint: Checkpoint) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Roll back sandbox state to a checkpoint.&quot;&quot;&quot;</span>
    ...

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)

Additional handlers are provided by custom resource types when they are registered.

Resource Path Resolution

Paths in tool invocations are resolved through a resource routing system that uses tool-resource bindings to determine the target resource:

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<br/>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

Code Intelligence & Context Discovery

Overview

CleverAgents employs a sophisticated multi-layered indexing and discovery system that enables agents to efficiently navigate and understand codebases of any scale. This system goes far beyond simple text search, providing semantic understanding of code structure, dependencies, and relationships through a combination of indexed embeddings, vector search, and an RDF-based graph store.

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.

Key Design Principles:

  1. Pluggable Architecture: Every component can be extended or replaced
  2. Progressive Enhancement: System works with basic text search, enhances with advanced features
  3. Eager Indexing: Indices are built immediately when resources are added and kept continuously up-to-date
  4. Agent Awareness: Agents understand available indices through skills
  5. Real-time Synchronization: Indices update immediately as code changes

Architecture Components

1. Multi-Modal Indexing Engine

The indexing engine operates across three complementary modalities:


IndexingEngine:
  modalities:
    # Traditional text-based indexing
    text_index:
      type: "full_text_search"
      backend: "tantivy" | "elasticsearch" | "sqlite_fts"
      features:
        - Token-based search
        - Regex patterns
        - Language-aware tokenization
        - File path indexing

# Semantic understanding via embeddings vector_index: type: "embedding_search" backend: "faiss" | "qdrant" | "weaviate" | "pgvector" models: - code: "codegen-6B-multi" - docs: "instructor-xl" - cross-modal: "clip-code" features: - Function-level embeddings - Class-level embeddings - Module-level embeddings - Documentation embeddings - Cross-language similarity

# Structural understanding via graph graph_index: type: "rdf_knowledge_graph" backend: "blazegraph" | "stardog" | "apache_jena" | "neo4j" ontology: "CodeOntology" features: - AST-based relationships - Dependency graphs - Call graphs - Inheritance hierarchies - Data flow analysis

2. RDF-Based Code Knowledge Graph

The graph store represents code as a rich semantic network using RDF (Resource Description Framework) triples. This enables sophisticated queries about code structure and relationships.

Core Ontology Design:


# CodeOntology - Core vocabulary for code representation
@prefix code: <https://cleveragents.ai/ontology/code#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

# Core Classes code:Module a rdfs:Class ; rdfs:comment "A code module (file, package, namespace)" .

code:Class a rdfs:Class ; rdfs:comment "A class or similar construct" .

code:Function a rdfs:Class ; rdfs:comment "A function, method, or procedure" .

code:Variable a rdfs:Class ; rdfs:comment "A variable, constant, or field" .

code:Type a rdfs:Class ; rdfs:comment "A type definition" .

# Core Properties code:contains a rdf:Property ; rdfs:domain code:Module ; rdfs:range code:Entity ; rdfs:comment "Module contains entity" .

code:imports a rdf:Property ; rdfs:domain code:Module ; rdfs:range code:Module ; rdfs:comment "Module imports another module" .

code:extends a rdf:Property ; rdfs:domain code:Class ; rdfs:range code:Class ; rdfs:comment "Class inheritance relationship" .

code:calls a rdf:Property ; rdfs:domain code:Function ; rdfs:range code:Function ; rdfs:comment "Function calls another function" .

code:references a rdf:Property ; rdfs:domain code:Entity ; rdfs:range code:Entity ; rdfs:comment "Entity references another entity" .

code:hasParameter a rdf:Property ; rdfs:domain code:Function ; rdfs:range code:Parameter ; rdfs:comment "Function has parameter" .

code:returns a rdf:Property ; rdfs:domain code:Function ; rdfs:range code:Type ; rdfs:comment "Function return type" .

# Annotations code:hasDocstring a rdf:Property ; rdfs:domain code:Entity ; rdfs:range xsd:string .

code:hasComplexity a rdf:Property ; rdfs:domain code:Function ; rdfs:range xsd:integer ; rdfs:comment "Cyclomatic complexity" .

code:hasTestCoverage a rdf:Property ; rdfs:domain code:Entity ; rdfs:range xsd:decimal ; rdfs:comment "Test coverage percentage" .

Example Knowledge Graph Fragment:


# Concrete example: Authentication module
<file:///src/auth/auth_manager.py> a code:Module ;
    code:imports <file:///src/core/user.py> ;
    code:imports <file:///src/utils/crypto.py> ;
    code:contains <class://AuthManager> .

<class://AuthManager> a code:Class ; code:hasMethod <method://AuthManager.authenticate> ; code:hasMethod <method://AuthManager.validate_token> ; code:extends <class://BaseManager> ; code:hasDocstring "Manages user authentication and session tokens" .

<method://AuthManager.authenticate> a code:Function ; code:hasParameter <param://username> ; code:hasParameter <param://password> ; code:returns <type://AuthToken> ; code:calls <method://CryptoUtils.hash_password> ; code:calls <method://UserDB.find_user> ; code:hasComplexity 8 ; code:hasTestCoverage 0.95 .

Advanced Graph Queries:


# Find all functions that manipulate user authentication
PREFIX code: <https://cleveragents.ai/ontology/code#>
SELECT ?function ?module
WHERE {
    ?function a code:Function ;
              code:calls*/code:references ?entity .
    ?entity rdfs:label ?label .
    FILTER(CONTAINS(LCASE(?label), "auth") || CONTAINS(LCASE(?label), "user"))
    ?module code:contains ?function .
}

# Find circular dependencies SELECT ?module1 ?module2 WHERE { ?module1 code:imports+ ?module2 . ?module2 code:imports+ ?module1 . FILTER(?module1 != ?module2) }

# Find most complex untested functions SELECT ?function ?complexity WHERE { ?function a code:Function ; code:hasComplexity ?complexity ; code:hasTestCoverage ?coverage . FILTER(?complexity > 10 && ?coverage < 0.5) } ORDER BY DESC(?complexity) LIMIT 10

3. Intelligent Context Assembly Pipeline

The context assembly pipeline leverages all three indices to build optimal context for each agent:


class ContextAssemblyPipeline:
    def assemble_context(self, 
                        query: str, 
                        actor_type: str,
                        resource_scope: List[Resource],
                        max_tokens: int) -> Context:
    <span style="opacity: 0.7;"># Stage 1: Query Understanding</span>
    intent = self.analyze_query_intent(query)
    entities = self.extract_entities(query)  <span style="opacity: 0.7;"># Classes, functions, concepts</span>
    
    <span style="opacity: 0.7;"># Stage 2: Multi-Modal Search</span>
    results = SearchResults()
    
    <span style="opacity: 0.7;"># Text search for exact matches</span>
    <span style="color: magenta; font-weight: 600;">if</span> intent.needs_exact_match:
        text_results = self.text_index.search(
            query=query,
            filters={<span style="color: #66cc66;">&quot;resources&quot;</span>: resource_scope},
            limit=100
        )
        results.add(text_results)
    
    <span style="opacity: 0.7;"># Vector search for semantic similarity</span>
    <span style="color: magenta; font-weight: 600;">if</span> intent.needs_semantic_match:
        query_embedding = self.embed_query(query, actor_type)
        vector_results = self.vector_index.search(
            embedding=query_embedding,
            filters={<span style="color: #66cc66;">&quot;resources&quot;</span>: resource_scope},
            limit=50
        )
        results.add(vector_results)
    
    <span style="opacity: 0.7;"># Graph traversal for structural relationships</span>
    <span style="color: magenta; font-weight: 600;">if</span> entities:
        graph_results = self.graph_index.traverse(
            start_nodes=entities,
            patterns=self.get_patterns_for_actor(actor_type),
            max_depth=3,
            limit=50
        )
        results.add(graph_results)
    
    <span style="opacity: 0.7;"># Stage 3: Relevance Ranking</span>
    ranked_results = self.rank_by_relevance(
        results=results,
        actor_type=actor_type,
        query_intent=intent
    )
    
    <span style="opacity: 0.7;"># Stage 4: Context Optimization</span>
    context = self.optimize_context(
        ranked_results=ranked_results,
        max_tokens=max_tokens,
        strategy=self.get_strategy_for_actor(actor_type)
    )
    
    <span style="color: magenta; font-weight: 600;">return</span> context

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">get_patterns_for_actor</span>(self, actor_type: <span style="color: cyan;">str</span>) -&gt; <span style="color: cyan;">List</span>[GraphPattern]:
    <span style="color: #66cc66;">&quot;&quot;&quot;Different actors need different traversal patterns&quot;&quot;&quot;</span>
    patterns = {
        <span style="color: #66cc66;">&quot;strategist&quot;</span>: [
            <span style="color: #66cc66;">&quot;module_dependencies&quot;</span>,      <span style="opacity: 0.7;"># Understand architecture</span>
            <span style="color: #66cc66;">&quot;interface_boundaries&quot;</span>,     <span style="opacity: 0.7;"># Find API surfaces</span>
            <span style="color: #66cc66;">&quot;test_coverage_gaps&quot;</span>        <span style="opacity: 0.7;"># Identify risks</span>
        ],
        <span style="color: #66cc66;">&quot;executor&quot;</span>: [
            <span style="color: #66cc66;">&quot;implementation_details&quot;</span>,   <span style="opacity: 0.7;"># Get full function bodies</span>
            <span style="color: #66cc66;">&quot;local_dependencies&quot;</span>,       <span style="opacity: 0.7;"># Find what to change</span>
            <span style="color: #66cc66;">&quot;usage_patterns&quot;</span>           <span style="opacity: 0.7;"># Understand call sites</span>
        ],
        <span style="color: #66cc66;">&quot;reviewer&quot;</span>: [
            <span style="color: #66cc66;">&quot;change_impact_analysis&quot;</span>,   <span style="opacity: 0.7;"># What could break</span>
            <span style="color: #66cc66;">&quot;similar_patterns&quot;</span>,        <span style="opacity: 0.7;"># Consistency checks</span>
            <span style="color: #66cc66;">&quot;test_relationships&quot;</span>       <span style="opacity: 0.7;"># Verification paths</span>
        ]
    }
    <span style="color: magenta; font-weight: 600;">return</span> patterns.get(actor_type, [<span style="color: #66cc66;">&quot;general_traversal&quot;</span>])

4. Plugin Architecture for Extensibility

The system is designed for extensibility at every level:


PluginSystem:
  # Language-specific analyzers
  analyzers:
    python:
      class: "PythonAnalyzer"
      features:
        - AST parsing via ast module
        - Type inference via mypy
        - Import resolution
        - Docstring extraction
<span style="color: cyan; font-weight: 600;">typescript</span>:
  <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;TypeScriptAnalyzer&quot;</span>
  <span style="color: cyan; font-weight: 600;">features</span>:
    - TSC-based parsing
    - Type extraction
    - Module resolution
    - JSDoc parsing

<span style="color: cyan; font-weight: 600;">rust</span>:
  <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;RustAnalyzer&quot;</span>
  <span style="color: cyan; font-weight: 600;">features</span>:
    - rust-analyzer integration
    - Lifetime analysis
    - Trait resolution
    - Macro expansion

# Custom analyzer example custom_dsl: class: "CustomDSLAnalyzer" config: grammar: "path/to/grammar.peg" semantic_rules: "path/to/rules.yaml"

# Index backend providers backends: graph: - name: "blazegraph" class: "BlazegraphBackend" scalability: "billions of triples" features: ["SPARQL", "reasoning", "geospatial"]

  - <span style="color: cyan;">name</span>: <span style="color: #66cc66;">&quot;neo4j&quot;</span>
    <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;Neo4jBackend&quot;</span>
    <span style="color: cyan; font-weight: 600;">scalability</span>: <span style="color: #66cc66;">&quot;enterprise&quot;</span>
    <span style="color: cyan; font-weight: 600;">features</span>: [&quot;Cypher&quot;, &quot;APOC&quot;, &quot;GDS&quot;]
  
  - <span style="color: cyan;">name</span>: <span style="color: #66cc66;">&quot;custom_graph&quot;</span>
    <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;MyCustomGraphDB&quot;</span>
    <span style="color: cyan; font-weight: 600;">config</span>:
      <span style="color: cyan; font-weight: 600;">connection</span>: <span style="color: #66cc66;">&quot;custom://localhost:7687&quot;</span>

<span style="color: cyan; font-weight: 600;">vector</span>:
  - <span style="color: cyan;">name</span>: <span style="color: #66cc66;">&quot;faiss&quot;</span>
    <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;FaissBackend&quot;</span>
    <span style="color: cyan; font-weight: 600;">scalability</span>: <span style="color: #66cc66;">&quot;100M vectors&quot;</span>
    <span style="color: cyan; font-weight: 600;">features</span>: [&quot;GPU acceleration&quot;, &quot;HNSW&quot;]
  
  - <span style="color: cyan;">name</span>: <span style="color: #66cc66;">&quot;qdrant&quot;</span>
    <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;QdrantBackend&quot;</span>
    <span style="color: cyan; font-weight: 600;">scalability</span>: <span style="color: #66cc66;">&quot;distributed&quot;</span>
    <span style="color: cyan; font-weight: 600;">features</span>: [&quot;filtering&quot;, &quot;payloads&quot;, &quot;snapshots&quot;]

# Embedding model providers embedders: - name: "openai" class: "OpenAIEmbedder" models: ["text-embedding-3-large", "text-embedding-3-small"]

- <span style="color: cyan;">name</span>: <span style="color: #66cc66;">&quot;local&quot;</span>
  <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;LocalEmbedder&quot;</span>
  <span style="color: cyan; font-weight: 600;">models</span>: [&quot;all-MiniLM-L6-v2&quot;, &quot;instructor-xl&quot;]

- <span style="color: cyan;">name</span>: <span style="color: #66cc66;">&quot;custom&quot;</span>
  <span style="color: cyan; font-weight: 600;">class</span>: <span style="color: #66cc66;">&quot;MyFineTunedEmbedder&quot;</span>
  <span style="color: cyan; font-weight: 600;">model_path</span>: <span style="color: #66cc66;">&quot;path/to/model&quot;</span>

5. Agent Skills for Code Intelligence

Agents interact with the code intelligence system through a specialized skill (local/code-intelligence) that contains tools for semantic search, dependency analysis, and refactoring:


# Actor references the code intelligence skill
actors:
  code_explorer:
    type: llm
    config:
      actor: anthropic/claude-3-opus
    skills:
      - local/code-intelligence   # Provides search_code_semantically,
                                  # analyze_dependencies, suggest_refactoring_targets

The local/code-intelligence skill uses anonymous inline tools to wrap the code intelligence subsystem. These tools are defined inline because they are tightly coupled to the skill's specific implementation and not reused elsewhere (if any were needed in multiple contexts, they would be registered independently via agents tool add and referenced by name):


# File: skills/code-intelligence.yaml
skill:
  name: local/code-intelligence
  description: "Semantic code search, dependency analysis, and refactoring recommendations"

anonymous_tools: - name: search_code_semantically description: "Find code similar to a concept using vector search, enriched with dependency context" input_schema: type: object properties: query: { type: string } scope: { type: string, default: "all" } limit: { type: integer, default: 10 } required: [query] capability: read_only: true code: | results = ctx.code_intelligence.vector_search( query=params["query"], scope=params.get("scope", "all"), limit=params.get("limit", 10) ) for result in results: result.context = ctx.code_intelligence.get_dependencies( entity=result.entity_id, depth=2 ) return results

- <span style="color: cyan;">name</span>: analyze_dependencies
  <span style="color: cyan; font-weight: 600;">description</span>: <span style="color: #66cc66;">&quot;Analyze module dependencies using graph store&quot;</span>
  <span style="color: cyan; font-weight: 600;">input_schema</span>:
    <span style="color: cyan; font-weight: 600;">type</span>: object
    <span style="color: cyan; font-weight: 600;">properties</span>:
      <span style="color: cyan; font-weight: 600;">module_path</span>: { type: string }
    <span style="color: cyan; font-weight: 600;">required</span>: [module_path]
  <span style="color: cyan; font-weight: 600;">capability</span>:
    <span style="color: cyan; font-weight: 600;">read_only</span>: <span style="color: magenta; font-weight: 600;">true</span>
  <span style="color: cyan; font-weight: 600;">code</span>: <span style="color: #66cc66;">|</span>
    module = params[&quot;module_path&quot;]
    deps = ctx.code_intelligence.graph_query(f&#x27;&#x27;&#x27;
        PREFIX code: &lt;https://cleveragents.ai/ontology/code#&gt;
        SELECT ?dep ?type WHERE {{
            &lt;{module}&gt; code:imports* ?dep . ?dep a ?type .
        }}
    &#x27;&#x27;&#x27;)
    return {
        &quot;direct_deps&quot;: len([d for d in deps if d.distance == 1]),
        &quot;transitive_deps&quot;: len(deps),
        &quot;circular_deps&quot;: ctx.code_intelligence.find_circular_deps(module),
        &quot;dependency_graph&quot;: deps
    }

- <span style="color: cyan;">name</span>: suggest_refactoring_targets
  <span style="color: cyan; font-weight: 600;">description</span>: <span style="color: #66cc66;">&quot;Combine text, graph, and vector search to find refactoring targets&quot;</span>
  <span style="color: cyan; font-weight: 600;">input_schema</span>:
    <span style="color: cyan; font-weight: 600;">type</span>: object
    <span style="color: cyan; font-weight: 600;">properties</span>:
      <span style="color: cyan; font-weight: 600;">scope</span>: { type: string }
    <span style="color: cyan; font-weight: 600;">required</span>: [scope]
  <span style="color: cyan; font-weight: 600;">capability</span>:
    <span style="color: cyan; font-weight: 600;">read_only</span>: <span style="color: magenta; font-weight: 600;">true</span>
  <span style="color: cyan; font-weight: 600;">code</span>: <span style="color: #66cc66;">|</span>
    todos = ctx.code_intelligence.text_search(
        pattern=&quot;(TODO|FIXME|HACK):&quot;, scope=params[&quot;scope&quot;]
    )
    complex_functions = ctx.code_intelligence.graph_query(&#x27;&#x27;&#x27;
        SELECT ?func ?complexity ?coverage WHERE {
            ?func a code:Function ;
                  <span style="color: cyan; font-weight: 600;">code</span>:hasComplexity ?complexity ;
                  <span style="color: cyan; font-weight: 600;">code</span>:hasTestCoverage ?coverage .
            FILTER(?complexity &gt; 15 || ?coverage &lt; 0.3)
        } ORDER BY DESC(?complexity)
    &#x27;&#x27;&#x27;)
    smells = []
    for pattern in [&quot;duplicate code&quot;, &quot;long method&quot;, &quot;large class&quot;]:
        smells.extend(ctx.code_intelligence.find_similar_code(
            pattern=pattern, threshold=0.8
        ))
    return {
        &quot;high_priority&quot;: complex_functions[:5],
        &quot;technical_debt&quot;: todos,
        &quot;code_smells&quot;: smells,
        &quot;suggested_order&quot;: ctx.code_intelligence.rank_by_impact(
            complex_functions + todos + smells
        )
    }

6. Real-time Index Synchronization

The system maintains index freshness through immediate, proactive updates:


class IndexSynchronizer:
    def __init__(self):
        self.file_watcher = FileSystemWatcher()
        self.git_monitor = GitChangeMonitor()
        self.incremental_indexer = IncrementalIndexer()
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_resource_added</span>(self, resource: Resource, project: Project):
    <span style="color: #66cc66;">&quot;&quot;&quot;When a resource is added to a project, index it immediately&quot;&quot;&quot;</span>
    <span style="opacity: 0.7;"># Full initial indexing - happens once when resource is added</span>
    <span style="color: magenta; font-weight: 600;">with</span> self.progress_reporter(<span style="color: #66cc66;">f&quot;Indexing {resource.name}&quot;</span>) <span style="color: magenta; font-weight: 600;">as</span> progress:
        files = self.scan_resource(resource)
        total = len(files)
        
        <span style="opacity: 0.7;"># Parallel indexing for performance</span>
        <span style="color: magenta; font-weight: 600;">with</span> ThreadPoolExecutor(max_workers=cpu_count()) <span style="color: magenta; font-weight: 600;">as</span> executor:
            futures = []
            
            <span style="color: magenta; font-weight: 600;">for</span> i, file <span style="color: magenta; font-weight: 600;">in</span> enumerate(files):
                future = executor.submit(self.index_file_complete, file)
                futures.append(future)
                progress.update(i / total)
            
            <span style="opacity: 0.7;"># Wait for all indexing to complete</span>
            <span style="color: magenta; font-weight: 600;">for</span> future <span style="color: magenta; font-weight: 600;">in</span> futures:
                future.result()
    
    <span style="opacity: 0.7;"># Now set up watchers for incremental updates</span>
    self.setup_watchers(resource)
    
    <span style="opacity: 0.7;"># Mark resource as indexed and ready</span>
    resource.indexing_status = <span style="color: #66cc66;">&quot;ready&quot;</span>
    self.notify_agents_index_ready(resource)
    
    <span style="opacity: 0.7;"># CRITICAL: Agents can now immediately search this resource</span>
    <span style="opacity: 0.7;"># No &quot;warming up&quot; period - indices are complete and ready</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">index_file_complete</span>(self, file_path: <span style="color: cyan;">str</span>):
    <span style="color: #66cc66;">&quot;&quot;&quot;Comprehensive initial indexing of a file&quot;&quot;&quot;</span>
    <span style="opacity: 0.7;"># Parse file once</span>
    ast = self.parse_file(file_path)
    
    <span style="opacity: 0.7;"># Update all indices immediately</span>
    self.update_text_index(file_path, ast)
    self.update_vector_embeddings(file_path, ast)
    self.update_graph_triples(file_path, ast)
    
    <span style="opacity: 0.7;"># Extract and index all metadata</span>
    self.index_symbols(file_path, ast)
    self.index_dependencies(file_path, ast)
    self.index_complexity_metrics(file_path, ast)

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">setup_watchers</span>(self, project: Project):
    <span style="opacity: 0.7;"># File system watching for immediate updates</span>
    self.file_watcher.watch(
        path=project.root_path,
        events=[<span style="color: #66cc66;">&quot;create&quot;</span>, <span style="color: #66cc66;">&quot;modify&quot;</span>, <span style="color: #66cc66;">&quot;delete&quot;</span>],
        callback=self.on_file_change
    )
    
    <span style="opacity: 0.7;"># Git monitoring for batch updates (using linked git resource)</span>
    git_resource = project.get_linked_resource(type=<span style="color: #66cc66;">&quot;git-checkout&quot;</span>)
    self.git_monitor.watch(
        repo=git_resource,
        events=[<span style="color: #66cc66;">&quot;commit&quot;</span>, <span style="color: #66cc66;">&quot;merge&quot;</span>, <span style="color: #66cc66;">&quot;rebase&quot;</span>],
        callback=self.on_git_change
    )

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_file_change</span>(self, event: FileEvent):
    <span style="opacity: 0.7;"># Quick incremental update</span>
    <span style="color: magenta; font-weight: 600;">if</span> event.type <span style="color: magenta; font-weight: 600;">in</span> [<span style="color: #66cc66;">&quot;create&quot;</span>, <span style="color: #66cc66;">&quot;modify&quot;</span>]:
        <span style="opacity: 0.7;"># Parse changed file</span>
        ast = self.parse_file(event.path)
        
        <span style="opacity: 0.7;"># Update indices</span>
        self.update_text_index(event.path, ast)
        self.update_vector_embeddings(event.path, ast)
        self.update_graph_triples(event.path, ast)
    
    <span style="color: magenta; font-weight: 600;">elif</span> event.type == <span style="color: #66cc66;">&quot;delete&quot;</span>:
        self.remove_from_indices(event.path)

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_git_change</span>(self, event: GitEvent):
    <span style="opacity: 0.7;"># Batch update for git operations</span>
    changed_files = event.get_changed_files()
    
    <span style="opacity: 0.7;"># Optimize batch processing</span>
    <span style="color: magenta; font-weight: 600;">with</span> self.batch_updater() <span style="color: magenta; font-weight: 600;">as</span> updater:
        <span style="color: magenta; font-weight: 600;">for</span> file <span style="color: magenta; font-weight: 600;">in</span> changed_files:
            updater.queue_update(file)
        
        <span style="opacity: 0.7;"># Process in parallel</span>
        updater.execute(parallel=<span style="color: magenta; font-weight: 600;">True</span>)

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">update_graph_triples</span>(self, file_path: <span style="color: cyan;">str</span>, ast: AST):
    <span style="opacity: 0.7;"># Generate RDF triples from AST</span>
    triples = []
    
    <span style="opacity: 0.7;"># Module-level triples</span>
    module_uri = self.uri_for_file(file_path)
    <span style="color: magenta; font-weight: 600;">for</span> import_stmt <span style="color: magenta; font-weight: 600;">in</span> ast.imports:
        imported_uri = self.resolve_import(import_stmt)
        triples.append((module_uri, <span style="color: #66cc66;">&quot;code:imports&quot;</span>, imported_uri))
    
    <span style="opacity: 0.7;"># Function-level triples</span>
    <span style="color: magenta; font-weight: 600;">for</span> func <span style="color: magenta; font-weight: 600;">in</span> ast.functions:
        func_uri = self.uri_for_function(func)
        triples.append((module_uri, <span style="color: #66cc66;">&quot;code:contains&quot;</span>, func_uri))
        triples.append((func_uri, <span style="color: #66cc66;">&quot;a&quot;</span>, <span style="color: #66cc66;">&quot;code:Function&quot;</span>))
        triples.append((func_uri, <span style="color: #66cc66;">&quot;code:hasComplexity&quot;</span>, func.complexity))
        
        <span style="opacity: 0.7;"># Call relationships</span>
        <span style="color: magenta; font-weight: 600;">for</span> call <span style="color: magenta; font-weight: 600;">in</span> func.calls:
            called_uri = self.resolve_call(call)
            triples.append((func_uri, <span style="color: #66cc66;">&quot;code:calls&quot;</span>, called_uri))
    
    <span style="opacity: 0.7;"># Update graph store</span>
    self.graph_store.update_triples(triples)

When advanced features are unavailable, the system gracefully degrades:


class FallbackSearchProvider:
    def search(self, query: str, resources: List[Resource]) -> SearchResults:
        # Try advanced search first
        try:
            if self.vector_index.is_available():
                return self.vector_search(query, resources)
        except ServiceUnavailable:
            pass
    <span style="opacity: 0.7;"># Fallback to graph search</span>
    <span style="color: magenta; font-weight: 600;">try</span>:
        <span style="color: magenta; font-weight: 600;">if</span> self.graph_index.is_available():
            <span style="color: magenta; font-weight: 600;">return</span> self.graph_search(query, resources)
    <span style="color: magenta; font-weight: 600;">except</span> ServiceUnavailable:
        <span style="color: magenta; font-weight: 600;">pass</span>
    
    <span style="opacity: 0.7;"># Ultimate fallback: grep-like text search</span>
    <span style="color: magenta; font-weight: 600;">return</span> self.basic_text_search(query, resources)

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">basic_text_search</span>(self, query: <span style="color: cyan;">str</span>, resources: <span style="color: cyan;">List</span>[Resource]):
    <span style="opacity: 0.7;"># Use ripgrep or similar for fast text search</span>
    results = []
    
    <span style="color: magenta; font-weight: 600;">for</span> resource <span style="color: magenta; font-weight: 600;">in</span> resources:
        matches = ripgrep.search(
            pattern=query,
            path=resource.path,
            context_lines=3
        )
        
        <span style="color: magenta; font-weight: 600;">for</span> match <span style="color: magenta; font-weight: 600;">in</span> matches:
            results.append(SearchResult(
                file=match.file,
                line=match.line,
                content=match.content,
                score=1.0  <span style="opacity: 0.7;"># Basic scoring</span>
            ))
    
    <span style="color: magenta; font-weight: 600;">return</span> results

Index Lifecycle

The system follows a clear lifecycle for index management:


Index Lifecycle:
  1_resource_added:
    trigger: "agents resource add / agents project link-resource"
    action: "Immediate full indexing"
    duration: "Depends on size (10K files ~1 minute)"
    result: "All indices ready for instant search"

2_code_changed: trigger: "File modification detected" action: "Immediate incremental update" duration: "Milliseconds per file" result: "Indices stay synchronized"

3_resource_removed: trigger: "agents project unlink-resource / agents resource remove" action: "Immediate index cleanup" duration: "Seconds" result: "No stale data in indices"

4_maintenance: trigger: "Scheduled or manual" action: "Reindex for consistency" duration: "Background process" result: "Indices optimized and verified"

Key Guarantees:

  • "No search happens on stale data"
  • "No 'index building' delays during agent execution"
  • "Changes visible in search immediately"
  • "Initial indexing is a one-time cost per resource"

Integration with Context Tiers

The Code Intelligence system directly feeds into the three-tier context architecture:


Context Tier Integration:
  hot_tier:
    source: "Real-time results from code intelligence"
    content:
      - Currently edited files
      - Direct dependencies
      - Immediately relevant functions

warm_tier: source: "Indexed embeddings and graph queries" content: - Recent search results - Cached graph traversals - Vector similarity matches - Active decision contexts

cold_tier: source: "Historical indices and compressed data" content: - Previous plan analyses - Archived dependency graphs - Historical refactoring patterns - Learned codebase conventions

Performance Characteristics

The system maintains pre-computed indices for instant search performance:


Performance Metrics:
  initial_indexing_speed:
    text_index: "10,000 files/minute"
    vector_index: "1,000 files/minute (with GPU)"
    graph_index: "5,000 files/minute"

query_performance: text_search: "< 100ms for 1M files" vector_search: "< 200ms for 10M embeddings" graph_traversal: "< 500ms for 3-hop queries"

storage_requirements: text_index: "~10% of source size" vector_index: "~1GB per 100K functions" graph_store: "~100MB per 10K files"

scalability: max_files: "No hard limit (tested to 10M files)" max_graph_size: "1B+ triples" max_vectors: "100M+ embeddings"

Progressive Enhancement Path

Organizations can adopt Code Intelligence features progressively. At each stage, existing resources are reindexed to take advantage of new capabilities:


adoption_stages:
  stage_1_basic:
    features: ["text search", "file watching"]
    requirements: ["ripgrep", "sqlite"]
    initial_setup: "Index all text content on resource add"
    benefit: "Instant exact-match search"

stage_2_semantic: features: ["vector embeddings", "similarity search"] requirements: ["embedding model", "vector DB"] initial_setup: "Generate embeddings for all code (one-time cost)" benefit: "Instant semantic similarity search"

stage_3_structural: features: ["RDF graph", "relationship queries"] requirements: ["graph database", "language analyzers"] initial_setup: "Parse and build complete knowledge graph" benefit: "Instant relationship queries"

stage_4_intelligent: features: ["ML-driven ranking", "automated analysis"] requirements: ["GPU", "training data"] initial_setup: "Pre-compute ML features and rankings" benefit: "Instant intelligent suggestions"

stage_5_custom: features: ["Domain-specific ontologies", "Custom analyzers"] requirements: ["Domain expertise", "Custom development"] initial_setup: "Build domain-specific indices" benefit: "Instant domain-aware intelligence"

This Code Intelligence & Context Discovery system ensures that CleverAgents can efficiently work with codebases of any size, providing agents with the contextual understanding they need to make intelligent decisions about code changes, refactoring, and feature development.

Summary of Timing:

  • Indexing: Eager (happens immediately when resources are added/changed)
  • Searching: Instant (because indices are pre-computed and ready)
  • Sandboxing: Lazy (only when execution needs to modify a resource)
  • Context Assembly: Real-time (but fast because it queries ready indices)

This design ensures agents never wait for index building during execution, providing a responsive and predictable experience even on massive codebases.

Context

Note: This section describes the high-level context management system. For details on how context is discovered and indexed, see the Code Intelligence & Context Discovery section above.

Context in CleverAgents is not "dump all files into an LLM." It is a system that:

  • finds relevant information from resources,
  • injects appropriate subsets into each actor/node,
  • and scales to large repositories.

Current Reality and Planned Improvements

key concepts:

  • There is a global context concept,
  • But nodes only see what is injected into their prompts,
  • It's functional but not yet elegant,
  • A more advanced automated system is planned.

Tiered Context Architecture (Hot/Warm/Cold)

The system uses a sophisticated three-tier memory architecture that enables working with massive codebases without holding everything in memory:

  • Hot context (hot cache) The small set of immediately relevant chunks injected into the current actor prompt. When working on a 50,000 file codebase, hot context focuses on the immediate task (e.g., 10-20 files for a specific refactoring).

  • Warm context Recent decisions and their contexts from this plan tree - quickly accessible. Includes indexed embeddings, vector search results, and graph store representations. Maintains the decision chain that led to the current work.

  • Cold storage Historical decisions from past plans on this codebase - queryable but not in active memory. Long-term storage in SQLite or caching systems containing prior summaries, older plan artifacts, and historical patterns (e.g., "last time we refactored auth, we also had to update these services").

Promotion/demotion behavior:

  • System analyzes current query
  • Promotes relevant data upward (cold → warm → hot)
  • Demotes stale data out of hot to keep prompts tight
  • Preserves complete context snapshots for every decision

This architecture leverages the key insight that software development is inherently local - even in huge codebases, individual changes typically touch a bounded set of files. The Decision Tree captures these localities.

Actor-Specific Context Views

A key missing feature identified in the notes is per-actor context views, filtering, relevance, and actor-aware context limits.

The intended direction:

  • global context exists at plan level,
  • each actor gets a "view" of that context tuned to their role,
  • memory may be shared or per-plan depending on design choices.
Actor Context View Service (Proposed)

A dedicated module/service that:

  • maintains actor-specific "context views,"
  • tracks actor memory and relevance,
  • enforces actor-specific limits (tokens, file types, etc.).

Initial Context vs Deep Context

A practical approach mentioned:

  • Initial context is high-level (repo tree, language, overview),
  • Then the system searches for relevant details iteratively via RAG.

This strongly suggests CleverAgents should define:

  • an "initial context recipe" per project type (codebase vs documents vs infra),
  • iterative context refinement loops during strategize/execute.

Output Rendering Framework

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:


Command Logic ──► OutputSession ──► ElementHandles ──► MaterializationStrategy ──► Terminal/Pipe
                  (lifecycle)       (typed producers)   (format-driven policy)      (stdout/stderr)
  1. Command Logic opens an OutputSession and creates typed element handlesPanelHandle, 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
    """
<span style="opacity: 0.7;"># --- Session lifecycle ---</span>

command: <span style="color: cyan;">str</span>                                  <span style="opacity: 0.7;"># The command that owns this session</span>
session_id: <span style="color: cyan;">str</span>                               <span style="opacity: 0.7;"># Unique session identifier (ULID)</span>
created_at: <span style="color: cyan;">datetime</span>                          <span style="opacity: 0.7;"># Session creation timestamp</span>

_strategy: MaterializationStrategy            <span style="opacity: 0.7;"># The active materialization strategy</span>
_handles: <span style="color: cyan;">OrderedDict</span>[<span style="color: cyan;">str</span>, ElementHandle]     <span style="opacity: 0.7;"># handle_id → handle, in declaration order</span>
_event_queue: asyncio.Queue[ElementEvent]     <span style="opacity: 0.7;"># Internal event queue for serialization</span>
_state: SessionState                          <span style="opacity: 0.7;"># &quot;open&quot; | &quot;closing&quot; | &quot;closed&quot;</span>
_lock: threading.Lock                         <span style="opacity: 0.7;"># Protects handle creation/removal</span>

<span style="color: yellow;">@classmethod</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">open</span>(cls, command: <span style="color: cyan;">str</span>, strategy: MaterializationStrategy,
         metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;OutputSession&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Open a new output session.</span>

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. """ ...

<span style="opacity: 0.7;"># --- Element handle factories ---</span>
<span style="opacity: 0.7;"># Each factory creates a typed handle, registers it with the session in</span>
<span style="opacity: 0.7;"># declaration order, and emits an ElementCreated event to the strategy.</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">panel</span>(self, title: <span style="color: cyan;">str</span>, *,
          border_style: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;rounded&quot;</span>,
          priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
          collapse_hint: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;auto&quot;</span>,
          metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;PanelHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a panel element handle for key-value pair output.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">table</span>(self, title: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span>, *,
          columns: <span style="color: cyan;">list</span>[<span style="color: #66cc66;">&quot;ColumnDef&quot;</span>],
          summary: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
          max_rows_hint: <span style="color: cyan;">int</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
          sort_key: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
          priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
          collapse_hint: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;auto&quot;</span>,
          metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;TableHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a table element handle for tabular data.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">tree</span>(self, root_label: <span style="color: cyan;">str</span>, *,
         root_style: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
         max_depth_hint: <span style="color: cyan;">int</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
         show_guides: <span style="color: cyan;">bool</span> = <span style="color: magenta; font-weight: 600;">True</span>,
         priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
         collapse_hint: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;auto&quot;</span>,
         metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;TreeHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a tree element handle for hierarchical data.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">progress</span>(self, label: <span style="color: cyan;">str</span>, *,
             total: <span style="color: cyan;">int</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
             indeterminate: <span style="color: cyan;">bool</span> = <span style="color: magenta; font-weight: 600;">False</span>,
             steps: <span style="color: cyan;">list</span>[<span style="color: cyan;">str</span>] | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
             priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
             metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;ProgressHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a progress indicator handle.</span>

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"). """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">status</span>(self, message: <span style="color: cyan;">str</span>, *,
           level: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;info&quot;</span>,
           detail: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
           priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
           metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;StatusHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a status message handle.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">text</span>(self, content: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;&quot;</span>, *,
         wrap: <span style="color: cyan;">bool</span> = <span style="color: magenta; font-weight: 600;">True</span>,
         indent: <span style="color: cyan;">int</span> = 0,
         priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
         metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;TextHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a text block handle.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">code</span>(self, content: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;&quot;</span>, *,
         language: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
         line_numbers: <span style="color: cyan;">bool</span> = <span style="color: magenta; font-weight: 600;">False</span>,
         highlight_lines: <span style="color: cyan;">list</span>[<span style="color: cyan;">int</span>] | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
         priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
         metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;CodeHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a code block handle.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">diff</span>(self, *,
         file_a: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
         file_b: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
         priority: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;normal&quot;</span>,
         metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;DiffHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a diff block handle.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">separator</span>(self, style: <span style="color: cyan;">str</span> = <span style="color: #66cc66;">&quot;line&quot;</span>) -&gt; <span style="color: #66cc66;">&quot;SeparatorHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create a visual separator. Separators are auto-closed on creation.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">action_hint</span>(self, commands: <span style="color: cyan;">list</span>[<span style="color: cyan;">str</span>],
                description: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: #66cc66;">&quot;ActionHintHandle&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Create an action hint. Action hints are auto-closed on creation.&quot;&quot;&quot;</span>
    ...

<span style="opacity: 0.7;"># --- Session operations ---</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">snapshot</span>(self) -&gt; <span style="color: #66cc66;">&quot;StructuredOutput&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Return a static snapshot of all elements accumulated so far.</span>

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. """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">close</span>(self, *, exit_code: <span style="color: cyan;">int</span> = 0) -&gt; <span style="color: #66cc66;">&quot;StructuredOutput&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Close the session and finalize all output.</span>

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. """ ...

<span style="opacity: 0.7;"># --- Context manager support ---</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">__enter__</span>(self) -&gt; <span style="color: #66cc66;">&quot;OutputSession&quot;</span>:
    <span style="color: magenta; font-weight: 600;">return</span> self

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">__exit__</span>(self, exc_type, exc_val, exc_tb) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Auto-close session on context exit.</span>

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: <span style="color: cyan;">str</span>                       <span style="opacity: 0.7;"># Unique handle identifier (ULID)</span>
element_type: <span style="color: cyan;">str</span>                    <span style="opacity: 0.7;"># Semantic type (&quot;panel&quot;, &quot;table&quot;, etc.)</span>
declaration_index: <span style="color: cyan;">int</span>               <span style="opacity: 0.7;"># Position in session&#x27;s declaration order</span>

_session: OutputSession              <span style="opacity: 0.7;"># Owning session (for event emission)</span>
_element: E                          <span style="opacity: 0.7;"># The accumulated element state</span>
_state: HandleState                  <span style="opacity: 0.7;"># &quot;open&quot; | &quot;closed&quot;</span>
_lock: threading.Lock                <span style="opacity: 0.7;"># Serializes writes to this handle</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">close</span>(self) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Close this handle, signaling that no more data will be written.</span>

Emits an ElementClosed event to the materialization strategy. For buffered strategies, this triggers rendering of the element. """ ...

<span style="color: yellow;">@property</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">is_open</span>(self) -&gt; <span style="color: cyan;">bool</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Whether this handle is still accepting writes.&quot;&quot;&quot;</span>
    ...

<span style="color: yellow;">@property</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">element</span>(self) -&gt; E:
    <span style="color: #66cc66;">&quot;&quot;&quot;The accumulated element state (read-only snapshot).&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">__enter__</span>(self) -&gt; <span style="color: cyan;">Self</span>:
    <span style="color: magenta; font-weight: 600;">return</span> self

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">__exit__</span>(self, exc_type, exc_val, exc_tb) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Auto-close handle on context exit.&quot;&quot;&quot;</span>
    <span style="color: magenta; font-weight: 600;">if</span> 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. """

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_entry</span>(self, key: <span style="color: cyan;">str</span>, value: <span style="color: cyan;">str</span>, *,
              style_hint: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
              icon: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set or update a key-value entry in the panel.</span>

If an entry with the given key already exists, it is updated. Otherwise, a new entry is appended. Emits an ElementUpdated event. """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_entries</span>(self, entries: <span style="color: cyan;">dict</span>[<span style="color: cyan;">str</span>, <span style="color: cyan;">str</span>], *,
                style_hints: <span style="color: cyan;">dict</span>[<span style="color: cyan;">str</span>, <span style="color: cyan;">str</span>] | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set multiple entries at once (batch update). Emits a single event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">remove_entry</span>(self, key: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Remove an entry by key. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

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. """

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">add_row</span>(self, row: <span style="color: cyan;">dict</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Append a single row to the table.</span>

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). """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">add_rows</span>(self, rows: <span style="color: cyan;">list</span>[<span style="color: cyan;">dict</span>]) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Append multiple rows in a batch. Emits a single ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_summary</span>(self, summary: <span style="color: cyan;">dict</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set or update the summary/aggregation row. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_sort_key</span>(self, column: <span style="color: cyan;">str</span>, *, descending: <span style="color: cyan;">bool</span> = <span style="color: magenta; font-weight: 600;">False</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Change the sort key. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

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. """

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">add_child</span>(self, parent_path: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span>, label: <span style="color: cyan;">str</span>, *,
              style_hint: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>,
              collapsed: <span style="color: cyan;">bool</span> = <span style="color: magenta; font-weight: 600;">False</span>,
              metadata: <span style="color: cyan;">dict</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: cyan;">str</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Add a child node to the tree.</span>

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. """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_node_style</span>(self, path: <span style="color: cyan;">str</span>, style_hint: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Update the style of an existing node. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

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). """

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_progress</span>(self, current: <span style="color: cyan;">int</span>, total: <span style="color: cyan;">int</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Update the progress counter.</span>

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). """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_step_status</span>(self, step_label: <span style="color: cyan;">str</span>, status: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Update the status of a named step.</span>

Args: step_label: The label of the step to update. status: New status — "pending" | "active" | "done" | "error" | "skipped". Emits an ElementUpdated event. """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_label</span>(self, label: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Update the progress label text. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">increment</span>(self, delta: <span style="color: cyan;">int</span> = 1) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Increment progress by delta. Convenience wrapper around set_progress.&quot;&quot;&quot;</span>
    ...

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"). """

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_message</span>(self, message: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Update the status message text. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_level</span>(self, level: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Change the status level. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_detail</span>(self, detail: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set or clear the detail text. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

class TextHandle(ElementHandle[TextBlock]): """Handle for a text block. Supports appending text incrementally."""

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">append</span>(self, text: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Append text to the block. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_content</span>(self, content: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Replace the entire content. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

class CodeHandle(ElementHandle[CodeBlock]): """Handle for a code block."""

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_content</span>(self, content: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set the code content. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_language</span>(self, language: <span style="color: cyan;">str</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set the language for syntax highlighting. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_highlight_lines</span>(self, lines: <span style="color: cyan;">list</span>[<span style="color: cyan;">int</span>]) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set lines to highlight. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

class DiffHandle(ElementHandle[DiffBlock]): """Handle for a diff block. Hunks can be added incrementally."""

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">add_hunk</span>(self, header: <span style="color: cyan;">str</span>, lines: <span style="color: cyan;">list</span>[<span style="color: #66cc66;">&quot;DiffLine&quot;</span>]) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Add a diff hunk. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">set_stats</span>(self, insertions: <span style="color: cyan;">int</span>, deletions: <span style="color: cyan;">int</span>, **extra: <span style="color: cyan;">int</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Set diff statistics. Emits an ElementUpdated event.&quot;&quot;&quot;</span>
    ...

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: <span style="color: cyan;">str</span>                   <span style="opacity: 0.7;"># &quot;live&quot; | &quot;sequential_buffer&quot; | &quot;accumulate&quot;</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">bind</span>(self, renderer: <span style="color: #66cc66;">&quot;ElementRenderer&quot;</span>,
         terminal_caps: <span style="color: #66cc66;">&quot;TerminalCapabilities&quot;</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Bind this strategy to a renderer and terminal capabilities.</span>

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. """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_session_begin</span>(self, session: OutputSession, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Called when the session opens. The strategy receives the output</span>

stream and may write preamble (e.g., opening JSON bracket).""" ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_element_created</span>(self, event: ElementCreated) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Called when a new element handle is created.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_element_updated</span>(self, event: ElementUpdated) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Called when data is written to an element handle.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_element_closed</span>(self, event: ElementClosed) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Called when an element handle is closed.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">on_session_end</span>(self, event: SessionEnd) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Called when the session closes. The strategy may write epilogue.&quot;&quot;&quot;</span>
    ...

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: <span style="color: cyan;">float</span> = 15.0            <span style="opacity: 0.7;"># Maximum redraws per second</span>
_element_regions: <span style="color: cyan;">OrderedDict</span>[<span style="color: cyan;">str</span>, ScreenRegion]  <span style="opacity: 0.7;"># handle_id → screen region</span>
_dirty_set: <span style="color: cyan;">set</span>[<span style="color: cyan;">str</span>]                 <span style="opacity: 0.7;"># handle_ids that need redraw</span>
_frame_timer: asyncio.TimerHandle    <span style="opacity: 0.7;"># Coalescing timer for frame redraws</span>

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: <span style="color: cyan;">int</span> = 0          <span style="opacity: 0.7;"># The declaration index to render next</span>
_rendered_buffers: <span style="color: cyan;">dict</span>[<span style="color: cyan;">int</span>, <span style="color: cyan;">str</span>]     <span style="opacity: 0.7;"># index → pre-rendered content (waiting)</span>
_closed_set: <span style="color: cyan;">set</span>[<span style="color: cyan;">int</span>]                <span style="opacity: 0.7;"># Declaration indices of closed elements</span>

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: <span style="color: cyan;">str</span>                     <span style="opacity: 0.7;"># &quot;plain&quot;, &quot;color&quot;, &quot;table&quot;, &quot;rich&quot;, &quot;json&quot;, &quot;yaml&quot;</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_panel</span>(self, panel: Panel, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a panel element to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_table</span>(self, table: Table, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a table element to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_tree</span>(self, tree: Tree, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a tree element to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_status</span>(self, status: StatusMessage, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a status message to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_progress</span>(self, progress: ProgressIndicator, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a progress indicator to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_code</span>(self, code: CodeBlock, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a code block to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_diff</span>(self, diff: DiffBlock, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a diff block to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_text</span>(self, text: TextBlock, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a text block to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_separator</span>(self, separator: Separator, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render a visual separator to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_action_hint</span>(self, hint: ActionHint, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Render an action hint to the stream.&quot;&quot;&quot;</span>
    ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_element</span>(self, element: OutputElement, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Dispatch to the appropriate render method based on element type.</span>

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)

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">serialize</span>(self, output: StructuredOutput, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Serialize a complete StructuredOutput to the stream.</span>

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. """ ...

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">can_render</span>(self, terminal_caps: <span style="color: #66cc66;">&quot;TerminalCapabilities&quot;</span>) -&gt; <span style="color: cyan;">bool</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Whether this renderer can operate in the given terminal environment.&quot;&quot;&quot;</span>
    ...

Format Resolution

The active format is resolved using a precedence chain:

  1. CLI flag: --format <value> on the command line (highest priority).
  2. Environment variable: CLEVERAGENTS_FORMAT=<value>.
  3. Config file: The core.format key in the global config (agents config set core.format <value>).
  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) val_01HXM5A pytest --cov=src --cov-fail-under=80 required val_01HXM5B ruff check . required val_01HXM5C 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

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) val_01HXM5A pytest --cov=src --cov-fail-under=80 required val_01HXM5B ruff check . required val_01HXM5C 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) ───────────────────────────────────────────╮ │ val_01HXM5A pytest --cov=src --cov-fail-under=80 required │ │ val_01HXM5B ruff check . required │ │ val_01HXM5C 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

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 <span style="color: cyan;">--json-compact</span> (future option).
  • Consistent schema per command: Each command's JSON schema is stable and documented, enabling reliable programmatic parsing.

Example (agents <span style="color: cyan;">--format</span> 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": [
      {
        "id": "val_01HXM5A",
        "command": "pytest --cov=src --cov-fail-under=80",
        "mode": "required",
        "timeout": 600,
        "resource": "repo"
      },
      {
        "id": "val_01HXM5B",
        "command": "ruff check .",
        "mode": "required",
        "timeout": 300,
        "resource": null
      },
      {
        "id": "val_01HXM5C",
        "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:
    - id: val_01HXM5A
      command: "pytest --cov=src --cov-fail-under=80"
      mode: required
      timeout: 600
      resource: repo
    - id: val_01HXM5B
      command: "ruff check ."
      mode: required
      timeout: 300
      resource: null
    - id: val_01HXM5C
      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: <span style="color: cyan;">dict</span>[<span style="color: cyan;">str</span>, FormatRegistration] = {}

<span style="color: yellow;">@classmethod</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">register</span>(cls, format_name: <span style="color: cyan;">str</span>,
             strategy_factory: <span style="color: cyan;">Callable</span>[[TerminalCapabilities], MaterializationStrategy],
             renderer_factory: <span style="color: cyan;">Callable</span>[[TerminalCapabilities], ElementRenderer],
             fallback: <span style="color: cyan;">str</span> | <span style="color: magenta; font-weight: 600;">None</span> = <span style="color: magenta; font-weight: 600;">None</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Register a format.</span>

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, )

<span style="color: yellow;">@classmethod</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">resolve</span>(cls, format_name: <span style="color: cyan;">str</span>,
            terminal_caps: TerminalCapabilities
            ) -&gt; <span style="color: cyan;">tuple</span>[MaterializationStrategy, ElementRenderer]:
    <span style="color: #66cc66;">&quot;&quot;&quot;Resolve the best (strategy, renderer) pair for the given format.</span>

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()

    <span style="color: magenta; font-weight: 600;">while</span> current <span style="color: magenta; font-weight: 600;">and</span> current <span style="color: magenta; font-weight: 600;">not</span> <span style="color: magenta; font-weight: 600;">in</span> visited:
        visited.add(current)
        registration = cls._formats.get(current)
        <span style="color: magenta; font-weight: 600;">if</span> registration <span style="color: magenta; font-weight: 600;">is</span> <span style="color: magenta; font-weight: 600;">None</span>:
            <span style="color: magenta; font-weight: 600;">break</span>
        
        renderer = registration.renderer_factory(terminal_caps)
        <span style="color: magenta; font-weight: 600;">if</span> renderer.can_render(terminal_caps):
            strategy = registration.strategy_factory(terminal_caps)
            strategy.bind(renderer, terminal_caps=terminal_caps)
            <span style="color: magenta; font-weight: 600;">return</span> strategy, renderer
        
        current = registration.fallback
    
    <span style="opacity: 0.7;"># Ultimate fallback is always plain</span>
    plain = cls._formats[<span style="color: #66cc66;">&quot;plain&quot;</span>]
    renderer = plain.renderer_factory(terminal_caps)
    strategy = plain.strategy_factory(terminal_caps)
    strategy.bind(renderer, terminal_caps=terminal_caps)
    <span style="color: magenta; font-weight: 600;">return</span> strategy, renderer

<span style="color: yellow;">@classmethod</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">available_formats</span>(cls) -&gt; <span style="color: cyan;">list</span>[<span style="color: cyan;">str</span>]:
    <span style="color: #66cc66;">&quot;&quot;&quot;Return all registered format names.&quot;&quot;&quot;</span>
    <span style="color: magenta; font-weight: 600;">return</span> sorted(cls._formats.keys())

<span style="color: yellow;">@classmethod</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">is_registered</span>(cls, format_name: <span style="color: cyan;">str</span>) -&gt; <span style="color: cyan;">bool</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Check if a format is registered.&quot;&quot;&quot;</span>
    <span style="color: magenta; font-weight: 600;">return</span> format_name <span style="color: magenta; font-weight: 600;">in</span> 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")
<span style="color: yellow;">@classmethod</span>
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">detect</span>(cls) -&gt; <span style="color: #66cc66;">&quot;TerminalCapabilities&quot;</span>:
    <span style="color: #66cc66;">&quot;&quot;&quot;Auto-detect terminal capabilities from the environment.</span>

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"

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">render_table</span>(self, table: Table, stream: <span style="color: cyan;">IO</span>) -&gt; <span style="color: magenta; font-weight: 600;">None</span>:
    writer = csv.writer(stream)
    writer.writerow([col.name <span style="color: magenta; font-weight: 600;">for</span> col <span style="color: magenta; font-weight: 600;">in</span> table.columns])
    <span style="color: magenta; font-weight: 600;">for</span> row <span style="color: magenta; font-weight: 600;">in</span> table.rows:
        writer.writerow([row.get(col.name, <span style="color: #66cc66;">&quot;&quot;</span>) <span style="color: magenta; font-weight: 600;">for</span> col <span style="color: magenta; font-weight: 600;">in</span> table.columns])

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">can_render</span>(self, terminal_caps: TerminalCapabilities) -&gt; <span style="color: cyan;">bool</span>:
    <span style="color: magenta; font-weight: 600;">return</span> <span style="color: magenta; font-weight: 600;">True</span>  <span style="opacity: 0.7;"># CSV works everywhere</span>

# 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"),
    ])
<span style="color: magenta; font-weight: 600;">try</span>:
    <span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">for</span> resource <span style="color: magenta; font-weight: 600;">in</span> client.list_resources():
        table.add_row({
            <span style="color: #66cc66;">&quot;Name&quot;</span>: resource.name,
            <span style="color: #66cc66;">&quot;Type&quot;</span>: resource.type,
            <span style="color: #66cc66;">&quot;Status&quot;</span>: resource.status,
        })
<span style="color: magenta; font-weight: 600;">except</span> ApiError <span style="color: magenta; font-weight: 600;">as</span> e:
    table.close()  <span style="opacity: 0.7;"># Close with partial data</span>
    session.status(<span style="color: #66cc66;">f&quot;Error fetching resources: {e}&quot;</span>, level=<span style="color: #66cc66;">&quot;error&quot;</span>)
    <span style="color: magenta; font-weight: 600;">return</span>

table.close()
session.status(<span style="color: #66cc66;">f&quot;{table.element.row_count} resources listed&quot;</span>, level=<span style="color: #66cc66;">&quot;ok&quot;</span>)

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)
<span style="opacity: 0.7;"># --- Build output elements ---</span>

<span style="opacity: 0.7;"># Panel: Project details</span>
<span style="color: magenta; font-weight: 600;">with</span> session.panel(<span style="color: #66cc66;">&quot;Project Details&quot;</span>) <span style="color: magenta; font-weight: 600;">as</span> panel:
    panel.set_entries({
        <span style="color: #66cc66;">&quot;Name&quot;</span>: project.name,
        <span style="color: #66cc66;">&quot;Description&quot;</span>: project.description,
        <span style="color: #66cc66;">&quot;Resources&quot;</span>: <span style="color: cyan;">str</span>(len(resources)),
        <span style="color: #66cc66;">&quot;Remote&quot;</span>: <span style="color: #66cc66;">&quot;yes&quot;</span> <span style="color: magenta; font-weight: 600;">if</span> project.remote <span style="color: magenta; font-weight: 600;">else</span> <span style="color: #66cc66;">&quot;no&quot;</span>,
        <span style="color: #66cc66;">&quot;Created&quot;</span>: project.created_at.strftime(<span style="color: #66cc66;">&quot;%Y-%m-%d %H:%M&quot;</span>),
    }, style_hints={
        <span style="color: #66cc66;">&quot;Name&quot;</span>: <span style="color: #66cc66;">&quot;identifier&quot;</span>,
        <span style="color: #66cc66;">&quot;Resources&quot;</span>: <span style="color: #66cc66;">&quot;number&quot;</span>,
        <span style="color: #66cc66;">&quot;Remote&quot;</span>: <span style="color: #66cc66;">&quot;success&quot;</span> <span style="color: magenta; font-weight: 600;">if</span> <span style="color: magenta; font-weight: 600;">not</span> project.remote <span style="color: magenta; font-weight: 600;">else</span> <span style="color: #66cc66;">&quot;info&quot;</span>,
        <span style="color: #66cc66;">&quot;Created&quot;</span>: <span style="color: #66cc66;">&quot;success&quot;</span>,
    })

<span style="opacity: 0.7;"># Table: Linked resources</span>
<span style="color: magenta; font-weight: 600;">with</span> session.table(<span style="color: #66cc66;">&quot;Linked Resources&quot;</span>, columns=[
    ColumnDef(name=<span style="color: #66cc66;">&quot;Resource&quot;</span>, type=<span style="color: #66cc66;">&quot;string&quot;</span>, style_hint=<span style="color: #66cc66;">&quot;identifier&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Type&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Sandbox&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Read-Only&quot;</span>),
]) <span style="color: magenta; font-weight: 600;">as</span> table:
    <span style="color: magenta; font-weight: 600;">for</span> r <span style="color: magenta; font-weight: 600;">in</span> resources:
        table.add_row({
            <span style="color: #66cc66;">&quot;Resource&quot;</span>: r.name,
            <span style="color: #66cc66;">&quot;Type&quot;</span>: r.type,
            <span style="color: #66cc66;">&quot;Sandbox&quot;</span>: r.sandbox_strategy,
            <span style="color: #66cc66;">&quot;Read-Only&quot;</span>: <span style="color: #66cc66;">&quot;yes&quot;</span> <span style="color: magenta; font-weight: 600;">if</span> r.read_only <span style="color: magenta; font-weight: 600;">else</span> <span style="color: #66cc66;">&quot;no&quot;</span>,
        })

<span style="opacity: 0.7;"># Table: Validations</span>
<span style="color: magenta; font-weight: 600;">with</span> session.table(<span style="color: #66cc66;">f&quot;Validations ({len(validations)})&quot;</span>, columns=[
    ColumnDef(name=<span style="color: #66cc66;">&quot;ID&quot;</span>, type=<span style="color: #66cc66;">&quot;id&quot;</span>, style_hint=<span style="color: #66cc66;">&quot;identifier&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Command&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Mode&quot;</span>),
]) <span style="color: magenta; font-weight: 600;">as</span> table:
    <span style="color: magenta; font-weight: 600;">for</span> v <span style="color: magenta; font-weight: 600;">in</span> validations:
        table.add_row({
            <span style="color: #66cc66;">&quot;ID&quot;</span>: v.id,
            <span style="color: #66cc66;">&quot;Command&quot;</span>: v.command,
            <span style="color: #66cc66;">&quot;Mode&quot;</span>: v.mode,
        })

<span style="opacity: 0.7;"># Status: Final message</span>
session.status(<span style="color: #66cc66;">&quot;Project loaded&quot;</span>, level=<span style="color: #66cc66;">&quot;ok&quot;</span>)

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) ID Command Mode


val_01HXM5A pytest --cov=src --cov-fail-under=80 required val_01HXM5B ruff check . required val_01HXM5C 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) ───────────────────────────────────────────────────╮ │ ID Command Mode │ │ ─────────── ───────────────────────────────────── ─────────── │ │ val_01HXM5A pytest --cov=src --cov-fail-under=80 required │ │ val_01HXM5B ruff check . required │ │ val_01HXM5C 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": [
      {
        "ID": "val_01HXM5A",
        "Command": "pytest --cov=src --cov-fail-under=80",
        "Mode": "required"
      },
      {
        "ID": "val_01HXM5B",
        "Command": "ruff check .",
        "Mode": "required"
      },
      {
        "ID": "val_01HXM5C",
        "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'."""
<span style="opacity: 0.7;"># Create the table handle — it will accumulate rows as we stream them</span>
table = session.table(<span style="color: #66cc66;">&quot;Resources&quot;</span>, columns=[
    ColumnDef(name=<span style="color: #66cc66;">&quot;Name&quot;</span>, type=<span style="color: #66cc66;">&quot;string&quot;</span>, style_hint=<span style="color: #66cc66;">&quot;identifier&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Type&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Project&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Sandbox&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Status&quot;</span>),
], sort_key=<span style="color: #66cc66;">&quot;Name&quot;</span>)

<span style="opacity: 0.7;"># Create a progress indicator for the fetch operation</span>
progress = session.progress(<span style="color: #66cc66;">&quot;Fetching resources...&quot;</span>, indeterminate=<span style="color: magenta; font-weight: 600;">True</span>)

<span style="opacity: 0.7;"># Stream pages from the API</span>
count = 0
<span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">for</span> page <span style="color: magenta; font-weight: 600;">in</span> api.list_resources_paginated(project=project):
    <span style="color: magenta; font-weight: 600;">for</span> resource <span style="color: magenta; font-weight: 600;">in</span> page.items:
        table.add_row({
            <span style="color: #66cc66;">&quot;Name&quot;</span>: resource.name,
            <span style="color: #66cc66;">&quot;Type&quot;</span>: resource.type,
            <span style="color: #66cc66;">&quot;Project&quot;</span>: resource.project,
            <span style="color: #66cc66;">&quot;Sandbox&quot;</span>: resource.sandbox_strategy,
            <span style="color: #66cc66;">&quot;Status&quot;</span>: resource.status,
        })
        count += 1
    
    <span style="opacity: 0.7;"># Update progress label with count so far</span>
    progress.set_label(<span style="color: #66cc66;">f&quot;Fetching resources... ({count} found)&quot;</span>)

<span style="opacity: 0.7;"># Close the progress indicator (it has served its purpose)</span>
progress.close()

<span style="opacity: 0.7;"># Set summary and close the table</span>
table.set_summary({<span style="color: #66cc66;">&quot;total&quot;</span>: count})
table.close()

<span style="opacity: 0.7;"># Final status</span>
session.status(<span style="color: #66cc66;">f&quot;{count} resources listed&quot;</span>, level=<span style="color: #66cc66;">&quot;ok&quot;</span>)

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)
<span style="opacity: 0.7;"># Panel: Plan metadata (created and closed synchronously)</span>
<span style="color: magenta; font-weight: 600;">with</span> session.panel(<span style="color: #66cc66;">&quot;Plan&quot;</span>) <span style="color: magenta; font-weight: 600;">as</span> panel:
    panel.set_entries({
        <span style="color: #66cc66;">&quot;Plan ID&quot;</span>: plan.id,
        <span style="color: #66cc66;">&quot;Phase&quot;</span>: plan.phase,
        <span style="color: #66cc66;">&quot;State&quot;</span>: plan.state,
        <span style="color: #66cc66;">&quot;Action&quot;</span>: plan.action,
        <span style="color: #66cc66;">&quot;Project&quot;</span>: plan.project,
        <span style="color: #66cc66;">&quot;Started&quot;</span>: plan.started_at.strftime(<span style="color: #66cc66;">&quot;%H:%M:%S&quot;</span>),
    }, style_hints={
        <span style="color: #66cc66;">&quot;Plan ID&quot;</span>: <span style="color: #66cc66;">&quot;identifier&quot;</span>,
        <span style="color: #66cc66;">&quot;Phase&quot;</span>: <span style="color: #66cc66;">&quot;info&quot;</span>,
        <span style="color: #66cc66;">&quot;State&quot;</span>: <span style="color: #66cc66;">&quot;warning&quot;</span> <span style="color: magenta; font-weight: 600;">if</span> plan.state == <span style="color: #66cc66;">&quot;processing&quot;</span> <span style="color: magenta; font-weight: 600;">else</span> <span style="color: #66cc66;">&quot;success&quot;</span>,
    })

<span style="opacity: 0.7;"># Create both table handles BEFORE starting concurrent producers.</span>
<span style="opacity: 0.7;"># Declaration order determines rendering order in sequential formats.</span>
resource_table = session.table(<span style="color: #66cc66;">&quot;Resource Status&quot;</span>, columns=[
    ColumnDef(name=<span style="color: #66cc66;">&quot;Resource&quot;</span>, style_hint=<span style="color: #66cc66;">&quot;identifier&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Type&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Status&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Latency&quot;</span>, type=<span style="color: #66cc66;">&quot;string&quot;</span>, alignment=<span style="color: #66cc66;">&quot;right&quot;</span>),
])

tool_table = session.table(<span style="color: #66cc66;">&quot;Tool Call Log&quot;</span>, columns=[
    ColumnDef(name=<span style="color: #66cc66;">&quot;#&quot;</span>, type=<span style="color: #66cc66;">&quot;number&quot;</span>, alignment=<span style="color: #66cc66;">&quot;right&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Tool&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Target&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Result&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Duration&quot;</span>, type=<span style="color: #66cc66;">&quot;string&quot;</span>, alignment=<span style="color: #66cc66;">&quot;right&quot;</span>),
])

<span style="opacity: 0.7;"># --- Run two producers concurrently ---</span>
<span style="opacity: 0.7;"># Each producer writes to its own handle. Neither producer knows</span>
<span style="opacity: 0.7;"># which format is active. The materialization strategy handles</span>
<span style="opacity: 0.7;"># the coordination.</span>

<span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">stream_resources</span>():
    <span style="color: #66cc66;">&quot;&quot;&quot;Producer A: streams resource status checks.&quot;&quot;&quot;</span>
    <span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">for</span> status <span style="color: magenta; font-weight: 600;">in</span> api.stream_resource_statuses(plan.id):
        resource_table.add_row({
            <span style="color: #66cc66;">&quot;Resource&quot;</span>: status.resource_name,
            <span style="color: #66cc66;">&quot;Type&quot;</span>: status.resource_type,
            <span style="color: #66cc66;">&quot;Status&quot;</span>: status.status,
            <span style="color: #66cc66;">&quot;Latency&quot;</span>: <span style="color: #66cc66;">f&quot;{status.latency_ms}ms&quot;</span>,
        })
    resource_table.close()

<span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">stream_tool_calls</span>():
    <span style="color: #66cc66;">&quot;&quot;&quot;Producer B: streams tool call results.&quot;&quot;&quot;</span>
    <span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">for</span> call <span style="color: magenta; font-weight: 600;">in</span> api.stream_tool_calls(plan.id):
        tool_table.add_row({
            <span style="color: #66cc66;">&quot;#&quot;</span>: call.sequence_number,
            <span style="color: #66cc66;">&quot;Tool&quot;</span>: call.tool_name,
            <span style="color: #66cc66;">&quot;Target&quot;</span>: call.target,
            <span style="color: #66cc66;">&quot;Result&quot;</span>: call.result_summary,
            <span style="color: #66cc66;">&quot;Duration&quot;</span>: <span style="color: #66cc66;">f&quot;{call.duration_ms}ms&quot;</span>,
        })
    tool_table.close()

<span style="opacity: 0.7;"># Launch both producers concurrently</span>
<span style="color: magenta; font-weight: 600;">await</span> asyncio.gather(stream_resources(), stream_tool_calls())

<span style="opacity: 0.7;"># Final status</span>
session.status(<span style="color: #66cc66;">f&quot;Plan {plan_id} status retrieved&quot;</span>, level=<span style="color: #66cc66;">&quot;ok&quot;</span>)

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)
<span style="opacity: 0.7;"># Panel: Execution metadata</span>
<span style="color: magenta; font-weight: 600;">with</span> session.panel(<span style="color: #66cc66;">&quot;Execution&quot;</span>) <span style="color: magenta; font-weight: 600;">as</span> panel:
    panel.set_entries({
        <span style="color: #66cc66;">&quot;Plan&quot;</span>: plan.id,
        <span style="color: #66cc66;">&quot;Phase&quot;</span>: <span style="color: #66cc66;">&quot;execute&quot;</span>,
        <span style="color: #66cc66;">&quot;Sandbox&quot;</span>: plan.sandbox_strategy,
        <span style="color: #66cc66;">&quot;Worker&quot;</span>: plan.worker,
        <span style="color: #66cc66;">&quot;Started&quot;</span>: <span style="color: cyan;">datetime</span>.now().strftime(<span style="color: #66cc66;">&quot;%H:%M:%S&quot;</span>),
    })

<span style="opacity: 0.7;"># Progress indicator with named steps</span>
progress = session.progress(<span style="color: #66cc66;">&quot;Executing plan&quot;</span>, total=4, steps=[
    <span style="color: #66cc66;">&quot;Collect context&quot;</span>,
    <span style="color: #66cc66;">&quot;Run tools&quot;</span>,
    <span style="color: #66cc66;">&quot;Build changeset&quot;</span>,
    <span style="color: #66cc66;">&quot;Validate&quot;</span>,
])

<span style="opacity: 0.7;"># Step 1: Collect context</span>
progress.set_step_status(<span style="color: #66cc66;">&quot;Collect context&quot;</span>, <span style="color: #66cc66;">&quot;active&quot;</span>)
context = <span style="color: magenta; font-weight: 600;">await</span> api.collect_context(plan.id)
progress.set_step_status(<span style="color: #66cc66;">&quot;Collect context&quot;</span>, <span style="color: #66cc66;">&quot;done&quot;</span>)
progress.set_progress(1, 4)

<span style="opacity: 0.7;"># Step 2: Run tools (parallel sub-operations)</span>
progress.set_step_status(<span style="color: #66cc66;">&quot;Run tools&quot;</span>, <span style="color: #66cc66;">&quot;active&quot;</span>)
tool_results = <span style="color: magenta; font-weight: 600;">await</span> api.run_tools(plan.id, context)
progress.set_step_status(<span style="color: #66cc66;">&quot;Run tools&quot;</span>, <span style="color: #66cc66;">&quot;done&quot;</span>)
progress.set_progress(2, 4)

<span style="opacity: 0.7;"># Step 3: Build changeset</span>
progress.set_step_status(<span style="color: #66cc66;">&quot;Build changeset&quot;</span>, <span style="color: #66cc66;">&quot;active&quot;</span>)
changeset = <span style="color: magenta; font-weight: 600;">await</span> api.build_changeset(plan.id, tool_results)
progress.set_step_status(<span style="color: #66cc66;">&quot;Build changeset&quot;</span>, <span style="color: #66cc66;">&quot;done&quot;</span>)
progress.set_progress(3, 4)

<span style="opacity: 0.7;"># Step 4: Validate</span>
progress.set_step_status(<span style="color: #66cc66;">&quot;Validate&quot;</span>, <span style="color: #66cc66;">&quot;active&quot;</span>)
validation = <span style="color: magenta; font-weight: 600;">await</span> api.validate_changeset(plan.id, changeset)
progress.set_step_status(<span style="color: #66cc66;">&quot;Validate&quot;</span>, <span style="color: #66cc66;">&quot;done&quot;</span>)
progress.set_progress(4, 4)

progress.close()

<span style="opacity: 0.7;"># Summary panel</span>
<span style="color: magenta; font-weight: 600;">with</span> session.panel(<span style="color: #66cc66;">&quot;Strategy Summary&quot;</span>) <span style="color: magenta; font-weight: 600;">as</span> panel:
    panel.set_entries({
        <span style="color: #66cc66;">&quot;Decisions&quot;</span>: <span style="color: cyan;">str</span>(changeset.decision_count),
        <span style="color: #66cc66;">&quot;Invariants&quot;</span>: <span style="color: cyan;">str</span>(changeset.invariant_count),
        <span style="color: #66cc66;">&quot;Planned Child Plans&quot;</span>: <span style="color: #66cc66;">f&quot;{changeset.child_plan_count}+&quot;</span>,
        <span style="color: #66cc66;">&quot;Estimated Files&quot;</span>: <span style="color: #66cc66;">f&quot;~{changeset.file_count}&quot;</span>,
        <span style="color: #66cc66;">&quot;Risk&quot;</span>: changeset.risk_level,
    })

<span style="opacity: 0.7;"># Final status</span>
<span style="color: magenta; font-weight: 600;">if</span> validation.passed:
    session.status(<span style="color: #66cc66;">&quot;Execution complete — all validations passed&quot;</span>, level=<span style="color: #66cc66;">&quot;ok&quot;</span>)
<span style="color: magenta; font-weight: 600;">else</span>:
    session.status(
        <span style="color: #66cc66;">f&quot;Execution complete — {validation.failure_count} validation(s) failed&quot;</span>,
        level=<span style="color: #66cc66;">&quot;warn&quot;</span>,
        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)
<span style="opacity: 0.7;"># Create a table that will be populated concurrently</span>
results_table = session.table(<span style="color: #66cc66;">&quot;Verification Results&quot;</span>, columns=[
    ColumnDef(name=<span style="color: #66cc66;">&quot;Resource&quot;</span>, style_hint=<span style="color: #66cc66;">&quot;identifier&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Type&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Check&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Status&quot;</span>),
    ColumnDef(name=<span style="color: #66cc66;">&quot;Detail&quot;</span>),
])

<span style="opacity: 0.7;"># Progress indicator</span>
progress = session.progress(
    <span style="color: #66cc66;">&quot;Verifying resources&quot;</span>,
    total=len(resources),
    steps=[r.name <span style="color: magenta; font-weight: 600;">for</span> r <span style="color: magenta; font-weight: 600;">in</span> resources],
)

<span style="opacity: 0.7;"># Verify each resource concurrently</span>
<span style="color: magenta; font-weight: 600;">async</span> <span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">verify_one</span>(resource):
    progress.set_step_status(resource.name, <span style="color: #66cc66;">&quot;active&quot;</span>)
    <span style="color: magenta; font-weight: 600;">try</span>:
        result = <span style="color: magenta; font-weight: 600;">await</span> api.verify_resource(resource.id)
        results_table.add_row({
            <span style="color: #66cc66;">&quot;Resource&quot;</span>: resource.name,
            <span style="color: #66cc66;">&quot;Type&quot;</span>: resource.type,
            <span style="color: #66cc66;">&quot;Check&quot;</span>: result.check_name,
            <span style="color: #66cc66;">&quot;Status&quot;</span>: <span style="color: #66cc66;">&quot;pass&quot;</span> <span style="color: magenta; font-weight: 600;">if</span> result.passed <span style="color: magenta; font-weight: 600;">else</span> <span style="color: #66cc66;">&quot;fail&quot;</span>,
            <span style="color: #66cc66;">&quot;Detail&quot;</span>: result.detail,
        })
        progress.set_step_status(
            resource.name,
            <span style="color: #66cc66;">&quot;done&quot;</span> <span style="color: magenta; font-weight: 600;">if</span> result.passed <span style="color: magenta; font-weight: 600;">else</span> <span style="color: #66cc66;">&quot;error&quot;</span>,
        )
    <span style="color: magenta; font-weight: 600;">except</span> ApiError <span style="color: magenta; font-weight: 600;">as</span> e:
        results_table.add_row({
            <span style="color: #66cc66;">&quot;Resource&quot;</span>: resource.name,
            <span style="color: #66cc66;">&quot;Type&quot;</span>: resource.type,
            <span style="color: #66cc66;">&quot;Check&quot;</span>: <span style="color: #66cc66;">&quot;connection&quot;</span>,
            <span style="color: #66cc66;">&quot;Status&quot;</span>: <span style="color: #66cc66;">&quot;error&quot;</span>,
            <span style="color: #66cc66;">&quot;Detail&quot;</span>: <span style="color: cyan;">str</span>(e),
        })
        progress.set_step_status(resource.name, <span style="color: #66cc66;">&quot;error&quot;</span>)
    progress.increment()

<span style="opacity: 0.7;"># Launch all verifications concurrently</span>
<span style="color: magenta; font-weight: 600;">await</span> asyncio.gather(
    *[verify_one(r) <span style="color: magenta; font-weight: 600;">for</span> r <span style="color: magenta; font-weight: 600;">in</span> resources],
    return_exceptions=<span style="color: magenta; font-weight: 600;">True</span>,  <span style="opacity: 0.7;"># Don&#x27;t fail fast — collect all results</span>
)

progress.close()
results_table.close()

<span style="opacity: 0.7;"># Summarize</span>
snapshot = results_table.element
pass_count = sum(1 <span style="color: magenta; font-weight: 600;">for</span> r <span style="color: magenta; font-weight: 600;">in</span> snapshot.rows <span style="color: magenta; font-weight: 600;">if</span> r[<span style="color: #66cc66;">&quot;Status&quot;</span>] == <span style="color: #66cc66;">&quot;pass&quot;</span>)
fail_count = sum(1 <span style="color: magenta; font-weight: 600;">for</span> r <span style="color: magenta; font-weight: 600;">in</span> snapshot.rows <span style="color: magenta; font-weight: 600;">if</span> r[<span style="color: #66cc66;">&quot;Status&quot;</span>] <span style="color: magenta; font-weight: 600;">in</span> (<span style="color: #66cc66;">&quot;fail&quot;</span>, <span style="color: #66cc66;">&quot;error&quot;</span>))

<span style="color: magenta; font-weight: 600;">if</span> fail_count == 0:
    session.status(<span style="color: #66cc66;">f&quot;All {pass_count} resources verified&quot;</span>, level=<span style="color: #66cc66;">&quot;ok&quot;</span>)
<span style="color: magenta; font-weight: 600;">else</span>:
    session.status(
        <span style="color: #66cc66;">f&quot;{fail_count} of {pass_count + fail_count} resources failed verification&quot;</span>,
        level=<span style="color: #66cc66;">&quot;error&quot;</span>,
    )

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

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 <namespace>/<name> 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.

The three safety flags (require_sandbox, require_checkpoints, allow_unsafe_tools) remain boolean since they are binary constraints rather than confidence-dependent behaviors.

Flag Type Description Behavior
auto_strategize float (0.01.0) Automatically enter Strategize after plan use When confidence >= threshold, Strategize begins immediately. Below threshold, system pauses; user must run agents plan execute to start Strategize.
auto_execute float (0.01.0) Automatically proceed from Strategize to Execute When confidence >= threshold, Execute begins when Strategize completes. Below threshold, system pauses for user review.
auto_apply float (0.01.0) Automatically proceed from Execute to Apply When confidence >= threshold, Apply begins when Execute completes. Below threshold, system pauses for user diff review.
auto_decisions_strategize float (0.01.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.
auto_decisions_execute float (0.01.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.
auto_validation_fix float (0.01.0) Automatically attempt to fix validation failures When confidence >= threshold, execution actor self-fixes failing validations. Below threshold, system pauses for user guidance.
auto_strategy_revision float (0.01.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.
auto_child_plans float (0.01.0) Automatically spawn and execute child plans When confidence >= threshold, child plans are created and executed without pausing. Below threshold, each spawn requires approval.
auto_retry_transient float (0.01.0) Automatically retry on transient failures (network, timeout, rate-limit) When confidence >= threshold, system retries with backoff. Below threshold, system pauses and asks user.
auto_checkpoint_restore float (0.01.0) Automatically restore from checkpoint on failure When confidence >= threshold, system rolls back and retries. Below threshold, user decides whether to restore.
require_sandbox boolean Require sandbox isolation for Execute phase When true, Execute must run in a sandbox. When false, sandbox is optional.
require_checkpoints boolean Require checkpointing during Execute When true, tools must create checkpoints before writes. When false, checkpointing is optional.
allow_unsafe_tools boolean Allow execution of tools marked as unsafe When true, unsafe tools can be invoked. When false, unsafe tools are blocked.

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
auto_strategize 1.0 0.0 0.0 0.7 0.0 0.0 0.0 0.0
auto_execute 1.0 0.0 1.0 0.7 0.0 0.0 0.0 0.0
auto_apply 1.0 1.0 1.0 1.0 1.0 1.0 0.0 0.0
auto_decisions_strategize 1.0 1.0 0.0 0.6 0.0 0.0 0.0 0.0
auto_decisions_execute 1.0 1.0 1.0 0.8 0.0 0.0 0.0 0.0
auto_validation_fix 1.0 1.0 1.0 0.7 0.0 0.0 0.0 0.0
auto_strategy_revision 1.0 1.0 1.0 0.8 1.0 0.0 0.0 0.0
auto_child_plans 1.0 0.0 1.0 0.7 0.0 0.0 0.0 0.0
auto_retry_transient 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
auto_checkpoint_restore 1.0 1.0 1.0 0.6 1.0 0.0 0.0 0.0
require_sandbox true true true true true true true false
require_checkpoints true true true true true true true false
allow_unsafe_tools false false false false false false false true

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), but all decisions within those phases require human approval (thresholds set to 1.0). Apply is manual. Transient retries and child plan spawning are automatic. 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.60.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 and child plan spawning proceed automatically. 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 <PROFILE> --project <PROJECT>
  4. Global-level: Set via agents config set core.automation-profile <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.01.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) auto_strategize: 0.0 auto_execute: 0.0 auto_apply: 1.0 auto_decisions_strategize: 0.0 auto_decisions_execute: 0.0 auto_validation_fix: 0.0 auto_strategy_revision: 1.0 auto_child_plans: 0.0 auto_retry_transient: 0.0 auto_checkpoint_restore: 0.0

# Safety flags (boolean) require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

A profile with intermediate thresholds provides nuanced control. For example, auto_decisions_execute: 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"

auto_strategize: 0.0 # Always auto-strategize auto_execute: 0.5 # Auto-execute when confidence >= 0.5 auto_apply: 1.0 # Always require manual apply auto_decisions_strategize: 0.3 # Low bar for strategy decisions auto_decisions_execute: 0.7 # Higher bar for execution decisions auto_validation_fix: 0.5 # Auto-fix when reasonably confident auto_strategy_revision: 0.8 # High confidence needed for auto-revision auto_child_plans: 0.5 # Auto-spawn when moderately confident auto_retry_transient: 0.0 # Always auto-retry transient errors auto_checkpoint_restore: 0.6 # Auto-restore when fairly confident

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.01.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)  <span style="opacity: 0.7;"># Returns 0.01.0</span>
    threshold = profile.get_threshold(decision.flag)  <span style="opacity: 0.7;"># e.g., auto_decisions_execute</span>
    
    <span style="color: magenta; font-weight: 600;">if</span> confidence &gt;= threshold:
        <span style="opacity: 0.7;"># Confidence meets or exceeds the profile threshold — proceed</span>
        <span style="color: magenta; font-weight: 600;">return</span> ProceedAutonomously(decision, confidence)
    <span style="color: magenta; font-weight: 600;">else</span>:
        <span style="opacity: 0.7;"># Confidence below threshold — escalate to human</span>
        <span style="color: magenta; font-weight: 600;">return</span> RequestHumanGuidance(decision, confidence, threshold, factors)

How thresholds and confidence interact: A profile with auto_decisions_execute: 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
  2. Move to review to let phases run automatically while staying in the decision loop
  3. Adopt supervised as confidence in the planning phase builds
  4. Try cautious for confidence-gated automation that escalates only when uncertain
  5. Adopt trusted for routine development tasks
  6. Enable auto for well-understood projects with strong invariant coverage
  7. Use ci for headless CI/CD pipelines with safety nets intact
  8. Use full-auto for low-risk batch operations where external safety mechanisms exist

Validation and Guardrails

Plan generation validation

The validation logic is stubbed and must be implemented. The spec should require:

  • validate action schema
  • validate actor availability
  • validate required skills exist
  • validate permission policy
  • validate rollback feasibility (if enabled)
  • validate project resource accessibility

This prevents "plan runs with fake providers" and other surprises.

Cost / rate limits

Future concerns:

  • API call limits
  • cost caps

So CleverAgents should define:

  • per-plan budgets
  • per-session budgets
  • per-org budgets
  • per-actor max tool calls / max retries

Correcting Plans (Core Feature)

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

  1. Revert-from-history correction (--mode=revert)
  • Find the decision point in the tree
  • Roll back all changes (code and non-code) to that point
  • Re-run from that decision point forward
  • Keep old execution artifacts for comparison
  • Potentially expensive if high up in the tree
  1. Add-at-end correction (--mode=append)
  • Leave history intact
  • Append a new plan at the end that fixes the outcome
  • Cheaper and safer sometimes
  • Does not rewrite history

Correction Flow (Revert Mode)

When user requests correction at Decision B:

  1. Mark for Correction

    
    Decision B.superseded_by = new_decision_id
    
  2. Identify Downstream Impact

    • Recursively collect all decisions that depend on Decision B (including invariant_enforced, subplan_spawn, and subplan_parallel_spawn decisions)
    • Collect all child plans spawned from those decisions
    • These form the "affected subtree"
  3. Rollback Resources

    • For each affected decision's artifacts_produced:
      • Rollback to the checkpoint before that artifact was created
    • For affected child plans:
      • Rollback their sandboxes entirely
  4. Preserve for Comparison

    • Archive the original subtree's artifacts
    • Create a CorrectionAttempt record linking old and new
  5. Re-execute from Decision Point

    • Restore context to Decision B.context_snapshot
    • User provides new guidance/correction
    • Re-run execution from that point
    • New decisions get is_correction: true, corrects_decision_id: B
  6. Apply as Normal

    • The corrected plan goes through normal Apply gating
    • Diff shows changes from the correction

History Cleanup

History can only be flagged for cleanup after a plan is Applied.

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

CLI Commands for Correction


# View decision tree
agents plan tree <plan_id>
agents --format=json plan tree <plan_id>  # For visualization tools

# 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

Corrections always:

  • Create a new attempt revision (increment plan.attempt)
  • Preserve old artifacts for diff/compare
  • Run execute in sandbox again
  • Require apply gating again
  • Never modify already-applied changes

This keeps history reproducible and prevents accidental destructive edits.

Human-in-the-Loop Collaboration

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).

So CleverAgents should aim for:

  • visibility: what is it doing now?
  • interruptibility: pause/cancel/retry
  • editability: allow user to modify strategy before execute
  • reconciliation: detect if user changed sandbox files mid-run and handle it

UI / Interaction Model

CLI-first + TUI + Web App + IDE

The system intends to be CLI-first, with:

  • a TUI built using Textual,
  • which can generate a web app "for free,"
  • and later an IDE plugin that embeds the TUI in the IDE.

This implies a "single UI codebase" model:

  • same underlying view logic,
  • multiple frontends.

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.

Configuration

This section provides a complete reference for the YAML configuration files used to define the major configurable objects in CleverAgents: Actors, Skills, Tools, Actions, Resource Types, Context Views, and Automation Profiles. Projects are created via CLI commands rather than standalone configuration files, but their context views are configured through YAML and are documented here as well. It also documents the global configuration keys that control system-wide behavior.

Global Configuration Keys

Global configuration keys control system-wide defaults and behavior. They are stored in the global configuration file (default: ~/.cleveragents/config.toml) and managed via the agents config set, agents config get, and agents config list commands.

Hierarchical Key Structure

Configuration keys use dot-separated hierarchical names, similar to git config. Each dot introduces a level of nesting, grouping related keys under a common parent. For example:


core.format              # top-level "core" group, "format" key
core.log.level           # "core" group, "log" subgroup, "level" key
index.text.backend       # "index" group, "text" subgroup, "backend" key

The key plan.concurrency is not the same as a top-level key concurrency — the dot path is the full identity of the key. This means you can have plan.concurrency and session.concurrency as distinct keys without conflict.

On the CLI, the full dot path is always used:


$ agents config set core.format table
$ agents config get plan.budget.per-plan
$ agents config list plan.*

The agents config list command accepts an optional glob pattern to filter keys by subtree. For example, agents config list index.* lists all keys under the index group, and agents config list provider.* lists all provider credential keys.

In the TOML configuration file, the hierarchy maps directly to TOML's native table structure. The dot-path key index.text.backend can be expressed equivalently as:


# Inline dot notation (convenient for single keys)
index.text.backend = "tantivy"

# Or as nested TOML tables (better for groups) [index.text] backend = "tantivy"

[index.vector] backend = "faiss"

Both forms are valid and can be mixed. The TOML parser normalizes them to the same internal representation.

Every key follows a resolution chain: CLI flag > environment variable > project-scoped config > global config file > built-in default.

Key Reference

Keys are organized by their top-level group. Within each group, the full dot-path, type, default, corresponding environment variable, and description are provided.

core.* — Core System Settings
Key Type Default Env Variable Description
core.data-dir string ~/.cleveragents CLEVERAGENTS_DATA_DIR Root directory for all CleverAgents persistent state: database, logs, cache, sessions, checkpoints, and backups. All other paths are derived relative to this directory unless individually overridden. Overridden per-invocation by the --data-dir CLI flag.
core.config-path string <core.data-dir>/config.toml CLEVERAGENTS_CONFIG_PATH Path to the global configuration file itself. Typically only set via environment variable or CLI flag to bootstrap an alternate configuration. Overridden per-invocation by the --config-path CLI flag.
core.format string rich CLEVERAGENTS_FORMAT Default output rendering format for all CLI commands. Accepted values: rich, color, table, plain, json, yaml. Overridden per-invocation by the --format CLI flag.
core.namespace string local CLEVERAGENTS_NAMESPACE The default namespace prefix applied when creating entities without an explicit namespace. For local-only usage, this is local. In server mode, typically the user's username or organization name.
core.automation-profile string supervised CLEVERAGENTS_AUTOMATION_PROFILE The default automation profile applied to new plans when no profile is specified at the plan, action, or project level. Accepts any built-in profile name (manual, review, supervised, cautious, trusted, auto, ci, full-auto) or a custom profile name in <namespace>/<name> format. Project-scopable.
core.log.level string INFO CLEVERAGENTS_LOG_LEVEL Global logging verbosity. Accepted values: DEBUG, INFO, WARNING, ERROR. Controls log output written to the log directory. The -v CLI flag can be repeated (-v, -vv, -vvv, -vvvv) to increase verbosity incrementally for a single invocation.
core.log.dir string <core.data-dir>/logs CLEVERAGENTS_LOG_DIR Directory where log files are written.
core.log.retention-days integer 30 CLEVERAGENTS_LOG_RETENTION_DAYS Number of days to retain log files before automatic cleanup.
core.backup.dir string <core.data-dir>/backups CLEVERAGENTS_BACKUP_DIR Directory where backup snapshots are stored.
core.backup.retention-days integer 7 CLEVERAGENTS_BACKUP_RETENTION_DAYS Number of days to retain backup snapshots created during project deletion, agents init resets, and plan correction history cleanup. Backups older than this are automatically purged.
core.cache.dir string <core.data-dir>/cache CLEVERAGENTS_CACHE_DIR Directory for transient caches (downloaded models, tool artifacts, temporary files).
server.* — Server Mode
Key Type Default Env Variable Description
server.url string (not set) CLEVERAGENTS_SERVER_URL URL of the CleverAgents server for multi-user collaborative mode. When set, the CLI operates in server mode, syncing namespaced entities (actors, actions, skills, projects) with the remote server. When unset, the CLI operates in local-only mode.
server.token string (not set) CLEVERAGENTS_SERVER_TOKEN Authentication token for server mode. Required when server.url is set. Obtained via server registration or team invite flow. Prefer the environment variable for CI environments.
server.sync.auto boolean true CLEVERAGENTS_SERVER_SYNC_AUTO Whether to automatically sync entity definitions (actors, actions, skills) with the server on startup and after registration changes. When false, sync must be triggered manually.
server.sync.interval integer 300 CLEVERAGENTS_SERVER_SYNC_INTERVAL Interval in seconds between automatic background syncs with the server. Only applies when server.sync.auto is true.
actor.* — Actor Defaults
Key Type Default Env Variable Description
actor.default.strategy string (not set) CLEVERAGENTS_DEFAULT_STRATEGY_ACTOR Default strategy actor used for plans when not specified on the action or plan use invocation. Must reference a registered actor in <namespace>/<name> format. When unset, the action's strategy_actor field is required.
actor.default.execution string (not set) CLEVERAGENTS_DEFAULT_EXECUTION_ACTOR Default execution actor used for plans when not specified on the action or plan use invocation. Must reference a registered actor. When unset, the action's execution_actor field is required.
actor.default.estimation string (not set) CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR Default estimation actor used for cost and effort estimation. Estimation is optional; when unset, plans skip the estimation step.
actor.default.invariant string (not set) CLEVERAGENTS_DEFAULT_INVARIANT_ACTOR Default Invariant Reconciliation Actor used globally. When a plan enters Strategize and neither the plan, action, nor project specifies an invariant actor, this actor reconciles invariant conflicts across scopes. Must reference a registered actor.
actor.default.orchestrator string (not set) CLEVERAGENTS_DEFAULT_ORCHESTRATOR Default orchestrator actor for new sessions created without an explicit --actor flag.
plan.* — Plan Execution
Key Type Default Env Variable Description
plan.concurrency integer 4 CLEVERAGENTS_PLAN_CONCURRENCY Maximum number of plans that can execute concurrently. When this limit is reached, new plan execute commands queue until a slot opens. Child plans count toward the parent's concurrency allocation, not toward the global limit. Project-scopable.
plan.max-child-depth integer 5 CLEVERAGENTS_PLAN_MAX_CHILD_DEPTH Maximum nesting depth for child plan spawning. Prevents runaway recursive plan decomposition. A value of 1 means no child plans; 5 means up to 5 levels of parent-child nesting. Project-scopable.
plan.budget.per-plan float (not set) CLEVERAGENTS_PLAN_BUDGET Maximum estimated API cost (in USD) allowed per plan. When the running cost estimate exceeds this budget, the plan pauses and requests human approval to continue. When unset, no per-plan cost limit is enforced. Project-scopable.
plan.budget.per-session float (not set) CLEVERAGENTS_SESSION_BUDGET Maximum estimated API cost (in USD) allowed per session. When cumulative session cost exceeds this budget, all plan operations in the session pause. When unset, no per-session cost limit is enforced.
plan.budget.warn-threshold float 0.8 CLEVERAGENTS_PLAN_BUDGET_WARN Fraction of the per-plan budget at which a warning is emitted. For example, 0.8 means a warning fires at 80% of the budget. Only effective when plan.budget.per-plan is set.
plan.tool.max-calls-per-step integer 25 CLEVERAGENTS_TOOL_MAX_CALLS Maximum number of tool invocations allowed in a single actor step (one LLM turn). Prevents runaway tool loops. When the limit is reached, the actor step is interrupted and the plan pauses for human review.
plan.tool.max-retries integer 3 CLEVERAGENTS_TOOL_MAX_RETRIES Maximum number of retry attempts for a single failing tool invocation before escalating. Applies to transient errors (network timeouts, rate limits). Non-transient errors fail immediately.
plan.tool.retry-backoff string exponential CLEVERAGENTS_TOOL_RETRY_BACKOFF Retry backoff strategy for transient tool failures. Accepted values: exponential (doubling delay starting at 1s), linear (fixed 2s delay), none (immediate retry).
sandbox.* — Sandbox and Checkpointing
Key Type Default Env Variable Description
sandbox.strategy string git_worktree CLEVERAGENTS_SANDBOX_STRATEGY Default sandbox isolation strategy for the Execute phase. Accepted values: git_worktree (create a git worktree for isolation), filesystem_copy (copy the project directory), transaction_rollback (for database resources), none (no isolation — requires require_sandbox: false in the automation profile). Per-resource-type strategies override this default. Project-scopable.
sandbox.cleanup string on_apply CLEVERAGENTS_SANDBOX_CLEANUP When to clean up sandbox working directories. Accepted values: on_apply (clean up after successful apply), on_terminal (clean up when plan reaches any terminal state — applied, cancelled, or failed), manual (never auto-clean; user must delete).
sandbox.checkpoint.enabled boolean true CLEVERAGENTS_CHECKPOINT_ENABLED Whether checkpointing is enabled globally. When true, the Execute phase creates checkpoints before write operations, enabling rollback. When false, checkpointing is skipped (requires require_checkpoints: false in the automation profile). Project-scopable.
sandbox.checkpoint.dir string <core.data-dir>/checkpoints CLEVERAGENTS_CHECKPOINT_DIR Directory where plan execution checkpoints are stored. Each plan gets a subdirectory named by its ULID.
sandbox.checkpoint.max-per-plan integer 50 CLEVERAGENTS_CHECKPOINT_MAX Maximum number of checkpoints retained per plan. When exceeded, the oldest checkpoints are pruned (keeping the first and most recent).
index.* — Code Intelligence and Indexing
Key Type Default Env Variable Description
index.text.backend string tantivy CLEVERAGENTS_INDEX_TEXT_BACKEND Backend for full-text search indexing of project resources. Accepted values: tantivy (recommended, high-performance Rust-based engine), sqlite_fts (built-in SQLite FTS5, no additional dependencies).
index.text.dir string <core.data-dir>/index/text CLEVERAGENTS_INDEX_TEXT_DIR Directory where the full-text search index is stored.
index.vector.backend string faiss CLEVERAGENTS_INDEX_VECTOR_BACKEND Backend for vector similarity search (semantic code search). Accepted values: faiss (Facebook AI Similarity Search, CPU or GPU), qdrant (requires a running Qdrant server), none (disable vector search).
index.vector.dir string <core.data-dir>/index/vector CLEVERAGENTS_INDEX_VECTOR_DIR Directory where the vector index is stored (for local backends).
index.vector.qdrant-url string (not set) CLEVERAGENTS_QDRANT_URL URL of the Qdrant server. Required when index.vector.backend is qdrant.
index.graph.backend string none CLEVERAGENTS_INDEX_GRAPH_BACKEND Backend for the knowledge graph store (structural code relationships, RDF triples). Accepted values: neo4j (requires a running Neo4j server), rdflib (in-process Python RDF library), none (disable graph queries).
index.graph.neo4j-url string (not set) CLEVERAGENTS_NEO4J_URL URL of the Neo4j server. Required when index.graph.backend is neo4j.
index.graph.neo4j-auth string (not set) CLEVERAGENTS_NEO4J_AUTH Authentication for Neo4j in user:password format. Required when index.graph.backend is neo4j.
index.embedding.provider string openai CLEVERAGENTS_EMBEDDING_PROVIDER Provider used for generating vector embeddings. Accepted values: openai, anthropic, local (uses a local sentence-transformers model). When local, no API key is required for embedding generation.
index.embedding.model string text-embedding-3-small CLEVERAGENTS_EMBEDDING_MODEL Model identifier used for generating vector embeddings when indexing project resources. Must be a valid model for the configured index.embedding.provider.
index.embedding.dimensions integer (provider default) CLEVERAGENTS_EMBEDDING_DIMENSIONS Number of dimensions for generated embeddings. When unset, the provider's default dimensionality for the chosen model is used. Can be reduced for faster search at the cost of accuracy.
index.auto-reindex boolean true CLEVERAGENTS_AUTO_REINDEX Whether to automatically re-index project resources when files change on disk. When true, indexes are updated on resource add and before each Strategize phase. When false, re-indexing must be triggered manually.
context.* — Context Tier Defaults

These keys set the default context policy for all projects. Project-level context policies (set via agents project context set) override these defaults. All keys in this group are project-scopable.

Key Type Default Env Variable Description
context.hot.max-tokens integer 16000 CLEVERAGENTS_CTX_HOT_TOKENS Default maximum token budget for hot context (the current working set loaded into the LLM context window). This is a soft cap; the actor's model context window is the hard limit.
context.warm.max-decisions integer 100 CLEVERAGENTS_CTX_WARM_DECISIONS Default maximum number of recent decisions retained in warm context (available for retrieval but not loaded by default).
context.cold.max-decisions integer 500 CLEVERAGENTS_CTX_COLD_DECISIONS Default maximum number of historical decisions retained in cold context (archived for audit and correction).
context.query.limit integer 20 CLEVERAGENTS_CTX_QUERY_LIMIT Default maximum number of retrieval results returned per context query during Strategize and Execute.
context.query.min-relevance float 0.3 CLEVERAGENTS_CTX_QUERY_MIN_RELEVANCE Minimum relevance score (0.01.0) for retrieval results to be included in context. Results below this threshold are discarded even if the query limit is not reached.
context.file.max-size integer 1048576 CLEVERAGENTS_CTX_MAX_FILE_SIZE Default maximum file size (in bytes) for files included in context. Files exceeding this size are summarized or excluded. Default is 1 MB (1,048,576 bytes).
context.file.max-total-size integer 52428800 CLEVERAGENTS_CTX_MAX_TOTAL_SIZE Default maximum total size (in bytes) across all files included in context. Default is 50 MB.
context.summarize.enabled boolean true CLEVERAGENTS_CTX_SUMMARIZE Whether to summarize large context segments that exceed token limits rather than truncating them. When true, an LLM summarization pass produces a condensed version. When false, content is hard-truncated.
context.summarize.max-tokens integer 1000 CLEVERAGENTS_CTX_SUMMARY_TOKENS Maximum number of tokens in a generated context summary. Controls the verbosity of summaries produced when context.summarize.enabled is true.
context.summarize.model string (uses actor's model) CLEVERAGENTS_CTX_SUMMARY_MODEL Model to use for context summarization. When unset, the active actor's own model is used. Set this to a faster/cheaper model (e.g., a smaller variant) to reduce summarization cost.
provider.* — LLM Provider Credentials

Provider credential keys follow the pattern provider.<name>.<field>. Each provider has an api-key field and may have additional fields for endpoint configuration. Environment variables for provider keys use standard naming conventions compatible with existing tooling (e.g., OPENAI_API_KEY).

Key Type Default Env Variable Description
provider.openai.api-key string (not set) OPENAI_API_KEY API key for OpenAI models. Required when using OpenAI-based actors or the default embedding provider. The standard OPENAI_API_KEY environment variable is checked for compatibility with existing tooling.
provider.openai.org-id string (not set) OPENAI_ORG_ID OpenAI organization ID. Optional; used when the API key belongs to multiple organizations.
provider.openai.base-url string (not set) OPENAI_BASE_URL Custom base URL for OpenAI-compatible APIs (e.g., a local proxy or alternative provider). When unset, the official OpenAI API URL is used.
provider.anthropic.api-key string (not set) ANTHROPIC_API_KEY API key for Anthropic models. Required when using Anthropic-based actors.
provider.google.api-key string (not set) GOOGLE_API_KEY API key for Google AI models. Required when using Google-based actors.
provider.azure.endpoint string (not set) AZURE_OPENAI_ENDPOINT Azure OpenAI endpoint URL. Required when using Azure-hosted OpenAI models.
provider.azure.api-key string (not set) AZURE_OPENAI_API_KEY API key for Azure OpenAI. Required alongside provider.azure.endpoint.
provider.azure.api-version string 2024-02-01 AZURE_OPENAI_API_VERSION Azure OpenAI API version string.
provider.openrouter.api-key string (not set) OPENROUTER_API_KEY API key for OpenRouter. Required when using OpenRouter as a provider.

Configuration Scoping

Several keys support project-scoped values in addition to the global default. When a project-scoped value is set, it applies only to plans targeting that project. Keys marked Project-scopable in the reference above support this feature.

The full dot path is used identically in both global and project-scoped contexts:


# Set a global default
$ agents config set core.automation-profile trusted

# Override for a specific project — same key, scoped to the project $ agents config set core.automation-profile manual --project local/production-api

# Project-scoped keys under any group work the same way $ agents config set plan.budget.per-plan 2.00 --project local/production-api $ agents config set sandbox.strategy git_worktree --project local/production-api $ agents config set context.hot.max-tokens 32000 --project local/large-codebase

The full list of project-scopable keys: core.automation-profile, plan.concurrency, plan.max-child-depth, plan.budget.per-plan, sandbox.strategy, sandbox.checkpoint.enabled, and all keys under context.*.

Resolution Order

When resolving the effective value of a configuration key, the following precedence applies (highest to lowest):

  1. CLI flag: Per-invocation overrides (e.g., --format maps to core.format, --data-dir maps to core.data-dir). Highest priority.
  2. Environment variable: The mapped CLEVERAGENTS_* variable or provider-specific variable (e.g., OPENAI_API_KEY for provider.openai.api-key).
  3. Project-scoped config: For project-scopable keys, the value set via agents config set <key> <value> --project <PROJECT>. Only applies in contexts where a project is known (e.g., during plan execution).
  4. Global config file: The value in the config file at the path specified by core.config-path.
  5. Built-in default: The hardcoded default value.

The agents config get <key> command displays the full resolution chain, showing which level provided the winning value. Listing subtrees is supported:


# Show the full resolution chain for a single key
$ agents config get sandbox.checkpoint.enabled

# List all keys in a group $ agents config list index.*

# List all keys with their current effective values $ agents config list

Configuration File Format

The global configuration file uses TOML format. The hierarchical key structure maps naturally to TOML tables. A typical config.toml after initial setup:


# ~/.cleveragents/config.toml

[core] data-dir = "/home/alex/.cleveragents" format = "rich" namespace = "local" automation-profile = "supervised"

[core.log] level = "INFO" retention-days = 30

[core.backup] retention-days = 7

[server] # url = "https://agents.example.com" # token = "tok_01HXR..."

[actor.default] strategy = "local/strategist" execution = "local/executor" invariant = "local/invariant-resolver" # estimation = "local/estimator" # orchestrator = "local/orchestrator"

[plan] concurrency = 4 max-child-depth = 5

[plan.budget] per-plan = 5.00 per-session = 25.00 warn-threshold = 0.8

[plan.tool] max-calls-per-step = 25 max-retries = 3 retry-backoff = "exponential"

[sandbox] strategy = "git_worktree" cleanup = "on_apply"

[sandbox.checkpoint] enabled = true max-per-plan = 50

[index.text] backend = "tantivy"

[index.vector] backend = "faiss"

[index.graph] backend = "none"

[index.embedding] provider = "openai" model = "text-embedding-3-small"

[context.hot] max-tokens = 16000

[context.warm] max-decisions = 100

[context.cold] max-decisions = 500

[context.query] limit = 20 min-relevance = 0.3

[context.file] max-size = 1048576 max-total-size = 52428800

[context.summarize] enabled = true max-tokens = 1000

# Provider keys — prefer environment variables for secrets [provider.openai] # api-key = "sk-..."

[provider.anthropic] # api-key = "sk-ant-..."

# Project-scoped overrides [project."local/production-api"] "core.automation-profile" = "manual" "plan.budget.per-plan" = 2.00 "sandbox.strategy" = "git_worktree" "sandbox.checkpoint.enabled" = true

[project."local/docs"] "core.automation-profile" = "auto" "plan.budget.per-plan" = 10.00 "context.hot.max-tokens" = 32000

Design Principles

All CleverAgents configuration files share a consistent set of design principles:

  1. YAML-first: All configuration files use YAML syntax. JSON is also accepted where a configuration file is loaded (since valid JSON is valid YAML), but YAML is the canonical format for human-authored configurations.

  2. Namespace/Name convention: Every configurable entity follows the <namespace>/<name> naming convention. The local/ namespace is reserved for local-only items. User namespaces (<username>/) and organization namespaces (<orgname>/) are stored on the server. Built-in entities use provider namespaces (e.g., openai/, anthropic/).

  3. Config + CLI override pattern: Configuration files serve as the complete definition of an entity. When a --config file is provided alongside CLI options, the CLI options act as overrides for values defined in the configuration file. This allows a single config file to be reused with per-invocation customization.

  4. Environment variable interpolation: All configuration files support ${ENV_VAR} and ${ENV_VAR:default_value} syntax for environment variable interpolation. If a variable is not set and no default is provided, an error is raised. Boolean strings (true/false) and numeric strings are automatically converted to their native types.

  5. Jinja2 template support: Actor configuration files support Jinja2 template syntax within string values (particularly system_prompt fields). Template placeholders like {{ context.project_name }} are preserved during YAML parsing and rendered at runtime.

  6. Idempotent registration: Adding an entity that already exists fails unless --update is provided. This prevents accidental overwrites while allowing intentional updates.

  7. Declarative structure: Configuration files are declarative — they describe what should exist, not how to create it. The system handles all lifecycle management.

  8. Schema version: Configuration files may include a top-level cleveragents.version field to indicate which schema version they target (currently "3.0"). When omitted, the latest schema version is assumed.


Actor Configuration Files

Actor configuration files define intelligent agents — anything conversational, from a single LLM to an entire graph of interconnected actors and tools. Actors are registered via agents actor add --config <file>.

JSON Schema

The following is the formal JSON Schema definition for actor configuration files. Since YAML is a superset of JSON, this schema can be used directly to validate actor YAML files using any JSON Schema validator.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/actor-config.json",
  "title": "CleverAgents Actor Configuration",
  "description": "Configuration file schema for defining CleverAgents actors — intelligent agents composed of LLMs, tools, and graph topologies.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-z0-9_-]+/[a-z0-9_-]+$",
      "description": "Namespaced actor name in <namespace>/<name> format (e.g., 'local/reviewer', 'myorg/deploy-agent'). Required. When the actor is added via the CLI, this value is used as the registered name unless overridden by the optional CLI NAME argument."
    },
    "cleveragents": {
      "type": "object",
      "description": "Metadata block containing schema version, logging, template engine, and safety settings.",
      "properties": {
        "version": {
          "type": "string",
          "description": "Schema version for this configuration file.",
          "default": "3.0"
        },
        "logging": {
          "type": "object",
          "properties": {
            "level": {
              "type": "string",
              "enum": ["DEBUG", "INFO", "WARNING", "ERROR"],
              "default": "INFO",
              "description": "Logging level."
            }
          },
          "additionalProperties": false
        },
        "template_engine": {
          "type": "string",
          "enum": ["JINJA2", "NONE"],
          "default": "JINJA2",
          "description": "Template engine for string interpolation."
        },
        "unsafe": {
          "type": "boolean",
          "default": false,
          "description": "When true, allows actors to perform operations flagged as unsafe. Requires --unsafe CLI flag."
        },
        "default_actor": {
          "type": "string",
          "description": "Name of the default actor when multiple actors are defined."
        }
      },
      "additionalProperties": false
    },
    "actors": {
      "$ref": "#/$defs/actorMap"
    },
    "agents": {
      "$ref": "#/$defs/actorMap",
      "description": "Alias for 'actors'. Both keys are accepted; use one or the other."
    },
    "routes": {
      "type": "object",
      "description": "Map of route names to their definitions. Routes connect actors via stream or graph topologies.",
      "additionalProperties": {
        "$ref": "#/$defs/route"
      }
    },
    "merges": {
      "type": "array",
      "description": "Stream merge operations combining multiple streams into one.",
      "items": {
        "type": "object",
        "properties": {
          "sources": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Source stream names to merge."
          },
          "target": {
            "type": "string",
            "description": "Target stream name for merged output."
          }
        },
        "required": ["sources", "target"],
        "additionalProperties": false
      }
    },
    "splits": {
      "type": "array",
      "description": "Stream split operations dividing one stream into multiple.",
      "items": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Source stream name to split."
          },
          "targets": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Target stream names for split output."
          }
        },
        "required": ["source", "targets"],
        "additionalProperties": false
      }
    },
    "templates": {
      "type": "object",
      "description": "Reusable template definitions for Jinja2 template inheritance.",
      "additionalProperties": true
    },
    "instances": {
      "type": "object",
      "description": "Instantiated templates with bound parameters.",
      "additionalProperties": true
    },
    "global_context": {
      "type": "object",
      "description": "Key-value pairs available to all actors via {{ context.key }} in templates.",
      "additionalProperties": true
    },
    "prompts": {
      "type": "object",
      "description": "Named prompt templates that can be referenced by actors.",
      "additionalProperties": { "type": "string" }
    },
    "pipelines": {
      "type": "object",
      "description": "Hybrid pipeline definitions combining stream and graph stages.",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "stages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "type": { "type": "string" },
                "config": { "type": "object", "additionalProperties": true }
              },
              "required": ["name", "type"]
            }
          },
          "metadata": { "type": "object", "additionalProperties": true }
        },
        "required": ["stages"]
      }
    }
  },
  "required": ["name"],
  "oneOf": [
    { "required": ["actors"] },
    { "required": ["agents"] }
  ],
  "additionalProperties": false,
  "$defs": {
    "actorMap": {
      "type": "object",
      "description": "Map of actor names to their definitions.",
      "additionalProperties": {
        "$ref": "#/$defs/actorDefinition"
      }
    },
    "actorDefinition": {
      "type": "object",
      "description": "A single actor definition.",
      "properties": {
        "type": {
          "type": "string",
          "enum": ["llm", "tool"],
          "description": "Actor type: 'llm' for language model actors, 'tool' for tool-based actors."
        },
        "config": {
          "type": "object",
          "description": "Actor configuration. Fields depend on actor type.",
          "properties": {
            "provider": {
              "type": "string",
              "description": "LLM provider identifier: openai, anthropic, google, azure, openrouter, etc."
            },
            "model": {
              "type": "string",
              "description": "Model identifier within the provider: gpt-4, claude-3.5-sonnet, gemini-pro, etc."
            },
            "actor": {
              "type": "string",
              "description": "Combined provider/model format (e.g., 'anthropic/claude-3.5-sonnet'). Alternative to specifying provider and model separately."
            },
            "system_prompt": {
              "type": "string",
              "description": "System prompt text. Supports Jinja2 template syntax for dynamic content."
            },
            "temperature": {
              "type": "number",
              "minimum": 0.0,
              "maximum": 2.0,
              "description": "Sampling temperature. Lower values are more deterministic."
            },
            "max_tokens": {
              "type": "integer",
              "minimum": 1,
              "description": "Maximum number of tokens in the generated response."
            },
            "memory_enabled": {
              "type": "boolean",
              "default": false,
              "description": "Enable conversation memory for multi-turn interactions."
            },
            "max_history": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "description": "Maximum number of conversation turns retained in memory."
            },
            "unsafe": {
              "type": "boolean",
              "default": false,
              "description": "Allow this specific actor to perform unsafe operations."
            },
            "options": {
              "type": "object",
              "description": "Provider-specific options passed through to the underlying LLM API.",
              "additionalProperties": true
            },
            "tools": {
              "type": "array",
              "description": "List of inline tool definitions for tool-type actors.",
              "items": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Tool name."
                  },
                  "code": {
                    "type": "string",
                    "description": "Inline Python code defining the tool's behavior."
                  }
                },
                "required": ["name", "code"],
                "additionalProperties": false
              }
            }
          },
          "additionalProperties": false
        }
      },
      "required": ["type", "config"],
      "additionalProperties": false
    },
    "route": {
      "type": "object",
      "description": "A route definition — either a stream or a graph topology.",
      "properties": {
        "type": {
          "type": "string",
          "enum": ["stream", "graph"],
          "description": "Route type."
        },
        "stream_type": {
          "type": "string",
          "enum": ["cold", "hot", "replay"],
          "default": "cold",
          "description": "Stream type (stream routes only)."
        },
        "operators": {
          "type": "array",
          "description": "Processing operators (stream routes).",
          "items": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": ["map", "graph_execute"],
                "description": "Operator type."
              },
              "params": {
                "type": "object",
                "properties": {
                  "agent": { "type": "string", "description": "Actor name for map operators." },
                  "graph": { "type": "string", "description": "Graph route name for graph_execute operators." }
                },
                "additionalProperties": true
              }
            },
            "required": ["type"]
          }
        },
        "subscriptions": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Input stream subscriptions."
        },
        "publications": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Output stream publications."
        },
        "agents": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Actor names used by this route."
        },
        "initial_value": {
          "description": "Initial stream value."
        },
        "buffer_size": {
          "type": "integer",
          "default": 10,
          "minimum": 1,
          "description": "Stream buffer size."
        },
        "template_config": {
          "type": "object",
          "description": "Template-specific configuration.",
          "additionalProperties": true
        },
        "bridge": {
          "type": "object",
          "description": "Bridge configuration for stream-to-graph upgrades.",
          "properties": {
            "upgrade_conditions": { "type": "object", "additionalProperties": true },
            "downgrade_conditions": { "type": "object", "additionalProperties": true },
            "state_extractor": { "type": "string" },
            "state_flattener": { "type": "string" },
            "preserve_subscriptions": { "type": "boolean", "default": true },
            "preserve_checkpointing": { "type": "boolean", "default": true }
          },
          "additionalProperties": false
        },
        "metadata": {
          "type": "object",
          "additionalProperties": true
        },
        "nodes": {
          "type": "object",
          "description": "Graph nodes (required for graph routes).",
          "additionalProperties": {
            "$ref": "#/$defs/graphNode"
          }
        },
        "edges": {
          "type": "array",
          "description": "Graph edges (required for graph routes).",
          "items": {
            "$ref": "#/$defs/graphEdge"
          }
        },
        "entry_point": {
          "type": "string",
          "description": "Entry point node name (required for graph routes)."
        },
        "checkpointing": {
          "type": "boolean",
          "default": false,
          "description": "Enable graph checkpointing."
        },
        "checkpoint_dir": {
          "type": "string",
          "description": "Directory for checkpoint storage."
        },
        "enable_time_travel": {
          "type": "boolean",
          "default": false,
          "description": "Enable time travel debugging."
        },
        "parallel_execution": {
          "type": "boolean",
          "default": false,
          "description": "Allow parallel node execution."
        },
        "state_class": {
          "type": "string",
          "description": "Custom state class name."
        }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "graphNode": {
      "type": "object",
      "description": "A graph node definition.",
      "properties": {
        "type": {
          "type": "string",
          "enum": ["agent", "function", "tool", "conditional", "subgraph", "start", "end", "message_router"],
          "description": "Node type."
        },
        "agent": { "type": "string", "description": "Actor name for agent nodes." },
        "function": { "type": "string", "description": "Function name for function nodes." },
        "tools": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Tool references for tool nodes."
        },
        "condition": { "type": "object", "additionalProperties": true, "description": "Condition for conditional nodes." },
        "subgraph": { "type": "string", "description": "Route name for subgraph nodes." },
        "retry_policy": { "type": "object", "additionalProperties": true, "description": "Retry configuration." },
        "timeout": { "type": "integer", "minimum": 1, "description": "Timeout in seconds." },
        "parallel": { "type": "boolean", "default": false, "description": "Allow parallel execution." },
        "metadata": { "type": "object", "additionalProperties": true }
      },
      "required": ["type"],
      "additionalProperties": false
    },
    "graphEdge": {
      "type": "object",
      "description": "A graph edge connecting two nodes.",
      "properties": {
        "source": { "type": "string", "description": "Source node name." },
        "target": { "type": "string", "description": "Target node name." },
        "condition": { "type": "object", "additionalProperties": true, "description": "Edge condition for conditional routing." },
        "metadata": { "type": "object", "additionalProperties": true }
      },
      "required": ["source", "target"],
      "additionalProperties": false
    }
  }
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations (comments, <placeholder> syntax, and | alternatives) to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Name ───────────────────────────────────────────────────────────
name: <namespace>/<actor-name>       # Namespaced actor name (required). Used as the registered name
                                    # unless overridden by the optional CLI NAME argument.
                                    # Must follow <namespace>/<name> format (e.g., local/reviewer).

# ─── Metadata ─────────────────────────────────────────────────────── cleveragents: version: "3.0" # Schema version (optional, default: latest) logging: level: "INFO" # Log level: DEBUG, INFO, WARNING, ERROR (optional) template_engine: "JINJA2" # Template engine: JINJA2 or NONE (optional, default: JINJA2) unsafe: false # Allow unsafe operations (optional, default: false) default_actor: <actor_name> # Default actor to use when multiple are defined (optional)

# ─── Actor Definitions ────────────────────────────────────────────── # The top-level key can be either "actors" or "agents" (both accepted). actors: <actor_name>: type: llm | tool # Actor type (required) config: # ── For type: llm ────────────────────────────────────────── provider: <string> # Provider identifier: openai, anthropic, google, azure, openrouter, etc. (required for LLM) model: <string> # Model identifier: gpt-4, claude-3.5-sonnet, etc. (required for LLM) # OR use the combined format: actor: "<provider>/<model>" # Combined provider/model (alternative to provider + model)

  <span style="color: cyan; font-weight: 600;">system_prompt</span>: |<span style="opacity: 0.7;">              # System prompt text, supports Jinja2 templates (optional)</span>
    You are a helpful assistant.
    <span style="color: cyan; font-weight: 600;">Project</span>: {{ context.project_name }}
  <span style="color: cyan; font-weight: 600;">temperature</span>: <span style="color: yellow;">0.7</span><span style="opacity: 0.7;">              # Sampling temperature 0.0-2.0 (optional, default: provider default)</span>
  <span style="color: cyan; font-weight: 600;">max_tokens</span>: <span style="color: yellow;">4096</span><span style="opacity: 0.7;">              # Maximum output tokens (optional, default: provider default)</span>
  <span style="color: cyan; font-weight: 600;">memory_enabled</span>: <span style="color: magenta; font-weight: 600;">true</span><span style="opacity: 0.7;">          # Enable conversation memory (optional, default: false)</span>
  <span style="color: cyan; font-weight: 600;">max_history</span>: <span style="color: yellow;">50</span><span style="opacity: 0.7;">               # Maximum conversation turns to retain (optional, default: 50)</span>
  <span style="color: cyan; font-weight: 600;">unsafe</span>: <span style="color: magenta; font-weight: 600;">false</span><span style="opacity: 0.7;">                 # Allow unsafe operations for this actor (optional, default: false)</span>
  <span style="color: cyan; font-weight: 600;">options</span>:                      # Additional provider-specific options (optional)
    <span style="color: cyan; font-weight: 600;">top_p</span>: <span style="color: yellow;">1.0</span>
    <span style="color: cyan; font-weight: 600;">frequency_penalty</span>: <span style="color: yellow;">0.0</span>
    <span style="color: cyan; font-weight: 600;">presence_penalty</span>: <span style="color: yellow;">0.0</span>
    <span style="color: cyan; font-weight: 600;">stop_sequences</span>: [<span style="color: #66cc66;">&quot;END&quot;</span>]
    <span style="color: cyan; font-weight: 600;">seed</span>: <span style="color: yellow;">42</span>

# ── For type: tool ───────────────────────────────────────── tools: - name: <tool_name> # Tool name (required per tool) code: | # Inline Python code (required per tool) def run(input_data): return {"result": input_data["query"]}

# ─── Routes ───────────────────────────────────────────────────────── routes: <route_name>: type: stream | graph # Route type (required)

# ── Stream route fields ────────────────────────────────────── stream_type: cold | hot | replay # Stream type (optional, default: cold) operators: # Processing operators (optional) - type: map | graph_execute # Operator type params: # Operator parameters agent: <actor_name> # Actor to use (for map) graph: <route_name> # Graph to execute (for graph_execute) subscriptions: # Input subscriptions (optional) - <stream_name> publications: # Output publications (optional) - <stream_name> agents: # Actors used by this route (optional) - <actor_name> initial_value: <any> # Initial stream value (optional) buffer_size: 10 # Stream buffer size (optional, default: 10) template_config: {} # Template-specific configuration (optional) bridge: # Bridge configuration for stream↔graph upgrades (optional) upgrade_conditions: {} # Conditions to upgrade from stream to graph downgrade_conditions: {} # Conditions to downgrade from graph to stream state_extractor: <string> # Function to extract state during upgrade state_flattener: <string> # Function to flatten state during downgrade preserve_subscriptions: true # Keep subscriptions during transition (optional) preserve_checkpointing: true # Keep checkpoints during transition (optional) metadata: {} # Arbitrary metadata (optional)

# ── Graph route fields ─────────────────────────────────────── nodes: # Graph nodes (required for graph routes) <node_name>: type: agent | function | tool | conditional | subgraph | start | end | message_router agent: <actor_name> # Actor for agent nodes function: <function_name> # Function for function nodes tools: # Tools for tool nodes - <tool_ref> condition: {} # Condition for conditional nodes subgraph: <route_name> # Subgraph for subgraph nodes retry_policy: {} # Retry configuration (optional) timeout: 30 # Timeout in seconds (optional) parallel: false # Allow parallel execution (optional) metadata: {} # Arbitrary metadata (optional) edges: # Graph edges (required for graph routes) - source: <node_name> # Source node (required) target: <node_name> # Target node (required) condition: {} # Edge condition (optional) metadata: {} # Arbitrary metadata (optional) entry_point: <node_name> # Entry point node (required for graph routes) checkpointing: false # Enable graph checkpointing (optional, default: false) checkpoint_dir: <path> # Checkpoint directory (optional) enable_time_travel: false # Enable time travel debugging (optional, default: false) parallel_execution: false # Allow parallel node execution (optional, default: false) state_class: <string> # Custom state class name (optional) metadata: {} # Arbitrary metadata (optional)

# ─── Merges & Splits ──────────────────────────────────────────────── merges: # Stream merge definitions (optional)

  • sources: # Source streams to merge
    • <stream_name> target: <stream_name> # Target stream for merged output

splits: # Stream split definitions (optional)

  • source: <stream_name> # Source stream to split targets: # Target streams for split output
    • <stream_name>

# ─── Templates & Context ──────────────────────────────────────────── templates: {} # Reusable template definitions (optional) instances: {} # Template instances (optional) global_context: {} # Global context available to all actors (optional) prompts: {} # Named prompt templates (optional)

# ─── Pipelines ────────────────────────────────────────────────────── pipelines: # Hybrid pipeline definitions (optional) <pipeline_name>: stages: - name: <stage_name> type: <stage_type> config: {} metadata: {}

Structure Reference

Top-Level Keys

Key Type Required Description
cleveragents object No Metadata block containing version, logging, template engine, and safety settings.
actors (or agents) object Yes Map of actor names to their definitions. Both actors and agents are accepted as the key name.
routes object No Map of route names to their definitions. Routes connect actors via stream or graph topologies.
merges list No Stream merge operations combining multiple streams into one.
splits list No Stream split operations dividing one stream into multiple.
templates object No Reusable template definitions for Jinja2 template inheritance.
instances object No Instantiated templates with bound parameters.
global_context object No Key-value pairs available to all actors via {{ context.key }} in templates.
prompts object No Named prompt templates that can be referenced by actors.
pipelines object No Hybrid pipelines combining stream and graph stages into sequential workflows.

cleveragents Block

Field Type Default Description
version string "3.0" Schema version for this configuration file.
logging.level string "INFO" Logging level: DEBUG, INFO, WARNING, ERROR.
template_engine string "JINJA2" Template engine for string interpolation: JINJA2 or NONE.
unsafe boolean false When true, allows actors to perform operations flagged as unsafe. Requires --unsafe CLI flag.
default_actor string (first actor) Name of the default actor when multiple actors are defined.

Actor Definition Fields

Field Type Required Description
type string Yes Actor type. llm for language model actors, tool for tool-based actors.
config.provider string Yes (LLM) LLM provider identifier: openai, anthropic, google, azure, openrouter, etc.
config.model string Yes (LLM) Model identifier within the provider: gpt-4, claude-3.5-sonnet, gemini-pro, etc.
config.actor string No Combined provider/model format. Alternative to specifying provider and model separately.
config.system_prompt string No System prompt text. Supports Jinja2 template syntax for dynamic content.
config.temperature float Provider default Sampling temperature (0.0 to 2.0). Lower values are more deterministic.
config.max_tokens integer Provider default Maximum number of tokens in the generated response.
config.memory_enabled boolean false Enable conversation memory for multi-turn interactions.
config.max_history integer 50 Maximum number of conversation turns retained in memory.
config.unsafe boolean false Allow this specific actor to perform unsafe operations.
config.options object {} Provider-specific options passed through to the underlying LLM API.
config.tools list Yes (tool) List of inline tool definitions for tool-type actors. Each tool has name and code.

Node Types (Graph Routes)

Type Description
agent A node backed by an actor. Requires agent field pointing to an actor name.
function A node backed by a Python function. Requires function field.
tool A node that invokes one or more tools. Requires tools list.
conditional A branching node that routes based on conditions. Requires condition field.
subgraph A node that delegates to another graph route. Requires subgraph field.
start The explicit start node (alternative to entry_point).
end A terminal node that ends graph execution.
message_router Routes messages to different nodes based on message content or metadata.

Examples

Example 1: Minimal Chat Actor (Simple)

A bare-minimum actor configuration for a simple conversational agent:


# minimal-chat.yaml
# Register: agents actor add --config minimal-chat.yaml

name: local/chat

actors: chat: type: llm config: provider: anthropic model: claude-3.5-sonnet system_prompt: "You are a helpful assistant."

routes: main: type: stream operators: - type: map params: agent: chat publications: - output

merges:

  • sources: [output] target: final

This is the simplest possible actor: one LLM actor, one stream route, one merge. No graph complexity, no tools, no templates.


Example 2: Code Reviewer with Tools (Medium)

An actor that can read files and search code to perform code reviews:


# code-reviewer.yaml
# Register: agents actor add --config code-reviewer.yaml

name: local/reviewer

cleveragents: version: "3.0" logging: level: "INFO"

actors: reviewer: type: llm config: provider: openai model: gpt-4 temperature: 0.2 max_tokens: 4096 system_prompt: | You are a senior code reviewer. Analyze code for: - Security vulnerabilities - Performance issues - Code style violations - Missing error handling Provide specific, actionable feedback with file and line references.

file_reader: type: tool config: tools: - name: read_file code: | def run(input_data): path = input_data.get("path", "") with open(path, "r") as f: return {"content": f.read(), "path": path}

routes: review_graph: type: graph nodes: analyze: type: agent agent: reviewer read: type: tool tools: [read_file] report: type: agent agent: reviewer edges: - source: analyze target: read - source: read target: report - source: analyze target: report condition: no_files_needed: true entry_point: analyze checkpointing: false

output_stream: type: stream operators: - type: graph_execute params: graph: review_graph publications: - review_output

merges:

  • sources: [review_output] target: final

This actor defines an LLM reviewer and a file-reading tool, connected via a graph route with conditional edges.


Example 3: Multi-Agent Research Pipeline with Templates (Complex)

A complex actor configuration with multiple LLM actors, Jinja2 templates, environment variable interpolation, memory, and hybrid routing:


# research-pipeline.yaml
# Register: agents actor add --config research-pipeline.yaml --unsafe

name: local/research

cleveragents: version: "3.0" logging: level: "DEBUG" template_engine: "JINJA2" unsafe: true default_actor: orchestrator

actors: orchestrator: type: llm config: provider: anthropic model: claude-3.5-sonnet temperature: 0.7 max_tokens: 8192 memory_enabled: true max_history: 100 system_prompt: | You are an orchestrator managing a research pipeline for {{ context.project_name }}. Topic: {{ context.research_topic }}

    Your job is to:
    1. Break down the research question into sub-questions
    2. Delegate to specialist researchers
    3. Synthesize findings into a coherent report

    {% if context.deadline %}
    <span style="color: cyan; font-weight: 600;">Deadline</span>: {{ context.deadline }}. Prioritize breadth over depth.
    {% endif %}

researcher: type: llm config: provider: openai model: gpt-4 temperature: 0.3 max_tokens: 4096 system_prompt: | You are a domain expert researcher. Provide thorough, factual analysis. Always cite sources and note confidence levels.

synthesizer: type: llm config: provider: anthropic model: claude-3.5-sonnet temperature: 0.5 max_tokens: 16384 system_prompt: | You are an expert at synthesizing multiple research reports into coherent narratives. Resolve contradictions, highlight consensus, and note gaps.

web_searcher: type: tool config: tools: - name: search_web code: | import os, json def run(input_data): api_key = os.environ.get("SEARCH_API_KEY", "") query = input_data.get("query", "") # Simulated web search return {"results": [], "query": query}

    - <span style="color: cyan; font-weight: 600;">name</span>: fetch_url
      <span style="color: cyan; font-weight: 600;">code</span>: |
        def run(input_data):
            url = input_data.get(&quot;url&quot;, &quot;&quot;)
            return {&quot;content&quot;: f&quot;Content from {url}&quot;, &quot;url&quot;: url}

routes: research_graph: type: graph nodes: plan: type: agent agent: orchestrator research_parallel: type: agent agent: researcher parallel: true search: type: tool tools: [search_web, fetch_url] synthesize: type: agent agent: synthesizer review: type: agent agent: orchestrator edges: - source: plan target: research_parallel - source: plan target: search - source: research_parallel target: synthesize - source: search target: synthesize - source: synthesize target: review - source: review target: plan condition: needs_more_research: true entry_point: plan checkpointing: true checkpoint_dir: "${CHECKPOINT_DIR:/tmp/research_checkpoints}" enable_time_travel: true parallel_execution: true

progress_stream: type: stream stream_type: hot operators: - type: map params: agent: orchestrator subscriptions: - research_updates publications: - progress_output buffer_size: 50

output_stream: type: stream operators: - type: graph_execute params: graph: research_graph publications: - research_output

merges:

  • sources: [progress_output, research_output] target: final

global_context: project_name: "AI Safety Research" research_topic: "Alignment techniques in large language models" deadline: "2026-03-01"

prompts: deep_dive: "Provide an in-depth analysis of {topic} with at least 5 sources." summary: "Summarize the following research in 500 words: {content}"

templates: research_section: template: | ## {{ section_title }} {{ section_content }} Confidence: {{ confidence_level }} Sources: {{ sources | join(', ') }}

This configuration demonstrates multi-actor orchestration, graph routing with parallel execution, hot stream monitoring, Jinja2 templates with conditionals, environment variables, checkpointing, and global context.


Example 4: Simple Echo/Tool Actor (Simple)

A non-LLM actor that processes input with pure Python code:


# echo-actor.yaml
# Register: agents actor add --config echo-actor.yaml

name: local/echo

cleveragents: version: "3.0"

actors: echo: type: tool config: tools: - name: echo_tool code: | def run(input_data): message = input_data.get("content", "") return {"response": f"Echo: {message}"}

routes: main: type: stream operators: - type: map params: agent: echo publications: - output

merges:

  • sources: [output] target: final

Example 5: Graph Actor with Conditional Routing (Medium)

An actor that routes between different specialists based on input classification:


# classifier-router.yaml
# Register: agents actor add --config classifier-router.yaml

name: local/smart-router

actors: classifier: type: llm config: provider: openai model: gpt-4 temperature: 0.0 max_tokens: 100 system_prompt: | Classify the user's request into exactly one category: CODING, WRITING, ANALYSIS, or GENERAL. Respond with only the category name.

coding_expert: type: llm config: provider: anthropic model: claude-3.5-sonnet temperature: 0.2 system_prompt: "You are an expert software engineer. Write clean, well-tested code."

writing_expert: type: llm config: provider: openai model: gpt-4 temperature: 0.7 system_prompt: "You are a professional writer. Produce clear, engaging prose."

analyst: type: llm config: provider: anthropic model: claude-3.5-sonnet temperature: 0.3 system_prompt: "You are a data analyst. Provide thorough, evidence-based analysis."

generalist: type: llm config: provider: openai model: gpt-4 temperature: 0.5 system_prompt: "You are a helpful general-purpose assistant."

routes: router_graph: type: graph nodes: classify: type: agent agent: classifier code: type: agent agent: coding_expert write: type: agent agent: writing_expert analyze: type: agent agent: analyst general: type: agent agent: generalist edges: - source: classify target: code condition: category: "CODING" - source: classify target: write condition: category: "WRITING" - source: classify target: analyze condition: category: "ANALYSIS" - source: classify target: general condition: category: "GENERAL" entry_point: classify

main: type: stream operators: - type: graph_execute params: graph: router_graph publications: - output

merges:

  • sources: [output] target: final

Skill Configuration Files

Skill configuration files define reusable, namespaced collections of tools. Skills assemble tools by referencing named tools from the Tool Registry, defining anonymous inline tools, and including other skills. Skills are registered via agents skill add --config <file>.

JSON Schema

The following is the formal JSON Schema definition for skill configuration files.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/skill-config.json",
  "title": "CleverAgents Skill Configuration",
  "description": "Configuration file schema for defining CleverAgents skills — reusable, namespaced collections of tools.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified skill name in <namespace>/<name> format."
    },
    "description": {
      "type": "string",
      "description": "Human-readable description of what this skill provides."
    },
    "tools": {
      "type": "array",
      "description": "References to named tools from the Tool Registry.",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
            "description": "Fully qualified name of a tool registered in the Tool Registry."
          },
          "description": {
            "type": "string",
            "description": "Override the tool's registered description within this skill context."
          },
          "writes": {
            "type": "boolean",
            "description": "Override the tool's writes capability flag."
          },
          "checkpointable": {
            "type": "boolean",
            "description": "Override the tool's checkpointable capability flag."
          }
        },
        "required": ["name"],
        "additionalProperties": false
      }
    },
    "inline_tools": {
      "type": "array",
      "description": "Anonymous tool definitions that exist only within this skill. Not registered in the Tool Registry.",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Tool name, unique within this skill."
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the tool's purpose."
          },
          "source": {
            "type": "string",
            "const": "custom",
            "description": "Source type. Always 'custom' for inline tools."
          },
          "code": {
            "type": "string",
            "description": "Python code defining the tool's behavior. Must contain a run(input_data) function."
          },
          "input_schema": {
            "$ref": "https://json-schema.org/draft/2020-12/schema",
            "description": "JSON Schema describing the tool's input parameters."
          },
          "writes": {
            "type": "boolean",
            "default": false,
            "description": "Whether this tool performs write operations."
          },
          "checkpointable": {
            "type": "boolean",
            "default": false,
            "description": "Whether this tool supports checkpointing."
          },
          "side_effects": {
            "type": "array",
            "items": { "type": "string" },
            "default": [],
            "description": "Descriptions of side effects (e.g., 'network_call', 'schema_mutation')."
          }
        },
        "required": ["name", "source", "code"],
        "additionalProperties": false
      }
    },
    "includes": {
      "type": "array",
      "description": "Other skills whose tools are merged into this skill.",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
            "description": "Fully qualified skill name to include."
          },
          "description": {
            "type": "string",
            "description": "Override the included skill's description."
          }
        },
        "required": ["name"],
        "additionalProperties": false
      }
    },
    "mcp_servers": {
      "type": "array",
      "description": "MCP server specifications for exposing remote tools.",
      "items": {
        "$ref": "#/$defs/mcpServer"
      }
    },
    "agent_skill_folders": {
      "type": "array",
      "description": "Agent Skills Standard folders to include.",
      "items": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "description": "Path to the folder containing SKILL.md."
          },
          "name": {
            "type": "string",
            "description": "Override the skill bundle name."
          }
        },
        "required": ["path"],
        "additionalProperties": false
      }
    }
  },
  "required": ["name"],
  "additionalProperties": false,
  "$defs": {
    "mcpServer": {
      "type": "object",
      "description": "An MCP server specification.",
      "properties": {
        "name": {
          "type": "string",
          "description": "Identifier for the MCP server."
        },
        "transport": {
          "type": "string",
          "enum": ["stdio", "sse", "streamable-http"],
          "description": "Transport protocol."
        },
        "command": {
          "type": "string",
          "description": "Command to start the server (required for stdio transport)."
        },
        "args": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Command-line arguments for the server command."
        },
        "env": {
          "type": "object",
          "additionalProperties": { "type": "string" },
          "description": "Environment variables to set when starting the server."
        },
        "url": {
          "type": "string",
          "format": "uri",
          "description": "Server URL (required for sse and streamable-http transports)."
        },
        "headers": {
          "type": "object",
          "additionalProperties": { "type": "string" },
          "description": "HTTP headers for remote server connections."
        },
        "tool_filter": {
          "type": "object",
          "properties": {
            "include": {
              "type": "array",
              "items": { "type": "string" },
              "description": "Whitelist of tool names to expose."
            },
            "exclude": {
              "type": "array",
              "items": { "type": "string" },
              "description": "Blacklist of tool names to hide."
            }
          },
          "additionalProperties": false
        }
      },
      "required": ["name", "transport"],
      "additionalProperties": false
    }
  }
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Skill Metadata ─────────────────────────────────────────────────
name: <namespace>/<name>            # Fully qualified skill name (required)
description: <string>               # Human-readable description (optional)

# ─── Tool References ──────────────────────────────────────────────── # Named tools from the Tool Registry, referenced by fully-qualified name. tools:

  • name: <namespace>/<tool_name> # Reference to a registered tool (required) description: <string> # Override the tool's description (optional) writes: <boolean> # Override the tool's writes flag (optional) checkpointable: <boolean> # Override the tool's checkpointable flag (optional)

# ─── Inline (Anonymous) Tools ─────────────────────────────────────── # Tools defined directly within this skill. These are NOT registered # in the Tool Registry and cannot be reused outside this skill. inline_tools:

  • name: <string> # Tool name (unique within this skill, required) description: <string> # Tool description (optional) source: custom # Source type (required, always "custom" for inline) code: | # Inline Python code (required) def run(input_data): return {"result": "value"} input_schema: # JSON Schema for tool inputs (optional) type: object properties: param_name: type: string description: "Parameter description" required: ["param_name"] writes: false # Whether this tool writes (optional, default: false) checkpointable: false # Whether this tool supports checkpointing (optional, default: false) side_effects: [] # List of side effect descriptions (optional)

# ─── Included Skills ──────────────────────────────────────────────── # Other skills whose tools are merged into this skill. includes:

  • name: <namespace>/<skill_name> # Fully qualified skill name to include (required) description: <string> # Override the included skill's description (optional)

# ─── MCP Server Specifications ────────────────────────────────────── # MCP servers whose tools are exposed through this skill. mcp_servers:

  • name: <string> # Server name for identification (required) transport: stdio | sse | streamable-http # Transport protocol (required) command: <string> # Server command (required for stdio) args: # Command arguments (optional)
    • <string> env: # Environment variables for the server (optional) KEY: "value" url: <string> # Server URL (required for sse/streamable-http) headers: {} # HTTP headers (optional, for sse/streamable-http) tool_filter: # Filter which tools to expose (optional) include: # Include only these tools (optional)
      • <tool_name> exclude: # Exclude these tools (optional)
      • <tool_name>

# ─── Agent Skills Standard Folders ────────────────────────────────── # References to Agent Skills Standard (SKILL.md-based) tool bundles. agent_skill_folders:

  • path: <string> # Path to the folder containing SKILL.md (required) name: <string> # Override the skill bundle name (optional)

Structure Reference

Top-Level Fields

Field Type Required Description
name string Yes Fully qualified skill name in <namespace>/<name> format. Can be overridden by the CLI <NAME> argument.
description string No Human-readable description of what this skill provides.
tools list No References to named tools from the Tool Registry.
inline_tools list No Anonymous tool definitions that exist only within this skill.
includes list No Other skills to include (their tools are merged in).
mcp_servers list No MCP server specifications for exposing remote tools.
agent_skill_folders list No Agent Skills Standard folders to include.

Tool Reference Fields (tools[])

Field Type Required Description
name string Yes Fully qualified name of a tool registered in the Tool Registry.
description string No Override the tool's registered description within this skill context.
writes boolean No Override the tool's writes capability flag.
checkpointable boolean No Override the tool's checkpointable capability flag.

Inline Tool Fields (inline_tools[])

Field Type Required Description
name string Yes Tool name, unique within this skill.
description string No Human-readable description of the tool's purpose.
source string Yes Always custom for inline tools.
code string Yes Python code defining the tool's behavior. Must contain a run(input_data) function.
input_schema object No JSON Schema describing the tool's input parameters.
writes boolean No Whether this tool performs write operations. Default: false.
checkpointable boolean No Whether this tool supports checkpointing. Default: false.
side_effects list No Descriptions of any side effects (e.g., ["network_call"], ["schema_mutation"]).

MCP Server Fields (mcp_servers[])

Field Type Required Description
name string Yes Identifier for the MCP server.
transport string Yes Transport protocol: stdio, sse, or streamable-http.
command string Conditional Command to start the server (required for stdio transport).
args list No Command-line arguments for the server command.
env object No Environment variables to set when starting the server.
url string Conditional Server URL (required for sse and streamable-http transports).
headers object No HTTP headers for remote server connections.
tool_filter.include list No Whitelist of tool names to expose. When set, only these tools are available.
tool_filter.exclude list No Blacklist of tool names to hide. Applied after include.

Examples

Example 1: Minimal Read-Only Skill (Simple)

A skill that bundles a few built-in file operations:


# file-reader-skill.yaml
# Register: agents skill add --config file-reader-skill.yaml

name: local/file-reader description: "Basic file reading operations"

tools:

  • name: builtin/read_file
  • name: builtin/list_directory
  • name: builtin/search_files

Example 2: Git Operations Skill with MCP (Medium)

A skill that combines built-in git tools with GitHub tools via an MCP server:


# git-and-github-skill.yaml
# Register: agents skill add --config git-and-github-skill.yaml

name: local/git-github description: "Git operations and GitHub integration"

tools:

  • name: builtin/git_status
  • name: builtin/git_diff
  • name: builtin/git_log
  • name: builtin/git_blame

includes:

  • name: local/file-reader

mcp_servers:

  • name: github transport: stdio command: npx args:
    • "-y"
    • "@modelcontextprotocol/server-github" env: GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}" tool_filter: include:
      • create_issue
      • create_pull_request
      • list_repos
      • get_file_contents

This skill includes another skill (local/file-reader) and adds GitHub tools from an MCP server, filtered to only expose four specific tools.


Example 3: Full DevOps Toolkit (Complex)

A comprehensive skill with multiple includes, MCP servers, inline tools, and agent skill folders:


# devops-toolkit.yaml
# Register: agents skill add --config devops-toolkit.yaml

name: local/devops-toolkit description: "Full-stack development and operations toolkit"

tools:

  • name: builtin/shell_execute description: "Execute shell commands in the project sandbox"
  • name: local/validate-api-compat description: "Check API backward compatibility"

includes:

  • name: local/file-reader
  • name: local/git-github
  • name: local/docker-tools

inline_tools:

  • name: run_migrations description: "Run database migrations with rollback support" source: custom code: | import subprocess def run(input_data): direction = input_data.get("direction", "up") count = input_data.get("count", 1) result = subprocess.run( ["alembic", direction, str(count)], capture_output=True, text=True ) return { "success": result.returncode == 0, "stdout": result.stdout, "stderr": result.stderr } input_schema: type: object properties: direction: type: string enum: ["up", "down"] description: "Migration direction" count: type: integer default: 1 description: "Number of migrations to run" required: ["direction"] writes: true checkpointable: true side_effects: ["schema_mutation"]

  • name: health_check description: "Check service health endpoints" source: custom code: | import urllib.request def run(input_data): url = input_data.get("url", "http://localhost:8000/health") try: resp = urllib.request.urlopen(url, timeout=10) return {"status": resp.status, "healthy": resp.status == 200} except Exception as e: return {"status": 0, "healthy": False, "error": str(e)} input_schema: type: object properties: url: type: string description: "Health check URL" writes: false

mcp_servers:

  • name: linear transport: stdio command: npx args: ["-y", "@modelcontextprotocol/server-linear"] env: LINEAR_API_KEY: "${LINEAR_API_KEY}"

agent_skill_folders:

  • path: ./skills/deploy-to-staging name: deploy-staging
  • path: ./skills/code-review-bundle name: code-review

Example 4: Skill with Only Inline Tools (Simple)

A self-contained skill that defines everything inline, with no external dependencies:


# text-processing-skill.yaml
# Register: agents skill add --config text-processing-skill.yaml

name: local/text-processing description: "Simple text transformation utilities"

inline_tools:

  • name: word_count description: "Count words in text" source: custom code: | def run(input_data): text = input_data.get("text", "") return {"count": len(text.split())} input_schema: type: object properties: text: type: string description: "Text to count words in" required: ["text"] writes: false

  • name: to_uppercase description: "Convert text to uppercase" source: custom code: | def run(input_data): return {"result": input_data.get("text", "").upper()} input_schema: type: object properties: text: type: string required: ["text"] writes: false

  • name: extract_urls description: "Extract URLs from text" source: custom code: | import re def run(input_data): text = input_data.get("text", "") urls = re.findall(r'https?://[^\s<>"{}|\^`[]]+', text) return {"urls": urls, "count": len(urls)} writes: false


Action Configuration Files

Action configuration files define reusable plan templates — complete specifications for work that can be applied to projects. Actions are created via agents action create --config <file>.

JSON Schema

The following is the formal JSON Schema definition for action configuration files.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/action-config.json",
  "title": "CleverAgents Action Configuration",
  "description": "Configuration file schema for defining CleverAgents actions — reusable plan templates that specify work to be applied to projects.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified action name in <namespace>/<name> format."
    },
    "description": {
      "type": "string",
      "description": "Short (one-line) description of the action."
    },
    "long_description": {
      "type": "string",
      "description": "Detailed multi-line description explaining purpose, usage, and expected outcomes."
    },
    "strategy_actor": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Actor to use during the Strategize phase. Must reference a registered actor."
    },
    "execution_actor": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Actor to use during the Execute phase. Must reference a registered actor."
    },
    "estimation_actor": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Actor for effort and cost estimation before execution."
    },
    "review_actor": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Actor for reviewing execution results."
    },
    "apply_actor": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Actor to use during the Apply phase."
    },
    "invariant_actor": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Actor for reconciling conflicting invariants across scopes."
    },
    "definition_of_done": {
      "type": "string",
      "description": "Clear, measurable criteria that define when the action's work is complete."
    },
    "reusable": {
      "type": "boolean",
      "default": true,
      "description": "Whether the action persists after being used."
    },
    "read_only": {
      "type": "boolean",
      "default": false,
      "description": "Whether the action is restricted to read-only operations."
    },
    "state": {
      "type": "string",
      "enum": ["draft", "available"],
      "default": "draft",
      "description": "Initial state of the action."
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Tags for categorization, searching, and filtering."
    },
    "arguments": {
      "type": "array",
      "description": "Typed parameters that users supply when using the action via agents plan use --arg name=value.",
      "items": {
        "$ref": "#/$defs/argument"
      }
    },
    "automation_profile": {
      "type": "string",
      "description": "Default automation profile for plans created from this action."
    },
    "invariants": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Constraints carried forward as plan-level invariants when the action is used."
    }
  },
  "required": ["name", "description", "strategy_actor", "execution_actor", "definition_of_done"],
  "additionalProperties": false,
  "$defs": {
    "argument": {
      "type": "object",
      "description": "A typed parameter for the action.",
      "properties": {
        "name": {
          "type": "string",
          "description": "Argument name. Used as the key in --arg name=value."
        },
        "type": {
          "type": "string",
          "enum": ["string", "integer", "float", "boolean", "list"],
          "description": "Data type of the argument."
        },
        "required": {
          "type": "boolean",
          "default": false,
          "description": "Whether the argument must be provided."
        },
        "description": {
          "type": "string",
          "description": "Human-readable description shown in help text."
        },
        "default": {
          "description": "Default value when the argument is not provided. Type must match the 'type' field."
        },
        "validation_pattern": {
          "type": "string",
          "description": "Regex pattern for validating string arguments."
        },
        "min_value": {
          "type": "number",
          "description": "Minimum acceptable value for integer and float arguments."
        },
        "max_value": {
          "type": "number",
          "description": "Maximum acceptable value for integer and float arguments."
        }
      },
      "required": ["name", "type"],
      "additionalProperties": false
    }
  }
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Action Identity ────────────────────────────────────────────────
name: <namespace>/<name>            # Fully qualified action name (required)
description: <string>               # Short description (required)
long_description: |                 # Detailed description (optional)
  Multi-line detailed explanation of what this action does,
  when to use it, and what outcomes to expect.

# ─── Lifecycle Actors ─────────────────────────────────────────────── strategy_actor: <namespace>/<name> # Actor for the Strategize phase (required) execution_actor: <namespace>/<name> # Actor for the Execute phase (required) estimation_actor: <namespace>/<name> # Actor for effort/cost estimation (optional) review_actor: <namespace>/<name> # Actor for reviewing results (optional) apply_actor: <namespace>/<name> # Actor for the Apply phase (optional) invariant_actor: <namespace>/<name> # Invariant Reconciliation Actor (optional)

# ─── Completion Criteria ──────────────────────────────────────────── definition_of_done: | # Criteria for when the action is complete (required) Clear, measurable criteria that define success. Multiple criteria can be listed.

# ─── Action Properties ────────────────────────────────────────────── reusable: true # Keep action after use (optional, default: true) read_only: false # Restrict to read-only operations (optional, default: false) state: draft # Initial state: draft or available (optional, default: draft) tags: # Tags for categorization and filtering (optional)

  • <string>

# ─── Arguments ────────────────────────────────────────────────────── # Arguments are typed parameters that must be supplied when using # the action via agents plan use --arg name=value. arguments:

  • name: <string> # Argument name (required) type: string | integer | float | boolean | list # Argument type (required) required: true # Whether the argument must be provided (optional, default: false) description: <string> # Human-readable description (optional) default: <value> # Default value when not provided (optional) validation_pattern: <regex> # Regex pattern for string validation (optional) min_value: <number> # Minimum value for numeric types (optional) max_value: <number> # Maximum value for numeric types (optional)

# ─── Automation ───────────────────────────────────────────────────── automation_profile: <string> # Default automation profile name (optional)

# ─── Invariants ───────────────────────────────────────────────────── # Invariants carried forward as plan-level invariants when this action is used. invariants:

  • <string> # Invariant text

Structure Reference

Top-Level Fields

Field Type Required Description
name string Yes Fully qualified action name in <namespace>/<name> format. Can be overridden by the CLI <NAME> argument.
description string Yes Short (one-line) description of the action.
long_description string No Detailed multi-line description explaining purpose, usage, and expected outcomes.
strategy_actor string Yes Actor to use during the Strategize phase. Must reference a registered actor.
execution_actor string Yes Actor to use during the Execute phase. Must reference a registered actor.
estimation_actor string No Actor to use for effort and cost estimation before execution.
review_actor string No Actor to use for reviewing execution results.
apply_actor string No Actor to use during the Apply phase.
invariant_actor string No Actor for reconciling conflicting invariants across scopes. Carried forward to plans.
definition_of_done string Yes Clear, measurable criteria that define when the action's work is complete.
reusable boolean No Whether the action persists after being used. Default: true.
read_only boolean No Whether the action is restricted to read-only operations. Default: false.
state string No Initial state of the action: draft or available. Default: draft.
tags list No Tags for categorization, searching, and filtering.
arguments list No Typed parameters that users supply when using the action.
automation_profile string No Default automation profile for plans created from this action.
invariants list No Constraints carried forward as plan-level invariants when the action is used.

Argument Fields (arguments[])

Field Type Required Description
name string Yes Argument name. Used as the key in --arg name=value.
type string Yes Data type: string, integer, float, boolean, list.
required boolean No Whether the argument must be provided. Default: false.
description string No Human-readable description shown in help text and agents action show.
default any No Default value when the argument is not provided. Type must match type.
validation_pattern string No Regex pattern for validating string arguments.
min_value number No Minimum acceptable value for integer and float arguments.
max_value number No Maximum acceptable value for integer and float arguments.

Examples

Example 1: Simple Linting Action (Simple)

A minimal action for running linters on a project:


# lint-check.yaml
# Create: agents action create --config lint-check.yaml --available

name: local/lint-check description: "Run linting checks on the project"

strategy_actor: local/strategist execution_actor: local/executor

definition_of_done: | All linting checks pass with zero errors.

reusable: true read_only: true state: available

Usage: agents plan use local/lint-check local/api-service


Example 2: Code Coverage Action with Arguments (Medium)

An action with typed arguments, invariants, and a specific automation profile:


# code-coverage.yaml
# Create: agents action create --config code-coverage.yaml

name: local/code-coverage description: "Increase test coverage to a target percentage" long_description: | Analyzes the current test coverage of a project, identifies modules with low coverage, and generates comprehensive test suites to meet the target coverage percentage.

The action prioritizes:

  1. Business-critical modules (auth, payments)
  2. Recently modified code
  3. Error-prone areas based on git history

strategy_actor: local/strategist execution_actor: local/executor estimation_actor: local/estimator

definition_of_done: | Test coverage reaches the target_coverage_percent threshold across all specified modules. All generated tests pass. No existing tests are broken by the changes.

reusable: true read_only: false state: draft

tags:

  • testing
  • quality
  • coverage

arguments:

  • name: target_coverage_percent type: integer required: true description: "Target test coverage percentage (1-100)" min_value: 1 max_value: 100

  • name: test_command type: string required: false description: "Test framework command to use" default: "pytest --cov"

  • name: exclude_patterns type: list required: false description: "File patterns to exclude from coverage analysis" default: ["/migrations/", "**/conftest.py"]

  • name: focus_modules type: list required: false description: "Specific modules to prioritize for coverage"

automation_profile: trusted

invariants:

  • "Generated tests must not import production secrets or credentials"
  • "Test files must follow the project's existing test naming conventions"
  • "All database interactions in tests must use mocks or fixtures"

Usage: agents plan use local/code-coverage local/api-service --arg target_coverage_percent=85


Example 3: Security Audit Action (Complex)

A comprehensive security audit action with multiple actors, extensive arguments, and strong invariants:


# security-audit.yaml
# Create: agents action create --config security-audit.yaml --available

name: local/security-audit description: "Comprehensive security audit of a project" long_description: | Performs a thorough security audit covering:

  • Dependency vulnerability scanning (CVEs)
  • Static Application Security Testing (SAST)
  • Authentication and authorization review
  • Input validation and injection prevention
  • Secrets detection and credential scanning
  • API security (rate limiting, CORS, headers)
  • Data handling and privacy compliance

Generates a detailed report with severity ratings (Critical, High, Medium, Low, Informational) and remediation guidance. Optionally creates fix plans for identified issues.

strategy_actor: local/security-strategist execution_actor: local/security-scanner estimation_actor: local/estimator review_actor: local/security-reviewer invariant_actor: local/invariant-resolver

definition_of_done: | All critical and high severity findings have been identified. A complete security report has been generated with:

  • Severity classification for each finding
  • Remediation steps for each finding
  • Risk score for the overall project If auto_fix is enabled, all critical findings have remediation plans created as child plans.

reusable: true read_only: false state: available

tags:

  • security
  • audit
  • compliance
  • sast

arguments:

  • name: severity_threshold type: string required: false description: "Minimum severity to include in report" default: "low" validation_pattern: "^(critical|high|medium|low|informational)$"

  • name: auto_fix type: boolean required: false description: "Automatically create fix plans for critical findings" default: false

  • name: scan_dependencies type: boolean required: false description: "Include dependency vulnerability scanning" default: true

  • name: compliance_frameworks type: list required: false description: "Compliance frameworks to check against" default: ["owasp-top-10"]

  • name: max_findings type: integer required: false description: "Maximum number of findings to report" default: 100 min_value: 1 max_value: 1000

  • name: ignore_paths type: list required: false description: "Paths to exclude from scanning" default: ["/node_modules/", "/vendor/", "/.git/"]

automation_profile: supervised

invariants:

  • "Never modify production database schemas during audit"
  • "Never execute discovered exploit code against live systems"
  • "All findings must include reproducible steps"
  • "Secrets found during scanning must be redacted in reports"
  • "Remediation fixes must not break existing tests"

Usage: agents plan use local/security-audit local/api-service local/web-app --arg auto_fix=true --arg severity_threshold=medium


Example 4: Database Migration Action (Medium)

An action for managing database schema migrations:


# db-migrate.yaml
# Create: agents action create --config db-migrate.yaml

name: local/db-migrate description: "Plan and execute database schema migrations"

strategy_actor: local/db-strategist execution_actor: local/db-executor

definition_of_done: | All migration scripts are generated and pass dry-run validation. Rollback scripts are generated for each migration. The migration can be applied without data loss.

reusable: true read_only: false

arguments:

  • name: migration_tool type: string required: false description: "Migration tool to use" default: "alembic" validation_pattern: "^(alembic|flyway|django|knex)$"

  • name: dry_run type: boolean required: false description: "Only generate and validate, do not apply" default: true

  • name: target_schema type: string required: false description: "Target schema version identifier"

automation_profile: supervised

invariants:

  • "All migrations must include corresponding rollback scripts"
  • "Data migrations must preserve existing data integrity"
  • "Schema changes must maintain backward compatibility for 24 hours"

Tool Configuration Files

Tool configuration files define namespaced, independently registered, callable operations. Tools are the atomic unit of execution — each has a name, input/output schemas, capability metadata, and an implementation. Tools are registered via agents tool add --config <file> and can then be referenced by name in skills and actor graphs.

JSON Schema

The following is the formal JSON Schema definition for tool configuration files.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/tool-config.json",
  "title": "CleverAgents Tool Configuration",
  "description": "Configuration file schema for defining CleverAgents tools — namespaced, independently registered, callable operations.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified tool name in <namespace>/<name> format."
    },
    "description": {
      "type": "string",
      "description": "Human-readable description of the tool's purpose and behavior."
    },
    "source": {
      "type": "string",
      "enum": ["custom", "mcp", "agent_skill", "builtin"],
      "description": "Tool source type. Determines which implementation fields are required."
    },
    "code": {
      "type": "string",
      "description": "Python code implementing the tool. Required when source is 'custom'. Must define a run(input_data) function."
    },
    "mcp_server": {
      "type": "string",
      "description": "Name of the MCP server exposing this tool. Required when source is 'mcp'."
    },
    "mcp_tool_name": {
      "type": "string",
      "description": "Name of the tool on the MCP server. Required when source is 'mcp'."
    },
    "agent_skill_path": {
      "type": "string",
      "description": "Path to the Agent Skills Standard folder containing SKILL.md. Required when source is 'agent_skill'."
    },
    "input_schema": {
      "$ref": "https://json-schema.org/draft/2020-12/schema",
      "description": "JSON Schema describing the tool's input parameters."
    },
    "output_schema": {
      "$ref": "https://json-schema.org/draft/2020-12/schema",
      "description": "JSON Schema describing the tool's output format."
    },
    "writes": {
      "type": "boolean",
      "default": false,
      "description": "Whether the tool performs any write operations."
    },
    "write_scope": {
      "type": "string",
      "description": "Scope of write operations (e.g., 'filesystem', 'database:migrations', 'api:github')."
    },
    "checkpointable": {
      "type": "boolean",
      "default": false,
      "description": "Whether the tool supports checkpointing — saving state before execution and restoring on failure."
    },
    "checkpoint_scope": {
      "type": "string",
      "enum": ["file", "transaction", "snapshot", "composite"],
      "description": "The checkpointing strategy."
    },
    "side_effects": {
      "type": "array",
      "items": { "type": "string" },
      "default": [],
      "description": "Side effects that cannot be undone by checkpointing alone (e.g., 'network_call', 'schema_mutation', 'email_sent')."
    },
    "idempotent": {
      "type": "boolean",
      "default": false,
      "description": "Whether the tool is safe to retry — calling it multiple times with the same input produces the same result."
    },
    "read_only": {
      "type": "boolean",
      "default": false,
      "description": "Whether the tool only reads data without modifying anything."
    },
    "unsafe": {
      "type": "boolean",
      "default": false,
      "description": "Whether the tool is flagged as unsafe. Requires allow_unsafe_tools: true in the automation profile."
    },
    "timeout": {
      "type": "integer",
      "default": 300,
      "minimum": 1,
      "description": "Default execution timeout in seconds."
    },
    "resource_slots": {
      "type": "array",
      "description": "Declared resource dependencies for this tool.",
      "items": {
        "$ref": "#/$defs/resourceSlot"
      }
    },
    "lifecycle": {
      "type": "object",
      "description": "Lifecycle hook implementations.",
      "properties": {
        "discover": {
          "type": "string",
          "description": "Python code or function name run during tool discovery."
        },
        "activate": {
          "type": "string",
          "description": "Python code or function name run when the tool is activated."
        },
        "deactivate": {
          "type": "string",
          "description": "Python code or function name run when the tool is deactivated."
        }
      },
      "additionalProperties": false
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Tags for categorization, searching, and filtering."
    }
  },
  "required": ["name", "description", "source"],
  "allOf": [
    {
      "if": { "properties": { "source": { "const": "custom" } } },
      "then": { "required": ["code"] }
    },
    {
      "if": { "properties": { "source": { "const": "mcp" } } },
      "then": { "required": ["mcp_server", "mcp_tool_name"] }
    },
    {
      "if": { "properties": { "source": { "const": "agent_skill" } } },
      "then": { "required": ["agent_skill_path"] }
    }
  ],
  "additionalProperties": false,
  "$defs": {
    "resourceSlot": {
      "type": "object",
      "description": "A declared resource dependency slot.",
      "properties": {
        "name": {
          "type": "string",
          "description": "Identifier for this resource slot."
        },
        "resource_type": {
          "type": "string",
          "description": "The resource type this slot requires (e.g., 'git-checkout', 'fs-directory')."
        },
        "access": {
          "type": "string",
          "enum": ["read_only", "read_write"],
          "description": "Access level needed."
        },
        "description": {
          "type": "string",
          "description": "Human-readable description of how the tool uses this resource."
        },
        "binding": {
          "type": "string",
          "enum": ["contextual", "static", "parameter"],
          "default": "contextual",
          "description": "How the slot is resolved at runtime."
        },
        "static_resource": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
          "description": "Fully qualified name of a specific resource. Required when binding is 'static'."
        }
      },
      "required": ["name", "resource_type", "access"],
      "if": { "properties": { "binding": { "const": "static" } } },
      "then": { "required": ["name", "resource_type", "access", "static_resource"] },
      "additionalProperties": false
    }
  }
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Tool Identity ──────────────────────────────────────────────────
name: <namespace>/<name>            # Fully qualified tool name (required)
description: <string>               # Human-readable description (required)

# ─── Source and Implementation ────────────────────────────────────── source: custom | mcp | agent_skill | builtin # Tool source type (required)

# For source: custom — inline Python implementation code: | # Python code with a run(input_data) function (required for custom) def run(input_data): param = input_data.get("param_name", "default") # ... tool logic ... return {"result": "value"}

# For source: mcp — tool exposed by an MCP server mcp_server: <string> # MCP server name (required for mcp) mcp_tool_name: <string> # Tool name on the MCP server (required for mcp)

# For source: agent_skill — tool from an Agent Skills Standard folder agent_skill_path: <string> # Path to the SKILL.md folder (required for agent_skill)

# ─── Input/Output Schema ──────────────────────────────────────────── input_schema: # JSON Schema for tool inputs (optional but recommended) type: object properties: param_name: type: string description: "Parameter description" enum: ["value1", "value2"] # Enumerated valid values (optional) default: "value1" # Default value (optional) numeric_param: type: integer description: "A numeric parameter" minimum: 0 # Minimum value (optional) maximum: 100 # Maximum value (optional) required: ["param_name"] # Required parameters

output_schema: # JSON Schema for tool outputs (optional) type: object properties: result: type: string success: type: boolean

# ─── Capability Metadata ──────────────────────────────────────────── writes: false # Whether the tool performs write operations (optional, default: false) write_scope: <string> # Scope of writes, e.g. "filesystem", "database:migrations" (optional) checkpointable: false # Whether the tool supports checkpointing (optional, default: false) checkpoint_scope: <string> # Checkpointing strategy: "file", "transaction", "snapshot", "composite" (optional) side_effects: # List of side effect types (optional)

  • <string> # e.g. "network_call", "schema_mutation", "process_spawn" idempotent: false # Whether the tool is safe to retry (optional, default: false) read_only: false # Whether the tool only reads (optional, default: false) unsafe: false # Whether the tool is flagged as unsafe (optional, default: false) timeout: 300 # Default execution timeout in seconds (optional, default: 300)

# ─── Resource Bindings ────────────────────────────────────────────── # Declare which resources this tool operates on. resource_slots:

  • name: <string> # Slot name for reference (required) resource_type: <string> # Required resource type, e.g. "git-checkout", "fs-directory" (required) access: read_only | read_write # Access level needed (required) description: <string> # Description of how the resource is used (optional) binding: contextual | static | parameter # How the slot is resolved (optional, default: contextual) static_resource: <namespace>/<name> # Specific resource (required when binding is static)

# ─── Lifecycle Hooks ──────────────────────────────────────────────── lifecycle: discover: <string> # Python function or code for tool discovery (optional) activate: <string> # Python function or code run when tool is activated (optional) deactivate: <string> # Python function or code run when tool is deactivated (optional)

# ─── Tags ─────────────────────────────────────────────────────────── tags: # Tags for categorization and filtering (optional)

  • <string>

Structure Reference

Top-Level Fields

Field Type Required Description
name string Yes Fully qualified tool name in <namespace>/<name> format. Can be overridden by the CLI <NAME> argument.
description string Yes Human-readable description of the tool's purpose and behavior.
source string Yes Tool source type. Determines which implementation fields are required: custom (inline Python), mcp (MCP server), agent_skill (SKILL.md folder), builtin (first-party operations).
code string Conditional Python code implementing the tool. Required when source is custom. Must define a run(input_data) function that accepts a dict and returns a dict.
mcp_server string Conditional Name of the MCP server exposing this tool. Required when source is mcp.
mcp_tool_name string Conditional Name of the tool on the MCP server. Required when source is mcp.
agent_skill_path string Conditional Path to the Agent Skills Standard folder containing SKILL.md. Required when source is agent_skill.
input_schema object No JSON Schema describing the tool's input parameters. Strongly recommended for all tools.
output_schema object No JSON Schema describing the tool's output format.
tags list No Tags for categorization, searching, and filtering.

Capability Metadata Fields

Field Type Default Description
writes boolean false Whether the tool performs any write operations (file writes, database mutations, API calls with side effects).
write_scope string Describes the scope of write operations, e.g. "filesystem", "database:migrations", "api:github". Used for permission checks and audit logging.
checkpointable boolean false Whether the tool supports checkpointing — the ability to save state before execution and restore it on failure.
checkpoint_scope string The checkpointing strategy: file (file-level backup), transaction (database transaction), snapshot (full state snapshot), composite (multi-resource checkpoint).
side_effects list [] Descriptions of side effects that cannot be undone by checkpointing alone, e.g. "network_call", "schema_mutation", "email_sent", "process_spawn".
idempotent boolean false Whether the tool is safe to retry — calling it multiple times with the same input produces the same result.
read_only boolean false Whether the tool only reads data without modifying anything. When true, writes must be false.
unsafe boolean false Whether the tool is flagged as unsafe. Unsafe tools require allow_unsafe_tools: true in the automation profile.
timeout integer 300 Default execution timeout in seconds. Can be overridden per invocation.

Resource Slot Fields (resource_slots[])

Field Type Required Description
name string Yes Identifier for this resource slot, used for reference in code and logs.
resource_type string Yes The resource type this slot requires, e.g. git-checkout, fs-directory, fs-file.
access string Yes Access level: read_only or read_write.
description string No Human-readable description of how the tool uses this resource.
binding string No How the slot is resolved at runtime. contextual (default): resolved from the plan's project. static: hardcoded to a specific resource. parameter: passed as a tool argument at invocation time.
static_resource string Conditional Fully qualified name of a specific resource. Required when binding is static.

Lifecycle Hook Fields (lifecycle)

Field Type Required Description
discover string No Code or function name run during tool discovery to check prerequisites and report capabilities.
activate string No Code or function name run when the tool is activated (e.g., establish connections, validate credentials).
deactivate string No Code or function name run when the tool is deactivated (e.g., close connections, release resources).

Examples

Example 1: Simple Read-Only Tool (Simple)

A tool that reads a file and returns its contents:


# read-config-file.yaml
# Register: agents tool add --config read-config-file.yaml

name: local/read-config description: "Read and parse a configuration file (JSON, YAML, or TOML)"

source: custom code: | import json, os def run(input_data): path = input_data["path"] if not os.path.exists(path): return {"error": f"File not found: {path}", "success": False} with open(path, "r") as f: content = f.read() ext = os.path.splitext(path)[1].lower() if ext == ".json": parsed = json.loads(content) elif ext in (".yaml", ".yml"): import yaml parsed = yaml.safe_load(content) else: parsed = None return {"content": content, "parsed": parsed, "path": path, "success": True}

input_schema: type: object properties: path: type: string description: "Path to the configuration file" required: ["path"]

output_schema: type: object properties: content: type: string parsed: type: object success: type: boolean

writes: false read_only: true idempotent: true tags:

  • files
  • configuration
  • read-only

Example 2: Database Migration Tool (Medium)

A tool that runs database migrations with rollback support:


# run-migrations.yaml
# Register: agents tool add --config run-migrations.yaml

name: local/run-migrations description: "Run database migrations with direction control and rollback support"

source: custom code: | import subprocess def run(input_data): direction = input_data.get("direction", "up") count = input_data.get("count", 1) dry_run = input_data.get("dry_run", False)

  cmd = [&quot;alembic&quot;]
  if dry_run:
      cmd.append(&quot;<span style="color: cyan;">--sql</span>&quot;)
  cmd.extend([direction, str(count)])

  result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
  return {
      <span style="color: cyan; font-weight: 600;">&quot;success&quot;</span>: result.returncode == 0,
      <span style="color: cyan; font-weight: 600;">&quot;stdout&quot;</span>: result.stdout,
      <span style="color: cyan; font-weight: 600;">&quot;stderr&quot;</span>: result.stderr,
      <span style="color: cyan; font-weight: 600;">&quot;direction&quot;</span>: direction,
      <span style="color: cyan; font-weight: 600;">&quot;count&quot;</span>: count,
      <span style="color: cyan; font-weight: 600;">&quot;dry_run&quot;</span>: dry_run,
      <span style="color: cyan; font-weight: 600;">&quot;return_code&quot;</span>: result.returncode
  }

input_schema: type: object properties: direction: type: string enum: ["up", "down"] description: "Migration direction: 'up' to apply, 'down' to rollback" count: type: integer default: 1 minimum: 1 maximum: 50 description: "Number of migrations to run" dry_run: type: boolean default: false description: "Generate SQL without executing" required: ["direction"]

writes: true write_scope: "database:migrations" checkpointable: true checkpoint_scope: "transaction" side_effects:

  • "schema_mutation" idempotent: false timeout: 120

resource_slots:

  • name: database resource_type: "local/database" access: read_write description: "The database to run migrations against" binding: contextual

tags:

  • database
  • migrations
  • schema

Example 3: MCP-Backed GitHub Tool (Simple)

A tool that delegates to a GitHub MCP server:


# github-create-issue.yaml
# Register: agents tool add --config github-create-issue.yaml

name: local/github-create-issue description: "Create a GitHub issue via the GitHub MCP server"

source: mcp mcp_server: github mcp_tool_name: create_issue

input_schema: type: object properties: owner: type: string description: "Repository owner" repo: type: string description: "Repository name" title: type: string description: "Issue title" body: type: string description: "Issue body (Markdown)" labels: type: array items: type: string description: "Labels to apply" required: ["owner", "repo", "title"]

writes: true write_scope: "api:github" checkpointable: false side_effects:

  • "network_call" idempotent: false

tags:

  • github
  • issues
  • project-management

Example 4: Deployment Tool with Resource Bindings (Complex)

A comprehensive deployment tool with multiple resource slots, lifecycle hooks, and safety metadata:


# deploy-staging.yaml
# Register: agents tool add --config deploy-staging.yaml

name: local/deploy-staging description: "Deploy the current build to the staging environment with health checks"

source: custom code: | import subprocess, time, urllib.request, json

def run(input_data): service = input_data["service"] version = input_data.get("version", "latest") wait_healthy = input_data.get("wait_healthy", True) health_timeout = input_data.get("health_timeout", 120)

# Build the deployment command cmd = ["kubectl", "set", "image", f"deployment/{service}", f"{service}={service}:{version}", "--namespace=staging"] result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) if result.returncode != 0: return {"success": False, "error": result.stderr, "phase": "deploy"}

# Wait for rollout rollout = subprocess.run( ["kubectl", "rollout", "status", f"deployment/{service}", "--namespace=staging", f"--timeout={health_timeout}s"], capture_output=True, text=True, timeout=health_timeout + 10 ) if rollout.returncode != 0: return {"success": False, "error": rollout.stderr, "phase": "rollout"}

# Health check if wait_healthy: health_url = f"http://{service}.staging.svc.cluster.local/health" start = time.time() while time.time() - start < health_timeout: try: resp = urllib.request.urlopen(health_url, timeout=5) if resp.status == 200: body = json.loads(resp.read()) if body.get("status") == "healthy": return { "success": True, "service": service, "version": version, "health": body } except Exception: pass time.sleep(5) return {"success": False, "error": "Health check timeout", "phase": "health"}

  return {&quot;success&quot;: True, &quot;service&quot;: service, &quot;version&quot;: version}

input_schema: type: object properties: service: type: string description: "Name of the service to deploy" version: type: string default: "latest" description: "Docker image version tag" wait_healthy: type: boolean default: true description: "Wait for health check to pass" health_timeout: type: integer default: 120 minimum: 10 maximum: 600 description: "Health check timeout in seconds" required: ["service"]

output_schema: type: object properties: success: type: boolean service: type: string version: type: string error: type: string phase: type: string

writes: true write_scope: "infrastructure:kubernetes" checkpointable: true checkpoint_scope: "composite" side_effects:

  • "network_call"
  • "process_spawn"
  • "infrastructure_mutation" idempotent: false unsafe: true timeout: 300

resource_slots:

  • name: repo resource_type: git-checkout access: read_only description: "Source repository for build artifacts" binding: contextual
  • name: cluster_config resource_type: fs-file access: read_only description: "Kubernetes cluster configuration (kubeconfig)" binding: static static_resource: local/staging-kubeconfig

lifecycle: activate: | def activate(context): import subprocess result = subprocess.run(["kubectl", "cluster-info"], capture_output=True, text=True) if result.returncode != 0: raise RuntimeError("Cannot connect to Kubernetes cluster") return {"cluster": "connected"} deactivate: | def deactivate(context): pass # No cleanup needed

tags:

  • deployment
  • staging
  • kubernetes
  • infrastructure

Example 5: API Compatibility Checker (Medium)

A tool that validates API backward compatibility:


# validate-api-compat.yaml
# Register: agents tool add --config validate-api-compat.yaml

name: local/validate-api-compat description: "Validate that API changes maintain backward compatibility with existing clients"

source: custom code: | import subprocess, json

def run(input_data): spec_path = input_data.get("spec_path", "openapi.yaml") base_branch = input_data.get("base_branch", "main")

# Get the base spec from the main branch base_result = subprocess.run( ["git", "show", f"{base_branch}:{spec_path}"], capture_output=True, text=True ) if base_result.returncode != 0: return {"compatible": True, "reason": "No base spec found (new API)", "changes": []}

# Run OpenAPI diff diff_result = subprocess.run( ["oasdiff", "breaking", "--format", "json", "--base", "/dev/stdin", "--revision", spec_path], input=base_result.stdout, capture_output=True, text=True )

  if diff_result.returncode == 0:
      return {&quot;compatible&quot;: True, &quot;changes&quot;: [], &quot;reason&quot;: &quot;No breaking changes&quot;}

  <span style="color: cyan; font-weight: 600;">try</span>:
      breaking = json.loads(diff_result.stdout)
  except json.JSONDecodeError:
      breaking = [{&quot;description&quot;: diff_result.stdout}]

  return {
      <span style="color: cyan; font-weight: 600;">&quot;compatible&quot;</span>: False,
      <span style="color: cyan; font-weight: 600;">&quot;changes&quot;</span>: breaking,
      <span style="color: cyan; font-weight: 600;">&quot;reason&quot;</span>: f&quot;Found {len(breaking)} breaking change(s)&quot;
  }

input_schema: type: object properties: spec_path: type: string default: "openapi.yaml" description: "Path to the OpenAPI specification file" base_branch: type: string default: "main" description: "Branch to compare against for backward compatibility" required: []

writes: false read_only: true checkpointable: false idempotent: true timeout: 60

resource_slots:

  • name: repo resource_type: git-checkout access: read_only description: "Git repository containing the API spec" binding: contextual

tags:

  • api
  • validation
  • compatibility
  • openapi

Resource Type Configuration Files

Resource type configuration files define custom resource type schemas that extend the built-in resource types (git-checkout, git, fs-mount, fs-directory, etc.). A resource type defines what CLI arguments agents resource add <type> accepts, whether instances are physical or virtual, allowed child/parent types, auto-discovery behavior, sandbox strategy, and handler implementation. Custom types are registered via agents resource type add --config <file>.

JSON Schema

The following is the formal JSON Schema definition for resource type configuration files.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/resource-type-config.json",
  "title": "CleverAgents Resource Type Configuration",
  "description": "Configuration file schema for defining custom resource types that extend the built-in resource types.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified resource type name in <namespace>/<name> format."
    },
    "description": {
      "type": "string",
      "description": "Human-readable description of what this resource type represents."
    },
    "physical": {
      "type": "boolean",
      "description": "true for physical types (concrete manifestations), false for virtual types (abstract identity linking equivalent physical resources)."
    },
    "user_addable": {
      "type": "boolean",
      "default": true,
      "description": "Whether users can create instances directly via 'agents resource add <type>'."
    },
    "cli_args": {
      "type": "array",
      "description": "Arguments accepted by 'agents resource add <type>'.",
      "items": {
        "$ref": "#/$defs/cliArg"
      }
    },
    "child_types": {
      "type": "array",
      "description": "Resource types that can be children of this type.",
      "items": {
        "$ref": "#/$defs/childType"
      }
    },
    "parent_types": {
      "type": "array",
      "description": "Resource types that can be parents of this type. If omitted, the resource can be top-level.",
      "items": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Parent resource type name."
          },
          "description": {
            "type": "string",
            "description": "Description of the parent-child relationship from the child's perspective."
          }
        },
        "required": ["type"],
        "additionalProperties": false
      }
    },
    "sandbox_strategy": {
      "type": "string",
      "enum": ["git_worktree", "copy_on_write", "transaction_rollback", "snapshot", "none"],
      "description": "Sandbox strategy for instances of this type."
    },
    "handler": {
      "type": "object",
      "description": "The Python handler class that implements resource operations.",
      "properties": {
        "class": {
          "type": "string",
          "description": "Python class name that implements the resource handler interface."
        },
        "module": {
          "type": "string",
          "description": "Python module path where the handler class is defined."
        },
        "config": {
          "type": "object",
          "description": "Arbitrary configuration passed to the handler constructor.",
          "additionalProperties": true
        }
      },
      "required": ["class", "module"],
      "additionalProperties": false
    },
    "auto_discovery": {
      "type": "object",
      "description": "Controls automatic child resource discovery when a resource of this type is created.",
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether auto-discovery runs when a resource of this type is created."
        },
        "scan_depth": {
          "type": "integer",
          "default": 3,
          "minimum": 1,
          "description": "Maximum recursion depth for scanning."
        },
        "include_patterns": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Glob patterns for resources to discover."
        },
        "exclude_patterns": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Glob patterns for resources to skip during discovery."
        }
      },
      "additionalProperties": false
    },
    "equivalence": {
      "type": "object",
      "description": "Equivalence criteria for virtual types. Only applicable when physical is false.",
      "properties": {
        "criteria": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Fields used to determine equivalence (e.g., 'content_hash', 'filename', 'permissions', 'url')."
        },
        "description": {
          "type": "string",
          "description": "Human-readable description of the equivalence rule."
        }
      },
      "required": ["criteria"],
      "additionalProperties": false
    },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Tags for categorization, searching, and filtering."
    }
  },
  "required": ["name", "description", "physical", "sandbox_strategy", "handler"],
  "if": {
    "properties": { "physical": { "const": false } }
  },
  "then": {
    "required": ["name", "description", "physical", "sandbox_strategy", "handler", "equivalence"]
  },
  "additionalProperties": false,
  "$defs": {
    "cliArg": {
      "type": "object",
      "description": "A CLI argument definition for 'agents resource add <type>'.",
      "properties": {
        "name": {
          "type": "string",
          "description": "Argument name. Becomes --<name> on the CLI."
        },
        "type": {
          "type": "string",
          "enum": ["string", "path", "integer", "boolean", "url"],
          "description": "Argument type. 'path' validates that the path exists; 'url' validates URL format."
        },
        "required": {
          "type": "boolean",
          "default": false,
          "description": "Whether the argument must be provided."
        },
        "description": {
          "type": "string",
          "description": "Description shown in --help."
        },
        "default": {
          "description": "Default value when the argument is not provided."
        },
        "validation_pattern": {
          "type": "string",
          "description": "Regex pattern for validating string and url type arguments."
        }
      },
      "required": ["name", "type"],
      "additionalProperties": false
    },
    "childType": {
      "type": "object",
      "description": "An allowed child resource type relationship.",
      "properties": {
        "type": {
          "type": "string",
          "description": "Child resource type name."
        },
        "auto_discover": {
          "type": "boolean",
          "default": false,
          "description": "Whether children of this type are automatically created when the parent resource is registered."
        },
        "manual_link": {
          "type": "boolean",
          "default": true,
          "description": "Whether manual 'agents resource link-child' is allowed for this relationship."
        },
        "description": {
          "type": "string",
          "description": "Description of the parent-child relationship."
        },
        "max_count": {
          "type": ["integer", "null"],
          "minimum": 1,
          "description": "Maximum number of children of this type. null or omitted means unlimited."
        }
      },
      "required": ["type"],
      "additionalProperties": false
    }
  }
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Resource Type Identity ─────────────────────────────────────────
name: <namespace>/<name>            # Fully qualified resource type name (required)
description: <string>               # Human-readable description (required)

# ─── Type Classification ──────────────────────────────────────────── physical: true # Whether instances are physical or virtual (required) # Physical: a specific, concrete manifestation (this file at this path) # Virtual: an abstract identity linking equivalent physical resources user_addable: true # Whether users can create instances directly (optional, default: true)

# ─── CLI Arguments ────────────────────────────────────────────────── # Define the arguments accepted by agents resource add &lt;type&gt;. cli_args:

  • name: <string> # Argument name (becomes --<name> on CLI) (required) type: string | path | integer | boolean | url # Argument type (required) required: true # Whether the argument is required (optional, default: false) description: <string> # Description shown in help text (optional) default: <value> # Default value (optional) validation_pattern: <regex> # Regex validation for string/url types (optional)

# ─── Parent/Child Type Relationships ──────────────────────────────── # Define which resource types can be children of this type. child_types:

  • type: <string> # Child resource type name (required) auto_discover: true # Automatically create children when parent is created (optional, default: false) manual_link: true # Allow manual parent-child linking (optional, default: true) description: <string> # Description of the relationship (optional) max_count: <integer> # Maximum number of children of this type (optional, null = unlimited)

# Define which resource types can be parents of this type. parent_types:

  • type: <string> # Parent resource type name (required) description: <string> # Description of the relationship (optional) # If parent_types is omitted, the resource can be top-level (no parent required).

# ─── Sandbox Strategy ────────────────────────────────────────────── sandbox_strategy: <string> # Sandbox strategy for instances of this type (required) # Built-in strategies: "git_worktree", "copy_on_write", # "transaction_rollback", "snapshot", "none"

# ─── Handler Implementation ──────────────────────────────────────── handler: class: <string> # Python class implementing the resource handler (required) module: <string> # Python module path (required) config: {} # Handler-specific configuration (optional)

# ─── Auto-Discovery Configuration ────────────────────────────────── auto_discovery: enabled: true # Whether child auto-discovery runs on creation (optional, default: true) scan_depth: <integer> # Max depth for recursive scanning (optional, default: 3) include_patterns: # Glob patterns for resources to auto-discover (optional) - <string> exclude_patterns: # Glob patterns to exclude from auto-discovery (optional) - <string>

# ─── Virtual Type Configuration ───────────────────────────────────── # Only applicable when physical: false (virtual types). equivalence: criteria: # Fields used to determine equivalence (required for virtual) - <string> # e.g. "content_hash", "filename", "permissions", "url" description: <string> # Human-readable description of the equivalence rule (optional)

Structure Reference

Top-Level Fields

Field Type Required Description
name string Yes Fully qualified resource type name in <namespace>/<name> format. Can be overridden by the CLI <NAME> argument.
description string Yes Human-readable description of what this resource type represents.
physical boolean Yes true for physical types (concrete manifestations), false for virtual types (abstract identity linking equivalent physical resources).
user_addable boolean No Whether users can create instances directly via agents resource add <type>. Default: true. When false, instances are only created via auto-discovery as children of other resources.
sandbox_strategy string Yes The sandbox strategy used when executing within this resource type.
handler object Yes The Python handler class that implements resource operations.

CLI Argument Fields (cli_args[])

Field Type Required Description
name string Yes Argument name. Becomes --<name> on the CLI.
type string Yes Argument type: string, path, integer, boolean, url. The path type validates that the path exists; url type validates URL format.
required boolean No Whether the argument must be provided. Default: false.
description string No Description shown in --help and agents resource type show.
default any No Default value when the argument is not provided.
validation_pattern string No Regex pattern for validating string and url type arguments.

Child Type Fields (child_types[])

Field Type Required Description
type string Yes Name of the allowed child resource type (e.g., fs-directory, svn-file).
auto_discover boolean No Whether children of this type are automatically created when the parent resource is registered. Default: false.
manual_link boolean No Whether manual agents resource link-child is allowed for this relationship. Default: true.
description string No Description of the parent-child relationship.
max_count integer No Maximum number of children of this type. null or omitted means unlimited.

Parent Type Fields (parent_types[])

Field Type Required Description
type string Yes Name of the allowed parent resource type.
description string No Description of the parent-child relationship from the child's perspective.

Handler Fields (handler)

Field Type Required Description
class string Yes Python class name that implements the resource handler interface.
module string Yes Python module path where the handler class is defined.
config object No Arbitrary configuration passed to the handler constructor.

Auto-Discovery Fields (auto_discovery)

Field Type Required Description
enabled boolean No Whether auto-discovery runs when a resource of this type is created. Default: true.
scan_depth integer No Maximum recursion depth for scanning. Default: 3.
include_patterns list No Glob patterns for resources to discover.
exclude_patterns list No Glob patterns for resources to skip during discovery.

Equivalence Fields (equivalence) — Virtual Types Only

Field Type Required Description
criteria list Yes (virtual) Fields used to determine whether two physical resources are equivalent. Common criteria: content_hash, filename, permissions, url, commit_hash, tree_hash.
description string No Human-readable description of the equivalence rule.

Built-in Sandbox Strategies

Strategy Description
git_worktree Creates a git worktree for isolated execution. Changes are committed to a branch and merged on apply.
copy_on_write Creates a CoW copy of the resource. Changes are applied by replacing the original.
transaction_rollback Wraps operations in a database transaction. Rolled back on failure, committed on apply.
snapshot Takes a full snapshot before execution. Restored on rollback.
none No sandbox. Changes are applied directly. Use only for read-only or idempotent operations.

Examples

Example 1: Simple SVN Repository Type (Simple)

A custom resource type for Subversion repositories:


# svn-type.yaml
# Register: agents resource type add --config svn-type.yaml

name: local/svn description: "A Subversion (SVN) repository checkout"

physical: true user_addable: true

cli_args:

  • name: url type: url required: true description: "SVN repository URL" validation_pattern: "^svn(\+ssh)?://.|^https?://."
  • name: checkout-path type: path required: true description: "Local checkout directory"
  • name: revision type: string required: false description: "Specific revision to checkout" default: "HEAD"

child_types:

  • type: fs-directory auto_discover: true description: "Working copy directory tree"
  • type: local/svn-revision auto_discover: true description: "SVN revision history"

sandbox_strategy: copy_on_write

handler: class: SVNHandler module: cleveragents.resources.handlers.svn config: svn_binary: "svn" trust_server_cert: true

auto_discovery: enabled: true scan_depth: 2 exclude_patterns: - "/.svn/"

tags:

  • version-control
  • svn

Usage: agents resource add local/svn local/legacy-repo --url svn://svn.example.com/trunk --checkout-path /repos/legacy


Example 2: S3 Bucket Resource Type (Medium)

A resource type for Amazon S3 buckets with prefix-based child discovery:


# s3-bucket-type.yaml
# Register: agents resource type add --config s3-bucket-type.yaml

name: local/s3-bucket description: "An Amazon S3 bucket with prefix-based object organization"

physical: true user_addable: true

cli_args:

  • name: bucket type: string required: true description: "S3 bucket name" validation_pattern: "^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$"
  • name: region type: string required: false description: "AWS region" default: "us-east-1"
  • name: prefix type: string required: false description: "Key prefix to scope resource to a 'subdirectory'" default: ""
  • name: profile type: string required: false description: "AWS CLI profile name" default: "default"

child_types:

  • type: local/s3-prefix auto_discover: true description: "S3 key prefixes (virtual directories)" max_count: 1000
  • type: local/s3-object auto_discover: true description: "S3 objects (files)"

sandbox_strategy: copy_on_write

handler: class: S3BucketHandler module: cleveragents.resources.handlers.s3 config: max_object_size: 104857600 # 100 MB default_acl: "private"

auto_discovery: enabled: true scan_depth: 3 include_patterns: - "/*.json" - "/.yaml" - "**/.yml" - "/*.py" - "/.sql" exclude_patterns: - "**/.log" - "/*.tmp" - "/node_modules/**"

tags:

  • cloud
  • aws
  • s3
  • storage

Example 3: Database Resource Type (Medium)

A resource type for relational databases:


# database-type.yaml
# Register: agents resource type add --config database-type.yaml

name: local/database description: "A relational database (PostgreSQL, MySQL, SQLite)"

physical: true user_addable: true

cli_args:

  • name: connection-string type: string required: true description: "Database connection string (e.g., postgresql://user:pass@host/db)"
  • name: engine type: string required: false description: "Database engine" default: "postgresql" validation_pattern: "^(postgresql|mysql|sqlite|mssql)$"
  • name: read-only type: boolean required: false description: "Connect in read-only mode" default: false
  • name: schema type: string required: false description: "Database schema to scope to" default: "public"

child_types:

  • type: local/db-table auto_discover: true description: "Database tables"
  • type: local/db-view auto_discover: true description: "Database views"
  • type: local/db-migration auto_discover: false manual_link: true description: "Migration scripts linked to this database"

parent_types:

  • type: git-checkout description: "Repository containing the application that owns this database"

sandbox_strategy: transaction_rollback

handler: class: DatabaseHandler module: cleveragents.resources.handlers.database config: connection_pool_size: 5 statement_timeout: 30000 # 30 seconds log_queries: true

auto_discovery: enabled: true scan_depth: 1

tags:

  • database
  • relational
  • sql

Example 4: Virtual File Type (Simple)

A virtual resource type that links equivalent physical files across repositories:


# virtual-config-file-type.yaml
# Register: agents resource type add --config virtual-config-file-type.yaml

name: local/config-file description: "Virtual type linking equivalent configuration files across repositories"

physical: false user_addable: false

child_types:

  • type: fs-file auto_discover: false manual_link: true description: "Physical file instances"
  • type: git-tree-entry auto_discover: false manual_link: true description: "Git tree entries representing the same config file"

sandbox_strategy: none

handler: class: VirtualConfigFileHandler module: cleveragents.resources.handlers.virtual_config config: track_content_drift: true

equivalence: criteria: - content_hash - filename description: "Two physical resources represent the same config file when they share the same filename and content hash"


Example 5: Docker Registry Resource Type (Complex)

A resource type for Docker container registries with full auto-discovery and lifecycle hooks:


# docker-registry-type.yaml
# Register: agents resource type add --config docker-registry-type.yaml

name: local/docker-registry description: "A Docker container registry with image and tag discovery"

physical: true user_addable: true

cli_args:

  • name: registry-url type: url required: true description: "Docker registry URL (e.g., registry.example.com, ghcr.io/org)" validation_pattern: "^[a-zA-Z0-9][a-zA-Z0-9.-]+(:[0-9]+)?(/[a-zA-Z0-9._-]+)*$"
  • name: username type: string required: false description: "Registry username for authentication"
  • name: password-env type: string required: false description: "Environment variable name containing the registry password"
  • name: namespace type: string required: false description: "Image namespace or organization filter"

child_types:

  • type: local/docker-image auto_discover: true description: "Docker images in the registry" max_count: 500
  • type: local/docker-tag auto_discover: true description: "Image tags"

sandbox_strategy: none

handler: class: DockerRegistryHandler module: cleveragents.resources.handlers.docker config: api_version: "v2" page_size: 100 cache_ttl: 300

auto_discovery: enabled: true scan_depth: 2 include_patterns: - "/latest" - "/main" - "/release-*" exclude_patterns: - "/sha256:" - "**/-dirty"

tags:

  • docker
  • containers
  • registry
  • infrastructure

Context View Configuration

Context views control how project resources are filtered and presented to actors during different plan phases. They are managed via agents project context set and its associated CLI flags, but can also be defined declaratively in YAML for portability and version control.

JSON Schema

The following is the formal JSON Schema definition for context view configuration files.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/context-view-config.json",
  "title": "CleverAgents Context View Configuration",
  "description": "Configuration file schema for defining context views that control how project resources are filtered and presented to actors during plan phases.",
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified project name this view applies to."
    },
    "view": {
      "type": "string",
      "enum": ["default", "strategize", "execute", "apply"],
      "description": "Phase view. 'default' is the fallback for all phases; phase-specific views override 'default'."
    },
    "include_resources": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Whitelist of resource names to include. When specified, only these resources provide context."
    },
    "exclude_resources": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Blacklist of resource names to exclude. Applied after include_resources."
    },
    "include_paths": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Glob patterns for file paths to include. When specified, only matching files are included."
    },
    "exclude_paths": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Glob patterns for file paths to exclude. Applied after include_paths."
    },
    "hot_max_tokens": {
      "type": ["integer", "null"],
      "minimum": 1,
      "description": "Soft cap on the number of tokens in hot (immediate) context. null means no soft cap."
    },
    "warm_max_decisions": {
      "type": "integer",
      "minimum": 1,
      "description": "Maximum number of decisions retained in warm context."
    },
    "cold_max_decisions": {
      "type": "integer",
      "minimum": 1,
      "description": "Maximum number of decisions retained in cold context."
    },
    "query_limit": {
      "type": "integer",
      "default": 20,
      "minimum": 1,
      "description": "Maximum number of retrieval results per query against the cold tier."
    },
    "max_file_size": {
      "type": "integer",
      "default": 1048576,
      "minimum": 1,
      "description": "Maximum individual file size in bytes that will be included in context. Default: 1 MB."
    },
    "max_total_size": {
      "type": "integer",
      "default": 52428800,
      "minimum": 1,
      "description": "Maximum aggregate size in bytes across all included files. Default: 50 MB."
    },
    "summarize": {
      "type": "boolean",
      "default": false,
      "description": "When true, large context segments are automatically summarized rather than excluded."
    },
    "summary_max_tokens": {
      "type": "integer",
      "minimum": 1,
      "description": "Maximum tokens for each generated summary. Only applies when summarize is true."
    }
  },
  "required": ["project", "view"],
  "additionalProperties": false
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Context View Identity ──────────────────────────────────────────
project: <namespace>/<name>         # Project this context view applies to (required)
view: default | strategize | execute | apply  # Which phase view (required)

# ─── Resource Filtering ───────────────────────────────────────────── include_resources: # Resources to include (whitelist, optional)

  • <resource_name> exclude_resources: # Resources to exclude (blacklist, optional)
  • <resource_name>

# ─── Path Filtering ───────────────────────────────────────────────── include_paths: # Glob patterns for files to include (optional)

  • "src/**/*.py"
  • "tests/**/*.py" exclude_paths: # Glob patterns for files to exclude (optional)
  • "/node_modules/"
  • "/pycache/"
  • "/.git/"
  • "/dist/"

# ─── Token and Size Budgets ───────────────────────────────────────── hot_max_tokens: <integer> # Soft cap on hot context tokens (optional, null = no limit) warm_max_decisions: <integer> # Max decisions in warm context (optional) cold_max_decisions: <integer> # Max decisions in cold context (optional) query_limit: <integer> # Max retrieval results per query (optional, default: 20) max_file_size: <integer> # Max file size in bytes to include (optional, default: 1048576) max_total_size: <integer> # Max total size across all included files (optional, default: 52428800)

# ─── Summarization ────────────────────────────────────────────────── summarize: true # Enable summarization for large context segments (optional) summary_max_tokens: <integer> # Token limit for generated summaries (optional)

Structure Reference

Top-Level Fields

Field Type Required Description
project string Yes Fully qualified project name this view applies to.
view string Yes Phase view: default (fallback for all phases), strategize, execute, or apply. Phase-specific views override the default view.
include_resources list No Whitelist of resource names to include. When specified, only these resources provide context.
exclude_resources list No Blacklist of resource names to exclude. Applied after include_resources.
include_paths list No Glob patterns for file paths to include. When specified, only matching files are included.
exclude_paths list No Glob patterns for file paths to exclude. Applied after include_paths.
hot_max_tokens integer No Soft cap on the number of tokens in hot (immediate) context. The effective limit is the lesser of this value and the actor's hard context window limit. When null, no soft cap is applied.
warm_max_decisions integer No Maximum number of decisions retained in warm context (recent decisions available for reference).
cold_max_decisions integer No Maximum number of decisions retained in cold context (older decisions queryable via search).
query_limit integer No Maximum number of retrieval results per query against the cold tier. Default: 20.
max_file_size integer No Maximum individual file size in bytes that will be included in context. Files exceeding this are either excluded or summarized. Default: 1 MB (1,048,576).
max_total_size integer No Maximum aggregate size in bytes across all included files. Default: 50 MB (52,428,800).
summarize boolean No When true, large context segments are automatically summarized rather than excluded. Default: false.
summary_max_tokens integer No Maximum tokens for each generated summary. Only applies when summarize is true.

Context Tiers

CleverAgents uses a three-tier context architecture:

Tier Description Controlled By
Hot Immediate context sent in the LLM prompt. Includes active files, recent changes, and current task description. hot_max_tokens, include_paths, exclude_paths
Warm Recent decisions and intermediate results. Available for reference but not always in the prompt. warm_max_decisions
Cold Historical decisions, full project index, and archived artifacts. Queryable via retrieval. cold_max_decisions, query_limit

View Resolution Order

When a plan enters a phase, the context view is resolved as follows:

  1. Check for a phase-specific view (e.g., strategize).
  2. Fall back to the default view.
  3. Fall back to system defaults (include all resources, no path filtering, default budgets).

Examples

Example 1: Basic Default View (Simple)

A default context view with minimal filtering:


# context-default.yaml
# Apply: agents project context set --view default --include-path "src/**" \
#        --exclude-path "**/node_modules/**" local/api-service
# Or import this file and apply via the CLI.

project: local/api-service view: default

exclude_paths:

  • "/node_modules/"
  • "/pycache/"
  • "/.git/"

max_file_size: 1048576 # 1 MB


Example 2: Strategize-Optimized View (Medium)

A focused view for the Strategize phase that limits context to essential architecture files:


# context-strategize.yaml

project: local/api-service view: strategize

include_resources:

  • local/api-repo

exclude_resources:

  • local/staging-db

include_paths:

  • "src/**/*.py"
  • "docs/architecture/**"
  • "README.md"
  • "pyproject.toml"

exclude_paths:

  • "/node_modules/"
  • "/test_fixtures/"
  • "/pycache/"
  • "/migrations/"

hot_max_tokens: 12000 warm_max_decisions: 50 cold_max_decisions: 200 query_limit: 20

max_file_size: 524288 # 512 KB max_total_size: 10485760 # 10 MB

summarize: true summary_max_tokens: 800

This view keeps the Strategize phase focused on source code and architecture docs, limits hot context to 12K tokens, and enables summarization for files that exceed the size limits.


Example 3: Execute-Phase View with Full Resources (Medium)

An execution view with broader access for implementing changes:


# context-execute.yaml

project: local/api-service view: execute

include_resources:

  • local/api-repo
  • local/staging-db

include_paths:

  • "src/**"
  • "tests/**"
  • "config/**"
  • "scripts/**"
  • "Makefile"
  • "pyproject.toml"
  • "requirements*.txt"

exclude_paths:

  • "/node_modules/"
  • "/pycache/"
  • "/dist/"
  • "**/*.pyc"

hot_max_tokens: 24000 warm_max_decisions: 100 cold_max_decisions: 500 query_limit: 30

max_file_size: 2097152 # 2 MB max_total_size: 104857600 # 100 MB

summarize: true summary_max_tokens: 1200


Example 4: Apply-Phase Minimal View (Simple)

A minimal view for the Apply phase, focused only on changed files and validation:


# context-apply.yaml

project: local/api-service view: apply

include_paths:

  • "src/**"
  • "tests/**"

exclude_paths:

  • "/pycache/"

hot_max_tokens: 8000 warm_max_decisions: 20 cold_max_decisions: 50

summarize: false


Example 5: Large Monorepo View with Aggressive Filtering (Complex)

A context view designed for a large monorepo where careful filtering is essential:


# context-monorepo-strategize.yaml

project: local/platform view: strategize

include_resources:

  • local/platform-repo

include_paths:

  • "packages/auth/**/*.ts"
  • "packages/auth/**/*.tsx"
  • "packages/shared/**/*.ts"
  • "packages/api-gateway/**/*.ts"
  • "docs/architecture/**"
  • "package.json"
  • "tsconfig.json"
  • "lerna.json"

exclude_paths:

  • "/node_modules/"
  • "/dist/"
  • "/coverage/"
  • "**/*.test.ts"
  • "**/*.spec.ts"
  • "**/*.stories.tsx"
  • "/fixtures/"
  • "/snapshots/"
  • "/generated/"

hot_max_tokens: 16000 warm_max_decisions: 30 cold_max_decisions: 150 query_limit: 15

max_file_size: 262144 # 256 KB - aggressive for a monorepo max_total_size: 5242880 # 5 MB

summarize: true summary_max_tokens: 600

This configuration is tailored for a TypeScript monorepo, focusing on specific packages and excluding generated code, tests, and build artifacts to keep context within manageable bounds.


Automation Profile Configuration Files

Automation profile configuration files define named collections of confidence thresholds (floating-point values from 0.0 to 1.0) and boolean safety flags controlling which operations are automated vs. requiring human approval. Each threshold specifies the minimum confidence score at which the system proceeds automatically; below the threshold, the system drops to manual mode. A threshold of 0.0 means "always automatic" and 1.0 means "always manual." Built-in profiles (manual, review, supervised, cautious, trusted, auto, ci, full-auto) are always available. Custom profiles are registered via agents automation-profile add --config <file>.

JSON Schema

The following is the formal JSON Schema definition for automation profile configuration files.


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/automation-profile-config.json",
  "title": "CleverAgents Automation Profile Configuration",
  "description": "Configuration file schema for defining automation profiles — named collections of confidence thresholds (0.0-1.0) and boolean safety flags controlling which operations are automated vs. requiring human approval.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified profile name in <namespace>/<name> format."
    },
    "description": {
      "type": "string",
      "description": "Human-readable description of the profile's purpose and behavior."
    },
    "auto_strategize": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically transitioning from Action to Strategize. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_execute": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically transitioning from Strategize to Execute. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_apply": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically applying changes after execution completes. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_decisions_strategize": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for autonomously making decisions during Strategize. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_decisions_execute": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for autonomously making decisions during Execute. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_validation_fix": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically attempting to fix validation failures. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_strategy_revision": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically revising the strategy when execution reveals issues. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_retry_transient": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically retrying operations that fail due to transient errors. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_checkpoint_restore": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically restoring from the most recent checkpoint on failure. 0.0 = always automatic, 1.0 = always manual."
    },
    "auto_child_plans": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically spawning child plans decided during Strategize. 0.0 = always automatic, 1.0 = always manual."
    },
    "require_sandbox": {
      "type": "boolean",
      "description": "When true, all write operations must execute within a sandbox. Execution fails if no sandbox strategy is available."
    },
    "require_checkpoints": {
      "type": "boolean",
      "description": "When true, checkpoints must be created before any write operation, enabling rollback."
    },
    "allow_unsafe_tools": {
      "type": "boolean",
      "description": "When true, tools flagged as unsafe can be invoked. When false, unsafe tool invocations are blocked."
    }
  },
  "required": [
    "name",
    "description",
    "auto_strategize",
    "auto_execute",
    "auto_apply",
    "auto_decisions_strategize",
    "auto_decisions_execute",
    "auto_validation_fix",
    "auto_strategy_revision",
    "auto_retry_transient",
    "auto_checkpoint_restore",
    "auto_child_plans",
    "require_sandbox",
    "require_checkpoints",
    "allow_unsafe_tools"
  ],
  "additionalProperties": false
}

Informal YAML Schema

The following annotated YAML provides an easier-to-read overview of the same schema defined formally above. It is not a validatable schema — it uses informal annotations to describe the structure. Refer to the JSON Schema above for the authoritative, machine-validatable definition.


# ─── Profile Identity ───────────────────────────────────────────────
name: <namespace>/<name>            # Fully qualified profile name (required)
description: <string>               # Human-readable description (required)

# ─── Phase Transition Thresholds ──────────────────────────────────── # Confidence thresholds controlling phase transitions. # 0.0 = always automatic, 1.0 = always manual. auto_strategize: <float: 0.01.0> # Confidence threshold for Action → Strategize (required, 0.0=auto, 1.0=manual) auto_execute: <float: 0.01.0> # Confidence threshold for Strategize → Execute (required, 0.0=auto, 1.0=manual) auto_apply: <float: 0.01.0> # Confidence threshold for Execute → Apply (required, 0.0=auto, 1.0=manual)

# ─── Decision Thresholds ──────────────────────────────────────────── # Confidence thresholds controlling decisions within each phase. # 0.0 = always automatic, 1.0 = always manual. auto_decisions_strategize: <float: 0.01.0> # Confidence threshold for decisions during Strategize (required, 0.0=auto, 1.0=manual) auto_decisions_execute: <float: 0.01.0> # Confidence threshold for decisions during Execute (required, 0.0=auto, 1.0=manual)

# ─── Self-Repair Thresholds ───────────────────────────────────────── auto_validation_fix: <float: 0.01.0> # Confidence threshold for auto-fixing validation failures (required, 0.0=auto, 1.0=manual) auto_strategy_revision: <float: 0.01.0> # Confidence threshold for auto-revising strategy (required, 0.0=auto, 1.0=manual) auto_retry_transient: <float: 0.01.0> # Confidence threshold for auto-retrying transient errors (required, 0.0=auto, 1.0=manual) auto_checkpoint_restore: <float: 0.01.0> # Confidence threshold for auto-restoring from checkpoints (required, 0.0=auto, 1.0=manual)

# ─── Execution Control Thresholds ────────────────────────────────── auto_child_plans: <float: 0.01.0> # Confidence threshold for auto-spawning child plans (required, 0.0=auto, 1.0=manual)

# ─── Safety Requirements ──────────────────────────────────────────── require_sandbox: <boolean> # Require sandbox for all write operations (required) require_checkpoints: <boolean> # Require checkpoint creation before write operations (required) allow_unsafe_tools: <boolean> # Allow tools flagged as unsafe (required)

Structure Reference

Top-Level Fields

Field Type Required Description
name string Yes Fully qualified profile name. Can be overridden by the CLI <NAME> argument.
description string Yes Human-readable description of the profile's purpose and behavior.

Phase Transition Thresholds

Field Type Required Description
auto_strategize number (0.01.0) Yes Confidence threshold for transitioning from Action to Strategize. When computed confidence >= threshold, Strategize begins automatically. 0.0 = always automatic, 1.0 = always manual.
auto_execute number (0.01.0) Yes Confidence threshold for transitioning from Strategize to Execute. When computed confidence >= threshold, Execute begins automatically. 0.0 = always automatic, 1.0 = always manual.
auto_apply number (0.01.0) Yes Confidence threshold for transitioning from Execute to Apply. When computed confidence >= threshold, Apply begins automatically. 0.0 = always automatic, 1.0 = always manual. A threshold of 0.0 means changes are committed without human review.

Decision Automation Thresholds

Field Type Required Description
auto_decisions_strategize number (0.01.0) Yes Confidence threshold for autonomous decision-making during Strategize. When computed confidence >= threshold, the strategy actor decides autonomously. 0.0 = always automatic, 1.0 = always manual.
auto_decisions_execute number (0.01.0) Yes Confidence threshold for autonomous decision-making during Execute. When computed confidence >= threshold, the execution actor decides autonomously. 0.0 = always automatic, 1.0 = always manual.

Self-Repair Thresholds

Field Type Required Description
auto_validation_fix number (0.01.0) Yes Confidence threshold for automatically fixing validation failures (e.g., failing tests, lint errors). When computed confidence >= threshold, fix is attempted automatically. 0.0 = always automatic, 1.0 = always manual.
auto_strategy_revision number (0.01.0) Yes Confidence threshold for automatically revising the strategy when execution reveals issues. When computed confidence >= threshold, revision proceeds automatically. 0.0 = always automatic, 1.0 = always manual.
auto_retry_transient number (0.01.0) Yes Confidence threshold for automatically retrying operations that fail due to transient errors (network timeouts, rate limits). When computed confidence >= threshold, retry proceeds automatically. 0.0 = always automatic, 1.0 = always manual.
auto_checkpoint_restore number (0.01.0) Yes Confidence threshold for automatically restoring from the most recent checkpoint on failure. When computed confidence >= threshold, restore proceeds automatically. 0.0 = always automatic, 1.0 = always manual.

Execution Control Thresholds

Field Type Required Description
auto_child_plans number (0.01.0) Yes Confidence threshold for automatically spawning child plans decided during Strategize. When computed confidence >= threshold, child plans spawn automatically during Execute. 0.0 = always automatic, 1.0 = always manual.

Safety Flags

Field Type Required Description
require_sandbox boolean Yes When true, all write operations must execute within a sandbox (git worktree, copy-on-write, transaction). Execution fails if no sandbox strategy is available.
require_checkpoints boolean Yes When true, checkpoints must be created before any write operation. This enables rollback.
allow_unsafe_tools boolean Yes When true, tools flagged as unsafe can be invoked. When false, unsafe tool invocations are blocked.

Built-in Profile Reference

Threshold manual review supervised cautious trusted auto ci full-auto
auto_strat 1.0 0.0 0.0 0.7 0.0 0.0 0.0 0.0
auto_exec 1.0 0.0 1.0 0.7 0.0 0.0 0.0 0.0
auto_apply 1.0 1.0 1.0 1.0 1.0 1.0 0.0 0.0
auto_dec_strat 1.0 1.0 0.0 0.6 0.0 0.0 0.0 0.0
auto_dec_exec 1.0 1.0 1.0 0.8 0.0 0.0 0.0 0.0
auto_val_fix 1.0 1.0 1.0 0.7 0.0 0.0 0.0 0.0
auto_strat_rev 1.0 1.0 1.0 0.8 1.0 0.0 0.0 0.0
auto_child 1.0 0.0 1.0 0.7 0.0 0.0 0.0 0.0
require_sandbox true true true true true true true false
allow_unsafe false false false false false false false true

Examples

Example 1: Careful Autonomous Profile (Simple)

A profile for autonomous execution with mandatory sandboxing and manual apply:


# careful-auto.yaml
# Register: agents automation-profile add --config careful-auto.yaml

name: local/careful-auto description: "Autonomous execution with mandatory sandbox and manual apply"

auto_strategize: 0.0 auto_execute: 0.0 auto_apply: 1.0

auto_decisions_strategize: 0.0 auto_decisions_execute: 0.0

auto_validation_fix: 0.0 auto_strategy_revision: 1.0 auto_retry_transient: 0.0 auto_checkpoint_restore: 0.0

auto_child_plans: 0.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

This is essentially the auto built-in profile but with auto_checkpoint_restore set to 0.0 (always automatic) for more aggressive self-repair.


Example 2: CI/CD Pipeline Profile (Medium)

A profile designed for automated CI/CD pipelines where everything runs autonomously:


# ci-pipeline.yaml
# Register: agents automation-profile add --config ci-pipeline.yaml

name: local/ci-pipeline description: "Full automation for CI/CD pipelines. All phases automated, sandbox required."

auto_strategize: 0.0 auto_execute: 0.0 auto_apply: 0.0

auto_decisions_strategize: 0.0 auto_decisions_execute: 0.0

auto_validation_fix: 0.0 auto_strategy_revision: 0.0 auto_retry_transient: 0.0 auto_checkpoint_restore: 0.0

auto_child_plans: 0.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

This profile is similar to full-auto but with mandatory sandboxing and checkpoints enabled — suitable for CI/CD environments where you want full automation but with safety nets.


Example 3: Review-Heavy Profile (Medium)

A profile for regulated environments where every decision must be reviewed:


# review-heavy.yaml
# Register: agents automation-profile add --config review-heavy.yaml

name: local/review-heavy description: "Maximum human oversight. Every decision and phase requires approval."

auto_strategize: 0.0 auto_execute: 1.0 auto_apply: 1.0

auto_decisions_strategize: 1.0 auto_decisions_execute: 1.0

auto_validation_fix: 1.0 auto_strategy_revision: 1.0 auto_retry_transient: 1.0 auto_checkpoint_restore: 1.0

auto_child_plans: 1.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

This profile auto-starts strategize but requires human approval for every decision, every phase transition, and every child plan spawn. Useful in regulated industries (finance, healthcare) where audit trails and human review are mandatory.


Example 4: Development Sandbox Profile (Simple)

A fast-iteration profile for local development where safety is relaxed:


# dev-sandbox.yaml
# Register: agents automation-profile add --config dev-sandbox.yaml

name: local/dev-sandbox description: "Fast iteration for local development. Relaxed safety, auto execution."

auto_strategize: 0.0 auto_execute: 0.0 auto_apply: 1.0

auto_decisions_strategize: 0.0 auto_decisions_execute: 0.0

auto_validation_fix: 0.0 auto_strategy_revision: 0.0 auto_retry_transient: 0.0 auto_checkpoint_restore: 0.0

auto_child_plans: 0.0

require_sandbox: false require_checkpoints: false allow_unsafe_tools: true

This profile removes sandbox and checkpoint requirements for speed during local development. It still requires manual apply to prevent accidental commits. Unsafe tools are allowed for full flexibility.


Example 5: Production Deployment Profile (Complex)

A profile for production deployments combining autonomous execution with maximum safety:


# production-deploy.yaml
# Register: agents automation-profile add --config production-deploy.yaml

name: local/production-deploy description: | Production deployment profile. Fully autonomous execution with maximum safety guarantees. All phases require sandbox and checkpoint. Apply requires manual approval. Strategy revision is enabled to adapt to deployment issues.

auto_strategize: 0.0 auto_execute: 0.0 auto_apply: 1.0

auto_decisions_strategize: 0.0 auto_decisions_execute: 0.0

auto_validation_fix: 0.0 auto_strategy_revision: 0.0 auto_retry_transient: 0.0 auto_checkpoint_restore: 0.0

auto_child_plans: 0.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

Workflow Examples

This section presents complete, end-to-end workflow examples showing how CleverAgents is used in practice. Each example starts from initial setup and walks through every command and decision point. The examples progress from simple single-action workflows to complex multi-project, multi-actor orchestrations.

Example 1: Hello World — Fix a Single Bug

Scenario: A developer finds a bug in their Python web API where the /health endpoint returns a 500 error instead of 200 when the database connection is unavailable. They want CleverAgents to fix it with full human oversight.

Complexity: Beginner. Single project, single action, manual automation profile.

Step 1: Initialize Environment and Register Resources


# Initialize CleverAgents (first-time setup)
$ agents init --yes

╭─ Initialized ────────────────────────────────────────────╮ │ Data Dir: /home/dev/.cleveragents (created) │ │ Config: /home/dev/.cleveragents/config.toml │ │ Database: initialized (schema v3) │ │ Directories: logs, cache, sessions, contexts │ ╰──────────────────────────────────────────────────────────╯

✓ OK Initialized (non-interactive)


# Register the git checkout as a resource
$ agents resource add git-checkout local/api-repo \
    --path /home/dev/projects/api-service \
    --branch main

╭─ Resource ──────────────────────────────────────────╮ │ Name: local/api-repo │ │ ID: 01HXR1A1B2C3D4E5F6G7H8J9K0 │ │ Type: git-checkout │ │ Physical/Virtual: physical │ │ Path: /home/dev/projects/api-service │ │ Branch: main │ │ Created: 2026-02-11 09:15 │ ╰─────────────────────────────────────────────────────╯

╭─ Auto-discovered Children ─────────────────────────────────────────╮ │ ID Type Status │ │ ─────────────── ────────────── ───────────────── │ │ 01HXR1A1B2C3… git created │ │ 01HXR1A1B2C4… git-remote created │ │ 01HXR1A1B2C5… git-branch created │ │ 01HXR1A1B2C6… fs-directory created │ │ + 32 git-commit resources │ │ + 187 git-tree-entry resources │ │ + 5 fs-directory + 41 fs-file │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Capabilities ─────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: git_worktree │ ╰────────────────────────────────╯

✓ OK Resource registered (270 child resources discovered)


# Create the project and link the resource
$ agents project create \
    --description "REST API service" \
    --resource local/api-repo \
    local/api-service

╭─ Project Created ──────────────────────────╮ │ Name: local/api-service │ │ Description: REST API service │ │ Type: local │ │ Created: 2026-02-11 09:15 │ ╰────────────────────────────────────────────╯

╭─ Linked Resources ───────────────────────────────────────╮ │ Name Type Read-Only │ │ ───────────────── ────────────── ───────── │ │ local/api-repo git-checkout no │ ╰──────────────────────────────────────────────────────────╯

╭─ Defaults ──────────────────────────────╮ │ Sandbox: git_worktree │ │ Validations: 0 │ │ Context Filters: none │ │ Automation Profile: (inherits global) │ ╰─────────────────────────────────────────╯

✓ OK Project created


# Add a required validation (tests must pass)
$ agents project validation add \
    --description "Unit tests" \
    --required \
    --resource local/api-repo \
    local/api-service "pytest tests/"

╭─ Validation Added ──────────────────────────────────────────╮ │ ID: val_01HXR1V1 │ │ Project: local/api-service │ │ Command: pytest tests/ │ │ Description: Unit tests │ │ Mode: required │ │ Resource: local/api-repo │ │ Timeout: 300s (default) │ ╰─────────────────────────────────────────────────────────────╯

✓ OK Validation added

Step 2: Create an Action

Create a file actions/fix-bug.yaml:


name: local/fix-bug
description: "Fix a reported bug in the codebase"
long_description: |
  Analyze the bug description, locate the relevant code,
  implement a fix, and add or update tests to cover the fix.
definition_of_done: |
  - The described bug no longer reproduces
  - All existing tests pass
  - At least one new test covers the fixed behavior
  - No unrelated code is modified
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
reusable: true
available: true
args:
  - name: bug_description
    type: string
    required: true
    description: "Description of the bug to fix"
  - name: affected_file
    type: string
    required: false
    description: "File path where the bug is suspected (optional hint)"

# Register the action
$ agents action create --config ./actions/fix-bug.yaml

╭─ Action Created ─────────────────────────────╮ │ Name: local/fix-bug │ │ ID: 01HXR1B1C2D3E4F5G6H7I8J9K0 │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 09:16 │ ╰──────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────╮ │ - The described bug no longer reproduces │ │ - All existing tests pass │ │ - At least one new test covers the fixed behavior │ │ - No unrelated code is modified │ ╰───────────────────────────────────────────────────────╯

╭─ Arguments ───────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ─────────────── ────── ──────── ────────────────────────────────────── │ │ bug_description string yes Description of the bug to fix │ │ affected_file string no File path where the bug is suspected │ ╰───────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: (inherits global) │ │ Source: default │ ╰───────────────────────────────────────╯

╭─ Usage ──────────────────────────────────────────────────────────────────╮ │ agents plan use local/fix-bug local/api-service │ │ --arg bug_description="..." │ ╰──────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 3: Create and Execute a Plan


# Bind the action to the project with the manual profile for full oversight
$ agents plan use \
    --automation-profile manual \
    --arg bug_description="The /health endpoint returns HTTP 500 when the database \
connection is unavailable. It should return HTTP 200 with {\"status\": \"degraded\", \
\"database\": \"unavailable\"} instead of crashing." \
    --arg affected_file="src/routes/health.py" \
    local/fix-bug local/api-service

╭─ Plan Created ──────────────────────────╮ │ Plan ID: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Phase: strategize │ │ Action: local/fix-bug │ │ Project: local/api-service │ │ Automation: manual │ │ Attempt: 1 │ ╰─────────────────────────────────────────╯

╭─ Inputs ──────────────────────────────────────────────────────────────╮ │ - bug_description="The /health endpoint returns HTTP 500 when the │ │ database connection is unavailable. It should return HTTP 200 with │ │ {"status": "degraded", "database": "unavailable"} instead │ │ of crashing." │ │ - affected_file="src/routes/health.py" │ │ - automation_profile=manual │ ╰───────────────────────────────────────────────────────────────────────╯

╭─ Actors ──────────────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: (none) │ ╰───────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: manual │ │ Source: plan override │ │ Read-Only: no │ ╰───────────────────────────────────────╯

╭─ Context ─────────────────────────╮ │ Resources: 1 (git-checkout) │ │ Indexed Files: 41 │ │ View: strategize │ │ Hot Token Budget: 8,000 │ ╰───────────────────────────────────╯

╭─ Next Steps ───────────────────────────────────────╮ │ - agents plan execute 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ - agents plan status 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ - agents plan tree 01HXR1C1D2E3F4G5H6I7J8K9L0 │ ╰────────────────────────────────────────────────────╯

✓ OK Plan created

Because the automation profile is manual, the plan stops and waits after creation. The developer must explicitly trigger each phase.


# Manually trigger Strategize → the strategy actor analyzes the codebase
$ agents plan execute 01HXR1C1D2E3F4G5H6I7J8K9L0

╭─ Execution ─────────────────────────────╮ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Phase: strategize │ │ Sandbox: git_worktree │ │ Worker: anthropic/claude-3.5-sonnet │ │ Started: 09:17:02 │ │ Attempt: 1 │ ╰─────────────────────────────────────────╯

╭─ Sandbox ───────────────────────────────────────────────────────╮ │ Strategy: git_worktree │ │ Path: /home/dev/projects/api-service/.worktrees/plan-01HXR1C1 │ │ Branch: cleveragents/plan-01HXR1C1D2 │ │ Status: active │ ╰─────────────────────────────────────────────────────────────────╯

╭─ Strategy Summary ────────────────╮ │ Decisions: 4 │ │ Invariants: 0 │ │ Planned Child Plans: 0 │ │ Estimated Files: ~2 │ │ Risk: low │ ╰───────────────────────────────────╯

╭─ Progress ────────╮ │ Collect context │ │ Build strategy │ │ Awaiting review │ ╰───────────────────╯

✓ OK Strategize complete — awaiting manual approval

The strategy actor has read the codebase, identified the relevant files, and produced decisions. Since auto_decisions_strategize is 1.0 (manual), the plan pauses for review:


# Review the decision tree
$ agents plan tree 01HXR1C1D2E3F4G5H6I7J8K9L0

╭─ Decision Tree ───────────────────────────────────────────────────────────────────────────╮ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ ├─ [prompt_definition] "Fix /health endpoint to return 200 when DB unavailable" │ │ ├─ [strategy_choice] "Wrap DB call in try/except, return degraded status" (conf: 0.95) │ │ ├─ [strategy_choice] "Modify src/routes/health.py only" (conf: 0.91) │ │ └─ [strategy_choice] "Add test_health_db_unavailable to tests/test_health.py" (conf: 0.93)│ ╰───────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Tree Summary ─────────────╮ │ Nodes: 4 │ │ Depth: 1 │ │ Child Plans: 0 │ │ Invariants: 0 │ │ Superseded: 0 (hidden) │ ╰────────────────────────────╯

╭─ Decision IDs (for correction) ──────────────────╮ │ Root: 01HXR1D1A2B3C4D5E6F7G8H9 │ │ Strategy 1: 01HXR1D2A2B3C4D5E6F7G8H9 │ │ Strategy 2: 01HXR1D3A2B3C4D5E6F7G8H9 │ │ Strategy 3: 01HXR1D4A2B3C4D5E6F7G8H9 │ ╰──────────────────────────────────────────────────╯

✓ OK Decision tree rendered


# Inspect the main strategy decision in detail
$ agents plan explain 01HXR1D2A2B3C4D5E6F7G8H9

╭─ Decision ──────────────────────────────────────────────────────────────╮ │ ID: 01HXR1D2A2B3C4D5E6F7G8H9 │ │ Type: strategy_choice │ │ Question: How should the /health endpoint handle database failures? │ │ Chosen: Wrap DB call in try/except, return degraded status │ │ Confidence: 0.95 │ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Sequence: 1 of 3 │ │ Created: 2026-02-11 09:17 │ ╰─────────────────────────────────────────────────────────────────────────╯

╭─ Alternatives Considered ──────────────────────────────────────────────────╮ │ 1. Wrap DB call in try/except, return degraded status (chosen) │ │ 2. Add a circuit breaker middleware for all DB-dependent routes │ │ 3. Return HTTP 503 Service Unavailable with retry-after header │ ╰────────────────────────────────────────────────────────────────────────────╯

╭─ Impact ──────────────────────╮ │ Downstream Decisions: 2 │ │ Downstream Child Plans: 0 │ │ Artifacts Produced: 2 │ │ Correction Impact: low │ ╰───────────────────────────────╯

╭─ Rationale ──────────────────────────────────────────────────╮ │ The bug description explicitly requires HTTP 200 with a │ │ degraded status JSON body. A try/except around the DB call │ │ in the health endpoint is the minimal, targeted fix. A │ │ circuit breaker would be over-engineering for a single │ │ endpoint. HTTP 503 contradicts the requested behavior. │ ╰──────────────────────────────────────────────────────────────╯

╭─ Correction ─────────────────────────────────────────────────╮ │ agents plan correct 01HXR1D2A2B3C4D5E6F7G8H9 │ │ --mode revert --guidance "Use a different approach..." │ ╰──────────────────────────────────────────────────────────────╯

✓ OK Decision explained


# Approve and proceed to Execute (manual profile requires explicit trigger)
$ agents plan execute 01HXR1C1D2E3F4G5H6I7J8K9L0

╭─ Execution ─────────────────────────────╮ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Phase: execute │ │ Sandbox: git_worktree │ │ Worker: anthropic/claude-3.5-sonnet │ │ Started: 09:18:30 │ │ Attempt: 1 │ ╰─────────────────────────────────────────╯

╭─ Sandbox ───────────────────────────────────────────────────────╮ │ Strategy: git_worktree │ │ Path: /home/dev/projects/api-service/.worktrees/plan-01HXR1C1 │ │ Branch: cleveragents/plan-01HXR1C1D2 │ │ Status: active │ ╰─────────────────────────────────────────────────────────────────╯

╭─ Progress ────────────────────────────────╮ │ Collect context (0.4s) │ │ Modify src/routes/health.py (1.2s) │ │ Add tests/test_health.py test (2.1s) │ │ Validate: pytest tests/ (3.8s) │ ╰───────────────────────────────────────────╯

✓ OK Execution complete — awaiting apply

The execution actor worked in the sandbox (git worktree), modifying src/routes/health.py and adding a test in tests/test_health.py. Validations ran automatically within the sandbox and passed.

Step 4: Review and Apply


# Review the changes
$ agents plan diff 01HXR1C1D2E3F4G5H6I7J8K9L0

╭─ Diff Summary ──────────────────────────────────╮ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Project: local/api-service │ │ Files Changed: 2 │ │ Insertions: 19 │ │ Deletions: 3 │ │ Net Change: +16 lines │ ╰─────────────────────────────────────────────────╯

╭─ Files ────────────────────────────────────╮ │ Path Change Status │ │ ─────────────────────── ────── ──────── │ │ src/routes/health.py +8 -3 modified │ │ tests/test_health.py +11 -0 modified │ ╰────────────────────────────────────────────╯

╭─ Patch Preview ──────────────────────────────────────────────────╮ │ --- a/src/routes/health.py │ │ +++ b/src/routes/health.py │ │ @@ -8,6 +8,11 @@ │ │ @app.get("/health") │ │ def health_check(): │ │ - db_status = check_database_connection() │ │ - return {"status": "ok", "database": db_status} │ │ + try: │ │ + db_status = check_database_connection() │ │ + return {"status": "ok", "database": "available"} │ │ + except ConnectionError: │ │ + return {"status": "degraded", "database": "unavailable"}│ │ --- a/tests/test_health.py │ │ +++ b/tests/test_health.py │ │ @@ -15,0 +16,11 @@ │ │ +def test_health_db_unavailable(client, monkeypatch): │ │ + def mock_check(): │ │ + raise ConnectionError("DB unreachable") │ │ + monkeypatch.setattr("src.routes.health.check_database…") │ │ + response = client.get("/health") │ │ + assert response.status_code == 200 │ │ + data = response.json() │ │ + assert data["status"] == "degraded" │ │ + assert data["database"] == "unavailable" │ ╰──────────────────────────────────────────────────────────────────╯

╭─ Risk Assessment ────────────────╮ │ API Compatibility: preserved │ │ Test Coverage: increased │ │ Breaking Changes: none detected │ ╰──────────────────────────────────╯

✓ OK Diff generated


# Check plan status (should be execute/complete, awaiting apply)
$ agents plan status 01HXR1C1D2E3F4G5H6I7J8K9L0

╭─ Plan Status ───────────────────────────╮ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Phase: execute │ │ State: complete │ │ Action: local/fix-bug │ │ Project: local/api-service │ │ Automation: manual │ │ Attempt: 1 │ ╰─────────────────────────────────────────╯

╭─ Progress ───────────╮ │ Strategize │ │ Execute │ │ Apply (awaiting) │ ╰──────────────────────╯

╭─ Timing ───────────────────────────╮ │ Started: 2026-02-11 09:17:02 │ │ Elapsed: 00:01:42 │ │ ETA: awaiting manual apply │ ╰────────────────────────────────────╯

╭─ Execution Detail ──────────╮ │ Sandbox: git_worktree │ │ Tool Calls: 5 │ │ Files Modified: 2 │ │ Child Plans: 0 │ │ Checkpoints: 1 created │ ╰─────────────────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 6,840 │ │ Cost So Far: $0.023 │ │ Estimated: $0.025 │ ╰──────────────────────╯

✓ OK Status refreshed


# Apply the changes to the real repository
$ agents plan apply --yes 01HXR1C1D2E3F4G5H6I7J8K9L0

╭─ Apply Summary ──────────────────────────╮ │ Plan: 01HXR1C1D2E3F4G5H6I7J8K9L0 │ │ Artifacts: 2 files updated │ │ Changes: 19 insertions, 3 deletions │ │ Project: local/api-service │ │ Applied At: 2026-02-11 09:19 │ ╰──────────────────────────────────────────╯

╭─ Validation ───────────────────╮ │ Tests: passed (14/14) │ │ Duration: 3.8s │ ╰────────────────────────────────╯

╭─ Sandbox Cleanup ──────────────────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰────────────────────────────────────────╯

╭─ Plan Lifecycle ──────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:01:58 │ │ Total Cost: $0.025 │ │ Decisions Made: 4 │ │ Child Plans: 0 │ ╰───────────────────────────────────────╯

╭─ Next Steps ──────╮ │ - Review git diff │ │ - Commit changes │ ╰───────────────────╯

✓ OK Changes applied

The sandbox changes are merged into the main working tree. The bug is fixed.


Example 2: Automated Test Generation for a Module

Scenario: A team wants to increase test coverage for their auth module from 45% to 80%. They trust CleverAgents to generate tests autonomously, but want to review before applying.

Complexity: Intermediate. Single project, trusted automation profile, validation-driven.

Step 1: Setup (Assuming Project Exists)


# Ensure the project has a coverage validation
# (project local/api-service and resource local/api-service-repo already exist)
$ agents project validation add \
    --description "Coverage must be at least 80%" \
    --required \
    --timeout 600 \
    --resource local/api-service-repo \
    local/api-service "pytest --cov=src/auth --cov-fail-under=80 tests/test_auth/"

╭─ Validation Added ────────────────────────────────────────────╮ │ ID: val_01HXR2V │ │ Project: local/api-service │ │ Command: pytest --cov=src/auth --cov-fail-under=80 │ │ tests/test_auth/ │ │ Description: Coverage must be at least 80% │ │ Mode: required │ │ Resource: local/api-service-repo │ │ Timeout: 600s │ ╰───────────────────────────────────────────────────────────────╯

✓ OK Validation added

# Automation profile will be set per-plan via --automation-profile on plan use

Step 2: Create the Test Generation Action

Create actions/generate-tests.yaml:


name: local/generate-tests
description: "Generate comprehensive tests for a module"
long_description: |
  Analyze the target module's code paths, identify untested branches,
  edge cases, and error conditions, then generate thorough test cases.
  Uses the project's existing test framework and conventions.
definition_of_done: |
  - Coverage of the target module reaches the specified threshold
  - All new tests pass
  - All existing tests continue to pass
  - Tests follow existing project conventions (fixtures, naming, structure)
  - No production code is modified
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
reusable: true
available: true
read_only: false
args:
  - name: target_module
    type: string
    required: true
    description: "Module path to generate tests for (e.g., src/auth)"
  - name: coverage_target
    type: integer
    required: false
    description: "Target coverage percentage"
    default: 80
invariants:
  - "Do not modify any production code — only add or modify test files"
  - "Follow the existing test file naming convention (test_<module>.py)"
  - "Use the project's existing test fixtures and conftest.py patterns"

$ agents action create --config ./actions/generate-tests.yaml

╭─ Action Created ───────────────────────────────────╮ │ Name: local/generate-tests │ │ ID: 01HXR2B1C2D3E4F5G6H7I8J9K0 │ │ State: draft │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Config: ./actions/generate-tests.yaml │ │ Created: 2026-02-11 09:15 │ ╰────────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────────────╮ │ - Coverage of the target module reaches the specified threshold │ │ - All new tests pass │ │ - All existing tests continue to pass │ │ - Tests follow existing project conventions │ │ - No production code is modified │ ╰───────────────────────────────────────────────────────────────────╯

╭─ Arguments ───────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ──────────────── ─────── ──────── ─────────────────────────────────────── │ │ target_module string yes Module path to generate tests for │ │ coverage_target integer no Target coverage percentage (default 80) │ ╰───────────────────────────────────────────────────────────────────────────────╯

╭─ Invariants ──────────────────────────────────────────────────────────────────╮ │ 1. Do not modify any production code — only add or modify test files │ │ 2. Follow the existing test file naming convention (test_<module>.py) │ │ 3. Use the project's existing test fixtures and conftest.py patterns │ ╰───────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: supervised │ │ Source: default │ ╰───────────────────────────────────────╯

✓ OK Action created

Step 3: Execute


# With trusted profile: Strategize and Execute run automatically,
# only Apply requires human approval
$ agents plan use \
    --automation-profile trusted \
    --arg target_module="src/auth" \
    --arg coverage_target=80 \
    local/generate-tests local/api-service

╭─ Plan Created ──────────────────────────────────────╮ │ Plan: 01HXR2B3C4D5E6F7G8H9J0K1L2 │ │ Phase: strategize │ │ State: processing │ │ Action: local/generate-tests │ │ Project: local/api-service │ │ Automation: trusted │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────────╯

╭─ Inputs ────────────────────────────╮ │ - target_module=src/auth │ │ - coverage_target=80 │ │ - automation_profile=trusted │ ╰─────────────────────────────────────╯

╭─ Actors ────────────────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: (none) │ ╰─────────────────────────────────────────────────╯

╭─ Automation ───────────────────────────╮ │ Profile: trusted │ │ Source: plan override │ │ Read-Only: no │ ╰────────────────────────────────────────╯

╭─ Context ────────────────────────╮ │ Resources: 1 (repo) │ │ Indexed Files: 214 │ │ View: strategize │ │ Hot Token Budget: 8,000 │ ╰──────────────────────────────────╯

╭─ Next Steps ─────────────────────────────────────────────────────────╮ │ Trusted profile — strategize and execute will proceed automatically. │ │ - agents plan status 01HXR2B3C4D5E6F7G8H9J0K1L2 │ │ - agents plan tree 01HXR2B3C4D5E6F7G8H9J0K1L2 │ ╰──────────────────────────────────────────────────────────────────────╯

✓ OK Plan created

The system runs through Strategize and Execute automatically. The strategy actor analyzes coverage gaps, identifies 12 untested code paths, and plans test cases. The execution actor writes tests in the sandbox. Validations run. If coverage reaches 80%, the plan reaches execute/complete and waits for apply.


# Check progress while it runs
$ agents plan status 01HXR2B3C4D5E6F7G8H9J0K1L2

╭─ Plan Status ───────────────────────────────╮ │ Plan: 01HXR2B3C4D5E6F7G8H9J0K1L2 │ │ Phase: execute │ │ State: processing │ │ Action: local/generate-tests │ │ Project: local/api-service │ │ Automation: trusted │ │ Attempt: 1 │ ╰─────────────────────────────────────────────╯

╭─ Progress ───────╮ │ Strategize │ │ Execute │ │ Apply (queued) │ ╰──────────────────╯

╭─ Timing ──────────╮ │ Started: 09:15:42 │ │ Elapsed: 00:02:18 │ │ ETA: 00:04:30 │ ╰───────────────────╯

╭─ Execution Detail ──────────╮ │ Sandbox: git_worktree │ │ Tool Calls: 14 │ │ Files Modified: 5 │ │ Child Plans: 0 │ │ Checkpoints: 3 created │ ╰─────────────────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 18,740 │ │ Cost So Far: $0.062 │ │ Estimated: $0.110 │ ╰──────────────────────╯

✓ OK Status refreshed


# When complete, review the generated tests
$ agents plan diff 01HXR2B3C4D5E6F7G8H9J0K1L2

╭─ Diff Summary ─────────────────────────────────────╮ │ Plan: 01HXR2B3C4D5E6F7G8H9J0K1L2 │ │ Project: local/api-service │ │ Files Changed: 5 │ │ Insertions: 287 │ │ Deletions: 3 │ │ Net Change: +284 lines │ ╰────────────────────────────────────────────────────╯

╭─ Files ────────────────────────────────────────────────╮ │ Path Change Status │ │ ────────────────────────────── ──────── ────────── │ │ tests/test_auth/test_login.py +72 -0 new file │ │ tests/test_auth/test_tokens.py +68 -0 new file │ │ tests/test_auth/test_session.py +54 -0 new file │ │ tests/test_auth/test_rbac.py +41 -0 new file │ │ tests/test_auth/conftest.py +52 -3 modified │ ╰────────────────────────────────────────────────────────╯

╭─ Patch Preview ───────────────────────────────────────────╮ │ --- /dev/null │ │ +++ b/tests/test_auth/test_login.py │ │ @@ -0,0 +1,72 @@ │ │ + import pytest │ │ + from src.auth.login import authenticate, verify_mfa │ │ + ... │ │ --- a/tests/test_auth/conftest.py │ │ +++ b/tests/test_auth/conftest.py │ │ @@ -1,5 +1,54 @@ │ │ - # minimal fixtures │ │ + # shared auth test fixtures │ │ + @pytest.fixture │ │ + def mock_user_db(): ... │ ╰───────────────────────────────────────────────────────────╯

╭─ Risk Assessment ────────────────╮ │ API Compatibility: preserved │ │ Test Coverage: 45% → 83% │ │ Breaking Changes: none detected │ ╰──────────────────────────────────╯

✓ OK Diff generated


$ agents plan artifacts 01HXR2B3C4D5E6F7G8H9J0K1L2

╭─ Artifacts ──────────────────────────────────────────────────────────╮ │ Path Type Size Change Child Plan │ │ ──────────────────────────────── ───── ────── ────── ─────── │ │ tests/test_auth/test_login.py write 3.8 KB +72 -0 root │ │ tests/test_auth/test_tokens.py write 3.4 KB +68 -0 root │ │ tests/test_auth/test_session.py write 2.7 KB +54 -0 root │ │ tests/test_auth/test_rbac.py write 2.1 KB +41 -0 root │ │ tests/test_auth/conftest.py edit 2.6 KB +52 -3 root │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Summary ────────────╮ │ Total: 5 │ │ Writes: 4 (new) │ │ Edits: 1 (modified) │ │ Deletes: 0 │ │ Total Size: 14.6 KB │ ╰──────────────────────╯

✓ OK 5 artifacts listed


# Apply the generated tests to the real repository
$ agents plan apply --yes 01HXR2B3C4D5E6F7G8H9J0K1L2

╭─ Apply Summary ──────────────────────────╮ │ Plan: 01HXR2B3C4D5E6F7G8H9J0K1L2 │ │ Artifacts: 5 files updated │ │ Changes: 287 insertions, 3 deletions │ │ Project: local/api-service │ │ Applied At: 2026-02-11 09:22 │ ╰──────────────────────────────────────────╯

╭─ Validation ──────────────────────────╮ │ Coverage: passed (83% ≥ 80%) │ │ All tests: passed (47/47) │ │ Duration: 18.2s │ ╰───────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ─────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:06:38 │ │ Total Cost: $0.107 │ │ Decisions Made: 12 │ │ Child Plans: 0 │ ╰──────────────────────────────────────────╯

╭─ Next Steps ──────╮ │ - Review git diff │ │ - Commit changes │ ╰───────────────────╯

✓ OK Changes applied


Example 3: Multi-File Refactoring with Invariants

Scenario: A senior engineer wants to refactor the authentication module to replace raw SQL queries with an ORM. The refactoring must maintain API backward compatibility and all existing tests must pass. Multiple invariants constrain the work.

Complexity: Intermediate-Advanced. Single project, multiple invariants, decision tree review.

Step 1: Define Invariants


$ 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_01HXR3A1B │ ╰────────────────────────────────────────────────────────────────────────╯

✓ OK Invariant added

$ agents invariant add --project local/api-service
"Database queries must use the SQLAlchemy ORM, not raw SQL"

╭─ Invariant Added ───────────────────────────────────────────────────────╮ │ Project: local/api-service │ │ Invariant: Database queries must use the SQLAlchemy ORM, not raw SQL │ │ Scope: project │ │ ID: inv_01HXR3A2C │ ╰─────────────────────────────────────────────────────────────────────────╯

✓ OK Invariant added

$ agents invariant list --project local/api-service --effective

╭─ Effective Invariants (Project local/api-service) ─────────────────────────────────────╮ │ ID Source Text │ │ ────────────── ──────── ────────────────────────────────────────────────────── │ │ inv_01HXR3A1B global All public APIs must maintain backward compatibility │ │ inv_01HXR3A2C project Database queries must use the SQLAlchemy ORM, not raw SQL │ ╰────────────────────────────────────────────────────────────────────────────────────────╯

✓ OK 2 effective invariants (1 global, 1 project)

Step 2: Create a Refactoring Action with Custom Actors

Create actors/refactoring-strategist.yaml:

name: local/refactoring-strategist
cleveragents:
  version: "3.0"
actors:
  strategist:
    type: llm
    config:
      provider: anthropic
      model: claude-3.5-sonnet
      temperature: 0.2
      system_prompt: |
        You are an expert software architect specializing in database layer refactoring.
        You analyze codebases to plan safe, incremental refactoring strategies.
        You always preserve backward compatibility and plan for comprehensive testing.
        Project: {{ context.project_name }}
        Resources: {{ context.resources | join(', ') }}
      memory_enabled: true
      max_history: 100

$ agents actor add --config ./actors/refactoring-strategist.yaml

╭─ Actor Added ────────────────────────────────────╮ │ Name: local/refactoring-strategist │ │ Provider: anthropic │ │ Model: claude-3.5-sonnet │ │ Default: yes │ │ Unsafe: no │ │ Type: graph │ ╰──────────────────────────────────────────────────╯

╭─ Config ────────────────────────────────────────────────────╮ │ Path: ./actors/refactoring-strategist.yaml │ │ Hash: 7a1e4c9 │ │ Options: 3 │ │ Nodes: 1 │ │ Edges: 0 │ ╰─────────────────────────────────────────────────────────────╯

╭─ Capabilities ────────────────╮ │ - database layer refactoring │ │ - incremental strategy │ │ - backward compatibility │ ╰───────────────────────────────╯

✓ OK Actor added

Create actions/refactor-to-orm.yaml:

name: local/refactor-to-orm
description: "Refactor raw SQL queries to use SQLAlchemy ORM"
long_description: |
  Systematically replace all raw SQL queries in the target module with
  SQLAlchemy ORM equivalents. Create ORM model definitions, replace
  query construction, update transaction handling, and ensure all
  existing behavior is preserved.
definition_of_done: |
  - Zero raw SQL strings remain in the target module
  - All ORM models are defined with proper relationships
  - All existing tests pass without modification
  - New integration tests verify ORM query correctness
  - API response formats are unchanged
  - Database migration script is generated
strategy_actor: local/refactoring-strategist
execution_actor: anthropic/claude-3.5-sonnet
estimation_actor: anthropic/claude-3.5-sonnet
reusable: true
available: true
automation_profile: cautious
args:
  - name: target_module
    type: string
    required: true
    description: "Module to refactor"
invariants:
  - "Each file must be refactored in a separate commit-sized change"
  - "ORM models must be defined before queries are converted"
  - "All raw SQL must be replaced — no partial conversion"

$ agents action create --config ./actions/refactor-to-orm.yaml

╭─ Action Created ─────────────────────────────────────────────╮ │ Name: local/refactor-to-orm │ │ ID: 01HXR3B1D2E3F4G5H6J7K8L9M0 │ │ State: available │ │ Strategy Actor: local/refactoring-strategist │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 09:14 │ ╰──────────────────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────────╮ │ - Zero raw SQL strings remain in the target module │ │ - All ORM models are defined with proper relationships │ │ - All existing tests pass without modification │ │ - New integration tests verify ORM query correctness │ │ - API response formats are unchanged │ │ - Database migration script is generated │ ╰───────────────────────────────────────────────────────────────╯

╭─ Arguments ──────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────────── ────── ──────── ───────────────────── │ │ target_module string yes Module to refactor │ ╰──────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: cautious │ │ Source: action config │ ╰───────────────────────────────────────╯

╭─ Action Invariants ──────────────────────────────────────────────────────╮ │ 1. Each file must be refactored in a separate commit-sized change │ │ 2. ORM models must be defined before queries are converted │ │ 3. All raw SQL must be replaced — no partial conversion │ ╰──────────────────────────────────────────────────────────────────────────╯

╭─ Usage ───────────────────────────────────────────────────────────────────╮ │ agents plan use local/refactor-to-orm local/api-service │ │ --arg target_module="src/auth" │ ╰───────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 3: Execute with Cautious Profile


$ agents plan use \
    --arg target_module="src/auth" \
    local/refactor-to-orm local/api-service

╭─ Plan Created ───────────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ Action: local/refactor-to-orm │ │ Project: local/api-service │ │ Automation: cautious │ │ Attempt: 1 │ ╰──────────────────────────────────────────────────────╯

╭─ Inputs ────────────────────────╮ │ - target_module="src/auth" │ │ - automation_profile=cautious │ ╰─────────────────────────────────╯

╭─ Actors ───────────────────────────────────────╮ │ Strategy: local/refactoring-strategist │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: anthropic/claude-3.5-sonnet │ ╰────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────────╮ │ Profile: cautious │ │ Source: action config │ │ Read-Only: no │ ╰───────────────────────────────────────────╯

╭─ Context ───────────────────────╮ │ Resources: 2 (repo, db) │ │ Indexed Files: 214 │ │ View: strategize │ │ Hot Token Budget: 16,000 │ ╰─────────────────────────────────╯

╭─ Next Steps ──────────────────────────────────────────╮ │ - agents plan execute 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ - agents plan status 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ - agents plan tree 01HXR3C4D5E6F7G8H9J0K1L2M3 │ ╰───────────────────────────────────────────────────────╯

✓ OK Plan created

Because the cautious profile uses intermediate confidence thresholds, the system:

  1. Enters Strategize automatically (threshold 0.7, confidence is high for well-understood tasks)
  2. Makes strategy decisions automatically when confidence >= 0.6, but pauses for complex architectural choices
  3. The Invariant Reconciliation Actor reconciles global ("backward compatibility"), project ("use ORM"), and action ("separate commits") invariants

# The system pauses at a decision where confidence is below threshold.
# Review the decision tree:

$ agents plan tree 01HXR3C4D5E6F7G8H9J0K1L2M3

╭─ Decision Tree ────────────────────────────────────────────────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ ├─ [prompt_definition] "Refactor raw SQL in src/auth to SQLAlchemy ORM" │ │ ├─ [invariant_enforced] "All public APIs must maintain backward compatibility" │ │ ├─ [invariant_enforced] "Database queries must use the SQLAlchemy ORM" │ │ ├─ [invariant_enforced] "Each file refactored in a separate commit-sized change" │ │ ├─ [invariant_enforced] "ORM models must be defined before queries are converted" │ │ ├─ [strategy_choice] "Define ORM models first, then convert queries" (conf: 0.85) │ │ ├─ [strategy_choice] "Place models inline in route files" (conf: 0.48) ⏸ PAUSED │ │ └─ (awaiting input — confidence below threshold) │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Tree Summary ─────────────╮ │ Nodes: 8 │ │ Depth: 2 │ │ Child Plans: 0 │ │ Invariants: 4 │ │ Superseded: 0 (hidden) │ ╰────────────────────────────╯

╭─ Decision IDs (for correction) ──────────────────────╮ │ Root: 01HXR3D1A2B3C4D5E6F7G8H9 │ │ Invariant 1: 01HXR3D1B3C4D5E6F7G8H9J0 │ │ Invariant 2: 01HXR3D1C4D5E6F7G8H9J0K1 │ │ Invariant 3: 01HXR3D1D5E6F7G8H9J0K1L2 │ │ Invariant 4: 01HXR3D1E6F7G8H9J0K1L2M3 │ │ Strategy 1: 01HXR3D2E3F4G5H6I7J8K9L0 │ │ Strategy 2: 01HXR3D5F6G7H8I9J0K1L2M3 (paused) │ ╰──────────────────────────────────────────────────────╯

✓ OK Decision tree rendered

# The paused decision is about model placement. Inspect it:

$ agents plan explain 01HXR3D5F6G7H8I9J0K1L2M3

╭─ Decision ──────────────────────────────────────────────╮ │ ID: 01HXR3D5F6G7H8I9J0K1L2M3 │ │ Type: strategy_choice │ │ Question: Where should ORM model classes be placed? │ │ Chosen: Place models inline in route files │ │ Confidence: 0.48 │ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ Sequence: 6 of 7 │ │ Created: 2026-02-11 09:15 │ ╰─────────────────────────────────────────────────────────╯

╭─ Alternatives Considered ─────────────────────────────────────╮ │ 1. Place models inline in route files (chosen) │ │ 2. Separate models/ directory with one model per file │ │ 3. Single models.py file alongside routes │ ╰───────────────────────────────────────────────────────────────╯

╭─ Impact ──────────────────────╮ │ Downstream Decisions: 4 │ │ Downstream Child Plans: 0 │ │ Artifacts Produced: 0 │ │ Correction Impact: high │ ╰───────────────────────────────╯

╭─ Rationale ────────────────────────────────────────────────────────╮ │ Placing models inline minimizes import changes and keeps related │ │ code co-located. However, this conflicts with project conventions │ │ and may make models harder to reuse across modules. The low │ │ confidence reflects genuine uncertainty about the trade-off. │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Correction ───────────────────────────────────────────────────────╮ │ agents plan correct 01HXR3D5F6G7H8I9J0K1L2M3 │ │ --mode revert --guidance "Use separate models/ directory..." │ ╰────────────────────────────────────────────────────────────────────╯

✓ OK Decision explained

# Provide guidance via the plan prompt command

$ agents plan prompt 01HXR3C4D5E6F7G8H9J0K1L2M3
"Convert the User model first, then Session, then Token.
Use Alembic for the migration script."

╭─ Guidance Added ─────────────────────────────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ Guidance: Convert the User model first, then Session, then Token. │ │ Use Alembic for the migration script. │ │ Scope: next execution step │ │ Phase: strategize │ │ State: awaiting_input → processing │ ╰──────────────────────────────────────────────────────────────────────────╯

╭─ Decision Created ───────────────────────────╮ │ Type: user_intervention │ │ ID: 01HXR3E1A2B3C4D5E6F7G8H9 │ │ Parent: 01HXR3D5F6G7H8I9J0K1L2M3 │ ╰──────────────────────────────────────────────╯

╭─ Queue ────╮ │ Pending: 1 │ │ Applied: 0 │ ╰────────────╯

✓ OK Guidance queued

# Execution continues. Monitor progress:

$ agents plan status 01HXR3C4D5E6F7G8H9J0K1L2M3

╭─ Plan Status ───────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ Phase: execute │ │ State: processing │ │ Action: local/refactor-to-orm │ │ Project: local/api-service │ │ Automation: cautious │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────╯

╭─ Progress ───────╮ │ Strategize │ │ Execute │ │ Apply (queued) │ ╰──────────────────╯

╭─ Timing ──────────╮ │ Started: 09:14:22 │ │ Elapsed: 00:02:38 │ │ ETA: 00:05:10 │ ╰───────────────────╯

╭─ Execution Detail ──────────╮ │ Sandbox: git_worktree │ │ Tool Calls: 14 │ │ Files Modified: 4 │ │ Child Plans: 0/0 complete │ │ Checkpoints: 3 created │ ╰─────────────────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 18,740 │ │ Cost So Far: $0.062 │ │ Estimated: $0.128 │ ╰──────────────────────╯

✓ OK Status refreshed

Step 4: Correct a Decision

During execution, you notice the strategy chose to inline the ORM models in the same file as the routes. You want them in a separate models/ directory:


# Find the decision that chose inline models

$ agents plan tree --show-superseded 01HXR3C4D5E6F7G8H9J0K1L2M3

╭─ Decision Tree ────────────────────────────────────────────────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ ├─ [prompt_definition] "Refactor raw SQL in src/auth to SQLAlchemy ORM" │ │ ├─ [invariant_enforced] "All public APIs must maintain backward compatibility" │ │ ├─ [invariant_enforced] "Database queries must use the SQLAlchemy ORM" │ │ ├─ [invariant_enforced] "Each file refactored in a separate commit-sized change" │ │ ├─ [invariant_enforced] "ORM models must be defined before queries are converted" │ │ ├─ [strategy_choice] "Define ORM models first, then convert queries" (conf: 0.85) │ │ ├─ [strategy_choice] "Place models inline in route files" (superseded) │ │ ├─ [user_intervention] "Convert User first, then Session, then Token" │ │ ├─ [strategy_choice] "Create User ORM model in routes/auth.py" (conf: 0.74) │ │ ├─ [tool_invocation] write_file src/auth/routes/auth.py │ │ └─ [tool_invocation] write_file src/auth/routes/session.py │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Tree Summary ─────────────╮ │ Nodes: 11 │ │ Depth: 3 │ │ Child Plans: 0 │ │ Invariants: 4 │ │ Superseded: 1 (shown) │ ╰────────────────────────────╯

╭─ Decision IDs (for correction) ──────────────────────╮ │ Root: 01HXR3D1A2B3C4D5E6F7G8H9 │ │ Strategy 1: 01HXR3D2E3F4G5H6I7J8K9L0 │ │ Strategy 2: 01HXR3D5F6G7H8I9J0K1L2M3 (superseded) │ │ Intervention: 01HXR3E1A2B3C4D5E6F7G8H9 │ │ Strategy 3: 01HXR3F1A2B3C4D5E6F7G8H9 │ │ Tool 1: 01HXR3F2B3C4D5E6F7G8H9J0 │ │ Tool 2: 01HXR3F3C4D5E6F7G8H9J0K1 │ ╰──────────────────────────────────────────────────────╯

✓ OK Decision tree rendered

# Correct it — revert mode replays from that decision

$ agents plan correct 01HXR3F1A2B3C4D5E6F7G8H9
--mode revert
--guidance "Place ORM models in src/auth/models/ with one model per file.
Import them in src/auth/models/__init__.py."
--yes

╭─ Correction ────────────────────────────────────────────────╮ │ Mode: revert │ │ Impact: 2 decisions, 0 child plans, 2 artifacts │ │ New Decision: 01HXR3G1A2B3C4D5E6F7G8H9 │ │ Corrects: 01HXR3F1A2B3C4D5E6F7G8H9 │ │ Attempt: 2 │ │ Correction ID: 01HXR3CORR1A2B3C4D5E6 │ ╰─────────────────────────────────────────────────────────────╯

╭─ Affected Subtree ──────────────╮ │ Decisions Invalidated: 2 │ │ Child Plans Rolled Back: 0 │ │ Artifacts Archived: 2 │ │ Unaffected Decisions: 6 │ ╰─────────────────────────────────╯

╭─ Sandbox Rollback ─────────────╮ │ Checkpoint: cp_01HXR3C4 │ │ Files Reverted: 2 │ │ Status: restored │ ╰────────────────────────────────╯

╭─ Recompute ───────────────╮ │ Queued: re-execute │ │ ETA: 3m │ ╰───────────────────────────╯

╭─ History ───────────────────────────────────────────────╮ │ - Original decision superseded │ │ - Prior artifacts archived for comparison │ │ - agents plan diff --correction 01HXR3CORR1A2B3C4D5E6 │ ╰─────────────────────────────────────────────────────────╯

✓ OK Correction applied

# The affected subtree is recomputed. Review the new approach:

$ agents plan diff --correction 01HXR3CORR1A2B3C4D5E6

╭─ Correction Diff ────────────────────────────────────────────╮ │ Correction: 01HXR3CORR1A2B3C4D5E6 │ │ Original Decision: 01HXR3F1A2B3C4D5E6F7G8H9 │ │ Mode: revert │ │ Files Changed: 5 │ │ New Insertions: 84 │ │ New Deletions: 36 │ ╰──────────────────────────────────────────────────────────────╯

╭─ Comparison ──────────────────────────────────────────────────────────────╮ │ File Before (original) After (corrected) │ │ ────────────────────────────── ──────────────── ──────────────────── │ │ src/auth/routes/auth.py +42 -8 (inline) +6 -8 (imports only) │ │ src/auth/routes/session.py +28 -6 (inline) +4 -6 (imports only) │ │ src/auth/models/__init__.py (did not exist) (new file) │ │ src/auth/models/user.py (did not exist) (new file, +38) │ │ src/auth/models/session.py (did not exist) (new file, +26) │ ╰───────────────────────────────────────────────────────────────────────────╯

╭─ Patch Preview (corrected vs original) ───────────────────────────╮ │ --- a/src/auth/routes/auth.py (original) │ │ +++ b/src/auth/routes/auth.py (corrected) │ │ @@ -1,42 +1,6 @@ │ │ - class User(Base): # was inline │ │ - tablename = "users" │ │ - id = Column(Integer, primary_key=True) │ │ + from src.auth.models import User │ │ ... │ │ +++ b/src/auth/models/user.py (new file) │ │ @@ -0,0 +1,38 @@ │ │ + from sqlalchemy import Column, Integer, String │ │ + from sqlalchemy.orm import relationship │ │ + class User(Base): │ │ + tablename = "users" │ │ ... │ ╰───────────────────────────────────────────────────────────────────╯

✓ OK Correction diff generated

Step 5: Apply


$ agents plan diff 01HXR3C4D5E6F7G8H9J0K1L2M3

╭─ Diff Summary ───────────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ Project: local/api-service │ │ Files Changed: 9 │ │ Insertions: 186 │ │ Deletions: 94 │ │ Net Change: +92 lines │ ╰──────────────────────────────────────────────────────╯

╭─ Files ───────────────────────────────────────────────╮ │ Path Change Status │ │ ────────────────────────────── ──────── ────────── │ │ src/auth/models/__init__.py +8 new file │ │ src/auth/models/user.py +38 new file │ │ src/auth/models/session.py +26 new file │ │ src/auth/models/token.py +22 new file │ │ src/auth/routes/auth.py +12 -28 modified │ │ src/auth/routes/session.py +8 -22 modified │ │ src/auth/routes/token.py +6 -18 modified │ │ src/auth/db.py +14 -26 modified │ │ alembic/versions/001_orm.py +52 new file │ ╰───────────────────────────────────────────────────────╯

╭─ Risk Assessment ────────────────╮ │ API Compatibility: preserved │ │ Test Coverage: maintained │ │ Breaking Changes: none detected │ ╰──────────────────────────────────╯

✓ OK Diff generated

$ agents plan apply --yes 01HXR3C4D5E6F7G8H9J0K1L2M3

╭─ Apply Summary ───────────────────────────────────╮ │ Plan: 01HXR3C4D5E6F7G8H9J0K1L2M3 │ │ Artifacts: 9 files updated │ │ Changes: 186 insertions, 94 deletions │ │ Project: local/api-service │ │ Applied At: 2026-02-11 09:23 │ ╰───────────────────────────────────────────────────╯

╭─ Validation ───────────────────────╮ │ Tests: passed (47/47) │ │ Lint: passed (0 warnings) │ │ Type Check: passed (0 errors) │ │ Duration: 18.6s │ ╰────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ───────────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:08:42 │ │ Total Cost: $0.128 │ │ Decisions Made: 11 │ │ Corrections: 1 │ │ Child Plans: 0 │ ╰────────────────────────────────────────────────╯

╭─ Next Steps ──────╮ │ - Review git diff │ │ - Commit changes │ ╰───────────────────╯

✓ OK Changes applied


Example 4: Multi-Project Dependency Update

Scenario: An organization has three microservices that share a common library. The library has a breaking change that requires coordinated updates across all three services. The update must be validated in each service independently before any changes are applied.

Complexity: Advanced. Multiple projects, child plans, coordinated apply.

Step 1: Register All Projects and Resources

# Register the common-lib resource (full output shown)

$ agents resource add git-checkout local/common-lib-repo --path /repos/common-lib --branch main

╭─ Resource ──────────────────────────────────────╮ │ Name: local/common-lib-repo │ │ ID: 01HXR4A1B2C3D4E5F6G7H8J9K0 │ │ Type: git-checkout │ │ Physical/Virtual: physical │ │ Path: /repos/common-lib │ │ Branch: main │ │ Created: 2026-02-11 10:00 │ ╰─────────────────────────────────────────────────╯

╭─ Auto-discovered Children ─────────────────────────────────────────╮ │ ID Type Status │ │ ─────────────── ────────────── ───────────────── │ │ 01HXR4A1B2C3… git created │ │ 01HXR4A1B2C4… git-remote created │ │ 01HXR4A1B2C5… git-branch created │ │ + 31 git-commit resources │ │ + 186 git-tree-entry resources │ │ + 2 fs-directory + 14 fs-file │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Capabilities ─────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: git_worktree │ ╰────────────────────────────────╯

✓ OK Resource registered (236 child resources discovered)

# Register the remaining 3 service resources (condensed output)

$ agents resource add git-checkout local/user-service-repo --path /repos/user-service --branch main ✓ OK Resource registered — Name: local/user-service-repo (312 children)

$ agents resource add git-checkout local/order-service-repo --path /repos/order-service --branch main ✓ OK Resource registered — Name: local/order-service-repo (287 children)

$ agents resource add git-checkout local/billing-service-repo --path /repos/billing-service --branch main ✓ OK Resource registered — Name: local/billing-service-repo (264 children)

# Create the common-lib project (full output shown)

$ agents project create -d "Shared common library"
--resource local/common-lib-repo local/common-lib

╭─ Project Created ─────────────────────────╮ │ Name: local/common-lib │ │ Description: Shared common library │ │ Type: local │ │ Created: 2026-02-11 10:01 │ ╰───────────────────────────────────────────╯

╭─ Linked Resources ───────────────────────────────────────╮ │ Resource Type Read-Only │ │ ───────────────────── ────────────── ───────── │ │ local/common-lib-repo git-checkout no │ ╰──────────────────────────────────────────────────────────╯

╭─ Defaults ──────────────────────────────╮ │ Sandbox: git_worktree │ │ Validations: 0 │ │ Context Filters: none │ │ Automation Profile: (inherits global) │ ╰─────────────────────────────────────────╯

✓ OK Project created

# Create the remaining 3 service projects (condensed output)

$ agents project create -d "User microservice"
--resource local/user-service-repo local/user-service ✓ OK Project created — Name: local/user-service

$ agents project create -d "Order microservice"
--resource local/order-service-repo local/order-service ✓ OK Project created — Name: local/order-service

$ agents project create -d "Billing microservice"
--resource local/billing-service-repo local/billing-service ✓ OK Project created — Name: local/billing-service

# Add validations — first one with full output

$ agents project validation add --required local/common-lib "pytest tests/ && mypy src/"

╭─ Validation Added ──────────────────────────────────╮ │ ID: val_01HXR4V1A │ │ Project: local/common-lib │ │ Command: pytest tests/ && mypy src/ │ │ Mode: required │ │ Timeout: 300s │ ╰─────────────────────────────────────────────────────╯

✓ OK Validation added

# Add validations to the remaining 3 services (condensed output)

$ agents project validation add --required local/user-service "pytest tests/ && mypy src/" ✓ OK Validation added — ID: val_01HXR4V2B Project: local/user-service

$ agents project validation add --required local/order-service "pytest tests/ && mypy src/" ✓ OK Validation added — ID: val_01HXR4V3C Project: local/order-service

$ agents project validation add --required local/billing-service "pytest tests/ && mypy src/" ✓ OK Validation added — ID: val_01HXR4V4D Project: local/billing-service

Step 2: Create a Coordinated Update Action

Create actions/coordinated-dependency-update.yaml:

name: local/coordinated-dep-update
description: "Update a shared dependency across multiple projects"
long_description: |
  When a shared library introduces a breaking change, this action coordinates
  the update across all dependent projects. It analyzes the breaking changes,
  creates per-project update plans as child plans, validates each independently,
  and produces a coordinated changeset.
definition_of_done: |
  - The shared library is updated to the target version
  - All dependent projects compile and pass tests with the new version
  - API contracts between services remain compatible
  - Migration guides are generated for each project if needed
  - All changes can be applied atomically or rolled back as a unit
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
automation_profile: supervised
reusable: true
available: true
args:
  - name: library_name
    type: string
    required: true
    description: "Name of the shared library to update"
  - name: target_version
    type: string
    required: true
    description: "Target version to update to"
  - name: changelog_url
    type: string
    required: false
    description: "URL to the library changelog or migration guide"
invariants:
  - "Each dependent project must be updated in its own child plan"
  - "All child plans must pass validation before any can be applied"
  - "The library update in common-lib must be applied first"
$ agents action create --config ./actions/coordinated-dependency-update.yaml

╭─ Action Created ─────────────────────────────────────────────╮ │ Name: local/coordinated-dep-update │ │ ID: 01HXR4B1D2E3F4G5H6J7K8L9M0 │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 10:02 │ ╰──────────────────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────────────────╮ │ - The shared library is updated to the target version │ │ - All dependent projects compile and pass tests with the new version │ │ - API contracts between services remain compatible │ │ - Migration guides are generated for each project if needed │ │ - All changes can be applied atomically or rolled back as a unit │ ╰───────────────────────────────────────────────────────────────────────╯

╭─ Arguments ──────────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────────── ────── ──────── ────────────────────────────────────────── │ │ library_name string yes Name of the shared library to update │ │ target_version string yes Target version to update to │ │ changelog_url string no URL to the library changelog or migration │ ╰──────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: supervised │ │ Source: action config │ ╰───────────────────────────────────────╯

╭─ Action Invariants ──────────────────────────────────────────────────────────────╮ │ 1. Each dependent project must be updated in its own child plan │ │ 2. All child plans must pass validation before any can be applied │ │ 3. The library update in common-lib must be applied first │ ╰──────────────────────────────────────────────────────────────────────────────────╯

╭─ Usage ───────────────────────────────────────────────────────────────────────────╮ │ agents plan use local/coordinated-dep-update local/common-lib │ │ --arg library_name="authlib" --arg target_version="2.0.0" │ ╰───────────────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 3: Execute Across Multiple Projects

# Create a plan targeting all four projects

$ agents plan use
--automation-profile supervised
--arg library_name="authlib"
--arg target_version="2.0.0"
--arg changelog_url="https://authlib.org/changelog/2.0"
local/coordinated-dep-update
local/common-lib local/user-service local/order-service local/billing-service

╭─ Plan Created ────────────────────────────────────────────╮ │ Plan: 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ Action: local/coordinated-dep-update │ │ Projects: local/common-lib, local/user-service, │ │ local/order-service, local/billing-service │ │ Automation: supervised │ │ Attempt: 1 │ ╰───────────────────────────────────────────────────────────╯

╭─ Inputs ───────────────────────────────────────────────────────────╮ │ - library_name="authlib" │ │ - target_version="2.0.0" │ │ - changelog_url="https://authlib.org/changelog/2.0" │ │ - automation_profile=supervised │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Actors ───────────────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ ╰────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────────╮ │ Profile: supervised │ │ Source: CLI override │ │ Read-Only: no │ ╰───────────────────────────────────────────╯

╭─ Context ──────────────────────────╮ │ Resources: 4 (git-checkout) │ │ Indexed Files: 1,099 │ │ View: strategize │ │ Hot Token Budget: 24,000 │ ╰────────────────────────────────────╯

╭─ Next Steps ──────────────────────────────────────────────╮ │ - agents plan tree 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ - agents plan status 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ - agents plan execute 01HXR4D5E6F7G8H9J0K1L2M3N4 │ ╰───────────────────────────────────────────────────────────╯

✓ OK Plan created

The system creates a parent plan. Strategize runs automatically (supervised profile). It produces a strategy that:

  1. Analyzes the breaking changes in authlib 2.0.0
  2. Plans child plans for each project
  3. Orders the updates: common-lib first, then services in parallel
# Review the strategy before execution begins

$ agents plan tree 01HXR4D5E6F7G8H9J0K1L2M3N4

╭─ Decision Tree ─────────────────────────────────────────────────────────────────────────────────────╮ │ Plan: 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ ├─ [prompt_definition] "Update authlib to 2.0.0 across 4 projects" │ │ ├─ [invariant_enforced] "Each dependent project must be updated in its own child plan" │ │ ├─ [invariant_enforced] "All child plans must pass validation before any can be applied" │ │ ├─ [invariant_enforced] "The library update in common-lib must be applied first" │ │ ├─ [strategy_choice] "Analyze changelog for breaking API changes" (conf: 0.92) │ │ ├─ [strategy_choice] "Update common-lib first, then services in parallel" (conf: 0.88) │ │ ├─ [strategy_choice] "Create 4 child plans: common-lib, user-svc, order-svc, billing-svc" │ │ │ (conf: 0.90) │ │ └─ (awaiting execution approval — supervised profile) │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Tree Summary ──────────────╮ │ Nodes: 8 │ │ Depth: 2 │ │ Child Plans: 0 (planned: 4) │ │ Invariants: 3 │ │ Superseded: 0 (hidden) │ ╰─────────────────────────────╯

╭─ Decision IDs (for correction) ──────────────────────────╮ │ Root: 01HXR4D6A1B2C3D4E5F6G7H8 │ │ Invariant 1: 01HXR4D6B2C3D4E5F6G7H8J9 │ │ Invariant 2: 01HXR4D6C3D4E5F6G7H8J9K0 │ │ Invariant 3: 01HXR4D6D4E5F6G7H8J9K0L1 │ │ Strategy 1: 01HXR4D7E5F6G7H8I9J0K1L2 │ │ Strategy 2: 01HXR4D7F6G7H8I9J0K1L2M3 │ │ Strategy 3: 01HXR4D7G7H8I9J0K1L2M3N4 │ ╰──────────────────────────────────────────────────────────╯

✓ OK Decision tree rendered

$ agents plan status 01HXR4D5E6F7G8H9J0K1L2M3N4

╭─ Plan Status ──────────────────────────────────────────╮ │ Plan: 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ Phase: strategize → execute (pending approval) │ │ State: awaiting_input │ │ Action: local/coordinated-dep-update │ │ Projects: 4 │ │ Automation: supervised │ │ Attempt: 1 │ ╰────────────────────────────────────────────────────────╯

╭─ Progress ────────────────────────────╮ │ Strategize │ │ Execute (awaiting approval) │ │ Apply (queued) │ ╰───────────────────────────────────────╯

╭─ Timing ──────────╮ │ Started: 10:02:14 │ │ Elapsed: 00:01:42 │ │ ETA: 00:12:00 │ ╰───────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 8,420 │ │ Cost So Far: $0.028 │ │ Estimated: $0.340 │ ╰──────────────────────╯

✓ OK Status refreshed

# Manually approve execution (supervised requires explicit approval)

$ agents plan execute 01HXR4D5E6F7G8H9J0K1L2M3N4

╭─ Execution Started ──────────────────────────────────────╮ │ Plan: 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ Phase: execute │ │ State: processing │ │ Automation: supervised │ ╰──────────────────────────────────────────────────────────╯

╭─ Child Plans Spawned ───────────────────────────────────────────────────╮ │ Plan ID Project Status │ │ ────────────────────────── ─────────────────── ──────────────── │ │ 01HXR4C1D2E3F4G5H6I7J8K9 local/common-lib executing │ │ 01HXR4C2E3F4G5H6I7J8K9L0 local/user-service waiting (common) │ │ 01HXR4C3F4G5H6I7J8K9L0M1 local/order-service waiting (common) │ │ 01HXR4C4G5H6I7J8K9L0M1N2 local/billing-service waiting (common) │ ╰─────────────────────────────────────────────────────────────────────────╯

╭─ Execution Order ──────────────────────────────────────────╮ │ Phase 1: common-lib (blocking) │ │ Phase 2: user-service, order-service, billing-service │ │ (parallel, after common-lib completes) │ ╰────────────────────────────────────────────────────────────╯

✓ OK Execution started (4 child plans spawned)

Step 4: Review and Apply in Order

Once all child plans complete execution and pass validation, review and apply them in dependency order.

# Review common-lib changes first (must be applied before services)

$ agents plan diff 01HXR4C1D2E3F4G5H6I7J8K9

╭─ Diff Summary ───────────────────────────────────────╮ │ Plan: 01HXR4C1D2E3F4G5H6I7J8K9 │ │ Project: local/common-lib │ │ Files Changed: 4 │ │ Insertions: 62 │ │ Deletions: 38 │ │ Net Change: +24 lines │ ╰──────────────────────────────────────────────────────╯

╭─ Files ───────────────────────────────────────────────────────╮ │ Path Change Status │ │ ──────────────────────────────── ──────── ────────── │ │ requirements.txt +1 -1 modified │ │ src/common/auth.py +28 -19 modified │ │ src/common/token_validator.py +18 -12 modified │ │ tests/test_auth.py +15 -6 modified │ ╰───────────────────────────────────────────────────────────────╯

╭─ Patch Preview ───────────────────────────────────────────────────╮ │ --- a/requirements.txt │ │ +++ b/requirements.txt │ │ @@ -3,1 +3,1 @@ │ │ - authlib==1.3.2 │ │ + authlib==2.0.0 │ │ --- a/src/common/auth.py │ │ +++ b/src/common/auth.py │ │ @@ -1,6 +1,8 @@ │ │ - from authlib.integrations.requests_client import OAuth2Session │ │ + from authlib.integrations.httpx_client import AsyncOAuth2Client │ │ ... │ ╰───────────────────────────────────────────────────────────────────╯

╭─ Validation ────────────────────────╮ │ pytest tests/ && mypy src/: passed │ │ Duration: 12.4s │ ╰─────────────────────────────────────╯

✓ OK Diff generated

$ agents plan apply --yes 01HXR4C1D2E3F4G5H6I7J8K9

╭─ Apply Summary ──────────────────────────────────────╮ │ Plan: 01HXR4C1D2E3F4G5H6I7J8K9 │ │ Artifacts: 4 files updated │ │ Changes: 62 insertions, 38 deletions │ │ Project: local/common-lib │ │ Applied At: 2026-02-11 10:14 │ ╰──────────────────────────────────────────────────────╯

╭─ Validation ───────────────────────╮ │ Tests: passed (24/24) │ │ Type Check: passed (0 errors) │ │ Duration: 12.4s │ ╰────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ───────────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:03:18 │ │ Total Cost: $0.064 │ ╰────────────────────────────────────────────────╯

✓ OK Changes applied

# Once common-lib is applied, review the 3 service child plans.
# Full diff shown for user-service; order-service and billing-service condensed.

$ agents plan diff 01HXR4C2E3F4G5H6I7J8K9L0

╭─ Diff Summary ───────────────────────────────────────╮ │ Plan: 01HXR4C2E3F4G5H6I7J8K9L0 │ │ Project: local/user-service │ │ Files Changed: 6 │ │ Insertions: 84 │ │ Deletions: 52 │ │ Net Change: +32 lines │ ╰──────────────────────────────────────────────────────╯

╭─ Files ───────────────────────────────────────────────────────╮ │ Path Change Status │ │ ──────────────────────────────── ──────── ────────── │ │ requirements.txt +1 -1 modified │ │ src/auth/middleware.py +22 -14 modified │ │ src/auth/oauth.py +18 -12 modified │ │ src/auth/token.py +16 -11 modified │ │ tests/test_middleware.py +14 -8 modified │ │ tests/test_oauth.py +13 -6 modified │ ╰───────────────────────────────────────────────────────────────╯

╭─ Validation ────────────────────────╮ │ pytest tests/ && mypy src/: passed │ │ Duration: 18.2s │ ╰─────────────────────────────────────╯

✓ OK Diff generated

$ agents plan diff 01HXR4C3F4G5H6I7J8K9L0M1

╭─ Diff Summary ───────────────────────────────────────╮ │ Plan: 01HXR4C3F4G5H6I7J8K9L0M1 │ │ Project: local/order-service │ │ Files Changed: 5 │ │ Insertions: 71 │ │ Deletions: 46 │ │ Net Change: +25 lines │ ╰──────────────────────────────────────────────────────╯

╭─ Validation ────────────────────────╮ │ pytest tests/ && mypy src/: passed │ │ Duration: 14.7s │ ╰─────────────────────────────────────╯

✓ OK Diff generated

$ agents plan diff 01HXR4C4G5H6I7J8K9L0M1N2

╭─ Diff Summary ───────────────────────────────────────╮ │ Plan: 01HXR4C4G5H6I7J8K9L0M1N2 │ │ Project: local/billing-service │ │ Files Changed: 4 │ │ Insertions: 58 │ │ Deletions: 34 │ │ Net Change: +24 lines │ ╰──────────────────────────────────────────────────────╯

╭─ Validation ────────────────────────╮ │ pytest tests/ && mypy src/: passed │ │ Duration: 11.3s │ ╰─────────────────────────────────────╯

✓ OK Diff generated

# Apply all 3 service child plans

$ agents plan apply --yes 01HXR4C2E3F4G5H6I7J8K9L0

╭─ Apply Summary ──────────────────────────────────────╮ │ Plan: 01HXR4C2E3F4G5H6I7J8K9L0 │ │ Artifacts: 6 files updated │ │ Changes: 84 insertions, 52 deletions │ │ Project: local/user-service │ │ Applied At: 2026-02-11 10:16 │ ╰──────────────────────────────────────────────────────╯

╭─ Validation ───────────────────────╮ │ Tests: passed (89/89) │ │ Type Check: passed (0 errors) │ │ Duration: 18.2s │ ╰────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ───────────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:04:12 │ │ Total Cost: $0.082 │ ╰────────────────────────────────────────────────╯

✓ OK Changes applied

$ agents plan apply --yes 01HXR4C3F4G5H6I7J8K9L0M1

╭─ Apply Summary ──────────────────────────────────────╮ │ Plan: 01HXR4C3F4G5H6I7J8K9L0M1 │ │ Artifacts: 5 files updated │ │ Changes: 71 insertions, 46 deletions │ │ Project: local/order-service │ │ Applied At: 2026-02-11 10:17 │ ╰──────────────────────────────────────────────────────╯

╭─ Validation ───────────────────────╮ │ Tests: passed (76/76) │ │ Type Check: passed (0 errors) │ │ Duration: 14.7s │ ╰────────────────────────────────────╯

╭─ Plan Lifecycle ───────────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:03:48 │ │ Total Cost: $0.074 │ ╰────────────────────────────────────────────────╯

✓ OK Changes applied

$ agents plan apply --yes 01HXR4C4G5H6I7J8K9L0M1N2

╭─ Apply Summary ──────────────────────────────────────╮ │ Plan: 01HXR4C4G5H6I7J8K9L0M1N2 │ │ Artifacts: 4 files updated │ │ Changes: 58 insertions, 34 deletions │ │ Project: local/billing-service │ │ Applied At: 2026-02-11 10:18 │ ╰──────────────────────────────────────────────────────╯

╭─ Validation ───────────────────────╮ │ Tests: passed (63/63) │ │ Type Check: passed (0 errors) │ │ Duration: 11.3s │ ╰────────────────────────────────────╯

╭─ Plan Lifecycle ───────────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:03:22 │ │ Total Cost: $0.068 │ ╰────────────────────────────────────────────────╯

╭─ Parent Plan Complete ──────────────────────────────────╮ │ Plan: 01HXR4D5E6F7G8H9J0K1L2M3N4 │ │ Phase: applied │ │ State: complete │ │ Child Plans: 4/4 complete │ │ Total Duration: 00:16:04 │ │ Total Cost: $0.340 │ │ All Validations: passed │ ╰─────────────────────────────────────────────────────────╯

✓ OK Changes applied


Example 5: Database Schema Migration with Safety Nets

Scenario: A team needs to add a last_login_at column to a users table with 10 million rows, backfill it from an audit log, and update the application code — all without downtime.

Complexity: Advanced. Mixed resource types (git + database), custom tools, checkpointing critical.

Step 1: Register the Database as a Resource

Register the custom resource type, then create a resource instance and link it to the project:


# Register the custom postgres-db resource type
$ agents resource type add --config ./resource-types/postgres-db.yaml

╭─ Resource Type ─────────────────────────╮ │ Name: local/postgres-db │ │ Physical/Virtual: physical │ │ User Addable: yes │ │ Registered: 2026-02-11 09:01 │ ╰─────────────────────────────────────────╯

╭─ CLI Arguments ──────────────────────────────────────────╮ │ Argument Required Description │ │ ──────────── ──────── ────────────────────────────── │ │ --host yes Database hostname │ │ --port no Port (default: 5432) │ │ --database yes Database name │ │ --schema no Schema (default: public) │ ╰──────────────────────────────────────────────────────────╯

╭─ Sandbox ──────────────────────────────╮ │ Strategy: transaction_rollback │ │ Handler: PostgresHandler (custom) │ ╰────────────────────────────────────────╯

✓ OK Resource type registered New subcommand available: agents resource add local/postgres-db


# Register the production database instance
$ agents resource add local/postgres-db local/prod-users-db \
    --host db.internal.example.com \
    --port 5432 \
    --database users_db \
    --schema public

╭─ Resource ───────────────────────────────────────╮ │ Name: local/prod-users-db │ │ ID: 01HXR5D3E4F5G6H7J8K9L0M1N2 │ │ Type: local/postgres-db │ │ Physical/Virtual: physical │ │ Host: db.internal.example.com │ │ Port: 5432 │ │ Database: users_db │ │ Schema: public │ │ Created: 2026-02-11 09:02 │ ╰──────────────────────────────────────────────────╯

╭─ Capabilities ──────────────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: transaction_rollback │ ╰─────────────────────────────────────────╯

✓ OK Resource registered


# Link the database resource to the project
$ agents project link-resource local/api-service local/prod-users-db

╭─ Resource Linked ────────────────────────────╮ │ Project: local/api-service │ │ Resource: local/prod-users-db │ │ Type: local/postgres-db │ │ Read-Only: no │ ╰──────────────────────────────────────────────╯

╭─ Permissions ────────────╮ │ Read: allowed │ │ Write: allowed │ │ Apply: requires approval │ ╰──────────────────────────╯

╭─ Project Resources ─────────────────────────────────────────────╮ │ ID Type Status │ │ ────────────────────────────── ──────────────── ────────── │ │ 01HXR1A1B2C3D4E5F6G7H8J9K0 git-checkout linked │ │ 01HXR5D3E4F5G6H7J8K9L0M1N2 local/postgres-db linked (new) │ ╰─────────────────────────────────────────────────────────────────╯

✓ OK Resource linked to project

Step 2: Create a Custom Skill with Database Tools

Create skills/database-ops.yaml:


name: local/database-ops
description: "Safe database operations with transaction support"
tools:
  - name: query_db
    description: "Execute a read-only SQL query and return results"
    input_schema:
      type: object
      properties:
        sql:
          type: string
          description: "SQL SELECT query"
        params:
          type: array
          description: "Query parameters"
      required: [sql]
    writes: false
    checkpointable: false
    resource_slots:
      - name: database
        type: local/postgres-db
        binding: contextual
  • name: execute_migration description: "Execute a DDL migration within a transaction" input_schema: type: object properties: up_sql: type: string description: "Forward migration SQL" down_sql: type: string description: "Rollback migration SQL" description: type: string description: "Human-readable description" required: [up_sql, down_sql, description] writes: true checkpointable: true resource_slots:

    • name: database type: local/postgres-db binding: contextual
  • name: backfill_column description: "Batch-update a column using a source query" input_schema: type: object properties: table: type: string column: type: string source_query: type: string description: "Query that returns (id, value) pairs" batch_size: type: integer default: 10000 required: [table, column, source_query] writes: true checkpointable: true resource_slots:

    • name: database type: local/postgres-db binding: contextual

$ agents skill add --config ./skills/database-ops.yaml

╭─ Skill Registered ─────────────────────────────────────────────╮ │ Name: local/database-ops │ │ Description: Safe database operations with transaction support │ │ Config: ./skills/database-ops.yaml │ │ Created: 2026-02-11 09:04 │ ╰────────────────────────────────────────────────────────────────╯

╭─ Tool Sources ──────────────────────────────────────╮ │ Source Count Details │ │ ──────── ───── ──────────────────────────── │ │ custom 3 query_db, execute_migration, │ │ backfill_column │ │ ──────── ───── ──────────────────────────── │ │ Total: 3 │ ╰─────────────────────────────────────────────────────╯

╭─ Resource Slots ───────────────────────────────────╮ │ Tool Slot Type │ │ ───────────────── ──────── ────────────────── │ │ query_db database local/postgres-db │ │ execute_migration database local/postgres-db │ │ backfill_column database local/postgres-db │ ╰────────────────────────────────────────────────────╯

✓ OK Skill registered with 3 tools

Step 3: Create the Migration Action and Execute the Plan

Create actions/add-column-with-backfill.yaml:


name: local/add-column-with-backfill
description: "Add a column, backfill data, and update application code"
definition_of_done: |
  - Database migration adds the column with a sensible default
  - Backfill completes for all rows using the specified source
  - Application code reads/writes the new column
  - All tests pass with the new schema
  - A rollback migration is available and tested
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
automation_profile: review
reusable: true
available: true
args:
  - name: table_name
    type: string
    required: true
  - name: column_name
    type: string
    required: true
  - name: column_type
    type: string
    required: true
  - name: backfill_source
    type: string
    required: true
    description: "Description of where to source backfill data"
invariants:
  - "Migration must be backward-compatible (add column, don't rename or drop)"
  - "Backfill must be batched to avoid locking the table"
  - "Rollback migration must be provided and tested"
  - "Application code must handle both old (null) and new values gracefully"

$ agents action create --config ./actions/add-column-with-backfill.yaml

╭─ Action Created ────────────────────────────────────╮ │ Name: local/add-column-with-backfill │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Config: ./actions/add-column-with-backfill.yaml │ │ Created: 2026-02-11 09:05 │ ╰─────────────────────────────────────────────────────╯

╭─ Definition of Done ─────────────────────────────────────────────╮ │ - Database migration adds the column with a sensible default │ │ - Backfill completes for all rows using the specified source │ │ - Application code reads/writes the new column │ │ - All tests pass with the new schema │ │ - A rollback migration is available and tested │ ╰──────────────────────────────────────────────────────────────────╯

╭─ Arguments ────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ──────────────── ────── ──────── ───────────────────────────────── │ │ table_name string yes (none) │ │ column_name string yes (none) │ │ column_type string yes (none) │ │ backfill_source string yes Where to source backfill data │ ╰────────────────────────────────────────────────────────────────────────╯

╭─ Invariants ──────────────────────────────────────────────────────────────────────╮ │ 1. Migration must be backward-compatible (add column, don't rename or drop) │ │ 2. Backfill must be batched to avoid locking the table │ │ 3. Rollback migration must be provided and tested │ │ 4. Application code must handle both old (null) and new values gracefully │ ╰───────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────╮ │ Profile: review │ │ Source: action config │ ╰───────────────────────────────────╯

╭─ Usage ─────────────────────────────────────────────────────────────────────────╮ │ agents plan use local/add-column-with-backfill local/api-service │ │ --arg table_name=TABLE --arg column_name=COL │ │ --arg column_type=TYPE --arg backfill_source=SOURCE │ ╰─────────────────────────────────────────────────────────────────────────────────╯

✓ OK Action created


$ agents plan use local/add-column-with-backfill local/api-service \
    --arg table_name="users" \
    --arg column_name="last_login_at" \
    --arg column_type="TIMESTAMP WITH TIME ZONE" \
    --arg backfill_source="audit_log table, event_type='login', max(created_at) per user_id"

╭─ Plan Created ──────────────────────────────────────╮ │ Plan ID: 01HXR5E6F7G8H9J0K1L2M3N4O5 │ │ Phase: strategize │ │ Action: local/add-column-with-backfill │ │ Project: local/api-service │ │ Automation: review │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────────╯

╭─ Inputs ────────────────────────────────────────────────────────────────────────────╮ │ - table_name=users │ │ - column_name=last_login_at │ │ - column_type=TIMESTAMP WITH TIME ZONE │ │ - backfill_source=audit_log table, event_type='login', max(created_at) per user_id │ ╰─────────────────────────────────────────────────────────────────────────────────────╯

╭─ Actors ───────────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: (none) │ ╰────────────────────────────────────────────╯

╭─ Plan Invariants ──────────────────────────────────────────────────────────────╮ │ Scope Source Invariant │ │ ──────── ─────── ────────────────────────────────────────────────────── │ │ plan action Migration must be backward-compatible │ │ plan action Backfill must be batched to avoid locking the table │ │ plan action Rollback migration must be provided and tested │ │ plan action Application code must handle both old (null) and new values │ ╰────────────────────────────────────────────────────────────────────────────────╯

╭─ Context ──────────────────────────────╮ │ Resources: 2 (git-checkout, postgres) │ │ Indexed Files: 347 │ │ View: strategize │ │ Hot Token Budget: 12,000 │ ╰────────────────────────────────────────╯

╭─ Next Steps ───────────────────────────────────────╮ │ - agents plan execute 01HXR5E6F7G8H9J0K1L2M3N4O5 │ │ - agents plan status 01HXR5E6F7G8H9J0K1L2M3N4O5 │ │ - agents plan tree 01HXR5E6F7G8H9J0K1L2M3N4O5 │ ╰────────────────────────────────────────────────────╯

✓ OK Plan created

The strategy produces a phased plan with child plans:

  1. Generate Alembic migration (add column with NULL default)
  2. Generate rollback migration
  3. Backfill from audit_log in batches of 10,000
  4. Update ORM model and application code
  5. Run tests with new schema

Each phase creates checkpoints. If the backfill fails at batch 850 of 1,000, the system can restore to the pre-backfill checkpoint rather than starting over.

Step 4: Monitor Execution and Rollback if Needed


# Monitor the migration execution
$ agents plan status 01HXR5E6F7G8H9J0K1L2M3N4O5

╭─ Plan Status ───────────────────────────────────────╮ │ Plan: 01HXR5E6F7G8H9J0K1L2M3N4O5 │ │ Phase: execute │ │ State: processing │ │ Action: local/add-column-with-backfill │ │ Project: local/api-service │ │ Automation: review │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────────╯

╭─ Progress ─────────────────╮ │ Strategize │ │ Execute (phase 3 of 5) │ │ Apply (queued) │ ╰────────────────────────────╯

╭─ Child Plans ────────────────────────────────────────────────────────────╮ │ Phase Description Status │ │ ───── ─────────────────────────────────── ────────────────────── │ │ 1 Generate Alembic migration ✓ complete │ │ 2 Generate rollback migration ✓ complete │ │ 3 Backfill from audit_log ⏳ batch 620/1,000 │ │ 4 Update ORM model and application code ○ waiting │ │ 5 Run tests with new schema ○ waiting │ ╰──────────────────────────────────────────────────────────────────────────╯

╭─ Execution Detail ──────────────────────╮ │ Sandbox: transaction_rollback │ │ Tool Calls: 14 │ │ Files Modified: 2 │ │ Rows Backfilled: 6,200,000 / 10,000,000 │ │ Checkpoints: 4 created │ ╰─────────────────────────────────────────╯

╭─ Timing ──────────────╮ │ Started: 09:06:01 │ │ Elapsed: 00:04:32 │ │ ETA: 00:02:50 │ ╰───────────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 18,940 │ │ Cost So Far: $0.063 │ │ Estimated: $0.110 │ ╰──────────────────────╯

✓ OK Status refreshed


# If something goes wrong during backfill, rollback to the pre-backfill checkpoint
$ agents plan rollback --yes 01HXR5E6F7G8H9J0K1L2M3N4O5 cp_01HXR5CP3

╭─ Rollback Summary ───────────────────────────────────╮ │ Plan: 01HXR5E6F7G8H9J0K1L2M3N4O5 │ │ Checkpoint: cp_01HXR5CP3 │ │ Label: before backfill (after migration applied) │ │ Files: 2 reverted │ ╰──────────────────────────────────────────────────────╯

╭─ Changes Reverted ──────────────────────────────────────────╮ │ File Action │ │ ─────────────────────────────────────────── ────────── │ │ alembic/versions/20260211_add_last_login.py restored │ │ alembic/versions/20260211_rollback.py restored │ ╰─────────────────────────────────────────────────────────────╯

╭─ Database Rollback ─────────────────────────────────────────╮ │ Transaction: rolled back │ │ Rows Affected: 6,200,000 updates reverted │ │ Schema State: restored to pre-backfill │ ╰─────────────────────────────────────────────────────────────╯

╭─ Impact ──────────────────────────────────────╮ │ Child Plans Invalidated: 1 (backfill phase) │ │ Sandbox: restored to cp_01HXR5CP3 │ │ Decisions After CP: 3 discarded │ │ Tool Calls After CP: 8 undone │ ╰───────────────────────────────────────────────╯

╭─ Post-Rollback State ──────────╮ │ Phase: execute │ │ State: queued (awaiting input) │ │ Checkpoints Remaining: 3 │ ╰────────────────────────────────╯

✓ OK Rollback complete


Example 6: Writing Technical Documentation from Codebase Analysis

Scenario: A project has grown to 50,000 lines of code with minimal documentation. The team wants CleverAgents to generate comprehensive API documentation, architecture guides, and developer onboarding docs by analyzing the actual codebase.

Complexity: Intermediate. Read-only action, large context usage, no sandbox modifications to source code.

Step 1: Create a Read-Only Documentation Action

Create actions/generate-docs.yaml:


name: local/generate-docs
description: "Generate comprehensive documentation from codebase analysis"
long_description: |
  Analyze the project codebase to produce developer documentation:
  API reference, architecture overview, module guides, and onboarding
  material. Uses code intelligence (search, vector similarity, graph
  queries) to understand structure and relationships.
definition_of_done: |
  - API reference covers all public endpoints/functions
  - Architecture document shows module dependencies and data flow
  - Each major module has a developer guide
  - An onboarding document provides setup and contribution instructions
  - All generated docs are accurate to the current codebase
  - Documentation is written in Markdown format
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
read_only: false
reusable: true
available: true
args:
  - name: doc_types
    type: string
    required: true
    description: "Comma-separated list: api-reference, architecture, module-guides, onboarding"
  - name: output_dir
    type: string
    required: false
    default: "docs/"
    description: "Output directory for generated docs"
invariants:
  - "Do not modify any source code files — only create or update files in the output directory"
  - "All code examples in documentation must be actual code from the project, not fabricated"
  - "Architecture diagrams must reflect actual module dependencies, not aspirational ones"

$ agents action create --config ./actions/generate-docs.yaml

╭─ Action Created ──────────────────────────────────────────────────────────────────╮ │ Name: local/generate-docs │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 10:30 │ ╰───────────────────────────────────────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────────────────────────────╮ │ - API reference covers all public endpoints/functions │ │ - Architecture document shows module dependencies and data flow │ │ - Each major module has a developer guide │ │ - An onboarding document provides setup and contribution instructions │ │ - All generated docs are accurate to the current codebase │ │ - Documentation is written in Markdown format │ ╰───────────────────────────────────────────────────────────────────────────────────╯

╭─ Arguments ───────────────────────────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────── ────── ──────── ────────────────────────────────────────────────────────────── │ │ doc_types string yes Comma-separated list: api-reference, architecture, module-guides… │ │ output_dir string no Output directory for generated docs (default: docs/) │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Invariants ───────────────────────────────────────────────────────────────────────────────────────╮ │ 1. Do not modify any source code files — only create or update files in the output directory │ │ 2. All code examples in documentation must be actual code from the project, not fabricated │ │ 3. Architecture diagrams must reflect actual module dependencies, not aspirational ones │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: (inherits global) │ │ Source: default │ ╰───────────────────────────────────────╯

╭─ Usage ────────────────────────────────────────────────────────────────────────────╮ │ agents plan use local/generate-docs local/api-service │ │ --arg doc_types="api-reference,architecture,module-guides,onboarding" │ ╰────────────────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 2: Configure Context for Large Codebase Analysis


# Set a generous context policy for the strategize view (needs to see architecture)
$ agents project context set --view strategize \
    --include-resource 01HXR6A1B2C3D4E5F6G7H8J9K0 \
    --exclude-path "**/node_modules/**" \
    --exclude-path "**/.git/**" \
    --exclude-path "**/dist/**" \
    --hot-max-tokens 32000 \
    --warm-max-decisions 200 \
    --query-limit 50 \
    --max-file-size 2097152 \
    --summarize \
    --summary-max-tokens 1500 \
    local/api-service

╭─ Context Policy ────────────────────────────────────────╮ │ Project: local/api-service │ │ View: strategize │ │ Include: 01HXR6A1B2C3D4E5F6G7H8J9K0 │ │ Exclude: /node_modules/, /.git/, /dist/ │ ╰─────────────────────────────────────────────────────────╯

╭─ Limits ──────────────────────────╮ │ Hot Tokens: 32000 (soft cap) │ │ Warm Decisions: 200 │ │ Query Limit: 50 │ │ Max File Size: 2 MB │ │ Max Total Size: 50 MB │ ╰───────────────────────────────────╯

╭─ Summarization ──────╮ │ Enabled: yes │ │ Max Tokens: 1500 │ ╰──────────────────────╯

╭─ Other Views ──────────╮ │ execute: (default) │ │ apply: (default) │ │ default: (unset) │ ╰────────────────────────╯

✓ OK Context policy updated


# Execution view can be narrower (writing docs, not analyzing all code)
$ agents project context set --view execute \
    --include-resource 01HXR6A1B2C3D4E5F6G7H8J9K0 \
    --hot-max-tokens 16000 \
    --query-limit 30 \
    --summarize \
    local/api-service

╭─ Context Policy ────────────────────────────────────────╮ │ Project: local/api-service │ │ View: execute │ │ Include: 01HXR6A1B2C3D4E5F6G7H8J9K0 │ ╰─────────────────────────────────────────────────────────╯

╭─ Limits ──────────────────────────╮ │ Hot Tokens: 16000 (soft cap) │ │ Query Limit: 30 │ │ Max File Size: 1 MB │ │ Max Total Size: 50 MB │ ╰───────────────────────────────────╯

╭─ Summarization ─╮ │ Enabled: yes │ │ Max Tokens: 800 │ ╰─────────────────╯

╭─ Other Views ──────────────╮ │ strategize: configured │ │ apply: (default) │ │ default: (unset) │ ╰────────────────────────────╯

✓ OK Context policy updated

Step 3: Execute


$ agents plan use \
    --automation-profile trusted \
    --arg doc_types="api-reference,architecture,module-guides,onboarding" \
    --arg output_dir="docs/generated/" \
    local/generate-docs local/api-service

╭─ Plan Created ──────────────────────────────────────╮ │ Plan: 01HXR6F7G8H9J0K1L2M3N4O5P6 │ │ Phase: strategize │ │ State: processing │ │ Action: local/generate-docs │ │ Project: local/api-service │ │ Automation: trusted │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────────╯

╭─ Inputs ─────────────────────────────────────────────────────────────────────╮ │ - doc_types="api-reference,architecture,module-guides,onboarding" │ │ - output_dir="docs/generated/" │ │ - automation_profile=trusted │ ╰──────────────────────────────────────────────────────────────────────────────╯

╭─ Actors ────────────────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: (none) │ ╰─────────────────────────────────────────────────╯

╭─ Automation ───────────────────────────╮ │ Profile: trusted │ │ Source: plan override │ │ Read-Only: no │ ╰────────────────────────────────────────╯

╭─ Context ──────────────────────────╮ │ Resources: 1 (git-checkout) │ │ Indexed Files: 487 │ │ View: strategize │ │ Hot Token Budget: 32,000 │ ╰────────────────────────────────────╯

╭─ Next Steps ─────────────────────────────────────────────────────────╮ │ Trusted profile — strategize and execute will proceed automatically. │ │ - agents plan status 01HXR6F7G8H9J0K1L2M3N4O5P6 │ │ - agents plan tree 01HXR6F7G8H9J0K1L2M3N4O5P6 │ ╰──────────────────────────────────────────────────────────────────────╯

✓ OK Plan created

The system analyzes the codebase using the code intelligence indexes (full-text, vector, and graph) to understand module relationships, public APIs, and data flows. It generates documentation files in the sandbox.


# Review generated docs
$ agents plan artifacts 01HXR6F7G8H9J0K1L2M3N4O5P6

╭─ Artifacts ───────────────────────────────────────────────────────────────────────────╮ │ Path Type Size Change Child Plan │ │ ──────────────────────────────────────── ───── ─────── ──────── ─────── │ │ docs/generated/api-reference.md write 18.2 KB +412 -0 root │ │ docs/generated/architecture.md write 12.6 KB +284 -0 root │ │ docs/generated/modules/auth.md write 6.4 KB +148 -0 root │ │ docs/generated/modules/billing.md write 5.8 KB +131 -0 root │ │ docs/generated/modules/notifications.md write 4.2 KB +97 -0 root │ │ docs/generated/modules/data-pipeline.md write 5.1 KB +118 -0 root │ │ docs/generated/onboarding.md write 8.9 KB +201 -0 root │ ╰───────────────────────────────────────────────────────────────────────────────────────╯

╭─ Summary ─────────────╮ │ Total: 7 │ │ Writes: 7 (new) │ │ Edits: 0 │ │ Deletes: 0 │ │ Total Size: 61.2 KB │ ╰───────────────────────╯

✓ OK 7 artifacts listed


$ agents plan diff 01HXR6F7G8H9J0K1L2M3N4O5P6

╭─ Diff Summary ─────────────────────────────────────╮ │ Plan: 01HXR6F7G8H9J0K1L2M3N4O5P6 │ │ Project: local/api-service │ │ Files Changed: 7 │ │ Insertions: 1,391 │ │ Deletions: 0 │ │ Net Change: +1,391 lines │ ╰────────────────────────────────────────────────────╯

╭─ Files ──────────────────────────────────────────────────────────╮ │ Path Change Status │ │ ──────────────────────────────────────── ───────── ───────── │ │ docs/generated/api-reference.md +412 -0 new file │ │ docs/generated/architecture.md +284 -0 new file │ │ docs/generated/modules/auth.md +148 -0 new file │ │ docs/generated/modules/billing.md +131 -0 new file │ │ docs/generated/modules/notifications.md +97 -0 new file │ │ docs/generated/modules/data-pipeline.md +118 -0 new file │ │ docs/generated/onboarding.md +201 -0 new file │ ╰──────────────────────────────────────────────────────────────────╯

╭─ Patch Preview ───────────────────────────────────────────────────────╮ │ --- /dev/null │ │ +++ b/docs/generated/api-reference.md │ │ @@ -0,0 +1,412 @@ │ │ + # API Reference │ │ + ## Authentication │ │ + ### POST /auth/login │ │ + ... │ │ --- /dev/null │ │ +++ b/docs/generated/architecture.md │ │ @@ -0,0 +1,284 @@ │ │ + # Architecture Overview │ │ + ## Module Dependency Graph │ │ + ... │ ╰───────────────────────────────────────────────────────────────────────╯

╭─ Risk Assessment ─────────────────╮ │ Source Code: unmodified │ │ Breaking Changes: none detected │ │ New Files Only: yes │ ╰───────────────────────────────────╯

✓ OK Diff generated


# Apply the documentation to the project
$ agents plan apply --yes 01HXR6F7G8H9J0K1L2M3N4O5P6

╭─ Apply Summary ──────────────────────────────╮ │ Plan: 01HXR6F7G8H9J0K1L2M3N4O5P6 │ │ Artifacts: 7 files created │ │ Changes: 1,391 insertions, 0 deletions │ │ Project: local/api-service │ │ Applied At: 2026-02-11 10:38 │ ╰──────────────────────────────────────────────╯

╭─ Validation ────────────────────────────────╮ │ Invariant: no source files modified │ │ Invariant: code examples verified │ │ Invariant: architecture matches codebase │ │ Duration: 4.1s │ ╰─────────────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ─────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:08:12 │ │ Total Cost: $0.184 │ │ Decisions Made: 18 │ │ Child Plans: 0 │ ╰──────────────────────────────────────────╯

╭─ Next Steps ──────╮ │ - Review git diff │ │ - Commit changes │ ╰───────────────────╯

✓ OK Changes applied


Example 7: CI/CD Integration — Automated PR Review and Fix

Scenario: A CI pipeline triggers CleverAgents to automatically review incoming pull requests, run analysis, and if issues are found, create fix commits. This runs headlessly without human intervention.

Complexity: Advanced. Non-interactive (CI profile), headless execution, full automation.

Step 1: Configure for CI


# Set CI-appropriate configuration

$ agents config set core.automation-profile ci

╭─ Config Updated ───────────────────────────╮ │ Key: core.automation-profile │ │ Value: ci │ │ Previous: (not set) │ │ Source: config │ │ Scope: global │ ╰────────────────────────────────────────────╯

╭─ Effective ────────────────────────╮ │ Sessions: new sessions │ │ Plans: future plans (unless set) │ │ Existing: unchanged │ ╰────────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 3 │ ╰─────────────────────────────────────╯

✓ OK Config updated

$ agents config set core.format json

╭─ Config Updated ─────────────────╮ │ Key: core.format │ │ Value: json │ │ Previous: (not set) │ │ Source: config │ │ Scope: global │ ╰──────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 4 │ ╰─────────────────────────────────────╯

✓ OK Config updated

$ agents config set core.log.level WARNING

╭─ Config Updated ──────────────────╮ │ Key: core.log.level │ │ Value: WARNING │ │ Previous: INFO │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 5 │ ╰─────────────────────────────────────╯

✓ OK Config updated

Step 2: Create the PR Review Action

Create actions/review-pr.yaml:


name: local/review-pr
description: "Automatically review a PR and fix issues"
definition_of_done: |
  - All lint issues are resolved
  - Type checking passes
  - Test coverage does not decrease
  - Security scan passes
  - All fixes are committed to the PR branch
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
automation_profile: ci
reusable: true
available: true
args:
  - name: pr_branch
    type: string
    required: true
    description: "Branch name of the PR"
  - name: base_branch
    type: string
    required: false
    default: "main"
    description: "Base branch to compare against"
invariants:
  - "Only modify files that are already changed in the PR"
  - "Do not change the intent of any code — only fix style, types, and test issues"
  - "All fixes must include a comment explaining what was changed and why"

$ agents action create --config ./actions/review-pr.yaml

╭─ Action Created ──────────────────────────────╮ │ Name: local/review-pr │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 14:00 │ ╰───────────────────────────────────────────────╯

╭─ Definition of Done ─────────────────────────────────────╮ │ - All lint issues are resolved │ │ - Type checking passes │ │ - Test coverage does not decrease │ │ - Security scan passes │ │ - All fixes are committed to the PR branch │ ╰──────────────────────────────────────────────────────────╯

╭─ Arguments ──────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────── ────── ──────── ────────────────────────────────── │ │ pr_branch string yes Branch name of the PR │ │ base_branch string no Base branch to compare against │ ╰──────────────────────────────────────────────────────────────────╯

╭─ Invariants ─────────────────────────────────────────────────────────────────────╮ │ 1. Only modify files that are already changed in the PR │ │ 2. Do not change the intent of any code — only fix style, types, and test │ │ issues │ │ 3. All fixes must include a comment explaining what was changed and why │ ╰──────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────╮ │ Profile: ci │ │ Source: action config │ ╰───────────────────────────────╯

╭─ Usage ──────────────────────────────────────────────────────────────────╮ │ agents plan use local/review-pr <PROJECT> │ │ --arg pr_branch="..." │ ╰──────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 3: CI Pipeline Script


#!/bin/bash
# ci-review.sh — called by CI when a PR is opened or updated

set -euo pipefail

PR_BRANCH="${1:?Usage: ci-review.sh <branch>}" BASE_BRANCH="${2:-main}"

# Register the resource pointing to the CI workspace. RESOURCE_NAME="local/ci-${PR_BRANCH}" agents resource add git-checkout "$RESOURCE_NAME"
--path "$GITHUB_WORKSPACE"
--branch "$PR_BRANCH"

echo "Registered resource: $RESOURCE_NAME"

# Create a project for this CI run, linking the resource by name. # If the project already exists from a previous run, ignore the error. agents --format json project create -d "CI workspace for PR $PR_BRANCH"
--resource "$RESOURCE_NAME"
local/ci-workspace 2>/dev/null || true

# Add validations (idempotent — duplicates are ignored) agents --format json project validation add
--required local/ci-workspace "ruff check ." 2>/dev/null || true agents --format json project validation add
--required local/ci-workspace "mypy src/" 2>/dev/null || true agents --format json project validation add
--required local/ci-workspace "pytest --cov=src --cov-fail-under=80" 2>/dev/null || true

# Run the plan — ci profile means full automation including apply PLAN_OUTPUT=$(agents --format json plan use
--automation-profile ci
--arg pr_branch="$PR_BRANCH"
--arg base_branch="$BASE_BRANCH"
local/review-pr local/ci-workspace)

PLAN_ID=$(echo "$PLAN_OUTPUT" | jq -r '.plan_id') echo "Plan started: $PLAN_ID"

# Wait for completion (ci profile runs everything automatically) while true; do STATUS=$(agents --format json plan status "$PLAN_ID" | jq -r '.state') case "$STATUS" in applied) echo "PR review complete. Changes applied." break ;; failed|cancelled) echo "PR review failed." agents --format json plan status "$PLAN_ID" exit 1 ;; *) sleep 10 ;; esac done

# Output the diff for the CI log agents --format json plan diff "$PLAN_ID"

Sample --format json output from resource add (captured into $RESOURCE_JSON):


{
  "id": "01HXR7G1A2B3C4D5E6F7H8J9K0",
  "type": "git-checkout",
  "physical": true,
  "path": "/home/runner/work/acme-api/acme-api",
  "branch": "fix/handle-null-users",
  "created": "2026-02-11T14:05:32Z",
  "children_discovered": 247,
  "capabilities": {
    "readable": true,
    "writable": true,
    "sandboxable": true,
    "checkpointable": true,
    "sandbox_strategy": "git_worktree"
  }
}

Sample --format json output from plan use (captured into $PLAN_OUTPUT):


{
  "plan_id": "01HXR7H2B3C4D5E6F7G8J9K0L1",
  "phase": "strategize",
  "action": "local/review-pr",
  "project": "local/ci-workspace",
  "automation_profile": "ci",
  "attempt": 1,
  "args": {
    "pr_branch": "fix/handle-null-users",
    "base_branch": "main"
  },
  "resources": ["01HXR7G1A2B3C4D5E6F7H8J9K0"]
}

Example 8: Cloud Infrastructure Management

Scenario: A DevOps team manages Terraform infrastructure. They want CleverAgents to analyze their current infrastructure, propose optimizations (right-sizing, unused resources), and generate the Terraform changes.

Complexity: Advanced. Custom resource types, custom skills, infrastructure domain.

Step 1: Register Custom Resource Types and Skills

Create resource-types/terraform-state.yaml:


name: local/terraform-state
description: "Terraform state file resource type"
physical: true
user_addable: true
sandbox_strategy: filesystem_copy
cli_args:
  - name: state-path
    type: string
    required: true
    description: "Path to terraform.tfstate or remote state configuration"
  - name: workspace
    type: string
    required: false
    default: "default"
    description: "Terraform workspace name"
handler: local/terraform-state-handler
child_types:
  - type: fs-file
    relationship: contains

Create skills/terraform-ops.yaml:


name: local/terraform-ops
description: "Terraform infrastructure operations"
tools:
  - name: terraform_plan
    description: "Run terraform plan and return the execution plan"
    input_schema:
      type: object
      properties:
        target:
          type: string
          description: "Specific resource to target (optional)"
      required: []
    writes: false
    checkpointable: false
  • name: terraform_show description: "Show current state of a Terraform resource" input_schema: type: object properties: resource_address: type: string description: "Terraform resource address (e.g., aws_instance.web)" required: [resource_address] writes: false checkpointable: false

  • name: cloud_metrics description: "Fetch CloudWatch/cloud monitoring metrics for a resource" input_schema: type: object properties: resource_id: type: string metric: type: string description: "e.g., CPUUtilization, NetworkIn, RequestCount" period_days: type: integer default: 30 required: [resource_id, metric] writes: false checkpointable: false

include_skills:

  • local/file-ops

$ agents resource type add --config ./resource-types/terraform-state.yaml

╭─ Resource Type ──────────────────────────────╮ │ Name: local/terraform-state │ │ Physical/Virtual: physical │ │ User Addable: yes │ │ Registered: 2026-02-11 14:30 │ ╰──────────────────────────────────────────────╯

╭─ CLI Arguments ──────────────────────────────────────────────────────────────╮ │ Argument Required Description │ │ ────────────── ──────── ────────────────────────────────────────────── │ │ --state-path yes Path to terraform.tfstate or remote state config │ │ --workspace no Terraform workspace name (default: "default") │ ╰──────────────────────────────────────────────────────────────────────────────╯

╭─ Child Types ──────────────╮ │ Auto-discover: fs-file │ ╰────────────────────────────╯

╭─ Sandbox ───────────────────────────────────────────╮ │ Strategy: filesystem_copy │ │ Handler: local/terraform-state-handler (custom) │ ╰─────────────────────────────────────────────────────╯

✓ OK Resource type registered New subcommand available: agents resource add local/terraform-state


$ agents skill add --config ./skills/terraform-ops.yaml

╭─ Skill ──────────────────────────────────────────╮ │ Name: local/terraform-ops │ │ Description: Terraform infrastructure operations │ │ Config: ./skills/terraform-ops.yaml │ │ Created: 2026-02-11 14:31 │ ╰──────────────────────────────────────────────────╯

╭─ Includes ────────────────────╮ │ local/file-ops (registered) │ ╰───────────────────────────────╯

╭─ Tool Sources ───────────────────────────────────────────────────────╮ │ Source Count Details │ │ ──────── ───── ────────────────────────────────────────────── │ │ custom 3 terraform_plan, terraform_show, cloud_metrics │ │ included 5 local/file-ops (5) │ │ ──────── ───── ────────────────────────────────────────────── │ │ Total: 8 │ ╰──────────────────────────────────────────────────────────────────────╯

✓ OK Skill registered with 8 tools

Step 2: Set Up the Project


# Register the infrastructure git checkout
$ agents resource add git-checkout local/infra-repo \
    --path /repos/infrastructure --branch main

╭─ Resource ──────────────────────────────────────╮ │ Name: local/infra-repo │ │ ID: 01HXR8A1B2C3D4E5F6G7H8J9K0 │ │ Type: git-checkout │ │ Physical/Virtual: physical │ │ Path: /repos/infrastructure │ │ Branch: main │ │ Created: 2026-02-11 14:32 │ ╰─────────────────────────────────────────────────╯

╭─ Auto-discovered Children ─────────────────────────────────────────╮ │ ID Type Status │ │ ─────────────── ────────────── ───────────────── │ │ 01HXR8A1B2C3… git created │ │ 01HXR8A1B2C4… git-remote created │ │ 01HXR8A1B2C5… git-branch created │ │ 01HXR8A1B2C6… fs-directory created │ │ + 18 git-commit resources │ │ + 84 git-tree-entry resources │ │ + 6 fs-directory + 42 fs-file │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Capabilities ─────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: git_worktree │ ╰────────────────────────────────╯

✓ OK Resource registered (155 child resources discovered)


# Register the Terraform state for the production workspace
$ agents resource add local/terraform-state local/prod-tfstate \
    --state-path /repos/infrastructure/environments/prod/terraform.tfstate \
    --workspace production

╭─ Resource ──────────────────────────────────────────────────────────────────╮ │ Name: local/prod-tfstate │ │ ID: 01HXR8B2C3D4E5F6G7H8J9K0L1 │ │ Type: local/terraform-state │ │ Physical/Virtual: physical │ │ State Path: /repos/infrastructure/environments/prod/terraform.tfstate │ │ Workspace: production │ │ Created: 2026-02-11 14:32 │ ╰─────────────────────────────────────────────────────────────────────────────╯

╭─ Auto-discovered Children ─────────────╮ │ + 1 fs-file (terraform.tfstate) │ ╰────────────────────────────────────────╯

╭─ Capabilities ──────────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: filesystem_copy │ ╰─────────────────────────────────────╯

✓ OK Resource registered (1 child resource discovered)


# Create the project, linking both resources by name
$ agents project create -d "Production infrastructure" \
    --resource local/infra-repo \
    --resource local/prod-tfstate \
    --invariant "Never delete or modify resources tagged with 'critical: true'" \
    --invariant "All changes must be backward-compatible with running services" \
    --invariant "Cost changes must be documented in the PR description" \
    local/infra-prod

╭─ Project Created ─────────────────────────────╮ │ Name: local/infra-prod │ │ Description: Production infrastructure │ │ Remote: no │ ╰───────────────────────────────────────────────╯

╭─ Linked Resources ──────────────────────────────────────────────────╮ │ Resource Type Read-Only │ │ ──────────────────────────── ────────────────────── ───────── │ │ local/infra-repo git-checkout no │ │ local/prod-tfstate local/terraform-state no │ ╰─────────────────────────────────────────────────────────────────────╯

╭─ Invariants ──────────────────────────────────────────────────────────────╮ │ 1. Never delete or modify resources tagged with 'critical: true' │ │ 2. All changes must be backward-compatible with running services │ │ 3. Cost changes must be documented in the PR description │ ╰───────────────────────────────────────────────────────────────────────────╯

✓ OK Project created


$ agents project validation add --required local/infra-prod \
    "cd environments/prod && terraform validate"

╭─ Validation Added ─────────────────────────────────────────────────╮ │ ID: val_01HXM8B │ │ Project: local/infra-prod │ │ Command: cd environments/prod && terraform validate │ │ Mode: required │ │ Timeout: 300s │ ╰────────────────────────────────────────────────────────────────────╯

✓ OK Validation added


$ agents project validation add --informational local/infra-prod \
    "cd environments/prod && terraform plan -detailed-exitcode"

╭─ Validation Added ──────────────────────────────────────────────────────────────╮ │ ID: val_01HXM8C │ │ Project: local/infra-prod │ │ Command: cd environments/prod && terraform plan -detailed-exitcode │ │ Mode: informational │ │ Timeout: 300s │ ╰─────────────────────────────────────────────────────────────────────────────────╯

✓ OK Validation added

Step 3: Create and Run the Optimization Action

Create actions/infra-optimize.yaml:


name: local/infra-optimize
description: "Analyze and optimize cloud infrastructure costs"
definition_of_done: |
  - Unused resources are identified and removal plans generated
  - Over-provisioned resources are identified with right-sizing recommendations
  - Terraform changes implement the approved optimizations
  - terraform validate passes on all changes
  - terraform plan shows no unexpected resource deletions
  - Estimated monthly cost savings are documented
strategy_actor: local/refactoring-strategist
execution_actor: anthropic/claude-3.5-sonnet
automation_profile: supervised
reusable: true
available: true
args:
  - name: optimization_targets
    type: string
    required: false
    default: "all"
    description: "Comma-separated: compute, storage, networking, database, all"
  - name: min_savings_threshold
    type: float
    required: false
    default: 10.0
    description: "Minimum monthly savings (USD) to include an optimization"
invariants:
  - "Changes to production databases require manual approval regardless of profile"
  - "Instance type downgrades must verify current peak CPU < 70% of new capacity"

$ agents action create --config ./actions/infra-optimize.yaml

╭─ Action Created ──────────────────────────────────────╮ │ Name: local/infra-optimize │ │ ID: 01HXR8C3D4E5F6G7H8J9K0L1M2 │ │ State: available │ │ Strategy Actor: local/refactoring-strategist │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Config: ./actions/infra-optimize.yaml │ │ Created: 2026-02-11 14:33 │ ╰───────────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────────────────╮ │ - Unused resources are identified and removal plans generated │ │ - Over-provisioned resources identified with right-sizing recs │ │ - Terraform changes implement the approved optimizations │ │ - terraform validate passes on all changes │ │ - terraform plan shows no unexpected resource deletions │ │ - Estimated monthly cost savings are documented │ ╰───────────────────────────────────────────────────────────────────────╯

╭─ Arguments ───────────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────────────────── ────── ──────── ────────────────────────────────── │ │ optimization_targets string no Comma-separated: compute, storage, … │ │ min_savings_threshold float no Min monthly savings (USD) to include │ ╰───────────────────────────────────────────────────────────────────────────────────╯

╭─ Invariants ──────────────────────────────────────────────────────────────────────────╮ │ 1. Changes to production databases require manual approval regardless of profile │ │ 2. Instance type downgrades must verify current peak CPU < 70% of new capacity │ ╰───────────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: supervised │ │ Source: action config │ ╰───────────────────────────────────────╯

╭─ Usage ─────────────────────────────────────────────────────────────╮ │ agents plan use local/infra-optimize local/infra-prod │ │ --arg optimization_targets=TARGET --arg min_savings_threshold=N │ ╰─────────────────────────────────────────────────────────────────────╯

✓ OK Action created


$ agents plan use \
    --arg optimization_targets="compute,storage" \
    --arg min_savings_threshold=25.0 \
    local/infra-optimize local/infra-prod

╭─ Plan Created ─────────────────────────────────────────╮ │ Plan ID: 01HXR8D4E5F6G7H8J9K0L1M2N3 │ │ Phase: strategize │ │ Action: local/infra-optimize │ │ Project: local/infra-prod │ │ Automation: supervised │ │ Attempt: 1 │ ╰────────────────────────────────────────────────────────╯

╭─ Inputs ──────────────────────────────────────╮ │ - optimization_targets=compute,storage │ │ - min_savings_threshold=25.0 │ ╰───────────────────────────────────────────────╯

╭─ Actors ─────────────────────────────────────╮ │ Strategy: local/refactoring-strategist │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: (none) │ ╰──────────────────────────────────────────────╯

╭─ Plan Invariants ──────────────────────────────────────────────────────────────────╮ │ Scope Source Invariant │ │ ──────── ──────── ───────────────────────────────────────────────────────── │ │ plan action Prod DB changes require manual approval regardless │ │ plan action Instance downgrades must verify peak CPU < 70% of new cap │ │ project config Never delete or modify resources tagged 'critical: true' │ │ project config All changes must be backward-compatible with running svcs │ │ project config Cost changes must be documented in PR description │ ╰────────────────────────────────────────────────────────────────────────────────────╯

╭─ Context ──────────────────────────────────────────╮ │ Resources: 2 (git-checkout, terraform-state) │ │ Indexed Files: 156 │ │ View: strategize │ │ Hot Token Budget: 12,000 │ ╰────────────────────────────────────────────────────╯

╭─ Next Steps ──────────────────────────────────────────╮ │ - agents plan execute 01HXR8D4E5F6G7H8J9K0L1M2N3 │ │ - agents plan status 01HXR8D4E5F6G7H8J9K0L1M2N3 │ │ - agents plan tree 01HXR8D4E5F6G7H8J9K0L1M2N3 │ ╰───────────────────────────────────────────────────────╯

✓ OK Plan created

The strategy actor queries cloud metrics via the cloud_metrics tool, analyzes the Terraform state using terraform_show, and proposes optimizations with cost estimates. Because the automation profile is supervised, the engineer reviews the full strategy — including any proposed instance downgrades or resource removals — before execution modifies any Terraform files. The execution actor then generates the .tf changes, and both validations (terraform validate and terraform plan -detailed-exitcode) run automatically before the plan can be applied.


Example 9: Session-Driven Interactive Exploration

Scenario: A developer uses a CleverAgents session to interactively explore a new codebase, ask questions, and gradually build up an action to automate a recurring task.

Complexity: Beginner-Intermediate. Session-based, conversational, action creation through natural language.

Step 1: Start a Session


$ agents session create --actor anthropic/claude-3.5-sonnet

╭─ Session ────────────────────────────────╮ │ ID: 01HXR9A1B2C3D4E5F6G7H8I9J0 │ │ Actor: anthropic/claude-3.5-sonnet │ │ Created: 2026-02-11 09:15 │ │ Namespace: local │ ╰──────────────────────────────────────────╯

╭─ Settings ─────────────╮ │ Automation: review │ │ Streaming: off │ │ Context: default │ │ Memory: enabled │ │ Max History: 50 turns │ ╰────────────────────────╯

╭─ Actor Details ────────────────────────╮ │ Provider: anthropic │ │ Model: claude-3.5-sonnet │ │ Temperature: 0.7 │ │ Context Window: 200K tokens │ ╰────────────────────────────────────────╯

✓ OK Session created

Step 2: Explore the Codebase Interactively


$ agents session tell --session 01HXR9A1B2C3D4E5F6G7H8I9J0 \
    "I just joined the team and need to understand the api-service project. What are the main modules and how do they interact?"

╭─ Plan Request ──────────────────────────────────────────────────────────────────────────╮ │ Actor: anthropic/claude-3.5-sonnet │ │ Session: 01HXR9A1B2C3D4E5F6G7H8I9J0 │ │ Automation: review │ │ Prompt: I just joined the team and need to understand the api-service project. Wha... │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯

The api-service project is organized into 5 core modules:

  1. src/api/routes/ — HTTP route definitions (REST + GraphQL). Each domain entity has its own router file (e.g. users.py, orders.py, products.py).

  2. src/api/services/ — Business logic layer. Services are injected into routes via dependency injection. Key files: user_service.py, order_service.py, notification_service.py.

  3. src/api/models/ — SQLAlchemy ORM models and Pydantic schemas. The models map 1:1 to database tables; schemas handle request/response validation.

  4. src/api/auth/ — Authentication and authorization. Implements JWT-based auth with role-based access control. Middleware in auth_middleware.py intercepts every request before it reaches a route handler.

  5. src/api/workers/ — Background task processors using Celery. Handles async jobs like email dispatch, report generation, and webhook delivery.

Data flow: Routes → Services → Models → Database. Auth middleware gates every route. Workers are dispatched by services for async operations.

╭─ Commands Executed ──────────────────────────────────────────────────────────────╮ │ - agents resource inspect local/api-service-repo --tree │ │ - agents resource inspect local/api-service-repo --file src/api/__init__.py │ ╰──────────────────────────────────────────────────────────────────────────────────╯

╭─ Usage ─────────────────────╮ │ Input Tokens: 2,480 │ │ Output Tokens: 846 │ │ Cost: $0.0128 │ │ Duration: 4.1s │ │ Tool Calls: 2 │ ╰─────────────────────────────╯

✓ OK Orchestrator completed 2 commands


$ agents session tell --session 01HXR9A1B2C3D4E5F6G7H8I9J0 \
    "Show me how authentication works. What's the flow from request to response?"

╭─ Plan Request ───────────────────────────────────────────────────────────────────╮ │ Actor: anthropic/claude-3.5-sonnet │ │ Session: 01HXR9A1B2C3D4E5F6G7H8I9J0 │ │ Automation: review │ │ Prompt: Show me how authentication works. What's the flow from request to res... │ ╰──────────────────────────────────────────────────────────────────────────────────╯

Here is the authentication flow in api-service:

1. Request arrivesauth_middleware.py:34 extracts the Authorization header and parses the Bearer token.

2. Token validationtoken_service.py:71 decodes the JWT using the public key from config.AUTH_PUBLIC_KEY. It verifies: - Signature (RS256) - Expiry (exp claim, default 3600s) - Issuer (iss must match api-service)

3. User resolutionuser_service.py:45 loads the user record from the database using the sub claim. Returns 401 if the user is inactive or deleted.

4. Permission checkrbac.py:22 evaluates the user's roles against the endpoint's required permissions (defined as decorators on each route, e.g. @require_role("admin")). Returns 403 on insufficient permissions.

5. Context injection → The authenticated user object is attached to request.state.user so downstream route handlers can access it without repeating lookups.

Key files: src/api/auth/auth_middleware.py, src/api/auth/token_service.py, src/api/auth/rbac.py, src/api/services/user_service.py.

╭─ Commands Executed ──────────────────────────────────────────────────────────────────────╮ │ - agents resource inspect local/api-service-repo --file src/api/auth/auth_middleware.py │ │ - agents resource inspect local/api-service-repo --file src/api/auth/token_service.py │ │ - agents resource inspect local/api-service-repo --file src/api/auth/rbac.py │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Usage ─────────────────────╮ │ Input Tokens: 3,960 │ │ Output Tokens: 1,024 │ │ Cost: $0.0187 │ │ Duration: 5.3s │ │ Tool Calls: 3 │ ╰─────────────────────────────╯

✓ OK Orchestrator completed 3 commands


$ agents session tell --session 01HXR9A1B2C3D4E5F6G7H8I9J0 \
    "I notice the team manually runs a dependency lock refresh every week. Can you create an action that automates this?"

╭─ Plan Request ──────────────────────────────────────────────────────────────────────────╮ │ Actor: anthropic/claude-3.5-sonnet │ │ Session: 01HXR9A1B2C3D4E5F6G7H8I9J0 │ │ Automation: review │ │ Prompt: I notice the team manually runs a dependency lock refresh every week. Can... │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯

I've created a local/refresh-locks action that automates the weekly dependency lock refresh. Here's what it does:

  1. Checks out the target project's repository
  2. Runs pip compile / poetry lock (auto-detected from project config)
  3. Runs the test suite to verify nothing broke
  4. Commits the updated lock files on a new branch
  5. Opens a pull request for review

The action is saved as a draft. You can review the generated config with agents action show local/refresh-locks and publish it when ready.

╭─ Commands Executed ──────────────────────────────────────────────────────────────────╮ │ - agents action create --config ./actions/refresh-locks.yaml local/refresh-locks │ ╰──────────────────────────────────────────────────────────────────────────────────────╯

╭─ Result ────────────────────────────╮ │ Action: local/refresh-locks (draft) │ │ Steps: 5 │ │ Trigger: manual │ ╰─────────────────────────────────────╯

╭─ Usage ─────────────────────╮ │ Input Tokens: 5,210 │ │ Output Tokens: 1,380 │ │ Cost: $0.0249 │ │ Duration: 6.7s │ │ Tool Calls: 1 │ ╰─────────────────────────────╯

✓ OK Orchestrator completed 1 command

Step 3: Review Session History


$ agents session show 01HXR9A1B2C3D4E5F6G7H8I9J0

╭─ Session Summary ─────────────────────────────╮ │ ID: 01HXR9A1B2C3D4E5F6G7H8I9J0 │ │ Actor: anthropic/claude-3.5-sonnet │ │ Messages: 6 │ │ Created: 2026-02-11 09:15 │ │ Updated: 2026-02-11 09:28 │ │ Automation: review │ ╰───────────────────────────────────────────────╯

╭─ Recent Messages ──────────────────────────────────────────────────────────────────────╮ │ user I just joined the team and need to understand the api-service project... │ │ assistant The api-service project is organized into 5 core modules... │ │ user Show me how authentication works... │ │ assistant Here is the authentication flow in api-service... │ │ user I notice the team manually runs a dependency lock refresh... │ │ assistant I've created a local/refresh-locks action that automates... │ ╰────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Linked Plans ──────────────────────────────────╮ │ Plan ID Phase State │ │ ─────────────────────────── ─────── ──────── │ │ 01HXR9K4M7N2P3Q5R6S8T9U0V1 execute complete │ ╰─────────────────────────────────────────────────╯

╭─ Token Usage ──────────────╮ │ Input Tokens: 11,650 │ │ Output Tokens: 3,250 │ │ Estimated Cost: $0.0564 │ ╰────────────────────────────╯

✓ OK Session details loaded


$ agents session export --output /tmp/onboarding-session.json 01HXR9A1B2C3D4E5F6G7H8I9J0

╭─ Session Export ────────────────────────────╮ │ Session: 01HXR9A1B2C3D4E5F6G7H8I9J0 │ │ Output: /tmp/onboarding-session.json │ │ Messages: 6 │ │ Size: 38 KB │ │ Format: JSON │ ╰─────────────────────────────────────────────╯

╭─ Contents ─────────────────╮ │ Messages: 6 │ │ Plan References: 1 │ │ Metadata Keys: 3 │ │ Actor Config: included │ │ Schema Version: v3 │ ╰────────────────────────────╯

╭─ Integrity ──────────────────╮ │ Checksum: sha256:3e8f...b7d2 │ │ Encrypted: no │ ╰──────────────────────────────╯

✓ OK Export completed


Example 10: Full-Auto Batch Operations — Formatting and Linting

Scenario: A team has 15 Python packages in a monorepo that need to be reformatted with ruff format and have their imports sorted. This is low-risk and can be fully automated.

Complexity: Simple. Full-auto profile, batch execution, minimal risk.

Step 1: Create a Formatting Action

Create actions/format-codebase.yaml:


name: local/format-codebase
description: "Apply code formatting and import sorting"
definition_of_done: |
  - ruff format passes with zero changes remaining
  - ruff check --select I passes (imports sorted)
  - All existing tests pass
  - No semantic changes to any code
strategy_actor: anthropic/claude-3.5-sonnet
execution_actor: anthropic/claude-3.5-sonnet
automation_profile: full-auto
reusable: true
available: true
args:
  - name: formatter_config
    type: string
    required: false
    default: "pyproject.toml"
    description: "Path to the formatter configuration file"
invariants:
  - "Only whitespace and import ordering changes — no semantic modifications"
  - "Every package must pass its own test suite after formatting"

$ agents action create --config ./actions/format-codebase.yaml

╭─ Action Created ─────────────────────────────────╮ │ Name: local/format-codebase │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 14:00 │ ╰──────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────╮ │ - ruff format passes with zero changes remaining │ │ - ruff check --select I passes (imports sorted) │ │ - All existing tests pass │ │ - No semantic changes to any code │ ╰───────────────────────────────────────────────────────────╯

╭─ Arguments ──────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ──────────────── ────── ──────── ────────────────────────────────────── │ │ formatter_config string no Path to the formatter configuration file │ ╰──────────────────────────────────────────────────────────────────────────────╯

╭─ Invariants ──────────────────────────────────────────────────────────────────────╮ │ 1. Only whitespace and import ordering changes — no semantic modifications │ │ 2. Every package must pass its own test suite after formatting │ ╰───────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: full-auto │ │ Source: action │ ╰───────────────────────────────────────╯

╭─ Usage ─────────────────────────────────────────────────────────╮ │ agents plan use local/format-codebase local/<project> │ │ --arg formatter_config="pyproject.toml" (optional) │ ╰─────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 2: Register All Packages and Run in Batch


# Register all 15 packages as resources and projects.
# resource add accepts a name — use it to link to project create.

for pkg in auth billing common gateway inventory notifications
orders payments reporting search shipping users webhooks
workers analytics; do agents resource add git-checkout "local/pkg-${pkg}-repo"
--path "/repos/monorepo/packages/${pkg}" --branch main agents project create -d "Package: ${pkg}"
--resource "local/pkg-${pkg}-repo"
"local/pkg-${pkg}" agents project validation add --required "local/pkg-${pkg}"
"cd /repos/monorepo/packages/${pkg} && pytest tests/" done


# Loop output — first 2 iterations shown, remaining 13 condensed

# --- auth ---

$ agents resource add git-checkout local/pkg-auth-repo
--path /repos/monorepo/packages/auth --branch main

╭─ Resource ──────────────────────────────────────────╮ │ Name: local/pkg-auth-repo │ │ ID: 01HXR7B1A2B3C4D5E6F7G8H9J0 │ │ Type: git-checkout │ │ Physical/Virtual: physical │ │ Path: /repos/monorepo/packages/auth │ │ Branch: main │ │ Created: 2026-02-11 14:01 │ ╰─────────────────────────────────────────────────────╯

╭─ Auto-discovered Children ─────────────────────────────────────────╮ │ ID Type Status │ │ ─────────────── ────────────── ───────────────── │ │ 01HXR7B1A2B3… git created │ │ 01HXR7B1A2B4… git-remote created │ │ 01HXR7B1A2B5… git-branch created │ │ + 22 git-commit resources │ │ + 134 git-tree-entry resources │ │ + 2 fs-directory + 11 fs-file │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Capabilities ─────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: git_worktree │ ╰────────────────────────────────╯

✓ OK Resource registered (172 child resources discovered)

$ agents project create -d "Package: auth"
--resource local/pkg-auth-repo local/pkg-auth

╭─ Project Created ──────────────────────────────╮ │ Name: local/pkg-auth │ │ Description: Package: auth │ │ Type: local │ │ Created: 2026-02-11 14:01 │ ╰────────────────────────────────────────────────╯

╭─ Linked Resources ───────────────────────────────────────╮ │ Resource Type Read-Only │ │ ───────────────── ────────────── ───────── │ │ local/pkg-auth-repo git-checkout no │ ╰──────────────────────────────────────────────────────────╯

╭─ Defaults ──────────────────────────────╮ │ Sandbox: git_worktree │ │ Validations: 0 │ │ Context Filters: none │ │ Automation Profile: (inherits global) │ ╰─────────────────────────────────────────╯

✓ OK Project created

$ agents project validation add --required local/pkg-auth
"cd /repos/monorepo/packages/auth && pytest tests/"

╭─ Validation Added ──────────────────────────────────────────────────────╮ │ ID: val_01HXR7V1A │ │ Project: local/pkg-auth │ │ Command: cd /repos/monorepo/packages/auth && pytest tests/ │ │ Mode: required │ │ Timeout: 300s │ ╰─────────────────────────────────────────────────────────────────────────╯

✓ OK Validation added

# --- billing ---

$ agents resource add git-checkout local/pkg-billing-repo
--path /repos/monorepo/packages/billing --branch main ✓ OK Resource registered — Name: local/pkg-billing-repo (189 children)

$ agents project create -d "Package: billing"
--resource local/pkg-billing-repo local/pkg-billing ✓ OK Project created — Name: local/pkg-billing

$ agents project validation add --required local/pkg-billing
"cd /repos/monorepo/packages/billing && pytest tests/" ✓ OK Validation added — ID: val_01HXR7V2B Project: local/pkg-billing

# ... (common, gateway, inventory, notifications, orders, payments, # reporting, search, shipping, users, webhooks, workers, analytics) # Each iteration: resource add → project create → validation add # All 15 packages registered.


# Run formatting across all packages.
# full-auto: Strategize, Execute, AND Apply all run without human intervention.
# Capture plan IDs so we can check results afterward.

PLAN_IDS=() for pkg in auth billing common gateway inventory notifications
orders payments reporting search shipping users webhooks
workers analytics; do PID=$(agents --format json plan use
--automation-profile full-auto
local/format-codebase "local/pkg-${pkg}"
| jq -r '.data.plan_id') PLAN_IDS+=("$PID") done


# Plan creation output — first 2 shown, remaining condensed

# --- auth ---

$ agents plan use
--automation-profile full-auto
local/format-codebase local/pkg-auth

╭─ Plan Created ───────────────────────────────────╮ │ Plan ID: 01HXR7D1A2B3C4D5E6F7G8H9J0 │ │ Phase: strategize (running) │ │ Action: local/format-codebase │ │ Project: local/pkg-auth │ │ Automation: full-auto │ │ Attempt: 1 │ ╰──────────────────────────────────────────────────╯

╭─ Invariants ─────────────────────────────────────────────────────────────╮ │ Scope Source Invariant │ │ ────── ────── ───────────────────────────────────────────────────── │ │ plan action Only whitespace and import ordering changes — no se… │ │ plan action Every package must pass its own test suite after fo… │ ╰──────────────────────────────────────────────────────────────────────────╯

✓ OK Plan created — full-auto: strategize → execute → apply will proceed automatically

# --- billing ---

$ agents plan use
--automation-profile full-auto
local/format-codebase local/pkg-billing

╭─ Plan Created ───────────────────────────────────╮ │ Plan ID: 01HXR7D2B3C4D5E6F7G8H9J0K1 │ │ Phase: strategize (running) │ │ Action: local/format-codebase │ │ Project: local/pkg-billing │ │ Automation: full-auto │ │ Attempt: 1 │ ╰──────────────────────────────────────────────────╯

✓ OK Plan created — full-auto: strategize → execute → apply will proceed automatically

# ... (common, gateway, inventory, notifications, orders, payments, # reporting, search, shipping, users, webhooks, workers, analytics) # 15 plans launched — all running full-auto in background.


# Wait for all plans to finish, then check results

$ agents plan list --state applied

╭─ Plans ──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ID Phase State Action Project Elapsed │ │ ──────── ─────── ──────── ───────────────────── ───────────────────── ───────── │ │ 01HXR7D1 applied complete local/format-codebase local/pkg-auth 00:02:14 │ │ 01HXR7D2 applied complete local/format-codebase local/pkg-billing 00:02:31 │ │ 01HXR7D3 applied complete local/format-codebase local/pkg-common 00:01:47 │ │ 01HXR7D4 applied complete local/format-codebase local/pkg-gateway 00:02:08 │ │ 01HXR7D5 applied complete local/format-codebase local/pkg-inventory 00:01:55 │ │ 01HXR7D6 applied complete local/format-codebase local/pkg-notifications 00:02:42 │ │ 01HXR7D7 applied complete local/format-codebase local/pkg-orders 00:02:19 │ │ 01HXR7D8 applied complete local/format-codebase local/pkg-payments 00:01:58 │ │ 01HXR7D9 applied complete local/format-codebase local/pkg-reporting 00:02:36 │ │ 01HXR7DA applied complete local/format-codebase local/pkg-search 00:01:41 │ │ 01HXR7DB applied complete local/format-codebase local/pkg-shipping 00:02:22 │ │ 01HXR7DC applied complete local/format-codebase local/pkg-users 00:01:49 │ │ 01HXR7DD applied complete local/format-codebase local/pkg-webhooks 00:02:05 │ │ 01HXR7DE applied complete local/format-codebase local/pkg-analytics 00:02:11 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Filters ───────────────────╮ │ Phase: (any) │ │ State: applied │ │ Project: (any) │ │ Action: (any) │ ╰─────────────────────────────╯

╭─ Summary ─────────────╮ │ Total: 14 │ │ Processing: 0 │ │ Completed: 14 │ │ Errored: 0 │ ╰───────────────────────╯

✓ OK 14 plans listed

$ agents plan list --state failed

╭─ Plans ──────────────────────────────────────────────────────────────────────────────────────────────╮ │ ID Phase State Action Project Elapsed │ │ ──────── ─────── ─────── ───────────────────── ─────────────────── ───────── │ │ 01HXR7DF execute errored local/format-codebase local/pkg-workers 00:03:07 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Filters ───────────────────╮ │ Phase: (any) │ │ State: failed │ │ Project: (any) │ │ Action: (any) │ ╰─────────────────────────────╯

╭─ Summary ─────────────╮ │ Total: 1 │ │ Processing: 0 │ │ Completed: 0 │ │ Errored: 1 │ ╰───────────────────────╯

✓ OK 1 plan listed


Example 11: Complex Graph Actor for Multi-Stage Code Review

Scenario: A team builds a custom multi-stage code review actor that performs security analysis, performance analysis, and style checking in a graph topology — with each stage running a different specialized sub-actor.

Complexity: Expert. Custom actor graph, multiple sub-actors, advanced actor configuration.

Step 1: Define Specialized Sub-Actors

Create actors/review-pipeline.yaml:


name: local/review-pipeline
cleveragents:
  version: "3.0"
  template_engine: JINJA2
  default_actor: orchestrator

global_context: review_standards: "Google Python Style Guide" severity_levels: "critical, high, medium, low, info"

actors: orchestrator: type: llm config: actor: anthropic/claude-3.5-sonnet temperature: 0.1 system_prompt: | You are a code review orchestrator. You coordinate specialized reviewers and synthesize their findings into a unified review report. Standards: {{ context.review_standards }} Severity levels: {{ context.severity_levels }} memory_enabled: true

security_reviewer: type: llm config: actor: anthropic/claude-3.5-sonnet temperature: 0.0 system_prompt: | You are a security-focused code reviewer. Analyze code for: - Injection vulnerabilities (SQL, command, XSS) - Authentication and authorization flaws - Sensitive data exposure - Insecure cryptographic practices - Dependency vulnerabilities Report findings with severity levels: {{ context.severity_levels }}

performance_reviewer: type: llm config: actor: anthropic/claude-3.5-sonnet temperature: 0.0 system_prompt: | You are a performance-focused code reviewer. Analyze code for: - N+1 query patterns - Unbounded loops or recursion - Memory leaks and excessive allocation - Missing caching opportunities - Blocking operations in async contexts Report findings with severity levels: {{ context.severity_levels }}

style_reviewer: type: llm config: actor: anthropic/claude-3.5-sonnet temperature: 0.0 system_prompt: | You are a code style and maintainability reviewer. Standards: {{ context.review_standards }} Analyze code for: - Naming conventions - Function/class design - Documentation completeness - Test coverage patterns - Code duplication

routes: review_graph: type: graph entry_point: dispatch checkpointing: true nodes: dispatch: type: agent agent: orchestrator security: type: agent agent: security_reviewer performance: type: agent agent: performance_reviewer style: type: agent agent: style_reviewer synthesize: type: agent agent: orchestrator edges: - from: dispatch to: security - from: dispatch to: performance - from: dispatch to: style - from: security to: synthesize - from: performance to: synthesize - from: style to: synthesize parallel_execution: true


$ agents actor add --config ./actors/review-pipeline.yaml \
    --skill local/code-analysis \
    --skill local/file-ops

╭─ Actor Added ──────────────────────────────────╮ │ Name: local/review-pipeline │ │ Provider: anthropic │ │ Model: claude-3.5-sonnet │ │ Default: yes │ │ Unsafe: no │ │ Type: graph │ ╰────────────────────────────────────────────────╯

╭─ Config ─────────────────────────────────────────────╮ │ Path: ./actors/review-pipeline.yaml │ │ Hash: 4f7a1e3 │ │ Options: 6 │ │ Nodes: 5 │ │ Edges: 6 │ ╰──────────────────────────────────────────────────────╯

╭─ Graph ────────────────────────────────────────────────────╮ │ Route: review_graph │ │ Entry Point: dispatch │ │ Checkpointing: yes │ │ Parallel Execution: yes │ │ │ │ Node Type Agent │ │ ─────────── ───── ────────────────────────────── │ │ dispatch agent orchestrator │ │ security agent security_reviewer │ │ performance agent performance_reviewer │ │ style agent style_reviewer │ │ synthesize agent orchestrator │ │ │ │ From To │ │ ─────────── ─────────── │ │ dispatch security │ │ dispatch performance │ │ dispatch style │ │ security synthesize │ │ performance synthesize │ │ style synthesize │ ╰────────────────────────────────────────────────────────────╯

╭─ Capabilities ──────────────────────╮ │ - multi-stage code review │ │ - security analysis │ │ - performance analysis │ │ - style and maintainability checks │ │ - unified report synthesis │ ╰─────────────────────────────────────╯

╭─ Skills ──────────────────────────────────────────╮ │ Skill Status │ │ ─────────────────── ──────────────────────── │ │ local/code-analysis attached │ │ local/file-ops attached │ ╰───────────────────────────────────────────────────╯

✓ OK Actor added

Step 2: Create the Review Action Using the Graph Actor

Create actions/deep-review.yaml:


name: local/deep-review
description: "Multi-stage deep code review with specialized reviewers"
definition_of_done: |
  - Security analysis complete with all findings classified by severity
  - Performance analysis complete with all findings classified by severity
  - Style analysis complete with all findings classified by severity
  - Unified review report generated with prioritized action items
  - Critical and high-severity issues have suggested fixes
strategy_actor: local/review-pipeline
execution_actor: local/review-pipeline
read_only: true
reusable: true
available: true
args:
  - name: target_paths
    type: string
    required: true
    description: "Comma-separated file or directory paths to review"
  - name: review_depth
    type: string
    required: false
    default: "standard"
    description: "Review depth: quick, standard, thorough"

$ agents action create --config ./actions/deep-review.yaml

╭─ Action Created ─────────────────────────────────────────────╮ │ Name: local/deep-review │ │ State: available │ │ Strategy Actor: local/review-pipeline │ │ Execution Actor: local/review-pipeline │ │ Reusable: yes │ │ Read Only: yes │ │ Created: 2026-02-11 16:30 │ ╰──────────────────────────────────────────────────────────────╯

╭─ Definition of Done ──────────────────────────────────────────────────────╮ │ - Security analysis complete with all findings classified by severity │ │ - Performance analysis complete with all findings classified by severity │ │ - Style analysis complete with all findings classified by severity │ │ - Unified review report generated with prioritized action items │ │ - Critical and high-severity issues have suggested fixes │ ╰───────────────────────────────────────────────────────────────────────────╯

╭─ Arguments ───────────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ──────────── ────── ──────── ────────────────────────────────────────────── │ │ target_paths string yes Comma-separated file or directory paths to review │ │ review_depth string no Review depth: quick, standard, thorough │ ╰───────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: supervised │ │ Source: default │ ╰───────────────────────────────────────╯

╭─ Usage ────────────────────────────────────────────────────────────────────────╮ │ agents plan use local/deep-review local/<project> │ │ --arg target_paths="src/auth/,src/routes/" │ │ --arg review_depth="thorough" (optional, default: "standard") │ ╰────────────────────────────────────────────────────────────────────────────────╯

✓ OK Action created


$ agents plan use \
    --automation-profile trusted \
    --arg target_paths="src/auth/,src/routes/" \
    --arg review_depth="thorough" \
    local/deep-review local/api-service

╭─ Plan Created ───────────────────────────────────────╮ │ Plan: 01HXR8D2E3F4G5H6J7K8L9M0N1 │ │ Phase: strategize │ │ State: processing │ │ Action: local/deep-review │ │ Project: local/api-service │ │ Automation: trusted │ │ Attempt: 1 │ ╰──────────────────────────────────────────────────────╯

╭─ Inputs ───────────────────────────────────────╮ │ - target_paths="src/auth/,src/routes/" │ │ - review_depth="thorough" │ │ - automation_profile=trusted │ ╰────────────────────────────────────────────────╯

╭─ Actors ────────────────────────────────────────╮ │ Strategy: local/review-pipeline │ │ Execution: local/review-pipeline │ │ Estimation: (none) │ │ Actor Type: graph (5 nodes, 6 edges) │ ╰─────────────────────────────────────────────────╯

╭─ Automation ───────────────────────────╮ │ Profile: trusted │ │ Source: plan override │ │ Read-Only: yes │ ╰────────────────────────────────────────╯

╭─ Context ──────────────────────────╮ │ Resources: 1 (git-checkout) │ │ Indexed Files: 312 │ │ View: strategize │ │ Hot Token Budget: 24,000 │ ╰────────────────────────────────────╯

╭─ Next Steps ─────────────────────────────────────────────────────────╮ │ Trusted profile — strategize and execute will proceed automatically. │ │ - agents plan status 01HXR8D2E3F4G5H6J7K8L9M0N1 │ │ - agents plan tree 01HXR8D2E3F4G5H6J7K8L9M0N1 │ ╰──────────────────────────────────────────────────────────────────────╯

✓ OK Plan created

The graph actor executes review_graph with parallel fan-out. The dispatch node (orchestrator) analyzes the target paths and prepares review context, then three edges fire concurrently: security, performance, and style nodes each run their specialized sub-actor in parallel. Once all three complete, their outputs converge at the synthesize node, where the orchestrator merges findings into a single prioritized report. Because read_only: true, no file modifications are produced — only the review report.


Example 12: Large-Scale Feature Implementation with Hierarchical Decomposition

Scenario: A startup is building a new notification system that spans the backend API, a message queue, a worker service, and a frontend dashboard. The feature requires changes across 4 projects and should decompose into manageable child plans.

Complexity: Expert. Multi-project, hierarchical child plans, deep decision tree, invariant reconciliation, full plan lifecycle.

Step 1: Set Up All Projects

# Register the API repo resource (full output shown)

$ agents resource add git-checkout local/api-repo --path /repos/api --branch main

╭─ Resource ──────────────────────────────────────╮ │ Name: local/api-repo │ │ ID: 01HXRA1A2B3C4D5E6F7G8H9J0K │ │ Type: git-checkout │ │ Physical/Virtual: physical │ │ Path: /repos/api │ │ Branch: main │ │ Created: 2026-02-11 14:00 │ ╰─────────────────────────────────────────────────╯

╭─ Auto-discovered Children ─────────────────────────────────────────╮ │ ID Type Status │ │ ─────────────── ────────────── ───────────────── │ │ 01HXRA1A2B3C… git created │ │ 01HXRA1A2B3D… git-remote created │ │ 01HXRA1A2B3E… git-branch created │ │ + 48 git-commit resources │ │ + 312 git-tree-entry resources │ │ + 6 fs-directory + 42 fs-file │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Capabilities ─────────────────╮ │ Readable: yes │ │ Writable: yes │ │ Sandboxable: yes │ │ Checkpointable: yes │ │ Sandbox Strategy: git_worktree │ ╰────────────────────────────────╯

✓ OK Resource registered (412 child resources discovered)

# Register the remaining 3 resources (condensed output)

$ agents resource add git-checkout local/worker-repo --path /repos/worker --branch main ✓ OK Resource registered — Name: local/worker-repo (278 children)

$ agents resource add git-checkout local/frontend-repo --path /repos/frontend --branch main ✓ OK Resource registered — Name: local/frontend-repo (524 children)

$ agents resource add git-checkout local/protos-repo --path /repos/protos --branch main ✓ OK Resource registered — Name: local/protos-repo (96 children)

# Create the Backend API project (full output shown)

$ agents project create -d "Backend API"
--resource local/api-repo
--resource local/protos-repo
--invariant "All new endpoints must have OpenAPI docs"
--invariant "All database changes require migration scripts"
local/api

╭─ Project Created ─────────────────────────╮ │ Name: local/api │ │ Description: Backend API │ │ Type: local │ │ Created: 2026-02-11 14:01 │ ╰───────────────────────────────────────────╯

╭─ Linked Resources ───────────────────────────────────────╮ │ Resource Type Read-Only │ │ ───────────────── ────────────── ───────── │ │ local/api-repo git-checkout no │ │ local/protos-repo git-checkout no │ ╰──────────────────────────────────────────────────────────╯

╭─ Invariants ─────────────────────────────────────────────╮ │ 1. All new endpoints must have OpenAPI docs │ │ 2. All database changes require migration scripts │ ╰──────────────────────────────────────────────────────────╯

╭─ Defaults ──────────────────────────────╮ │ Sandbox: git_worktree │ │ Validations: 0 │ │ Context Filters: none │ │ Automation Profile: (inherits global) │ ╰─────────────────────────────────────────╯

✓ OK Project created

# Create the remaining 3 projects (condensed output)

$ agents project create -d "Background worker service"
--resource local/worker-repo
--resource local/protos-repo
--invariant "Workers must be idempotent"
--invariant "All queue consumers must implement dead-letter handling"
local/worker ✓ OK Project created — Name: local/worker

$ agents project create -d "Frontend dashboard"
--resource local/frontend-repo
--invariant "All components must have Storybook stories"
--invariant "Accessibility: WCAG 2.1 AA compliance required"
local/frontend ✓ OK Project created — Name: local/frontend

$ agents project create -d "Shared protobuf definitions"
--resource local/protos-repo
--invariant "Proto changes must be backward-compatible (no field renumbering)"
local/protos ✓ OK Project created — Name: local/protos

# Add validations — first one with full output

$ agents project validation add --required local/api "pytest tests/ && mypy src/"

╭─ Validation Added ──────────────────────────────────╮ │ ID: val_01HXRV1A │ │ Project: local/api │ │ Command: pytest tests/ && mypy src/ │ │ Mode: required │ │ Timeout: 300s │ ╰─────────────────────────────────────────────────────╯

✓ OK Validation added

# Add validations to the remaining 3 projects (condensed output)

$ agents project validation add --required local/worker "pytest tests/ && mypy src/" ✓ OK Validation added — ID: val_01HXRV2B Project: local/worker

$ agents project validation add --required local/frontend "npm run test && npm run lint" ✓ OK Validation added — ID: val_01HXRV3C Project: local/frontend

$ agents project validation add --required local/protos "buf lint && buf breaking --against .git#branch=main" ✓ OK Validation added — ID: val_01HXRV4D Project: local/protos

# Global invariant for this effort

$ agents invariant add --global
"All inter-service communication must use the shared proto definitions"

╭─ Invariant Added ──────────────────────────────────────────────────────────────╮ │ Invariant: All inter-service communication must use the shared proto defs. │ │ Scope: global │ │ ID: inv_01HXRI1A │ ╰────────────────────────────────────────────────────────────────────────────────╯

✓ OK Invariant added

Step 2: Create the Feature Action

Create actions/build-notification-system.yaml:


name: local/build-notification-system
description: "Build a complete notification system spanning multiple services"
long_description: |
  Implement a full notification system with:
  - Backend API: notification preferences, send endpoints, delivery tracking
  - Message Queue: notification event schemas, routing rules
  - Worker: email/SMS/push delivery workers with retry logic
  - Frontend: notification center UI, preference settings, real-time updates

The system must be designed for reliability (at-least-once delivery), scalability (async processing via queue), and user control (per-channel preferences with quiet hours). definition_of_done: |

  • Proto definitions for notification events are complete and compatible
  • API endpoints: CRUD for preferences, send notification, list history
  • Worker processes: email, SMS, push delivery with retry and dead-letter
  • Frontend: notification center, preference settings, real-time badge
  • Integration tests verify end-to-end notification flow
  • All per-project validations pass
  • API docs updated, Storybook stories added strategy_actor: local/refactoring-strategist execution_actor: anthropic/claude-3.5-sonnet estimation_actor: anthropic/claude-3.5-sonnet invariant_actor: local/invariant-resolver automation_profile: cautious reusable: false available: true args:
  • name: notification_channels type: string required: true description: "Comma-separated: email, sms, push, in-app"
  • name: priority_levels type: string required: false default: "critical,high,normal,low"
  • name: max_retry_attempts type: integer required: false default: 5 invariants:
  • "Proto definitions must be implemented and reviewed before any service code"
  • "Each service must be deployable independently after its changes"
  • "Frontend must gracefully degrade if the notification API is unavailable"
  • "All notification delivery must be async — API endpoints return immediately"
$ agents action create --config ./actions/build-notification-system.yaml

╭─ Action Created ──────────────────────────────────────────────────╮ │ Name: local/build-notification-system │ │ ID: 01HXRB1A2B3C4D5E6F7G8H9J0 │ │ State: available │ │ Strategy Actor: local/refactoring-strategist │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Estimation Actor: anthropic/claude-3.5-sonnet │ │ Invariant Actor: local/invariant-resolver │ │ Reusable: no │ │ Read Only: no │ │ Created: 2026-02-11 14:02 │ ╰───────────────────────────────────────────────────────────────────╯

╭─ Definition of Done ───────────────────────────────────────────────────╮ │ - Proto definitions for notification events are complete/compatible │ │ - API endpoints: CRUD for preferences, send notification, list hist. │ │ - Worker: email, SMS, push delivery with retry and dead-letter │ │ - Frontend: notification center, preference settings, real-time badge │ │ - Integration tests verify end-to-end notification flow │ │ - All per-project validations pass │ │ - API docs updated, Storybook stories added │ ╰────────────────────────────────────────────────────────────────────────╯

╭─ Arguments ──────────────────────────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────────────────── ──────── ──────── ────────────────────────────────── │ │ notification_channels string yes Comma-separated: email, sms, push │ │ priority_levels string no (default: critical,high,normal,low) │ │ max_retry_attempts integer no (default: 5) │ ╰──────────────────────────────────────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────╮ │ Profile: cautious │ │ Source: action config │ ╰───────────────────────────────────────╯

╭─ Action Invariants ───────────────────────────────────────────────────────────────────╮ │ 1. Proto definitions must be implemented and reviewed before any service code │ │ 2. Each service must be deployable independently after its changes │ │ 3. Frontend must gracefully degrade if the notification API is unavailable │ │ 4. All notification delivery must be async — API endpoints return immediately │ ╰───────────────────────────────────────────────────────────────────────────────────────╯

╭─ Usage ────────────────────────────────────────────────────────────────────────────╮ │ agents plan use local/build-notification-system local/protos │ │ --arg notification_channels="email,push,in-app" │ ╰────────────────────────────────────────────────────────────────────────────────────╯

✓ OK Action created

Step 3: Initiate the Plan

$ agents plan use \
    --arg notification_channels="email,push,in-app" \
    --arg priority_levels="critical,high,normal,low" \
    --arg max_retry_attempts=5 \
    local/build-notification-system \
    local/protos local/api local/worker local/frontend

╭─ Plan Created ────────────────────────────────────────────────╮ │ Plan: 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ Action: local/build-notification-system │ │ Projects: local/protos, local/api, │ │ local/worker, local/frontend │ │ Automation: cautious │ │ Attempt: 1 │ ╰───────────────────────────────────────────────────────────────╯

╭─ Inputs ───────────────────────────────────────────────────────────╮ │ - notification_channels="email,push,in-app" │ │ - priority_levels="critical,high,normal,low" │ │ - max_retry_attempts=5 │ │ - automation_profile=cautious │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Actors ────────────────────────────────────────────╮ │ Strategy: local/refactoring-strategist │ │ Execution: anthropic/claude-3.5-sonnet │ │ Estimation: anthropic/claude-3.5-sonnet │ │ Invariant: local/invariant-resolver │ ╰─────────────────────────────────────────────────────╯

╭─ Automation ──────────────────────────────╮ │ Profile: cautious │ │ Source: action config │ │ Read-Only: no │ ╰───────────────────────────────────────────╯

╭─ Context ──────────────────────────╮ │ Resources: 4 (git-checkout) │ │ Indexed Files: 1,310 │ │ View: strategize │ │ Hot Token Budget: 32,000 │ ╰────────────────────────────────────╯

╭─ Next Steps ──────────────────────────────────────────────╮ │ - agents plan tree 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ - agents plan status 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ - agents plan execute 01HXRF1A2B3C4D5E6F7G8H9J0 │ ╰───────────────────────────────────────────────────────────╯

✓ OK Plan created

The plan (01HXRF1A2B3C4D5E6F7G8H9J0) enters Strategize. The strategy actor:

  1. Reconciles invariants from all four projects plus global plus action-level
  2. Decomposes the work into ordered child plans:
    • Phase 1: Proto definitions (local/protos)
    • Phase 2 (parallel): API endpoints (local/api) + Worker skeleton (local/worker)
    • Phase 3 (parallel): Worker delivery logic (local/worker) + Frontend notification center (local/frontend)
    • Phase 4: Integration wiring and end-to-end tests

Because the cautious profile uses confidence thresholds, the system pauses on complex architectural decisions (e.g., "Should notifications use a fan-out or point-to-point queue topology?") but proceeds automatically on routine decisions.

Step 4: Monitor and Guide the Hierarchical Execution

# View the full plan tree with child plans

$ agents plan tree 01HXRF1A2B3C4D5E6F7G8H9J0

╭─ Decision Tree ─────────────────────────────────────────────────────────────────────────────────────────╮ │ Plan: 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ ├─ [prompt_definition] "Build notification system across 4 projects" │ │ ├─ [invariant_enforced] "All inter-service communication must use shared proto defs" │ │ ├─ [invariant_enforced] "Proto definitions must be implemented before any service code" │ │ ├─ [invariant_enforced] "Each service must be deployable independently after its changes" │ │ ├─ [invariant_enforced] "Frontend must gracefully degrade if notification API unavailable" │ │ ├─ [invariant_enforced] "All notification delivery must be async" │ │ ├─ [strategy_choice] "Phase 1: proto definitions first (blocking)" (conf: 0.95) │ │ ├─ [strategy_choice] "Phase 2: API + worker skeleton in parallel" (conf: 0.88) │ │ ├─ [strategy_choice] "Phase 3: worker delivery + frontend UI in parallel" (conf: 0.84) │ │ ├─ [strategy_choice] "Phase 4: integration wiring and e2e tests" (conf: 0.90) │ │ ├─ [strategy_choice] "Queue topology: fan-out vs point-to-point?" (conf: 0.55 — PAUSED) │ │ ├─ [child_plan] 01HXRC1A2B3C4D5E6F7G8H9J0 (Phase 1: proto defs) [execute/complete] │ │ ├─ [child_plan] 01HXRC2B3C4D5E6F7G8H9J0K1 (Phase 2a: API endpoints) [execute/processing] │ │ ├─ [child_plan] 01HXRC3C4D5E6F7G8H9J0K1L2 (Phase 2b: worker skeleton) [execute/processing] │ │ ├─ [child_plan] 01HXRC4D5E6F7G8H9J0K1L2M3 (Phase 3a: worker delivery) [strategize/pending] │ │ ├─ [child_plan] 01HXRC5E6F7G8H9J0K1L2M3N4 (Phase 3b: frontend UI) [strategize/pending] │ │ └─ [child_plan] 01HXRC6F7G8H9J0K1L2M3N4P5 (Phase 4: integration) [strategize/pending] │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Tree Summary ──────────────────╮ │ Nodes: 17 │ │ Depth: 2 │ │ Child Plans: 6 (1 done, 2 exec) │ │ Invariants: 5 │ │ Superseded: 0 (hidden) │ ╰─────────────────────────────────╯

╭─ Decision IDs (for correction) ──────────────────────────╮ │ Root: 01HXRD1A2B3C4D5E6F7G8H9J │ │ Invariant 1: 01HXRD1B3C4D5E6F7G8H9J0 │ │ Invariant 2: 01HXRD1C4D5E6F7G8H9J0K1 │ │ Invariant 3: 01HXRD1D5E6F7G8H9J0K1L2 │ │ Invariant 4: 01HXRD1E6F7G8H9J0K1L2M3 │ │ Invariant 5: 01HXRD1F7G8H9J0K1L2M3N4 │ │ Strategy 1: 01HXRD2A3B4C5D6E7F8G9H0 │ │ Strategy 2: 01HXRD2B4C5D6E7F8G9H0J1 │ │ Strategy 3: 01HXRD2C5D6E7F8G9H0J1K2 │ │ Strategy 4: 01HXRD2D6E7F8G9H0J1K2L3 │ │ Paused: 01HXRD2E7F8G9H0J1K2L3M4 │ ╰──────────────────────────────────────────────────────────╯

✓ OK Decision tree rendered

# The system paused at a decision about queue topology (confidence 0.55 < threshold 0.7)

$ agents plan explain 01HXRD2E7F8G9H0J1K2L3M4

╭─ Decision ──────────────────────────────────────────────────╮ │ ID: 01HXRD2E7F8G9H0J1K2L3M4 │ │ Type: strategy_choice │ │ Question: Queue topology for notification delivery │ │ Chosen: (none — paused for user input) │ │ Confidence: 0.55 │ │ Plan: 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ Sequence: 5 of 5 strategy choices │ │ Created: 2026-02-11 14:04 │ ╰─────────────────────────────────────────────────────────────╯

╭─ Alternatives Considered ──────────────────────────────────────────────────────╮ │ 1. Fan-out exchange: one exchange per event type, separate queues per channel │ │ 2. Point-to-point: single queue, worker routes by notification type │ │ 3. Topic-based: single exchange with routing keys for channel + priority │ ╰────────────────────────────────────────────────────────────────────────────────╯

╭─ Impact ─────────────────────────╮ │ Downstream Decisions: 4 │ │ Downstream Child Plans: 3 │ │ Artifacts Produced: 0 (pending) │ │ Correction Impact: high │ ╰──────────────────────────────────╯

╭─ Rationale ──────────────────────────────────────────────────────────╮ │ The confidence is low because both fan-out and topic-based patterns │ │ are viable. Fan-out gives independent scaling per channel but adds │ │ more exchanges. Topic-based is simpler but couples routing logic. │ │ The existing codebase uses RabbitMQ but has no precedent for this │ │ pattern — no strong signal either way. │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Correction ──────────────────────────────────────────────────╮ │ agents plan correct 01HXRD2E7F8G9H0J1K2L3M4 │ │ --mode revert --guidance "Use fan-out exchange pattern..." │ ╰───────────────────────────────────────────────────────────────╯

✓ OK Decision explained

# Provide guidance to resolve the paused decision

$ agents plan prompt 01HXRF1A2B3C4D5E6F7G8H9J0
"Use a fan-out exchange pattern: one exchange per notification event type,
with separate queues per delivery channel. This matches our existing
RabbitMQ setup in the order service."

╭─ Guidance Added ────────────────────────────────────────────────────────╮ │ Plan: 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ Guidance: Use a fan-out exchange pattern: one exchange per │ │ notification event type, with separate queues per delivery │ │ channel. This matches our existing RabbitMQ setup. │ │ Scope: next execution step │ │ Phase: strategize │ │ State: awaiting_input → processing │ ╰─────────────────────────────────────────────────────────────────────────╯

╭─ Decision Created ────────────────────────╮ │ Type: user_intervention │ │ ID: 01HXRD3A2B3C4D5E6F7G8H9J │ │ Parent: 01HXRD2E7F8G9H0J1K2L3M4 │ ╰───────────────────────────────────────────╯

╭─ Queue ────╮ │ Pending: 1 │ │ Applied: 0 │ ╰────────────╯

✓ OK Guidance queued

Step 5: Handle a Failure in One Child Plan

The worker delivery child plan fails validation because the SMS provider SDK is not installed. Rather than failing the entire tree:

# Check which child plan failed

$ agents plan status 01HXRC4D5E6F7G8H9J0K1L2M3

╭─ Plan Status ──────────────────────────────────────────────╮ │ Plan: 01HXRC4D5E6F7G8H9J0K1L2M3 │ │ Phase: execute │ │ State: errored │ │ Action: local/build-notification-system (child plan) │ │ Project: local/worker │ │ Automation: cautious │ │ Attempt: 1 │ │ Parent: 01HXRF1A2B3C4D5E6F7G8H9J0 │ ╰────────────────────────────────────────────────────────────╯

╭─ Progress ───────────╮ │ Strategize │ │ Execute │ │ Apply (skipped) │ ╰──────────────────────╯

╭─ Error Detail ──────────────────────────────────────────────────────────╮ │ Error: Validation failed: ModuleNotFoundError: No module named │ │ 'twilio' — SMS provider SDK not installed │ │ Tool: execute_command (pip install check) │ │ Step: 3 of 8 │ │ Checkpoint: cp_01HXRC4D (sandbox state preserved) │ │ Recoverable: yes — use "agents plan prompt" to provide guidance │ ╰─────────────────────────────────────────────────────────────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 14,280 │ │ Cost So Far: $0.048 │ ╰──────────────────────╯

✗ ERROR Plan errored — use agents plan prompt to resume or agents plan cancel to abort

# Correct the strategy — tell it to skip SMS for now

$ agents plan correct 01HXRD4A2B3C4D5E6F7G8H9J
--mode append
--guidance "Skip SMS delivery for the initial implementation.
Add a placeholder worker that logs a warning.
SMS support will be added in a follow-up action."

╭─ Correction ─────────────────────────────────────────────────╮ │ Mode: append │ │ Impact: adds to existing subtree, no rollback │ │ New Decision: 01HXRD5A2B3C4D5E6F7G8H9J │ │ Appended After: 01HXRD4A2B3C4D5E6F7G8H9J │ │ Attempt: 2 │ ╰──────────────────────────────────────────────────────────────╯

╭─ Append Detail ────────────────────────────────────────────────────╮ │ Original decision preserved: yes │ │ Existing artifacts kept: yes │ │ Additional work: re-execute with SMS placeholder │ │ The worker delivery plan will be re-executed. Email and push │ │ workers are kept; SMS worker replaced with a logging stub. │ │ Other child plans (API, frontend, integration) are unaffected. │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Queued ──────────────╮ │ Re-execute: 1 child │ │ ETA: 3m │ ╰───────────────────────╯

✓ OK Append correction queued

Step 6: Apply in Phases

# Apply proto definitions first (other plans depend on this)

$ agents plan apply --yes 01HXRC1A2B3C4D5E6F7G8H9J0

╭─ Apply Summary ──────────────────────────────────────────╮ │ Plan: 01HXRC1A2B3C4D5E6F7G8H9J0 │ │ Artifacts: 3 files updated │ │ Changes: 84 insertions, 0 deletions │ │ Project: local/protos │ │ Applied At: 2026-02-11 14:18 │ ╰──────────────────────────────────────────────────────────╯

╭─ Validation ──────────────────────────────────────────╮ │ buf lint: passed │ │ buf breaking: passed (no breaking changes) │ │ Duration: 2.1s │ ╰───────────────────────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ─────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:02:41 │ │ Total Cost: $0.024 │ │ Decisions Made: 4 │ │ Child Plans: 0 │ ╰──────────────────────────────────────────╯

✓ OK Changes applied

# Apply API and worker in parallel

$ agents plan apply --yes 01HXRC2B3C4D5E6F7G8H9J0K1 ✓ OK Changes applied — Plan: 01HXRC2B...J0K1 Project: local/api (8 files, +246 -12)

$ agents plan apply --yes 01HXRC3C4D5E6F7G8H9J0K1L2 ✓ OK Changes applied — Plan: 01HXRC3C...K1L2 Project: local/worker (5 files, +178 -4)

# Apply worker delivery and frontend

$ agents plan apply --yes 01HXRC4D5E6F7G8H9J0K1L2M3 ✓ OK Changes applied — Plan: 01HXRC4D...L2M3 Project: local/worker (6 files, +312 -18)

$ agents plan apply --yes 01HXRC5E6F7G8H9J0K1L2M3N4 ✓ OK Changes applied — Plan: 01HXRC5E...M3N4 Project: local/frontend (12 files, +487 -22)

# Apply integration tests

$ agents plan apply --yes 01HXRC6F7G8H9J0K1L2M3N4P5 ✓ OK Changes applied — Plan: 01HXRC6F...N4P5 Projects: local/api, local/worker (4 files, +156 -0)

# Apply the parent plan (finalizes everything)

$ agents plan apply --yes 01HXRF1A2B3C4D5E6F7G8H9J0

╭─ Apply Summary ───────────────────────────────────────────╮ │ Plan: 01HXRF1A2B3C4D5E6F7G8H9J0 │ │ Artifacts: 38 files across 4 projects │ │ Changes: 1,463 insertions, 56 deletions │ │ Projects: local/protos, local/api, │ │ local/worker, local/frontend │ │ Applied At: 2026-02-11 14:32 │ ╰───────────────────────────────────────────────────────────╯

╭─ Validation ─────────────────────────────────────────╮ │ local/protos: passed (buf lint + breaking) │ │ local/api: passed (pytest 48/48, mypy 0 err) │ │ local/worker: passed (pytest 31/31, mypy 0) │ │ local/frontend: passed (tests + lint) │ │ Duration: 34.2s │ ╰──────────────────────────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktrees: 4 removed │ │ Branches: merged to main │ │ Checkpoints: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:30:14 │ │ Total Cost: $0.847 │ │ Decisions Made: 42 │ │ Child Plans: 6 (all completed) │ │ Corrections: 1 │ ╰─────────────────────────────────────────╯

╭─ Next Steps ──────╮ │ - Review git diff │ │ - Commit changes │ ╰───────────────────╯

✓ OK Changes applied


Example 13: Custom Automation Profile with Semantic Escalation

Scenario: A team wants fine-grained automation control. They trust the system with routine planning but want human oversight on any decision involving database schema changes or security-sensitive code, regardless of confidence.

Complexity: Intermediate. Custom profile, invariant-driven escalation.

Step 1: Create a Custom Profile

Create profiles/db-cautious.yaml:


name: local/db-cautious
description: "Auto for most tasks, manual for database and security decisions"

auto_strategize: 0.0 auto_execute: 0.3 auto_apply: 1.0 auto_decisions_strategize: 0.4 auto_decisions_execute: 0.6 auto_validation_fix: 0.5 auto_strategy_revision: 0.8 auto_child_plans: 0.3 auto_retry_transient: 0.0 auto_checkpoint_restore: 0.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false


$ agents automation-profile add --config ./profiles/db-cautious.yaml

╭─ Profile Registered ──────────────────────────────────────────────────────╮ │ Name: local/db-cautious │ │ Description: Auto for most tasks, manual for database and security │ │ decisions │ │ Created: 2026-02-11 09:00 │ ╰───────────────────────────────────────────────────────────────────────────╯

╭─ Confidence Thresholds ────────────────╮ │ auto_strategize: 0.0 │ │ auto_execute: 0.3 │ │ auto_apply: 1.0 │ │ auto_decisions_strategize: 0.4 │ │ auto_decisions_execute: 0.6 │ │ auto_validation_fix: 0.5 │ │ auto_strategy_revision: 0.8 │ │ auto_child_plans: 0.3 │ │ auto_retry_transient: 0.0 │ │ auto_checkpoint_restore: 0.0 │ │ require_sandbox: true │ │ require_checkpoints: true │ │ allow_unsafe_tools: false │ ╰────────────────────────────────────────╯

✓ OK Profile registered

Step 2: Apply to a Project with Database Resources


$ agents config set core.automation-profile local/db-cautious --project local/api-service

╭─ Config Updated ─────────────────────────────────╮ │ Key: core.automation-profile │ │ Value: local/db-cautious │ │ Previous: review │ │ Source: config │ │ Scope: project (local/api-service) │ ╰──────────────────────────────────────────────────╯

╭─ Effective ────────────────────────────────────╮ │ Sessions: new sessions on local/api-service │ │ Plans: future plans (unless overridden) │ │ Existing: unchanged │ ╰────────────────────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 24 │ ╰─────────────────────────────────────╯

✓ OK Config updated


# Add invariants that force escalation on sensitive operations
$ agents invariant add --project local/api-service \
    "Any change to database migration files requires explicit human approval"

╭─ Invariant Added ───────────────────────────────────────────────────────────────╮ │ Project: local/api-service │ │ Invariant: Any change to database migration files requires explicit human │ │ approval │ │ Scope: project │ │ ID: inv_01HXRBA1A │ ╰─────────────────────────────────────────────────────────────────────────────────╯

✓ OK Invariant added

$ agents invariant add --project local/api-service
"Changes to authentication or authorization logic require security review"

╭─ Invariant Added ───────────────────────────────────────────────────────────────╮ │ Project: local/api-service │ │ Invariant: Changes to authentication or authorization logic require │ │ security review │ │ Scope: project │ │ ID: inv_01HXRBA2B │ ╰─────────────────────────────────────────────────────────────────────────────────╯

✓ OK Invariant added

Step 3: Run a Plan and Observe Escalation


$ agents plan use \
    --arg target_module="src/auth" \
    local/refactor-to-orm local/api-service

╭─ Plan Created ─────────────────────────────────────╮ │ Plan ID: 01HXRBG1H2I3J4K5L6M7N8O9P0 │ │ Phase: strategize (running) │ │ Action: local/refactor-to-orm │ │ Project: local/api-service │ │ Automation: local/db-cautious │ │ Attempt: 1 │ ╰────────────────────────────────────────────────────╯

╭─ Inputs ─────────────────────╮ │ - target_module=src/auth │ ╰──────────────────────────────╯

╭─ Actors ───────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ │ Invariant: local/invariant-resolver │ ╰────────────────────────────────────────╯

╭─ Plan Invariants ──────────────────────────────────────────────────────────────╮ │ Scope Source Invariant │ │ ──────── ─────── ────────────────────────────────────────────────────── │ │ project config Any change to database migration files requires explicit │ │ human approval │ │ project config Changes to authentication or authorization logic require │ │ security review │ ╰────────────────────────────────────────────────────────────────────────────────╯

╭─ Next Steps ─────────────────────────────────────────╮ │ - agents plan status 01HXRBG1H2I3J4K5L6M7N8O9P0 │ │ - agents plan tree 01HXRBG1H2I3J4K5L6M7N8O9P0 │ ╰──────────────────────────────────────────────────────╯

✓ OK Plan created — strategize in progress

During execution, the system encounters a decision to create a new Alembic migration. The confidence score is 0.82 (the system is fairly confident), but the invariant "database migration files require explicit human approval" causes the Invariant Reconciliation Actor to enforce escalation regardless. The system pauses:


# The plan pauses — check why
$ agents plan status 01HXRBG1H2I3J4K5L6M7N8O9P0

╭─ Plan Status ───────────────────────────────────────╮ │ Plan: 01HXRBG1H2I3J4K5L6M7N8O9P0 │ │ Phase: execute │ │ State: awaiting_input │ │ Action: local/refactor-to-orm │ │ Project: local/api-service │ │ Automation: local/db-cautious │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────────╯

╭─ Progress ────────────────╮ │ Strategize │ │ Execute (paused) │ │ Apply (waiting) │ ╰───────────────────────────╯

╭─ Escalation ───────────────────────────────────────────────────────────────╮ │ ⚠ Decision paused — invariant forced escalation │ │ Decision: 01HXRBD1E2F3G4H5I6J7K8L9 │ │ Type: implementation_choice │ │ Question: Create Alembic migration for users table schema change? │ │ Confidence: 0.82 (would auto-proceed, but invariant overrides) │ │ Invariant: "Any change to database migration files requires explicit │ │ human approval" │ ╰────────────────────────────────────────────────────────────────────────────╯

╭─ Timing ───────────╮ │ Started: 09:05:12 │ │ Elapsed: 00:02:48 │ │ ETA: (paused) │ ╰────────────────────╯

╭─ Cost ───────────────╮ │ Tokens Used: 18,740 │ │ Cost So Far: $0.062 │ │ Estimated: $0.095 │ ╰──────────────────────╯

⚠ WARN Plan paused — awaiting human input for escalated decision


# Review the decision requiring approval
$ agents plan explain 01HXRBD1E2F3G4H5I6J7K8L9

╭─ Decision ───────────────────────────────────────────────────────────╮ │ ID: 01HXRBD1E2F3G4H5I6J7K8L9 │ │ Type: implementation_choice │ │ Question: Create Alembic migration for users table schema change? │ │ Chosen: Add nullable orm_version column with migration │ │ Confidence: 0.82 │ │ Plan: 01HXRBG1H2I3J4K5L6M7N8O9P0 │ │ Sequence: 4 of 7 │ │ Created: 2026-02-11 09:07 │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Alternatives Considered ────────────────────────────────────────────╮ │ 1. Add nullable orm_version column with migration (chosen) │ │ 2. Use a shadow table approach (no schema change) │ │ 3. In-place column rename via ALTER (risky in production) │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Escalation Reason ──────────────────────────────────────────────────╮ │ Invariant Override: inv_01HXRBA1A │ │ Text: "Any change to database migration files requires explicit │ │ human approval" │ │ Effect: Confidence 0.82 would normally auto-proceed (threshold │ │ 0.6), but invariant forces manual escalation regardless │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Impact ─────────────────────────╮ │ Downstream Decisions: 3 │ │ Downstream Child Plans: 0 │ │ Artifacts Produced: 2 │ │ Correction Impact: medium │ ╰──────────────────────────────────╯

╭─ Rationale ──────────────────────────────────────────────────────────╮ │ The auth module currently uses raw SQL queries. Refactoring to ORM │ │ requires an orm_version tracking column on the users table. │ │ Adding as nullable first avoids downtime; the backfill + NOT NULL │ │ constraint can follow in a second migration after data is populated. │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Correction ────────────────────────────────────────────────╮ │ agents plan prompt 01HXRBG1H2I3J4K5L6M7N8O9P0 │ │ "Approved. <guidance>" │ │ agents plan correct 01HXRBD1E2F3G4H5I6J7K8L9 │ │ --mode revert --guidance "Use approach 2 instead..." │ ╰─────────────────────────────────────────────────────────────╯

✓ OK Decision explained


# Approve the migration approach with specific guidance
$ agents plan prompt 01HXRBG1H2I3J4K5L6M7N8O9P0 \
    "Approved. Use a two-phase migration: first add the column as nullable, \
     then in a separate migration add the NOT NULL constraint after backfill."

╭─ Guidance Added ──────────────────────────────────────────────────────────╮ │ Plan: 01HXRBG1H2I3J4K5L6M7N8O9P0 │ │ Guidance: Approved. Use a two-phase migration: first add the column as │ │ nullable, then in a separate migration add the NOT NULL │ │ constraint after backfill. │ │ Scope: next execution step │ │ Phase: execute │ │ State: awaiting_input → processing │ ╰───────────────────────────────────────────────────────────────────────────╯

╭─ Decision Created ──────────────────────────────╮ │ Type: user_intervention │ │ ID: 01HXRBE2F3G4H5I6J7K8L9M0 │ │ Parent: 01HXRBD1E2F3G4H5I6J7K8L9 │ ╰─────────────────────────────────────────────────╯

╭─ Queue ────╮ │ Pending: 1 │ │ Applied: 0 │ ╰────────────╯

✓ OK Guidance queued — execution resuming


Example 14: Server Mode — Team Collaboration

Scenario: A distributed team uses CleverAgents in server mode. Multiple engineers share actions, actors, and projects while working on the same codebase from different machines.

Complexity: Intermediate. Server mode, multi-user, namespace management.

Step 1: Connect to the Server


# Configure server connection
$ agents config set server.url https://agents.example.com

╭─ Config Updated ──────────────────────────────╮ │ Key: server.url │ │ Value: https://agents.example.com │ │ Previous: (not set) │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 3 │ ╰─────────────────────────────────────╯

✓ OK Config updated

$ agents config set server.token "tok_01HXR..."

╭─ Config Updated ──────────────────────────╮ │ Key: server.token │ │ Value: tok_01HXR... (redacted) │ │ Previous: (not set) │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 4 │ ╰─────────────────────────────────────╯

✓ OK Config updated

$ agents config set core.namespace myteam

╭─ Config Updated ──────────────────────╮ │ Key: core.namespace │ │ Value: myteam │ │ Previous: local │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────────╯

╭─ Saved To ──────────────────────────╮ │ File: ~/.cleveragents/config.toml │ │ Line: 5 │ ╰─────────────────────────────────────╯

✓ OK Config updated


# Verify connection
$ agents diagnostics

╭─ Checks ────────────────────────────────────────────────╮ │ Check Status Details │ │ ─────────────── ────── ─────────────────────── │ │ Config file OK readable │ │ Database OK writable │ │ Anthropic key OK configured │ │ OPENAI_API_KEY WARN missing │ │ Disk space OK 4.8 GB free │ │ Text index OK tantivy 0.22 │ │ Vector index OK faiss (CPU) │ │ Graph store OK neo4j 5.15 │ │ File permissions OK data dir r/w │ │ Git OK git 2.43.0 │ │ Server OK connected (agents.example.com) │ │ Namespace OK myteam (4 members) │ ╰─────────────────────────────────────────────────────────╯

╭─ Summary ─────────╮ │ Checks: 12 total │ │ Warnings: 1 │ │ Errors: 0 │ │ Duration: 0.8s │ ╰───────────────────╯

╭─ Server ────────────────────────────╮ │ URL: https://agents.example.com │ │ Auth: valid (tok_01HXR...) │ │ Namespace: myteam │ │ Members: 4 │ │ Shared Actions: 7 │ │ Shared Actors: 3 │ │ Latency: 42ms │ ╰─────────────────────────────────────╯

╭─ Recommendations ──────────────────────────────╮ │ - Set OPENAI_API_KEY to enable OpenAI models │ ╰────────────────────────────────────────────────╯

⚠ WARN 1 warning requires attention

Step 2: Publish Shared Resources


# Publish an action to the team namespace (visible to all team members)
$ agents action create --config ./actions/generate-tests.yaml

╭─ Action Created ──────────────────────────────────────╮ │ Name: myteam/generate-tests │ │ ID: 01HXRC1A2B3C4D5E6F7G8H9J0K │ │ State: available │ │ Strategy Actor: anthropic/claude-3.5-sonnet │ │ Execution Actor: anthropic/claude-3.5-sonnet │ │ Reusable: yes │ │ Read Only: no │ │ Created: 2026-02-11 09:15 │ ╰───────────────────────────────────────────────────────╯

╭─ Definition of Done ───────────────────────────────────╮ │ All target modules have test coverage above 80% │ │ Tests pass in CI without flaky failures │ ╰────────────────────────────────────────────────────────╯

╭─ Arguments ─────────────────────────────────────────────────────╮ │ Name Type Required Description │ │ ────────────── ────── ──────── ─────────────────────── │ │ target_module string yes Module path to generate tests │ ╰─────────────────────────────────────────────────────────────────╯

╭─ Automation ────────────────────────╮ │ Profile: supervised │ │ Source: action default │ ╰─────────────────────────────────────╯

╭─ Usage ───────────────────────────────────────────────────────────╮ │ agents plan use myteam/generate-tests local/my-project │ │ --arg target_module="src/payments" │ ╰───────────────────────────────────────────────────────────────────╯

✓ OK Action created


# Publish a shared actor
$ agents actor add --config ./actors/review-pipeline.yaml

╭─ Actor Added ──────────────────────────────────╮ │ Name: myteam/review-pipeline │ │ Provider: anthropic │ │ Model: claude-3.5-sonnet │ │ Default: no │ │ Unsafe: no │ │ Type: graph │ ╰────────────────────────────────────────────────╯

╭─ Config ───────────────────────────────╮ │ Path: ./actors/review-pipeline.yaml │ │ Hash: 5a7c2e1 │ │ Options: 3 │ │ Nodes: 5 │ │ Edges: 6 │ ╰────────────────────────────────────────╯

╭─ Capabilities ──────────────────╮ │ - multi-stage code review │ │ - security analysis │ │ - performance analysis │ │ - style checking │ ╰─────────────────────────────────╯

╭─ Tools ────────────────────────╮ │ Tool Read-Only Safe │ │ ──────────── ───────── ──── │ │ read_file yes yes │ │ search_files yes yes │ │ git_diff yes yes │ │ run_tests yes yes │ ╰────────────────────────────────╯

✓ OK Actor added


# List available actions (team namespace)
$ agents action list --namespace myteam

╭─ Actions ────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Name State Strategy Actor Execution Actor Reusable │ │ ──────────────────────── ───────── ─────────────────────────── ─────────────────────────── ──────── │ │ myteam/generate-tests available anthropic/claude-3.5-sonnet anthropic/claude-3.5-sonnet ✓ │ │ myteam/deep-review available myteam/review-pipeline myteam/review-pipeline ✓ │ │ myteam/format-codebase available anthropic/claude-3.5-sonnet anthropic/claude-3.5-sonnet ✓ │ │ myteam/security-audit available anthropic/claude-3.5-sonnet anthropic/claude-3.5-sonnet ✓ │ │ myteam/refactor-to-orm available anthropic/claude-3.5-sonnet anthropic/claude-3.5-sonnet ✗ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Filters ──────────────────╮ │ State: (any) │ │ Namespace: myteam │ ╰────────────────────────────╯

╭─ Summary ──────────────────╮ │ Total: 5 │ │ Available: 5 │ │ Draft: 0 │ │ Archived: 0 │ ╰────────────────────────────╯

✓ OK 5 actions listed

Step 3: Use Shared Resources from Another Machine

On a different developer's machine:


# Configure server connection
$ agents config set server.url https://agents.example.com

╭─ Config Updated ──────────────────────────────╮ │ Key: server.url │ │ Value: https://agents.example.com │ │ Previous: (not set) │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────────────────╯

✓ OK Config updated

$ agents config set server.token "tok_01HXS..."

╭─ Config Updated ──────────────────────────╮ │ Key: server.token │ │ Value: tok_01HXS... (redacted) │ │ Previous: (not set) │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────────────╯

✓ OK Config updated

$ agents config set core.namespace myteam

╭─ Config Updated ──────────────────────╮ │ Key: core.namespace │ │ Value: myteam │ │ Previous: local │ │ Source: config │ │ Scope: global │ ╰───────────────────────────────────────╯

✓ OK Config updated


# Use the team's shared action
$ agents plan use \
    --arg target_module="src/payments" \
    myteam/generate-tests local/payment-service

╭─ Plan Created ─────────────────────────────────────────╮ │ Plan ID: 01HXRC2B3C4D5E6F7G8H9J0K1L2 │ │ Phase: strategize (running) │ │ Action: myteam/generate-tests │ │ Project: local/payment-service │ │ Automation: supervised │ │ Attempt: 1 │ ╰────────────────────────────────────────────────────────╯

╭─ Inputs ──────────────────────╮ │ - target_module=src/payments │ ╰───────────────────────────────╯

╭─ Actors ──────────────────────────────────╮ │ Strategy: anthropic/claude-3.5-sonnet │ │ Execution: anthropic/claude-3.5-sonnet │ │ Source: server (myteam) │ ╰───────────────────────────────────────────╯

╭─ Context ───────────────────────╮ │ Resources: 1 (repo) │ │ Indexed Files: 189 │ │ View: strategize │ │ Hot Token Budget: 12,000 │ ╰─────────────────────────────────╯

╭─ Next Steps ──────────────────────────────────────────────╮ │ - agents plan status 01HXRC2B3C4D5E6F7G8H9J0K1L2 │ │ - agents plan tree 01HXRC2B3C4D5E6F7G8H9J0K1L2 │ ╰───────────────────────────────────────────────────────────╯

✓ OK Plan created — strategize in progress

Step 4: Monitor Across the Team


# List all plans across the team
$ agents plan list --namespace myteam

╭─ Plans ────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ID Phase State Action Project User Elapsed │ │ ──────── ──────── ────────── ────────────────────── ───────────────────── ─────── ───────── │ │ 01HXRC2B execute processing myteam/generate-tests local/payment-service jdoe 00:04:12 │ │ 01HXRC3C applied complete myteam/deep-review local/api-service asmith 00:08:47 │ │ 01HXRC4D execute processing myteam/generate-tests local/api-service mwong 00:02:35 │ │ 01HXRC5E applied complete myteam/format-codebase local/frontend blee 00:01:58 │ │ 01HXRC6F execute awaiting myteam/security-audit local/worker-service asmith 00:06:20 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Filters ──────────────────╮ │ Phase: (any) │ │ State: (any) │ │ Namespace: myteam │ │ Project: (any) │ │ Action: (any) │ ╰────────────────────────────╯

╭─ Summary ─────────────╮ │ Total: 5 │ │ Processing: 2 │ │ Completed: 2 │ │ Awaiting: 1 │ │ Errored: 0 │ ╰───────────────────────╯

✓ OK 5 plans listed


# See who is running what — filter to executing state
$ agents plan list --namespace myteam --state processing

╭─ Plans ────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ID Phase State Action Project User Elapsed │ │ ──────── ─────── ────────── ───────────────────── ───────────────────── ─────── ───────── │ │ 01HXRC2B execute processing myteam/generate-tests local/payment-service jdoe 00:04:12 │ │ 01HXRC4D execute processing myteam/generate-tests local/api-service mwong 00:02:35 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Filters ──────────────────────╮ │ Phase: (any) │ │ State: processing │ │ Namespace: myteam │ │ Project: (any) │ │ Action: (any) │ ╰────────────────────────────────╯

╭─ Summary ─────────────╮ │ Total: 2 │ │ Processing: 2 │ │ Completed: 0 │ │ Errored: 0 │ ╰───────────────────────╯

✓ OK 2 plans listed


Example 15: Disaster Recovery — Rollback a Failed Apply

Scenario: A plan was applied, but the changes broke production. The team needs to understand what happened and roll back.

Complexity: Intermediate. Rollback, checkpoint restore, post-mortem analysis.

Step 1: Investigate the Failed Apply


# Check the plan status
$ agents plan status 01HXRCF1G2H3I4J5K6L7M8N9O0

╭─ Plan Status ───────────────────────────────────────╮ │ Plan: 01HXRCF1G2H3I4J5K6L7M8N9O0 │ │ Phase: applied │ │ State: errored │ │ Action: local/optimize-db-connections │ │ Project: local/api-service │ │ Automation: trusted │ │ Attempt: 1 │ ╰─────────────────────────────────────────────────────╯

╭─ Progress ─────────────────────╮ │ Strategize │ │ Execute │ │ Apply (post-apply failure) │ ╰────────────────────────────────╯

╭─ Timing ──────────────────────────╮ │ Started: 2026-02-11 08:30:00 │ │ Applied At: 2026-02-11 08:42:18 │ │ Failed At: 2026-02-11 08:44:05 │ │ Total Duration: 00:14:05 │ ╰───────────────────────────────────╯

╭─ Result ───────────────────────────────────────────────╮ │ Decisions Made: 6 │ │ Child Plans: 0 │ │ Artifacts: 4 files updated │ │ Validations: 2/3 passed (1 FAILED post-apply) │ │ Total Cost: $0.072 │ ╰────────────────────────────────────────────────────────╯

╭─ Error ──────────────────────────────────────────────────────────────────────╮ │ Post-apply health check failed: connection pool exhaustion detected │ │ Impact: API response times increased 10x, 503 errors in production │ │ Root Cause Decision: 01HXRCD3E4F5G6H7I8J9K0L1 │ ╰──────────────────────────────────────────────────────────────────────────────╯

╭─ Recovery Options ──────────────────────────────────────────────────╮ │ - agents plan rollback — restore to a previous checkpoint │ │ - agents plan correct — revert and re-execute with guidance │ │ - agents plan explain — investigate the root cause decision │ ╰─────────────────────────────────────────────────────────────────────╯

✗ ERROR Plan applied but post-apply validation failed


# Review the decision tree to understand what was done
$ agents plan tree 01HXRCF1G2H3I4J5K6L7M8N9O0

╭─ Decision Tree ────────────────────────────────────────────────────────────────────────────────╮ │ Plan: 01HXRCF1G2H3I4J5K6L7M8N9O0 │ │ ├─ [prompt_definition] "Optimize database connection handling" │ │ ├─ [invariant_enforced] "All DB config changes must preserve existing pool limits" │ │ ├─ [strategy_choice] "Refactor connection pool configuration" (confidence: 0.91) │ │ ├─ [tool_invocation] write_file: src/db/pool_config.py │ │ ├─ [implementation_choice] "Increase pool size to 100" (confidence: 0.78) ← ROOT CAUSE │ │ └─ [tool_invocation] write_file: src/db/health_check.py │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯

╭─ Tree Summary ──────────────────╮ │ Nodes: 6 │ │ Depth: 2 │ │ Child Plans: 0 │ │ Invariants: 1 │ │ Superseded: 0 (hidden) │ ╰─────────────────────────────────╯

╭─ Decision IDs (for correction) ──────────────────────╮ │ Root: 01HXRCC1D2E3F4G5H6I7J8K9 │ │ Invariant 1: 01HXRCC2E3F4G5H6I7J8K9L0 │ │ Strategy: 01HXRCC3F4G5H6I7J8K9L0M1 │ │ Tool 1: 01HXRCC4G5H6I7J8K9L0M1N2 │ │ Pool Size (root cause): 01HXRCD3E4F5G6H7I8J9K0L1 │ │ Tool 2: 01HXRCE4F5G6H7I8J9K0L1M2 │ ╰──────────────────────────────────────────────────────╯

✓ OK Decision tree rendered


# Look at the specific changes that were applied
$ agents plan diff 01HXRCF1G2H3I4J5K6L7M8N9O0

╭─ Diff Summary ─────────────────────────────────────╮ │ Plan: 01HXRCF1G2H3I4J5K6L7M8N9O0 │ │ Project: local/api-service │ │ Files Changed: 4 │ │ Insertions: 38 │ │ Deletions: 12 │ │ Net Change: +26 lines │ ╰────────────────────────────────────────────────────╯

╭─ Files ──────────────────────────────────────╮ │ Path Change Status │ │ ──────────────────────── ────── ──────── │ │ src/db/pool_config.py +14 -6 modified │ │ src/db/health_check.py +18 -0 new file │ │ src/db/__init__.py +4 -4 modified │ │ config/database.toml +2 -2 modified │ ╰──────────────────────────────────────────────╯

╭─ Patch Preview ──────────────────────────────────╮ │ --- a/src/db/pool_config.py │ │ +++ b/src/db/pool_config.py │ │ @@ -8,6 +8,14 @@ │ │ - POOL_SIZE = 20 │ │ - POOL_MAX_OVERFLOW = 10 │ │ + POOL_SIZE = 100 │ │ + POOL_MAX_OVERFLOW = 50 │ │ + POOL_RECYCLE = 3600 │ │ + POOL_PRE_PING = True │ │ --- a/config/database.toml │ │ +++ b/config/database.toml │ │ @@ -3,2 +3,2 @@ │ │ - pool_size = 20 │ │ + pool_size = 100 │ ╰──────────────────────────────────────────────────╯

╭─ Risk Assessment ──────────────────────────╮ │ API Compatibility: preserved │ │ Test Coverage: maintained │ │ Breaking Changes: pool size 5x increase │ │ Resource Impact: high (connection limit) │ ╰────────────────────────────────────────────╯

✓ OK Diff generated


# Examine the decision that led to the problematic change
$ agents plan explain 01HXRCD3E4F5G6H7I8J9K0L1 --show-context --show-reasoning

╭─ Decision ───────────────────────────────────────────────────────────╮ │ ID: 01HXRCD3E4F5G6H7I8J9K0L1 │ │ Type: implementation_choice │ │ Question: What pool size should be configured? │ │ Chosen: Increase pool size from 20 to 100 │ │ Confidence: 0.78 │ │ Plan: 01HXRCF1G2H3I4J5K6L7M8N9O0 │ │ Sequence: 5 of 6 │ │ Created: 2026-02-11 08:38 │ ╰──────────────────────────────────────────────────────────────────────╯

╭─ Alternatives Considered ─────────────────────────────────────╮ │ 1. Increase pool size from 20 to 100 (chosen) │ │ 2. Keep pool at 20, add connection health checks only │ │ 3. Increase to 50 with overflow to 75 │ ╰───────────────────────────────────────────────────────────────╯

╭─ Impact ─────────────────────────╮ │ Downstream Decisions: 1 │ │ Downstream Child Plans: 0 │ │ Artifacts Produced: 2 │ │ Correction Impact: low │ ╰──────────────────────────────────╯

╭─ Context Snapshot ────────────────────────────────────────────────╮ │ - Current pool_size=20 in config/database.toml │ │ - Database server: PostgreSQL 15, max_connections=150 │ │ - 3 application replicas running (total: 60 connections used) │ │ - Slow query logs show connection wait times of 200-500ms │ │ Hot Context Hash: sha256:9c4f...a1b2 │ ╰───────────────────────────────────────────────────────────────────╯

╭─ Rationale ─────────────────────────────────────────────────────╮ │ Connection wait times of 200-500ms suggest pool exhaustion. │ │ Increasing to 100 connections per replica provides headroom │ │ for burst traffic and eliminates the queueing bottleneck. │ ╰─────────────────────────────────────────────────────────────────╯

╭─ Model Reasoning (raw) ────────────────────────────────────────────────╮ │ The slow query logs show connection acquisition delays of 200-500ms │ │ which indicates the pool is frequently exhausted. Current config: │ │ pool_size=20, max_overflow=10 (total 30 per replica). │ │ │ │ With 3 replicas that's 90 connections max. The PostgreSQL server │ │ allows 150. I'll increase to 100 per replica (300 total with │ │ overflow). This exceeds the server's max_connections=150 but │ │ overflow connections are temporary and unlikely to all be active │ │ simultaneously. │ │ │ │ [NOTE: The model failed to account for 3 replicas × 100 = 300 │ │ exceeding PostgreSQL max_connections=150] │ ╰────────────────────────────────────────────────────────────────────────╯

╭─ Correction ─────────────────────────────────────────────────╮ │ agents plan correct 01HXRCD3E4F5G6H7I8J9K0L1 │ │ --mode revert --guidance "Keep pool at 20, add health..." │ ╰──────────────────────────────────────────────────────────────╯

✓ OK Decision explained

Step 2: Roll Back to a Checkpoint


# List available checkpoints for this plan
$ agents plan artifacts 01HXRCF1G2H3I4J5K6L7M8N9O0

╭─ Artifacts ────────────────────────────────────────────────────────╮ │ Path Type Size Change Child Plan │ │ ─────────────────────── ───── ────── ─────── ────────── │ │ src/db/pool_config.py edit 1.4 KB +14 -6 root │ │ src/db/health_check.py write 2.1 KB +18 -0 root │ │ src/db/__init__.py edit 0.8 KB +4 -4 root │ │ config/database.toml edit 0.3 KB +2 -2 root │ ╰────────────────────────────────────────────────────────────────────╯

╭─ Summary ───────────╮ │ Total: 4 │ │ Writes: 1 (new) │ │ Edits: 3 (modified) │ │ Deletes: 0 │ │ Total Size: 4.6 KB │ ╰─────────────────────╯

╭─ Checkpoints ──────────────────────────────────────────────────────╮ │ ID Label Created │ │ ──────────────────── ─────────────────────────── ────────────── │ │ checkpoint_01HXRCP1 before pool config changes 08:36:12 │ │ checkpoint_01HXRCP2 before health check addition 08:39:45 │ │ checkpoint_01HXRCP3 pre-apply snapshot 08:42:00 │ ╰────────────────────────────────────────────────────────────────────╯

╭─ By Plan ──────────────╮ │ Root Plan: 4 artifacts │ ╰────────────────────────╯

✓ OK 4 artifacts listed


# Roll back to the checkpoint before the problematic pool config change
$ agents plan rollback --yes 01HXRCF1G2H3I4J5K6L7M8N9O0 checkpoint_01HXRCP1

╭─ Rollback Summary ─────────────────────────────────╮ │ Plan: 01HXRCF1G2H3I4J5K6L7M8N9O0 │ │ Checkpoint: checkpoint_01HXRCP1 │ │ Label: before pool config changes │ │ Files: 4 reverted │ ╰────────────────────────────────────────────────────╯

╭─ Changes Reverted ──────────────────────╮ │ File Action │ │ ──────────────────────── ────────── │ │ src/db/pool_config.py restored │ │ src/db/health_check.py removed │ │ src/db/__init__.py restored │ │ config/database.toml restored │ ╰─────────────────────────────────────────╯

╭─ Impact ──────────────────────────────────╮ │ Child Plans Invalidated: 0 │ │ Sandbox: restored to checkpoint_01HXRCP1 │ │ Decisions After CP: 2 discarded │ │ Tool Calls After CP: 3 undone │ ╰───────────────────────────────────────────╯

╭─ Post-Rollback State ──────────╮ │ Phase: execute │ │ State: queued (awaiting input) │ │ Checkpoints Remaining: 1 │ ╰────────────────────────────────╯

✓ OK Rollback complete

Step 3: Correct and Re-Execute


# Correct the decision that caused the issue
$ agents plan correct 01HXRCD3E4F5G6H7I8J9K0L1 \
    --mode revert \
    --guidance "The connection pool size change caused the outage. \
                Keep the pool at 20 connections maximum and add \
                connection health checks instead." --yes

╭─ Correction ──────────────────────────────────────────────╮ │ Mode: revert │ │ Impact: 1 decision, 0 child plans, 2 artifacts │ │ New Decision: 01HXRCCORR1A2B3C4D5 │ │ Corrects: 01HXRCD3E4F5G6H7I8J9K0L1 │ │ Attempt: 2 │ ╰───────────────────────────────────────────────────────────╯

╭─ Affected Subtree ──────────────╮ │ Decisions Invalidated: 1 │ │ Child Plans Rolled Back: 0 │ │ Artifacts Archived: 2 │ │ Unaffected Decisions: 4 │ ╰─────────────────────────────────╯

╭─ Sandbox Rollback ──────────────────╮ │ Checkpoint: checkpoint_01HXRCP1 │ │ Files Reverted: 2 │ │ Status: restored │ ╰─────────────────────────────────────╯

╭─ Recompute ───────────╮ │ Queued: 1 re-execute │ │ ETA: 2m │ ╰───────────────────────╯

╭─ History ───────────────────────────────────────────────╮ │ - Original decision superseded │ │ - Prior artifacts archived for comparison │ │ - agents plan diff --correction 01HXRCCORR1A2B3C4D5 │ ╰─────────────────────────────────────────────────────────╯

✓ OK Correction applied — re-executing affected subtree


# The affected subtree is re-executed. Review the new changes.
$ agents plan diff --correction 01HXRCCORR1A2B3C4D5

╭─ Correction Diff ────────────────────────────────────╮ │ Correction: 01HXRCCORR1A2B3C4D5 │ │ Original Decision: 01HXRCD3E4F5G6H7I8J9K0L1 │ │ Mode: revert │ │ Files Changed: 3 │ │ New Insertions: 32 │ │ New Deletions: 4 │ ╰──────────────────────────────────────────────────────╯

╭─ Comparison ─────────────────────────────────────────────────────────────╮ │ File Before (original) After (corrected) │ │ ──────────────────────── ────────────────── ────────────────────── │ │ src/db/pool_config.py +14 -6 (pool=100) +8 -2 (pool=20, checks) │ │ src/db/health_check.py +18 -0 (basic) +24 -0 (robust checks) │ │ config/database.toml +2 -2 (pool=100) (unchanged — pool=20) │ ╰──────────────────────────────────────────────────────────────────────────╯

╭─ Patch Preview (corrected vs original) ───────────────────────╮ │ --- a/src/db/pool_config.py (original) │ │ +++ b/src/db/pool_config.py (corrected) │ │ @@ -8,6 +8,10 @@ │ │ - POOL_SIZE = 100 │ │ - POOL_MAX_OVERFLOW = 50 │ │ + POOL_SIZE = 20 │ │ + POOL_MAX_OVERFLOW = 10 │ │ + POOL_PRE_PING = True │ │ + POOL_HEALTH_CHECK_INTERVAL = 30 │ │ --- a/src/db/health_check.py (original) │ │ +++ b/src/db/health_check.py (corrected) │ │ @@ -1,18 +1,24 @@ │ │ + # Added: connection validation, stale connection eviction, │ │ + # periodic health probes, and circuit breaker pattern │ │ ... │ ╰───────────────────────────────────────────────────────────────╯

✓ OK Correction diff generated


# Re-apply with the fix
$ agents plan apply --yes 01HXRCF1G2H3I4J5K6L7M8N9O0

╭─ Apply Summary ──────────────────────────╮ │ Plan: 01HXRCF1G2H3I4J5K6L7M8N9O0 │ │ Artifacts: 3 files updated │ │ Changes: 32 insertions, 4 deletions │ │ Project: local/api-service │ │ Applied At: 2026-02-11 09:02 │ ╰──────────────────────────────────────────╯

╭─ Validation ───────────────────╮ │ Tests: passed (31/31) │ │ Lint: passed (0 warnings) │ │ Type Check: passed (0 errors) │ │ Health Check: passed │ │ Duration: 18.6s │ ╰────────────────────────────────╯

╭─ Sandbox Cleanup ─────────╮ │ Worktree: removed │ │ Branch: merged to main │ │ Checkpoint: archived │ ╰───────────────────────────╯

╭─ Plan Lifecycle ──────────────────────────╮ │ Phase: applied │ │ State: complete │ │ Total Duration: 00:32:02 (incl. rollback) │ │ Total Cost: $0.118 │ │ Decisions Made: 7 (1 corrected) │ │ Child Plans: 0 │ ╰───────────────────────────────────────────╯

╭─ Next Steps ──────╮ │ - Review git diff │ │ - Commit changes │ ╰───────────────────╯

✓ OK Changes applied

Architecture

This section provides the complete architectural blueprint for CleverAgents. It defines the system's structural composition, technology choices, layer boundaries, data flow, and operational characteristics. An implementor should be able to build the entire system from this section combined with the behavioral specification above.

Architecture Overview

CleverAgents is architected as a layered, event-driven application following Domain-Driven Design (DDD) principles with clean architecture boundaries. The system is organized into four primary layers — Presentation, Application, Domain, and Infrastructure — with strict dependency rules: outer layers depend on inner layers, never the reverse. Cross-cutting concerns (logging, configuration, security) are handled through dependency injection and aspect-oriented patterns.

The architecture supports two deployment modes:

  1. Local Mode: A single-process CLI application where all components run in the same Python process. The CLI is the primary entry point, the database is SQLite, and all resources are local.
  2. Server Mode: A multi-user service where the CLI acts as a thin client communicating with a remote server over HTTPS. The server hosts shared storage, namespace resolution, permissions, and remote plan execution.

Both modes share the same domain model and application layer. The infrastructure layer provides swappable implementations for each deployment target.

High-Level Component Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│                          Presentation Layer                                  │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌──────────────┐  ┌────────────┐  │
│  │   CLI   │  │   TUI   │  │   Web   │  │  IDE Plugin  │  │  REST API  │  │
│  │ (Typer) │  │(Textual)│  │(Textual │  │  (Language   │  │ (uvicorn/  │  │
│  │         │  │         │  │  Web)   │  │   Server)    │  │  FastAPI)  │  │
│  └────┬────┘  └────┬────┘  └────┬────┘  └──────┬───────┘  └─────┬──────┘  │
│       │            │            │               │                │          │
│       └────────────┴────────────┴───────────────┴────────────────┘          │
│                                    │                                         │
├────────────────────────────────────┼─────────────────────────────────────────┤
│                          Application Layer                                   │
│  ┌────────────────────┐  ┌─────────────────────┐  ┌──────────────────────┐  │
│  │  Service Facade    │  │  Workflow Engine     │  │  Event Bus           │  │
│  │  ┌──────────────┐  │  │  ┌───────────────┐  │  │  ┌────────────────┐  │  │
│  │  │PlanService   │  │  │  │PlanLifecycle  │  │  │  │StructuredLog   │  │  │
│  │  │ProjectService│  │  │  │SessionWorkflow│  │  │  │EventEmitter    │  │  │
│  │  │ActorService  │  │  │  │CorrectionFlow │  │  │  │MetricsCollector│  │  │
│  │  │ContextService│  │  │  │MergeWorkflow  │  │  │  └────────────────┘  │  │
│  │  │ToolService   │  │  │  └───────────────┘  │  │                      │  │
│  │  │SkillService  │  │  │                     │  │                      │  │
│  │  │ResourceSvc   │  │  │                     │  │                      │  │
│  │  └──────────────┘  │  └─────────────────────┘  └──────────────────────┘  │
│  └────────────────────┘                                                      │
│       │                                                                      │
│  ┌────────────────────────────────────────────────────────────────────────┐  │
│  │  DI Container (dependency-injector DeclarativeContainer)               │  │
│  └────────────────────────────────────────────────────────────────────────┘  │
│                                    │                                         │
├────────────────────────────────────┼─────────────────────────────────────────┤
│                            Domain Layer                                      │
│  ┌──────────────────────┐  ┌─────────────────────┐  ┌────────────────────┐  │
│  │  Domain Models       │  │  Domain Services     │  │  Domain Events     │  │
│  │  ┌────────────────┐  │  │  ┌───────────────┐  │  │  ┌──────────────┐  │  │
│  │  │Plan            │  │  │  │InvariantEnfrc │  │  │  │PlanCreated   │  │  │
│  │  │Decision        │  │  │  │AutonomyCtrl  │  │  │  │PhaseChanged  │  │  │
│  │  │Project         │  │  │  │ContextBuilder│  │  │  │DecisionMade  │  │  │
│  │  │Resource        │  │  │  │MergeResolver │  │  │  │ToolInvoked   │  │  │
│  │  │Actor           │  │  │  └───────────────┘  │  │  │ApplyCompleted│  │  │
│  │  │Action          │  │  │                     │  │  │CorrectionReq │  │  │
│  │  │Tool / Skill    │  │  │  Repository Ifaces  │  │  └──────────────┘  │  │
│  │  │Session         │  │  │  (Protocol classes) │  │                    │  │
│  │  │Invariant       │  │  │                     │  │                    │  │
│  │  │AutomationProf  │  │  │                     │  │                    │  │
│  │  │Checkpoint      │  │  │                     │  │                    │  │
│  │  │CorrectionAtmpt │  │  │                     │  │                    │  │
│  │  └────────────────┘  │  └─────────────────────┘  └────────────────────┘  │
│  └──────────────────────┘                                                    │
│                                    │                                         │
├────────────────────────────────────┼─────────────────────────────────────────┤
│                         Infrastructure Layer                                 │
│  ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐│
│  │  Database     │ │  Indexing    │ │  Sandbox     │ │  LLM / AI Runtime   ││
│  │  ┌────────┐  │ │  ┌───────┐  │ │  ┌────────┐  │ │  ┌──────────────┐   ││
│  │  │SQLite  │  │ │  │Tantivy│  │ │  │GitWrktree│ │ │  │LangChain     │   ││
│  │  │SQLAlch.│  │ │  │FAISS  │  │ │  │FsCopy   │  │ │  │LangGraph     │   ││
│  │  │Alembic │  │ │  │Neo4j  │  │ │  │TxnRollbk│  │ │  │ProviderReg   │   ││
│  │  │UoW     │  │ │  │Qdrant │  │ │  │NoOp     │  │ │  │RxPY Bridge   │   ││
│  │  └────────┘  │ │  │RDFLib │  │ │  └────────┘  │ │  │MCP SDK       │   ││
│  └──────────────┘ │  └───────┘  │ └──────────────┘ │  └──────────────┘   ││
│                   └─────────────┘                   └──────────────────────┘│
│  ┌───────────────────────┐ ┌────────────────────────────────────────────┐   │
│  │  External Integrations│ │  File System / OS                          │   │
│  │  ┌─────────────────┐  │ │  ┌──────────┐ ┌──────────┐ ┌───────────┐ │   │
│  │  │MCP Servers      │  │ │  │Watchdog  │ │Git CLI   │ │OS Process │ │   │
│  │  │Agent Skills Std │  │ │  │File I/O  │ │Subprocess│ │Signals    │ │   │
│  │  │REST/gRPC Clients│  │ │  └──────────┘ └──────────┘ └───────────┘ │   │
│  │  └─────────────────┘  │ └────────────────────────────────────────────┘   │
│  └───────────────────────┘                                                   │
└─────────────────────────────────────────────────────────────────────────────┘

Architectural Principles

  1. Hexagonal Architecture (Ports and Adapters): The domain layer defines abstract repository interfaces (ports). The infrastructure layer provides concrete implementations (adapters). This allows swapping SQLite for PostgreSQL, FAISS for Qdrant, or local execution for remote server execution without touching domain logic.

  2. Command Query Responsibility Segregation (CQRS): Write operations (plan creation, decision recording, resource modification) flow through command handlers that enforce invariants and emit domain events. Read operations (plan status, decision tree visualization, context queries) use optimized read paths that may bypass the ORM for performance.

  3. Event-Driven Architecture: All significant state changes emit domain events through a structured event bus. Events flow through RxPY reactive streams for real-time processing and through the structured logging pipeline for persistence. This enables decoupled observability, audit logging, and future webhook/notification systems.

  4. Dependency Injection: All service dependencies are wired through a DeclarativeContainer (from the dependency-injector library). This eliminates hidden coupling, enables testing with mock implementations, and supports runtime reconfiguration (e.g., switching providers).

  5. Convention over Configuration: Default behavior requires zero configuration. YAML configuration files override defaults. CLI flags override configuration files. Environment variables override both. This four-tier resolution chain (built-in default < config file < env var < CLI flag) is applied consistently.

Data Flow: Plan Lifecycle

The following diagram traces data flow through the system during a complete plan lifecycle:

User                CLI              Application         Domain            Infrastructure
 │                   │                   │                  │                    │
 │  plan use         │                   │                  │                    │
 │──────────────────>│                   │                  │                    │
 │                   │  PlanService      │                  │                    │
 │                   │  .create_plan()   │                  │                    │
 │                   │──────────────────>│                  │                    │
 │                   │                   │  Plan(phase=     │                    │
 │                   │                   │  strategize)     │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │  PlanRepository    │
 │                   │                   │                  │  .save(plan)       │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │                   │                   │  InvariantEnfrc  │                    │
 │                   │                   │  .reconcile()    │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │                    │
 │                   │                   │  AutonomyCtrl    │                    │
 │                   │                   │  .should_proceed │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │                    │
 │                   │                   │  [if auto]       │                    │
 │                   │                   │  StrategyActor   │                    │
 │                   │                   │  .invoke()       │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │  LangGraph         │
 │                   │                   │                  │  StateGraph.invoke │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │                   │                   │                  │  ContextBuilder    │
 │                   │                   │                  │  .build_hot_ctx()  │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │  [FAISS/Tantivy]   │
 │                   │                   │                  │<───────────────────│
 │                   │                   │                  │                    │
 │                   │                   │                  │  LLM Provider      │
 │                   │                   │                  │  .generate()       │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │<───────────────────│
 │                   │                   │                  │                    │
 │                   │                   │  Decision[]      │                    │
 │                   │                   │<─────────────────│                    │
 │                   │                   │                  │  DecisionRepo      │
 │                   │                   │                  │  .save_batch()     │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │                   │                   │  [Execute phase] │                    │
 │                   │                   │  SandboxManager  │                    │
 │                   │                   │  .create()       │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │  GitWorktree       │
 │                   │                   │                  │  .create_worktree()│
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │                   │                   │  ExecutionActor  │                    │
 │                   │                   │  .invoke(sandbox)│                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │  Tool calls via    │
 │                   │                   │                  │  SkillRegistry     │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │                   │                   │  ChangeSet       │                    │
 │                   │                   │<─────────────────│                    │
 │                   │                   │                  │                    │
 │                   │                   │  [Apply phase]   │                    │
 │                   │                   │  Validation      │                    │
 │                   │                   │  .run_all()      │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │  Subprocess        │
 │                   │                   │                  │  .run(commands)    │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │                   │                   │  SandboxManager  │                    │
 │                   │                   │  .commit()       │                    │
 │                   │                   │─────────────────>│                    │
 │                   │                   │                  │  git merge         │
 │                   │                   │                  │───────────────────>│
 │                   │                   │                  │                    │
 │  ✓ OK Applied     │                  │                  │                    │
 │<──────────────────│                   │                  │                    │

Technical Stack

This section enumerates every technology choice in the CleverAgents stack, organized by functional area. Version constraints are minimum versions; newer compatible versions are acceptable.

Core Runtime

Technology Version Role Rationale
Python >= 3.13 Primary language Type hint maturity, async/await, pattern matching, performance improvements in 3.13. The entire codebase is Python-only for consistency and LLM ecosystem alignment.
Hatchling >= 1.21.0 PEP 517 build backend Lightweight, standards-compliant build system. Produces wheels and sdists without complex configuration.
uv >= 0.8.0 Package installer and resolver 10-100x faster than pip. Used in CI, Docker builds, and Nox sessions for dependency installation. Drop-in replacement for pip with full PEP 723 support.

CLI and Presentation

Technology Version Role Rationale
Typer >= 0.9.0 CLI framework Built on Click with automatic help generation, type inference from Python type hints, and Rich integration for styled output. Supports nested command groups matching the agents <noun> <verb> pattern.
Rich (transitive via Typer) Terminal rendering Provides Panel, Table, Tree, Syntax, Progress, Spinner, and Markdown rendering used by all output formats except plain and structured (json/yaml).
Textual (future) TUI framework Built by the Rich maintainers. Provides a reactive terminal UI framework that can be served as a web app via Textual Web, enabling the "single UI codebase" strategy for TUI, Web, and IDE plugin.

LLM and AI Runtime

Technology Version Role Rationale
LangChain >= 0.2.14 LLM abstraction layer Provider-agnostic interface for chat models, embeddings, output parsing, prompt templates, and tool calling. The BaseLanguageModel protocol enables swapping providers without changing application code.
LangGraph (transitive) Stateful workflow orchestration StateGraph with conditional edges, checkpointing (MemorySaver), and streaming execution. Used for the plan generation graph (load_context -> analyze -> generate -> validate) and auto-debug graph.
LangChain Provider Packages varies LLM provider integrations langchain-openai (>= 0.2.0), langchain-google-genai (>= 0.2.0), langchain-anthropic, langchain-groq, langchain-together, langchain-cohere. Each provides a ChatModel implementation.
LangChain Community >= 0.2.14 Community integrations FAISS vector store, FakeListLLM/FakeEmbeddings for testing.
RxPY >= 3.2.0 Reactive stream processing Subject, BehaviorSubject, ReplaySubject, and operators (map, filter, flat_map, debounce, throttle, scan) for real-time event routing between actors, stream-to-graph bridging, and backpressure management.
MCP SDK >= 1.4.0 Model Context Protocol Client SDK for communicating with MCP servers. Enables CleverAgents to discover and invoke tools exposed by any MCP-compliant server.

Data and Persistence

Technology Version Role Rationale
SQLite (system) Primary database Zero-configuration, file-based, ACID-compliant. Sufficient for local mode; supports WAL mode for concurrent reads during plan execution. For server mode, the infrastructure layer swaps in PostgreSQL via the same SQLAlchemy interface.
SQLAlchemy (transitive via Alembic) ORM and database abstraction Declarative model mapping, session management, Unit of Work pattern, and dialect abstraction enabling database portability.
Alembic >= 1.13.1 Database migrations Version-controlled schema migrations with upgrade/downgrade support. Migrations are auto-applied on first run and during agents init.
python-ulid >= 2.7.0 ID generation ULID generation for plans, decisions, resources, and correction attempts. ULIDs are lexicographically sortable by creation time, enabling efficient time-range queries without separate timestamp indexes.

Indexing and Code Intelligence

Technology Version Role Rationale
Tantivy (via tantivy-py) configurable Full-text search Rust-based search engine providing sub-millisecond full-text search across project resources. Used for keyword-based code search during context building. Alternative: SQLite FTS5 for zero-dependency installations.
FAISS (faiss-cpu) >= 1.7.4 Vector similarity search Facebook AI Similarity Search for semantic code search. Indexes embedding vectors generated from project files. Supports approximate nearest neighbor search for fast retrieval during context building.
Qdrant configurable Vector search (alternative) External vector database for production deployments requiring horizontal scaling, persistence, and filtering. Connected via qdrant-client.
Neo4j configurable Knowledge graph Graph database for structural code relationships (class hierarchies, call graphs, dependency trees). Enables queries like "find all callers of function X" during Strategize. Alternative: rdflib for in-process graph queries.
rdflib >= 7.1.4 In-process graph store Python RDF library for lightweight structural code analysis without external dependencies. Stores RDF triples representing code relationships.
OpenAI Embeddings configurable Vector generation Default embedding provider (text-embedding-3-small). Alternative providers: Anthropic, local sentence-transformers models via index.embedding.provider config.

Configuration and Validation

Technology Version Role Rationale
Pydantic >= 2.7.0 Data validation and modeling All domain models, configuration objects, and API schemas use Pydantic v2 for runtime validation, JSON Schema generation, and serialization. Provides type-safe data boundaries between layers.
Pydantic Settings >= 2.11.0 Environment configuration BaseSettings subclasses for environment variable loading with the CLEVERAGENTS_ prefix, .env file support, and nested model resolution. Implements the four-tier configuration resolution chain.
Jinja2 >= 3.1.0 Template rendering Used for actor system prompts, YAML configuration interpolation, and prompt template rendering. Supports {{ context.* }} variable expansion with sandboxed execution.
TOML (stdlib tomllib) Configuration file format Global configuration uses TOML for its native support of nested tables, which maps naturally to the dot-separated hierarchical key structure. Python 3.13 includes tomllib in stdlib.
YAML (via PyYAML) Entity configuration format All entity definitions (actors, skills, tools, actions, resource types, automation profiles) use YAML as the canonical human-authored format. JSON is accepted as valid YAML.

Testing

Technology Version Role Rationale
Behave >= 1.2.6 BDD feature tests Gherkin .feature files describe behavioral scenarios in natural language. Step implementations exercise the full application stack. Custom behave-parallel runner enables parallel execution via ProcessPoolExecutor.
Robot Framework >= 7.3.2 Integration tests Keyword-driven integration tests for end-to-end CLI workflows. robotframework-pabot enables parallel suite execution.
pytest >= 8.0.0 Unit tests Standard Python test framework for unit-level testing with fixtures, parametrization, and plugin support.
pytest-asyncio >= 0.23.0 Async test support Enables async def test_* functions for testing async LangGraph workflows and RxPY stream operations.
pytest-cov / coverage >= 7.11.0 Coverage reporting Target: 85% line coverage. HTML and XML reports generated by Nox sessions. Coverage gates enforce minimum thresholds in CI.
Hypothesis >= 6.136.6 Property-based testing Generates randomized test inputs for invariant verification, particularly useful for testing decision tree operations, merge strategies, and context tier boundaries.
ASV (Airspeed Velocity) >= 0.6.5 Performance benchmarks Tracks plan generation latency, CLI startup time, and indexing throughput across commits. Prevents performance regressions.

Code Quality

Technology Version Role Rationale
Ruff >= 0.1.0 Linting and formatting Single tool replacing Black, Flake8, isort, and pyupgrade. Rules: E, F, W, B, UP, I, SIM, RUF. Line length: 88. Double quotes. 4-space indent.
Pyright >= 1.1.350 Static type checking Strict mode type checking for the entire codebase. Catches type errors at development time rather than runtime. Configured via pyrightconfig.json.

Infrastructure and Deployment

Technology Version Role Rationale
Docker multi-stage Containerization Production image uses python:3.13-slim with multi-stage build. Non-root user (appuser, uid 1000). Entrypoint: python -m cleveragents.
Helm (chart) Kubernetes deployment Helm chart in k8s/ directory for server mode deployment. Linted and template-tested in CI.
Nox >= 2025.4.22 Task automation Session-based task runner for lint, test, build, docs, benchmarks, and coverage. Uses uv as the virtual environment backend for fast session creation.
Forgejo CI (workflow) Continuous integration Self-hosted Forgejo instance with GitHub Actions-compatible workflow syntax. Pipeline: lint -> typecheck -> behave (matrix 3.11/3.12/3.13) -> build -> docker -> helm.

Monitoring and Observability

Technology Version Role Rationale
structlog >= 24.4.0 Structured logging JSON-structured log output with context binding (plan_id, decision_id, actor_name, tool_name). Enables log aggregation, filtering, and correlation across complex plan hierarchies.
LangSmith (optional) LLM observability Optional integration for tracing LLM calls, token usage, latency, and cost. Configured via CLEVERAGENTS_LANGSMITH_* environment variables. Syncs to LANGCHAIN_TRACING_V2.

Additional Libraries

Technology Version Role Rationale
dependency-injector >= 4.41.0 DI container DeclarativeContainer with Singleton, Factory, and Configuration providers. Wires all services, repositories, and infrastructure components.
watchdog >= 4.0.0 File system monitoring Watches project resource directories for changes. Triggers automatic re-indexing when index.auto-reindex is enabled.
numpy >= 2.1.0 Numerical computing Vector operations for embedding similarity computation, confidence score aggregation, and distance calculations in the vector store layer.
uvicorn >= 0.30.1 ASGI server HTTP server for server mode REST API. Serves the FastAPI application for remote plan execution, namespace resolution, and multi-user collaboration.

Storage and Persistence

This section defines the complete storage strategy for every persistent concept in CleverAgents, specifying the storage backend, data format, lifecycle management, and migration strategy for each entity type.

Storage Architecture Overview

CleverAgents uses a hybrid storage model combining a relational database for structured data, the filesystem for configuration files and artifacts, and specialized indexes for search operations. The storage layer is accessed exclusively through repository interfaces defined in the domain layer, ensuring that storage backends can be swapped without affecting application logic.

┌─────────────────────────────────────────────────────────────┐
│                    Storage Architecture                       │
│                                                               │
│  ┌──────────────┐  ┌──────────────┐  ┌────────────────────┐ │
│  │  Relational   │  │  Filesystem  │  │  Search Indexes    │ │
│  │  Database     │  │              │  │                    │ │
│  │  ┌──────────┐ │  │  ┌────────┐ │  │  ┌──────────────┐ │ │
│  │  │Plans     │ │  │  │Config  │ │  │  │Text (Tantivy)│ │ │
│  │  │Decisions │ │  │  │YAML    │ │  │  │Vector (FAISS)│ │ │
│  │  │Projects  │ │  │  │Files   │ │  │  │Graph (Neo4j) │ │ │
│  │  │Resources │ │  │  ├────────┤ │  │  └──────────────┘ │ │
│  │  │Sessions  │ │  │  │Sandbox │ │  │                    │ │
│  │  │Actors(db)│ │  │  │Worktree│ │  │  ┌──────────────┐ │ │
│  │  │Invariants│ │  │  │Files   │ │  │  │Checkpoint    │ │ │
│  │  │Changes   │ │  │  ├────────┤ │  │  │Store         │ │ │
│  │  │Checkpoint│ │  │  │Artifact│ │  │  │(filesystem)  │ │ │
│  │  │Metadata  │ │  │  │Storage │ │  │  └──────────────┘ │ │
│  │  │CorrAtmpt │ │  │  └────────┘ │  │                    │ │
│  │  │AuditLog  │ │  │             │  │                    │ │
│  │  └──────────┘ │  └──────────────┘  └────────────────────┘ │
│  └──────────────┘                                             │
└─────────────────────────────────────────────────────────────┘

Entity Storage Map

The following table specifies where each CleverAgents concept is persisted, in both local and server modes:

Entity Local Storage Server Storage Format Identifier
Plans SQLite plans table Server PostgreSQL Relational rows ULID (plan_id)
Decisions SQLite decisions table Server PostgreSQL Relational rows + JSON context_snapshot ULID (decision_id)
Projects SQLite projects table Server PostgreSQL (for non-local/ namespaces) Relational rows Namespaced name
Resources SQLite resources table + resource_links table Server PostgreSQL Relational rows + DAG edges ULID (resource_id)
Resource Types SQLite resource_types table + YAML config files Server PostgreSQL + synced YAML Relational rows Namespaced name (built-ins unnamespaced)
Actions SQLite actions table + YAML config files Server PostgreSQL + synced YAML Relational rows Namespaced name
Actors SQLite actors table + YAML config files Server PostgreSQL + synced YAML Relational rows + file reference Namespaced name
Skills SQLite skills table + YAML config files Server PostgreSQL + synced YAML Relational rows + file reference Namespaced name
Tools SQLite tools table + YAML config files Server PostgreSQL + synced YAML Relational rows + file reference Namespaced name
Sessions SQLite sessions table + session_messages table Server PostgreSQL Relational rows ULID (session_id)
Invariants SQLite invariants table Server PostgreSQL Relational rows Auto-generated ID
Automation Profiles SQLite automation_profiles table + YAML config files Server PostgreSQL + synced YAML Relational rows Namespaced name (built-ins unnamespaced)
Changes / ChangeSets SQLite changes table Server PostgreSQL Relational rows ULID per change
Checkpoints Filesystem (<data-dir>/checkpoints/<plan_id>/) + SQLite checkpoint_metadata table Server object storage + PostgreSQL metadata Git refs or filesystem snapshots + metadata rows ULID (checkpoint_id)
Correction Attempts SQLite correction_attempts table + archived artifacts on filesystem Server PostgreSQL + object storage Relational rows + file archives ULID (correction_attempt_id)
Artifacts Filesystem (<data-dir>/artifacts/<plan_id>/) Server object storage (S3-compatible) Raw files (code, documents, images, etc.) Filesystem path relative to plan
Context Indexes (Text) Filesystem (<data-dir>/index/text/) Server-managed index cluster Tantivy index files or SQLite FTS5 Index directory per project
Context Indexes (Vector) Filesystem (<data-dir>/index/vector/) Server-managed FAISS/Qdrant cluster FAISS index files or Qdrant collections Index directory per project
Context Indexes (Graph) Neo4j database or rdflib files Server-managed Neo4j instance Graph triples Graph database per project
Configuration TOML file (<data-dir>/config.toml) N/A (server has own config) TOML Single file
Logs Filesystem (<data-dir>/logs/) Server-managed log aggregation Structured JSON (structlog) Rotated log files
Audit Logs SQLite audit_log table Server PostgreSQL Relational rows Auto-incrementing ID

Database Schema Design

The relational database follows a normalized design with foreign key constraints enforcing referential integrity. The schema is version-controlled through Alembic migrations.

Key design decisions:

  1. ULID primary keys: All time-series entities (plans, decisions, checkpoints, correction attempts) use ULID primary keys. This provides natural time-ordering without separate timestamp indexes, collision-free generation without coordination, and URL-safe string representation.

  2. JSON columns for semi-structured data: Fields like context_snapshot, alternatives_considered, artifacts_produced, and resource_bindings are stored as JSON text columns. This avoids over-normalization for data that is always read and written as a unit, while still being queryable via SQLite's json_extract() or PostgreSQL's jsonb operators.

  3. Soft delete pattern: Entities that support archival (actions, actors, skills) use a state column with values like available, draft, archived. No rows are physically deleted except during explicit agents init reset or retention policy enforcement.

  4. Optimistic concurrency control: The updated_at timestamp column on mutable entities serves as a version check. Update operations include WHERE updated_at = <previous_value> to detect concurrent modifications. On conflict, the operation fails with an explicit error rather than silently overwriting.

Core tables (SQLite DDL):

-- Plans table: the fundamental unit of orchestration
CREATE TABLE plans (
    plan_id TEXT PRIMARY KEY,                    -- ULID
    parent_plan_id TEXT REFERENCES plans(plan_id),
    root_plan_id TEXT NOT NULL REFERENCES plans(plan_id),
    action_name TEXT NOT NULL,                    -- namespaced action name
    phase TEXT NOT NULL DEFAULT 'strategize',     -- strategize|execute|apply
    state TEXT NOT NULL DEFAULT 'queued',         -- queued|processing|errored|complete|cancelled
    attempt INTEGER NOT NULL DEFAULT 1,
    automation_profile_name TEXT NOT NULL,
    effective_profile_snapshot TEXT NOT NULL,      -- JSON: frozen profile at creation
    arguments TEXT,                                -- JSON: action arguments
    project_names TEXT NOT NULL,                   -- JSON array of project names
    strategy_actor_name TEXT,
    execution_actor_name TEXT,
    estimation_actor_name TEXT,
    invariant_actor_name TEXT,
    created_by TEXT,                               -- session ID or user identity
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
    updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
    completed_at TEXT,
    error_message TEXT,
    error_traceback TEXT,
    cost_estimate_usd REAL,
    cost_actual_usd REAL,
    token_count_input INTEGER DEFAULT 0,
    token_count_output INTEGER DEFAULT 0
);

CREATE INDEX idx_plans_parent ON plans(parent_plan_id);
CREATE INDEX idx_plans_root ON plans(root_plan_id);
CREATE INDEX idx_plans_phase_state ON plans(phase, state);
CREATE INDEX idx_plans_action ON plans(action_name);
CREATE INDEX idx_plans_created ON plans(created_at);

-- Decisions table: the decision tree
CREATE TABLE decisions (
    decision_id TEXT PRIMARY KEY,                 -- ULID
    plan_id TEXT NOT NULL REFERENCES plans(plan_id),
    parent_decision_id TEXT REFERENCES decisions(decision_id),
    decision_type TEXT NOT NULL,                   -- prompt_definition|invariant_enforced|
                                                   -- strategy_choice|subplan_spawn|
                                                   -- subplan_parallel_spawn|implementation_choice
    question TEXT NOT NULL,
    chosen_option TEXT NOT NULL,
    alternatives_considered TEXT,                  -- JSON array of alternative options
    confidence_score REAL,                         -- 0.0-1.0
    rationale TEXT,
    context_snapshot TEXT NOT NULL,                -- JSON: hot_context_hash, relevant_resources,
                                                   --       actor_state_ref
    downstream_plan_ids TEXT,                      -- JSON array of child plan ULIDs
    artifacts_produced TEXT,                       -- JSON array of artifact references
    is_correction BOOLEAN DEFAULT FALSE,
    corrects_decision_id TEXT REFERENCES decisions(decision_id),
    superseded_by TEXT REFERENCES decisions(decision_id),
    sequence_number INTEGER NOT NULL,              -- ordering within this plan
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))
);

CREATE INDEX idx_decisions_plan ON decisions(plan_id);
CREATE INDEX idx_decisions_parent ON decisions(parent_decision_id);
CREATE INDEX idx_decisions_type ON decisions(decision_type);
CREATE INDEX idx_decisions_superseded ON decisions(superseded_by) WHERE superseded_by IS NOT NULL;

-- Resources table: the resource registry
CREATE TABLE resources (
    resource_id TEXT PRIMARY KEY,                  -- ULID
    name TEXT,                                     -- namespaced name (NULL for auto-discovered children)
    resource_type_name TEXT NOT NULL,              -- namespaced type name
    classification TEXT NOT NULL,                  -- physical|virtual
    description TEXT,
    properties TEXT,                               -- JSON: type-specific properties
    location TEXT,                                 -- physical resources only
    content_hash TEXT,                             -- for equivalence tracking
    sandbox_strategy TEXT,                         -- override per resource
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
    updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))
);

CREATE UNIQUE INDEX idx_resources_name ON resources(name) WHERE name IS NOT NULL;
CREATE INDEX idx_resources_type ON resources(resource_type_name);
CREATE INDEX idx_resources_classification ON resources(classification);

-- Resource DAG: parent/child relationships
CREATE TABLE resource_links (
    parent_id TEXT NOT NULL REFERENCES resources(resource_id),
    child_id TEXT NOT NULL REFERENCES resources(resource_id),
    link_type TEXT DEFAULT 'contains',            -- contains|references|derived_from
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
    PRIMARY KEY (parent_id, child_id)
);

CREATE INDEX idx_resource_links_child ON resource_links(child_id);

-- Project-resource linkage
CREATE TABLE project_resources (
    project_name TEXT NOT NULL,
    resource_id TEXT NOT NULL REFERENCES resources(resource_id),
    read_only BOOLEAN DEFAULT FALSE,
    linked_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
    PRIMARY KEY (project_name, resource_id)
);

-- Checkpoint metadata (actual data on filesystem)
CREATE TABLE checkpoint_metadata (
    checkpoint_id TEXT PRIMARY KEY,               -- ULID
    plan_id TEXT NOT NULL REFERENCES plans(plan_id),
    decision_id TEXT REFERENCES decisions(decision_id),
    checkpoint_type TEXT NOT NULL,                 -- pre_write|post_step|manual
    resource_id TEXT REFERENCES resources(resource_id),
    filesystem_path TEXT NOT NULL,                 -- relative path within checkpoint dir
    size_bytes INTEGER,
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))
);

CREATE INDEX idx_checkpoints_plan ON checkpoint_metadata(plan_id);

-- Correction attempts
CREATE TABLE correction_attempts (
    correction_attempt_id TEXT PRIMARY KEY,        -- ULID
    plan_id TEXT NOT NULL REFERENCES plans(plan_id),
    original_decision_id TEXT NOT NULL REFERENCES decisions(decision_id),
    new_decision_id TEXT REFERENCES decisions(decision_id),
    mode TEXT NOT NULL,                            -- revert|append
    guidance TEXT NOT NULL,
    archived_artifacts_path TEXT,                  -- filesystem path to archived originals
    state TEXT NOT NULL DEFAULT 'pending',         -- pending|executing|complete|failed
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
    completed_at TEXT
);

CREATE INDEX idx_corrections_plan ON correction_attempts(plan_id);

-- Audit log for apply operations
CREATE TABLE audit_log (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    event_type TEXT NOT NULL,                      -- plan_applied|plan_cancelled|resource_modified|
                                                   -- correction_applied|config_changed
    plan_id TEXT,
    project_name TEXT,
    actor_name TEXT,
    user_identity TEXT,
    details TEXT NOT NULL,                         -- JSON: event-specific details
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now'))
);

CREATE INDEX idx_audit_event ON audit_log(event_type);
CREATE INDEX idx_audit_plan ON audit_log(plan_id) WHERE plan_id IS NOT NULL;
CREATE INDEX idx_audit_created ON audit_log(created_at);

Filesystem Layout

The data directory follows a deterministic layout. All paths are relative to core.data-dir (default: ~/.cleveragents):

~/.cleveragents/
├── config.toml                    # Global configuration
├── cleveragents.db                # SQLite database (WAL mode)
├── cleveragents.db-wal            # WAL file (auto-managed by SQLite)
├── cleveragents.db-shm            # Shared memory file (auto-managed)
├── logs/
│   ├── cleveragents.log           # Current log file (structured JSON)
│   ├── cleveragents.log.1         # Rotated log files
│   └── ...
├── cache/
│   ├── models/                    # Cached model artifacts
│   ├── tools/                     # Cached tool downloads
│   └── templates/                 # Compiled Jinja2 templates
├── backups/
│   ├── 2026-02-08T12-30-00/       # Timestamped backup snapshots
│   └── ...
├── checkpoints/
│   ├── 01HXR1C1D2E3F4G5H6I7.../  # Per-plan checkpoint directories
│   │   ├── chk_01HXR1E1.tar.gz   # Compressed checkpoint snapshots
│   │   └── ...
│   └── ...
├── artifacts/
│   ├── 01HXR1C1D2E3F4G5H6I7.../  # Per-plan artifact directories
│   │   ├── src/routes/health.py   # Generated/modified artifacts
│   │   └── ...
│   └── ...
├── index/
│   ├── text/
│   │   ├── local_api-service/     # Per-project Tantivy indexes
│   │   └── ...
│   ├── vector/
│   │   ├── local_api-service/     # Per-project FAISS indexes
│   │   └── ...
│   └── graph/
│       └── ...                     # rdflib stores or Neo4j connection info
├── sessions/
│   └── ...                         # Session state files (if needed beyond DB)
└── contexts/
    └── ...                         # Exported/cached context snapshots

Data Lifecycle and Retention

Data Type Retention Policy Cleanup Trigger
Plans (active) Indefinite until applied or cancelled Manual deletion
Plans (terminal) Governed by core.backup.retention-days for archives Automatic cleanup daemon
Decisions Retained as long as parent plan exists Cascade delete with plan
Checkpoints sandbox.checkpoint.max-per-plan per plan; oldest pruned first (keeping first + most recent) After apply or on retention limit
Correction archives core.backup.retention-days after plan is applied Automatic cleanup daemon
Logs core.log.retention-days Daily rotation + age-based cleanup
Backups core.backup.retention-days Age-based cleanup
Cache No automatic retention; manual cleanup via agents diagnostics --cleanup User-initiated
Search indexes Rebuilt on resource add/remove; no explicit retention Re-index on change
Audit logs Indefinite (critical for compliance) Manual archival only

Migration Strategy

Database schema changes are managed through Alembic migrations with the following rules:

  1. Forward-only in production: Downgrade scripts are provided but only used in development. Production deployments only move forward.
  2. Auto-apply on startup: When CLEVERAGENTS_AUTO_APPLY_MIGRATIONS is set (default in development), migrations run automatically on first database access. In production, migrations are triggered by agents init or explicit upgrade commands.
  3. Backward compatibility window: Each migration maintains backward compatibility with the previous schema version for at least one minor release cycle, allowing rolling upgrades in server mode.
  4. Data migration separation: Schema DDL changes and data transformations are kept in separate migration steps to enable rollback of data changes independently.

Observability

CleverAgents implements a comprehensive observability strategy across three pillars — logging, metrics, and tracing — designed to provide full visibility into plan execution, actor behavior, tool invocations, and resource access. Every significant operation in the system is observable, enabling debugging of complex multi-plan hierarchies and performance optimization.

Structured Logging

All logging uses structlog with JSON output format. Every log entry includes contextual fields that enable correlation across plan hierarchies:

import structlog

logger = structlog.get_logger()

# Every log entry automatically includes bound context
logger = logger.bind(
    plan_id="01HXR1C1D2E3F4G5H6I7J8K9L0",
    phase="execute",
    actor_name="anthropic/claude-3.5-sonnet",
    session_id="01HXM2A6K1P2E9Q9D4GQ7J4S7Z",
)

# Example: tool invocation logging
logger.info(
    "tool_invoked",
    tool_name="local/write-file",
    skill_name="local/file-ops",
    resource_id="01HXR1A1B2C3D4E5F6G7H8J9K0",
    resource_type="git-checkout",
    input_schema_hash="sha256:a1b2c3...",
    duration_ms=142,
    writes=True,
    checkpoint_created=True,
)

Log levels and their semantics:

Level Usage Examples
DEBUG Internal state transitions, context building details, LLM prompt construction "Building hot context: 12 files, 8,420 tokens", "Decision confidence computed: 0.87"
INFO Significant lifecycle events, phase transitions, tool completions "Plan entered execute phase", "Tool write-file completed in 142ms", "Validation passed: pytest"
WARNING Degraded operations, approaching limits, non-fatal issues "Budget at 82% ($4.10/$5.00)", "Checkpoint pruned: exceeded max-per-plan", "Provider fallback: openai -> anthropic"
ERROR Operation failures, invariant violations, unrecoverable tool errors "Validation failed: pytest exited 1", "Invariant violated: API compatibility", "LLM provider error: rate limited"

Log correlation: Every log entry within a plan execution context includes plan_id, root_plan_id, parent_plan_id, phase, state, and attempt. This enables tracing a single decision through the entire plan hierarchy using standard log querying tools (e.g., jq '.plan_id == "01HXR1C1..."').

Event System

CleverAgents emits domain events for every significant state change. Events flow through two channels:

  1. RxPY Reactive Stream: Real-time event stream for in-process subscribers (TUI updates, progress bars, streaming output). Uses Subject for fan-out distribution.
  2. Persistent Event Log: All events are written to the audit_log table for post-hoc analysis and compliance.

Event taxonomy:

from enum import Enum
from pydantic import BaseModel
from datetime import datetime

class EventType(str, Enum):
    # Plan lifecycle events
    PLAN_CREATED = "plan.created"
    PLAN_PHASE_CHANGED = "plan.phase_changed"
    PLAN_STATE_CHANGED = "plan.state_changed"
    PLAN_APPLIED = "plan.applied"
    PLAN_CANCELLED = "plan.cancelled"
    PLAN_ERRORED = "plan.errored"

    # Decision events
    DECISION_CREATED = "decision.created"
    DECISION_APPROVED = "decision.approved"
    DECISION_CORRECTED = "decision.corrected"
    DECISION_SUPERSEDED = "decision.superseded"

    # Invariant events
    INVARIANT_RECONCILED = "invariant.reconciled"
    INVARIANT_VIOLATED = "invariant.violated"
    INVARIANT_ENFORCED = "invariant.enforced"

    # Actor events
    ACTOR_INVOKED = "actor.invoked"
    ACTOR_COMPLETED = "actor.completed"
    ACTOR_ERRORED = "actor.errored"
    ACTOR_ESCALATED = "actor.escalated"       # confidence below threshold

    # Tool events
    TOOL_INVOKED = "tool.invoked"
    TOOL_COMPLETED = "tool.completed"
    TOOL_ERRORED = "tool.errored"
    TOOL_RETRIED = "tool.retried"

    # Resource events
    RESOURCE_ACCESSED = "resource.accessed"
    RESOURCE_MODIFIED = "resource.modified"
    RESOURCE_INDEXED = "resource.indexed"

    # Sandbox events
    SANDBOX_CREATED = "sandbox.created"
    SANDBOX_COMMITTED = "sandbox.committed"
    SANDBOX_ROLLED_BACK = "sandbox.rolled_back"
    CHECKPOINT_CREATED = "checkpoint.created"
    CHECKPOINT_RESTORED = "checkpoint.restored"

    # Context events
    CONTEXT_BUILT = "context.built"
    CONTEXT_QUERY_EXECUTED = "context.query_executed"

    # Validation events
    VALIDATION_STARTED = "validation.started"
    VALIDATION_PASSED = "validation.passed"
    VALIDATION_FAILED = "validation.failed"

    # Session events
    SESSION_CREATED = "session.created"
    SESSION_MESSAGE_SENT = "session.message_sent"

    # Cost events
    BUDGET_WARNING = "budget.warning"
    BUDGET_EXCEEDED = "budget.exceeded"


class DomainEvent(BaseModel):
    """Base event model emitted by all domain operations."""
    event_type: EventType
    timestamp: datetime
    plan_id: str | None = None
    root_plan_id: str | None = None
    session_id: str | None = None
    actor_name: str | None = None
    project_name: str | None = None
    details: dict  # Event-type-specific payload

Event emission pattern: Domain services emit events through an injected EventBus interface. The infrastructure layer provides two implementations:

from typing import Protocol
import rx
from rx.subject import Subject

class EventBus(Protocol):
    def emit(self, event: DomainEvent) -> None: ...
    def subscribe(self, event_type: EventType, handler: Callable) -> None: ...

class ReactiveEventBus:
    """In-process event bus using RxPY for real-time distribution."""
    def __init__(self):
        self._subject = Subject()
        self._subscriptions: dict[EventType, list[Callable]] = {}

    def emit(self, event: DomainEvent) -> None:
        # Push to reactive stream for real-time subscribers
        self._subject.on_next(event)
        # Persist to audit log
        self._persist_audit(event)
        # Dispatch to type-specific handlers
        for handler in self._subscriptions.get(event.event_type, []):
            handler(event)

    def subscribe(self, event_type: EventType, handler: Callable) -> None:
        self._subscriptions.setdefault(event_type, []).append(handler)

    @property
    def stream(self) -> rx.Observable:
        """Raw observable stream for advanced RxPY operators."""
        return self._subject

LLM Call Tracing

Every LLM invocation is traced with full context for debugging and cost tracking:

# Trace record for each LLM call
class LLMTrace(BaseModel):
    trace_id: str                     # ULID
    plan_id: str
    decision_id: str | None
    actor_name: str
    provider: str                     # openai, anthropic, google, etc.
    model: str                        # gpt-4o, claude-3.5-sonnet, etc.
    prompt_tokens: int
    completion_tokens: int
    total_tokens: int
    cost_usd: float
    latency_ms: int
    temperature: float
    tool_calls: list[str]             # tool names invoked by the LLM
    context_hash: str                 # hash of the context window contents
    context_refs: list[str]           # resource IDs referenced in context
    streaming: bool
    retry_count: int
    error: str | None
    timestamp: datetime

LangSmith integration: When CLEVERAGENTS_LANGSMITH_ENABLED is true, all LLM traces are additionally forwarded to LangSmith for visualization, comparison, and cost analysis. The integration maps CleverAgents plan IDs to LangSmith run tags, enabling filtering by plan hierarchy in the LangSmith UI.

Metrics Collection

CleverAgents collects operational metrics for performance monitoring and capacity planning. Metrics are emitted as structured log entries (for local mode) and optionally exported to Prometheus (for server mode):

Metric Type Description
plan.duration_seconds Histogram Total wall-clock time per plan, labeled by phase
plan.cost_usd Counter Cumulative API cost per plan
plan.decisions_count Counter Number of decisions per plan
plan.child_plans_count Counter Number of child plans spawned
actor.invocation_duration_ms Histogram Per-actor invocation latency
actor.token_usage Counter Token counts by provider and model
tool.invocation_duration_ms Histogram Per-tool invocation latency
tool.error_rate Counter Tool invocation failures by tool name
context.build_duration_ms Histogram Context building time by tier (hot/warm/cold)
context.tokens_used Gauge Current token usage in hot context
index.query_duration_ms Histogram Index query latency by backend (text/vector/graph)
sandbox.operation_duration_ms Histogram Sandbox create/commit/rollback time
validation.duration_seconds Histogram Per-validation command execution time
validation.pass_rate Counter Validation pass/fail counts

Diagnostic Dashboard

The agents diagnostics command provides a real-time health check combining all observability data:

  1. System health: Config file readability, database accessibility, disk space, provider API key validation.
  2. Index health: Text index status, vector index dimensionality and count, graph store connectivity.
  3. Active plan overview: Running plans, queued plans, resource utilization.
  4. Cost summary: Current session cost, budget utilization, provider-level breakdown.
  5. Performance summary: Average plan duration, tool call latency percentiles, context build times.

Security Model

CleverAgents implements a defense-in-depth security model addressing five concerns: sandbox isolation, access control, prompt injection mitigation, secret management, and audit logging. The security model differs between local mode (single-user, trusted environment) and server mode (multi-user, potentially untrusted environment).

Sandbox Isolation

The sandbox is the primary safety mechanism preventing untested changes from reaching production resources. Every plan's Execute phase runs within an isolated sandbox unless explicitly disabled by the automation profile (require_sandbox: false).

Sandbox strategies and their security properties:

Strategy Isolation Level Resource Type Mechanism Rollback
git_worktree Process-level filesystem isolation Git repositories Creates a separate git worktree on a plan-specific branch. Changes are confined to the worktree directory. Merge back to main requires explicit apply. git checkout -- . or worktree deletion
filesystem_copy Process-level filesystem isolation Non-git filesystems Creates a copy-on-write snapshot (using cp --reflink=auto where supported, falling back to full copy). Original files are never modified during execution. Delete the copy directory
transaction_rollback Database transaction isolation Databases Opens a database transaction with SERIALIZABLE isolation level. All changes are staged within the transaction. Commit on apply; rollback on cancel/error. ROLLBACK
none No isolation Any Changes are applied directly. Requires require_sandbox: false in the automation profile. Only appropriate when external safety mechanisms exist. No automatic rollback

Sandbox security invariants:

  1. No cross-sandbox access: Each plan's sandbox is isolated. Plan A cannot read or write Plan B's sandbox contents. The sandbox path is derived deterministically from the plan ULID, preventing path traversal.
  2. Read-only source guarantee during Execute: The original project resources are never modified during Execute. All tool write operations target the sandbox copy.
  3. Atomic apply: The Apply phase is an atomic operation — either all sandbox changes are committed to the real resources, or none are. For git-based resources, this uses git merge. For database resources, this uses transaction commit.
  4. Sandbox cleanup: Sandbox directories are cleaned up according to sandbox.cleanup policy. Sensitive data (API responses, LLM outputs) is purged from the sandbox on cleanup.

Access Control

Local mode: Local resources have unrestricted access. The read_only flag on project-resource links provides soft enforcement — the tool layer checks this flag and refuses write operations when set, but there is no OS-level enforcement since the user running CleverAgents already has filesystem access.

Server mode: Server mode implements namespace-based access control:

class AccessPolicy(BaseModel):
    """Defines who can access what in server mode."""
    namespace: str                    # Owner namespace (username or orgname)
    entity_type: str                  # plan, project, action, actor, etc.
    entity_name: str                  # Namespaced entity name
    permissions: set[Permission]      # read, write, execute, admin

class Permission(str, Enum):
    READ = "read"                     # View entity and its details
    WRITE = "write"                   # Modify entity configuration
    EXECUTE = "execute"               # Execute plans, invoke actors
    ADMIN = "admin"                   # Delete, transfer ownership, manage permissions

# Permission resolution:
# 1. Entity owner (namespace match) has all permissions
# 2. Organization members have permissions granted by org admin
# 3. Public entities (if supported) grant READ to all authenticated users
# 4. The `local/` namespace is never accessible from server mode

Resource-level ACLs: Resources linked to projects inherit the project's namespace for permission checking. A resource linked to orgname/production-api is accessible only to members of the orgname organization. Resources linked to multiple projects are accessible to users with permissions on any of those projects.

Prompt Injection Mitigation

In server mode, where user-provided content may flow into LLM prompts, CleverAgents implements several mitigations:

  1. Input sanitization: User-provided text in action arguments, invariant text, and session prompts is sanitized before inclusion in LLM prompts. HTML entities, control characters, and known injection patterns are escaped or rejected.

  2. Prompt boundary markers: System prompts and user content are separated by clear boundary markers that the LLM is instructed to recognize. The system prompt explicitly states that content between [USER_CONTENT_START] and [USER_CONTENT_END] markers is user-provided and should not be treated as system instructions.

  3. Output validation: LLM outputs that are used as tool invocations are validated against the tool's JSON Schema before execution. This prevents the LLM from being tricked into invoking tools with malicious parameters.

  4. Tool capability restrictions: Tools declare their capabilities (read_only, writes, checkpointable, side_effects). The execution engine enforces these declarations — a tool declared as read_only cannot invoke write operations even if the LLM requests it.

  5. Unsafe tool gating: Tools marked as unsafe (e.g., arbitrary shell execution, network access) are blocked unless the automation profile explicitly sets allow_unsafe_tools: true. In server mode, only administrators can create automation profiles that allow unsafe tools.

Secret Management

Secrets (API keys, database credentials, authentication tokens) are managed through a layered approach:

  1. Environment variables (preferred): Provider API keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) and the server token (CLEVERAGENTS_SERVER_TOKEN) are read from environment variables. This is the recommended approach for both local and CI environments.

  2. Configuration file (fallback): API keys can be stored in config.toml under the provider.* section. The config file should have restrictive permissions (chmod 600). The agents diagnostics command warns if config file permissions are too permissive.

  3. Secret masking in logs: All log output and CLI display automatically masks values that match known secret patterns (keys starting with sk-, sk-ant-, tok_, etc.). Masked values are replaced with ***REDACTED***. The masking is applied at the structlog processor level, ensuring no secret leaks through any log path.

  4. Secret masking in LLM context: Before constructing LLM prompts, the context builder scans for patterns matching known secret formats and replaces them with [REDACTED]. This prevents accidental exposure of secrets in LLM training data (for providers that use customer data for training, which CleverAgents discourages).

  5. Server mode credential isolation: In server mode, each user's API keys are stored encrypted in the server database using AES-256-GCM with a per-user key derived from the server's master secret. Keys are decrypted only at the moment of LLM invocation and are never transmitted to the client CLI.

Audit Logging

All security-relevant operations are recorded in the audit_log table with the following events:

Event Type Trigger Details Captured
plan_applied agents plan apply Plan ID, project names, files changed, validation results, user identity
plan_cancelled agents plan cancel Plan ID, reason, resources released
resource_modified Tool write operations during Execute Resource ID, modification type, sandbox path, tool name
correction_applied agents plan correct Correction attempt ID, original decision ID, mode, guidance
config_changed agents config set Key, old value (masked if secret), new value (masked if secret), user identity
entity_deleted agents <entity> delete/remove Entity type, entity name, cascade effects
session_created agents session create Session ID, actor name, user identity
auth_success Server mode login User identity, IP address, token prefix
auth_failure Server mode failed login Attempted identity, IP address, failure reason
permission_denied Unauthorized access attempt in server mode User identity, entity, requested permission

Audit log retention: Audit logs are never automatically deleted. In server mode, audit logs can be exported for compliance archival using server administration commands. In local mode, audit logs are preserved in the SQLite database indefinitely and are included in backup snapshots.

Extensibility

CleverAgents is designed as an extensible platform where every major subsystem supports custom implementations. The extensibility model follows the Open/Closed Principle — the system is open for extension through well-defined interfaces, but closed for modification of core behavior.

Plugin Architecture Overview

┌────────────────────────────────────────────────────────┐
│                   Extension Points                      │
│                                                         │
│  ┌─────────────┐  ┌──────────────┐  ┌───────────────┐ │
│  │ Custom Tools │  │ Custom Skills│  │ Custom Actors │ │
│  │ (YAML/Python)│  │ (YAML)       │  │ (YAML/Graph) │ │
│  └──────┬──────┘  └──────┬───────┘  └───────┬───────┘ │
│         │                │                   │          │
│  ┌──────┴──────┐  ┌──────┴───────┐  ┌───────┴───────┐ │
│  │ MCP Servers │  │ Agent Skills │  │ Custom LLM    │ │
│  │ (stdio/SSE) │  │ Standard     │  │ Providers     │ │
│  └──────┬──────┘  └──────┬───────┘  └───────┬───────┘ │
│         │                │                   │          │
│  ┌──────┴────────────────┴───────────────────┴───────┐ │
│  │              Tool Registry                         │ │
│  │              Skill Registry                        │ │
│  │              Actor Registry                        │ │
│  │              Provider Registry                     │ │
│  └──────────────────────┬────────────────────────────┘ │
│                         │                               │
│  ┌──────────────────────┴────────────────────────────┐ │
│  │  Custom Resource    │  Custom Sandbox  │  Custom  │ │
│  │  Types (YAML)       │  Strategies     │  Index   │ │
│  │                     │  (Python)       │  Backends│ │
│  └─────────────────────┴─────────────────┴──────────┘ │
└────────────────────────────────────────────────────────┘

Tool Extensibility

Tools are the atomic unit of execution and the primary extension point. There are five ways to add tools:

  1. Custom Python tools: Define a tool with inline Python code in a YAML configuration file. The code runs in a sandboxed execution context with access to the plan context, resource bindings, and checkpoint API.

    # File: tools/my-custom-tool.yaml
    tool:
      name: local/analyze-complexity
      description: "Compute cyclomatic complexity for Python files"
      source: custom
    
      input_schema:
        type: object
        properties:
          file_path: { type: string }
        required: [file_path]
    
      output_schema:
        type: object
        properties:
          complexity: { type: integer }
          functions: { type: array }
    
      capability:
        writes: false
        checkpointable: false
    
      resource_slots:
        - name: source
          type: git-checkout
          binding: contextual
    
      code: |
        import ast
        content = ctx.resources["source"].read(params["file_path"])
        tree = ast.parse(content)
        # ... complexity analysis ...
        return {"complexity": total, "functions": results}
    
  2. MCP server tools: Any MCP-compliant server can expose tools to CleverAgents. Skills reference MCP servers by their transport configuration:

    # File: skills/kubernetes-ops.yaml
    skill:
      name: local/kubernetes-ops
      description: "Kubernetes cluster management tools"
      mcp_servers:
        - transport: stdio
          command: npx
          args: ["-y", "@anthropic/mcp-kubernetes"]
    
  3. Agent Skills Standard tools: Tools organized in standard folder structures are auto-discovered and registered:

    skill:
      name: local/project-tools
      agent_skills_dirs:
        - ./agent-skills/
    
  4. Built-in tools: Core file operations (read_file, write_file, edit_file, delete_file, move_file, list_files, search_files), plan operations (create-subplan), and system operations are provided as built-in tools grouped into built-in skills.

  5. Anonymous inline tools: Tools can be defined inline within actor graph nodes or skill definitions for one-off operations that don't need global registration.

Tool lifecycle hooks: Every tool follows a four-phase lifecycle — discover (find available capabilities), activate (prepare for use, acquire connections), execute (perform the operation), deactivate (release resources). The tool registry manages these lifecycle transitions.

Skill Extensibility

Skills compose tools into capability collections. Skills support:

  • Tool aggregation: Reference named tools from the Tool Registry
  • Inline anonymous tools: Define tools directly in the skill YAML
  • Skill inclusion: Include other skills by reference (composability)
  • MCP server aggregation: Expose tools from one or more MCP servers
  • Agent Skills Standard: Expose tools from Agent Skills Standard directories

Actor Extensibility

Actors can be extended through:

  1. YAML-defined agents: Single LLM actors with custom system prompts, temperature settings, tool bindings, and capability constraints.
  2. YAML-defined graphs: LangGraph topologies with multiple actors and tool nodes connected by edges, conditional routing, and parallel execution groups.
  3. Provider extension: New LLM providers can be added by implementing the AIProviderInterface protocol and registering with the ProviderRegistry. The registry uses auto-discovery to detect installed langchain-* packages.
from typing import Protocol

class AIProviderInterface(Protocol):
    """Protocol for LLM provider implementations."""

    @property
    def provider_name(self) -> str: ...

    @property
    def capabilities(self) -> ProviderCapabilities: ...

    def create_chat_model(
        self,
        model: str,
        temperature: float = 0.7,
        **kwargs,
    ) -> BaseChatModel: ...

    def create_embedding_model(
        self,
        model: str,
        **kwargs,
    ) -> BaseEmbeddings: ...

Custom Resource Types

New resource types extend CleverAgents to manage any kind of resource:

# File: resource-types/docker-registry.yaml
resource_type:
  name: local/docker-registry
  description: "Docker container registry"
  classification: physical
  user_addable: true

  cli_args:
    - name: registry_url
      type: string
      required: true
    - name: repository
      type: string
      required: true
    - name: tag
      type: string
      default: "latest"

  sandbox_strategy: none    # Docker images are immutable
  handler: docker_registry_handler

  child_types:
    - type: local/docker-image
      relationship: contains
      auto_discover: true

  auto_discovery:
    enabled: true
    strategy: list_tags

Custom Index Backends

The indexing layer is abstracted behind three interfaces (text, vector, graph). Custom implementations can be registered for each:

class TextIndexBackend(Protocol):
    """Interface for full-text search backends."""
    def index_document(self, project: str, doc_id: str, content: str, metadata: dict) -> None: ...
    def search(self, project: str, query: str, limit: int) -> list[SearchResult]: ...
    def remove_document(self, project: str, doc_id: str) -> None: ...
    def rebuild_index(self, project: str) -> None: ...

class VectorIndexBackend(Protocol):
    """Interface for vector similarity search backends."""
    def index_embedding(self, project: str, doc_id: str, embedding: list[float], metadata: dict) -> None: ...
    def search_similar(self, project: str, query_embedding: list[float], limit: int, min_relevance: float) -> list[VectorResult]: ...
    def remove_embedding(self, project: str, doc_id: str) -> None: ...

class GraphIndexBackend(Protocol):
    """Interface for knowledge graph backends."""
    def add_triple(self, project: str, subject: str, predicate: str, obj: str) -> None: ...
    def query(self, project: str, sparql: str) -> list[dict]: ...
    def remove_triples(self, project: str, subject: str | None, predicate: str | None, obj: str | None) -> None: ...

New backends are registered via configuration:

# config.toml
[index.text]
backend = "custom"
custom_module = "my_extensions.elasticsearch_backend"
custom_class = "ElasticsearchTextIndex"

[index.text.custom_options]
hosts = ["http://localhost:9200"]
index_prefix = "cleveragents"

Custom Sandbox Strategies

The sandbox layer supports custom isolation strategies for specialized resource types:

class SandboxStrategy(Protocol):
    """Interface for sandbox isolation strategies."""
    def create(self, plan_id: str, resource: Resource) -> SandboxRef: ...
    def read(self, ref: SandboxRef, path: str) -> bytes: ...
    def write(self, ref: SandboxRef, path: str, content: bytes) -> Change: ...
    def diff(self, ref: SandboxRef) -> DiffView: ...
    def commit(self, ref: SandboxRef) -> None: ...
    def rollback(self, ref: SandboxRef) -> None: ...
    def checkpoint(self, ref: SandboxRef, checkpoint_id: str) -> None: ...
    def restore_checkpoint(self, ref: SandboxRef, checkpoint_id: str) -> None: ...
    def cleanup(self, ref: SandboxRef) -> None: ...

Custom strategies are mapped to resource types via the resource type configuration's sandbox_strategy field, or globally via sandbox.strategy config.

Extension Points Summary

Extension Point Registration Mechanism Configuration Format Discovery
Custom Tools agents tool add --config <file> YAML Manual registration
MCP Server Tools Referenced in skill YAML mcp_servers section YAML Auto-discovered from MCP server
Agent Skills Standard Referenced in skill YAML agent_skills_dirs section Folder structure Auto-discovered from directory
Custom Skills agents skill add --config <file> YAML Manual registration
Custom Actors agents actor add --config <file> YAML Manual registration
Custom Resource Types agents resource type add --config <file> YAML Manual registration
Custom LLM Providers Python package installation + ProviderRegistry auto-discovery Python module Auto-discovered via langchain-* package naming
Custom Index Backends config.toml index.*.custom_module TOML + Python module Configuration-driven
Custom Sandbox Strategies Resource type sandbox_strategy field YAML + Python module Configuration-driven
Custom Automation Profiles agents automation-profile add --config <file> YAML Manual registration
Custom Invariant Actors Standard actor registration + assignment via --invariant-actor YAML Manual assignment

Summary of Key Intended Behaviors (If You Only Read One Section)

  • Plans follow Action → Strategize → Execute → Apply with automation profiles controlling transitions and decision automation.
  • Strategize is read-only and produces a strategy + blueprint.
  • Execute happens in a sandbox, can spawn child plans, and should support checkpoints/rollback when enabled.
  • Apply commits changes from sandbox to real project after review/validation.
  • Actors are hierarchical: an actor can be a single agent or an entire graph.
  • Graph nodes can be actors or tools (tools are provided by referenced skills, which aggregate tools from MCP servers, Agent Skills folders, built-ins, and custom code).
  • Context should evolve toward hot/warm/cold tiers and actor-specific context views.
  • The system is designed for large tasks where the user can correct a decision and only recompute downstream work, visualizable as a plan decision tree.

The system can handle Firefox-scale projects not through magic, but through:

  • Hierarchical decomposition breaking massive tasks into bounded work
  • Persistent decision graphs maintaining context across any scale
  • Isolated execution preventing cascading failures
  • Semantic validation catching errors before propagation
  • Progressive automation building trust through incremental success

Future details to add to this document:

  • a canonical JSON/YAML schema for Actions, Actors, Projects, Plans, Skills, and Context Views,
  • a CLI command reference (every command, flags, examples),
  • and a set of end-to-end example workflows (single project, multi-project, infra task, paper-writing task) consistent with this spec.

Work Remaining to Make CleverAgents Fully Functional

This section describes what remains to be done to bring the current CleverAgents codebase up to the specification.

Last Updated: February 6, 2026

Current State Assessment

What's Implemented

Based on analysis of the current codebase:

  1. Plan Lifecycle Foundation - The 4-phase lifecycle (Action → Strategize → Execute → Apply) is partially implemented in plan_lifecycle_service.py
  2. Database Models - Models exist for projects, plans, contexts, changes, and actors
  3. LangGraph Integration - Graph-based workflow support exists but is not fully connected to the plan workflow
  4. Reactive System - A reactive system with stream routing is present
  5. Actor System - Actor models and services exist but lack full behavioral definitions
  6. Basic Context Analysis - Simple context loading and analysis capabilities
  7. Change Tracking - Basic Change and ChangeSet models exist

What's Missing

Critical gaps between the specification and current implementation:

  1. No Resource Abstraction - The unified resource layer for files, databases, APIs is entirely missing
  2. No Sandboxing - Execute phase writes directly to files without isolation
  3. No Decision Tree - No decision tracking, storage, or correction mechanism
  4. No Skills/MCP Integration - No skill registry, skill YAML parsing, tool adapters, or MCP protocol support
  5. Single-File Limitation - Hard-coded to generate exactly one file per plan
  6. Text-Based Code Generation - Still parsing LLM output instead of tool-based approach
  7. No Checkpointing - No rollback or checkpoint capabilities
  8. No Code Intelligence - Missing indexing, vector search, and RDF graph store
  9. No Context Tiers - No hot/warm/cold memory architecture
  10. Limited Validation - Basic stub validation instead of semantic checks

Work Items by Priority

1) Implement Tool-Based Resource Modification (Critical Foundation)

Problem

The current system generates code as a single text blob that gets written to one file. The specification requires a modern tool-based approach where LLMs invoke discrete operations on resources.

Implementation Steps

  1. Create Resource Abstraction Layer

    
    # New modules needed:
    src/cleveragents/domain/models/resources.py
    src/cleveragents/domain/resources/handlers.py
    src/cleveragents/domain/resources/sandbox.py
    
  2. Implement Built-in Tools (via built-in skills)

    
    # Core file operations (provided by built-in skill groups)
    read_file(path: str) -> str
    write_file(path: str, content: str) -> None
    edit_file(path: str, changes: list[Edit]) -> None
    delete_file(path: str) -> None
    move_file(src: str, dst: str) -> None
    create_directory(path: str) -> None
    list_files(pattern: str) -> list[str]
    search_files(pattern: str, content_pattern: str) -> list[Match]
    
  3. Connect Tools to ChangeSet

    • Each tool invocation that modifies resources creates a Change record
    • ChangeSet accumulates these changes during execution
    • No more parsing LLM text output for code

Estimated Effort: 2-3 weeks

2) Implement Sandbox Infrastructure (Critical for Safety)

Problem

Execute phase currently writes directly to the project. The specification requires all changes happen in an isolated sandbox that can be reviewed before applying.

Implementation Steps

  1. Define Sandbox Interface

    
    class Sandbox(Protocol):
        def create() -> SandboxRef
        def read(path: str) -> Content
        def write(path: str, content: Content) -> Change
        def diff() -> DiffView
        def commit() -> None
        def rollback() -> None
    
  2. Implement Sandbox Strategies

    • GitWorktreeSandbox - For git repositories (preferred)
    • FilesystemCopySandbox - For non-git projects
    • TransactionSandbox - For databases
    • NoOpSandbox - For non-sandboxable resources
  3. Lazy Sandbox Creation

    • Only create sandboxes when resources are accessed
    • Each plan gets its own sandbox namespace

Estimated Effort: 2 weeks

3) Build Decision Tree System (Core Innovation)

Problem

No decision tracking exists. The specification's key innovation is recording every decision with full context, enabling correction without full re-execution.

Implementation Steps

  1. Create Decision Models

    
    -- New tables needed
    CREATE TABLE decisions (
        decision_id TEXT PRIMARY KEY,  -- ULID
        plan_id TEXT NOT NULL,
        parent_decision_id TEXT,
        decision_type TEXT NOT NULL,
        question TEXT NOT NULL,
        chosen_option TEXT NOT NULL,
        alternatives_considered TEXT,  -- JSON array
        context_snapshot TEXT NOT NULL,  -- JSON
        created_at TEXT NOT NULL
    );
    
  2. Implement Decision Recording

    • Every choice during Strategize creates a Decision record
    • Capture complete context snapshot with each decision
    • Track downstream dependencies
  3. Build Correction Mechanism

    
    agents plan correct <decision_id> --mode=revert --guidance "<new decision>"
    
    - Mark decision as superseded - Recompute only affected subtree - Preserve unaffected work

Estimated Effort: 3 weeks

4) Implement Code Intelligence System (Scalability Enabler)

Problem

Current context is limited to a few hundred characters from a few files. Large codebases require intelligent context discovery.

Implementation Steps

  1. Eager Indexing on Resource Add

    
    def on_resource_added(resource: Resource):
        # Index immediately when resource added to project
        index_text_content(resource)      # Full-text search
        generate_embeddings(resource)     # Vector embeddings
        build_knowledge_graph(resource)   # RDF triples
    
  2. Three-Index Architecture

    • Text Index: Tantivy/SQLite FTS for exact matches
    • Vector Index: FAISS/Qdrant for semantic search
    • Graph Store: RDF store for relationships
  3. Tiered Context System

    • Hot: Current working set (in LLM context)
    • Warm: Recent decisions and search results
    • Cold: Historical data and patterns

Estimated Effort: 4 weeks

5) Complete Actor System with Behavioral Definitions

Problem

Actors exist but don't define behavior beyond model selection. The specification requires actors to be composable graphs with tools, memory, and context policies.

Implementation Steps

  1. Extend Actor Configuration

    
    actors:
      my_strategist:
        type: graph
        config:
          provider: anthropic
          model: claude-3-opus
          memory_policy: per_plan
          context_view: architect # High-level view
        skills:
          - local/file-ops             # provides read_file
          - local/code-intelligence    # provides search_code, analyze_dependencies
        routes:
          strategize:
            entry_point: analyze
            nodes:
              - name: analyze
                type: llm
              - name: plan
                type: llm
    
  2. Implement Tool Access Policies

    • Strategy actors: read-only tools
    • Execute actors: read/write within sandbox
    • Apply actors: commit tools
  3. Actor-Specific Context Views

    • Strategist: Architecture, dependencies, patterns
    • Executor: Implementation details, specific files
    • Reviewer: Diffs, tests, risk analysis

Estimated Effort: 2 weeks

6) Resource System, Resource Types, and Resource Registry

Problem

Resources are currently defined inline within projects. The specification requires resources to be independently registered first-class entities with a type system, DAG relationships (physical/virtual), auto-discovery, and content-identity tracking. Tools need resource bindings to declare and resolve their resource dependencies.

Implementation Steps

  1. Resource Type Registry and CLI

    • Implement 24 built-in resource types: 15 physical (git-checkout, git, git-remote, git-branch, git-tag, git-commit, git-tree, git-tree-entry, git-stash, git-submodule, fs-mount, fs-directory, fs-file, fs-symlink, fs-hardlink) and 9 virtual (file, directory, symlink, commit, branch, tag, remote, submodule, tree)
    • Implement resource type YAML parsing and validation for custom types
    • Implement agents resource type add [<span style="color: cyan;">--update</span>]/remove/list/show commands
    • Implement dynamic CLI subcommand registration (custom types create new agents resource add subcommands)
  2. Resource Registry and CLI

    • Implement agents resource add <type>/remove/list/show/tree commands
    • Implement Resource Registry persistence in database
    • Implement DAG parent/child relationships with type constraints and cycle detection
    • Implement agents resource link-child/unlink-child for manual DAG management
  3. Auto-Discovery System

    • Implement handler-driven child resource discovery (git-checkout discovers git + fs-directory worktree root; git discovers remotes, branches, tags, commits, stashes, submodules; git-commit discovers root git-tree; git-tree discovers tree entries + subtrees; fs-mount discovers root fs-directory; fs-directory discovers subdirectories, files, symlinks, hardlinks)
    • Implement resource reuse during discovery (link existing resources instead of duplicating)
    • Implement refresh mechanism for keeping discovered children up to date
  4. Physical/Virtual Resource Model

    • Implement content hashing for identity tracking
    • Implement virtual resource linking (shared virtual parents for identical physical resources)
    • Implement divergence detection (unlink when content changes)
  5. Project-Resource Linking

    • Replace agents project add-resource/remove-resource with link-resource/unlink-resource
    • Implement project-level overrides (read-only, alias)
    • Migrate any existing inline resource data to Resource Registry
  6. Resource Handlers

    • Implement GitCheckoutHandler with auto-discovery, sandbox creation, checkpoint support
    • Implement GitHandler for git repository structure discovery (remotes, branches, tags, commits, stashes, submodules)
    • Implement GitObjectHandler for git-commit, git-tree, git-tree-entry (read-only access to git objects)
    • Implement GitRefHandler for git-branch, git-tag, git-stash (read/write ref manipulation)
    • Implement GitConfigHandler for git-remote, git-submodule (read-only config access)
    • Implement FilesystemHandler with auto-discovery for fs-mount, fs-directory, fs-file, fs-symlink, fs-hardlink
    • Implement handler plugin system for custom resource types

Estimated Effort: 5 weeks

7) MCP Integration, Tool System, Skill System, and Tool-Resource Bindings

Problem

No tool or skill abstraction exists. The specification defines tools as independently registered operations managed via agents tool CLI commands, and skills as namespaced collections of tools managed via agents skill CLI commands. Tools can be sourced from MCP servers, Agent Skills folders, built-ins, and custom code. Tools also need resource bindings to declare and resolve their dependencies on resources.

Implementation Steps

  1. Tool Registry and CLI

    • Implement tool YAML parsing and validation (including resources section for resource slots)
    • Implement agents tool add [<span style="color: cyan;">--update</span>]/remove/list/show commands
    • Implement Tool Registry persistence in database
    • Implement anonymous tool support (inline definitions without registration)
  2. Skill Registry and CLI

    • Implement skill YAML parsing and validation
    • Implement agents skill add [<span style="color: cyan;">--update</span>]/remove/list/show/tools commands
    • Implement hierarchical skill composition (includes) with per-tool metadata overrides
    • Implement Skill Registry persistence in database
    • Implement named tool references (resolving from Tool Registry) and anonymous inline tools
  3. Tool-Resource Binding System

    • Implement resource slot parsing and validation in tool YAML
    • Implement three binding modes: contextual, static, parameter
    • Implement binding resolution at activation time (contextual/static) and invocation time (parameter)
    • Implement resource type compatibility validation
    • Implement built-in tool implicit resource bindings
    • Inject bound resources into ToolExecutionContext.resources
  4. MCP Tool Adapter

    
    class MCPToolAdapter:
        def wrap_mcp_tool(self, tool) -> Tool:
            # Add sandbox interception
            # Add change tracking
            # Add capability metadata
            # Add resource binding support
    
  5. Tool Capability Metadata

    
    class ToolCapability:
        read_only: bool
        write_scope: list[str]       # References resource slot names
        checkpointable: bool
        idempotent: bool
        side_effects: list[str]
    
  6. External MCP Server Support

    
    # In tool or skill YAML configuration
    mcp_servers:
      - name: github
        command: "npx @anthropic/mcp-github"
        env: {GITHUB_TOKEN: "${GITHUB_TOKEN}"}
    
  7. Agent Skills Adapter

    • Implement SKILL.md frontmatter parsing for discovery
    • Implement progressive disclosure (metadata → instructions → resources)
    • Implement sandboxed script execution
  8. Metadata Override System

    • Implement shallow-merge override logic for tool capability metadata
    • Support overrides at skill-level (tool refs), include-level (tool_overrides), and actor graph node-level
    • Built-in tool metadata is not overridable

Estimated Effort: 5 weeks

8) Implement Validation and Semantic Error Prevention

Problem

Current validation is a stub. The specification requires multi-layer semantic validation.

Implementation Steps

  1. Decision-Time Validation

    • Validate choices during Strategize
    • Check alternatives for feasibility
    • Record validation in decision metadata
  2. Execution-Time Guards

    
    # Actor references a skill containing validation tools
    skills:
      - local/semantic-validators   # validate_api_compatibility,
                                    # check_invariants, verify_test_coverage
    
  3. Project-Specific Validation

    
    agents project validation add --description "Run tests" --required my-api "pytest"
    agents project validation add --description "Lint check" --required my-api "ruff check ."
    

Estimated Effort: 2 weeks

9) Connect LangGraph to Plan Lifecycle

Problem

The reactive/LangGraph infrastructure exists but isn't connected to the main plan workflow.

Implementation Steps

  1. Create Unified Plan Graph

    
    class PlanLifecycleGraph:
        def strategize_subgraph(self) -> StateGraph
        def execute_subgraph(self) -> StateGraph
        def apply_subgraph(self) -> StateGraph
    
  2. Wire Phase Transitions

    • use command triggers strategize graph
    • execute command triggers execute graph
    • apply command triggers apply graph
  3. Remove Linear Pipeline

    • Replace tell/build/apply with graph execution
    • Maintain backward compatibility at CLI level

Estimated Effort: 1 week

Implementation Roadmap

Phase 1: Foundation (8-10 weeks)

  1. Tool-based resource modification (critical foundation)
  2. Sandbox infrastructure
  3. Decision tree system

Phase 2: Core Systems (10-12 weeks)

  1. Code intelligence system
  2. Actor system with behavioral definitions
  3. Resource system, resource types, and resource registry
  4. MCP integration, tool system, skill system, and tool-resource bindings

Phase 3: Validation and Integration (3 weeks)

  1. Validation and semantic error prevention
  2. Connect LangGraph to plan lifecycle

Phase 4: Production Hardening (4 weeks)

  1. Checkpointing and rollback
  2. Cost controls and rate limiting
  3. Security fixes (remove eval, fix async)

Total Estimated Timeline: 6-7 months

Key Success Metrics

  1. Multi-file generation: Can generate a REST API with routes/, models/, tests/
  2. Safe execution: All changes happen in sandbox, reviewed before apply
  3. Decision correction: Can correct a decision and recompute only affected work
  4. Scale to large codebases: Can work with 10K+ file projects efficiently
  5. Semantic safety: Catches breaking changes before they're applied

Migration Strategy

The implementation can proceed incrementally:

  1. Start with resource abstraction (enables everything else)
  2. Add sandboxing to existing execute phase
  3. Gradually replace text parsing with tool invocations
  4. Build decision tree alongside existing flow
  5. Enhance context as indexing comes online

This allows the system to remain functional during development while progressively adding the architectural improvements described in the specification.

CleverAgents Architecture FAQ

Q: How does CleverAgents handle persistent repository knowledge beyond ephemeral context windows?

What exists today architecturally: The specification defines a sophisticated multi-tier memory system that goes far beyond ephemeral context windows. At its core is the Decision Tree structure which provides a durable, queryable record of every choice made during planning, along with the complete context that informed those choices.

How the persistent model works in practice:

When a strategy actor analyzes a codebase during the Strategize phase, it doesn't just make decisions in isolation. Each decision creates a comprehensive Decision record that includes:


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

This means 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

The three-tier memory architecture enables scale:

  1. Hot tier: Immediate working context (what's in the current LLM context window)
  2. Warm tier: Recent decisions and their contexts from this plan tree - quickly accessible
  3. Cold tier: Historical decisions from past plans on this codebase - queryable but not in active memory

When working on a 50,000 file codebase, the system doesn't need to hold all files in memory. Instead:

  • Hot context focuses on the immediate task (e.g., 10-20 files for a specific refactoring)
  • Warm context maintains the decision chain that got us here
  • Cold context provides historical patterns ("last time we refactored auth, we also had to update these services")

Why this scales to massive codebases:

The key insight is that software development is inherently local - even in huge codebases, individual changes typically touch a bounded set of files. The Decision Tree captures these localities. When converting Firefox to Rust (your example), the system would:

  1. Make high-level architectural decisions and enforce invariants (captured as root decision nodes)
  2. Decompose into major subsystem conversions (each a subplan_parallel_spawn or subplan_spawn decision spawning child plans)
  3. Each subsystem plan makes decisions about its modules, inheriting applicable invariants
  4. Module plans make decisions about individual files

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.

Concrete example of persistence in action:


Plan: Convert Firefox Renderer to Rust
├── [invariant_enforced] "Maintain API compatibility with existing C++ callers"
├── [invariant_enforced] "All converted modules must pass existing C++ test suites"
├── [strategy_choice] Architecture approach: Start with leaf modules, work inward
│   Context: Analyzed module dependency graph, 2,847 modules total
│   Resources: module_graph.json, architecture_docs.md
│   
├── [subplan_parallel_spawn] Phase 1: Convert utility libraries (no external deps)
│   └── [subplan_spawn] Convert string_utils module
│       └── Plan: 01KH29R8WPKPBHRY7Q0NA9XW86
│           ├── [prompt_definition] "Convert string_utils module to Rust"
│           ├── [invariant_enforced] "Maintain API compatibility with existing C++ callers"
│           ├── [implementation_choice] Use Rust's String type, not custom implementation
│           │   Context: Analyzed 47 string_utils.cpp functions
│           │   Resources: string_utils.cpp, string_utils.h, 12 dependent files
│           │   Rationale: Rust's String provides same guarantees with better ergonomics
│           └── ...

Even months later, we can query: "Why did we use Rust's String type?" and get the exact context and reasoning, without reprocessing the entire codebase.

Q: How does the system compute task-specific dependency closures for large-scale operations?

What exists today architecturally: The specification defines multiple mechanisms for computing and maintaining minimal dependency closures. The execution blueprint produced during the Strategize phase doesn't just list steps - it includes a complete dependency graph with explicit scoping for each operation.

How dependency closure computation works:

During the Strategize phase, the strategy actor employs several mechanisms to compute precise dependency closures:

  1. Resource-aware analysis: The actor uses specialized skills to trace dependencies:

    
    # Pseudocode of what happens inside a strategy actor
    def compute_closure_for_refactoring(target_module):
        closure = ResourceClosure()
    
    <span style="opacity: 0.7;"># Direct file dependencies</span>
    closure.add_files(find_imports(target_module))
    closure.add_files(find_includes(target_module))
    
    <span style="opacity: 0.7;"># Symbol dependencies</span>
    <span style="color: magenta; font-weight: 600;">for</span> symbol <span style="color: magenta; font-weight: 600;">in</span> extract_exported_symbols(target_module):
        closure.add_files(find_symbol_usage(symbol, scope=<span style="color: #66cc66;">&#x27;project&#x27;</span>))
    
    <span style="opacity: 0.7;"># Test dependencies</span>
    closure.add_files(find_tests_for_module(target_module))
    
    <span style="opacity: 0.7;"># Build system dependencies</span>
    closure.add_files(find_build_references(target_module))
    
    <span style="color: magenta; font-weight: 600;">return</span> closure
    

  2. Hierarchical scoping: When spawning child plans (via subplan_spawn or subplan_parallel_spawn), each child plan receives:

    • An explicit relevant_resources list
    • A sandbox_strategy appropriate for those resources
    • Clear boundaries of what it can and cannot modify
    • The parent plan's effective invariant view (already reconciled from action, project, and global scopes)
  3. Decision-based tracking: Each subplan_spawn decision records the child plan it creates, and subplan_parallel_spawn decisions group parallel child plans:

    
    # Individual child plan spawn
    decision_type: subplan_spawn
    chosen_option: "Refactor authentication module"
    downstream_plan_ids: ["plan-auth-refactor-123"]
    artifacts_produced: 
      - auth_module_files: ["auth.rs", "auth_test.rs", "auth_types.rs"]
      - api_updates: ["api/v2/login.rs", "api/v2/logout.rs"]
    

    # Parallel group of child plans decision_type: subplan_parallel_spawn chosen_option: "Convert utility libraries in parallel" # Contains subplan_spawn children, each with their own downstream_plan_ids

Concrete example - Converting a subsystem to Rust:

Let's trace how the system handles "Convert Firefox's Network Stack to Rust":


STRATEGIZE PHASE:
1. Analyze network stack structure
   - Identifies 847 C++ files in netwerk/ directory
   - Traces public API surface (237 exported functions)
   - Maps internal dependencies (1,432 internal calls)
  1. Compute minimal closure for Phase 1 (DNS resolver):

    • Core files: dns_resolver.cpp, dns_cache.cpp, dns_config.cpp (3 files)
    • Direct dependencies: 12 files in netwerk/base/
    • Test files: 8 test files specific to DNS
    • Build files: 2 moz.build files
    • Total closure: 25 files (not 847!)
  2. Generate execution blueprint with child plans:

    • [subplan_parallel_spawn] DNS module conversions:
      • convert-dns-types: Closure of 5 files (type definitions)
      • convert-dns-cache: Closure of 8 files (cache + tests)
      • convert-dns-resolver: Closure of 12 files (resolver + integration)

Why this is tractable even for massive codebases:

The system leverages several key insights about real software:

  1. Modular boundaries exist: Even in legacy codebases, there are natural boundaries
  2. Changes are incremental: We don't convert 50,000 files atomically
  3. Dependencies are sparse: Most modules depend on a small fraction of the codebase
  4. Interfaces are narrow: Public APIs are much smaller than implementations

The Firefox example would decompose into ~1,000 bounded child plans (grouped via subplan_parallel_spawn decisions where independent), each touching 10-100 files. The parent plan tracks the overall architecture and enforces invariants, while each child plan maintains its focused closure.

How we prevent closure explosion:

  • Lazy expansion: Dependencies are traced only as deep as needed for correctness
  • Interface-based boundaries: When possible, work against stable interfaces
  • Incremental validation: Each child plan validates its changes don't break dependents
  • Hierarchical merge strategies: Parent plans resolve conflicts between child plan changes

Q: What mechanisms enforce global consistency during parallel execution across many files?

What exists today architecturally: The sandbox model combined with hierarchical plan execution provides strong guarantees about consistency during parallel execution. This isn't just process isolation - it's semantic isolation with intelligent merge strategies.

How the coordination mechanism prevents compound errors:

  1. Complete isolation during execution: 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
  2. Resource-specific sandbox strategies provide natural coordination:

    
    Git repositories:
      - Strategy: git worktrees
      - Coordination: Git's three-way merge algorithm
      - Conflict detection: Built into Git
      - Rollback: git reset/checkout
    

    Databases:

    • Strategy: Transaction isolation
    • Coordination: MVCC (multi-version concurrency control)
    • Conflict detection: Serialization failures
    • Rollback: Transaction abort

    Cloud Infrastructure:

    • Strategy: Terraform workspaces
    • Coordination: State locking
    • Conflict detection: Resource conflicts in plan
    • Rollback: Previous state restoration
  3. 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)
    
    <span style="opacity: 0.7;"># Apply resource-specific merge strategies</span>
     <span style="color: magenta; font-weight: 600;">for</span> resource_type, changes <span style="color: magenta; font-weight: 600;">in</span> by_resource:
         <span style="color: magenta; font-weight: 600;">if</span> resource_type == <span style="color: #66cc66;">&#x27;git-checkout&#x27;</span>:
             merge_git_changes(changes)  <span style="opacity: 0.7;"># Three-way merge</span>
         <span style="color: magenta; font-weight: 600;">elif</span> resource_type == <span style="color: #66cc66;">&#x27;fs-mount&#x27;</span>:
             merge_fs_changes(changes)   <span style="opacity: 0.7;"># Copy-on-write reconciliation</span>
         <span style="color: magenta; font-weight: 600;">elif</span> resource_type.startswith(<span style="color: #66cc66;">&#x27;database&#x27;</span>):
             merge_db_changes(changes)   <span style="opacity: 0.7;"># Sequential application</span>
    
    <span style="opacity: 0.7;"># Validate merged state</span>
    run_integration_tests()
    

Concrete example - Preventing cascading failures:

Consider refactoring a shared authentication library used by 15 services:


PARALLEL EXECUTION WITHOUT COORDINATION (what we prevent):
- Service A refactors to async auth → breaks Service B
- Service B compensates with workaround → breaks Service C  
- Service C changes error handling → breaks Services D, E, F
- Cascade of failures!

CLEVERAGENTS COORDINATED EXECUTION: Parent Plan: Refactor auth library ├── [invariant_enforced] "Auth library public API must remain backward compatible during transition" ├── [subplan_spawn] Plan 1: Update auth library interface │ Sandbox: Only auth library files │ Output: New interface definition │
├── Barrier: Wait for Plan 1 completion │
├── [subplan_parallel_spawn] Plans 2-16: Update each service (in parallel) │ Each sandbox: Only that service's files │ Each uses: New interface from Plan 1 │ No inter-service dependencies during execution │
└── Merge Phase: - Collect all service updates - Apply to main branch in order - Run integration tests - If conflicts: Parent plan resolves using semantic understanding

Advanced coordination patterns:

  1. Optimistic concurrency with semantic conflict resolution:

    
    Two child plans both modify api/user.rs:
    - Plan A: Adds async fn get_user_profile()
    - Plan B: Adds fn validate_user_permissions()
    

    Merge strategy:

    • Git merge succeeds (different functions)
    • Semantic validation ensures both functions work together
    • Parent plan adds integration glue if needed
  2. Checkpoint-based coordination:

    
    Execution timeline:
    T1: Plan A creates checkpoint before major refactor
    T2: Plan B creates checkpoint before API changes
    T3: Plan A encounters error, rolls back to T1
    T4: Plan B completes successfully
    T5: Plan A retries with knowledge of B's success
    
  3. Resource locking for critical sections:

    
    When modifying shared schema files:
    - Acquire exclusive lock on schema resources
    - Make changes atomically
    - Release lock with new version
    - Other plans rebase on new schema
    

Q: How does the system proactively prevent semantic errors before they propagate?

What exists today architecturally: The specification defines multiple layers of proactive error prevention that go far beyond traditional testing. This is a comprehensive defense-in-depth approach that catches semantic errors before they can propagate.

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:


actors:
  code_executor:
    type: graph
    skills:
      - local/semantic-validators    # Contains 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 (independently registered via agents tool add) performs semantic validation — not just syntax checking. It extracts API signatures, finds breaking changes, checks affected consumers, and either auto-migrates or raises a SemanticError for manual review.

Layer 3: Invariant enforcement through the decision tree:

Invariants are attached at four scopes (global, project, action, plan) and managed via the unified agents invariant command or --invariant flags on creation commands. When a plan enters Strategize, the Invariant Reconciliation Actor (set via --invariant-actor on actions/plans/projects, or globally via agents config set actor.default.invariant) computes the effective invariant view by applying precedence rules (plan > project > global) to resolve conflicts. Each effective invariant is recorded as an invariant_enforced decision, making them visible, correctable, and auditable:


# The system collects, reconciles, and enforces semantic invariants
class InvariantEnforcer:
    def compute_effective_invariants(self, plan):
        """Compute the effective invariant view using the Invariant Reconciliation Actor."""
        raw = self.collect_all_invariants(plan)
        reconciler = (
            self.get_plan_invariant_actor(plan)
            or self.get_project_invariant_actor(plan)
            or self.get_global_invariant_actor()
        )
        # Apply precedence: plan > project > global
        return reconciler.reconcile(raw, precedence=['plan', 'project', 'global'])
<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">collect_all_invariants</span>(self, plan):
    <span style="color: #66cc66;">&quot;&quot;&quot;Collect invariants from all scopes accessible to this plan.&quot;&quot;&quot;</span>
    invariants = []
    invariants.extend(self.get_global_invariants())
    <span style="color: magenta; font-weight: 600;">for</span> project <span style="color: magenta; font-weight: 600;">in</span> plan.projects:
        invariants.extend(self.get_project_invariants(project))
    invariants.extend(self.get_action_invariants(plan.action))
    invariants.extend(self.get_plan_invariants(plan))
    <span style="color: magenta; font-weight: 600;">return</span> invariants

<span style="opacity: 0.7;"># Example invariants at different scopes:</span>
<span style="opacity: 0.7;"># Global:  &quot;Payment processing must be idempotent&quot;</span>
<span style="opacity: 0.7;"># Project: &quot;Database transactions must complete within 5 seconds&quot;</span>
<span style="opacity: 0.7;"># Action:  &quot;Test files must not import production secrets&quot;</span>
<span style="opacity: 0.7;"># Plan:    &quot;All API calls over TCP must be mocked&quot;</span>

<span style="color: magenta; font-weight: 600;">def</span> <span style="color: cyan; font-weight: 600;">check_invariant_preservation</span>(self, changes, enforced_invariants):
    <span style="color: magenta; font-weight: 600;">for</span> invariant <span style="color: magenta; font-weight: 600;">in</span> enforced_invariants:
        <span style="color: magenta; font-weight: 600;">if</span> <span style="color: magenta; font-weight: 600;">not</span> self.verify_invariant(invariant, changes):
            <span style="color: magenta; font-weight: 600;">return</span> InvariantViolation(invariant, changes)
    <span style="color: magenta; font-weight: 600;">return</span> Success()

Layer 4: Predictive error prevention through pattern matching:

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"

Concrete example - Preventing a subtle distributed systems bug:

Scenario: Refactoring a service to use event sourcing:


PROACTIVE CONTAINMENT IN ACTION:
  1. Strategy Phase Semantic Analysis:

    • Decision: "Convert order service to event sourcing"
    • Semantic check: "Event sourcing requires eventual consistency"
    • Identifies: 3 services assume immediate consistency
    • Adds decision: "Update dependent services for eventual consistency"
  2. Execution Phase Invariant Checking:

    • Detects: PaymentService.chargeCard() called after OrderCreated event
    • Semantic issue: Payment before order confirmation violates business rules
    • Automatic fix: Insert OrderConfirmed event requirement
  3. Validation Node Catches Edge Case:

    • Discovers: Audit service expects synchronous order numbers
    • Impact: Async events break compliance reporting
    • Resolution: Add audit event buffer with guaranteed ordering
  4. Pre-Apply Semantic Verification:

    • Simulates production event flow
    • Detects: Under high load, events can arrive out of order
    • Adds: Event ordering guarantees via vector clocks

Why this prevents issues that traditional testing misses:

Traditional tests check "does the code work?" Our semantic containment asks:

  • Does it preserve business invariants?
  • Does it maintain architectural patterns?
  • Does it respect distributed systems principles?
  • Does it handle the edge cases we've seen before?

Integration with Definition of Done (DoD):

Each plan's DoD includes semantic requirements:


definition_of_done:
  must:
    - "All API changes maintain backward compatibility"
    - "No increase in p99 latency"
    - "Audit trail remains complete"
  should:
    - "Improve code coverage by 10%"
    - "Reduce cyclomatic complexity"
  may:
    - "Optimize for memory usage"

The validation nodes enforce these semantics, not just test passage.

Q: How does the system balance human supervision with autonomous operation?

What exists today architecturally: The specification defines a comprehensive automation profile system with 10 confidence thresholds (0.01.0) and 3 boolean safety flags controlling every aspect of human-vs-automated operation. This isn't a binary human/AI split — it's a continuously adjustable matrix where each threshold specifies the minimum confidence level for automatic operation, tunable per task, per project, or per organization.

How the automation profiles work in practice:


manual Profile (all thresholds = 1.0):
  - Every phase transition pauses for human action
  - Every decision point pauses for human input
  - User sees: Context, alternatives, recommendation, confidence score
  - User provides: Explicit choice or custom guidance
  - Use case: New users, critical production changes, first-time codebase exploration

review Profile (phase thresholds = 0.0, decision thresholds = 1.0):

  • Phases run automatically (Strategize, Execute proceed without pausing)
  • Every decision within those phases pauses for human input
  • Apply is manual; transient retries and child plans are automatic
  • Use case: Teams that want to stay in the decision loop without triggering phases

supervised Profile (strategize thresholds = 0.0, execute/apply = 1.0):

  • Strategize runs automatically with autonomous decisions
  • System pauses before Execute for human review of strategy
  • Transient failures retried automatically
  • Use case: Projects where you trust planning but want to review before execution

cautious Profile (intermediate thresholds = 0.6-0.8):

  • System proceeds automatically only when Semantic Escalation reports high confidence
  • Escalates to human when uncertain (confidence below threshold)
  • Higher bars (0.8) for risky operations, lower bars (0.6) for safer ones
  • Use case: Gradual automation adoption, mixed-complexity projects

trusted Profile (most thresholds = 0.0, apply = 1.0):

  • Strategize and Execute run automatically with autonomous decisions
  • Validation failures self-fixed within strategy bounds
  • Child plans spawned automatically
  • System pauses before Apply for human diff review
  • Use case: Normal feature development, refactoring

autonomous Profile (all thresholds = 0.0 except apply = 1.0):

  • Everything automatic except Apply
  • Can revise its own strategy if execution hits a wall
  • Restores from checkpoints on failure
  • Use case: Well-understood projects, batch operations

ci Profile (all thresholds = 0.0, sandbox + checkpoints required):

  • Complete end-to-end automation including Apply
  • Sandbox and checkpoints remain mandatory for safety
  • Unsafe tools blocked
  • Use case: CI/CD pipelines, headless batch jobs, scheduled automation

full-auto Profile (all thresholds = 0.0):

  • Complete end-to-end automation including Apply
  • No sandbox or checkpoint requirements
  • Unsafe tools allowed
  • Use case: Routine updates, environments with external safety mechanisms

Custom profiles with intermediate thresholds (e.g., 0.3, 0.5, 0.7):

  • Fine-grained control: auto-execute with confidence >= 0.5 but escalate below
  • Different thresholds per flag: low bar for retries, high bar for strategy revision
  • Enables "trust but verify" patterns without binary on/off
  • Use case: Teams building confidence gradually, mixed-risk projects

The decision correction mechanism enables progressive automation:

The agents plan correct command is crucial for building trust:


# User observes AI made suboptimal choice
agents plan tree <plan_id>
# Sees: [Decision] "Use REST API for service communication"

# User knows gRPC would be better for this use case agents plan correct <decision_id> --mode=revert </span> --guidance "Use gRPC instead of REST. This service requires streaming updates and binary protocol efficiency. Set up protocol buffer definitions and generate client/server stubs."

# System: # 1. Marks original decision as superseded # 2. Creates new decision with user guidance # 3. Recomputes ONLY affected downstream decisions # 4. Preserves all unrelated work

Progressive trust building through automation profiles:

New users typically follow this progression:

  1. Start with manual to understand system behavior
  2. Move to supervised as confidence in the planning phase builds, or customize a profile with intermediate thresholds (e.g., 0.5) for gradual autonomy
  3. Adopt trusted for routine development tasks
  4. Enable auto for well-understood projects
  5. Use full-auto for low-risk batch operations

Real autonomy through semantic understanding:

True autonomy isn't about removing humans - it's about the system understanding when it needs help:


class AutonomyController:
    def assess_decision_confidence(self, decision, context, profile):
        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)  <span style="opacity: 0.7;"># Returns 0.01.0</span>
    threshold = profile.get_threshold(decision.flag)  <span style="opacity: 0.7;"># From profile</span>
    
    <span style="color: magenta; font-weight: 600;">if</span> confidence &gt;= threshold:
        <span style="color: magenta; font-weight: 600;">return</span> ProceedAutonomously(decision, confidence)
    <span style="color: magenta; font-weight: 600;">else</span>:
        <span style="opacity: 0.7;"># Confidence below profile threshold — escalate to human</span>
        <span style="color: magenta; font-weight: 600;">return</span> RequestHumanGuidance(decision, confidence, threshold, factors)

Concrete example - Autonomous handling of a complex refactoring:


Scenario: "Modernize legacy e-commerce system"

INITIAL PLAN (Full Automation Mode):

  1. System analyzes 50,000 line codebase
  2. Identifies modernization opportunities
  3. Creates plan with 47 child plans

AUTONOMOUS EXECUTION WITH SMART ESCALATION:

[subplan_parallel_spawn] Plans 1-15: Update utility functions (executes autonomously)

  • Confidence: 0.95 (straightforward transformations)
  • Result: Success

[subplan_spawn] Plan 16: Refactor payment processing

  • Confidence: 0.4 (critical business logic)
  • [invariant_enforced] "Preserve exact penny rounding behavior"
  • Action: ESCALATES to human
  • Human provides: "Preserve exact penny rounding behavior"
  • Continues autonomously with constraint

[subplan_parallel_spawn] Plans 17-30: UI component updates (executes autonomously)

  • Confidence: 0.9 (isolated changes)
  • Result: Success

[subplan_spawn] Plan 31: Database schema migration

  • Detects: Would require 6-hour downtime
  • Action: ESCALATES to human
  • Human provides: "Use online migration with feature flags"
  • Re-plans with zero-downtime approach

[subplan_parallel_spawn] Plans 32-47: Complete autonomously

The path to greater autonomy:

The system becomes more autonomous through:

  1. Learning from corrections:

    • Every correction teaches the system about user preferences
    • Patterns emerge: "This team always prefers gRPC for microservices"
    • Future decisions incorporate these learnings
  2. Building project-specific context:

    • Each successful plan adds to project knowledge
    • System learns codebase patterns, team conventions, business rules
    • Confidence increases with familiarity
  3. Hierarchical delegation:

    • Proven child plan patterns become fully autonomous
    • Human focuses on high-level decisions
    • System handles implementation details
  4. Semantic safety nets:

    • Comprehensive invariant checking reduces risk
    • Rollback capabilities provide recovery path
    • Humans can trust system won't cause catastrophic failures

Q: What's actually implemented today versus planned for the future?

Concrete implementations in the architecture:

  1. Decision Tree with Complete Context Capture

    • Full schema defined
    • Storage model specified
    • Correction mechanism detailed
    • Query patterns established
  2. Hierarchical Plan System

    • Spawning mechanism defined (sequential subplan_spawn and parallel subplan_parallel_spawn)
    • Execution semantics specified (child plans are full Plans with their own decision trees)
    • Invariant inheritance from parent plans, projects, and global scope
    • Merge strategies documented
    • Failure handling described
  3. Resource-Aware Sandbox Isolation

    • Multiple strategies defined (git worktree, filesystem overlay, transactions)
    • Lazy sandboxing for efficiency
    • Resource-specific merge algorithms
    • Cleanup behavior specified
  4. Multi-Layer Error Prevention

    • Decision validation during planning
    • Semantic validation nodes
    • Invariant enforcement
    • Definition of Done checking
  5. Graduated Automation Controls

    • Three levels clearly defined
    • Decision correction without full re-execution
    • Confidence-based escalation
    • Progressive trust building

Near-term implementations (architecture complete, engineering straightforward):

  1. Memory Tier Management

    • Hot/warm/cold distinction clear
    • Context loading patterns defined
    • Just needs LRU cache and storage backend
  2. Cross-Plan Learning

    • Decision history provides training data
    • Pattern extraction is standard ML
    • Confidence scoring is well-understood
  3. Cost/Risk Estimation

    • Dedicated estimation actor role defined
    • Historical data provides baselines
    • Standard prediction problem
  4. Extended Validation Patterns

    • Pluggable validation architecture
    • Project-specific rules as configuration
    • Industry patterns can be packaged

Research territory (requires innovation but architecture supports):

  1. Optimal Context Selection for 100K+ file codebases

    • Current: Heuristic-based selection
    • Research: ML-driven relevance ranking
    • Architecture supports: Any selection algorithm can plug in
  2. Automated Invariant Discovery

    • Current: User-defined invariants
    • Research: Mining invariants from code patterns
    • Architecture supports: Invariants are just validation rules
  3. Cross-Project Knowledge Transfer

    • Current: Project-specific learning
    • Research: Generalized pattern recognition
    • Architecture supports: Cold tier can span projects
  4. Fully Autonomous Recovery Strategies

    • Current: Rollback and retry with guidance
    • Research: Automatic error understanding and fixing
    • Architecture supports: Recovery is just another plan type

Why we can confidently handle Firefox-scale projects:

The architecture doesn't require magical AI breakthroughs. It requires:

  • Hierarchical decomposition: ✓ Fully specified
  • Bounded context operations: ✓ Dependency closure computation defined
  • Parallel execution with isolation: ✓ Sandbox model complete
  • Semantic validation: ✓ Multi-layer approach specified
  • Progressive automation: ✓ Automation profiles and correction defined

The difference between handling a 1,000 file project and a 100,000 file project is:

  • More child plans (hierarchical decomposition handles this)
  • Larger cold storage (standard database scaling)
  • Better context selection (improves with use but works with heuristics)
  • More validation patterns (accumulate over time)

This isn't speculative architecture astronautics - it's applying proven distributed systems principles to AI agent coordination. The innovation is in the integration, not in requiring fundamental breakthroughs.