Skip to main content
agent_config() reads an agent’s prompt and skills from DecimalAI and hands them over as two ADK pieces, which you pass into your own LlmAgent(...): an instruction provider with the saved prompt and the agent’s skill list, and a load_skill tool. DecimalAIPlugin(), in your App(plugins=[...]), makes each invocation one trace, filed under the DecimalAI agent. Nothing in ADK is patched, so an agent gets DecimalAI’s prompt and skills only when you give it these pieces, and only the runners built from that App are traced. agent_config() needs SDK 0.21 or later; 0.20 called it load_agent(). ADK is Gemini-native. The release gate checks this adapter live on an OpenAI model through LiteLLM; its Gemini cells run only when a release’s gate includes the google provider.

Install

The extra needs Python 3.11+ (google-adk 2.12.0 and later). On Python 3.10, pip quietly installs decimalai 0.13.9 instead, so check with pip show decimalai, or install "decimalai[adk]>=0.20" to make pip fail rather than fall back to a release without agent_config().

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 instruction. With no key at all, the agent runs without a DecimalAI key: the skills your project lists in .decimal/skills.toml, with nothing sent.
  • instruction=support.instruction is an ADK instruction provider, which ADK calls before each model request. It returns the saved prompt, then this agent’s skill list, chosen for the invocation’s message, and one sentence telling the model to load a skill before using it.
  • load_skill is support.tools’ 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 invocation’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 invocation’s list showed it, while one reachable only through the public registry loads only when this invocation was offered it.
  • support.name is the agent’s name in DecimalAI, and the name every invocation is routed and traced for. ADK’s own name= has to be a Python identifier, which a DecimalAI name with a hyphen is not, so the two can differ: the trace is filed under support.name either way.
  • DecimalAIPlugin() goes in the App, ADK’s place for plugins (Runner(plugins=...) is deprecated). It is the one line ADK adds to agent_config(): the plugin is what makes an invocation a trace, and agent_config() does not install it. Tracing has what it records. With no key it does nothing, so the same file runs keyless.
  • No decimalai.init(). With a key, agent_config() initializes the SDK from DECIMAL_API_KEY itself. init() refuses to start without a key, so a file that calls it cannot run keyless.
runner.run(...) is the synchronous form of run_async and is traced the same way. types comes from google-genai, which google-adk already depends on. adk web and adk run load a module-level app before a root_agent, so define app as above in your agent.py and the plugin comes with it.
Model ids: Gemini 2.x model ids are retired upstream — use gemini-3.5-flash or newer. For non-Gemini models, ADK routes through LiteLLM: pip install "google-adk[extensions]", then from google.adk.models.lite_llm import LiteLlm and pass model=LiteLlm(model="openai/gpt-5-mini").

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 invocation within a minute, with no redeploy. Pinning an older version there, or serving the latest again, works the same way. On Claude, an open session 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 when the agent’s model is Claude (AnthropicLlm, Claude, or LiteLlm with an anthropic/ model), a session’s later invocations show the same instruction and load_skill as its first invocation. A saved version, a changed skill list or a newly picked list reaches the next session instead. DecimalAIPlugin keeps that copy in the session’s state, under _decimalai_conversation, so it reaches any process that serves the session from a persistent session service. Without the plugin, only the process that served the session’s first invocation has the copy. Variables keep the values they had at the session’s first invocation. On Gemini and other models, every invocation gets the newest prompt. A saved prompt can hold variables, written {{name}}, filled from the session’s state, as attributes or dict keys ({{customer.name}} reads state["customer"]["name"]):
A variable with no value stops the invocation 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. ADK fills no {var} of its own in an instruction provider’s text, so {{name}} is the only template syntax in play.

How each invocation’s skills are picked

Each invocation’s skill list is routed on that invocation’s own message, the new_message you pass to run_async.
  • The first invocation is routed before its first model request.
  • Later invocations show the local copy of the list, and their own routing decision is recorded in the background, so no invocation waits on it.
  • An agent with more skills than the list holds is routed before every invocation, so the list is picked for the message.
  • A later invocation of a Claude session shows that session’s list. Its own decision is recorded in the background, or, when the list was cut to fit, the invocation names the decision the list came from, so the skills it shows can be loaded.
An invocation makes one routing decision however many tool calls it takes, and every model request in it sees the same list. An invocation whose message 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’s own tools include ADK’s SkillToolset (see below) or another tool named load_skill. The toolset is a catalog of its own, and a second load_skill would share a name with DecimalAI’s, so the agent gets neither DecimalAI’s skill list nor its load_skill. The prompt still runs. Three more switches:
  • The tool’s kill switch. With DECIMALAI_LOAD_SKILL_TOOL=0 or decimalai.init(load_skill_tool=False), every invocation is routed and the text of the skills picked for it goes into the instruction 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 invocation 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.
  • An outage during an invocation is not an error. If DecimalAI cannot be reached mid-invocation, it 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 ADK’s SkillToolset below.

