Agent configuration
An agent's configuration is one JSON object, the agent template. It is stored on a workflow revision and travels on the wire at data.parameters.agent.
The schema is published as the catalog type agent-template. Fetch the live JSON Schema with:
GET /api/workflows/catalog/types/agent-template
The template rejects unknown keys. The harness, runner, and sandbox sub-objects also reject unknown keys at parse time and return HTTP 400.
For what these parts mean, see Agents, Instructions, Harnesses and models, and Permissions.
Top-level fields
Every field is optional. An omitted field falls back to the default in the table.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
instructions | object | No | {"agents_md": "<built-in text>"} | The agent's instruction documents. |
llm | object | No | see llm | The model the agent runs on, its provider, and its credential connection. |
tools | array | No | [] | Tools the agent can call. Each entry is one of the tool objects below. |
mcps | array | No | [] | MCP servers exposed to the agent. |
skills | array | No | [] | Skills the agent ships with. |
harness | object | No | see harness | The coding agent to drive, plus its gating posture. |
runner | object | No | see runner | The engine that drives the harness loop, plus the tool execution policy. |
sandbox | object | No | see sandbox | Where the agent runs, plus its security boundary. |
instructions
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
agents_md | string | No | A built-in hello-world text | The agent's system prompt. The harness receives it as AGENTS.md. |
llm
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
model | string | No | "gpt-5.6-luna" | Model id in the provider's namespace. A provider/model string also parses, split on the first /. |
provider | string or null | No | null | Model provider. When unset, resolution infers it from a matching stored connection, and fails with an error when it cannot. |
connection | object or null | No | null | Where the model credential comes from. Omit for the project default. |
extras | object | No | {} | Model knobs passed through unchanged, for example reasoning_effort. |
llm.connection
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
mode | "agenta" | "self_managed" | No | "agenta" | agenta uses a connection stored in the project. self_managed injects no credential; the harness signs itself in. |
slug | string or null | No | null | The named stored connection. Valid only with mode: "agenta". Omit for the project default. Setting it with self_managed is rejected. |
Which providers, deployments, and connection modes each harness can reach is served per harness:
GET /api/workflows/catalog/harnesses/{harness}
In the shipped table, pi_core reaches openai, anthropic, gemini, mistral, groq, minimax, together_ai, and openrouter, with deployments direct and custom. claude reaches anthropic only, with deployments direct, custom, bedrock, and vertex_ai, and selects its model by alias rather than by a provider/model string.
tools
Each entry in tools is an object discriminated by type. Code, client, and reference tools accept the shared fields below. A gateway_connection entry uses its own policy instead.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
permission | "allow" | "ask" | "deny" | null | No | null | Per-tool override of the runner policy. Absent means inherit runner.permissions.default. |
render | object or null | No | null | Display hint carried through to the client. |
Harness built-ins
Harness built-ins are always active. Do not list them in tools. Pi provides read, bash, edit, write, grep, find, and ls; the runner treats read, grep, find, and ls as read-only.
{"type": "builtin", "name": "read"} is a legacy shape. Agenta accepts and ignores it while older revisions migrate.
type: gateway_connection
One connected application, including all actions that its integration advertises.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | "gateway_connection" | Yes | ||
connection.provider | "composio" | No | "composio" | Integration gateway. |
connection.integration | string | Yes | Connected app key, such as github. | |
connection.slug | string | Yes | Existing project connection slug. | |
policy.permissions.default | "inherit" | "allow" | "ask" | "deny" | No | "inherit" | Default for actions on this connection. |
policy.permissions.tools | object | No | {} | Per-action decisions keyed by action name. |
{
"type": "gateway_connection",
"connection": {
"provider": "composio",
"integration": "github",
"slug": "github-primary"
},
"policy": {
"permissions": {
"default": "allow",
"tools": { "DELETE_REPOSITORY": "deny" }
}
}
}
The connection slug must already exist. A second gateway_connection for the same provider and integration is rejected.
The per-action gateway shape is legacy. Preserve it when reading an older revision, but use gateway_connection for new configurations.
type: code
A script the runner executes.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | "code" | Yes | ||
name | string | Yes | Model-visible tool name. | |
description | string or null | No | null | What the tool does. |
runtime | "python" | "node" | No | "python" | Script runtime. |
script | string | Yes | The script source. | |
input_schema | object | No | {"type": "object", "properties": {}} | JSON Schema for the tool's arguments. |
secrets | array of string | No | [] | Names of secrets injected into the script's environment. |
type: client
A tool the calling client fulfils instead of the server.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | "client" | Yes | ||
name | string | Yes | Model-visible tool name. | |
description | string or null | No | null | What the tool does. |
input_schema | object | No | {"type": "object", "properties": {}} | JSON Schema for the tool's arguments. |
type: reference
Another workflow exposed to the agent as a tool. Agenta runs it server-side.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | "reference" | Yes | ||
ref_by | "variant" | "environment" | No | "variant" | Which axis selects the workflow revision. |
slug | string | Yes | The workflow slug to reference. | |
environment | string or null | No | null | Environment slug. Required when ref_by is "environment", rejected otherwise. |
version | string or null | No | null | Pin a revision. Valid only with ref_by: "variant". Absent means the latest revision. |
name | string or null | No | null | Legacy display-name copy. It does not change the model-visible name. |
description | string or null | No | null | What the tool does. |
input_schema | object | No | {"type": "object", "properties": {}} | JSON Schema for the tool's arguments. |
The workflow slug becomes the model-visible tool name.
Platform tools
Agenta can inject platform operations such as discover_tools into a run. Do not add a type: "platform" entry to the stored template. The commit API rejects authored platform tools.
mcps
Each entry declares one MCP server. See MCP servers for these fields in context, and Tools and integrations for the concept.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | 1 to 128 characters matching ^[A-Za-z0-9._-]+$. The name agenta-tools is reserved and rejected. The harness renders this server's tools as mcp__<name>__<tool>, so it is frozen when the connection is chosen and renaming that connection does not change it. | |
connection | object | Yes | Which connection reaches the server. One of the two shapes below, selected by type. | |
policy | object | No | {"tools": {"mode": "all", "names": []}} | Which of the server's tools are exposed, and at what permission. |
mcps[].connection, gateway
The shape the platform writes. The upstream URL and the credentials belong to the connection, so neither appears in the agent template.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | "gateway" | Yes | ||
namespace | "custom" | "standard" | "builtin" | Yes | custom is a server connected in this project. | |
slug | string | With custom | The connection's platform slug, derived once and never changed. Rejected with the other namespaces. | |
provider | string | With standard and builtin | The provider key. Rejected with custom. |
An entry that carries no connection is matched to a connection by name. That fallback is deprecated and kept only for agent revisions committed before connections had an identity of their own.
mcps[].connection, direct HTTP
Used where no gateway is configured, such as an SDK run outside the platform.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | "http" | Yes | Transport. | |
url | string | Yes | The server URL. | |
headers | object of string | No | {} | Public request headers. |
credentials | object | No | {"type": "none"} | Either {"type": "none"} or {"type": "header_secret_refs", "headers": {"<header>": "<secret-slug>"}}. Secret values resolve at run time and are never stored in the configuration. |
A header name may not appear in both headers and credentials.headers. The comparison ignores case.
mcps[].policy
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
tools.mode | "all" | "include" | No | "all" | all exposes every tool the server advertises. include exposes only tools.names. |
tools.names | array of string | No | [] | Tool names as the server advertises them. Required with include, rejected with all. |
permission | "allow" | "ask" | "deny" | null | No | null | Permission applied to this server's tools. Absent means inherit runner.permissions.default. |
tool_permissions | object | No | {} | Per-tool permissions, keyed by the name the server advertises (echo), never the harness-rendered name (mcp__acme__echo). |
new_tool_permission | "allow" | "ask" | "deny" | No | unset | Permission for an advertised tool that tool_permissions does not name. |
Setting either tool_permissions or new_tool_permission opts this server into per-tool policy. An advertised tool then resolves to its tool_permissions entry, and otherwise to new_tool_permission, which is ask when you leave it unset. Neither permission nor runner.permissions.default reaches a tool the table does not name, so nothing set elsewhere can widen the table. With both fields absent, the entry carries no per-tool policy and permission governs the whole server, exactly as before.
The permission editor writes new_tool_permission for you where the server is set to allow: giving one tool a rule of its own also records allow as the default for the tools you have not named, so those tools keep running as they did. Set the field yourself to choose a narrower default. Picking Ask for write and delete in that editor writes permission: "ask", an allow entry in tool_permissions for each tool the server marks read-only that the filter admits, and new_tool_permission: "ask".
tool_permissions may not name a tool that tools.mode: "include" hides. That configuration is rejected rather than silently dropped.
skills
Each entry is an inline skill package. See Skills.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | 1 to 64 characters matching ^[a-z0-9]+(-[a-z0-9]+)*$. | |
description | string | Yes | 1 to 1024 characters. This is what the agent sees at the start of a session, and what decides when the skill loads. | |
body | string | Yes | 1 to 50,000 characters. The skill's SKILL.md content after the frontmatter. | |
files | array | No | [] | Files laid beside SKILL.md. |
disable_model_invocation | boolean | No | false | Hide the skill from the prompt so it loads only when invoked by name. |
allow_executable_files | boolean | No | false | Allow bundled files to be marked executable. Sandbox policy must also allow it. |
skills[].files[]
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
path | string | Yes | 1 to 255 characters. Relative POSIX path. A leading /, a backslash, a .. segment, or a root-level SKILL.md is rejected. | |
content | string | Yes | UTF-8 text, up to 200,000 characters. | |
executable | boolean | No | false | Mark the file executable when it is written out. |
harness
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
kind | "pi_core" | "claude" | "codex" | No | "pi_core" | Which coding agent to drive. |
permissions | object | No | see harness.permissions | Tool-use gating posture, applied by harnesses that gate. |
extras | object | No | {} | Per-harness knobs passed through unchanged. For Pi, system replaces the base system prompt and append_system adds to it. Both are independent of instructions.agents_md. |
kind | Display name | Versioned slug |
|---|---|---|
pi_core | Pi | agenta:harness:pi_core:v0 |
claude | Claude Code | agenta:harness:claude:v0 |
codex | Codex | agenta:harness:codex:v0 |
pi_agenta was an experimental Pi variant, removed in August 2026. A stored config that still carries the value runs as pi_core.
harness.permissions
Applied by harnesses that gate tool use. Claude Code renders it into .claude/settings.json in the session working directory. Pi uses these rules for its built-in tools. Codex renders no per-tool rules of its own; its tool gating comes from runner.permissions and the permission on each tool entry.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
default_mode | "default" | "acceptEdits" | "plan" | "bypassPermissions" | null | No | null | The harness's own default permission mode. |
allow | array of string | No | [] | Per-tool rules approved without prompting. |
ask | array of string | No | [] | Per-tool rules that raise a prompt. |
deny | array of string | No | [] | Per-tool rules always rejected. |
runner
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
kind | "sidecar" | No | "sidecar" | The engine that drives the harness loop. sidecar is the only value. |
permissions | object | No | {"default": "allow_reads"} | The runner-enforced tool execution policy. |
extras | object | No | {} | Per-runner knobs passed through unchanged. |
runner.permissions
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
default | "allow" | "ask" | "deny" | "allow_reads" | No | "allow_reads" | allow runs every tool without asking. ask requires approval for every tool. deny refuses every tool. allow_reads runs read-hinted tools and asks for everything else. |
A value outside that set is rejected. A permission set on a single tool entry overrides this default for that tool.
sandbox
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
kind | "local" | "daytona" | No | "local" | Where the agent runs. |
credentials | array | No | [] | Project secret references bound to environment variables in the sandbox. |
permissions | object or null | No | null | The declared security boundary. Unset means no declared boundary, and the field never reaches the wire. |
extras | object | No | {} | Per-sandbox knobs passed through unchanged, for example a Daytona snapshot. |
Each credential entry has secret.slug and a binding shaped as {"type": "env", "name": "VARIABLE_NAME"}.
A deployment restricts which sandbox providers it accepts. A request naming a provider the deployment has not enabled is refused before the run starts.
sandbox.permissions
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
network.mode | "on" | "off" | "allowlist" | No | "on" | Outbound network policy. |
network.allowlist | array of string | No | [] | CIDR ranges allowed when network.mode is "allowlist". |
filesystem | "on" | "readonly" | "off" | null | No | null | Declared only. Not enforced. |
enforcement | "strict" | "best_effort" | No | "strict" | strict fails the run when the boundary cannot be applied. |
The default template
This is the value a new agent starts with. It is also the default on the agent workflow's /inspect parameters schema.
{
"instructions": {
"agents_md": "You are a friendly hello-world agent running on the Agenta agent service.\n\n- Greet the user warmly.\n- Answer the user's message in one or two short sentences."
},
"llm": {
"provider": "openai",
"model": "gpt-5.6-luna"
},
"tools": [],
"mcps": [],
"harness": { "kind": "pi_core" },
"runner": { "kind": "sidecar", "permissions": { "default": "allow_reads" } },
"sandbox": { "kind": "local" }
}
An empty tools array adds no configured tools. The harness built-ins remain active.
Rejected shapes
The parser returns HTTP 400 instead of falling back to a default when:
| Sent | Error | Use instead |
|---|---|---|
A flat model key on the template | Pre-migration flat key | llm.model |
A flat agents_md key on the template | Pre-migration flat key | instructions.agents_md |
harness or sandbox as a bare string | Pre-migration flat selector | {"kind": "..."} |
A key other than kind, permissions, or extras inside harness, runner, or sandbox | Unknown selector key | One of the three allowed keys |
A runner.permissions.default outside the four modes | Invalid permission default | allow, ask, deny, or allow_reads |
Embed references
A tools or skills entry can be an @ag.embed reference instead of an inline object. Agenta resolves it into the inline shape server-side, before the runner sees it.
{
"@ag.embed": {
"@ag.references": { "workflow": { "slug": "pdf-report" } },
"@ag.selector": { "path": "parameters.skill" }
}
}