Skip to main content
agent_config() reads an agent’s prompt and skills from DecimalAI and hands them over as one Pydantic AI capability, which you pass in your own Agent(capabilities=[...]). The capability gives the agent its saved prompt and skill list as instructions, adds a load_skill tool, and makes each run one trace, filed under the DecimalAI agent, with no other setup (SDK 0.25+). Nothing in Pydantic AI is patched, so an agent gets DecimalAI’s prompt and skills only when you give it the capability, and other agents in the process are left alone. agent_config() needs SDK 0.21 or later; 0.19 and 0.20 called it load_agent().

Install

The extra installs pydantic-ai-slim[openai,google,anthropic]>=2.56.0 (SDK 0.14.0+), so the adapter needs no second package; pydantic-ai-harness is only for loading installed skills with the harness (pydantic-ai-harness 0.56.0 pins pydantic-ai-slim 2.56.0 exactly). The adapter is tested with pydantic-ai-slim 2.56.0 and supports 2.56 and later only. It needs Python 3.11+: on Python 3.10, pip quietly installs decimalai 0.13.9 instead, so check with pip show decimalai, or install "decimalai[pydantic-ai]>=0.19" to make pip fail rather than fall back to a release without agent_config(). Don’t pin the pydantic-ai meta package to an older release: pydantic-ai==2.31.1 pins pydantic-ai-slim==2.31.1, and pip resolves decimalai back to 0.13.9 to satisfy it.

Use

  • agent_config("support-agent") reads the agent’s saved prompt when it is called. It initializes the SDK from DECIMAL_API_KEY when decimalai.init() has not been called, and a name your workspace has no agent by is created (SDK 0.24+), so a misspelled name makes a new agent rather than an error. fallback= is what runs when the agent has no saved prompt yet, when no DecimalAI key is set, or when DecimalAI cannot be reached at startup; with a key and no fallback=, an unreachable DecimalAI raises instead of starting an agent with no instructions. With no key at all, the agent runs without a DecimalAI key: the skills your project lists in .decimal/skills.toml, with nothing sent.
  • capabilities=[support] adds instructions: the saved prompt, then this agent’s skill list, chosen for the run’s prompt, and one sentence telling the model to load a skill before using it. Your own instructions= stay first and unchanged, so they remain a prefix a provider can cache.
  • load_skill is the capability’s one tool, limited to the agent’s skills. The model calls it with a skill’s name and gets the skill’s full text back, which counts as delivered and activated on the usage ladder. Each load names the run’s routing decision, and the platform decides what it serves: a skill your org owns, has installed or has assigned to the agent loads whether or not this run’s list showed it, while one reachable only through the public registry loads only when this run was offered it.
  • support.name is the agent’s name in DecimalAI. Every run is routed for it and traced under it, whatever the Agent is called. name=support.name makes the two agree.
  • Each run is one trace, with Pydantic AI’s own spans for its model calls and tool calls, and no other line: no decimalai.init(otel=True), no Agent.instrument_all() (SDK 0.25+). Tracing says how, and what happens when your app traces Pydantic AI itself. decimalai init --framework pydantic-ai writes the same file.

Change the prompt without redeploying

agent_config() keeps a local copy of the prompt and re-reads it in the background at most once a minute, so a version saved in the dashboard’s Prompt tab reaches the next run within a minute, with no redeploy. Pinning an older version there, or serving the latest again, works the same way. On Claude, an open conversation keeps its prompt. Claude rejects a conversation whose system prompt or tools changed once a thinking block is in its history (HTTP 400, “The block is bound to a different conversation”), and Claude 5.x models think by default. So on a Claude model, a run given message_history= shows the same instructions and load_skill as that conversation’s first run. A saved version, a changed skill list or a newly picked list reaches the next conversation instead. The capability keeps its copy in the metadata of each run’s first request. Pydantic AI keeps that field in result.all_messages() and never sends it to the model, so a history you store with ModelMessagesTypeAdapter and load in another process keeps the copy too. Variables keep the values of the conversation’s first run, and your own instructions must stay the same across a conversation as well. On other models, every run gets the newest prompt. A saved prompt can hold variables, written {{name}}, filled from the run’s deps, as attributes or dict keys ({{customer.name}} reads deps.customer.name or deps["customer"]["name"]):
A variable with no value stops the run before the model request, with a MissingPromptVariable error (decimalai.MissingPromptVariable) that names it. DecimalAI fills only the prompt, never a skill’s text, and the trace keeps the placeholder names, not their values.