Tracing

DecimalAIPlugin() in App(plugins=[...]) makes each ADK invocation (one run_async or run) one DecimalAI trace, with its model calls, tool calls and their results, and sub-agent activity, and registers the root agent’s model, instruction, tools and sub-agents as a manifest. A runner built without the plugin is not traced, and an agent_config() agent it runs logs one warning per agent saying so, with the line to add (SDK 0.25+; through 0.24 its prompt version and skills were dropped without a word).
  • The trace’s agent. An invocation of an agent given agent_config()’s instruction is filed under support.name, with the prompt version, the variable names and the skills offered, loaded and delivered. Any other invocation is filed under DecimalAIPlugin(agent_name=...), else the agent decimalai.init(agent_name=...) named (or DECIMAL_AGENT_NAME), else the ADK root agent’s name.
  • Linking runs. An invocation made inside decimalai.start_trace() is filed as that trace’s child, through runner.run(...) too. For a runner that runs as a sub-agent of another orchestrator, pass the parent’s trace id as DecimalAIPlugin(parent_trace_id=...).
  • Reading each trace. DecimalAIPlugin(on_trace=fn) calls fn once per invocation, failed ones included, with a copy of the finished trace before it is exported. An fn that raises is logged and changes nothing else.

Load installed skills with ADK SkillToolset

ADK can also read skill folders itself. Install registry skills into the project with decimalai skills add (SDK 0.15.0+), then give ADK’s loader the skills decimalai.adk.skills() reads from them (SDK 0.16.0+):
Run it as in Use. The model finds the skills through ADK’s list_skills tool and reads one with load_skill.
  • Each load is an activation (SDK 0.16.0+). The plugin records every load_skill result as an activation carrying the version of the body ADK handed the model, and the names list_skills returns as offered. A skill loaded twice in one invocation is one activation.
  • ADK keeps serving the version it loaded. ADK parses the folders when decimalai.adk.skills() runs, so an agent built before decimalai skills update serves the old version until you build it again. The activation names the version it actually served.
  • Don’t also give this agent agent_config()’s pieces. The toolset is already its catalog, so DecimalAI would add neither its skill list nor load_skill, and one warning says so. If one invocation’s requests carried both catalogs anyway (the toolset on one agent, agent_config()’s instruction on another), a WARNING says so once: give the toolset to the agent that uses it.
  • One bad folder costs only itself. decimalai.adk.skills() loads each folder on its own and skips one ADK refuses, with a WARNING that names it; ADK’s own load_skills_from_dir raises on one bad folder and loads nothing at all. decimalai skills verify reports what a loader would reject.
  • On-demand skills are offered anyway. ADK ignores disable-model-invocation, so a skill the registry marks on-demand is listed to the model like any other.
See Native skill loaders for how the version is decided and how the other frameworks compare.

What gets captured

  • One trace per invocation: model calls, tool calls with their inputs and results (matched to each call by ADK’s function-call id, so parallel calls to one tool each get their own), and sub-agent activity
  • On an agent given agent_config()’s instruction: 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. A load_skill result is in the next model call’s input on the trace.
  • An auto-detected manifest from the root agent: model, instruction (system prompt), tools (names + descriptions), and sub-agents
  • Errors: model and tool errors mark their span; the invocation’s end status is recorded on the trace
Manifest tool depth is names + descriptions, not full JSON schemas — use register_manifest() if you need schema-aware regression checks.
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 ADKAgentConfig(name='support-agent', prompt_version=3, skills=['refund-policy']), and the run appears on the Traces page under that name. No trace? Check that DecimalAIPlugin() is in the App the runner was built from; from SDK 0.25 a run without it logs a warning, this run is not traced, that names it. 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.19

Through 0.19, decimalai.init(adk=True) and decimalai.adk.instrument(enable_skill_loader=True) patched Runner.__init__ to add the DecimalAI plugin to every runner in the process, and the plugin pasted a skill list and a skill’s text into each request’s system_instruction. 0.20 removed instrument(), init(adk=True) and the plugin’s enable_skill_loader and enable_load_skill_tool arguments: an agent gets its prompt and skills from agent_config(), and its traces come from DecimalAIPlugin() in its App:
Your instruction= text becomes the fallback=: the prompt saved in the dashboard takes its place, and the fallback runs while none is saved. A string instruction’s {var} placeholders were ADK’s, filled from session state; a saved prompt’s are {{var}}, filled from the same state. DECIMAL_AUTO_TRACE=adk now logs a warning that names the plugin and traces nothing. See Migrations for a file decimalai init wrote before 0.20.

What’s next

Skills

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

Multi-agent guide

Linking sub-agent Runners with parent_trace_id.