Agent Definition Reference
An agent in Achilles is a single YAML document that describes who the agent is, which systems it can reach, who may do what, and when it must ask a person. Most customers never edit this file by hand: Agent Builder generates it from your procedures and database, and you refine it through the console.
Reach for the raw file when you want to review exactly what an agent is allowed to do (compliance teams often do), make a bulk change that is faster as text, keep a copy in your own version control, or move an agent between workspaces.
Import and export in the console
Open the agent in the console and use the editor to view its YAML. Edit it in place and save, or use Import YAML to bring in a file. Every save is validated first: if something is wrong, you see the exact field and a plain message, and nothing is changed. Take a version snapshot before larger edits so you can compare and restore. To export, copy the YAML from the editor into your own repository.
The same checks run whether you save from the editor, the API, or Agent Builder. Beyond shape, they verify cross-references (every tool points at a real datasource, every role at real tools), row-filter coverage on database queries, and safe defaults for approvals and personal data.
Top-level fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
app | string | yes | none | Display name for labels and filenames. Operational API identity is embed_key (public name: agentKey), not this field. Minimum length 1. |
version | positive integer | yes | none | Definition version number. |
tenant | string | yes | none | Tenant id. Copied into tokens and session records, and used to scope channels. |
persona | object | yes | none | Name, tone, and prompt-level behavior. See persona. |
model | object | no | provider defaults | Model routing. See model. |
datasources | array | yes | none | At least one datasource. See datasources. |
roles | map of role key to object | yes | none | Roles and their tool access and row filters. See roles. |
role_mapping | map of string to string | no | none | Maps a host application's role names to role keys in roles. |
tools | array | yes | none | At least one tool. See tools. |
guardrails | object | no | see guardrails | Platform-level safety rules enforced in code. |
fast_path | array | no | [] | Cheap routes that skip the full agentic loop. |
evals | array | no | [] | Test cases that run against the runtime. |
voice | object | no | none | Voice channel configuration. |
orchestration | object | no | none | Step limits, chain hints, and human handoff. |
role_mapping values must be role keys defined under roles. Roles that are not mapped fall back to least privilege. See Role Mapping.
persona
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | none | The agent's display name. |
tone | string | yes | none | Tone guidance, for example "friendly and concise". |
language | string | no | en-hi | Language hint. |
refuse_outside_scope | boolean | no | true | Whether the agent declines requests outside its tools. |
greeting | string | no | none | Opening message shown in a fresh session. |
industry | enum | no | none | Console grouping for icons. One of travel, insurance, banking, healthcare, retail, support, sales, operations, general. Cosmetic only. |
icon | string | no | none | Icon id from the console catalog. Cosmetic only. |
icon_color | string | no | none | Chip color for the icon. Cosmetic only. |
limitations | array of string | no | [] | Refusal rules injected into the system prompt verbatim. |
system_prompt_extra | string | no | none | Extra system prompt text. |
system_prompt | string | no | none | Accepted alias for system_prompt_extra. If both are set, system_prompt_extra wins. |
limitations are prompt guidance, not a security boundary. Anything that must not happen belongs in guardrails or roles, which the model cannot talk its way past. See Guardrails.
model
The whole block is optional. Omit it to use auto routing. See Model Routing.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
provider | enum | no | auto | One of auto, anthropic, openrouter, ollama, ollama-local, sarvam, bedrock. |
model | string | no | auto | A plain model name, or provider:model for explicit routing. |
max_tokens | number | no | 1024 | Maximum output tokens per model call. |
temperature | number, 0 to 1 | no | 0.3 | Sampling temperature. |
fast_model | string | no | none | Cheaper model for fast-path single-tool queries, for example ollama:gemma4:31b-cloud. |
datasources
An array with at least one entry. Datasource definitions never contain credentials. They name a credential, and the value is stored encrypted under Datasources in the console. See Datasources.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | yes | none | Referenced by tools[].datasource_id. |
type | enum | yes | none | One of postgres, rest, mysql, mcp. |
connection_env | string | yes | none | Environment variable name. Must match ^[A-Z][A-Z0-9_]*$. Never the value. |
base_url_env | string | no | none | For rest: env var holding the base URL. |
auth | enum | no | service_account | One of bearer_passthrough, service_account, api_key. |
mcp | object | required when type is mcp | none | See below. |
datasources[].mcp
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
server | enum | yes | none | achilles:db and achilles:email are first-party servers hosted in-process. remote is any third-party MCP server. |
transport | enum | no | streamable_http | Only streamable_http. Relevant to remote. |
timeout_ms | positive integer | no | 15000 | Per-call timeout. |
forward_context | boolean | no | false | Send the signed Achilles context (identity and row scope) to a remote server. First-party servers always receive it. |
token_env | string | no | none | remote: env var holding the bearer token. |
from_env | string | no | none | achilles:email: env var holding the From address. Required for email. |
reply_to_env | string | no | none | achilles:email: env var holding the Reply-To address. |
allowed_recipient_domains | array of string | no | [] | achilles:email: domains the connector may send to. Empty means any (the validator warns). |
max_recipients | positive integer | no | 5 | achilles:email: cap on to and cc recipients per send. |
See Connectors and MCP.
roles
roles is a map. Each key is a role name, and the value has the fields below.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
row_filters | map of string to string | no | {} | SQL predicates injected server-side. The default key applies to any table without its own entry. Values can interpolate identity claims such as {{user.customerId}}. |
allowed_tools | array of string | yes | none | At least one entry. Tool ids the role may call. |
deny_write | boolean | no | false | Blocks mutation tools for this role. |
See Role Mapping and Guardrails.
tools
An array with at least one entry. Which fields apply depends on type and on the datasource.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | yes | none | Unique tool id. |
description | string | yes | none | What the tool does and when to use it. The model reads this to choose tools. |
datasource_id | string | yes | none | Must match a datasource id. |
type | enum | no | query | query, mutation, or dynamic_query. |
sql | string | SQL tools | none | Template with {{row_filter}} and $1, $2 placeholders. Not allowed on dynamic_query. |
method | enum | REST tools | none | GET, POST, PUT, PATCH, or DELETE. |
path | string | REST tools | none | Request path. |
body_template | string | no | none | REST body template. |
mcp_tool | string | MCP tools | none | The tool's name on the MCP server, for example query or send_email. |
input_schema | object | no | none | The server's JSON Schema for mcp_tool, pinned at discovery time. Has type (always object), properties (default {}), and optional required. |
allowed_tables | array of string | dynamic_query | none | Table allowlist the model may reference. Also required on MCP database tools. |
unscoped_tables | array of string | no | [] | dynamic_query: subset of allowed_tables that are shared catalogs and need no row filter. |
denied_columns | array of string | no | [] | dynamic_query: columns the model may never select, merged with a built-in denylist of secret-shaped names. |
schema_hint | string | no | none | dynamic_query: column and enum notes injected into the system prompt verbatim. |
params | map of string to object | no | {} | Declared parameters. See below. |
pii_fields | array of string | no | [] | Result fields to mask or hash. See PII Protection. |
requires_confirmation | boolean | no | false | Ask the user to approve before the tool runs. See Confirmations. |
max_rows | number | no | none | Per-tool row cap. |
returns | enum | no | object | table, object, scalar, or void. |
status_label | string, max 80 | no | none | End-user status line shown while the tool runs. Defaults to a generic line, never the tool id. |
escalation_rules | array | no | [] | Rules evaluated on the result to trigger human handoff. |
chainable_to | array of string | no | [] | Tools expected to follow this one. Metadata only. |
Dynamic query tools are covered in Dynamic Query Tools.
tools[].params
params is a map from parameter name to an object.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | enum | yes | none | string, integer, number, boolean, or enum. |
description | string | yes | none | Shown to the model. |
required | boolean | no | false | Whether the model must supply it. |
default | string, number, or boolean | no | none | Value used when omitted. |
min | number | no | none | Lower bound for numbers. |
max | number | no | none | Upper bound for numbers. |
pattern | string | no | none | Regular expression a string must match. |
values | array of string | enum only | none | Allowed values. The validator rejects an enum without them. |
tools[].escalation_rules
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
if | string | yes | none | A single condition in the form field OP value, for example premium_amount > 500000. Evaluated in code against the tool result. |
flag | string | no | requires_human_review | The flag set on a match. Matches the handoff trigger tool_result_flag. |
guardrails
Optional. If omitted, all defaults below apply. See Guardrails.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
block_if_no_row_filter | boolean | no | true | Refuse to run a query for a role that has no row filter. |
max_rows | number | no | 50 | Global row cap. |
deny_write_for_roles | array of string | no | [] | Roles that may never run mutation tools. |
mask_pii_unless_roles | array of string | no | [] | Roles that see unmasked pii_fields. Everyone else sees masked values. |
require_confirmation_for_mutations | boolean | no | true | Require user approval for every mutation. |
fast_path
An array of rules that route a matching question straight to one tool, skipping the full agentic loop. See Fast Path. Each rule accepts either of two shapes.
| Field | Type | Required | Description |
|---|---|---|---|
intent | string | one of intent or intent_keywords | A phrase. It is split on whitespace into keywords. |
intent_keywords | array of string | one of intent or intent_keywords | Explicit keywords. Must be non-empty if used. |
tool | string | one of tool or tool_id | Tool id to run. |
tool_id | string | one of tool or tool_id | Alias for tool. |
The alias exists so definitions written against either spelling load unchanged. The same list may also be nested under orchestration.fast_path. If the top-level list is empty, the nested one is used.
evals
An array of test cases. See Evaluation.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ask | string | yes | none | The user message. |
description | string | no | none | Label shown in reports. |
role | string | no | least privileged role | Run the case as this role. Must exist in roles. |
expect_tool | string | no | none | Passes when this tool is called. Must exist in tools. |
expect_refusal | boolean | no | none | Passes when the reply is a refusal and no tool ran. |
expect_contains | string | no | none | Passes when the reply contains the string. |
expect_handoff | boolean | no | none | Passes when the handoff outcome matches. |
voice
Optional. See Voice. If present, every field below has a default.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled | boolean | no | false | Turn the voice channel on. |
modes | array of text or voice | no | [text, voice] | Modes the agent offers. |
greeting | string | no | none | Spoken opening line. |
stt | object | no | sarvam, saaras:v3 | Speech-to-text config. |
tts | object | no | sarvam, bulbul:v3, speaker priya | Text-to-speech config. |
voice.stt
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
provider | enum | no | sarvam | sarvam or deepgram. |
model | string | no | saaras:v3 | STT model. |
language | string | no | none | Language code. |
voice.tts
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
provider | enum | no | sarvam | sarvam, elevenlabs, or azure. |
model | string | no | bulbul:v3 | TTS model. |
speaker | string | no | priya | Voice name. |
The validator warns when a provider is not implemented by the runtime.
orchestration
Optional. See Orchestration and Handoff.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
max_steps | integer, 1 to 50 | no | runtime default | Hard ceiling on agentic loop iterations. |
pipeline_tools | array | no | [] | Chain hints. Metadata only, not enforced. |
handoff | object | no | none | Human handoff configuration. |
fast_path | array | no | none | Accepted alias for the top-level fast_path. |
orchestration.pipeline_tools[]
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | The tool. |
chainable_to | array of string | yes | Non-empty list of tools expected to follow it. |
Hints declared here and in tools[].chainable_to are merged.
orchestration.handoff
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled | boolean | no | false | Turn handoff on. |
triggers | object | no | see below | What causes a handoff. |
notify_channel | enum | no | email | email, webhook, whatsapp, or slack. |
notify_to_role | string | yes | none | A role key whose contact receives the notification. |
agent_response | string | yes | none | Message shown to the user. Supports the {{session_id}} and {{role}} placeholders. |
orchestration.handoff.triggers
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
phrase_match | array of string | no | [] | Phrases in the user message that force a handoff. |
tool_result_flag | string | no | requires_human_review | The escalation flag that forces a handoff. |
unresolved_turns | positive integer | no | 3 | Consecutive turns of the same unresolved ask before handing off. |
Full annotated example
This is a complete, valid definition. It is a generic support agent and contains no credentials.
app: example-support # display name; API uses embed_key as agentKey
version: 1
tenant: example
persona:
name: Ava
tone: friendly and concise
language: en
refuse_outside_scope: true
greeting: "Hi, I'm Ava. Ask me about an order or a customer's support tickets."
industry: support # cosmetic
icon: headset # cosmetic
limitations: # prompt-level guidance, not a security boundary
- Read-only, never creates, updates, or deletes anything
system_prompt_extra: |
You help a support team look up orders and tickets. Always use the tools
to fetch exact values and never guess.
model:
provider: auto
model: auto
max_tokens: 512
temperature: 0.2
datasources:
- id: support_db
type: postgres
connection_env: EXAMPLE_SUPPORT_DB_URL # an env var NAME, never the value
auth: service_account
roles:
viewer:
row_filters:
default: '"customerId" = {{user.customerId}}' # injected server-side
allowed_tools: [get_order_status, list_customer_tickets]
agent:
row_filters:
default: 1=1
allowed_tools: ['*']
role_mapping: # host role -> agent role
VIEWER: viewer
SUPPORT_AGENT: agent
tools:
- id: get_order_status
description: Look up an order's fulfilment and payment status by order number.
datasource_id: support_db
type: query
params:
orderNumber:
type: string
description: The order number to look up
required: true
sql: |
SELECT "orderNumber", "customerId", "status", "paymentStatus"
FROM "Order"
WHERE {{row_filter}} AND "orderNumber" = $1
returns: table
pii_fields: [customerId]
status_label: Checking your order
chainable_to: [list_customer_tickets]
guardrails:
block_if_no_row_filter: true
max_rows: 50
require_confirmation_for_mutations: true
deny_write_for_roles: [viewer, agent]
mask_pii_unless_roles: [agent]
fast_path:
- intent: order status
tool: get_order_status
evals:
- description: Order status, happy path
ask: What's the status of order ORD-1001?
expect_tool: get_order_status
- description: Human handoff on complaint
ask: This is a complaint, I want to speak to a person
role: viewer
expect_handoff: true
voice:
enabled: false
orchestration:
max_steps: 6
handoff:
enabled: true
triggers:
phrase_match: [talk to a human, this is a complaint]
tool_result_flag: requires_human_review
unresolved_turns: 3
notify_channel: email
notify_to_role: agent
agent_response: >
I've passed this conversation to a support agent. Your reference number
is {{session_id}}.
Validate a definition before saving it by pasting it into the console editor, which checks it as you type, or by calling the validate endpoint in the API reference.