Files
cleveragents-core/docs/specification/configuration.md

521 KiB
Raw Permalink Blame History

Configuration

!!! adr "Architecture Decision" The configuration system design principles, YAML-first approach, and config file conventions are defined in ADR-024: Configuration System.

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

!!! adr "Architecture Decision" Global configuration keys, hierarchical key structure, and config precedence are defined in ADR-024: Configuration System.

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.

!!! note "Configuration Precedence (highest to lowest)" 1. ==CLI flag== (--format, --data-dir, etc.) 2. ==Environment variable== (CLEVERAGENTS_FORMAT, etc.) 3. ==Project-scoped config== (per-project overrides) 4. ==Global config file== (~/.cleveragents/config.toml) 5. ==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 FATAL CLEVERAGENTS_LOG_LEVEL Base logging verbosity level. Accepted values (from least to most verbose): FATAL, ERROR, WARN, INFO, DEBUG, TRACE. The default FATAL means only fatal errors (where the application exits) produce log output; all other log messages are suppressed. The -v CLI flag can be repeated (-v through -vvvvv) to raise the effective level for a single invocation: -v = ERROR, -vv = WARN, -vvv = INFO, -vvvv = DEBUG, -vvvvv = TRACE. The effective level applies to both log file output and terminal log output (subject to core.log.terminal and core.log.file-enabled settings).
core.log.dir string <core.data-dir>/logs CLEVERAGENTS_LOG_DIR Directory where log files are written. Can be set to an alternative path to redirect log storage.
core.log.file-enabled boolean true CLEVERAGENTS_LOG_FILE_ENABLED Whether log output is written to log files. When true, log messages at or above the effective verbosity level are written to the log directory. When false, log file output is suppressed entirely (useful when log output should only go to the terminal).
core.log.terminal string auto CLEVERAGENTS_LOG_TERMINAL Controls whether log output raised by -v is also displayed on the terminal. Accepted values: auto (show on terminal when -v is used, suppress otherwise), always (always show log output on terminal at the effective level), never (suppress terminal log output entirely — log only to file). This keeps log output separate from normal program output, which goes to stdout.
core.log.terminal-stream string stderr CLEVERAGENTS_LOG_TERMINAL_STREAM The stream used for terminal log output. Accepted values: stderr (default, keeps logs separate from normal stdout output), stdout (merge with normal output), or a file path / device path (e.g., /dev/null, /dev/pts/1, or a file path) to redirect terminal log output to an alternative destination.
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).
audit.* — Audit Logging
Key Type Default Env Variable Description
audit.retention-days integer 0 CLEVERAGENTS_AUDIT_RETENTION_DAYS Days to retain audit log entries before pruning. 0 means keep indefinitely (default for compliance).
audit.async boolean true CLEVERAGENTS_AUDIT_ASYNC When true (default), audit entries are written asynchronously via a write-behind queue on a background daemon thread, so that AuditService.record() does not block the calling domain operation. Set to false to restore synchronous behaviour (useful for debugging or when strict ordering is required).
audit.queue-maxsize integer 10000 CLEVERAGENTS_AUDIT_QUEUE_MAXSIZE Maximum number of pending audit entries in the write-behind queue. When the queue is full, record() blocks until space is available, providing back-pressure. Increase for very high-throughput workloads. Only effective when audit.async is true.
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.
context.strategies.enabled list ["simple-keyword", "semantic-embedding", "breadth-depth-navigator"] CLEVERAGENTS_CTX_STRATEGIES Ordered list of ACMS context strategies enabled globally. Strategies are run in parallel and their results fused by the Context Assembly Pipeline.
context.strategies.custom.* object (none) Registration block for custom context strategies. Each key under custom names a strategy; the value specifies its module, class, max_quality, and optional config.
context.strategies.arce.model string (uses actor's model) CLEVERAGENTS_CTX_ARCE_MODEL Model used by the ARCE (Autonomous Reasoning Context Extraction) strategy for its internal reasoning loop.
context.strategies.arce.max-rounds integer 3 CLEVERAGENTS_CTX_ARCE_ROUNDS Maximum number of search-refine rounds the ARCE strategy performs before returning results.
context.strategies.breadth-depth-navigator.max-hops integer 4 CLEVERAGENTS_CTX_BDN_HOPS Maximum graph traversal depth for the breadth-depth-navigator strategy.
context.budget.response-reserve-tokens integer 4096 CLEVERAGENTS_CTX_RESPONSE_RESERVE Number of tokens reserved from the model's context window for the response. Subtracted before computing the context budget.
context.budget.tool-definition-estimate integer (auto-computed) CLEVERAGENTS_CTX_TOOL_ESTIMATE Estimated tokens consumed by tool definitions in the prompt. When unset, computed from the active skill set.
context.budget.skeleton-ratio float 0.15 CLEVERAGENTS_CTX_SKELETON_RATIO Default fraction of the context budget reserved for inherited plan skeleton context.
context.budget.refresh-threshold float 0.30 CLEVERAGENTS_CTX_REFRESH_THRESHOLD Fractional change in available budget that triggers automatic context re-assembly. E.g., 0.30 means re-assemble when budget changes by more than 30%.
context.budget.min-useful-budget integer 500 CLEVERAGENTS_CTX_MIN_BUDGET Minimum useful context budget in tokens. If the computed budget falls below this, context assembly is skipped and a warning is emitted.
context.tiers.warm.retention-hours integer 24 CLEVERAGENTS_CTX_WARM_HOURS Number of hours warm-tier context entries are retained before demotion to cold tier.
context.tiers.cold.retention-days integer 90 CLEVERAGENTS_CTX_COLD_DAYS Number of days cold-tier context entries are retained before archival/expiry.
context.uko.default-analyzers list ["python", "typescript", "rust", "java", "markdown", "json-schema"] CLEVERAGENTS_CTX_UKO_ANALYZERS List of UKO analyzers enabled by default for resource indexing. Each analyzer extracts language-specific UKO nodes from resources.
context.uko.analyzers.custom.* object (none) Registration block for custom UKO analyzers. Each key under custom names an analyzer; the value specifies its module, class, languages, and optional config.
context.pipeline.strategy-selector string "builtin:ConfidenceWeightedSelector" CLEVERAGENTS_CTX_PIPELINE_SELECTOR Implementation class for the StrategySelector pipeline component. Decides which strategies to invoke and with what confidence. Value is "module:ClassName".
context.pipeline.budget-allocator string "builtin:ProportionalBudgetAllocator" CLEVERAGENTS_CTX_PIPELINE_ALLOCATOR Implementation class for the BudgetAllocator pipeline component. Distributes token budget across selected strategies.
context.pipeline.strategy-executor string "builtin:ParallelStrategyExecutor" CLEVERAGENTS_CTX_PIPELINE_EXECUTOR Implementation class for the StrategyExecutor pipeline component. Controls parallelism, timeouts, and circuit breaking for strategy invocation.
context.pipeline.fragment-deduplicator string "builtin:ContentHashDeduplicator" CLEVERAGENTS_CTX_PIPELINE_DEDUP Implementation class for the FragmentDeduplicator pipeline component. Removes duplicate fragments via content-hash, UKO-identity, or semantic similarity.
context.pipeline.detail-depth-resolver string "builtin:MaxDepthResolver" CLEVERAGENTS_CTX_PIPELINE_DEPTH Implementation class for the DetailDepthResolver pipeline component. Resolves conflicts when the same UKO node appears at different detail depths.
context.pipeline.fragment-scorer string "builtin:WeightedCompositeScorer" CLEVERAGENTS_CTX_PIPELINE_SCORER Implementation class for the FragmentScorer pipeline component. Computes composite relevance scores for ranking during budget packing.
context.pipeline.budget-packer string "builtin:GreedyKnapsackPacker" CLEVERAGENTS_CTX_PIPELINE_PACKER Implementation class for the BudgetPacker pipeline component. Fits scored fragments into the token budget with depth fallback support.
context.pipeline.fragment-orderer string "builtin:RelevanceCoherenceOrderer" CLEVERAGENTS_CTX_PIPELINE_ORDERER Implementation class for the FragmentOrderer pipeline component. Orders packed fragments for optimal coherence in the context window.
context.pipeline.preamble-generator string "builtin:ProvenancePreambleGenerator" CLEVERAGENTS_CTX_PIPELINE_PREAMBLE Implementation class for the PreambleGenerator pipeline component. Generates provenance summaries prepended to assembled context.
context.pipeline.skeleton-compressor string "builtin:DepthReductionCompressor" CLEVERAGENTS_CTX_PIPELINE_COMPRESSOR Implementation class for the SkeletonCompressor pipeline component. Compresses parent context into skeleton for child plan inheritance.
context.pipeline.strategy-executor.timeout-seconds integer 30 CLEVERAGENTS_CTX_PIPELINE_EXEC_TIMEOUT Timeout in seconds for each strategy execution within the StrategyExecutor.
context.pipeline.strategy-executor.max-workers integer 4 CLEVERAGENTS_CTX_PIPELINE_EXEC_WORKERS Maximum number of parallel workers for concurrent strategy execution.
context.pipeline.strategy-executor.circuit-breaker-threshold integer 3 CLEVERAGENTS_CTX_PIPELINE_EXEC_CB Number of consecutive failures before the circuit breaker opens for a strategy.
context.pipeline.fragment-scorer.relevance-weight float 0.4 CLEVERAGENTS_CTX_PIPELINE_SCORER_REL Weight of relevance score in composite fragment scoring.
context.pipeline.fragment-scorer.hierarchy-weight float 0.3 CLEVERAGENTS_CTX_PIPELINE_SCORER_HIER Weight of hierarchy position in composite fragment scoring.
context.pipeline.fragment-scorer.quality-weight float 0.2 CLEVERAGENTS_CTX_PIPELINE_SCORER_QUAL Weight of strategy quality in composite fragment scoring.
context.pipeline.fragment-scorer.recency-weight float 0.1 CLEVERAGENTS_CTX_PIPELINE_SCORER_REC Weight of recency bonus in composite fragment scoring.
context.pipeline.budget-packer.depth-fallback-steps list [9, 4, 2, 0] CLEVERAGENTS_CTX_PIPELINE_PACKER_STEPS Ordered list of detail depths to try during depth fallback when a fragment doesn't fit at its current depth.
context.pipeline.budget-packer.min-fragment-tokens integer 10 CLEVERAGENTS_CTX_PIPELINE_PACKER_MIN Minimum token size for a fragment to be included. Fragments below this threshold are excluded.
context.pipeline.preamble-generator.enabled boolean true CLEVERAGENTS_CTX_PIPELINE_PREAMBLE_ON Whether the PreambleGenerator produces a preamble. When false, no preamble is prepended to assembled context.
context.pipeline.preamble-generator.max-tokens integer 200 CLEVERAGENTS_CTX_PIPELINE_PREAMBLE_TOK Maximum tokens allocated to the context preamble.
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.google.gemini-api-key string (not set) GEMINI_API_KEY API key for Google Gemini models. Required when using Gemini-based actors. The standard GEMINI_API_KEY environment variable is checked for compatibility with Google's tooling.
provider.huggingface.token string (not set) HF_TOKEN Access token for Hugging Face Inference API. Required when using Hugging Face-hosted models. The standard HF_TOKEN environment variable is checked for compatibility with Hugging Face tooling.
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 = "FATAL" terminal = "auto" terminal-stream = "stderr" file-enabled = true 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-as-complete-definition pattern: For entity registration commands (actor add, skill add, tool add, validation add, resource type add, action create, automation-profile add), the YAML configuration file is the sole source of truth — the --config file fully defines the entity. For runtime commands that reference existing entities (e.g., plan use), CLI options may override entity defaults to customize behavior per-invocation. Exception: validation add accepts --required/--informational flags that override the YAML mode field, as described in the Validation Mode section under Core Concepts.

  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

!!! adr "Architecture Decision" The actor configuration schema and actor registration model are defined in ADR-010: Actor and Agent Architecture.

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>. For behavioral documentation including Jinja2 template preprocessing, actor composition, multi-actor workflows, and field-level descriptions, see the Actor section. For the Jinja2 preprocessing pipeline specifically, see Jinja2 Template Preprocessing and ADR-032.

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."
    },
    "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
              }
            },
            "response_format": {
              "type": "object",
              "description": "JSON schema for structured output from the LLM. When set, the model is constrained to produce output matching this schema.",
              "additionalProperties": true
            }
          },
          "additionalProperties": false
        },
        "skills": {
          "type": "array",
          "description": "List of skill names this actor can use. Each entry is a namespaced skill name (e.g., 'local/file-ops'). Skills provide tool capabilities to the actor.",
          "items": { "type": "string", "pattern": "^[a-z0-9_-]+/[a-z0-9_-]+$" }
        },
        "lsp": {
          "description": "LSP server bindings for language intelligence. Can be a list of server names (explicit), an object with languages (language-based), or an object with auto: true (resource-auto).",
          "oneOf": [
            {
              "type": "array",
              "items": { "type": "string", "pattern": "^[a-z0-9_-]+/[a-z0-9_-]+$" },
              "description": "Explicit binding: list of namespaced LSP server names."
            },
            {
              "type": "object",
              "properties": {
                "languages": {
                  "type": "array",
                  "items": { "type": "string" },
                  "description": "Language-based binding: resolve LSP servers for these languages from the registry."
                },
                "auto": {
                  "type": "boolean",
                  "description": "Resource-auto binding: discover languages from project resources and resolve servers automatically."
                }
              },
              "additionalProperties": false
            }
          ]
        },
        "lsp_capabilities": {
          "description": "Controls which LSP capabilities are exposed as tools. When 'all' or omitted, all capabilities are available.",
          "oneOf": [
            {
              "type": "string",
              "enum": ["all"]
            },
            {
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["diagnostics", "hover", "completions", "definitions", "references", "rename", "code_actions", "formatting", "signature_help", "document_symbols", "workspace_symbols"]
              }
            }
          ]
        },
        "lsp_context_enrichment": {
          "type": "object",
          "description": "Controls automatic LSP context enrichment (diagnostic and type info injection into ACMS context).",
          "properties": {
            "diagnostics": { "type": "boolean", "default": true, "description": "Auto-inject LSP diagnostics into context." },
            "type_annotations": { "type": "boolean", "default": false, "description": "Auto-inject type information into context." },
            "max_diagnostics_per_file": { "type": "integer", "default": 50, "minimum": 1, "description": "Maximum diagnostics per file to avoid context bloat." }
          },
          "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.
                                    # 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"]}

  <span style="color: cyan; font-weight: 600;">response_format</span>: {}<span style="opacity: 0.7;">            # JSON schema for structured LLM output (optional, LLM only)</span>

# ── Skills (both LLM and tool actors) ──────────────────────── skills: # Skill references providing tool capabilities (optional) - <namespace>/<skill-name> # e.g., local/file-ops, local/git-ops

# ── LSP Binding (language intelligence for actor nodes) ───── # Three binding modes — pick one:

# Mode 1: Explicit — list specific registered LSP servers lsp: # LSP server binding (optional) - <namespace>/<server-name> # e.g., local/pyright, local/typescript-language-server

# Mode 2: Language-based — runtime resolves servers from registry # lsp: # languages: [python, typescript]

# Mode 3: Auto-discovery — detect languages from project resources # lsp: # auto: true

<span style="color: cyan; font-weight: 600;">lsp_capabilities</span>: <span style="color: magenta;">all</span><span style="opacity: 0.7;">              # Which LSP capabilities to expose (optional, default: all)</span>

# "all" | list of: diagnostics, hover, completions, references, # definitions, symbols, formatting, code_actions, rename

<span style="color: cyan; font-weight: 600;">lsp_context_enrichment</span>:            # ACMS context enrichment from LSP (optional)
  <span style="color: cyan; font-weight: 600;">diagnostics</span>: <span style="color: magenta;">true</span><span style="opacity: 0.7;">               # Auto-inject diagnostics into code context windows</span>
  <span style="color: cyan; font-weight: 600;">type_annotations</span>: <span style="color: magenta;">true</span><span style="opacity: 0.7;">          # Auto-inject inferred types into code context windows</span>
  <span style="color: cyan; font-weight: 600;">max_diagnostics_per_file</span>: <span style="color: magenta;">50</span><span style="opacity: 0.7;">   # Limit diagnostics per file (default: 50)</span>

# ─── 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.
config.response_format object No JSON schema for structured output from the LLM. Constrains model output to match the schema.
skills list No List of namespaced skill names (e.g., local/file-ops) providing tool capabilities to the actor.
lsp list or object No LSP server binding. List of namespaced server names (explicit mode), object with languages list (language-based mode), or object with auto: true (auto-discovery mode).
lsp_capabilities string or list No Which LSP capabilities to expose. "all" (default) or a list from: diagnostics, hover, completions, references, definitions, symbols, formatting, code_actions, rename.
lsp_context_enrichment object No ACMS context enrichment from LSP. Fields: diagnostics (bool), type_annotations (bool), max_diagnostics_per_file (int, default 50).

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

Example 6: Environment-Aware Actor with Jinja2 Conditionals (Simple Jinja2)

A single-actor configuration demonstrating the most common Jinja2 preprocessing features: {{ variable }} interpolation, {% if %} conditionals, the | default filter, and ${VAR:default} environment variable substitution. See ADR-032 for the full Jinja2 preprocessing specification.


# support-bot.yaml
# Register: agents actor add --config support-bot.yaml
#
# Jinja2 preprocessing (Phase 1) resolves {{ }} and {% %} at load time.
# Phase 2: env var interpolation resolves ${VAR} after parsing.

name: local/support-bot

cleveragents: version: "3.0" template_engine: "JINJA2"

actors: support: type: llm config: # Phase 2: environment variables with defaults and type coercion provider: ${LLM_PROVIDER:anthropic} model: ${LLM_MODEL:claude-3.5-sonnet} temperature: 0.4 max_tokens: ${MAX_TOKENS:4096} # coerced to int automatically memory_enabled: ${ENABLE_MEMORY:true} # coerced to bool automatically system_prompt: | You are a {{ context.role }} for {{ context.company }}.

    {% if context.tier == "enterprise" %}
    This is an enterprise customer. Provide priority support with
    detailed technical explanations and offer to escalate issues
    to the engineering team when needed.
    {% else %}
    Provide friendly, concise support. Direct complex issues to
    the documentation at {{ context.docs_url }}.
    {% endif %}

    Always respond in {{ context.language | default("English") }}.

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

merges:

  • sources: [output] target: final

# global_context populates the {{ context.* }} namespace at load time global_context: company: "Acme Corp" role: "technical support specialist" tier: "enterprise" docs_url: "https://docs.acme.example.com"

This example shows the three most common Jinja2 preprocessing patterns: variable interpolation ({{ context.company }}), conditional blocks ({% if context.tier == "enterprise" %}), and the | default filter for safe fallbacks. Environment variables (${LLM_PROVIDER:anthropic}) are resolved in Phase 2 after YAML parsing, with automatic type coercion converting "4096" to int and "true" to bool.


Example 7: Multi-Actor Paper Writer with Advanced Jinja2 (Advanced Jinja2)

A comprehensive multi-actor configuration exercising the full Jinja2 preprocessing feature set. Crucially, this example places {% for %} and {% if %} directives outside any YAML value — directly at the structural level where YAML keys and list items would normally appear. The raw file is not valid YAML until after Jinja2 Phase 1 preprocessing renders it into static YAML text. Features demonstrated include: structural {% for %} loops that generate actor definitions, graph nodes, and graph edges; structural {% if %} conditionals that include or exclude entire actor blocks, route definitions, and merge sources; {% if %} nested inside {% for %} at the structural level; loop.index; Jinja2 type tests (is mapping); .get() with defaults; string slicing ([:200]); ternary expressions; arithmetic; | tojson / | length / | upper / | join filters; {# comment #} blocks; and deeply nested global_context. See ADR-032 for full details.


# paper-writer.yaml
# Register: agents actor add --config paper-writer.yaml
#
# IMPORTANT: This file is NOT valid YAML as written. Jinja2 directives
# ({% for %}, {% if %}, {% endif %}, {% endfor %}) appear at the structural
# level — where YAML keys and list items would normally be — making the
# raw file unparseable by any YAML parser. Phase 1 (Jinja2 preprocessing)
# renders these directives into static YAML text BEFORE the YAML parser
# ever sees the file. Jinja2 syntax inside system_prompt fields is
# preserved for deferred runtime rendering.

name: local/paper-writer

cleveragents: version: "3.0" template_engine: "JINJA2" logging: level: "${LOG_LEVEL:INFO}" unsafe: ${ALLOW_UNSAFE:false} # Phase 2: coerced to bool default_actor: orchestrator

{# ─── Template comment: stripped from output, never reaches YAML parser ─── #}

actors: # ── Orchestrator: uses deferred Jinja2 in system_prompt ───────────── orchestrator: type: llm config: provider: ${LLM_PROVIDER:anthropic} model: ${PRIMARY_MODEL:claude-3.5-sonnet} temperature: 0.7 max_tokens: ${MAX_TOKENS:8192} memory_enabled: true max_history: ${MAX_HISTORY:100} system_prompt: | You are the lead orchestrator for a research paper. Topic: {{ context.paper_details.topic | tojson }} Audience: {{ context.paper_details.audience | tojson }} Max length: {{ context.paper_details.length | tojson }} words

    {# ── Vetted sources: for-loop with type test, .get(), slicing ── #}
    {% if context.vetted_sources and context.vetted_sources|length &gt; 0 %}
    The following {{ context.vetted_sources|length }} vetted sources:
    {% for source in context.vetted_sources %}
    {{ loop.index }}.
    {% if source is mapping %}
      {{ source.get('citation', 'Untitled') }}
      {% if source.get('summary') %}
      — {{ source.get('summary')[:200] }}
      {% if source.get('summary')|length &gt; 200 %}
      ...
      {% endif %}
      {% endif %}
    {% else %}
      {{ source }}
    {% endif %}
    {% endfor %}
    {% else %}
    No vetted sources are available yet. Begin with the discovery phase.
    {% endif %}

    {% if context.deadline %}
    DEADLINE: {{ context.deadline }}. Prioritize accordingly.
    {% endif %}

    {# ── Section plan: ternary expression highlights current section ── #}
    Section plan:
    {% for section in context.sections %}
    {% set m = "&gt;&gt;&gt; " if section == context.current_section else "    " %}
    {{ m }}{{ loop.index }}. {{ section }}
    {% endfor %}

    {# ── Arithmetic in expressions ── #}
    Progress: section {{ context.current_section_index + 1 }}
    of {{ context.sections|length }}.

# ── Writer: deferred templates with nested conditionals ───────────── writer: type: llm config: provider: ${LLM_PROVIDER:anthropic} model: ${PRIMARY_MODEL:claude-3.5-sonnet} temperature: 0.5 max_tokens: 16384 system_prompt: | You are writing section "{{ context.current_section }}" of a paper on {{ context.paper_details.topic }}.

    {% if context.section_content %}
    Previous draft:
    {% set sec = context.current_section %}
    {{ context.section_content.get(sec, 'No prior draft.') }}
    {% endif %}

    {# ── Nested: loop inside conditional ── #}
    {% if context.review_feedback and context.review_feedback|length &gt; 0 %}
    Reviewer feedback to address:
    {% for fb in context.review_feedback %}
    [{{ fb.reviewer }}] ({{ fb.severity }}): {{ fb.comment }}
    {% endfor %}
    {% endif %}

    Format: {{ context.paper_details.get('format', 'markdown') | upper }}

# ── STRUCTURAL {% if %}: the entire assembler actor definition — its YAML # ── key and all nested content — is conditionally included. The {% if %} # ── and {% endif %} lines occupy positions where YAML keys would be, # ── making this raw text invalid YAML. After Phase 1 rendering, either # ── the full assembler: block appears or nothing does. {% if context.enable_assembly %} assembler: type: llm config: actor: anthropic/claude-3.5-sonnet temperature: 0.3 max_tokens: 32768 system_prompt: | Assemble the final paper from these completed sections: {% for path in context.sections %} --- {{ path }} --- {{ context.section_content.get(path, '[MISSING]') }} {% endfor %}

    Total sections: {{ context.sections|length }}
    Target length: {{ context.paper_details.length }} words

    {% if context.latex_errors %}
    Previous compilation errors (last 2000 chars):
    {{ context.latex_errors[-2000:] }}
    {% endif %}

{% endif %}

# ── STRUCTURAL {% for %}: GENERATE one reviewer actor per entry in # ── context.reviewers. The {% for %} line sits where a YAML key would # ── be — not inside any string value. A YAML parser would reject this. # This {% for %} runs at Phase 1 and produces static YAML actor definitions. # With 3 reviewers in global_context, the rendered YAML contains 3 actors: # reviewer_methods, reviewer_domain, reviewer_style. {% for reviewer in context.reviewers %} reviewer_{{ reviewer.id }}: type: llm config: provider: {{ reviewer.get('provider', 'openai') }} model: {{ reviewer.get('model', 'gpt-4') }} temperature: 0.2 max_tokens: 4096 system_prompt: | You are {{ reviewer.name }}, an expert reviewer specializing in {{ reviewer.specialty }}.

    Evaluate the paper section for:
    {# ── Nested loop: iterate criteria inside reviewer loop ── #}
    {% for criterion in reviewer.criteria %}
    - {{ criterion }}
    {% endfor %}

    Severity ratings: Critical, Major, Minor, Suggestion.

    {% if context.review_mode == &quot;strict&quot; %}
    Apply strict academic standards. Flag all unsupported claims.
    {% else %}
    Focus on substantive issues. Ignore minor style preferences.
    {% endif %}

{% endfor %}

# ── Routes: load-time loop generates graph nodes and edges ────────── routes: writing_graph: type: graph nodes: plan: type: agent agent: orchestrator draft: type: agent agent: writer # STRUCTURAL {% for %}: generates review_methods, review_domain, # review_style as concrete YAML keys — invalid YAML until rendered {% for reviewer in context.reviewers %} review_{{ reviewer.id }}: type: agent agent: reviewer_{{ reviewer.id }} {% endfor %} # STRUCTURAL {% if %}: the assemble node only exists when assembly # is enabled — matches the conditional assembler actor above {% if context.enable_assembly %} assemble: type: agent agent: assembler {% endif %} edges: - source: plan target: draft # STRUCTURAL {% for %}: generates edge sets for each reviewer. # Contains a NESTED STRUCTURAL {% if %} — the assemble edge only # appears when enable_assembly is true. Both directives sit where # YAML list items would be — completely invalid YAML until rendered. {% for reviewer in context.reviewers %} - source: draft target: review_{{ reviewer.id }} - source: review_{{ reviewer.id }} target: draft condition: has_critical_feedback: true # {% if %} NESTED inside {% for %}: each reviewer gets an edge # to assemble only when the assembler exists {% if context.enable_assembly %} - source: review_{{ reviewer.id }} target: assemble condition: review_passed: true {% endif %} {% endfor %} entry_point: plan checkpointing: true checkpoint_dir: "${CHECKPOINT_DIR:/tmp/paper_checkpoints}" parallel_execution: true

output_stream: type: stream operators: - type: graph_execute params: graph: writing_graph publications: - paper_output

# ── STRUCTURAL {% if %}: this entire route definition — the YAML key # ── "progress_stream:" and all its children — only exists in the # ── rendered output when enable_monitoring is true. A YAML parser # ── would choke on the bare {% if %} line sitting where it expects # ── a mapping key. {% if context.enable_monitoring %} progress_stream: type: stream stream_type: hot operators: - type: map params: agent: orchestrator subscriptions: - writing_updates publications: - progress_output buffer_size: 50 {% endif %}

merges:

  • sources:
    • paper_output # STRUCTURAL {% if %} inside a YAML list: this list item only # appears in the rendered YAML when the condition is true. # The raw file has a {% if %} line where a "- value" is expected. {% if context.enable_monitoring %}
    • progress_output {% endif %} target: final

# ── global_context: deeply nested structures drive all template rendering ── global_context: paper_details: topic: "Alignment techniques in large language models" audience: "ML researchers" length: 8000 publication: "NeurIPS 2026" format: "latex" sections: - "Abstract" - "Introduction" - "Related Work" - "Methodology" - "Experiments" - "Results > Quantitative" - "Results > Qualitative" - "Discussion" - "Conclusion" current_section: "Introduction" current_section_index: 1 deadline: "2026-06-01" review_mode: "strict" # These flags drive the structural {% if %} conditionals above. # Set to false to exclude the assembler actor and monitoring route entirely. enable_assembly: true enable_monitoring: true # The reviewers list drives the structural {% for %} loops that generate # actor definitions, graph nodes, and graph edges at load time. reviewers: - id: methods name: "Dr. Methods" specialty: "research methodology" provider: "openai" model: "gpt-4" criteria: - "Statistical validity" - "Reproducibility of experiments" - "Clarity of methodology description" - id: domain name: "Dr. Domain" specialty: "AI alignment" provider: "anthropic" model: "claude-3.5-sonnet" criteria: - "Technical accuracy" - "Completeness of literature review" - "Novelty of contributions" - id: style name: "Prof. Style" specialty: "academic writing" criteria: - "Clarity and readability" - "Logical flow between sections" - "Proper citation format"

This configuration demonstrates every major Jinja2 preprocessing feature:

Feature Where Used
Structural {% if %} wrapping entire YAML blocks Assembler actor def, assemble graph node, progress_stream route, merge source list item
Structural {% for %} generating YAML keys/items Reviewer actor defs, graph nodes, graph edges
{% if %} nested inside {% for %} at structural level Reviewer→assemble edge (conditional per-reviewer)
{{ context.X.Y }} — nested variable access Orchestrator, writer, assembler system_prompt
{{ X | tojson }} — safe serialization filter Orchestrator prompt: topic, audience, length
{{ X | length }} — collection length Source count, section count
{{ X | upper }} — string transformation Writer prompt: format output
{{ X | default("Y") }} — fallback defaults Reviewer .get('provider', 'openai')
{% if X and X|length > 0 %} — compound conditions Vetted sources, review feedback, deadline
{% for X in Y %} / loop.index — iteration Sources list, sections list, reviewers list
{# comment #} — template comments Stripped from rendered output
source is mapping — Jinja2 type test Vetted sources loop
.get('key', 'default') — safe dict access Section content, paper format
[:200] / [-2000:] — string/list slicing Source summaries, LaTeX errors
"X" if cond else "Y" — ternary expressions Section plan current-section marker
{{ index + 1 }} — arithmetic Section progress counter
Nested {% for %} inside {% for %} Reviewer criteria inside reviewer loop
${VAR:default} — env var with type coercion Provider, model, tokens, unsafe flag
global_context with nested dicts/lists paper_details, sections, reviewers
Deferred rendering in system_prompt All system_prompt fields preserve {{ }} for runtime

Why the raw file is not valid YAML: The {% for %}, {% endfor %}, {% if %}, and {% endif %} directives in this file appear at positions where the YAML parser expects mapping keys or list items — for example, {% if context.enable_assembly %} sits at the same indentation level as assembler: under the actors: mapping, and {% if context.enable_monitoring %} sits where a route name key would be under routes:. A YAML parser would reject these lines as syntax errors. Jinja2 Phase 1 preprocessing resolves all directives into plain text before the YAML parser ever runs, producing a valid static YAML document.

Load-time vs. runtime rendering: The structural {% for %} and {% if %} directives in the actors, routes, and merges sections run at load time (Phase 1) and produce static YAML — the three reviewer entries expand into three concrete actor definitions (reviewer_methods, reviewer_domain, reviewer_style), their corresponding graph nodes and edges, and the assembler and monitoring route conditionally appear or disappear. In contrast, Jinja2 syntax inside system_prompt fields is preserved through the load-parse cycle (via the template protection mechanism) and evaluated at runtime when the actor's execution context is available.


Skill Configuration Files

!!! adr "Architecture Decision" The skill configuration schema, tool references, and skill inclusion are defined in ADR-012: Skill System.

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. This value is used as the skill's registered name.
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

!!! adr "Architecture Decision" The action configuration schema and action-to-plan lifecycle are defined in ADR-006: Plan Lifecycle.

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": ["available", "archived"],
      "default": "available",
      "description": "State of the action."
    },
    "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: available # State of the action: available or archived (optional, default: available) # ─── 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. This value is used as the action's registered name.
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 State of the action: available or archived. Default: available.
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

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

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

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

!!! adr "Architecture Decision" The tool configuration schema, source types, and capability metadata are defined in ADR-011: Tool System.

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

Structure Reference

Top-Level Fields

Field Type Required Description
name string Yes Fully qualified tool name in <namespace>/<name> format. This value is used as the tool's registered name.
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.
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 access 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


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

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

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


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

Validation Configuration Files

!!! adr "Architecture Decision" The validation configuration schema and read-only enforcement are defined in ADR-013: Validation Abstraction.

Validation configuration files define Validations — a specialized subtype of Tool. A Validation YAML file uses the same format as a Tool YAML file, with an additional validation block containing the validation-specific metadata. Because Validation extends Tool, all tool fields (name, description, source, code, input_schema, output_schema, capability metadata, resource bindings, lifecycle hooks) are available and behave identically. Validations are registered via agents validation add --config <file>.

Read-only enforcement: Validations are always read-only. The writes and checkpointable fields are always forced to false regardless of what the YAML file specifies — if a validation YAML includes writes: true or checkpointable: true, these values are silently overridden to false at registration time. Because this is enforced, it is idiomatic to omit read_only, writes, and checkpointable from validation YAML files entirely (they are unnecessary). The examples below include read_only: true for documentation clarity, but it is not required.

Shared namespace: The name field in a validation YAML occupies the same namespace as tools. Registration will fail if a tool with the same name already exists.

Validation-Specific Fields

In addition to all fields from the Tool Configuration schema, a Validation YAML adds:

Field Type Default Description
validation.mode string "required" "required" or "informational". Required validations must pass for execution to proceed; informational validations report results without blocking.
wraps string (none) Name of an existing registered Tool to wrap. When set, the Validation delegates execution to the wrapped Tool and passes its output through the transform function. Mutually exclusive with source and code.
transform string (none) Python function that converts the wrapped Tool's output to the Validation return format. Required when wraps is set (unless the wrapped Tool already returns validation-format output). The function receives the Tool's output as its argument and must return { "passed": bool, ... }.
argument_mapping object (none) Dictionary mapping the wrapped Tool's input parameter names to either a Validation input parameter name (string) or a fixed literal value. When present, only mapped arguments are forwarded to the wrapped Tool. When absent, the Validation's input arguments are passed through unchanged. Only valid when wraps is set.

When wraps is used, the source and code fields must be omitted — the Validation's implementation is the wrapped Tool plus the transform. The Validation inherits the wrapped Tool's input_schema, resource_slots, and timeout unless explicitly overridden. When the Validation defines a custom input_schema, an argument_mapping should be provided to specify how the Validation's inputs map to the wrapped Tool's expected inputs. See the Tool Wrapping subsection under Core Concepts > Validation for full semantics.

The output of a validation tool must conform to a structured JSON format:

Field Type Required Description
passed boolean Yes Whether the validation passed (true) or failed (false).
message string No Human-readable summary of the validation result.
data object No Arbitrary structured data in any format the validation chooses to convey informational output about the result.

Examples

Example 1: Unit Test Validation (Required)


# validations/run-tests.yaml
# Register: agents validation add --config validations/run-tests.yaml

name: local/run-tests description: "Run unit tests with coverage and report pass/fail"

source: custom code: | import subprocess, json def run(input_data): threshold = input_data.get("coverage_threshold", 80) result = subprocess.run( ["pytest", "--cov=src", f"--cov-fail-under={threshold}", "--tb=short", "-q"], capture_output=True, text=True ) passed = result.returncode == 0 return { "passed": passed, "message": "All tests passed" if passed else f"Tests failed (exit code {result.returncode})", "data": { "stdout": result.stdout, "stderr": result.stderr, "returncode": result.returncode, "coverage_threshold": threshold } }

validation: mode: required

input_schema: type: object properties: coverage_threshold: type: integer default: 80 description: "Minimum coverage percentage required"

read_only: true idempotent: true timeout: 600

resource_slots:

  • name: repo resource_type: git-checkout access: read_only binding: contextual

Example 2: Lint Check Validation (Required, Simple)


# validations/lint-check.yaml

name: local/lint-check description: "Run linter and report pass/fail"

source: custom code: | import subprocess def run(input_data): result = subprocess.run(["ruff", "check", "."], capture_output=True, text=True) passed = result.returncode == 0 return { "passed": passed, "message": "Lint clean" if passed else f"Lint errors found", "data": {"stdout": result.stdout, "stderr": result.stderr} }

validation: mode: required

read_only: true idempotent: true timeout: 300


Example 3: Bundle Size Check (Informational)


# validations/check-bundle-size.yaml

name: local/check-bundle-size description: "Check bundle size (advisory — does not block execution)"

source: custom code: | import subprocess, json def run(input_data): result = subprocess.run(["node", "scripts/check-bundle-size.js"], capture_output=True, text=True) try: size_data = json.loads(result.stdout) except json.JSONDecodeError: size_data = {"raw_output": result.stdout} passed = result.returncode == 0 return { "passed": passed, "message": "Bundle size within limits" if passed else "Bundle size exceeds advisory threshold", "data": size_data }

validation: mode: informational

read_only: true timeout: 120


Example 4: MCP-Backed Validation

A validation that uses an MCP server to perform security scanning:


# validations/security-scan.yaml

name: local/security-scan description: "Run security vulnerability scan via MCP"

source: mcp mcp_server: "npx @security/mcp-scanner" mcp_tool_name: scan_vulnerabilities

validation: mode: required

read_only: true timeout: 300


Example 5: Wrapping an Existing Tool

A validation that wraps an existing local/run-tests tool, reusing its implementation and interpreting its output as pass/fail. No test-running logic is duplicated — only the pass/fail interpretation is defined.


# validations/tests-pass.yaml
# Assumes local/run-tests is already registered as a Tool that runs
# the test suite and returns {returncode, tests_run, tests_passed, ...}

name: local/tests-pass description: "Validate that all unit tests pass (wraps local/run-tests)"

wraps: local/run-tests

transform: | def transform(tool_output): passed = tool_output.get("returncode") == 0 tests_run = tool_output.get("tests_run", 0) tests_passed = tool_output.get("tests_passed", 0) return { "passed": passed, "message": f"{tests_passed}/{tests_run} tests passed" if passed else f"{tests_run - tests_passed} tests failed", "data": tool_output }

validation: mode: required

timeout: 600

Note: source, code, input_schema, and resource_slots are omitted — they are inherited from the wrapped local/run-tests tool. Only the transform, validation.mode, and optional overrides (like timeout) are needed. If the Validation defines a custom input_schema, an argument_mapping should also be provided to map the Validation's inputs to the wrapped Tool's expected inputs.


Example 6: Wrapping with Different Interpretation (Informational)

A second validation wrapping the same tool but extracting a different signal — coverage threshold — as an advisory check:


# validations/coverage-check.yaml

name: local/coverage-check description: "Check test coverage exceeds threshold (advisory)"

wraps: local/run-tests

transform: | def transform(tool_output): coverage = tool_output.get("coverage_percent", 0) threshold = 80 return { "passed": coverage >= threshold, "message": f"Coverage: {coverage:.1f}% (threshold: {threshold}%)", "data": { "coverage_percent": coverage, "threshold": threshold, "above_threshold": coverage >= threshold } }

validation: mode: informational


Resource Type Configuration Files

!!! adr "Architecture Decision" The resource type system, custom type registration, and type hierarchy are defined in ADR-008: Resource System.

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

# ─── Type Inheritance ─────────────────────────────────────────────── inherits: <parent-type-name> # Parent resource type to inherit from (optional) # Subtypes inherit all fields from the parent type. # Only fields that differ from or extend the parent need to be declared. # See ADR-042 for full inheritance semantics.

# ─── 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. This value is used as the resource type's registered name.
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.
inherits string No Parent resource type name to inherit from. Subtypes inherit all properties, capabilities, child types, sandbox strategy, and handler behavior from the parent. Only fields that differ from or extend the parent need to be declared. Collection fields (cli_args, child_types, parent_types) use additive merging by default; use <field>_replace: true to replace entirely. Single inheritance only; maximum chain depth of 5. See ADR-042.
sandbox_strategy string Yes (unless inherited) The sandbox strategy used when executing within this resource type. Inherited from parent type if inherits is set and field is omitted.
handler object Yes (unless inherited) The Python handler class that implements resource operations. Inherited from parent type if inherits is set and field is omitted; subtypes typically override with a subclass handler.

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.resource.handlers.svn config: svn_binary: "svn" trust_server_cert: true

auto_discovery: enabled: true scan_depth: 2 exclude_patterns: - "/.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.resource.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/**"


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.resource.handlers.database config: connection_pool_size: 5 statement_timeout: 30000 # 30 seconds log_queries: true

auto_discovery: enabled: true scan_depth: 1


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

Example 6: Devcontainer Instance Resource Type (Inherited)

This example demonstrates the devcontainer-instance type, which inherits from container-instance via the resource type inheritance mechanism (ADR-042). Fields not shown here are inherited from the parent type. Only the additional fields and overrides specific to devcontainer semantics are defined.

# devcontainer-instance inherits from container-instance (ADR-039)
# See ADR-042 for inheritance rules, ADR-043 for devcontainer lifecycle

name: "devcontainer-instance" inherits: "container-instance" description: "A container instance defined by a devcontainer.json configuration file. Auto-discovered as a child of git-checkout resources containing a .devcontainer/ directory. Supports lazy activation — detected at discovery time but built only on first access." physical_virtual: "physical"

fields: # Inherited from container-instance: image, engine, ports, environment, volumes # Additional fields specific to devcontainer semantics: devcontainer_json_path: type: "string" required: true description: "Relative path to devcontainer.json from the parent resource root (e.g., .devcontainer/devcontainer.json)" workspace_folder: type: "string" required: false default: "/workspaces/${localWorkspaceFolderBasename}" description: "Container-side workspace path, parsed from devcontainer.json workspaceFolder field" features: type: "map<string, object>" required: false description: "Dev Container Features to install, parsed from devcontainer.json features field" post_create_command: type: "string | list<string>" required: false description: "Command(s) to run after container creation, from devcontainer.json postCreateCommand" post_start_command: type: "string | list<string>" required: false description: "Command(s) to run after container start, from devcontainer.json postStartCommand" activation_state: type: "enum(detected, building, running, stopping, stopped, failed)" required: true default: "detected" description: "Lifecycle state. Starts as 'detected' (lazy); transitions to 'building' then 'running' on first access. The 'stopping' state tracks in-progress shutdown before reaching 'stopped'."

handler: "DevcontainerHandler"

sandbox_strategy: "container_snapshot" # Overrides the parent's sandbox_strategy; devcontainers use container snapshots # for checkpoint/rollback rather than the generic container strategy.

capabilities: readable: true writable: true sandboxable: true checkpointable: true executable: true

auto_discovery: enabled: true parent_types: - "git-checkout" detection: scan_paths: - ".devcontainer/devcontainer.json" - ".devcontainer.json" activation: "lazy" # Container is NOT built at discovery time. # State remains "detected" until the execution environment router # selects this devcontainer for tool execution.


Context View Configuration

!!! adr "Architecture Decision" The context view configuration, resource filtering, and phase-specific context assembly are defined in ADR-014: Context Management (ACMS).

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."
    },
    "strategy": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Ordered list of ACMS context strategies to use for this view. Overrides the global strategy list. Valid built-in values: simple-keyword, semantic-embedding, breadth-depth-navigator, arce, temporal-archaeology, plan-decision-context."
    },
    "default_breadth": {
      "type": "integer",
      "minimum": 0,
      "default": 2,
      "description": "Default number of hops from focus nodes in the UKO graph for context expansion. 0 = focus nodes only."
    },
    "default_depth": {
      "oneOf": [
        { "type": "integer", "minimum": 0 },
        { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" }
      ],
      "default": 3,
      "description": "Default detail depth for context fragments. May be a non-negative integer or a named level string from the active domain's DetailLevelMap (e.g., 'SIGNATURES', 'FULL_SOURCE'). Named levels are resolved to integers via the DetailLevelMap inheritance chain. Default: 3."
    },
    "depth_gradient": {
      "type": "object",
      "additionalProperties": {
        "oneOf": [
          { "type": "integer", "minimum": 0 },
          { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" }
        ]
      },
      "description": "Per-hop detail depth overrides. Key is the hop distance (0 = focus node), value is an integer depth or named level string. Hops not listed use default_depth."
    },
    "skeleton_ratio": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "default": 0.15,
      "description": "Fraction of the context budget reserved for inherited plan skeleton context. 0.0 = no skeleton inheritance; 1.0 = all budget to skeleton."
    },
    "temporal_scope": {
      "type": "string",
      "enum": ["current", "recent", "all"],
      "default": "current",
      "description": "Temporal scope for UKO node resolution. 'current' = only isCurrent nodes; 'recent' = current + nodes valid within warm retention window; 'all' = include historical versions."
    },
    "auto_refresh": {
      "type": "boolean",
      "default": true,
      "description": "When true, the ACMS automatically re-assembles context when the available budget changes by more than the refresh threshold (default 30%). When false, context is only assembled on explicit request."
    }
  },
  "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)

# ─── ACMS Strategy & Context Assembly ─────────────────────────────── strategy: # ACMS strategies to use (optional, overrides global list)

  • simple-keyword
  • semantic-embedding
  • breadth-depth-navigator default_breadth: <integer> # Default hop count for UKO graph expansion (optional, default: 2) default_depth: 3 # Default detail depth — integer or named level (optional, default: 3) depth_gradient: # Per-hop detail depth overrides (optional) 0: 9 # Focus nodes get depth 9 (FULL_SOURCE for code) 1: 4 # 1-hop neighbors get depth 4 (SIGNATURES for code) 2: 0 # 2-hop neighbors get depth 0 (MODULE_LISTING for code) skeleton_ratio: <float> # Fraction of budget for inherited plan skeleton (optional, default: 0.15) temporal_scope: current | recent | all # Temporal scope for UKO node resolution (optional, default: current) auto_refresh: true # Auto re-assemble context on budget change (optional, default: true)

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.
strategy list No Ordered list of ACMS context strategies to use for this view. Overrides the global context.strategies.enabled list. Built-in strategies: simple-keyword, semantic-embedding, breadth-depth-navigator, arce, temporal-archaeology, plan-decision-context.
default_breadth integer No Default number of hops from focus nodes in the UKO graph for context expansion. 0 = focus nodes only. Default: 2.
default_depth integer or string No Default detail depth for context fragments. Accepts a non-negative integer or a named level string from the active domain's DetailLevelMap (e.g., SIGNATURES, FULL_SOURCE). Default: 3.
depth_gradient object No Per-hop detail depth overrides. Keys are hop distances (0 = focus node), values are integers or named level strings. Hops not listed use default_depth.
skeleton_ratio number No Fraction of context budget reserved for inherited plan skeleton context. Range: 0.01.0. Default: 0.15.
temporal_scope string No Temporal scope for UKO node resolution: current (only isCurrent nodes), recent (current + warm retention window), all (include historical versions). Default: current.
auto_refresh boolean No When true, ACMS automatically re-assembles context when the available budget changes by more than the refresh threshold. Default: 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

!!! adr "Architecture Decision" The automation profile configuration schema, threshold model, and built-in profiles are defined in ADR-017: Automation Profiles.

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."
    },
    "decompose_task": {
      "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."
    },
    "create_tool": {
      "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."
    },
    "select_tool": {
      "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."
    },
    "edit_code": {
      "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."
    },
    "execute_command": {
      "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."
    },
    "create_file": {
      "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."
    },
    "delete_content": {
      "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."
    },
    "access_network": {
      "type": "number",
      "minimum": 0.0,
      "maximum": 1.0,
      "description": "Confidence threshold (0.0-1.0) for automatically reverting from a constrained Apply phase to Strategize. 0.0 = always automatic, 1.0 = always manual."
    },
    "modify_config": {
      "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."
    },
    "approve_plan": {
      "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."
    },
    "install_dependency": {
      "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",
    "decompose_task",
    "create_tool",
    "select_tool",
    "edit_code",
    "execute_command",
    "create_file",
    "delete_content",
    "access_network",
    "modify_config",
    "approve_plan",
    "install_dependency",
    "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. decompose_task: <float: 0.01.0> # Confidence threshold for Action → Strategize (required, 0.0=auto, 1.0=manual) create_tool: <float: 0.01.0> # Confidence threshold for Strategize → Execute (required, 0.0=auto, 1.0=manual) select_tool: <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. edit_code: <float: 0.01.0> # Confidence threshold for decisions during Strategize (required, 0.0=auto, 1.0=manual) execute_command: <float: 0.01.0> # Confidence threshold for decisions during Execute (required, 0.0=auto, 1.0=manual)

# ─── Self-Repair Thresholds ───────────────────────────────────────── create_file: <float: 0.01.0> # Confidence threshold for auto-fixing validation failures (required, 0.0=auto, 1.0=manual) delete_content: <float: 0.01.0> # Confidence threshold for auto-revising strategy when Execute hits constraints (required, 0.0=auto, 1.0=manual) access_network: <float: 0.01.0> # Confidence threshold for auto-reverting from constrained Apply to Strategize (required, 0.0=auto, 1.0=manual) modify_config: <float: 0.01.0> # Confidence threshold for auto-retrying transient errors (required, 0.0=auto, 1.0=manual) approve_plan: <float: 0.01.0> # Confidence threshold for auto-restoring from checkpoints (required, 0.0=auto, 1.0=manual)

# ─── Execution Control Thresholds ────────────────────────────────── install_dependency: <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. This value is used as the profile's registered name.
description string Yes Human-readable description of the profile's purpose and behavior.

Phase Transition Thresholds

Field Type Required Description
decompose_task 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.
create_tool 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.
select_tool 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
edit_code 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.
execute_command 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
create_file 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.
delete_content 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.
access_network number (0.01.0) Yes Confidence threshold for automatically reverting from a constrained Apply phase to Strategize. When computed confidence >= threshold, reversion proceeds automatically. 0.0 = always automatic, 1.0 = always manual.
modify_config 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.
approve_plan 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
install_dependency 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
select_tool 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_rev_apply 1.0 1.0 1.0 0.9 1.0 1.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"

decompose_task: 0.0 create_tool: 0.0 select_tool: 1.0

edit_code: 0.0 execute_command: 0.0

create_file: 0.0 delete_content: 1.0 access_network: 1.0 modify_config: 0.0 approve_plan: 0.0

install_dependency: 0.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

This is essentially the auto built-in profile but with approve_plan 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."

decompose_task: 0.0 create_tool: 0.0 select_tool: 0.0

edit_code: 0.0 execute_command: 0.0

create_file: 0.0 delete_content: 0.0 access_network: 0.0 modify_config: 0.0 approve_plan: 0.0

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

decompose_task: 0.0 create_tool: 1.0 select_tool: 1.0

edit_code: 1.0 execute_command: 1.0

create_file: 1.0 delete_content: 1.0 access_network: 1.0 modify_config: 1.0 approve_plan: 1.0

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

decompose_task: 0.0 create_tool: 0.0 select_tool: 1.0

edit_code: 0.0 execute_command: 0.0

create_file: 0.0 delete_content: 0.0 access_network: 1.0 modify_config: 0.0 approve_plan: 0.0

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

decompose_task: 0.0 create_tool: 0.0 select_tool: 1.0

edit_code: 0.0 execute_command: 0.0

create_file: 0.0 delete_content: 0.0 access_network: 1.0 modify_config: 0.0 approve_plan: 0.0

install_dependency: 0.0

require_sandbox: true require_checkpoints: true allow_unsafe_tools: false

LSP Server Configuration Files

!!! adr "Architecture Decision" The LSP Registry, actor LSP binding, capability exposure, and server lifecycle are defined in ADR-027: Language Server Protocol (LSP) Integration.

LSP server configuration files define Language Server Protocol servers that provide language intelligence to actors. LSP servers are Infrastructure-layer components — they have nothing to do with IDE integration. Each server has a namespaced name, a launch command, supported languages, initialization options, and capability declarations. LSP servers are registered via agents lsp add --config <file> and can then be referenced by actors in their lsp: configuration field.

JSON Schema

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


{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cleveragents.dev/schemas/lsp-server-config.json",
  "title": "CleverAgents LSP Server Configuration",
  "description": "Configuration file schema for defining LSP servers registered in the LSP Registry and attached to actors for language intelligence.",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^([a-zA-Z0-9_-]+:)?[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$",
      "description": "Fully qualified LSP server name in [[server:]namespace/]name format."
    },
    "description": {
      "type": "string",
      "description": "Human-readable description of the LSP server's purpose."
    },
    "languages": {
      "type": "array",
      "items": { "type": "string" },
      "minItems": 1,
      "description": "Programming languages this server supports. Used for language-based and auto-discovery binding resolution."
    },
    "command": {
      "type": "string",
      "description": "Shell command to launch the LSP server process. Must support --stdio or equivalent for stdin/stdout JSON-RPC communication."
    },
    "args": {
      "type": "array",
      "items": { "type": "string" },
      "default": [],
      "description": "Additional arguments appended to the command."
    },
    "env": {
      "type": "object",
      "additionalProperties": { "type": "string" },
      "default": {},
      "description": "Environment variables set when launching the server process."
    },
    "root_path": {
      "type": "string",
      "default": "{{ project.root }}",
      "description": "Workspace root path sent in the LSP initialize request. Supports Jinja2 template variables."
    },
    "init_options": {
      "type": "object",
      "additionalProperties": true,
      "default": {},
      "description": "Initialization options sent in the LSP initialize request. Server-specific; passed through verbatim."
    },
    "capabilities": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": ["diagnostics", "hover", "completions", "references", "definitions", "symbols", "formatting", "code_actions", "rename"]
      },
      "default": ["diagnostics", "hover", "completions", "references", "definitions", "symbols", "formatting", "code_actions", "rename"],
      "description": "LSP capabilities this server advertises. The runtime uses this to determine which tool adapters and context enrichment features are available. Defaults to all capabilities; restrict to a subset if the server does not support certain features."
    },
    "health_check": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": true,
          "description": "Whether to perform periodic health checks on the running server process."
        },
        "interval_seconds": {
          "type": "integer",
          "default": 60,
          "minimum": 10,
          "description": "Seconds between health check probes."
        },
        "restart_on_failure": {
          "type": "boolean",
          "default": true,
          "description": "Whether to automatically restart the server if health checks fail."
        },
        "max_restarts": {
          "type": "integer",
          "default": 3,
          "minimum": 0,
          "description": "Maximum number of automatic restarts before marking the server as failed."
        }
      },
      "additionalProperties": false,
      "description": "Health check configuration for the running server process."
    }
  },
  "required": ["name", "languages", "command"],
  "additionalProperties": false
}

