## Configuration !!! adr "Architecture Decision" The configuration system design principles, YAML-first approach, and config file conventions are defined in [ADR-024: Configuration System](adr/ADR-024-configuration-system.md). 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](adr/ADR-024-configuration-system.md). 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 | `/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 `/` 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 | `/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 | `/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 | `/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 `/` 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 | `/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 | `/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 | `/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..`. Each provider has an `api-key` field and may have additional fields for endpoint configuration. Environment variables for provider keys use standard naming conventions compatible with existing tooling (e.g., `OPENAI_API_KEY`). | Key | Type | Default | Env Variable | Description | |-----|------|---------|-------------|-------------| | `provider.openai.api-key` | string | *(not set)* | `OPENAI_API_KEY` | API key for OpenAI models. Required when using OpenAI-based actors or the default embedding provider. The standard `OPENAI_API_KEY` environment variable is checked for compatibility with existing tooling. | | `provider.openai.org-id` | string | *(not set)* | `OPENAI_ORG_ID` | OpenAI organization ID. Optional; used when the API key belongs to multiple organizations. | | `provider.openai.base-url` | string | *(not set)* | `OPENAI_BASE_URL` | Custom base URL for OpenAI-compatible APIs (e.g., a local proxy or alternative provider). When unset, the official OpenAI API URL is used. | | `provider.anthropic.api-key` | string | *(not set)* | `ANTHROPIC_API_KEY` | API key for Anthropic models. Required when using Anthropic-based actors. | | `provider.google.api-key` | string | *(not set)* | `GOOGLE_API_KEY` | API key for Google AI models. Required when using Google-based actors. | | `provider.azure.endpoint` | string | *(not set)* | `AZURE_OPENAI_ENDPOINT` | Azure OpenAI endpoint URL. Required when using Azure-hosted OpenAI models. | | `provider.azure.api-key` | string | *(not set)* | `AZURE_OPENAI_API_KEY` | API key for Azure OpenAI. Required alongside `provider.azure.endpoint`. | | `provider.azure.api-version` | string | `2024-02-01` | `AZURE_OPENAI_API_VERSION` | Azure OpenAI API version string. | | `provider.google.gemini-api-key` | string | *(not set)* | `GEMINI_API_KEY` | API key for Google Gemini models. Required when using Gemini-based actors. The standard `GEMINI_API_KEY` environment variable is checked for compatibility with Google's tooling. | | `provider.huggingface.token` | string | *(not set)* | `HF_TOKEN` | Access token for Hugging Face Inference API. Required when using Hugging Face-hosted models. The standard `HF_TOKEN` environment variable is checked for compatibility with Hugging Face tooling. | | `provider.openrouter.api-key` | string | *(not set)* | `OPENROUTER_API_KEY` | API key for OpenRouter. Required when using OpenRouter as a provider. | #### Configuration Scoping Several keys support **project-scoped** values in addition to the global default. When a project-scoped value is set, it applies only to plans targeting that project. Keys marked **Project-scopable** in the reference above support this feature. The full dot path is used identically in both global and project-scoped contexts:

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

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

# Project-scoped keys under any group work the same way
$ agents config set plan.budget.per-plan 2.00 --project local/production-api
$ agents config set sandbox.strategy git_worktree --project local/production-api
$ agents config set context.hot.max-tokens 32000 --project local/large-codebase
The full list of project-scopable keys: `core.automation-profile`, `plan.concurrency`, `plan.max-child-depth`, `plan.budget.per-plan`, `sandbox.strategy`, `sandbox.checkpoint.enabled`, and all keys under `context.*`. #### Resolution Order When resolving the effective value of a configuration key, the following precedence applies (highest to lowest): 1. **CLI flag**: Per-invocation overrides (e.g., `--format` maps to `core.format`, `--data-dir` maps to `core.data-dir`). Highest priority. 2. **Environment variable**: The mapped `CLEVERAGENTS_*` variable or provider-specific variable (e.g., `OPENAI_API_KEY` for `provider.openai.api-key`). 3. **Project-scoped config**: For project-scopable keys, the value set via `agents config set --project `. Only applies in contexts where a project is known (e.g., during plan execution). 4. **Global config file**: The value in the config file at the path specified by `core.config-path`. 5. **Built-in default**: The hardcoded default value. The `agents config get ` command displays the full resolution chain, showing which level provided the winning value. Listing subtrees is supported:

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

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

# List all keys with their current effective values
$ agents config list
#### Configuration File Format The global configuration file uses TOML format. The hierarchical key structure maps naturally to TOML tables. A typical `config.toml` after initial setup:

# ~/.cleveragents/config.toml

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

[core.log]
level = "FATAL"
terminal = "auto"
terminal-stream = "stderr"
file-enabled = true
retention-days = 30

[core.backup]
retention-days = 7

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

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

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

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

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

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

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

[index.text]
backend = "tantivy"

[index.vector]
backend = "faiss"

[index.graph]
backend = "none"

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

[context.hot]
max-tokens = 16000

[context.warm]
max-decisions = 100

[context.cold]
max-decisions = 500

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

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

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

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

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

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

