521 KiB
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.0–1.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):
- CLI flag: Per-invocation overrides (e.g.,
--formatmaps tocore.format,--data-dirmaps tocore.data-dir). Highest priority. - Environment variable: The mapped
CLEVERAGENTS_*variable or provider-specific variable (e.g.,OPENAI_API_KEYforprovider.openai.api-key). - 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). - Global config file: The value in the config file at the path specified by
core.config-path. - 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:
-
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.
-
Namespace/Name convention: Every configurable entity follows the
<namespace>/<name>naming convention. Thelocal/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/). -
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--configfile 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 addaccepts--required/--informationalflags that override the YAMLmodefield, as described in the Validation Mode section under Core Concepts. -
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. -
Jinja2 template support: Actor configuration files support Jinja2 template syntax within string values (particularly
system_promptfields). Template placeholders like{{ context.project_name }}are preserved during YAML parsing and rendered at runtime. -
Idempotent registration: Adding an entity that already exists fails unless
--updateis provided. This prevents accidental overwrites while allowing intentional updates. -
Declarative structure: Configuration files are declarative — they describe what should exist, not how to create it. The system handles all lifecycle management.
-
Schema version: Configuration files may include a top-level
cleveragents.versionfield 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;">"END"</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 --unsafename: 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("url", "") return {"content": f"Content from {url}", "url": 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 > 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 > 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 = ">>> " 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 > 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 == "strict" %} 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.yamlname: 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:
- Business-critical modules (auth, payments)
- Recently modified code
- 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.yamlname: 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 = ["alembic"]
if dry_run:
cmd.append("<span style="color: cyan;">--sql</span>")
cmd.extend([direction, str(count)])
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
return {
<span style="color: cyan; font-weight: 600;">"success"</span>: result.returncode == 0,
<span style="color: cyan; font-weight: 600;">"stdout"</span>: result.stdout,
<span style="color: cyan; font-weight: 600;">"stderr"</span>: result.stderr,
<span style="color: cyan; font-weight: 600;">"direction"</span>: direction,
<span style="color: cyan; font-weight: 600;">"count"</span>: count,
<span style="color: cyan; font-weight: 600;">"dry_run"</span>: dry_run,
<span style="color: cyan; font-weight: 600;">"return_code"</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.yamlname: 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 {"success": True, "service": service, "version": 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 {"compatible": True, "changes": [], "reason": "No breaking changes"}
<span style="color: cyan; font-weight: 600;">try</span>:
breaking = json.loads(diff_result.stdout)
except json.JSONDecodeError:
breaking = [{"description": diff_result.stdout}]
return {
<span style="color: cyan; font-weight: 600;">"compatible"</span>: False,
<span style="color: cyan; font-weight: 600;">"changes"</span>: breaking,
<span style="color: cyan; font-weight: 600;">"reason"</span>: f"Found {len(breaking)} breaking change(s)"
}
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.yamlname: 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.yamlname: 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.yamlname: 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.yamlname: 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 <type>. 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.yamlname: 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.yamlname: 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.yamlname: 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.yamlname: 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.yamlname: 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 lifecyclename: "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.0–1.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:
- Check for a phase-specific view (e.g.,
strategize). - Fall back to the
defaultview. - 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.yamlproject: 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.yamlproject: 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.yamlproject: 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.yamlproject: 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.0–1.0> # Confidence threshold for Action → Strategize (required, 0.0=auto, 1.0=manual) create_tool: <float: 0.0–1.0> # Confidence threshold for Strategize → Execute (required, 0.0=auto, 1.0=manual) select_tool: <float: 0.0–1.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.0–1.0> # Confidence threshold for decisions during Strategize (required, 0.0=auto, 1.0=manual) execute_command: <float: 0.0–1.0> # Confidence threshold for decisions during Execute (required, 0.0=auto, 1.0=manual)
# ─── Self-Repair Thresholds ───────────────────────────────────────── create_file: <float: 0.0–1.0> # Confidence threshold for auto-fixing validation failures (required, 0.0=auto, 1.0=manual) delete_content: <float: 0.0–1.0> # Confidence threshold for auto-revising strategy when Execute hits constraints (required, 0.0=auto, 1.0=manual) access_network: <float: 0.0–1.0> # Confidence threshold for auto-reverting from constrained Apply to Strategize (required, 0.0=auto, 1.0=manual) modify_config: <float: 0.0–1.0> # Confidence threshold for auto-retrying transient errors (required, 0.0=auto, 1.0=manual) approve_plan: <float: 0.0–1.0> # Confidence threshold for auto-restoring from checkpoints (required, 0.0=auto, 1.0=manual)
# ─── Execution Control Thresholds ────────────────────────────────── install_dependency: <float: 0.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.0–1.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.yamlname: 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.yamlname: 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.yamlname: 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.yamlname: 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.yamlname: 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