c2db74ba81
CI / lint (push) Successful in 15s
CI / build (push) Successful in 16s
CI / quality (push) Successful in 20s
CI / security (push) Successful in 35s
CI / typecheck (push) Successful in 42s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m38s
CI / integration_tests (push) Successful in 3m11s
CI / docker (push) Successful in 39s
CI / coverage (push) Successful in 4m58s
CI / benchmark-publish (push) Successful in 17m32s
196 lines
12 KiB
Markdown
196 lines
12 KiB
Markdown
---
|
|
adr_number: 11
|
|
title: Tool System
|
|
status_history:
|
|
- - '2026-02-16'
|
|
- Proposed
|
|
- Jeffrey Phillips Freeman
|
|
- - '2026-02-16'
|
|
- Accepted
|
|
- Jeffrey Phillips Freeman
|
|
tier: 2
|
|
authors:
|
|
- Jeffrey Phillips Freeman
|
|
superseded_by: null
|
|
related_adrs:
|
|
- number: 2
|
|
title: Namespace System
|
|
relationship: Tools use namespaced identifiers for discovery and conflict resolution
|
|
- number: 4
|
|
title: Data Validation
|
|
relationship: Tool input/output schemas are Pydantic models with JSON Schema generation
|
|
- number: 8
|
|
title: Resource System
|
|
relationship: Tools declare resource bindings that determine which resources they operate on
|
|
- number: 10
|
|
title: Actor and Agent Architecture
|
|
relationship: Tools serve as atomic execution nodes within actor graphs
|
|
- number: 12
|
|
title: Skill System
|
|
relationship: Skills compose tools into reusable collections for actor assignment
|
|
- number: 13
|
|
title: Validation Abstraction
|
|
relationship: Validations are a specialized Tool subtype with structured pass/fail semantics
|
|
- number: 15
|
|
title: Sandbox and Checkpoint
|
|
relationship: Tool invocations create checkpoints for rollback and recovery
|
|
- number: 28
|
|
title: Agent Skills Standard (AgentSkills.io)
|
|
relationship: Agent Skills are a tool source (`agent_skill`) integrated into the Tool Registry
|
|
- number: 29
|
|
title: Model Context Protocol (MCP) Adoption
|
|
relationship: MCP tools are registered as Tool records and follow the four-stage tool lifecycle
|
|
- number: 30
|
|
title: Skill Abstraction Definition
|
|
relationship: Tools are the atomic operations that skills collect and present to actors
|
|
- number: 37
|
|
title: Tool Reachability and Access Projection
|
|
relationship: Extends resource bindings with transitive reachability, access projection, and read/write routing
|
|
acceptance:
|
|
votes_for:
|
|
- voter: Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>
|
|
comment: The four-stage lifecycle with dual role as skill component and graph node is a clean unification
|
|
votes_against: []
|
|
abstentions: []
|
|
---
|
|
## Context
|
|
|
|
CleverAgents must integrate tools from multiple sources — built-in file/git operations, MCP server-hosted tools, Agent Skills (SKILL.md-based instructions), and custom user-defined tools. Each source has different discovery mechanisms, execution protocols, and capability characteristics. The system needs a uniform tool abstraction that normalizes these differences while preserving source-specific capabilities like checkpointing, resource binding, and sandbox awareness.
|
|
|
|
## Decision Drivers
|
|
|
|
- Must integrate tools from four distinct sources (built-in, MCP servers, Agent Skills, custom) with different discovery and execution protocols
|
|
- Tools must serve a dual role: as LLM tool-calling targets within skills and as deterministic graph nodes in actor workflows
|
|
- Resource bindings must decouple tools from specific resources, enabling portability across projects
|
|
- Need a uniform four-stage lifecycle (discover, activate, execute, deactivate) to normalize source-specific differences
|
|
- Change tracking must be driven by tool invocations, not by parsing LLM output, to ensure reliable auditable changesets
|
|
- Capability metadata (read-only, checkpointable, side effects) must be declared per tool to enable safety enforcement at runtime
|
|
|
|
## Decision
|
|
|
|
A **tool** is the atomic unit of execution — the smallest piece of functionality that can read, write, or transform resources. Tools are namespaced, independently registered, and follow a **four-stage lifecycle** (discover, activate, execute, deactivate). Every tool has a uniform interface regardless of source, and plays a **dual role**: as a component of a skill (available for LLM tool-calling) and as a tool node in an actor graph (deterministic, non-LLM execution step).
|
|
|
|
## Design
|
|
|
|
### Tool Identity and Registration
|
|
|
|
Tools follow the namespace system (`[[server:]namespace/]name`). They are defined in YAML, registered via `agents tool add --config <FILE>`, and stored in the persistent **Tool Registry**. The registry stores: name, description, source, config path, input/output schemas (JSON Schema), capability metadata, resource slots, and implementation code or server reference.
|
|
|
|
### Tool Sources
|
|
|
|
| Source | Discovery | Execution | Examples |
|
|
|--------|-----------|-----------|---------|
|
|
| **Built-in** | Hardcoded descriptors | Native Python calls | `read_file`, `write_file`, `edit_file`, `search_files` |
|
|
| **MCP** | MCP server `tools/list` | JSON-RPC `tools/call` | Any MCP-compliant server tool |
|
|
| **Agent Skill** | SKILL.md frontmatter parsing | Agent-mediated instruction following | Instruction-based tools from SKILL.md files |
|
|
| **Custom** | YAML registration | User-defined implementation | User-created tools |
|
|
|
|
### Four-Stage Lifecycle
|
|
|
|
**discover()**: Find and catalog the tool. Built-in: return hardcoded descriptors. MCP: spawn server, `initialize` handshake, `tools/list`. Agent Skill: parse SKILL.md frontmatter (~50-100 tokens). Custom: parse YAML definition.
|
|
|
|
**activate()**: Prepare the tool for use. Built-in: no-op. MCP: ensure server running, register for `notifications/tools/list_changed`. Agent Skill: load full SKILL.md body into agent context. Custom: load implementation.
|
|
|
|
**execute(params, ctx)**: Run the tool. Built-in: call native Python. MCP: translate to `tools/call` JSON-RPC, rewrite sandbox paths, validate params, record changes. Agent Skill: agent-mediated execution following instructions. Custom: user-defined execution.
|
|
|
|
**deactivate()**: Clean up. MCP: clean server shutdown. Agent Skill: remove instructions from context. Others: no-op.
|
|
|
|
### Dual Role
|
|
|
|
**As a skill component**: When an actor references a skill, all tools in that skill become available for LLM tool-calling. The LLM generates tool call requests, and the Tool Router validates and dispatches them.
|
|
|
|
**As an actor graph node**: `type: tool` nodes in actor graphs execute deterministically without LLM involvement. Can reference a named registered tool or define an anonymous inline tool.
|
|
|
|
### Tool Interface
|
|
|
|
```
|
|
Tool:
|
|
Identity: name, qualified_name, source (mcp | agent_skill | builtin | custom)
|
|
Schema: input_schema (JSONSchema), output_schema (JSONSchema)
|
|
CapabilityMetadata: read_only, writes, write_scope, idempotent,
|
|
checkpointable, checkpoint_scope, side_effects,
|
|
cost_profile, human_approval_required
|
|
ResourceBindings: slots (Map<String, ResourceSlot>)
|
|
Lifecycle: discover(), activate(), execute(params, ctx), deactivate()
|
|
```
|
|
|
|
### Tool Adapter Layer
|
|
|
|
Each source has an adapter that translates to the uniform interface:
|
|
|
|
- **MCPToolAdapter**: Manages MCP server lifecycle, JSON-RPC communication, sandbox path rewriting, and capability inference from tool names.
|
|
- **AgentSkillAdapter**: Three-tier progressive disclosure (metadata ~50-100 tokens → instructions < 5000 tokens → resources variable).
|
|
- **BuiltinToolAdapter**: Direct native Python execution with hardcoded capability metadata.
|
|
- **CustomToolAdapter**: User-defined implementation with manually declared capabilities.
|
|
|
|
### Resource Bindings
|
|
|
|
Tools declare **resource slots** — named slots specifying what resource type and access mode is needed. Three binding modes:
|
|
|
|
- **Contextual** (default): Resolved from the plan's project at activation time.
|
|
- **Static**: Hardcoded to a specific resource by name via `bind` field.
|
|
- **Parameter**: Passed as argument at invocation time via `from_param` field.
|
|
|
|
Built-in tool groups have implicit resource slots (e.g., `file_operations` implicitly binds a `directory` slot of type `fs-directory` or `git-checkout`).
|
|
|
|
### Capability Metadata
|
|
|
|
Every tool declares capabilities: `read_only`, `writes`, `write_scope` (file paths, resource slots, environment), `idempotent`, `checkpointable`, `checkpoint_scope` (file, transaction, commit, snapshot), `side_effects`, `cost_profile`, and `human_approval_required`.
|
|
|
|
Metadata origin varies by source: built-in (hardcoded, not overridable), MCP (inferred + overrides), Agent Skill (SKILL.md frontmatter + overrides), custom (manually declared).
|
|
|
|
### Metadata Overrides
|
|
|
|
When referencing a named tool in a skill or actor graph, `capability` and `description` fields can be overridden at the point of use. Overrides are shallow-merged, never persist back to the registry, and cannot override schema or built-in metadata.
|
|
|
|
### Anonymous Tools
|
|
|
|
Inline tool definitions in skill YAML or actor graph nodes. Same format as named tools but unregistered, unnamespaced, and scoped only to their defining context.
|
|
|
|
### Tool Execution Flow
|
|
|
|
Six-step pipeline: LLM generates call → Tool Router validates → Resource binding resolution and sandbox setup → Adapter-specific execution → Change recording → Result return.
|
|
|
|
### Change Tracking
|
|
|
|
The changeset is built from tool invocations, not by parsing LLM output. Each tool execution receives a `ToolExecutionContext` with sandbox, plan, resources, and a changes recorder. Write operations record their changes directly.
|
|
|
|
## Constraints
|
|
|
|
- Tools must not parse LLM output to extract code or changes. All resource modification happens through tool invocations.
|
|
- `read_only: true` actions can only use tools where `read_only: true`. Enforced at runtime.
|
|
- Tool input/output schemas are JSON Schema, generated from Pydantic models where applicable.
|
|
- Anonymous tools share the same format as named tools but are scoped only to their defining skill or actor graph.
|
|
- Maximum tool calls per actor step is controlled by `plan.tool.max-calls-per-step` (default: 25).
|
|
- Maximum retries for transient failures is controlled by `plan.tool.max-retries` (default: 3).
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- A single tool interface normalizes four different sources (built-in, MCP, Agent Skill, custom) behind the same lifecycle and capability model.
|
|
- The dual role (skill component + graph node) maximizes tool reuse across LLM-driven and deterministic execution.
|
|
- Resource bindings decouple tools from specific resources, enabling portability across projects.
|
|
- Change tracking from tool invocations ensures reliable, auditable changesets.
|
|
|
|
### Negative
|
|
- The adapter layer adds complexity — each source requires its own adapter implementation with source-specific behavior.
|
|
- Capability inference for MCP tools (from tool names) is heuristic and may be inaccurate.
|
|
- The four-stage lifecycle adds overhead for simple tools that need no activation or deactivation.
|
|
|
|
### Risks
|
|
- MCP server availability is an external dependency. Server crashes or network failures during execution require retry and recovery logic.
|
|
- Agent Skill tools depend on LLM instruction-following quality, which is less reliable than programmatic execution.
|
|
- The capability metadata for custom and MCP tools is self-declared and may be inaccurate.
|
|
|
|
## Alternatives Considered
|
|
|
|
None — specification-driven requirement. The tool system with its four-stage lifecycle, dual role, adapter layer, and resource binding model is prescribed by the specification.
|
|
|
|
## Compliance
|
|
|
|
- **Adapter conformance tests**: Each adapter (MCP, Agent Skill, Built-in, Custom) has tests verifying correct lifecycle behavior across all four stages.
|
|
- **Resource binding tests**: Tests verify all three binding modes with correct resolution and error handling for missing bindings.
|
|
- **Capability enforcement tests**: Tests verify that `read_only` actions reject tools with `writes: true`, and that `human_approval_required` tools trigger approval gates.
|
|
- **Change tracking tests**: Tests verify that the changeset accurately reflects all tool invocations and contains no changes from LLM output parsing.
|
|
- **Schema validation**: Tool registration validates input/output schemas against JSON Schema specification.
|