[project."local/docs"]
"core.automation-profile" = "auto"
"plan.budget.per-plan" = 10.00
"context.hot.max-tokens" = 32000
### Design Principles All CleverAgents configuration files share a consistent set of design principles: 1. **YAML-first**: All configuration files use YAML syntax. JSON is also accepted where a configuration file is loaded (since valid JSON is valid YAML), but YAML is the canonical format for human-authored configurations. 2. **Namespace/Name convention**: Every configurable entity follows the `/` naming convention. The `local/` namespace is reserved for local-only items. User namespaces (`/`) and organization namespaces (`/`) are stored on the server. Built-in entities use provider namespaces (e.g., `openai/`, `anthropic/`). 3. **Config-as-complete-definition pattern**: For entity registration commands (`actor add`, `skill add`, `tool add`, `validation add`, `resource type add`, `action create`, `automation-profile add`), the YAML configuration file is the **sole source of truth** — the `--config` file fully defines the entity. For runtime commands that reference existing entities (e.g., `plan use`), CLI options may override entity defaults to customize behavior per-invocation. **Exception**: `validation add` accepts `--required`/`--informational` flags that override the YAML `mode` field, as described in the Validation Mode section under Core Concepts. 4. **Environment variable interpolation**: All configuration files support `${ENV_VAR}` and `${ENV_VAR:default_value}` syntax for environment variable interpolation. If a variable is not set and no default is provided, an error is raised. Boolean strings (`true`/`false`) and numeric strings are automatically converted to their native types. 5. **Jinja2 template support**: Actor configuration files support Jinja2 template syntax within string values (particularly `system_prompt` fields). Template placeholders like `{{ context.project_name }}` are preserved during YAML parsing and rendered at runtime. 6. **Idempotent registration**: Adding an entity that already exists fails unless `--update` is provided. This prevents accidental overwrites while allowing intentional updates. 7. **Declarative structure**: Configuration files are declarative — they describe *what* should exist, not *how* to create it. The system handles all lifecycle management. 8. **Schema version**: Configuration files may include a top-level `cleveragents.version` field to indicate which schema version they target (currently `"3.0"`). When omitted, the latest schema version is assumed. --- ### Actor Configuration Files !!! adr "Architecture Decision" The actor configuration schema and actor registration model are defined in [ADR-010: Actor and Agent Architecture](adr/ADR-010-actor-and-agent-architecture.md). 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 `. For behavioral documentation including Jinja2 template preprocessing, actor composition, multi-actor workflows, and field-level descriptions, see the [Actor](#actor) section. For the Jinja2 preprocessing pipeline specifically, see [Jinja2 Template Preprocessing](#jinja2-template-preprocessing) and [ADR-032](adr/ADR-032-jinja2-yaml-template-preprocessing.md). #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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, `` 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)

      system_prompt: |              # System prompt text, supports Jinja2 templates (optional)
        You are a helpful assistant.
        Project: {{ context.project_name }}
      temperature: 0.7              # Sampling temperature 0.0-2.0 (optional, default: provider default)
      max_tokens: 4096              # Maximum output tokens (optional, default: provider default)
      memory_enabled: true          # Enable conversation memory (optional, default: false)
      max_history: 50               # Maximum conversation turns to retain (optional, default: 50)
      unsafe: false                 # Allow unsafe operations for this actor (optional, default: false)
      options:                      # Additional provider-specific options (optional)
        top_p: 1.0
        frequency_penalty: 0.0
        presence_penalty: 0.0
        stop_sequences: ["END"]
        seed: 42

      # ── 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"]}

      response_format: {}            # JSON schema for structured LLM output (optional, LLM only)

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

    lsp_capabilities: all              # Which LSP capabilities to expose (optional, default: all)
                                      # "all" | list of: diagnostics, hover, completions, references,
                                      #   definitions, symbols, formatting, code_actions, rename

    lsp_context_enrichment:            # ACMS context enrichment from LSP (optional)
      diagnostics: true               # Auto-inject diagnostics into code context windows
      type_annotations: true          # Auto-inject inferred types into code context windows
      max_diagnostics_per_file: 50   # Limit diagnostics per file (default: 50)

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

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

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

# ─── Merges & Splits ────────────────────────────────────────────────
merges:                             # Stream merge definitions (optional)
  - sources:                        # Source streams to merge
      - <stream_name>
    target: <stream_name>           # Target stream for merged output

splits:                             # Stream split definitions (optional)
  - source: <stream_name>           # Source stream to split
    targets:                        # Target streams for split output
      - <stream_name>

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

# ─── Pipelines ──────────────────────────────────────────────────────
pipelines:                          # Hybrid pipeline definitions (optional)
  <pipeline_name>:
    stages:
      - name: <stage_name>
        type: <stage_type>
        config: {}
    metadata: {}
#### Structure Reference **Top-Level Keys** | Key | Type | Required | Description | |-----|------|----------|-------------| | `cleveragents` | object | No | Metadata block containing version, logging, template engine, and safety settings. | | `actors` (or `agents`) | object | Yes | Map of actor names to their definitions. Both `actors` and `agents` are accepted as the key name. | | `routes` | object | No | Map of route names to their definitions. Routes connect actors via stream or graph topologies. | | `merges` | list | No | Stream merge operations combining multiple streams into one. | | `splits` | list | No | Stream split operations dividing one stream into multiple. | | `templates` | object | No | Reusable template definitions for Jinja2 template inheritance. | | `instances` | object | No | Instantiated templates with bound parameters. | | `global_context` | object | No | Key-value pairs available to all actors via `{{ context.key }}` in templates. | | `prompts` | object | No | Named prompt templates that can be referenced by actors. | | `pipelines` | object | No | Hybrid pipelines combining stream and graph stages into sequential workflows. | **`cleveragents` Block** | Field | Type | Default | Description | |-------|------|---------|-------------| | `version` | string | `"3.0"` | Schema version for this configuration file. | | `logging.level` | string | `"INFO"` | Logging level: `DEBUG`, `INFO`, `WARNING`, `ERROR`. | | `template_engine` | string | `"JINJA2"` | Template engine for string interpolation: `JINJA2` or `NONE`. | | `unsafe` | boolean | `false` | When `true`, allows actors to perform operations flagged as unsafe. Requires `--unsafe` CLI flag. | | `default_actor` | string | (first actor) | Name of the default actor when multiple actors are defined. | **Actor Definition Fields** | Field | Type | Required | Description | |-------|------|----------|-------------| | `type` | string | Yes | Actor type. `llm` for language model actors, `tool` for tool-based actors. | | `config.provider` | string | Yes (LLM) | LLM provider identifier: `openai`, `anthropic`, `google`, `azure`, `openrouter`, etc. | | `config.model` | string | Yes (LLM) | Model identifier within the provider: `gpt-4`, `claude-3.5-sonnet`, `gemini-pro`, etc. | | `config.actor` | string | No | Combined `provider/model` format. Alternative to specifying `provider` and `model` separately. | | `config.system_prompt` | string | No | System prompt text. Supports Jinja2 template syntax for dynamic content. | | `config.temperature` | float | Provider default | Sampling temperature (0.0 to 2.0). Lower values are more deterministic. | | `config.max_tokens` | integer | Provider default | Maximum number of tokens in the generated response. | | `config.memory_enabled` | boolean | `false` | Enable conversation memory for multi-turn interactions. | | `config.max_history` | integer | `50` | Maximum number of conversation turns retained in memory. | | `config.unsafe` | boolean | `false` | Allow this specific actor to perform unsafe operations. | | `config.options` | object | `{}` | Provider-specific options passed through to the underlying LLM API. | | `config.tools` | list | Yes (tool) | List of inline tool definitions for tool-type actors. Each tool has `name` and `code`. | | `config.response_format` | object | No | JSON schema for structured output from the LLM. Constrains model output to match the schema. | | `skills` | list | No | List of namespaced skill names (e.g., `local/file-ops`) providing tool capabilities to the actor. | | `lsp` | list or object | No | LSP server binding. List of namespaced server names (explicit mode), object with `languages` list (language-based mode), or object with `auto: true` (auto-discovery mode). | | `lsp_capabilities` | string or list | No | Which LSP capabilities to expose. `"all"` (default) or a list from: `diagnostics`, `hover`, `completions`, `references`, `definitions`, `symbols`, `formatting`, `code_actions`, `rename`. | | `lsp_context_enrichment` | object | No | ACMS context enrichment from LSP. Fields: `diagnostics` (bool), `type_annotations` (bool), `max_diagnostics_per_file` (int, default 50). | **Node Types (Graph Routes)** | Type | Description | |------|-------------| | `agent` | A node backed by an actor. Requires `agent` field pointing to an actor name. | | `function` | A node backed by a Python function. Requires `function` field. | | `tool` | A node that invokes one or more tools. Requires `tools` list. | | `conditional` | A branching node that routes based on conditions. Requires `condition` field. | | `subgraph` | A node that delegates to another graph route. Requires `subgraph` field. | | `start` | The explicit start node (alternative to `entry_point`). | | `end` | A terminal node that ends graph execution. | | `message_router` | Routes messages to different nodes based on message content or metadata. | #### Examples **Example 1: Minimal Chat Actor (Simple)** A bare-minimum actor configuration for a simple conversational agent:

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

