spec.tools
Function-call entrypoints the agent can invoke at runtime. The generator turns each tool into a typed stub in the target language.
spec:
tools:
- id: knowledge_search
name: knowledge_search
description: Search the company knowledge base
tags:
- knowledge
- search
schema:
type: object
properties:
query:
type: string
description: The search query
required:
- queryShape
- Type: array of
Toolobjects. - Required: no
Tool fields
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Unique identifier. Pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$. Becomes the symbol name in code. |
name | string | Human-readable name. Required for user-defined tools (see below). | |
description | string | What the tool does. Required for user-defined tools. | |
tags | string[] | Discoverability/grouping tags. Required for user-defined tools. | |
schema | object | Free-form JSON Schema for the tool's input parameters. Required for user-defined tools. | |
inject | string[] | Names of services from spec.services to inject when the tool body is invoked. |
additionalProperties are not allowed - anything outside this set fails validation.
User-defined vs. built-in tools
The schema makes a deliberate split:
- User-defined tools must supply
name,description,tags, andschema- that's how the generator knows what to wire up. - Built-in tools use the five reserved IDs
read,bash,write,edit, andfetch, and may omit those fields. The generator supplies the canonical name, description, tags, and schema for built-ins.
Activating a built-in takes two steps: list the ID under spec.tools, and set spec.config.tools.<id>.enabled: true. Listing the ID alone registers the tool in a disabled state, and it fails at runtime. Each built-in also has its own typed config keys - see the reserved tools group.
For a user-defined tool, spell out all four metadata fields; no config.tools entry is required.
spec:
tools:
# Built-in: generator fills in the rest
- id: read
- id: bash
# User-defined: must spell everything out
- id: send_email
name: send_email
description: Send a transactional email via Postmark
tags:
- communication
- email
schema:
type: object
properties:
to: { type: string, format: email }
subject: { type: string }
body: { type: string }
required:
- to
- subject
- body
# Built-ins stay off until enabled here
config:
tools:
read:
enabled: true
bash:
enabled: true
whitelist:
- git status
timeout_seconds: 30schema
A free-form JSON Schema describing the tool's input parameters. The ADL schema deliberately doesn't constrain its contents - anything a JSON Schema validator accepts is allowed. Generators turn this into a typed input struct (Go), interface (TypeScript), or struct (Rust), and surface it to the LLM via the provider's function-calling API.
Common patterns
# Simple required-string input
schema:
type: object
properties:
query: { type: string }
required:
- query
# Enum-constrained input
schema:
type: object
properties:
region:
type: string
enum:
- us-east-1
- us-west-2
- eu-west-1
required:
- region
# Nested object
schema:
type: object
properties:
customer:
type: object
properties:
id: { type: string }
email: { type: string, format: email }
required:
- id
required:
- customerinject
A list of service names from spec.services that should be wired into the tool body when the generator emits the stub. The generator uses these names to construct typed parameters or struct fields, so the tool implementation receives the dependencies directly rather than reaching out to a service locator.
spec:
services:
customerRepo:
type: repository
interface: CustomerRepository
factory: NewPostgresCustomerRepository
description: ...
tools:
- id: get_customer
name: get_customer
description: Look up a customer by ID
tags:
- customer
schema:
type: object
properties:
id: { type: string }
required:
- id
inject:
- customerRepoEach entry must match the pattern ^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*$ - a single identifier or a dotted path (foo.bar.baz) for sub-references.