Skip to main content
Eight agent frameworks load Agent Skills from disk on their own: they read SKILL.md folders, offer the skills to the model, and give it tools to load a skill, read its files and run its scripts. decimalai skills add writes folders all eight accept. This page is the one line that points each framework at them, and what DecimalAI records when the framework loads one. Each framework has a helper in its decimalai.<framework> module (pip install "decimalai>=0.16"). It points the framework’s own loader at your installed skills and, with DecimalAI’s instrumentation on, every skill the loader hands the model is recorded as an activation of the exact version the model received. DecimalAI’s skill router stays out of an agent whose own loader serves its skills, so the model sees one catalog.

What DecimalAI records

When the framework’s loader delivers a skill to the model, the trace for that run gets an activation carrying the skill’s registry id and version id. The version is decided from the bytes the model received, never from the folder on disk:
  1. the identity stamp in the delivered copy (metadata.decimalai-*), when the delivered body’s hash matches it;
  2. otherwise the lock, by the delivered body’s hash;
  3. otherwise any version this process has already seen with that hash.
A body that is none of these (a skill you edited by hand, for example) is reported with its skill id and hash and no version, and the platform resolves the version if it can. This matters after decimalai skills update. Some loaders keep serving a skill they already loaded, so the folder holds version 4 while the model still reads version 3, and the activation then says version 3: Also on the trace:
  • A skill loaded twice in one run is one activation.
  • The skills the loader listed for the model are recorded as offered.
  • The router steps aside. An agent whose own loader serves its skills gets no DecimalAI skill list and no DecimalAI load_skill tool; the SDK logs this once at INFO, or as a warning on an OpenAI Agents, Pydantic AI or Google ADK agent you also gave agent_config()’s skills. If both still reach the model, because the loader was attached where the adapter could not see it, a WARNING says so once.

Setup at a glance

Each helper lives in its framework’s module; import the module before you use it (import decimalai.adk): import decimalai alone does not load it. Microsoft Agent Framework, Strands and the Pydantic AI harness need no DecimalAI adapter: with init(otel=True) (and, on Pydantic AI, Agent.instrument_all()) their own OpenTelemetry spans become the trace, and the load is recorded on it. Pass agent_name there, since the exporter names the trace by it. The Pydantic AI harness needed decimalai.pydantic_ai.instrument() as well through SDK 0.18; 0.19 removed it. Run inside decimalai.start_trace() and the load is recorded on that trace instead.

decimalai.skills_dir()

The helpers start from decimalai.skills_dir(); you can use it directly too.
  • It finds the project from the working directory, as every decimalai skills command does, so it works from any subdirectory of the project. skills_dir(directory=...) starts the search somewhere else.
  • It returns the absolute, symlink-resolved path. With relative_to=, it returns the path relative to that directory instead, for the two loaders that need one (OpenAI Agents and the Pydantic AI harness), and raises UsageError when the root is not under it.
  • It raises SkillsNotInstalledError when the project has no lock or no root yet (run decimalai skills install), LegacyLockError for a lock from SDK 0.14 or older (run decimalai skills migrate), and IllegalEntryError when .agents or .agents/skills is a symlink.

The eight loaders

Each snippet below is the documented setup that the SDK’s own test suite runs against the real framework. In the suite a scripted model stands in for yours; model, llm and client in the snippets are your framework’s own model objects.

Claude Agent SDK and Claude Code

The Claude Agent SDK drives the Claude Code CLI, and both load .agents as a plugin named decimalai-skills: its skills/ folder is the root the other seven read.
Interactively:
  • The plugin path must be absolute: a relative --plugin-dir .agents started from a subdirectory loads nothing, with exit status 0 and nothing on stderr. skills_plugin() returns an absolute one.
  • Skills are listed as decimalai-skills:<install-name>. The plugin is not named decimalai, the marketplace plugin’s name, so the two load side by side.
  • It reads name, description and the body, and acts on allowed-tools and disable-model-invocation. It pre-approves the tools a skill lists: a skill your organization authored can run its own bundled scripts with no prompt (Bash(python3 ${CLAUDE_SKILL_DIR}/scripts/… *)), any other command needs permission, and a skill your organization did not author lists only Read, Grep and Glob, so its scripts always need permission. A user-only skill (disable-model-invocation: true) is listed but never offered to the model.
  • The frontmatter never reaches your process, so the version comes from the lock, by the hash of the body the CLI delivered.
Graded at claude-agent-sdk 0.2.166 (Claude Code 2.1.299).