Informal YAML Schema


# ─── LSP Server Configuration ────────────────────────────────────────
# Registered via: agents lsp add --config <this-file>
# Referenced by actors via: lsp: [<namespace>/<name>]

name: <namespace>/<server-name> # Namespaced identifier (required) description: "..." # Human-readable description (optional)

languages: # Supported languages (required, min 1)

  • python
  • pyi # e.g., Python stub files

command: pyright-langserver # Launch command (required) args: # Additional arguments (optional)

  • --stdio

env: # Environment variables (optional) PYTHONPATH: /app/src

root_path: "{{ project.root }}" # Workspace root, Jinja2 supported (optional, default: {{ project.root }})

init_options: # LSP initialize request options (optional) python.analysis.typeCheckingMode: standard python.analysis.autoSearchPaths: true python.analysis.diagnosticSeverityOverrides: reportMissingImports: warning reportUnusedVariable: information

capabilities: # Advertised capabilities (optional, default: all)

  • diagnostics
  • hover
  • completions
  • references
  • definitions
  • symbols
  • formatting
  • code_actions
  • rename

health_check: # Health monitoring (optional) enabled: true # Periodic health probes (default: true) interval_seconds: 60 # Probe interval (default: 60, min: 10) restart_on_failure: true # Auto-restart on failure (default: true) max_restarts: 3 # Max auto-restarts before marking failed (default: 3)