name: local/chat

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

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

merges:
  - sources: [output]
    target: final
This is the simplest possible actor: one LLM actor, one stream route, one merge. No graph complexity, no tools, no templates. --- **Example 2: Code Reviewer with Tools (Medium)** An actor that can read files and search code to perform code reviews:

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

name: local/reviewer

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

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

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

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

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

merges:
  - sources: [review_output]
    target: final
This actor defines an LLM reviewer and a file-reading tool, connected via a graph route with conditional edges. --- **Example 3: Multi-Agent Research Pipeline with Templates (Complex)** A complex actor configuration with multiple LLM actors, Jinja2 templates, environment variable interpolation, memory, and hybrid routing:

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

name: local/research

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

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

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

        {% if context.deadline %}
        Deadline: {{ 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}

        - name: fetch_url
          code: |
            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](adr/ADR-032-jinja2-yaml-template-preprocessing.md) 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](adr/ADR-032-jinja2-yaml-template-preprocessing.md) 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](adr/ADR-012-skill-system.md). 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 `. #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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 `/` 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](adr/ADR-006-plan-lifecycle.md). 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 `. #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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 `/` format. This value is used as the action's registered name. | | `description` | string | Yes | Short (one-line) description of the action. | | `long_description` | string | No | Detailed multi-line description explaining purpose, usage, and expected outcomes. | | `strategy_actor` | string | Yes | Actor to use during the Strategize phase. Must reference a registered actor. | | `execution_actor` | string | Yes | Actor to use during the Execute phase. Must reference a registered actor. | | `estimation_actor` | string | No | Actor to use for effort and cost estimation before execution. | | `review_actor` | string | No | Actor to use for reviewing execution results. | | `apply_actor` | string | No | Actor to use during the Apply phase. | | `invariant_actor` | string | No | Actor for reconciling conflicting invariants across scopes. Carried forward to plans. | | `definition_of_done` | string | Yes | Clear, measurable criteria that define when the action's work is complete. | | `reusable` | boolean | No | Whether the action persists after being used. Default: `true`. | | `read_only` | boolean | No | Whether the action is restricted to read-only operations. Default: `false`. | | `state` | string | No | State of the action: `available` or `archived`. Default: `available`. | | `arguments` | list | No | Typed parameters that users supply when using the action. | | `automation_profile` | string | No | Default automation profile for plans created from this action. | | `invariants` | list | No | Constraints carried forward as plan-level invariants when the action is used. | **Argument Fields (`arguments[]`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | Yes | Argument name. Used as the key in `--arg name=value`. | | `type` | string | Yes | Data type: `string`, `integer`, `float`, `boolean`, `list`. | | `required` | boolean | No | Whether the argument must be provided. Default: `false`. | | `description` | string | No | Human-readable description shown in help text and `agents action show`. | | `default` | any | No | Default value when the argument is not provided. Type must match `type`. | | `validation_pattern` | string | No | Regex pattern for validating string arguments. | | `min_value` | number | No | Minimum acceptable value for `integer` and `float` arguments. | | `max_value` | number | No | Maximum acceptable value for `integer` and `float` arguments. | #### Examples **Example 1: Simple Linting Action (Simple)** A minimal action for running linters on a project:

# lint-check.yaml
# Create: agents action create --config lint-check.yaml

name: local/lint-check
description: "Run linting checks on the project"

strategy_actor: local/strategist
execution_actor: local/executor

definition_of_done: |
  All linting checks pass with zero errors.

reusable: true
read_only: true
state: available
Usage: `agents plan use local/lint-check local/api-service` --- **Example 2: Code Coverage Action with Arguments (Medium)** An action with typed arguments, invariants, and a specific automation profile:

# code-coverage.yaml
# Create: agents action create --config code-coverage.yaml

name: local/code-coverage
description: "Increase test coverage to a target percentage"
long_description: |
  Analyzes the current test coverage of a project, identifies
  modules with low coverage, and generates comprehensive test
  suites to meet the target coverage percentage.

  The action prioritizes:
  1. Business-critical modules (auth, payments)
  2. Recently modified code
  3. Error-prone areas based on git history

strategy_actor: local/strategist
execution_actor: local/executor
estimation_actor: local/estimator

definition_of_done: |
  Test coverage reaches the target_coverage_percent threshold
  across all specified modules. All generated tests pass.
  No existing tests are broken by the changes.

reusable: true
read_only: false
arguments:
  - name: target_coverage_percent
    type: integer
    required: true
    description: "Target test coverage percentage (1-100)"
    min_value: 1
    max_value: 100

  - name: test_command
    type: string
    required: false
    description: "Test framework command to use"
    default: "pytest --cov"

  - name: exclude_patterns
    type: list
    required: false
    description: "File patterns to exclude from coverage analysis"
    default: ["**/migrations/**", "**/conftest.py"]

  - name: focus_modules
    type: list
    required: false
    description: "Specific modules to prioritize for coverage"

automation_profile: trusted

invariants:
  - "Generated tests must not import production secrets or credentials"
  - "Test files must follow the project's existing test naming conventions"
  - "All database interactions in tests must use mocks or fixtures"
Usage: `agents plan use local/code-coverage local/api-service --arg target_coverage_percent=85` --- **Example 3: Security Audit Action (Complex)** A comprehensive security audit action with multiple actors, extensive arguments, and strong invariants:

# security-audit.yaml
# Create: agents action create --config security-audit.yaml

name: local/security-audit
description: "Comprehensive security audit of a project"
long_description: |
  Performs a thorough security audit covering:
  - Dependency vulnerability scanning (CVEs)
  - Static Application Security Testing (SAST)
  - Authentication and authorization review
  - Input validation and injection prevention
  - Secrets detection and credential scanning
  - API security (rate limiting, CORS, headers)
  - Data handling and privacy compliance

  Generates a detailed report with severity ratings (Critical,
  High, Medium, Low, Informational) and remediation guidance.
  Optionally creates fix plans for identified issues.

strategy_actor: local/security-strategist
execution_actor: local/security-scanner
estimation_actor: local/estimator
review_actor: local/security-reviewer
invariant_actor: local/invariant-resolver

definition_of_done: |
  All critical and high severity findings have been identified.
  A complete security report has been generated with:
  - Severity classification for each finding
  - Remediation steps for each finding
  - Risk score for the overall project
  If auto_fix is enabled, all critical findings have remediation
  plans created as child plans.

reusable: true
read_only: false
state: available

