AURA is an agentic harness that turns LLM models into a reliable, autonomous service capable of executing real SRE work. AURA provides the guardrails, API servers, state management, authentication, streaming, error handling, and tool integrations necessary to run AI SRE agents safely in production.
With AURA you can:
- Run entirely on your own infrastructure, including air-gapped and highly-regulated environments
- Define orchestrated clusters of production agents in one simple, human-readable TOML file: models, per-agent prompts, tools, and guardrails
- Run on the LLM backends you already use (OpenAI, Anthropic, Bedrock, Gemini, Ollama, OpenRouter), switch providers with a one-section edit, or mix models per worker
- Give agents real tools: point a config at any MCP server (HTTP streamable, SSE, or STDIO) and its tools are discovered and callable at runtime
- Require human approval (webhook or in-conversation) before sensitive tool calls execute
- Survive huge tool outputs without context floods: oversized results are parked on disk and the agent pulls in only the slices it needs
- Fan complex requests out to user-defined specialist workers: a coordinator plans a task DAG, runs independent tasks in parallel, and consolidates the results
- Ground answers in your own data with vector search (Qdrant, AWS Bedrock Knowledge Base) and teach agents task-specific procedures with on-demand skills
- Chat from the terminal with or without a server: the CLI runs agents in-process from a config, or connects to any OpenAI-compatible API
- Interoperate with other agents over the A2A protocol, or embed the Rust core directly in your own application
- Serve every agent as an OpenAI-compatible API, so existing clients and SDKs (LibreChat, OpenWebUI, …) work unchanged
Install the aura CLI and aura-web-server binaries (Linux/macOS, amd64/arm64):
curl -fsSL https://raw.githubusercontent.com/mezmo/aura/main/scripts/install.sh | bash| Variable | Default | Description |
|---|---|---|
AURA_VERSION |
latest |
Release version to install |
AURA_INSTALL |
~/.local/bin |
Install directory |
AURA_COMPONENT |
all |
Which binary: all, server, or cli |
AURA_REQUIRE_CHECKSUM |
0 |
1 to fail when a release checksum is missing, 0 to warn and continue |
Running a binary needs a config — see the quickstart guide and Configuration. To try AURA with no setup, use the Quick Start below.
cp .env.example .env # set your LLM provider, model, and API key
docker compose up -d # starts Aura (orchestrator mode) + LibreChat + Phoenix
docker compose exec -it aura ./aura --api-url http://localhost:8080 # chat with the orchestrator from your terminalAura boots in orchestrator mode: a coordinator routes each request — answering simple ones directly and decomposing complex ones across specialized workers. The bundled aura connects to the in-container server automatically and renders the coordinator's plan and worker activity as it streams.
Prefer a browser? Open http://localhost:3080 to chat in LibreChat, or http://localhost:6006 to inspect traces in Phoenix.
Full quickstart guide — provider setup (OpenAI, Anthropic, Ollama, llama-server), adding MCP tools, enabling vector search, serving multiple agents, and troubleshooting.
- Orchestration — Math MCP — Multi-agent orchestration with coordinator/worker architecture
- Kubernetes SRE — AI-powered SRE agent on KIND with Kubernetes and Prometheus MCP servers
- Example Configs — Minimal per-provider configs and complete agent compositions
Run the web server (to build and run from source, see DEVELOPMENT.md):
# Default: reads config.toml
cargo run --bin aura-web-server
# Custom config file
CONFIG_PATH=my-config.toml cargo run --bin aura-web-server
# Config directory (serves multiple agents)
CONFIG_PATH=configs/ cargo run --bin aura-web-server
# Host/port override
HOST=0.0.0.0 PORT=3000 cargo run --bin aura-web-server
# Enable Aura custom SSE events
AURA_CUSTOM_EVENTS=true cargo run --bin aura-web-server
# Kitchen sink: all options
CONFIG_PATH=configs/ \
HOST=0.0.0.0 PORT=8080 \
AURA_CUSTOM_EVENTS=true \
AURA_EMIT_REASONING=true \
TOOL_RESULT_MODE=aura \
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
cargo run --bin aura-web-server -- --verboseCore server options:
| Option | Env Variable | Default | Description |
|---|---|---|---|
--config |
CONFIG_PATH |
config.toml |
Path to TOML config file or directory |
--host |
HOST |
127.0.0.1 |
Bind host |
--port |
PORT |
8080 |
Bind port |
--server-url |
AURA_SERVER_URL |
host/port | Canonical public origin published in the A2A agent card (see below) |
--streaming-timeout-secs |
STREAMING_TIMEOUT_SECS |
900 |
Max SSE request duration |
--first-chunk-timeout-secs |
FIRST_CHUNK_TIMEOUT_SECS |
90 |
Max time to first provider chunk |
--streaming-buffer-size |
STREAMING_BUFFER_SIZE |
400 |
SSE backpressure buffer |
--aura-custom-events |
AURA_CUSTOM_EVENTS |
false |
Enable aura.* events |
--aura-emit-reasoning |
AURA_EMIT_REASONING |
false |
Enable aura.reasoning |
--tool-result-mode |
TOOL_RESULT_MODE |
none |
Tool result streaming: none, open-web-ui, aura |
--tool-result-max-length |
TOOL_RESULT_MAX_LENGTH |
1000 |
Max chars before truncation (aura events) |
--debug-provider-errors |
AURA_DEBUG_PROVIDER_ERRORS |
false |
Dev only. Surface raw upstream provider errors to clients (capped). Keep off when public-facing — error bodies can echo request content. Raw error is always in logs/OTel. |
--shutdown-timeout-secs |
SHUTDOWN_TIMEOUT_SECS |
30 |
Graceful shutdown window |
Tool result modes:
none: spec-compliant; tool results appear only in model summary.open-web-ui: tool results emitted throughtool_callsfor OpenWebUI compatibility.aura: tool results emitted viaaura.tool_completeevents.
API examples:
# Health
curl http://localhost:8080/health
# List available models (agents)
curl http://localhost:8080/v1/models
# OpenAI-compatible chat completion
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Hello"}]}'
# Select a specific agent by name or alias via the model field
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "my-agent", "messages": [{"role": "user", "content": "Hello"}]}'
# Streaming response
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Hello"}], "stream": true}'SSE protocol details, event types, custom events, and client handling are documented in docs/streaming-api-guide.md.
Disabled by default. A2A endpoints are only activated when the server is started with
--enable-a2a(orAURA_ENABLE_A2A=true). Omitting the flag means no A2A routes are registered and the agent card is not served.
Aura exposes A2A protocol endpoints for agent-to-agent interoperability. This allows other A2A-compatible agents and clients to discover and interact with Aura agents using a standardized protocol.
# Agent card (capability discovery)
curl http://localhost:8080/.well-known/agent-card.json
# Send a message via REST
curl -X POST http://localhost:8080/a2a/v1/message:send \
-H "Content-Type: application/json" \
-H "A2A-Version: 1.0" \
-d '{"message": {"messageId": "msg-001", "role": "ROLE_USER", "parts": [{"text": "Hello"}]}}'
# Send a message via JSON-RPC
curl -X POST http://localhost:8080/a2a/v1/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "method": "SendMessage", "params": {"message": {"messageId": "msg-002", "role": "ROLE_USER", "parts": [{"text": "Hello"}]}}, "id": 1}'Set
AURA_SERVER_URLwhen running behind a proxy, load balancer, or in Kubernetes. The agent card must advertise absolute endpoint URLs, and A2A clients use those URLs directly — a relative or wrong-host URL makesmessage:sendfail even though the card itself loads. Aura builds the card's URLs fromAURA_SERVER_URL(or--server-url); set it to the externally-reachable origin clients use (e.g.https://aura.example.com). When unset, it falls back to the bind host/port, which is only correct for direct local access.
A2A endpoints, transport modes, the agent card URL, task lifecycle, and testing examples are documented in docs/a2a-implementation.md.
Setting
enable_client_tools = trueon an agent grants the LLM the ability to call tools that execute on the client's machine. When clients (e.g.aura) advertise tools likeShell,Read, orUpdate, the LLM can invoke them and the client will execute them with the privileges of the user running the client. This is functionally equivalent to giving the model a shell prompt on every connecting client.The risks are real:
- Prompt injection. Anything the model reads — a file, an MCP tool output, a vector-store hit, a URL — can contain instructions that hijack the model into running destructive commands. The server cannot tell a legitimate request from an injected one.
- Hallucination. The model can confidently call the wrong tool with the wrong arguments. There is no undo for a
Shell("rm -rf ...")invocation.- No server-side sandbox. The server only forwards tool calls; execution happens client-side with full host privileges. Whatever sandboxing exists is the client's responsibility.
- Per-agent permission filters reduce blast radius but are not a security boundary.
client_tool_filtercontrols which tools the model can ask for, not what they do once invoked.Only enable on agents where:
- You trust the model, the provider, and every data source the model can read (configs, MCP servers, vector stores, web fetches).
- You trust every client that will connect with
--enable-client-toolsand the user account it runs under.- You and your users accept that worst-case loss (deleted files, leaked credentials, modified source) is acceptable or recoverable.
Disabled by default. Opting an agent in is your decision and your responsibility — and your users'.
See aura's matching warning for the client-side perspective.
Single-agent configurations only. Client-side tools are not supported in orchestrated (multi-agent) configurations — when
[orchestration].enabled = true, anytoolsarray on the request is dropped with a warning. The reason: the passthrough mechanism requires terminating the user-facing SSE stream withfinish_reason: "tool_calls", which doesn't compose with the coordinator/worker pipeline. If you need local tools, use a single-agent config.
The server honors a tools array on incoming chat completion requests. Whether those tools are actually attached to the LLM is a per-agent opt-in in TOML — there is no server-wide flag. Tools that get attached are registered as passthrough tools: the LLM sees them alongside any server-side MCP tools and can call them, but instead of executing server-side, the stream terminates with finish_reason: "tool_calls" so the client can run the tool locally and submit the result back as a role: "tool" follow-up.
[agent]
name = "Assistant"
system_prompt = "..."
enable_client_tools = true
client_tool_filter = ["Read", "ListFiles", "Find*"] # optional; omitted/empty = allclient_tool_filter is a list of glob patterns matched against the request's tools[].function.name. An empty or omitted filter means all client tools are available. A request that supplies tools never reaches an agent that did not opt in.
# 1) Initial request advertising a client-side tool
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"stream": true,
"messages": [{"role": "user", "content": "What time is it?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_current_time",
"description": "Get the current time",
"parameters": {"type": "object", "properties": {}}
}
}]
}'
# 2) Stream ends with finish_reason: "tool_calls". The client executes the tool
# locally and submits the result back in a follow-up request:
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"stream": true,
"tools": [ ... same tools array ... ],
"messages": [
{"role": "user", "content": "What time is it?"},
{"role": "assistant", "content": null, "tool_calls": [
{"id": "call_abc", "type": "function",
"function": {"name": "get_current_time", "arguments": "{}"}}
]},
{"role": "tool", "tool_call_id": "call_abc", "content": "2026-04-30T14:30:00Z"}
]
}'When the loaded agent doesn't opt in (the default), any tools field on the request is silently dropped; the server runs MCP tools as usual but never asks the client to execute anything. Per-agent opt-in is the design — accepting client-supplied tool definitions means trusting the client to execute them, so it should be a deliberate config decision. See aura for the matching client-side flag (--enable-client-tools) and how the two halves coordinate.
Recent breaking changes
- 21 April 2026:
[llm]moved under[agent.llm]; workers may override via[orchestration.worker.<name>.llm]. See migration guide. - 10 April 2026: Several fields moved from
[agent]to[llm]; Ollama params consolidated under[llm.additional_params]. See migration guide.
CONFIG_PATH can point to a single TOML file or a directory of .toml files. When pointed at a directory, AURA loads every .toml file and serves each as a selectable agent. Clients choose an agent via the model field in chat completion requests — the same field that tools like LibreChat, OpenWebUI, and CLI clients use to present a model picker.
To serve multiple agents, create a directory with one TOML file per agent:
configs/
├── research-assistant.toml
├── devops-agent.toml
└── code-reviewer.toml
CONFIG_PATH=configs/ cargo run --bin aura-web-serverEach agent is identified by its alias (if set) or name. Clients discover available agents via GET /v1/models and select one by passing its identifier as the model field in requests. When no model is specified, the server resolves the agent via DEFAULT_AGENT, or automatically when only one config is loaded.
The alias field provides a stable, client-facing identifier that is independent of the agent's display name:
[agent]
name = "DevOps Assistant"
alias = "devops" # clients send "model": "devops"
system_prompt = "You are a DevOps expert."
model_owner = "mezmo" # override owned_by in /v1/models (defaults to LLM provider)Hidden agents are excluded from GET /v1/models and the CLI's /model list but remain fully accessible when a caller targets them by exact name or alias. Set hidden = true to hide agents that are in development, restricted to known callers, or should not appear in model pickers (LibreChat, OpenWebUI, etc.):
[agent]
name = "Internal Triage Agent"
hidden = true # excluded from /v1/models and CLI model list; still callable by name
system_prompt = "..."Aliases must be unique across all loaded configs. If two configs share the same name and neither has an alias, loading fails with a validation error.
Configuration sections:
[agent]: identity, system prompt, and runtime behavior.[agent.llm]: provider and model configuration for the agent.[[vector_stores]]: optional vector search configuration.[mcp]and[mcp.servers.*]: MCP configuration, schema sanitization, and transports.[hitl]and[hitl.route]: optional approval gates for orchestration worker tool calls.
Supported providers: OpenAI, Anthropic, Bedrock, Gemini, Ollama, and OpenRouter.
Supported MCP transports:
http_streamable(recommended for production)ssestdio- launches a local child process per request. The MCP specification defines this transport for client-side sidecars, not for server deployments. If you need high concurrency, usehttp_streamable.
STDIO configuration uses cmd and args, both are lists. cmd[0] is the executable. Any additional elements in cmd are part of the command itself, such as a script path that needs an interpreter. args are passed to the spawned process separately:
# Binary with package arguments
[mcp.servers.my_stdio]
transport = "stdio"
cmd = ["npx"]
args = ["-y", "@modelcontextprotocol/server-everything"]
# Script that needs an interpreter
[mcp.servers.my_script]
transport = "stdio"
cmd = ["python3", "/opt/mcp-servers/weather.py"]
args = ["--verbose"]
# Direct binary
[mcp.servers.my_binary]
transport = "stdio"
cmd = ["/usr/local/bin/mcp-server"]
args = ["--config", "/etc/mcp/config.json"]Tool names are not namespaced by server. If two servers register a tool with the same name, the first one loaded wins silently (#186).
headers_from_request can forward incoming request headers to MCP servers for per-request auth.
turn_depth controls how many tool-calling rounds can happen in a single turn. Higher values allow multi-step tool workflows before final response generation. This acts as a failsafe to prevent models from spinning out in unbounded tool-call loops.
context_window sets the context window size (in tokens) for the agent, used for usage percentage reporting in aura.session_info streaming events.
The complete starter configuration is in examples/reference.toml. Minimal per-provider configs are in examples/minimal/ and complete agent examples are in examples/complete/.
Minimal example:
[agent]
name = "Assistant"
alias = "my-assistant" # optional: stable client-facing identifier
system_prompt = "You are a helpful assistant."
turn_depth = 2
[agent.llm]
provider = "openai"
api_key = "{{ env.OPENAI_API_KEY }}"
model = "gpt-5.2"
context_window = 128000
[mcp.servers.my_server]
transport = "http_streamable"
url = "http://localhost:8081/mcp"
headers = { "Authorization" = "Bearer {{ env.MCP_TOKEN }}" }To validate your own config file, start the web server or CLI — both validate the config immediately and exit with a clear error if parsing fails, before binding to any port or entering the REPL:
# Validate via web server (exits on parse error before binding)
cargo run -p aura-web-server -- --config your-config.toml
# Validate via standalone CLI (exits on parse error before REPL)
cargo run -p aura-cli -- --config your-config.tomlEnable orchestration mode in config:
# Top-level: shared by orchestration persistence and single-agent scratchpad
memory_dir = "/tmp/orchestration-memory"
[orchestration]
enabled = true
max_planning_cycles = 3
tools_in_planning = "summary"
allow_direct_answers = true
allow_clarification = true
[orchestration.worker.operations]
description = "Operational analysis and diagnostics"
preamble = "You are an operations specialist."
mcp_filter = ["ops_*"]
vector_stores = []
[orchestration.worker.knowledge]
description = "Documentation and procedures"
preamble = "You are a knowledge specialist."
mcp_filter = []
vector_stores = ["docs"]Each worker inherits [agent.llm] by default. To run a worker against a different model (cheaper, faster, bigger context, different provider), add a complete LLM configuration at [orchestration.worker.<name>.llm] - this must be a complete LLM configuration not just the individual LLM fields you want to "override":
[orchestration.worker.formatting.llm]
provider = "anthropic"
api_key = "{{ env.ANTHROPIC_API_KEY }}"
model = "claude-haiku-4-5-20251001"
context_window = 200000The worker's resolved context_window is what gets reported in per-worker aura.session_info events.
Execution loop:
Plan: coordinator decomposes the request into a task DAG.Execute: dependency-ready tasks run in parallel waves on worker agents.Continue: coordinator consolidates worker outputs and routes to a final response, replan, or clarification.
Workers run with isolated task context windows and filtered MCP/vector-store access based on each worker block.
For a fuller multi-worker example, see configs/example-math-orchestration.toml.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Enable orchestration mode |
max_planning_cycles |
int | 3 |
Maximum plan→execute→continue iterations |
allow_direct_answers |
bool | true |
Allow coordinator to answer simple queries directly |
allow_clarification |
bool | true |
Allow coordinator to ask for clarification |
tools_in_planning |
string | "summary" |
Tool visibility for coordinator: "none", "summary" (names only), "full" (with descriptions) |
max_plan_parse_retries |
int | 3 |
Retries if coordinator produces unparseable plan JSON |
max_tools_per_worker |
int | 10 |
Cap on MCP tools exposed to each worker |
duplicate_call_nudge_threshold |
int | 3 |
Consecutive identical tool calls before appending guidance annotation |
duplicate_call_block_threshold |
int | 5 |
Consecutive identical tool calls before appending abort annotation and setting escalation flag |
worker_system_prompt |
string | — | Optional global system prompt prepended to all workers |
coordinator_vector_stores |
list | [] |
Vector stores available to the coordinator agent |
result_artifact_threshold |
int | 4000 |
Character count above which worker results are saved as artifacts |
result_summary_length |
int | 2000 |
Max characters for artifact summaries passed to coordinator |
timeouts.per_call_timeout_secs |
int | 0 |
Per-tool-call timeout in seconds (0 = disabled) |
| Field | Type | Default | Description |
|---|---|---|---|
description |
string | required | Short description shown to coordinator during planning |
preamble |
string | required | System prompt for this worker |
mcp_filter |
list | [] |
Glob patterns selecting which MCP tools this worker can use |
vector_stores |
list | [] |
Named vector stores this worker has access to |
turn_depth |
int | — | Per-worker tool-call depth limit (overrides [agent].turn_depth) |
llm |
table | inherits [agent.llm] |
Optional per-worker LLM override — different model (and other [agent.llm] fields) while reusing provider credentials |
scratchpad |
table | inherits [agent.scratchpad] |
Optional per-worker scratchpad config override |
skills |
table | inherits [agent.skills] |
Optional per-worker skill sources; an explicit local = [] disables skills for this worker |
Human-in-the-loop (HITL) approval gates let orchestration workers ask for
permission before running selected MCP tools. Configure [hitl] with tool-name
globs and a [hitl.route]. Approved calls run normally; denied calls return a
blocked-action result to the worker without running the MCP tool.
[hitl]
require_approval = ["k8s_apply_*", "restart_*", "delete_*"]
[hitl.route]
mode = "webhook"
url = "https://approvals.example.com/aura"
timeout_secs = 300Current scope: webhook and conversational approval work for orchestration
workers. Approval lifecycle SSE events are emitted regardless of
AURA_CUSTOM_EVENTS; conversational mode also emits aura.approval_pending and
requires stream=true plus an Aura-aware client such as the AURA CLI in HTTP
mode. Single-agent config gates are not wired in this phase. See
docs/hitl.md for the route contracts and response behavior.
MCP tools can return responses far larger than an LLM's context window — a single Kubernetes workload listing or log export can be tens of thousands of tokens. Without intervention, this fills the context and degrades reasoning quality.
Scratchpad solves this by intercepting large tool outputs and storing them on disk. The LLM gets a summary and eight read-only exploration tools (head, slice, grep, schema, item_schema, get_in, iterate_over, read) to selectively pull in only the data it needs.
Scratchpad works in both single-agent and orchestration modes. Configure at [agent.scratchpad] (applies to the single agent, or provides defaults for orchestration workers) and optionally override per worker at [orchestration.worker.<name>.scratchpad]. Set a top-level memory_dir for persistence:
# Top-level — required when scratchpad is enabled. Shared by single-agent
# scratchpad and orchestration persistence.
memory_dir = "/tmp/aura"
[agent.scratchpad]
enabled = true
context_safety_margin = 0.20 # 20% of context reserved for reasoning/output
max_extraction_tokens = 10_000 # cap per extraction tool call
turn_depth_bonus = 6 # extra ReAct turns when scratchpad is active
[orchestration.worker.data-explorer.scratchpad]
# Override just for this worker
max_extraction_tokens = 5_000Storage location:
- Single-agent:
{memory_dir}/scratchpad/ - Orchestration:
{memory_dir}/{run_id}/iteration-{n}/scratchpad/(legacy[orchestration.artifacts].memory_dirstill works as a fallback)
Per-tool interception thresholds are configured at [mcp.servers.<server>.scratchpad]. Keys are glob patterns (default threshold 5_120 if omitted) that are matched against tool names at interception time:
[mcp.servers.k8s-sre.scratchpad]
"*_list_*" = { min_tokens = 512 } # broad
"k8s_list_service_monitors" = { min_tokens = 384 } # specific override
"*" = { min_tokens = 4096 } # catch-allWhen multiple patterns match the same tool, the longest (most specific) pattern wins; on length ties the smallest threshold wins. Token counting uses real BPE tokenization via tiktoken-rs — not byte/character heuristics — so min_tokens reflects actual model token cost.
Per-call extraction limit (max_extraction_tokens, default 10_000): every exploration tool checks the size of its result before returning. If a single call would exceed this cap (or the cumulative ContextBudget), the tool returns a structured JSON error like {"error": "head_too_large", "estimated_tokens": ..., "suggestions": [...]} instead of the content. The LLM sees this as a successful tool result and retries with smaller params — each retry consumes a turn, which is why turn_depth_bonus exists.
Each agent (single-agent or orchestration worker) gets a fresh ContextBudget scoped to that agent's effective LLM's context_window. LLM-reported per-turn token counts feed back into the budget as ground truth, so remaining() reflects actual context pressure (orchestration via StreamItem::TurnUsage, single-agent via the streaming hook). A per-agent aura.scratchpad_usage SSE event is emitted when the agent finishes — the same event name fires for both single-agent and worker contexts (it lives in the base aura.* namespace, not aura.orchestrator.*).
Result artifacts and read_artifact: in orchestration, large task results are saved to artifact files under {memory_dir}/{run_id}/artifacts/. When a worker reads one back with read_artifact, the same budget rules apply: an artifact that fits is returned inline, while one that exceeds the limit comes back as a scratchpad pointer the worker explores in place with the read tools (head, grep, slice, …) — the artifact is read directly from the artifacts directory, never copied into the scratchpad. (The coordinator has no scratchpad, so its read_artifact always returns inline content.)
Skills package task-specific instructions that the agent pulls in only when a task calls for them. Each skill is a directory in the Agent Skills format: a SKILL.md file with YAML frontmatter (name, description) followed by the instructions, plus optional references/, scripts/, and assets/ subdirectories for supporting files.
Rather than inlining every skill into the system prompt, AURA appends only a catalog of names and descriptions. The LLM calls the load_skill tool to fetch a skill's full instructions on demand, and read_skill_file to fetch individual resource files. read_skill_file resolves symlinks and rejects any path that escapes the skill directory.
[agent.skills]
local = [
{ source = "./skills" }, # relative paths resolve from the process CWD
{ source = "/opt/aura/shared-skills" }
]Each source is a directory containing skill subdirectories:
skills/
└── code-review/
├── SKILL.md # required: frontmatter (name, description) + instructions
├── references/ # optional resources, fetched via read_skill_file
├── scripts/
└── assets/
Discovery runs at agent build time and validates each skill against the specification; the frontmatter name must match the directory name. Directories without a SKILL.md are skipped. When two sources provide the same skill name, the first one loaded wins and a warning is logged. Relative sources resolve from the process current working directory in every mode (web server, standalone CLI, and A2A). CONFIG_PATH / --config locate the TOML file only; they do not change how paths inside TOML are resolved.
In orchestration mode the coordinator inherits [agent.skills]. Workers inherit it too, unless [orchestration.worker.<name>.skills] provides their own sources; an explicit empty list disables skills for that worker:
[orchestration.worker.knowledge.skills]
local = [{ source = "./knowledge-skills" }] # worker-specific skills
[orchestration.worker.operations.skills]
local = [] # no skills for this workerAURA supports Ollama, including fallback tool-call parsing for models that emit tool calls as text. Full setup, parameter guidance, and model caveats are in docs/ollama-guide.md.
OpenTelemetry support is enabled by default via the otel feature in both aura and aura-web-server. Configure your OTLP endpoint using standard environment variables (for example OTEL_EXPORTER_OTLP_ENDPOINT) to export traces.
AURA emits spans using the OpenInference semantic convention (llm.*, tool.*, input.*, output.*) rather than the gen_ai.* conventions. Any gen_ai.* attributes from underlying provider libraries (Rig.rs) are automatically translated to OpenInference equivalents at export time. This makes AURA traces natively compatible with Phoenix and other OpenInference-aware observability tools.
- DEVELOPMENT.md: building from source, project structure, Make targets, testing, and architecture.
- CONTRIBUTING.md: how to contribute, including the CLA, commit conventions, and the PR process.
- docs/quickstart.md: getting started guide — setup, customization, architecture, and troubleshooting.
- CHANGELOG.md: release and version history.
- docs/streaming-api-guide.md: SSE protocol guide, event taxonomy, tool result modes, custom
aura.*events, orchestration events, and client examples. - docs/hitl.md: human approval gates for orchestration worker tool calls, including webhook and conversational routes.
- docs/request-lifecycle.md: request flow diagram, lifecycle, timeout, cancellation, and shutdown behavior.
- docs/ollama-guide.md: Ollama configuration, fallback tool parsing, and local model guidance.
- docs/rig-fork-changes.md: Rig fork changes, tool execution order, and rationale.
- docs/tracing-spans.md: OpenTelemetry span layout, OpenInference span kinds, and trace parenting for both single-agent and orchestration modes.
- docs/breaking-changes/20260421-llm-under-agent.md: breaking configuration changes from 21 April 2026 —
[llm]moved under[agent.llm]and per-worker LLM overrides. - docs/breaking-changes/20260410-agent-llm-toml-configuration.md: breaking configuration changes from 10 April 2026 — field migrations from
[agent]to[llm]and Ollama parameter consolidation. - docs/a2a-implementation.md: A2A protocol endpoints, transport modes (REST and JSON-RPC), task lifecycle, and testing examples.
- docs/telemetry.md: anonymous, opt-out CLI telemetry — the three-state consent model, exactly what is and isn't collected, kill switches, and how to audit it.
Licensed under the Apache License, Version 2.0.