How each run’s skills are picked

Each run’s skill list is routed on that run’s own prompt: agent.run_sync("Where is order 1001?") routes on that question, and so does a run that continues a conversation with message_history=.
  • The first run is routed before its first model request.
  • Later runs show the local copy of the list, and their own routing decision is recorded in the background, so no run waits on it.
  • An agent with more skills than the list holds is routed before every run, so the list is picked for the prompt.
  • A run that continues a Claude conversation shows that conversation’s list. Its own decision is recorded in the background, or, when the list was cut to fit, the run names the decision the list came from, so the skills it shows can be loaded.
A run makes one routing decision however many tool calls it takes, and every model request in it sees the same list. A run whose prompt has no text DecimalAI can read gets the skills in the platform’s fixed order.

When an agent’s skills are switched off

DecimalAI turns its skills off for one agent, with one warning, when the agent also loads skills with the Pydantic AI harness’s Skills capability (see below). That capability is a catalog of its own, so the agent gets neither DecimalAI’s skill list nor load_skill. The prompt still runs. An agent with another tool named load_skill does not run at all: Pydantic AI refuses two tools with one name and fails the run with its own UserError. Rename your tool. Three more switches:
  • The tool’s kill switch. With DECIMALAI_LOAD_SKILL_TOOL=0 or decimalai.init(load_skill_tool=False), every run is routed and the text of the skills picked for it goes into the instructions instead (inject_skill_body, which defaults to on once the tool is off). With inject_skill_body=False as well, the agent gets no skills, and one warning says so.
  • decimalai.init(enabled=False) after agent_config() stops routing and skills for that config; the prompt it read keeps running. An agent_config() called while it is off asks DecimalAI nothing: the agent runs on its fallback= text, and without one agent_config() raises RuntimeError (SDK 0.22.1+).
  • on_unavailable="fail". By default ("continue") an agent whose skill list never came back answers without skills, and its trace says so. With agent_config(..., on_unavailable="fail") the run raises before the model request instead.
Three things to plan for:
  • Loading a skill costs a model request. The model asks for the skill in one request and uses it in the next, so leave room under UsageLimits(request_limit=...) if your agent already runs close to it.
  • An outage during a run is not an error. If DecimalAI cannot be reached mid-run, the run keeps the last skill list DecimalAI returned, and load_skill answers with a sentence the model can read.
  • Skills come from DecimalAI, not from disk. agent_config() reads no local SKILL.md files. To serve skill folders installed in your project, use the harness below.

Tracing

agent_config() turns tracing on for its runs (SDK 0.25+). It puts DecimalAI’s OpenTelemetry exporter on the global tracer provider (an app with its own sets it up first), and the exporter sends only DecimalAI runs: none of your app’s other spans. Each run of the capability is instrumented with Pydantic AI’s own Instrumentation, for that run alone, so its model calls and tool calls (with their results) are in the trace whatever the model, and other agents in the process are not instrumented. A run is a trace of its own, rooted in DecimalAI’s run span and filed under support.name, linked to the span that was open when it started (a web request’s, say). A conversation’s runs carry its conversation_id as the trace’s session. You don’t need agent_run() here. When your app traces Pydantic AI itself, nothing is reported twice:
  • Your own instrumentation (Agent.instrument_all(), Agent(instrument=...), an Instrumentation capability, or Logfire’s logfire.instrument_pydantic_ai()) keeps tracing the run with its settings, inside DecimalAI’s run span; the capability adds none of its own. Its spans reach DecimalAI when they go to the global tracer provider.
  • A provider instrumentor that DecimalAI runs (decimalai.init(openai=True), anthropic=True or google=True, for the SDK the run’s model calls) records the model calls, so the capability does not instrument the run again. Such a run’s tool calls are not in its trace.