arguments:
  - name: severity_threshold
    type: string
    required: false
    description: "Minimum severity to include in report"
    default: "low"
    validation_pattern: "^(critical|high|medium|low|informational)$"

  - name: auto_fix
    type: boolean
    required: false
    description: "Automatically create fix plans for critical findings"
    default: false

  - name: scan_dependencies
    type: boolean
    required: false
    description: "Include dependency vulnerability scanning"
    default: true

  - name: compliance_frameworks
    type: list
    required: false
    description: "Compliance frameworks to check against"
    default: ["owasp-top-10"]

  - name: max_findings
    type: integer
    required: false
    description: "Maximum number of findings to report"
    default: 100
    min_value: 1
    max_value: 1000

  - name: ignore_paths
    type: list
    required: false
    description: "Paths to exclude from scanning"
    default: ["**/node_modules/**", "**/vendor/**", "**/.git/**"]

automation_profile: supervised

invariants:
  - "Never modify production database schemas during audit"
  - "Never execute discovered exploit code against live systems"
  - "All findings must include reproducible steps"
  - "Secrets found during scanning must be redacted in reports"
  - "Remediation fixes must not break existing tests"
Usage: `agents plan use local/security-audit local/api-service local/web-app --arg auto_fix=true --arg severity_threshold=medium` --- **Example 4: Database Migration Action (Medium)** An action for managing database schema migrations:

# db-migrate.yaml
# Create: agents action create --config db-migrate.yaml

name: local/db-migrate
description: "Plan and execute database schema migrations"

strategy_actor: local/db-strategist
execution_actor: local/db-executor

definition_of_done: |
  All migration scripts are generated and pass dry-run validation.
  Rollback scripts are generated for each migration.
  The migration can be applied without data loss.

reusable: true
read_only: false

arguments:
  - name: migration_tool
    type: string
    required: false
    description: "Migration tool to use"
    default: "alembic"
    validation_pattern: "^(alembic|flyway|django|knex)$"

  - name: dry_run
    type: boolean
    required: false
    description: "Only generate and validate, do not apply"
    default: true

  - name: target_schema
    type: string
    required: false
    description: "Target schema version identifier"

automation_profile: supervised

invariants:
  - "All migrations must include corresponding rollback scripts"
  - "Data migrations must preserve existing data integrity"
  - "Schema changes must maintain backward compatibility for 24 hours"
--- ### Tool Configuration Files !!! adr "Architecture Decision" The tool configuration schema, source types, and capability metadata are defined in [ADR-011: Tool System](adr/ADR-011-tool-system.md). 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 ` and can then be referenced by name in skills and actor graphs. #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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 `/` format. This value is used as the tool's registered name. | | `description` | string | Yes | Human-readable description of the tool's purpose and behavior. | | `source` | string | Yes | Tool source type. Determines which implementation fields are required: `custom` (inline Python), `mcp` (MCP server), `agent_skill` (SKILL.md folder), `builtin` (first-party operations). | | `code` | string | Conditional | Python code implementing the tool. Required when `source` is `custom`. Must define a `run(input_data)` function that accepts a dict and returns a dict. | | `mcp_server` | string | Conditional | Name of the MCP server exposing this tool. Required when `source` is `mcp`. | | `mcp_tool_name` | string | Conditional | Name of the tool on the MCP server. Required when `source` is `mcp`. | | `agent_skill_path` | string | Conditional | Path to the Agent Skills Standard folder containing `SKILL.md`. Required when `source` is `agent_skill`. | | `input_schema` | object | No | JSON Schema describing the tool's input parameters. Strongly recommended for all tools. | | `output_schema` | object | No | JSON Schema describing the tool's output format. | **Capability Metadata Fields** | Field | Type | Default | Description | |-------|------|---------|-------------| | `writes` | boolean | `false` | Whether the tool performs any write operations (file writes, database mutations, API calls with side effects). | | `write_scope` | string | — | Describes the scope of write operations, e.g. `"filesystem"`, `"database:migrations"`, `"api:github"`. Used for access checks and audit logging. | | `checkpointable` | boolean | `false` | Whether the tool supports checkpointing — the ability to save state before execution and restore it on failure. | | `checkpoint_scope` | string | — | The checkpointing strategy: `file` (file-level backup), `transaction` (database transaction), `snapshot` (full state snapshot), `composite` (multi-resource checkpoint). | | `side_effects` | list | `[]` | Descriptions of side effects that cannot be undone by checkpointing alone, e.g. `"network_call"`, `"schema_mutation"`, `"email_sent"`, `"process_spawn"`. | | `idempotent` | boolean | `false` | Whether the tool is safe to retry — calling it multiple times with the same input produces the same result. | | `read_only` | boolean | `false` | Whether the tool only reads data without modifying anything. When `true`, `writes` must be `false`. | | `unsafe` | boolean | `false` | Whether the tool is flagged as unsafe. Unsafe tools require `allow_unsafe_tools: true` in the automation profile. | | `timeout` | integer | `300` | Default execution timeout in seconds. Can be overridden per invocation. | **Resource Slot Fields (`resource_slots[]`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | Yes | Identifier for this resource slot, used for reference in code and logs. | | `resource_type` | string | Yes | The resource type this slot requires, e.g. `git-checkout`, `fs-directory`, `fs-file`. | | `access` | string | Yes | Access level: `read_only` or `read_write`. | | `description` | string | No | Human-readable description of how the tool uses this resource. | | `binding` | string | No | How the slot is resolved at runtime. `contextual` (default): resolved from the plan's project. `static`: hardcoded to a specific resource. `parameter`: passed as a tool argument at invocation time. | | `static_resource` | string | Conditional | Fully qualified name of a specific resource. Required when `binding` is `static`. | **Lifecycle Hook Fields (`lifecycle`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `discover` | string | No | Code or function name run during tool discovery to check prerequisites and report capabilities. | | `activate` | string | No | Code or function name run when the tool is activated (e.g., establish connections, validate credentials). | | `deactivate` | string | No | Code or function name run when the tool is deactivated (e.g., close connections, release resources). | #### Examples **Example 1: Simple Read-Only Tool (Simple)** A tool that reads a file and returns its contents:

# read-config-file.yaml
# Register: agents tool add --config read-config-file.yaml

name: local/read-config
description: "Read and parse a configuration file (JSON, YAML, or TOML)"

source: custom
code: |
  import json, os
  def run(input_data):
      path = input_data["path"]
      if not os.path.exists(path):
          return {"error": f"File not found: {path}", "success": False}
      with open(path, "r") as f:
          content = f.read()
      ext = os.path.splitext(path)[1].lower()
      if ext == ".json":
          parsed = json.loads(content)
      elif ext in (".yaml", ".yml"):
          import yaml
          parsed = yaml.safe_load(content)
      else:
          parsed = None
      return {"content": content, "parsed": parsed, "path": path, "success": True}

input_schema:
  type: object
  properties:
    path:
      type: string
      description: "Path to the configuration file"
  required: ["path"]

