Agents
Agents are defined on the Pimcore PHP side. They come from three sources - Pimcore Studio edits, project container config, or bundle presets - and all of them are served to the agent-server through a single export endpoint. The agent-server image itself ships no built-in agent definitions.
Three-layer merge model with user-wins semantics: see README → The merge model. For the full mechanism - export endpoint, reload paths, skill materialization - see Architecture → Configuration System.
Editing an agent in Pimcore Studio
Open System → Pimcore Agent → Agent Configuration, pick an agent from the tree on the left, and use the tabbed editor. Saving an agent automatically calls the agent-server reload endpoint so the change takes effect on the next message - no restart needed.
Bundle presets live alongside the CRUD DAO, not inside it, so they do not appear in the Pimcore Studio tree. To customize a preset, create a new agent with the same name; the merge rules guarantee the new user-scoped entry wins. To revert, delete the user entry - the bundle preset will resurface automatically on the next reload.
YAML schema
Whether an agent lives in Pimcore Studio, in a project
config/packages/*.yaml, or in a bundle preset file, it has the same
shape. The example below shows every field an agent supports.
name: data-management # Unique identifier (required)
displayName: Data Management # Shown in the agent dropdown (required)
description: >- # Shown as tooltip, used in cross-agent (required)
Search and edit Pimcore data. # awareness block
All writes go through proposals.
icon: edit # Icon name for the UI (e.g. chat, edit, search, image)
default: false # Exactly one agent may be the default
provider: anthropic-cloud # Named inference provider; omit to use default_provider
model: claude-haiku-4-5-20251001 # Per-agent LLM model; resolved within the chosen provider
streamThinking: true # Stream model reasoning as collapsible bubbles
allowAgentSwitch: true # Offer the cross-agent awareness block + switch widget (chat only)
reasoningEffort: medium # Reasoning-effort level (model-specific); omit for provider default
group: editors # Optional folder grouping in the Pimcore Studio tree
systemMessage: >- # Prepended to the SDK's system sections
You are a Pimcore data management assistant. All write operations
require user approval - follow the proposal skills for the correct
propose → review → approve workflow.
skills: # Skill names. See 02_Skills.md
- pql-search
- general
- data-object-proposals
includeSdkTools: # Opt-in SDK tools. See 04_Tool_Security_Reference.md
- web_fetch
- ask_user
richChatWidgets: # LLM-callable display widgets only
- pimcore_open_element
- show_data_object_preview
- show_data_table
pimcoreMcpServers: # Direct Pimcore MCP tool groups. See 03_MCP_Servers.md
- pimcore-data-objects-read
- pimcore-data-objects-write
allowedFileStagingSets: # File-set names this agent may stage; non-empty
- cms_layouts # also auto-enables the stage_file_set tool
pimcoreMetaGroups: # Pimcore tool groups via the meta-tool
- pimcore-tags-read
mcpServers: # Third-party MCP servers. See 03_MCP_Servers.md
pimcore-datahub:
type: http
url: ${MCP_PIMCORE_URL}
headers:
Authorization: "Bearer ${MCP_PIMCORE_TOKEN}"
tools: "*"
pauseAfter: # Interactive "continue or stop" checkpoint
toolCalls: 25
timeoutMinutes: 2
Only name, displayName, and description are required. Everything
else is optional.
Field reference
| Field | Type | Meaning |
|---|---|---|
name | string | Unique id. For a bundle preset file, the filename (minus extension) is used if this field is omitted. |
displayName | string | Label shown in the agent dropdown. |
description | string | Tooltip + used in the cross-agent awareness block in every agent's system prompt. |
icon | string | Icon name (e.g. chat, edit, search, image). |
default | boolean | Exactly one agent can be default: true. Listed first in the dropdown and used when no agent is specified. |
provider | string | Named inference provider from pimcore_agent.inference.providers. Omit to use default_provider. If set to an unknown name, session creation fails. Selectable in the Pimcore Studio agent editor. See Inference Providers. |
model | string | Per-agent LLM model. Resolved within the chosen provider - must be a model id present in that provider's available_models (byok) or the Copilot catalog (github). Omit to use the provider's default_model. Validated on reload; unknown models block session creation. |
streamThinking | boolean | Stream reasoning / thinking events to the chat UI as collapsible bubbles. |
allowAgentSwitch | boolean | Whether this agent takes part in agent switching in interactive chat. Default true. When false, the cross-agent awareness block is left out of the system message and the pimcore_switch_agent widget is never offered for this agent. Chat only; it has no effect on agent tasks, where switching is unsupported regardless of this field. Editable in Pimcore Studio on the agent's Behavior tab. |
reasoningEffort | string | Reasoning-effort level for this agent. Must be one of the levels the selected model advertises (e.g. low, medium, high). Empty or absent means the model's default is used. The Pimcore Studio shows this field only when the selected model has reasoning-effort levels; in github mode the levels come from the Copilot catalog. An incompatible value (level not in the model's supported set) fails the chat turn (at session creation or resume) with an explicit error. |
group | string | Folder grouping in the Pimcore Studio config tree. |
systemMessage | string | Prepended to the SDK's own system sections. Append mode - SDK guardrails remain in place. |
skills | string[] | Skill names. Unknown names are silently dropped. See Skills. |
includeSdkTools | string[] | Opt-in SDK tools beyond the default read-only set. See Tool Security Reference. |
richChatWidgets | string[] | LLM-callable display widgets this agent may emit. Proposal widgets are auto-emitted by the server when a propose_* tool succeeds and do not need to be listed here - only the display widgets do. |
pimcoreMcpServers | string[] | Direct Pimcore MCP group names. See MCP Servers. |
allowedFileStagingSets | string[] | File-set names this agent may stage. A non-empty value auto-enables stage_file_set. See File Staging. |
pimcoreMetaGroups | string[] | Meta-tool Pimcore groups. See MCP Servers. |
mcpServers | object | Third-party MCP servers. See MCP Servers. |
pauseAfter | object | Interactive pause thresholds. See below. |
permissions | object | Optional per-agent visibility and access restriction (run/update per user or role). See below. |
executionUser | string | Optional Pimcore username the whole session runs as instead of the chat initiator. Admin only. See Execution user. |
pauseAfter sub-schema
| Key | Type | Default | Purpose |
|---|---|---|---|
toolCalls | integer | 50 | Pause after this many tool calls. |
timeoutMinutes | integer | 5 | Pause after this much active processing time. User-wait time is excluded. |
Whichever threshold fires first triggers the pause. Both keys are optional; omit one to use its default. For the
user-facing flow and when to tune these values, see Features → Interactive Input → pauseAfter.
Permissions
Agent configurations can optionally carry a permissions field that restricts which Pimcore users may see, run,
and manage a given agent. When the field is absent, the agent is governed only by the two global permissions -
pimcore_agent_use to run any agent, pimcore_agent_config to configure any agent - and every user who holds them
can use every agent equally.
permissions:
user:
- { name: jdoe, run: true, update: true }
role:
- { name: editors, run: true, update: false }
Each entry under user or role identifies a Pimcore user or role by name, not id, so a configuration stays
portable across Pimcore instances where numeric ids differ. Two independent booleans control what that user or role
may do with this specific agent:
| Level | Grants |
|---|---|
run | See the agent in the Pimcore Studio tree and in the chat agent selector, and start chat sessions with it. Together with the global pimcore_agent_config permission, also allows opening its configuration read only. |
update | Change the agent configuration, edit its permissions, clone it, and delete it. Implies run. |
update is the top per-agent level: it grants full management of the agent (including editing this same
permissions block and deleting the agent), so there is no separate delete level to escalate to. A user who can
create or clone an agent therefore holds update on it and can restrict it themselves.
Evaluation rules
Evaluation mirrors the Data Hub permission model:
- Admin users are always allowed everything, regardless of
permissions. - When both the
userandrolelists are empty, the agent carries no per-agent restriction and is governed only by the global permissions. - When any entry exists, a direct
userentry decides on its own: an explicitfalseblocks that user even when one of their roles would grant the same level. - If no direct
userentry matches, the user's roles are unioned: any role that grants a level is enough. - Per-agent permissions only ever restrict within the global permission; they never extend it. A user without
pimcore_agent_usecannot run any agent regardless ofpermissions.
Where run is enforced
The run permission is enforced everywhere an agent can be used, not only in the configuration tree:
- The Pimcore Studio agent configuration tree hides agents the user cannot run.
- The chat agent selector lists only runnable agents, and the agent-server omits non-runnable agents from the switch-suggestion prompt so an agent is never proposed as a switch target the user cannot use.
- Starting a chat session with, or switching a session to, an agent the user cannot run is rejected server side.
The agent-server obtains the per-user runnable set from a Pimcore endpoint gated by pimcore_agent_use, so the
permission logic stays authoritative in one place.
Editing permissions in Pimcore Studio
Open the agent in System → Pimcore Agent → Agent Configuration and switch to the Permissions tab. The tab
lists users and roles with the run and update checkboxes and only appears for users who may update the agent. The
clone and delete tree actions are likewise available only to users who may update the agent. The picker behind
the tab is backed by a listing endpoint gated by pimcore_agent_config.
Presets and portability
Bundle-shipped preset agents carry no permission sets unless their YAML explicitly declares them, so presets stay
open to every user with the global permissions by default. To restrict a preset on a given instance, override it
by name in Pimcore Studio and add a permissions block to the override; the merge rules guarantee the new
user-scoped entry wins. See Editing an agent in Pimcore Studio above for
how overrides work.
Execution user
Agent configurations can optionally carry an executionUser field: a Pimcore username the whole session runs as,
instead of the user who started the chat.
executionUser: reporting-service-account
When the field is empty (the default), the agent runs as the chat initiator, exactly as it does without this field set at all. When it is set, every tool call, MCP call, and permission check in that session runs with the configured user's permissions rather than the initiator's. This works because the effective user is resolved once at session creation and the MCP access token is minted for that user - the tools already derive their acting user from the token, so no further wiring is needed. See Architecture → Authentication → Execution user resolution for the mechanism.
Session ownership stays with the initiator: the chat session, its history, its entry in the session listing, and resume all remain the initiating user's. Only the acting identity changes for the duration of the session.
Fail closed
If executionUser is set to a name that does not resolve to an active Pimcore user, session creation fails with an
error rather than silently falling back to the initiator. Fix the typo or reactivate the user before sessions with
that agent can start again.
Admin only
Only administrators can set, change, or clear executionUser. Non-admin users see the field read only in Pimcore
Studio, and the server rejects a changed value coming from a non-admin request.
Editing in Pimcore Studio
Open the agent in System → Pimcore Agent → Agent Configuration and find the field on the General tab. Pimcore Studio shows a warning next to the field once it carries a value, calling out the permission implications described below.
Security implications
The execution user can hold more permissions than the users who chat with the agent. Because the agent acts as the execution user, its responses can surface information (object content, listings, search results, proposal values) that the chatting users cannot access directly - an information disclosure risk. HITL proposals created during such a session are computed with the execution user's permissions too, so an approver may see proposed values derived from data outside their own visibility.
The recommended mitigation is to combine an execution user with the agent's own run permission so
only an intended audience can start sessions with that agent at all. See
Architecture → Tool Security and
Tool Security Reference for the full
security note.
Agent tasks
pimcore_agent.tasks.* bounds the whole headless-task subsystem used by
headless agent tasks - work delegated to an agent from PHP rather than through a
Studio chat session. Whether a given agent writes autonomously or through HITL proposals inside a task is not a
task-specific setting at all; it follows directly from which MCP tool group the agent configuration grants it, see
Features → Agent Tasks → Autonomy and HITL.
pimcore_agent:
tasks:
max_concurrent: 5 # bundle-wide cap on concurrently `running` tasks
retention_days: 30 # terminal tasks are reaped this many days after finishing
default_deadline_minutes: 30 # soft per-task deadline, unless the caller overrides it
default_max_auto_continues: 5 # auto-continue budget, unless the caller overrides it
| Key | Type | Default | Meaning |
|---|---|---|---|
max_concurrent | integer | 5 | Hard cap on tasks in queued/running at once, enforced at start(). A caller over the cap gets TooManyTasksException; the Copilot step retries with backoff instead of failing outright. |
retention_days | integer | 30 | How long a terminal task (and its session) survives before the maintenance watchdog deletes it. |
default_deadline_minutes | integer | 30 | Soft deadline applied to a task when its request does not set deadlineMinutes itself. |
default_max_auto_continues | integer | 5 | Auto-continue budget applied to a task when its request does not set maxAutoContinues itself. |
These are container parameters, not per-agent YAML fields - set them once under pimcore_agent.tasks in
config/packages/pimcore_agent.yaml. See Architecture → Agent Tasks for
how the concurrency cap, deadline, and retention window are enforced.
Model validation
The model field is validated on startup, on every reload, and periodically (AGENT_SERVER_MODEL_CHECK_INTERVAL_MS, default 1 h).
An agent that references a model the provider does not serve logs a warning and blocks at session-creation time -
no silent fallback. Mechanism: Architecture → Agent Framework → Model configuration.
Inspect the current agent / model pairings:
curl -H "Authorization: Bearer $AGENT_SERVER_ADMIN_TOKEN" \
http://localhost/agent-server/api/admin/models
BYOK providers: the SDK has no built-in model catalog in BYOK mode. Define the model list in the provider's
available_modelsblock so validation can run and the Pimcore Studio model dropdown is populated. See Inference Providers.
Reloading changes
Saving in Pimcore Studio auto-triggers a reload on the agent-server - the change takes effect on the next message with no restart. To trigger a reload manually (for debugging, or after editing a preset YAML in a bundle):
curl -X POST -H "Authorization: Bearer $AGENT_SERVER_ADMIN_TOKEN" \
http://localhost/agent-server/api/admin/reload-agents
The response body includes modelWarnings and toolWarnings. For the three paths the registry can be repopulated
(Studio CRUD push, background retry after startup failure, manual reload), see
Architecture → Configuration System → Reload & recovery paths.
Related docs
- Inference Providers - defining named providers, byok vs github,
available_models, per-model limits. - Features → Agents and Switching - user-facing behaviour, awareness block, agent switching UX.
- Architecture → Configuration System - merge pipeline, recovery paths, skill materialization.
- Shipping Presets - ship agents from your own bundle.
- Features → Agent Tasks - headless agent tasks,
pimcore_agent.tasks.*in use. - Architecture → Agent Tasks - the task state machine and delegated access.