Agent specification reference
An agent is fully described by a JSON configuration document stored in the registry. This page is the authoritative reference for that format.
Minimal agent
Section titled “Minimal agent”{ "assistant_id": "support-bot", "nickname": "Support Bot", "description": "Answers product support questions", "response": { "provider_id": "alquimia", "profile": { "system_prompt": "You are a helpful support assistant. Answer concisely.", "evaluation_strategy": { "evaluation_strategy_id": "one-shoot" }, "persistence_strategy": "INCREMENTAL" }, "config": { "provider_id": "openai", "params": { "model": "gpt-4o-mini", "api_key": { "$secretRef": "RESPONSE_PROVIDER_API_KEY" } } } }}Top-level fields (AssistantConfig)
Section titled “Top-level fields (AssistantConfig)”| Field | Type | Required | Description |
|---|---|---|---|
assistant_id | string | Yes | Unique agent identifier within the agentspace |
nickname | string | No | Human-readable name (max 64 characters) |
description | string | No | Description shown in discovery and A2A tool lists (max 3000 characters) |
tags | string[] | No | Labels for registry queries |
channels | Channel[] | No | Inbound/outbound channel configurations |
shields | object | No | Pre-inference classifiers keyed by shield name |
empathy | EmpathyEngine | No | Conditional profile overrides based on shield output |
role | "reader" | "editor" | "operator" | No | Zero Trust capability tier ceiling |
response | ResponseProfile | Yes | Main response provider and execution profile |
Profile fields
Section titled “Profile fields”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
system_prompt | string | No | — | Jinja2 template used as the system prompt |
prompt_clauses | object | No | — | Named sections appended to the system prompt |
knowledge_base | KnowledgeBase[] | No | — | Vector-search or direct-access knowledge sources |
short_term_memory_strategy | object[] | No | — | Token-based history trimming |
long_term_memory_strategy | object[] | No | — | Context flush strategies |
evaluation_strategy | object | No | one-shoot | Tool use and termination policy |
tools | ToolConfig[] | No | — | External tool sources |
persistence_strategy | "INCREMENTAL" | "FLUSH" | "EPHEMERAL" | No | "INCREMENTAL" | How conversation history is persisted |
Shields (shield-config)
Section titled “Shields (shield-config)”shields is a map of classifier names to shield-config objects. Each shield runs before the main inference call. Agent-scoped shields operate on the user request; tool- and topic-scoped shields operate on tool outputs and retrieved knowledge chunks.
shield-config schema
Section titled “shield-config schema”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
provider_id | "shield-config" | Yes | — | Must be shield-config |
connector | object | Yes | — | Underlying classifier connector |
action | "observe" | "flag" | "block" | No | "observe" | Action when threshold is crossed |
threshold | number | No | 0.5 | Score threshold |
target_label | string | No | — | Only this predicted label triggers the action |
fail_closed | boolean | No | false | Block on shield errors or timeouts |
block_message | string | No | — | Refusal text used when blocking |
Shield connector variants
Section titled “Shield connector variants”Built-in prompt-injection detector:
{ "provider_id": "shield-config", "connector": { "provider_id": "alquimia/prompt-injection-detection", "heuristic_weight": 0.3, "base_classifier_score": 0.0 }, "action": "block", "threshold": 0.5, "fail_closed": true}External Hugging Face text-classification model:
{ "provider_id": "shield-config", "connector": { "provider_id": "huggingface/text-classification", "url": "https://your-hf-endpoint.com", "token": { "$secretRef": "SHIELDS_PROVIDER_API_KEY" }, "label_map": { "LABEL_0": "safe", "LABEL_1": "toxic" } }, "action": "block", "threshold": 0.8, "target_label": "toxic", "block_message": "This request violates our safety policy."}LLM-based classifier using a registered model:
{ "provider_id": "shield-config", "connector": { "provider_id": "alquimia", "profile": { "system_prompt": "Classify user intent as one of: support, sales, enterprise.", "evaluation_strategy": { "evaluation_strategy_id": "one-shoot", "structured_output": { "method": "json_schema", "json_schema": { "type": "object", "properties": { "intent": { "type": "string" } }, "required": ["intent"] } } } }, "config": { "model_ref": "gpt-4o-mini-classifier" } }, "action": "observe"}See Shields & empathy for the conceptual model and How to configure content shields for step-by-step instructions.
Empathy engine
Section titled “Empathy engine”empathy.rules is a list of conditional profile overrides evaluated after all shields run. The first matching rule is applied.
EmpathyRule schema
Section titled “EmpathyRule schema”| Field | Type | Required | Description |
|---|---|---|---|
rule_id | string | Yes | Unique rule identifier |
strategy | "none" | "override" | "merge" | Yes | How the rule changes the response profile |
description | string | No | Human-readable explanation |
requirements | string[] | Yes | Shield IDs that must be present for the rule to run |
conditions | string[] | Yes | simpleeval expressions; all must be true |
response | ResponseProfile | Yes | Profile to apply (override) or merge |
Strategies
Section titled “Strategies”| Strategy | Behavior |
|---|---|
none | No-op |
override | Replace the entire response profile with response |
merge | Deep-merge response into the main profile |
Example
Section titled “Example”{ "empathy": { "rules": [ { "rule_id": "toxic-input", "strategy": "override", "description": "Refuse toxic requests", "requirements": ["toxicity"], "conditions": ["toxicity['label'] == 'toxic'"], "response": { "provider_id": "fixed", "message": "I'm sorry, I can't help with that." } }, { "rule_id": "formal-enterprise", "strategy": "merge", "description": "Use formal tone for enterprise intent", "requirements": ["intent-classifier"], "conditions": ["intent-classifier.get('intent') == 'enterprise'"], "response": { "provider_id": "alquimia", "profile": { "prompt_clauses": { "tone": "Use formal, professional language. Avoid contractions." } } } } ] }}Response provider (config)
Section titled “Response provider (config)”The config section inside response declares the LLM connector.
OpenAI
Section titled “OpenAI”{ "provider_id": "openai", "params": { "model": "gpt-4o", "temperature": 0.2, "max_tokens": 2048, "api_key": { "$secretRef": "RESPONSE_PROVIDER_API_KEY" }, "base_url": { "$secretRef": "RESPONSE_PROVIDER_BASE_URL" } }}{ "provider_id": "groq", "params": { "model": "llama-3.3-70b-versatile", "temperature": 0.1, "groq_api_key": { "$secretRef": "RESPONSE_PROVIDER_API_KEY" } }}Hugging Face
Section titled “Hugging Face”{ "provider_id": "huggingface", "params": { "model": "meta-llama/Llama-3.1-8B-Instruct", "api_key": { "$secretRef": "RESPONSE_PROVIDER_API_KEY" }, "base_url": { "$secretRef": "RESPONSE_PROVIDER_BASE_URL" } }}Common connector parameters
Section titled “Common connector parameters”| Field | Type | Description |
|---|---|---|
model | string | Model identifier |
temperature | number | Sampling temperature |
max_tokens | integer | Max output tokens |
timeout | integer | Request timeout in seconds |
top_p | number | Top-p sampling |
max_retries | integer | Retry count on failure |
api_key | SecretRef | API key for OpenAI or Hugging Face |
groq_api_key | SecretRef | API key for Groq |
base_url | SecretRef | Custom endpoint URL |
organization | string | OpenAI organization ID |
reasoning_format | string | Reasoning format hint |
reasoning_effort | string | Reasoning effort level |
Fixed response (testing)
Section titled “Fixed response (testing)”{ "provider_id": "fixed", "message": "This is a fixed response for testing.", "chunk_size": 64}Registered model reference (model_ref)
Section titled “Registered model reference (model_ref)”Instead of embedding a model connector in every profile, you can reference a model registered in the registry:
alquimia registry models add gpt-4o-mini \ --provider-id openai \ --params '{"model": "gpt-4o-mini", "temperature": 0.0, "api_key": {"$secretRef": "RESPONSE_PROVIDER_API_KEY"}}'Then use model_ref in response.config or inside a shield connector:
{ "response": { "provider_id": "alquimia", "config": { "model_ref": "gpt-4o-mini" }, "profile": { "system_prompt": "You are a helpful assistant.", "evaluation_strategy": { "evaluation_strategy_id": "one-shoot" } } }}Per-use params in the agent spec or shield override the registered model defaults.
Secrets
Section titled “Secrets”Sensitive values are never stored in the agent spec. Declare them with $secretRef and resolve them at inference time.
{ "api_key": { "$secretRef": "RESPONSE_PROVIDER_API_KEY" }}Secret scopes
Section titled “Secret scopes”| Scope | Environment key format | Vault path |
|---|---|---|
global | KEY | global/KEY |
shared | {REALM}_{KEY} | {realm}/shared/KEY |
local | {REALM}_{ASSISTANT_ID}_{KEY} | {realm}/local/{assistant_id}/KEY |
REALM is the agentspace_id.
Secret data types
Section titled “Secret data types”dtype | Format | Example |
|---|---|---|
str | Raw string | sk-abc123 |
bool | true/false, 1/0, yes/no, on/off | true |
int | Integer string | 587 |
float | Float string | 0.7 |
list | JSON array or comma-separated | ["a","b"] or a,b |
See Rotate secrets and Vault policies for operational details.
Evaluation strategies
Section titled “Evaluation strategies”one-shoot
Section titled “one-shoot”Single LLM call, no tools. Use for simple Q&A agents.
{ "evaluation_strategy_id": "one-shoot"}native
Section titled “native”Native function calling for agents that use tools.
{ "evaluation_strategy_id": "native", "max_steps": 10, "max_concurrent_tools": 1, "tool_choice": "auto", "decorators": null, "structured_output": null}| Field | Type | Default | Description |
|---|---|---|---|
max_steps | integer | 10 | Max LLM calls before termination |
max_concurrent_tools | integer | 1 | Max tool calls per step |
tool_choice | string or object | "auto" | Tool selection mode |
decorators | Decorator[] | null | plan-mode and skills decorators |
structured_output | object | null | Force structured JSON output |
Parse tool calls from unstructured text for models without native function calling.
{ "evaluation_strategy_id": "raw", "max_steps": 10, "max_concurrent_tools": 5, "parse_regex_pattern": "\\{\\s*\"name\"\\s*:..."}Memory strategies
Section titled “Memory strategies”Short-term: max_tokens
Section titled “Short-term: max_tokens”Trims conversation history to stay within a token budget.
{ "short_term_memory_strategy": [ { "memory_strategy_id": "max_tokens", "memory_max_tokens": 10000, "conditions": [] } ]}| Field | Type | Default | Description |
|---|---|---|---|
memory_max_tokens | integer | 10000 | Token budget; -1 disables trimming |
conditions | string[] | [] | Empathy-style conditions |
Long-term: summarizer
Section titled “Long-term: summarizer”Triggers a context flush when thresholds are exceeded.
{ "long_term_memory_strategy": [ { "long_term_memory_id": "summarizer", "interaction_threshold_qty": 20, "interaction_threshold_tokens": 20000, "interaction_keep": 3, "cod_max_loops": 5, "instructions": "Focus on decisions and action items." } ]}| Field | Type | Default | Description |
|---|---|---|---|
interaction_threshold_qty | integer | 20 | Flush after this many interactions |
interaction_threshold_tokens | integer | 20000 | Flush after this many tokens |
input_tokens_threshold | integer | 0 | Flush when LLM reports this many input tokens |
interaction_keep | integer | 0 | Human turns to keep after flush |
step_keep_qty | integer | 0 | Trailing tool-call round trips to keep |
step_keep_tokens | integer | 0 | Same as above, bounded by token budget |
cod_max_loops | integer | 5 | Chain-of-Density summarization iterations |
instructions | string | — | Summarization focus instructions |
knowledge_base | object | — | Store summary in this knowledge base |
Long-term: neuralyzer
Section titled “Long-term: neuralyzer”Erases memory beyond retained interactions without summarization.
{ "long_term_memory_strategy": [ { "long_term_memory_id": "neuralyzer", "interaction_threshold_qty": 10, "interaction_keep": 2 } ]}Decorators
Section titled “Decorators”Decorators augment native evaluation with extra tools and prompt clauses.
plan-mode
Section titled “plan-mode”Injects plan-management tools and a planning instruction block.
{ "decorator_id": "plan-mode", "force_completion": false}| Field | Type | Default | Description |
|---|---|---|---|
force_completion | boolean | false | Agent must resolve all tasks before answering |
Injected tools: create_plan, get_current_plan, mark_done, mark_failed, mark_blocked, mark_pending, add_task, add_note, rename_task.
skills
Section titled “skills”Loads MDX skill documents and exposes tools to browse and activate them.
{ "decorator_id": "skills", "skills_dir": "/app/skills"}| Field | Type | Required | Description |
|---|---|---|---|
skills_dir | string | Yes | Path to directory containing .mdx skill files |
Injected tools: list_skills, get_skill, select_skill, deselect_skill.
Channels
Section titled “Channels”{ "provider_id": "whatsapp", "channel_id": "whatsapp-main", "template": "{{answer}}", "middleware": [], "whatsapp_assistant_phone_number_id": { "$secretRef": "WHATSAPP_PHONE_NUMBER_ID" }, "whatsapp_verify_token": { "$secretRef": "WHATSAPP_VERIFY_TOKEN" }, "whatsapp_access_token": { "$secretRef": "WHATSAPP_ACCESS_TOKEN" }, "whatsapp_api_base_url": { "$secretRef": "WHATSAPP_API_BASE_URL" }}{ "provider_id": "email", "channel_id": "email-support", "read_mailbox": "inbox", "email_select_status": "UNSEEN", "template": "<html><body>{{ answer | markdown_to_html }}</body></html>", "middleware": [], "email_username": { "$secretRef": "EMAIL_USERNAME" }, "email_password": { "$secretRef": "EMAIL_PASSWORD" }, "email_smtp_server": { "$secretRef": "EMAIL_SMTP_SERVER" }, "email_imap_server": { "$secretRef": "EMAIL_IMAP_SERVER" }}| Field | Type | Default | Description |
|---|---|---|---|
read_mailbox | string | "inbox" | IMAP mailbox to poll |
email_select_status | string | "UNSEEN" | IMAP search criteria |
flag_on_read | string | "(\\Seen)" | Flag set when message is read |
unflag_on_error | string | "(\\Seen)" | Flag removed on processing error |
template | string | — | Jinja2 template for outbound HTML email |
{ "provider_id": "slack", "channel_id": "slack-main", "template": "{{answer}}", "middleware": [], "slack_access_token": { "$secretRef": "SLACK_ACCESS_TOKEN" }}Channel middleware
Section titled “Channel middleware”Whitelist
Section titled “Whitelist”{ "middleware": [ { "provider_id": "alquimia:whitelist", "allowed_ids": { "$secretRef": "WHITELIST_MIDDLEWARE_ALLOWED_IDS" } } ]}WHITELIST_MIDDLEWARE_ALLOWED_IDS must be a list dtype secret. Use "*" to allow all users.
Cognito OTP
Section titled “Cognito OTP”{ "middleware": [ { "provider_id": "cognito:otp", "user_pool_id": { "$secretRef": "AWS_COGNITO_USER_POOL_ID" }, "client_id": { "$secretRef": "AWS_COGNITO_CLIENT_ID" }, "client_secret": { "$secretRef": "AWS_COGNITO_CLIENT_SECRET" }, "otp_regex": "\\b(\\d{6})\\b", "otp_message": "Please send your 6-digit authentication code." } ]}Requires the AWS extra and a Redis instance.
MCP tools
Section titled “MCP tools”HTTP transport:
{ "provider_id": "mcp", "tools_id": "filesystem-tools", "human_approval": "NONE", "url": { "$secretRef": "MCP_PROVIDER_URL" }, "auth": { "$secretRef": "MCP_PROVIDER_AUTH" }, "transport": "streamable-http"}Stdio transport:
{ "provider_id": "mcp", "tools_id": "shell-tools", "human_approval": "REQUIRED", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"], "transport": "stdio"}| Field | Type | Required | Description |
|---|---|---|---|
tools_id | string | No | Unique identifier for this tool source |
human_approval | "NONE" | "REQUIRED" | No | Legacy approval gate |
url | SecretRef or string | No | MCP server URL |
auth | SecretRef or string | No | Bearer token or auth method |
command | string | No | Command to launch for stdio transport |
args | string[] | No | Arguments for stdio command |
env | object | No | Environment variables for stdio command |
headers | object | No | HTTP headers |
transport | string | No | Transport type hint |
Llama Stack tools
Section titled “Llama Stack tools”{ "provider_id": "llama-stack", "tools_id": "llama-tools", "human_approval": "NONE", "tool_group_id": "my-tool-group", "authorization": { "$secretRef": "LLAMA_STACK_PROVIDER_AUTHORIZATION" }}Requires LLAMA_STACK_BASE_URL and LLAMA_STACK_API_KEY environment variables.
A2A tools
Section titled “A2A tools”{ "provider_id": "a2a", "tools_id": "specialist-agents", "human_approval": "NONE", "selector": { "tags": ["specialist"] }, "context": null}| Field | Type | Required | Description |
|---|---|---|---|
selector | object | Yes | Registry query to find agents |
context | object | No | Extra context passed to discovered agents |
Tool registry reference (tool_ref)
Section titled “Tool registry reference (tool_ref)”Agent specs may reference a registered tool by tool_ref instead of embedding raw connection config.
{ "provider_id": "mcp", "tool_ref": "filesystem-tools", "human_approval": "NONE"}The registry must contain a matching ToolRegistration. Inline fields override registry values. For bundled connections, classify individual operations by severity, tier grants, and approval.
| Field | Type | Required | Description |
|---|---|---|---|
tool_ref | string | Yes | registered_tool_id to look up |
tier_ceiling | string[] | No | Narrows registry tier_grants for this agent (intersection) |
human_approval | "NONE" | "REQUIRED" | No | Legacy approval gate |
tier_ceiling intersects with the registry grants; it can never widen them.
| Severity | Max grantable tier | Approval |
|---|---|---|
read-only | reader, editor, operator | As configured |
mutating-recoverable | editor, operator | As configured |
destructive | operator only | Always required |
A tool name matching no classified operation is denied outright.
Human approval
Section titled “Human approval”| Value | Behavior |
|---|---|
"NONE" | Tool executes immediately unless the global authorization policy denies it |
"REQUIRED" | Emits a human-approval event before execution |
Knowledge bases
Section titled “Knowledge bases”A KnowledgeBase pairs a topic or collection with a consumption mode. It is safer to reference a registered topic by topic_id than to embed a raw collection_id, because the registry can enforce access policy and namespacing.
Common KnowledgeBase fields
Section titled “Common KnowledgeBase fields”| Field | Type | Required | Description |
|---|---|---|---|
topic_id | string | No | Reference to a TopicRegistration in the registry |
collection_id | string | No | Raw vector collection name (use only in dev/tests) |
description | string | No | Description used by the model |
search_mode | string | Yes | rag, on_demand, direct, or brain |
search_type | string | No | similarity, mmr, or similarity_score_threshold |
search_kwargs | object | No | Provider-specific search arguments |
connector | object | No | Knowledge provider connector; omitted for direct and brain |
tier_ceiling | string[] | No | Narrows the topic’s tier_grants for this agent (intersection) |
When topic_id is set, the runtime resolves agentspace_id, external_collection_id, and the topic’s access_policy from the registry. The effective collection name is {agentspace_id}__{collection_id} and an agentspace_id metadata filter is injected into every query.
Qdrant
Section titled “Qdrant”{ "collection_id": "product-docs", "description": "Product documentation and FAQs", "search_mode": "on_demand", "search_type": "similarity", "search_kwargs": { "k": 4 }, "connector": { "provider_id": "qdrant" }}{ "collection_id": "session-context", "search_mode": "rag", "search_kwargs": { "k": 4 }, "connector": { "provider_id": "redis", "ttl": 600 }}In-memory
Section titled “In-memory”{ "collection_id": "upload-context", "search_mode": "on_demand", "search_kwargs": { "k": 4 }, "connector": { "provider_id": "in_memory" }}search_mode
Section titled “search_mode”| Value | Behavior | Connector |
|---|---|---|
rag | Searched automatically before each LLM call | Required |
on_demand | Exposed as a search tool the agent calls explicitly | Required |
direct | Exposes list_files/read_file tools over a registered topic; no connector | Requires topic_id |
brain | Queries a registered Boltzmann Brain | Must be unset |
search_kwargs
Section titled “search_kwargs”| Field | Type | Default | Description |
|---|---|---|---|
k | integer | 4 | Number of results |
score_threshold | number | — | Minimum similarity score |
fetch_k | integer | — | Documents to fetch before MMR filtering |
lambda_mult | number | — | MMR diversity vs relevance |
filter | object | — | Metadata filters |
Direct file access
Section titled “Direct file access”search_mode: "direct" exposes list_files and read_file tools over a registered topic’s files. The agent can browse and read files directly instead of relying on vector search. The topic’s access_policy is enforced by the KnowledgeAuthzPolicy, so direct mode is not a bypass.
{ "topic_id": "product-docs", "search_mode": "direct", "tier_ceiling": ["reader", "editor"]}connectormust be omitted.- Files must be uploaded and associated with the topic via the runtime API or CLI.
- Use
tier_ceilingto narrow the registry’stier_grantsfor this agent.
See How to ingest files into a topic for upload and association steps.
Boltzmann brains
Section titled “Boltzmann brains”{ "search_mode": "brain", "brain_ref": "fourier-signals", "modules": ["semantic", "procedural"]}| Field | Type | Description |
|---|---|---|
brain_ref | string | brain_id of a registered brain |
modules | string[] | Memory modules to query |
See Memory & context and Tools & integrations for conceptual overviews.