output_schema:
  type: object
  properties:
    content:
      type: string
    parsed:
      type: object
    success:
      type: boolean

writes: false
read_only: true
idempotent: true
--- **Example 2: Database Migration Tool (Medium)** A tool that runs database migrations with rollback support:

# run-migrations.yaml
# Register: agents tool add --config run-migrations.yaml

name: local/run-migrations
description: "Run database migrations with direction control and rollback support"

source: custom
code: |
  import subprocess
  def run(input_data):
      direction = input_data.get("direction", "up")
      count = input_data.get("count", 1)
      dry_run = input_data.get("dry_run", False)

      cmd = ["alembic"]
      if dry_run:
          cmd.append("--sql")
      cmd.extend([direction, str(count)])

      result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
      return {
          "success": result.returncode == 0,
          "stdout": result.stdout,
          "stderr": result.stderr,
          "direction": direction,
          "count": count,
          "dry_run": dry_run,
          "return_code": result.returncode
      }

input_schema:
  type: object
  properties:
    direction:
      type: string
      enum: ["up", "down"]
      description: "Migration direction: 'up' to apply, 'down' to rollback"
    count:
      type: integer
      default: 1
      minimum: 1
      maximum: 50
      description: "Number of migrations to run"
    dry_run:
      type: boolean
      default: false
      description: "Generate SQL without executing"
  required: ["direction"]

writes: true
write_scope: "database:migrations"
checkpointable: true
checkpoint_scope: "transaction"
side_effects:
  - "schema_mutation"
idempotent: false
timeout: 120

resource_slots:
  - name: database
    resource_type: "local/database"
    access: read_write
    description: "The database to run migrations against"
    binding: contextual
--- **Example 3: MCP-Backed GitHub Tool (Simple)** A tool that delegates to a GitHub MCP server:

# github-create-issue.yaml
# Register: agents tool add --config github-create-issue.yaml

name: local/github-create-issue
description: "Create a GitHub issue via the GitHub MCP server"

source: mcp
mcp_server: github
mcp_tool_name: create_issue

input_schema:
  type: object
  properties:
    owner:
      type: string
      description: "Repository owner"
    repo:
      type: string
      description: "Repository name"
    title:
      type: string
      description: "Issue title"
    body:
      type: string
      description: "Issue body (Markdown)"
    labels:
      type: array
      items:
        type: string
      description: "Labels to apply"
  required: ["owner", "repo", "title"]

writes: true
write_scope: "api:github"
checkpointable: false
side_effects:
  - "network_call"
idempotent: false
--- **Example 4: Deployment Tool with Resource Bindings (Complex)** A comprehensive deployment tool with multiple resource slots, lifecycle hooks, and safety metadata:

# deploy-staging.yaml
# Register: agents tool add --config deploy-staging.yaml

name: local/deploy-staging
description: "Deploy the current build to the staging environment with health checks"