Structure Reference

LSP Server Configuration Fields

Field Type Required Description
name string Yes Fully qualified LSP server name in [[server:]namespace/]name format.
description string No Human-readable description of the server's purpose.
languages list Yes Programming languages this server supports (min 1). Used for language-based and auto-discovery binding resolution.
command string Yes Shell command to launch the LSP server process. Must support stdio JSON-RPC communication.
args list No Additional arguments appended to the command.
env object No Environment variables set when launching the server process.
root_path string No Workspace root path sent in the LSP initialize request. Supports Jinja2 template variables. Default: {{ project.root }}.
init_options object No Initialization options sent in the LSP initialize request. Server-specific; passed through verbatim.
capabilities list No LSP capabilities this server advertises: diagnostics, hover, completions, references, definitions, symbols, formatting, code_actions, rename. Default: all.
health_check object No Health monitoring configuration.
health_check.enabled boolean No Whether to perform periodic health checks. Default: true.
health_check.interval_seconds integer No Seconds between health check probes. Default: 60, min: 10.
health_check.restart_on_failure boolean No Auto-restart server on health check failure. Default: true.
health_check.max_restarts integer No Maximum automatic restarts before marking server as failed. Default: 3, min: 0.

Examples

Example 1: Pyright (Python type checker and language server)