agent_config(..., on_trace=fn) calls fn once per run with a copy of the finished trace before it is sent; an fn that raises is logged and changes nothing else. A run made inside decimalai.start_trace() is filed as that trace’s child. Through SDK 0.24 the capability opened only the run span, and the trace needed decimalai.init(otel=True) with Agent.instrument_all(), or a provider flag. Those setups keep working; you can delete the two lines. Deleting them has one more effect: an agent started while DecimalAI is down runs on its fallback=. decimalai.init() checks the key when it is called and raises DecimalConfigError when it cannot connect (init(verify=False) skips the check). Manifests aren’t auto-detected on this adapter — use register_manifest() if you want regression checks over your Pydantic AI agent’s config.

Load installed skills with the Pydantic AI harness

pydantic-ai-harness reads skill folders itself. Install registry skills into the project with decimalai skills add (SDK 0.15.0+), then give the harness decimalai.pydantic_ai_harness.skills(project), its Skills capability over your installed skills (SDK 0.16.0+):
  • Each load is an activation (SDK 0.16.0+). Each skill the model loads with the harness’s load_capability is recorded as an activation carrying the version of the body it received, and the run’s skills as offered. The harness drops metadata, so the version comes from the lock, by the hash of the delivered body. It reads the skills at the start of every run, so a run after decimalai skills update serves the new version.
  • A load needs a trace to land on. The two OpenTelemetry lines above give every run one, filed under init()’s agent_name; no instrument() is needed (SDK 0.19+). Inside decimalai.start_trace(), the load goes on that trace instead. With neither, the load is dropped, and a warning says so once.
  • Don’t also give this agent agent_config()’s capability. The harness’s Skills is already its catalog, so DecimalAI would add neither its skill list nor load_skill, and one warning says so. Build the Skills with decimalai.pydantic_ai_harness.skills(...): a plain Skills(...) serves the same skills, but its loads are not recorded.
  • The path is relative to the workspace. A skills folder outside the workspace still lists, but the harness’s read_file refuses its files, which is why the workspace above is the project itself. skills(project) raises when the skills folder is not inside project.
  • allowed-tools is not enforced. The harness says so with a UserWarning (Ignoring unsupported Agent Skill behavioral frontmatter fields) on every run; grant tools in the agent’s own configuration. From pydantic-ai-harness 0.57.0 it keeps a user-only skill (disable-model-invocation: true) out of the model’s catalog.
See Native skill loaders for how the version is decided and how the other frameworks compare.

What gets captured

  • Model calls and tool calls, from Pydantic AI’s own spans (or, beside init(openai=True) and the like, the provider instrumentor’s model calls)
  • On an agent given agent_config()’s capability: the prompt version, the variable names it filled, any skill outage, and the skills offered, loaded and delivered, each delivery with the exact version the model received
  • Skills the harness’s decimalai.pydantic_ai_harness.skills() capability loads, as activations
Checkpoint: run the agent from Use once with a question that matches one of your skills, then print(support). It names the prompt version the agent ran and the skills on its list, for example PydanticAIAgentConfig(name='support-agent', prompt_version=3, skills=['refund-policy']), and the run appears on the Traces page under that name. No trace? Check that DECIMAL_API_KEY is set where the agent runs: without a key the agent runs keyless and nothing is sent (see Tracing). An empty skill list means the router had none to offer: check that your workspace has the skill installed or forked, and that agent_config() names the agent it is assigned to (see the silent no-ops list in the Quickstart).

Moving from SDK 0.18

Through 0.18, decimalai.pydantic_ai.instrument(enable_skill_loader=True) patched Pydantic AI to give every Agent in the process skills and a load_skill tool, and opened a run span around every run. 0.19 removed instrument() and get_current_routing_id(): an agent gets its prompt and skills from agent_config(), as a capability, and from 0.25 that capability traces its runs too (0.19 to 0.24 took their traces from init(otel=True) with Agent.instrument_all(), or from a provider flag):
Your system_prompt= text becomes the fallback=: the prompt saved in the dashboard takes its place, and the fallback runs while none is saved. Through 0.18, DecimalAI’s tool was renamed decimalai_load_skill when the agent had another tool named load_skill; in 0.19 that run fails until you rename yours. See Migrations for a file decimalai init wrote before 0.19, and for the decimalai.agent_config() change in the same release.

What’s next

Skills

Skill list vs body delivery, the load_skill tool, and the usage ladder.

Manifests

Register a manifest explicitly for regression checks.