source: custom
code: |
  import subprocess, time, urllib.request, json

  def run(input_data):
      service = input_data["service"]
      version = input_data.get("version", "latest")
      wait_healthy = input_data.get("wait_healthy", True)
      health_timeout = input_data.get("health_timeout", 120)

      # Build the deployment command
      cmd = ["kubectl", "set", "image",
             f"deployment/{service}",
             f"{service}={service}:{version}",
             "--namespace=staging"]
      result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
      if result.returncode != 0:
          return {"success": False, "error": result.stderr, "phase": "deploy"}

      # Wait for rollout
      rollout = subprocess.run(
          ["kubectl", "rollout", "status", f"deployment/{service}",
           "--namespace=staging", f"--timeout={health_timeout}s"],
          capture_output=True, text=True, timeout=health_timeout + 10
      )
      if rollout.returncode != 0:
          return {"success": False, "error": rollout.stderr, "phase": "rollout"}

      # Health check
      if wait_healthy:
          health_url = f"http://{service}.staging.svc.cluster.local/health"
          start = time.time()
          while time.time() - start < health_timeout:
              try:
                  resp = urllib.request.urlopen(health_url, timeout=5)
                  if resp.status == 200:
                      body = json.loads(resp.read())
                      if body.get("status") == "healthy":
                          return {
                              "success": True,
                              "service": service,
                              "version": version,
                              "health": body
                          }
              except Exception:
                  pass
              time.sleep(5)
          return {"success": False, "error": "Health check timeout", "phase": "health"}

      return {"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"}

      try:
          breaking = json.loads(diff_result.stdout)
      except json.JSONDecodeError:
          breaking = [{"description": diff_result.stdout}]

      return {
          "compatible": False,
          "changes": breaking,
          "reason": 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](adr/ADR-013-validation-abstraction.md). 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 `. **Read-only enforcement**: Validations are always read-only. The `writes` and `checkpointable` fields are always forced to `false` regardless of what the YAML file specifies — if a validation YAML includes `writes: true` or `checkpointable: true`, these values are silently overridden to `false` at registration time. Because this is enforced, it is idiomatic to omit `read_only`, `writes`, and `checkpointable` from validation YAML files entirely (they are unnecessary). The examples below include `read_only: true` for documentation clarity, but it is not required. **Shared namespace**: The `name` field in a validation YAML occupies the same namespace as tools. Registration will fail if a tool with the same name already exists. #### Validation-Specific Fields In addition to all fields from the Tool Configuration schema, a Validation YAML adds: | Field | Type | Default | Description | |-------|------|---------|-------------| | `validation.mode` | string | `"required"` | `"required"` or `"informational"`. Required validations must pass for execution to proceed; informational validations report results without blocking. | | `wraps` | string | (none) | Name of an existing registered Tool to wrap. When set, the Validation delegates execution to the wrapped Tool and passes its output through the `transform` function. Mutually exclusive with `source` and `code`. | | `transform` | string | (none) | Python function that converts the wrapped Tool's output to the Validation return format. Required when `wraps` is set (unless the wrapped Tool already returns validation-format output). The function receives the Tool's output as its argument and must return `{ "passed": bool, ... }`. | | `argument_mapping` | object | (none) | Dictionary mapping the wrapped Tool's input parameter names to either a Validation input parameter name (string) or a fixed literal value. When present, only mapped arguments are forwarded to the wrapped Tool. When absent, the Validation's input arguments are passed through unchanged. Only valid when `wraps` is set. | When `wraps` is used, the `source` and `code` fields must be omitted — the Validation's implementation is the wrapped Tool plus the transform. The Validation inherits the wrapped Tool's `input_schema`, `resource_slots`, and `timeout` unless explicitly overridden. When the Validation defines a custom `input_schema`, an `argument_mapping` should be provided to specify how the Validation's inputs map to the wrapped Tool's expected inputs. See the **Tool Wrapping** subsection under Core Concepts > Validation for full semantics. The output of a validation tool must conform to a structured JSON format: | Field | Type | Required | Description | |-------|------|----------|-------------| | `passed` | boolean | Yes | Whether the validation passed (`true`) or failed (`false`). | | `message` | string | No | Human-readable summary of the validation result. | | `data` | object | No | Arbitrary structured data in any format the validation chooses to convey informational output about the result. | #### Examples **Example 1: Unit Test Validation (Required)**

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

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

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

validation:
  mode: required

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

read_only: true
idempotent: true
timeout: 600

resource_slots:
  - name: repo
    resource_type: git-checkout
    access: read_only
    binding: contextual
--- **Example 2: Lint Check Validation (Required, Simple)**

# validations/lint-check.yaml

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

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

validation:
  mode: required

read_only: true
idempotent: true
timeout: 300
--- **Example 3: Bundle Size Check (Informational)**

# validations/check-bundle-size.yaml

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

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

validation:
  mode: informational

read_only: true
timeout: 120
--- **Example 4: MCP-Backed Validation** A validation that uses an MCP server to perform security scanning:

# validations/security-scan.yaml

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

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

validation:
  mode: required

read_only: true
timeout: 300
--- **Example 5: Wrapping an Existing Tool** A validation that wraps an existing `local/run-tests` tool, reusing its implementation and interpreting its output as pass/fail. No test-running logic is duplicated — only the pass/fail interpretation is defined.

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

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

wraps: local/run-tests

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

validation:
  mode: required

timeout: 600
Note: `source`, `code`, `input_schema`, and `resource_slots` are omitted — they are inherited from the wrapped `local/run-tests` tool. Only the `transform`, `validation.mode`, and optional overrides (like `timeout`) are needed. If the Validation defines a custom `input_schema`, an `argument_mapping` should also be provided to map the Validation's inputs to the wrapped Tool's expected inputs. --- **Example 6: Wrapping with Different Interpretation (Informational)** A second validation wrapping the same tool but extracting a different signal — coverage threshold — as an advisory check:

# validations/coverage-check.yaml

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

wraps: local/run-tests

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

validation:
  mode: informational
--- ### Resource Type Configuration Files !!! adr "Architecture Decision" The resource type system, custom type registration, and type hierarchy are defined in [ADR-008: Resource System](adr/ADR-008-resource-system.md). 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 ` 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 `. #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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 `/` 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 `. 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 `_replace: true` to replace entirely. Single inheritance only; maximum chain depth of 5. See [ADR-042](adr/ADR-042-resource-type-inheritance.md). | | `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 `--` on the CLI. | | `type` | string | Yes | Argument type: `string`, `path`, `integer`, `boolean`, `url`. The `path` type validates that the path exists; `url` type validates URL format. | | `required` | boolean | No | Whether the argument must be provided. Default: `false`. | | `description` | string | No | Description shown in `--help` and `agents resource type show`. | | `default` | any | No | Default value when the argument is not provided. | | `validation_pattern` | string | No | Regex pattern for validating `string` and `url` type arguments. | **Child Type Fields (`child_types[]`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `type` | string | Yes | Name of the allowed child resource type (e.g., `fs-directory`, `svn-file`). | | `auto_discover` | boolean | No | Whether children of this type are automatically created when the parent resource is registered. Default: `false`. | | `manual_link` | boolean | No | Whether manual `agents resource link-child` is allowed for this relationship. Default: `true`. | | `description` | string | No | Description of the parent-child relationship. | | `max_count` | integer | No | Maximum number of children of this type. `null` or omitted means unlimited. | **Parent Type Fields (`parent_types[]`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `type` | string | Yes | Name of the allowed parent resource type. | | `description` | string | No | Description of the parent-child relationship from the child's perspective. | **Handler Fields (`handler`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `class` | string | Yes | Python class name that implements the resource handler interface. | | `module` | string | Yes | Python module path where the handler class is defined. | | `config` | object | No | Arbitrary configuration passed to the handler constructor. | **Auto-Discovery Fields (`auto_discovery`)** | Field | Type | Required | Description | |-------|------|----------|-------------| | `enabled` | boolean | No | Whether auto-discovery runs when a resource of this type is created. Default: `true`. | | `scan_depth` | integer | No | Maximum recursion depth for scanning. Default: `3`. | | `include_patterns` | list | No | Glob patterns for resources to discover. | | `exclude_patterns` | list | No | Glob patterns for resources to skip during discovery. | **Equivalence Fields (`equivalence`) — Virtual Types Only** | Field | Type | Required | Description | |-------|------|----------|-------------| | `criteria` | list | Yes (virtual) | Fields used to determine whether two physical resources are equivalent. Common criteria: `content_hash`, `filename`, `permissions`, `url`, `commit_hash`, `tree_hash`. | | `description` | string | No | Human-readable description of the equivalence rule. | **Built-in Sandbox Strategies** | Strategy | Description | |----------|-------------| | `git_worktree` | Creates a git worktree for isolated execution. Changes are committed to a branch and merged on apply. | | `copy_on_write` | Creates a CoW copy of the resource. Changes are applied by replacing the original. | | `transaction_rollback` | Wraps operations in a database transaction. Rolled back on failure, committed on apply. | | `snapshot` | Takes a full snapshot before execution. Restored on rollback. | | `none` | No sandbox. Changes are applied directly. Use only for read-only or idempotent operations. | #### Examples **Example 1: Simple SVN Repository Type (Simple)** A custom resource type for Subversion repositories:

# svn-type.yaml
# Register: agents resource type add --config svn-type.yaml

name: local/svn
description: "A Subversion (SVN) repository checkout"

physical: true
user_addable: true

cli_args:
  - name: url
    type: url
    required: true
    description: "SVN repository URL"
    validation_pattern: "^svn(\\+ssh)?://.*|^https?://.*"
  - name: checkout-path
    type: path
    required: true
    description: "Local checkout directory"
  - name: revision
    type: string
    required: false
    description: "Specific revision to checkout"
    default: "HEAD"

child_types:
  - type: fs-directory
    auto_discover: true
    description: "Working copy directory tree"
  - type: local/svn-revision
    auto_discover: true
    description: "SVN revision history"

sandbox_strategy: copy_on_write

handler:
  class: SVNHandler
  module: cleveragents.resource.handlers.svn
  config:
    svn_binary: "svn"
    trust_server_cert: true

auto_discovery:
  enabled: true
  scan_depth: 2
  exclude_patterns:
    - "**/.svn/**"
Usage: `agents resource add local/svn local/legacy-repo --url svn://svn.example.com/trunk --checkout-path /repos/legacy` --- **Example 2: S3 Bucket Resource Type (Medium)** A resource type for Amazon S3 buckets with prefix-based child discovery:

# s3-bucket-type.yaml
# Register: agents resource type add --config s3-bucket-type.yaml

name: local/s3-bucket
description: "An Amazon S3 bucket with prefix-based object organization"

physical: true
user_addable: true