name: local/pyright
description: "Pyright language server for Python type checking and intelligence"
languages:
  - python
  - pyi
command: pyright-langserver
args: ["--stdio"]
init_options:
  python.analysis.typeCheckingMode: standard
  python.analysis.autoSearchPaths: true
  python.analysis.useLibraryCodeForTypes: true

Example 2: TypeScript Language Server


name: local/ts-server
description: "TypeScript/JavaScript language server"
languages:
  - typescript
  - javascript
  - tsx
  - jsx
command: typescript-language-server
args: ["--stdio"]
init_options:
  preferences:
    includeInlayParameterNameHints: all
    includeInlayVariableTypeHints: true

Example 3: gopls (Go language server) with restricted capabilities


name: local/gopls
description: "Go language server (diagnostics and navigation only)"
languages:
  - go
command: gopls
args: ["serve"]
capabilities:
  - diagnostics
  - hover
  - references
  - definitions
  - symbols
health_check:
  interval_seconds: 120
  max_restarts: 5

Example 4: Rust Analyzer with custom environment


name: local/rust-analyzer
description: "Rust Analyzer language server"
languages:
  - rust
command: rust-analyzer
env:
  CARGO_HOME: /home/user/.cargo
  RUSTUP_HOME: /home/user/.rustup
init_options:
  cargo:
    allFeatures: true
  checkOnSave:
    command: clippy