Google ADK

  • The plugin in the App traces each invocation and records each load (SDK 0.20+; through 0.19, decimalai.init(adk=True) added it to every runner).
  • decimalai.adk.skills() loads each folder on its own and skips a bad one with a WARNING that names it. ADK’s own load_skills_from_dir raises on one bad folder and loads nothing at all.
  • It reads each folder’s frontmatter, metadata included, and the body. The model first lists the skills, then loads one.
  • ADK parses the skills when skills() runs, so an agent built before decimalai skills update keeps serving the old version until you build it again. The activation says which version that was.
  • Without a code_executor, ADK offers no run_skill_script. UnsafeLocalCodeExecutor runs scripts on your machine with no sandbox; use it only for skills you trust.
Graded at google-adk 2.12.0.

CrewAI

  • CrewAI’s own skill tool is load_skill, which delivers the body. CrewAI has no resource reader and no script runner of its own, so skill_tools() adds two: load_skill_resource reads a skill’s references/, assets/ or scripts/ file, and run_skill_script runs one of its scripts/ (Python with your interpreter, shell scripts with bash, no shell expansion, with a timeout). Both accept only installed skills and paths inside them. run_skill_script does not enforce a skill’s allowed-tools; skill_tools(scripts=False) leaves it out.
  • It has the strictest metadata parser of the eight: every value must be a string. A bad folder is skipped with a SkillLoadFailedEvent and a log line, not an exception.
  • CrewAI reads a skill’s body from disk on every load, so it serves the new version right after decimalai skills update.
Graded at crewai 1.15.27.

OpenAI Agents (SandboxAgent)

  • sandbox_skills() is the sandbox’s Skills(lazy_from=LocalDirLazySkillSource(...)) over skills_dir(relative_to=Path.cwd()). Run from the project root: a source outside the working directory, reached through a symlink or through the macOS /tmp alias, lists zero skills.
  • It adds two guards the plain capability lacks. The sandbox skips a symlinked skill folder without a word, so sandbox_skills() warns when it would list nothing. And the sandbox’s load_skill aborts the whole run on a name it cannot find; the helper’s answers the model with the names it can load instead.
  • Keep default_manifest=Manifest(); without it the skills vanish.
  • When the model loads a skill, the sandbox copies its folder to .agents/<install-name> and drops the exec bit on the way, so run scripts through their interpreter (python3 scripts/compute_refund.py), never as ./scripts/.... DecimalAI identifies the load from that copy, the bytes the model reads.
  • On macOS, commands run under sandbox-exec.
Graded at openai-agents 0.23.1.

Deep Agents

  • decimalai.deepagents.skills() returns the two arguments Deep Agents needs together: skills=[<your skills folder>] and a backend that can see it. The default backend is a FilesystemBackend(root_dir=<project>, virtual_mode=False), which reads files but has no shell, so a skill’s scripts cannot run. To run them, pass one: decimalai.deepagents.skills(backend=LocalShellBackend(root_dir=project, virtual_mode=False)). LocalShellBackend runs commands on your machine.
  • virtual_mode=False. With True, the prompt advertises virtual /skills/... paths that execute cannot open.
  • The skills middleware lists each skill in the system prompt with the path of its SKILL.md; the model reads it with read_file. A read that stops short of the whole file delivers part of the body, and the activation then carries no version, because that body is no version.
  • A namespaced or uppercase name: is listed under that name, with a warning on the deepagents logger, rather than under its folder’s.
Graded at deepagents 0.7.25.

Microsoft Agent Framework

  • skills() is SkillsProvider.from_paths(...) over your skills folder, with three things added on the same object: the observer, a script runner (MAF ships none; without one a script answers that it requires a runner), and an approval rule. MAF makes every skill tool wait for approval by default; the helper lets skill loads and file reads run unasked, and keeps scripts waiting for approval unless you pass skills(auto_approve_scripts=True).
  • It caches skills by default, so a long-running provider keeps serving the old version after decimalai skills update, and the activation says so. Restart the process to serve the new one.
  • Without enable_sensitive_telemetry(), the activation is still recorded, but the trace does not show what each tool call read or returned.
  • A bad folder is skipped, with an ERROR line on the agent_framework logger.
Graded at agent-framework-core 1.21.0.