cli_args:
  - name: bucket
    type: string
    required: true
    description: "S3 bucket name"
    validation_pattern: "^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$"
  - name: region
    type: string
    required: false
    description: "AWS region"
    default: "us-east-1"
  - name: prefix
    type: string
    required: false
    description: "Key prefix to scope resource to a 'subdirectory'"
    default: ""
  - name: profile
    type: string
    required: false
    description: "AWS CLI profile name"
    default: "default"

child_types:
  - type: local/s3-prefix
    auto_discover: true
    description: "S3 key prefixes (virtual directories)"
    max_count: 1000
  - type: local/s3-object
    auto_discover: true
    description: "S3 objects (files)"

sandbox_strategy: copy_on_write

handler:
  class: S3BucketHandler
  module: cleveragents.resource.handlers.s3
  config:
    max_object_size: 104857600  # 100 MB
    default_acl: "private"

auto_discovery:
  enabled: true
  scan_depth: 3
  include_patterns:
    - "**/*.json"
    - "**/*.yaml"
    - "**/*.yml"
    - "**/*.py"
    - "**/*.sql"
  exclude_patterns:
    - "**/*.log"
    - "**/*.tmp"
    - "**/node_modules/**"
--- **Example 3: Database Resource Type (Medium)** A resource type for relational databases:

# database-type.yaml
# Register: agents resource type add --config database-type.yaml

name: local/database
description: "A relational database (PostgreSQL, MySQL, SQLite)"

physical: true
user_addable: true

cli_args:
  - name: connection-string
    type: string
    required: true
    description: "Database connection string (e.g., postgresql://user:pass@host/db)"
  - name: engine
    type: string
    required: false
    description: "Database engine"
    default: "postgresql"
    validation_pattern: "^(postgresql|mysql|sqlite|mssql)$"
  - name: read-only
    type: boolean
    required: false
    description: "Connect in read-only mode"
    default: false
  - name: schema
    type: string
    required: false
    description: "Database schema to scope to"
    default: "public"

child_types:
  - type: local/db-table
    auto_discover: true
    description: "Database tables"
  - type: local/db-view
    auto_discover: true
    description: "Database views"
  - type: local/db-migration
    auto_discover: false
    manual_link: true
    description: "Migration scripts linked to this database"

parent_types:
  - type: git-checkout
    description: "Repository containing the application that owns this database"

sandbox_strategy: transaction_rollback

handler:
  class: DatabaseHandler
  module: cleveragents.resource.handlers.database
  config:
    connection_pool_size: 5
    statement_timeout: 30000  # 30 seconds
    log_queries: true

auto_discovery:
  enabled: true
  scan_depth: 1
--- **Example 4: Virtual File Type (Simple)** A virtual resource type that links equivalent physical files across repositories:

# virtual-config-file-type.yaml
# Register: agents resource type add --config virtual-config-file-type.yaml

name: local/config-file
description: "Virtual type linking equivalent configuration files across repositories"

physical: false
user_addable: false

child_types:
  - type: fs-file
    auto_discover: false
    manual_link: true
    description: "Physical file instances"
  - type: git-tree-entry
    auto_discover: false
    manual_link: true
    description: "Git tree entries representing the same config file"

sandbox_strategy: none

handler:
  class: VirtualConfigFileHandler
  module: cleveragents.resource.handlers.virtual_config
  config:
    track_content_drift: true

equivalence:
  criteria:
    - content_hash
    - filename
  description: "Two physical resources represent the same config file when they share the same filename and content hash"
--- **Example 5: Docker Registry Resource Type (Complex)** A resource type for Docker container registries with full auto-discovery and lifecycle hooks:

# docker-registry-type.yaml
# Register: agents resource type add --config docker-registry-type.yaml

name: local/docker-registry
description: "A Docker container registry with image and tag discovery"

physical: true
user_addable: true

cli_args:
  - name: registry-url
    type: url
    required: true
    description: "Docker registry URL (e.g., registry.example.com, ghcr.io/org)"
    validation_pattern: "^[a-zA-Z0-9][a-zA-Z0-9.-]+(:[0-9]+)?(/[a-zA-Z0-9._-]+)*$"
  - name: username
    type: string
    required: false
    description: "Registry username for authentication"
  - name: password-env
    type: string
    required: false
    description: "Environment variable name containing the registry password"
  - name: namespace
    type: string
    required: false
    description: "Image namespace or organization filter"

child_types:
  - type: local/docker-image
    auto_discover: true
    description: "Docker images in the registry"
    max_count: 500
  - type: local/docker-tag
    auto_discover: true
    description: "Image tags"

sandbox_strategy: none

handler:
  class: DockerRegistryHandler
  module: cleveragents.resource.handlers.docker
  config:
    api_version: "v2"
    page_size: 100
    cache_ttl: 300

auto_discovery:
  enabled: true
  scan_depth: 2
  include_patterns:
    - "**/latest"
    - "**/main"
    - "**/release-*"
  exclude_patterns:
    - "**/sha256:*"
     - "**/*-dirty"
**Example 6: Devcontainer Instance Resource Type (Inherited)** This example demonstrates the `devcontainer-instance` type, which inherits from `container-instance` via the resource type inheritance mechanism ([ADR-042](adr/ADR-042-resource-type-inheritance.md)). Fields not shown here are inherited from the parent type. Only the additional fields and overrides specific to devcontainer semantics are defined.
# devcontainer-instance inherits from container-instance (ADR-039)
# See ADR-042 for inheritance rules, ADR-043 for devcontainer lifecycle

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

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

handler: "DevcontainerHandler"

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

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

auto_discovery:
  enabled: true
  parent_types:
    - "git-checkout"
  detection:
    scan_paths:
      - ".devcontainer/devcontainer.json"
      - ".devcontainer.json"
    activation: "lazy"
    # Container is NOT built at discovery time.
    # State remains "detected" until the execution environment router
    # selects this devcontainer for tool execution.
--- ### Context View Configuration !!! adr "Architecture Decision" The context view configuration, resource filtering, and phase-specific context assembly are defined in [ADR-014: Context Management (ACMS)](adr/ADR-014-context-management-acms.md). 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](https://json-schema.org/) 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: 1. Check for a phase-specific view (e.g., `strategize`). 2. Fall back to the `default` view. 3. Fall back to system defaults (include all resources, no path filtering, default budgets). #### Examples **Example 1: Basic Default View (Simple)** A default context view with minimal filtering:

# context-default.yaml
# Apply: agents project context set --view default --include-path "src/**" \
#        --exclude-path "**/node_modules/**" local/api-service
# Or import this file and apply via the CLI.

project: local/api-service
view: default

exclude_paths:
  - "**/node_modules/**"
  - "**/__pycache__/**"
  - "**/.git/**"

max_file_size: 1048576   # 1 MB
--- **Example 2: Strategize-Optimized View (Medium)** A focused view for the Strategize phase that limits context to essential architecture files:

# context-strategize.yaml

project: local/api-service
view: strategize

include_resources:
  - local/api-repo

exclude_resources:
  - local/staging-db

include_paths:
  - "src/**/*.py"
  - "docs/architecture/**"
  - "README.md"
  - "pyproject.toml"

