Skills
A Skill is a Markdown document plus the files it references. agent-bundle discovers Skills from
the src/ convention, lowers each one into the spelling every selected host expects, and ships
the directory's other files as that Skill's resources.
The convention
One directory per Skill, with SKILL.md inside:
That ships with no declaration at all. Everything in the directory other than SKILL.md, and
other than the rendered-skill source files, which are build inputs, becomes a resource of that
Skill, copied into the artifact with its relative path preserved.
The document
SKILL.md starts with YAML frontmatter and continues as ordinary Markdown:
Frontmatter is required. A document with none reports AB3001; invalid YAML reports AB3002.
name and description are what every host reads, the description is the activation surface,
so write it as the condition under which the Skill should be used, not as a title.
Links to sibling files are how a Skill points at its own resources. They stay relative in the emitted document, so they resolve inside whichever artifact the host installed.
Keep instructions focused
Host UIs load every Skill's name and description into context so the
model can choose. Long or overlapping descriptions get truncated; vague
triggers load the wrong Skill. Prefer a short capability plus a
discriminating when, not a broad domain:
Avoid, fires on anything database-shaped:
Prefer, fires when the task is actually a migration:
Put only useful shared instructions and real safety or authorization constraints in the body. A repeated “When to use” section is unnecessary when the description already gives the boundary.
Treat the root SKILL.md as a router: link substantial mode-specific
procedures from references/ and say when to read them (progressive
disclosure). Do not load every reference at entry or create resource folders
for a short, self-contained Skill. assets/ holds files used in the output,
not instructions that must always enter context. Overly specific step-by-step
itineraries that helped weaker models often over-constrain stronger ones,
keep invariants, drop ceremony.
Write the body so the agent matches the user's scope. A plan or review should not silently become implementation or release. Reuse existing authorization and current evidence. Complete the relevant preparation before a necessary approval, and finish with the requested result and its validation or limitations. Avoid mandatory broad audits, repeated checks, and fixed report rituals unless the workflow's actual contract requires them. A release-readiness verdict still requires current candidate checks; a planning task can identify those checks as remaining work.
The create-agent-bundle minimal template follows this pattern. It inspects
the current Skill tree instead of assuming the scaffold's original
capabilities are unchanged. Apply the same principles to rendered Skills:
review the emitted Markdown, not just the component source.
Selecting Skills explicitly
Conventional discovery covers src/skills/*/SKILL.{md,ts,tsx}. Declare skills when you need a
different location, a subset, or a literal list:
Literal paths stay literal; globs match Skill directories or SKILL.md files. Config always
wins over the convention.
Host extensions
Portable Skill metadata, name, description, license, compatibility, allowed-tools (the
Agent Skills spelling; camelCase allowedTools is accepted only under targets.claude), and a
free-form metadata record, is understood by every target. Host-specific keys live under
their host so they reach only that adapter:
targets in Skill frontmatter is that per-host object and nothing else; a list such as
targets: ['claude'] is AB3006. A Skill is emitted to every target the project selects. There
is no per-Skill artifact restriction.
Claude Code, Codex, Cursor, and portable share skills/<name>/SKILL.md; Amp receives its copy
under .amp/plugins/<plugin>/skills/<name>/SKILL.md. A host extension that lowers a shared
document differently for one selected host than for
another, targets: { claude: { effort: high } } in a claude + codex build, say, is a
fatal AB4103 collision. Keep the emitted document identical for every selected host, or build
those hosts into separate artifacts (one targets entry per build).
Amp registration and skill MCP
Amp does not scan a directory plugin's skills/ folder. Its generated index.js awaits
amp.registerSkill({ path: 'skills/<name>' }) exactly once for every bundled skill. Amp lists
the result as <plugin>:<skill>, so it does not compete with a bare skill discovered from the
machine, project, Claude-compatible, built-in, personal, or workspace skill roots.
builtin-tools gates tools registered by that same Amp plugin until the skill loads.
mcpServers in SKILL.md frontmatter wins over a sibling mcp.json; an authored sibling is
also preserved rather than overwritten. If canonical mcp.servers target Amp, the adapter emits
the flat server map beside exactly one bundled skill only when neither native source exists.
Path tokens
Host placeholder syntax differs, ${CLAUDE_PLUGIN_ROOT} is not what Cursor or the portable
standard write. Author the canonical token instead and let build-time lowering substitute the
host spelling:
Lowering substitutes syntax only; no runtime value is resolved at build time. A token a host cannot express is reported rather than silently emitted as literal text.
Rendered Skills
When a Skill document is generated rather than typed, the same checklist repeated per
environment, a table derived from a contract, put a component at src/skills/<name>/SKILL.tsx
(or .ts). It default-exports a component and exports a frontmatter record; the build compiles
the rendered tree into the SKILL.md document hosts consume:
Six Skill.* members emit canonical tokens: Skill.Arguments, Skill.PluginData,
Skill.PluginRoot, Skill.ProjectRoot, Skill.SessionIdentity, and Skill.SkillRoot.
Skill.Resource renders a Markdown link ([path](path)), not a token. Host syntax is
applied during lowering, never in the component.
A rendered source may import project code, so the document is computed from the same sources the
plugin ships, and it may import agent-bundle/meta: the loader serves the same
{ name, packageName, packageVersion, version } the compiler stamps into every built surface, so a
skill can print the version it documents. Its JSX compiles against the loader's own element
factory rather than the project's react/jsx-runtime, the renderer walks plain element objects
and needs no React internals, so the evaluation does not depend on how the process resolves
react (the react-server condition of the route-unit pool included), and inspectWorkbenchSurface
inspects a project with rendered skills from any pool.
A hand-authored SKILL.md in the same directory always wins, an authored file beats a
generated one, and the shadowed component reports the informational AB4735 nudge. A rendered
module that fails to load reports AB3003; one that does not default-export a component
function, or does not export a frontmatter record, reports AB3004.
defineSkill types a Skill definition next to a rendered source:
Inspecting what shipped
The skill focus shows each discovered Skill, its provenance (conventional or config), its
resources, and the per-target lowering decisions. In the developer Workbench, select the Skill
under Application → Skills. Its emitted document is the default view; source/generated
differences, frontmatter, resources, and eval coverage are inspector tabs.
Raw HTML, JSX/MDX, and Mermaid inside Skill Markdown are inert in the Workbench renderer. That is a deliberate containment boundary, not a rendering gap.
Next
- Hooks: react to lifecycle events.
- MCP servers and Apps: expose tools, resources, and prompts.