Skill Plugin Model
Smarter API PluginData Skill Connection Manifest Constants.
Note
Experimental. The SkillPlugin was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.
Parsing and validation of SKILL.md documents, per the Agent Skills specification.
An Agent Skill is a directory containing, at minimum, a SKILL.md file: a YAML
frontmatter block followed by Markdown instructions. The directory may also contain
bundled files, conventionally in scripts/, references/ and assets/, which
SKILL.md refers to by paths relative to the skill root.
---
name: pdf-processing
description: Extract PDF text, fill forms, merge files. Use when handling PDFs.
license: Apache-2.0
allowed-tools: Bash(python:*) Read
metadata:
author: example-org
version: "1.0"
---
# PDF processing
## Filling forms
Read [the forms guide](references/FORMS.md), then run `scripts/fill_form.py`.
This module is shared by the manifest (Pydantic) layer and the storage (Django ORM)
layer, so that both parse and validate SKILL.md text identically.
See also
Agent Skills specification: https://agentskills.io/specification
Anthropic’s skills repository: https://github.com/anthropics/skills
Note
Experimental. The SkillPlugin was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.
- smarter.apps.plugin.manifest.models.skill_plugin.document.MAX_RESOURCES = 100
The maximum number of bundled files.
- smarter.apps.plugin.manifest.models.skill_plugin.document.MAX_RESOURCE_LENGTH = 500000
The maximum length of a single bundled file, in characters.
- smarter.apps.plugin.manifest.models.skill_plugin.document.MAX_SKILL_DOCUMENT_LENGTH = 200000
The maximum length of a SKILL.md document, in characters.
The specification recommends < 500 lines.
- class smarter.apps.plugin.manifest.models.skill_plugin.document.SkillDocument(document, frontmatter, body, allowed_tools=<factory>)[source]
Bases:
objectA parsed and validated
SKILL.mddocument.- Variables:
document – The verbatim SKILL.md text, with line endings normalized to
\n.frontmatter – The complete parsed frontmatter, including any keys beyond the standard fields, such as the extensions supported by Claude Code.
body – The Markdown instructions that follow the frontmatter.
allowed_tools – The
allowed-toolsfrontmatter field, normalized to a list.
- __init__(document, frontmatter, body, allowed_tools=<factory>)
- exception smarter.apps.plugin.manifest.models.skill_plugin.document.SkillDocumentError(message='')[source]
Bases:
SmarterValueErrorRaised when a SKILL.md document or a bundled file path is invalid.
- smarter.apps.plugin.manifest.models.skill_plugin.document.find_resource_references(body)[source]
Find the bundled files that a SKILL.md body refers to.
Recognizes relative Markdown links, e.g.
[guide](./reference/guide.md), and inline code that looks like a path, e.g.`scripts/fill_form.py`. URLs, absolute paths, anchors and paths that escape the skill root are ignored.
- smarter.apps.plugin.manifest.models.skill_plugin.document.normalize_line_endings(text)[source]
Normalize line endings to
\nand remove a leading byte order mark.- Return type:
- smarter.apps.plugin.manifest.models.skill_plugin.document.normalize_resource_path(path)[source]
Normalize the path of a bundled file, relative to the skill root.
- Parameters:
path (
str) – A relative path, e.g../references/FORMS.md.- Return type:
- Returns:
The normalized path, e.g.
references/FORMS.md.- Raises:
SkillDocumentError – If the path is empty, absolute, a URL, contains a backslash or control characters, or escapes the skill root.
- smarter.apps.plugin.manifest.models.skill_plugin.document.normalize_resources(resources)[source]
Validate and normalize a mapping of bundled file paths to their contents.
A
Nonevalue denotes a file whose contents are unavailable, such as a binary asset.- Parameters:
resources (
dict[str,str|None] |None) – The bundled files, keyed by path relative to the skill root.- Return type:
- Returns:
The bundled files, keyed by normalized path, in sorted order.
- Raises:
SkillDocumentError – If a path is invalid or duplicated after normalization, a file is SKILL.md itself, a file is too long, or there are too many files.
- smarter.apps.plugin.manifest.models.skill_plugin.document.parse_allowed_tools(value)[source]
Normalize the
allowed-toolsfrontmatter field to a list of tool names.The specification defines
allowed-toolsas a space-separated string, e.g.Bash(git:*) Bash(jq:*) Read. Tool patterns may themselves contain spaces inside parentheses, e.g.Bash(git status:*). Comma-separated strings and YAML lists, both common in practice, are accepted too.- Parameters:
value (
Any) – The raw frontmatter value.- Return type:
- Returns:
The tool names, in order.
- Raises:
SkillDocumentError – If the value is neither a string nor a list of strings.
Example:
parse_allowed_tools("Bash(git status:*) Read, Grep") # ['Bash(git status:*)', 'Read', 'Grep']
- smarter.apps.plugin.manifest.models.skill_plugin.document.parse_skill_document(document)[source]
Parse and validate a
SKILL.mddocument.- Parameters:
document (
str) – The verbatim contents of a SKILL.md file.- Return type:
- Returns:
The parsed document.
- Raises:
SkillDocumentError – If the document is too long, has no frontmatter block, the frontmatter is not a valid YAML mapping, or a standard frontmatter field is invalid.
Example:
skill = parse_skill_document(open("pdf/SKILL.md").read()) skill.name # 'pdf'
- smarter.apps.plugin.manifest.models.skill_plugin.document.validate_frontmatter(frontmatter)[source]
Validate the standard frontmatter fields against the Agent Skills specification.
Keys beyond the standard fields are permitted and preserved, since agent implementations such as Claude Code define their own extensions.
- Parameters:
- Raises:
SkillDocumentError – If a standard field is missing or invalid.
- Return type:
Resolution of the remote locations from which a SkillPlugin can source its skill.
A skill can be sourced from a public GitHub repository, such as Anthropic’s
https://github.com/anthropics/skills, by referring to either the skill’s directory
or its SKILL.md file. Any other https URL of a SKILL.md file is supported too.
# a skill directory in a GitHub repository
https://github.com/anthropics/skills/tree/main/skills/pdf
# a SKILL.md file in a GitHub repository
https://github.com/anthropics/skills/blob/main/skills/pdf/SKILL.md
https://raw.githubusercontent.com/anthropics/skills/main/skills/pdf/SKILL.md
# a GitHub repository whose root is a skill. HEAD is its default branch.
https://github.com/example-org/my-skill
# any other SKILL.md file
https://example.com/skills/my-skill/SKILL.md
Note
GitHub branch names may contain slashes, which makes a URL such as
/tree/feature/x/skills/pdf ambiguous. The first path segment after tree or
blob is always taken to be the ref, so refer to such branches by commit SHA instead.
Note
Experimental. The SkillPlugin was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.
- exception smarter.apps.plugin.manifest.models.skill_plugin.source.SkillSourceError(message='')[source]
Bases:
SmarterValueErrorRaised when a skill source URL is invalid, or a skill cannot be retrieved from it.
- class smarter.apps.plugin.manifest.models.skill_plugin.source.SkillSourceLocation(url, skill_url, base_url, owner=None, repo=None, ref=None, path=None)[source]
Bases:
objectThe resolved location of a remote skill.
- Variables:
url – The URL as written in the manifest.
skill_url – The URL from which to download SKILL.md.
base_url – The URL of the skill root directory, ending in
/. Bundled files are resolved relative to it.owner – The GitHub repository owner, for GitHub sources.
repo – The GitHub repository name, for GitHub sources.
ref – The GitHub branch, tag or commit, for GitHub sources.
path – The path of the skill root directory within the GitHub repository, for GitHub sources. Empty if the skill is the repository root.
- __init__(url, skill_url, base_url, owner=None, repo=None, ref=None, path=None)
- resource_url(path)[source]
Return the download URL of a bundled file, given its normalized path relative to the skill root.
- Return type:
- smarter.apps.plugin.manifest.models.skill_plugin.source.parse_source_url(url)[source]
Resolve a skill source URL to the location of its SKILL.md file and bundled files.
- Parameters:
url (
str) – A GitHub URL of a skill directory or SKILL.md file, or an https URL of a SKILL.md file.- Return type:
- Returns:
The resolved location.
- Raises:
SkillSourceError – If the URL is not a supported https URL.
Example:
location = parse_source_url("https://github.com/anthropics/skills/tree/main/skills/pdf") location.skill_url # 'https://raw.githubusercontent.com/anthropics/skills/main/skills/pdf/SKILL.md'
Smarter API Manifest - SkillPlugin.spec.
A SkillPlugin’s spec.skillData contains an Agent Skill, either verbatim or by reference.
Verbatim: paste the unmodified contents of a SKILL.md file into skill, using a
YAML literal block scalar (|) so that the Markdown is preserved exactly. Bundled files,
which the skill refers to by relative path, can be pasted into resources.
skillData:
skill: |
---
name: meeting-notes
description: Turns raw meeting transcripts into structured notes. Use when the user shares a meeting transcript.
---
# Meeting notes
Follow the template in [the template](assets/template.md).
resources:
assets/template.md: |
## Decisions
...
By reference: refer to a skill in a public GitHub repository, or to any https URL of a
SKILL.md file. The skill and its bundled files are retrieved when the manifest is
applied, and stored with the plugin. Apply the manifest again to retrieve the latest version.
skillData:
source:
url: https://github.com/anthropics/skills/tree/main/skills/pdf
Note
Experimental. The SkillPlugin was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.
- class smarter.apps.plugin.manifest.models.skill_plugin.spec.SAMSkillPluginSpec(*, selector: SAMPluginCommonSpecSelector, prompt: SAMPluginCommonSpecPrompt, skillData: SkillData)[source]
Bases:
SAMPluginCommonSpecSmarter API Manifest - SkillPlugin.spec.
- model_config = {'arbitrary_types_allowed': True, 'from_attributes': True, 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_post_init(context, /)
This function is meant to behave like a BaseModel method to initialize private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- class smarter.apps.plugin.manifest.models.skill_plugin.spec.SkillData(*, skill: str | None = None, source: SkillSource | None = None, resources: dict[str, str | None] | None = None)[source]
Bases:
SmarterBasePydanticModelSmarter API - SkillPlugin.spec.skillData: an Agent Skill.
Exactly one of
skillorsourceis required.- property document: SkillDocument | None
The parsed SKILL.md document of a verbatim skill, or None for a remote skill.
- model_config = {'arbitrary_types_allowed': True, 'from_attributes': True, 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_post_init(context, /)
This function is meant to behave like a BaseModel method to initialize private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- source: SkillSource | None
- class smarter.apps.plugin.manifest.models.skill_plugin.spec.SkillSource(*, url: str)[source]
Bases:
SmarterBasePydanticModelSmarter API - SkillPlugin.spec.skillData.source: the remote location of a skill.
- property location: SkillSourceLocation
The resolved location of the skill.
- model_config = {'arbitrary_types_allowed': True, 'from_attributes': True, 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_post_init(context, /)
This function is meant to behave like a BaseModel method to initialize private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
Smarter API Plugin Manifest.
Note
Experimental. The SkillPlugin was designed and coded by Claude Code (Anthropic’s Claude Opus 5.5), with Lawrence McDaniel as co-author. It is experimental, and will be documented.
- class smarter.apps.plugin.manifest.models.skill_plugin.model.SAMSkillPlugin(*, apiVersion: str, kind: str, metadata: SAMPluginCommonMetadata, spec: SAMSkillPluginSpec, status: SAMPluginCommonStatus | None = None)[source]
Bases:
SAMPluginCommonSmarter API Manifest - Skill Connection Model.
- model_config = {'arbitrary_types_allowed': True, 'from_attributes': True, 'frozen': True}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- model_post_init(context, /)
This function is meant to behave like a BaseModel method to initialize private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- spec: SAMSkillPluginSpec