exclude_paths:
  - "**/node_modules/**"
  - "**/test_fixtures/**"
  - "**/__pycache__/**"
  - "**/migrations/**"

hot_max_tokens: 12000
warm_max_decisions: 50
cold_max_decisions: 200
query_limit: 20

max_file_size: 524288     # 512 KB
max_total_size: 10485760  # 10 MB

summarize: true
summary_max_tokens: 800
This view keeps the Strategize phase focused on source code and architecture docs, limits hot context to 12K tokens, and enables summarization for files that exceed the size limits. --- **Example 3: Execute-Phase View with Full Resources (Medium)** An execution view with broader access for implementing changes:

# context-execute.yaml

project: local/api-service
view: execute

include_resources:
  - local/api-repo
  - local/staging-db

include_paths:
  - "src/**"
  - "tests/**"
  - "config/**"
  - "scripts/**"
  - "Makefile"
  - "pyproject.toml"
  - "requirements*.txt"

exclude_paths:
  - "**/node_modules/**"
  - "**/__pycache__/**"
  - "**/dist/**"
  - "**/*.pyc"

hot_max_tokens: 24000
warm_max_decisions: 100
cold_max_decisions: 500
query_limit: 30

max_file_size: 2097152     # 2 MB
max_total_size: 104857600  # 100 MB

summarize: true
summary_max_tokens: 1200
--- **Example 4: Apply-Phase Minimal View (Simple)** A minimal view for the Apply phase, focused only on changed files and validation:

# context-apply.yaml

project: local/api-service
view: apply

include_paths:
  - "src/**"
  - "tests/**"

exclude_paths:
  - "**/__pycache__/**"

hot_max_tokens: 8000
warm_max_decisions: 20
cold_max_decisions: 50

summarize: false
--- **Example 5: Large Monorepo View with Aggressive Filtering (Complex)** A context view designed for a large monorepo where careful filtering is essential:

# context-monorepo-strategize.yaml

project: local/platform
view: strategize

include_resources:
  - local/platform-repo

include_paths:
  - "packages/auth/**/*.ts"
  - "packages/auth/**/*.tsx"
  - "packages/shared/**/*.ts"
  - "packages/api-gateway/**/*.ts"
  - "docs/architecture/**"
  - "package.json"
  - "tsconfig.json"
  - "lerna.json"

exclude_paths:
  - "**/node_modules/**"
  - "**/dist/**"
  - "**/coverage/**"
  - "**/*.test.ts"
  - "**/*.spec.ts"
  - "**/*.stories.tsx"
  - "**/fixtures/**"
  - "**/__snapshots__/**"
  - "**/generated/**"

hot_max_tokens: 16000
warm_max_decisions: 30
cold_max_decisions: 150
query_limit: 15

max_file_size: 262144     # 256 KB - aggressive for a monorepo
max_total_size: 5242880   # 5 MB

summarize: true
summary_max_tokens: 600
This configuration is tailored for a TypeScript monorepo, focusing on specific packages and excluding generated code, tests, and build artifacts to keep context within manageable bounds. --- ### Automation Profile Configuration Files !!! adr "Architecture Decision" The automation profile configuration schema, threshold model, and built-in profiles are defined in [ADR-017: Automation Profiles](adr/ADR-017-automation-profiles.md). 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 `. #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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.yaml

name: local/careful-auto
description: "Autonomous execution with mandatory sandbox and manual apply"

decompose_task: 0.0
create_tool: 0.0
select_tool: 1.0

edit_code: 0.0
execute_command: 0.0

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

install_dependency: 0.0

require_sandbox: true
require_checkpoints: true
allow_unsafe_tools: false
This is essentially the `auto` built-in profile but with `approve_plan` set to 0.0 (always automatic) for more aggressive self-repair. --- **Example 2: CI/CD Pipeline Profile (Medium)** A profile designed for automated CI/CD pipelines where everything runs autonomously:

# ci-pipeline.yaml
# Register: agents automation-profile add --config ci-pipeline.yaml

name: local/ci-pipeline
description: "Full automation for CI/CD pipelines. All phases automated, sandbox required."

decompose_task: 0.0
create_tool: 0.0
select_tool: 0.0

edit_code: 0.0
execute_command: 0.0

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

install_dependency: 0.0

require_sandbox: true
require_checkpoints: true
allow_unsafe_tools: false
This profile is similar to `full-auto` but with mandatory sandboxing and checkpoints enabled — suitable for CI/CD environments where you want full automation but with safety nets. --- **Example 3: Review-Heavy Profile (Medium)** A profile for regulated environments where every decision must be reviewed:

# review-heavy.yaml
# Register: agents automation-profile add --config review-heavy.yaml

name: local/review-heavy
description: "Maximum human oversight. Every decision and phase requires approval."

decompose_task: 0.0
create_tool: 1.0
select_tool: 1.0

edit_code: 1.0
execute_command: 1.0

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

install_dependency: 1.0

require_sandbox: true
require_checkpoints: true
allow_unsafe_tools: false
This profile auto-starts strategize but requires human approval for every decision, every phase transition, and every child plan spawn. Useful in regulated industries (finance, healthcare) where audit trails and human review are mandatory. --- **Example 4: Development Sandbox Profile (Simple)** A fast-iteration profile for local development where safety is relaxed:

# dev-sandbox.yaml
# Register: agents automation-profile add --config dev-sandbox.yaml

name: local/dev-sandbox
description: "Fast iteration for local development. Relaxed safety, auto execution."

decompose_task: 0.0
create_tool: 0.0
select_tool: 1.0

edit_code: 0.0
execute_command: 0.0

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

install_dependency: 0.0

require_sandbox: false
require_checkpoints: false
allow_unsafe_tools: true
This profile removes sandbox and checkpoint requirements for speed during local development. It still requires manual apply to prevent accidental commits. Unsafe tools are allowed for full flexibility. --- **Example 5: Production Deployment Profile (Complex)** A profile for production deployments combining autonomous execution with maximum safety:

# production-deploy.yaml
# Register: agents automation-profile add --config production-deploy.yaml

name: local/production-deploy
description: |
  Production deployment profile. Fully autonomous execution
  with maximum safety guarantees. All phases require sandbox
  and checkpoint. Apply requires manual approval. Strategy
  revision is enabled to adapt to deployment issues.

decompose_task: 0.0
create_tool: 0.0
select_tool: 1.0

edit_code: 0.0
execute_command: 0.0

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

install_dependency: 0.0

require_sandbox: true
require_checkpoints: true
allow_unsafe_tools: false
### LSP Server Configuration Files !!! adr "Architecture Decision" The LSP Registry, actor LSP binding, capability exposure, and server lifecycle are defined in [ADR-027: Language Server Protocol (LSP) Integration](adr/ADR-027-language-server-protocol.md). 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 ` and can then be referenced by actors in their `lsp:` configuration field. #### JSON Schema The following is the formal [JSON Schema](https://json-schema.org/) 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