# ADR-011: Tool System

**Status:** Accepted  
**Date:** 2026-02-16  
**Supersedes:** None  
**Author(s):** Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>  
**Approver(s):** Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>

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

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.

## Related ADRs

| ADR | Title | Relationship |
|-----|-------|-------------|
| [ADR-002](ADR-002-namespace-system.md) | Namespace System | Tools use namespaced identifiers for discovery and conflict resolution |
| [ADR-004](ADR-004-data-validation.md) | Data Validation | Tool input/output schemas are Pydantic models with JSON Schema generation |
| [ADR-008](ADR-008-resource-system.md) | Resource System | Tools declare resource bindings that determine which resources they operate on |
| [ADR-010](ADR-010-actor-and-agent-architecture.md) | Actor and Agent Architecture | Tools serve as atomic execution nodes within actor graphs |
| [ADR-012](ADR-012-skill-system.md) | Skill System | Skills compose tools into reusable collections for actor assignment |
| [ADR-013](ADR-013-validation-abstraction.md) | Validation Abstraction | Validations are a specialized Tool subtype with structured pass/fail semantics |
| [ADR-015](ADR-015-sandbox-and-checkpoint.md) | Sandbox and Checkpoint | Tool invocations create checkpoints for rollback and recovery |
| [ADR-028](ADR-028-agent-skills-standard.md) | Agent Skills Standard (AgentSkills.io) | Agent Skills are a tool source (`agent_skill`) integrated into the Tool Registry |
| [ADR-029](ADR-029-model-context-protocol.md) | Model Context Protocol (MCP) Adoption | MCP tools are registered as Tool records and follow the four-stage tool lifecycle |
| [ADR-030](ADR-030-skill-abstraction-definition.md) | Skill Abstraction Definition | Tools are the atomic operations that skills collect and present to actors |

## Acceptance

### Votes For

| Voter | Comment |
|-------|---------|
| Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com> | The four-stage lifecycle with dual role as skill component and graph node is a clean unification |

**Total: 1**

### Votes Against

| Voter | Comment |
|-------|---------|

**Total: 0**

### Abstentions

| Voter | Comment |
|-------|---------|

**Total: 0**