Pydantic AI harness

  • decimalai.pydantic_ai_harness.skills(project) is the harness’s Skills over your skills folder, relative to the workspace as the harness requires: a skills folder outside it still lists, but read_file refuses its files.
  • No DecimalAI adapter is involved (SDK 0.19+). Don’t also give this agent decimalai.pydantic_ai.agent_config()’s capability: the harness’s catalog already serves its skills, so the capability adds neither DecimalAI’s skill list nor load_skill, and one warning says so.
  • The harness keeps a skill’s name, description and body; metadata is parsed and dropped, so the version comes from the lock, by the hash of the delivered body.
  • It keeps a user-only skill (disable-model-invocation: true) out of the model’s catalog. It does not enforce allowed-tools, and says so on every run with a UserWarning: Ignoring unsupported Agent Skill behavioral frontmatter fields.
  • A bad folder goes into the catalog’s skipped list with a UserWarning, never an exception.
Graded at pydantic-ai-harness 0.57.0 with pydantic-ai-slim 2.57.0.

Strands Agents

  • skills() is AgentSkills(skills=<absolute skills folder>, strict=True) with the observer attached, still the one plugin Strands knows as agent_skills. The skills tool answers with the body and a Location: line; the model then reads files with file_editor and runs scripts with shell. file_editor refuses relative paths, which is why the root is absolute.
  • Strands puts tool arguments and results in span events, which the exporter does not read. Set OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental,gen_ai_span_attributes_only before the first agent is built to have them on the trace; the activation is recorded either way.
  • Strands loads an agent’s skills once, so the same agent keeps serving the old version after decimalai skills update.
  • strict=True on the plugin does not raise: it logs “failed to load skill” and skips that folder. Skill.from_file(path, strict=True) is the call that raises.
  • Always pass model=. Strands’ default model is Amazon Bedrock.
Graded at strands-agents 1.61.0.

Known upstream gaps

Facts about the frameworks, not about the folders. Each is re-checked on every run of the SDK’s test suite, so the line here goes the day the framework changes.

What a loader does with a bad folder

Measured one defect at a time, with every loader at the version graded above. Most of them do not raise:
  • Google ADK raises for a name or a list-typed field that breaks the format, and then loads nothing at all (decimalai.adk.skills() skips that folder instead).
  • Microsoft Agent Framework, CrewAI, Strands and the Pydantic AI harness skip the folder and log a warning, which is easy to miss.
  • OpenAI Agents and Deep Agents rename: a namespaced or uppercase name: is listed under that name instead of the folder’s. OpenAI Agents also skips a symlinked skill folder without a word.
  • Claude Code lists a skill whose name: differs from its folder under the other name.
So a broken folder usually shows up as a skill the agent never uses. decimalai skills verify reports these defects before a loader drops them, and the folders decimalai skills add writes have none of them.

How the SDK checks this

On every commit, the SDK’s test suite starts each of the eight loaders in a child process of its own, points it at a project in the format decimalai skills add writes, and drives it with a scripted model. That the loaders read the folders. One scenario per loader (load a skill, read one of its bundled files, run its script, answer), checking that:
  • the loader lists exactly the installed skills, under their install names;
  • its own warning channel stays quiet;
  • the model receives the skill’s own body, and its hash equals the stamp;
  • a bundled file reads back byte for byte, and a bundled script runs and prints what it should, through the loader’s own tools;
  • the identity stamp reads back and equals the lock;
  • user-only skills are hidden (Claude Code, the Pydantic AI harness), or the upstream gap above holds;
  • the script keeps its exec bit in the copy the loader runs.
That DecimalAI sees them do it. With DecimalAI’s instrumentation on and the helper on this page, each framework runs once: it lists, loads a skill twice, reads its resource and runs its script. Then decimalai skills update moves the skill to a new version, and the same agent loads it again. The suite checks the traces DecimalAI sends for:
  • the listing;
  • one activation carrying the installed version’s exact ids;
  • the resource read and the script run;
  • after the update, the version whose body the model actually received.
It runs at each framework’s lowest supported version too.

Without a helper

The DecimalAI adapters for the Claude Agent SDK, Google ADK, CrewAI, OpenAI Agents and Deep Agents watch the framework’s own loader however you set it up, so the plain snippets from those frameworks’ docs are recorded too. For Microsoft Agent Framework, Strands and the Pydantic AI harness, the observer lives on the object the helper returns. Anywhere else, record a load yourself inside a trace. Name the skill as the loader shows it, by its install name, decimalai-skills:<install-name> or its folder path. Before the trace is sent, the SDK looks the name up in the lock and adds the registry name, skill id, version id and body hash. It hashes the folder as it is at that moment, though, so after a skills update a loader that cached the old version is credited with the new one. The helpers above do not have that problem.
See Skills in the SDK for the trace calls, and Skills on disk for how installs and loads are counted.