Skill LLMTool Plugin
Technical References
Class Reference:
smarter.apps.llmtool.plugin.skill.SkillPluginDjango ORM Model:
smarter.apps.llmtool.models.PluginDataSkillRemote skill retrieval:
smarter.apps.llmtool.plugin.skill_sourcesAgent Skills specification: https://agentskills.io/specification
A Plugin that provides an Agent Skill to the LLM, per the SKILL.md standard.
Note
This is a complex AI resource that exists within the following class hierarchy
Smarter Skill Plugin: The plugin that contains, or refers to, an Agent Skill: a SKILL.md document plus any bundled files.
Smarter LLMClient: The prompting resource (LLMClient, Agent, Workflow unit, etcetera) that includes the Skill Plugin.
Note
An Agent Skill is a SKILL.md document – YAML frontmatter containing at least name
and description, followed by Markdown instructions – plus any bundled files, such as
scripts/, references/ and assets/, that the instructions refer to by relative path.
A SkillPlugin manifest either contains the SKILL.md verbatim, or refers to it by URL, such
as a skill in Anthropic’s https://github.com/anthropics/skills repository.
The SkillPlugin implements the progressive disclosure of the Agent Skills specification:
The skill’s
descriptionis the description of the plugin’s tool, which tells the LLM what the skill does and when to use it.When the LLM invokes the tool, it receives the skill’s instructions and the paths of its bundled files.
The LLM invokes the tool again, with a
resourcepath, to read a bundled file only when the instructions call for it.
---
# A SkillPlugin for an engineering use case, whose SKILL.md uses the optional
# license, compatibility, metadata and allowed-tools frontmatter fields, and
# which bundles a reference checklist.
apiVersion: smarter.sh/v1
kind: SkillPlugin
metadata:
name: code_review
pluginClass: skill
description: Reviews code changes for correctness, security and maintainability.
version: 0.1.0
tags:
- engineering
- code-review
annotations:
- smarter.sh/code-review/use-case: software engineering
spec:
selector:
directive: search_terms
searchTerms:
- code review
- review my code
- pull request
- diff
prompt:
provider: openai
systemRole: >
You are a senior software engineer who gives precise, actionable code reviews.
model: gpt-6-luna
temperature: 1.0
maxTokens: 4096
skillData:
skill: |
---
name: code-review
description: Reviews a code change or pull request for correctness bugs, security issues and maintainability, and reports findings ranked by severity. Use when the user shares a diff, a pull request or a code snippet and asks for a review, feedback or a second opinion.
license: MIT
compatibility: Works with any programming language. Reviews only the code that the user provides.
allowed-tools: Read Grep Glob Bash(git diff:*)
metadata:
author: smarter
version: "1.0"
---
# Code review
## Process
1. Establish what the change is supposed to do. If the user did not say, infer it
from the code, and state your inference.
2. Review the change against the [review checklist](references/checklist.md), in order.
3. For every finding, confirm it by tracing the actual code path. Do not report a
finding that you cannot point to in the code.
## Reporting
Report findings most severe first, using these severities:
- **Blocker:** incorrect behavior, data loss, or a security vulnerability.
- **Major:** a likely bug, or a significant maintainability problem.
- **Minor:** style, naming, or a small simplification.
For each finding, give the file and line, a one sentence summary, and a concrete
failure scenario or suggested fix. End with a one line overall verdict.
If you find nothing wrong, say so plainly. Do not invent findings.
resources:
references/checklist.md: |
# Review checklist
## Correctness
- Off-by-one errors, and empty, null and boundary inputs.
- Error handling: are failures surfaced, or silently swallowed?
- Concurrency: shared state, ordering, and transactions.
## Security
- Injection: SQL, shell, template and path traversal.
- Secrets in code, logs or error messages.
- Authorization checks on every entry point.
## Maintainability
- Names that say what things are.
- Duplicated logic that should be shared.
- Tests for the new behavior, including a failure case.
---
# A SkillPlugin that refers to Anthropic's pdf skill in the public
# https://github.com/anthropics/skills repository, by the URL of its directory.
# SKILL.md and all of its bundled files are retrieved when this manifest is
# applied. Apply it again to retrieve the latest version.
#
# Note: Anthropic's skills are subject to their own license terms. See the
# LICENSE.txt bundled with each skill.
apiVersion: smarter.sh/v1
kind: SkillPlugin
metadata:
name: anthropic_pdf
pluginClass: skill
description: Anthropic's pdf skill, for reading, creating, merging and filling PDF files.
version: 0.1.0
tags:
- pdf
- documents
- anthropic
annotations:
- smarter.sh/anthropic-pdf/source: https://github.com/anthropics/skills
spec:
selector:
directive: search_terms
searchTerms:
- pdf
- pdf form
- merge pdfs
prompt:
provider: openai
systemRole: >
You are a helpful assistant that is expert at working with PDF documents.
model: gpt-6-luna
temperature: 1.0
maxTokens: 4096
skillData:
source:
url: https://github.com/anthropics/skills/tree/main/skills/pdf
apiVersion: smarter.sh/v1
kind: LLMClient
metadata:
description: "An example llmclient with tool calling and Smarter Plugins."
name: example
version: 0.1.0
tags:
- gibberish
- jabberwocky
- talk-talk-talk
annotations:
- smarter.sh/tests/focus-level: low
- smarter.sh/tests/purpose: Provide an example configuration for OpenAI API Function Calling.
- smarter.sh/tests/last-updated: 2025-12-31
- smarter.sh/tests/documentation: https://docs.tests.edu/example-function-calling
- smarter.sh/tests/owner: Lawrence McDaniel
spec:
apiKey: null
config:
prompt:
appAssistant: Lawrence
appExamplePrompts:
- What is the weather in San Francisco?
- What is an Everlasting Gobstopper?
- example function calling configuration
appFileAttachment: false
appInfoUrl: https://smarter.sh
appName: Smarter Demo
appPlaceholder: Ask me anything...
appWelcomeMessage: Welcome to the Smarter demo!
customDomain: null
defaultMaxTokens: 4096
defaultModel: gpt-6-luna
defaultSystemRole: You are a helpful llmclient. When given the opportunity to utilize
function calling, you should always do so. This will allow you to provide the
best possible responses to the user. If you are unable to provide a response,
you should prompt the user for more information. If you are still unable to
provide a response, you should inform the user that you are unable to help them
at this time.
Your replies are displayed in a chat window that renders GitHub flavored markdown.
Use **bold** for key facts, bulleted lists for several items, and a small table when
you present structured data from a function. When a function returns
an image url, show the image with markdown image syntax, .
defaultTemperature: 1.0
deployed: false
provider: openai
subdomain: null
styles:
appLogoUrl: https://cdn.smarter.sh/images/logo/smarter-crop.png
appBackgroundImageUrl: https://cdn.smarter.sh/cms/img/techdots.png
assistantAvatarUrl: https://cdn.smarter.sh/images/llmclients/example/assistant.png
googleFont: Montserrat
borderRadius: 14px
conversationHeader:
backgroundColor: '#f15a29'
color: '#ffffff'
infoColor: '#ffe3d1'
messageList:
backgroundColor: rgba(255, 255, 255, 0.7)
color: '#3a2a1a'
incomingMessage:
backgroundColor: '#ffffff'
color: '#3a2a1a'
borderColor: '#f7c9b5'
outgoingMessage:
backgroundColor: '#fdb913'
color: '#3a2a00'
buttons:
color: '#f15a29'
typingIndicator:
color: '#f15a29'
functions:
- get_current_weather
plugins:
- everlasting_gobstopper
- example_configuration
- image_search
guardrails:
- prompt_injection_keyword_input
- moderation_input
- moderation_output
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.
- class smarter.apps.llmtool.plugin.skill.SkillPlugin(*args, manifest=None, **kwargs)[source]
Bases:
PluginBaseImplements a plugin that provides an Agent Skill to the LLM.
A skill teaches the LLM a repeatable procedure, workflow or domain-specific technique, expressed as a
SKILL.mddocument, rather than returning a data payload or executing a remote query. The skill is either contained verbatim in the plugin manifest, or retrieved from a remote source, such as a GitHub repository, when the manifest is applied.Key Features:
Accepts an unmodified SKILL.md document, validated against the Agent Skills specification.
Accepts a URL of a skill on GitHub, or of any SKILL.md file, in lieu of the document itself.
Stores the skill’s bundled files, which the LLM can read on demand.
Provides a tool definition compatible with OpenAI function calling.
Emits signals when the plugin is called and when it responds.
Example Use Cases:
Teaching an llmclient a company’s code review standards, or brand voice.
Teaching an llmclient a database schema and the rules for querying it.
Reusing a published skill, such as Anthropic’s pdf or mcp-builder skills.
See also
PluginBasePluginDataSkillPluginSkillSerializersmarter.apps.llmtool.plugin.skill_sourcesOpenAI Function Calling Quickstart- SAMPluginType
alias of
SAMSkillPlugin
- __init__(*args, manifest=None, **kwargs)[source]
Initialize a PluginBase instance.
Key features:
Lazy instantiation of class properties.
Supports multiple initialization methods including manifest, database model, and YAML/JSON.
Integrates with Django ORM for plugin metadata management.
Utilizes Pydantic models for manifest validation and serialization.
Provides hooks for plugin selection and prompt customization.
Ensures plugin readiness and validation before use.
Sends signals upon plugin creation or update.
This constructor supports several ways to create a plugin object:
Manifest-based initialization:
Pass a Pydantic model instance via the
manifestargument. This is the preferred method and is typically used when loading plugins from a manifest broker.Database model initialization:
Provide a Django model plugin ID via
plugin_idor aPluginMetainstance viaplugin_metato load an existing plugin from the database.YAML/JSON manifest initialization:
Supply a YAML or JSON string (or dictionary) via the
dataargument to create a plugin from a manifest representation.
See
./data/sample-plugins/everlasting-gobstopper.yamlfor an example manifest.The constructor sets up internal state, initializes plugin properties, and triggers plugin creation or update logic as needed. It also sends signals when the plugin is ready.
- Parameters:
user_profile (Optional[UserProfile]) – The user profile associated with the plugin.
selected (bool) – Whether the plugin is initially selected.
api_version (Optional[str]) – The API version for the plugin manifest.
manifest (
SAMSkillPlugin|None) – A Pydantic model representing the plugin manifest.plugin_id (Optional[int]) – The Django ORM plugin ID.
plugin_meta (Optional[PluginMeta]) – The Django ORM PluginMeta instance.
data (Union[SmarterDictType, str, None]) – YAML/JSON manifest as a string or dictionary.
name (Optional[str]) – The name of the plugin.
kwargs – Additional keyword arguments.
- property custom_tool: dict[str, Any] | None
Return the plugin tool definition for OpenAI function calling.
The tool description is the skill’s
description. If the skill bundles files, the tool takes an optionalresourceparameter, whoseenumis the paths of the bundled files, so that the LLM can read them on demand.See the OpenAI documentation: https://platform.openai.com/docs/assistants/tools/function-calling/quickstart
- Returns:
The tool definition, or
Noneif the plugin is not ready.- Return type:
Optional[SmarterDictType]
Example:
tool = { "type": "function", "function": { "name": "smarter_plugin_0000000042", "description": "Turns raw meeting transcripts into structured meeting notes ...", "parameters": { "type": "object", "properties": { "resource": { "type": "string", "description": "Optional. The path of a bundled file to read ...", "enum": ["assets/template.md"], }, }, "required": [], }, }, }
- classmethod example_manifest(kwargs=None)[source]
Use Pydantic models to generate an example manifest for a SkillPlugin.
- Parameters:
kwargs (
dict[str,Any] |None) – Optional keyword arguments to customize the example manifest.- Returns:
An example manifest as a dictionary.
- Return type:
See Also:
SAMSkillPluginSkillDatasmarter/apps/llmtool/data/sample-plugins/skill-*.yamlfor more examples.
- property kind: str
Returns the kind identifier for this plugin.
- Returns:
The string identifier representing the plugin kind.
- Return type:
- Example:
>>> SkillPlugin().kind 'SkillPlugin'
- property manifest: SAMSkillPlugin | None
Return the Pydantic model representation of the plugin manifest.
If the manifest has not been set but the plugin is in a ready state, it is reconstructed from the Django ORM data, using
to_json(). A remotely sourced skill is reconstructed with itssource, as the manifest author wrote it.- Returns:
The manifest, or
Noneif unavailable.- Return type:
Optional[SAMSkillPlugin]
- property plugin_data: PluginDataSkill | None
Return the plugin data as a Django ORM instance.
If the plugin data has already been set, it is returned directly.
If the plugin data exists in the database, it is retrieved.
If both a manifest and plugin metadata are present, but the plugin data does not exist in the database, it is created from the manifest.
Otherwise,
Noneis returned.
- Returns:
The skill data, or
Noneif unavailable.- Return type:
Optional[PluginDataSkill]
- property plugin_data_class: Type[PluginDataSkill]
Return the Django ORM class used for skill plugin data.
- Returns:
The Django ORM class for skill plugin data.
- Return type:
Type[PluginDataSkill]
- property plugin_data_django_model: dict[str, Any] | None
Transform the Pydantic manifest into a Django ORM-compatible dictionary.
A verbatim skill is stored as written. A remotely sourced skill is retrieved, and a snapshot of it is stored, along with its source URL and the time it was retrieved.
The tool description presented to the LLM is the skill’s
description, which, per the specification, describes what the skill does and when to use it.- Returns:
A dictionary of
PluginDataSkillfields, orNoneif the manifest is not available.- Return type:
Optional[SmarterDictType]
- Raises:
SmarterSkillPluginError – If a remote skill cannot be retrieved, or is invalid.
- property plugin_data_serializer: PluginSkillSerializer | None
Return the serializer instance for the plugin’s skill data.
- Returns:
The serializer instance for the plugin’s skill data.
- Return type:
Optional[PluginSkillSerializer]
- property plugin_data_serializer_class: Type[PluginSkillSerializer]
Return the plugin data serializer class.
- Returns:
The serializer class for skill plugin data.
- Return type:
Type[PluginSkillSerializer]
- property retrieved_skill: RetrievedSkill | None
Return the skill retrieved from the manifest’s
skillData.source, if any.The skill is retrieved once per plugin instance, when it is first needed, which is when the manifest is applied. Tool calls use the stored snapshot, and never retrieve it.
- Returns:
The retrieved skill, or
Noneif the manifest does not refer to a remote skill.- Return type:
Optional[RetrievedSkill]
- Raises:
SmarterSkillPluginError – If the skill cannot be retrieved, or is invalid.
- to_json(version='v1')[source]
Serialize the SkillPlugin to a JSON-compatible dictionary suitable for Pydantic import.
spec.skillDatais rendered as the manifest author wrote it:sourcefor a remotely sourced skill, otherwise the verbatimskilland itsresources.- Parameters:
version (
str) – The API version to use for serialization. Only “v1” is supported.- Returns:
A dictionary representing the plugin in JSON format, or
Noneif the plugin is not ready.- Return type:
- Raises:
SmarterPluginError – If the data is not a valid JSON object, or an unsupported version is specified.
- tool_call_fetch_plugin_response(function_args)[source]
Return the skill’s instructions, or one of its bundled files, in response to a tool call.
Invoked without arguments, the tool returns the skill’s instructions, along with the paths of its bundled files. Invoked with
resourceset to one of those paths, it returns that file. SeePluginDataSkill.sanitized_return_data().Example tool call payload:
"tool_calls": [ { "id": "call_1Ucn2R5WmBh7TtoE197SsP3p", "function": { "arguments": "{\"resource\":\"assets/template.md\"}", # these are the function_args "name": "smarter_plugin_0000004468" }, "type": "function" } ]
- Parameters:
function_args (
dict[str,Any] |str|None) – The function arguments, as a dict or as the JSON string sent by OpenAI.- Returns:
The skill’s instructions, or the bundled file.
- Return type:
- Raises:
SmarterSkillPluginError – If the arguments are malformed, the plugin is not ready or lacks data, or the requested resource does not exist.
- exception smarter.apps.llmtool.plugin.skill.SmarterSkillPluginError(message='')[source]
Bases:
SmarterPluginErrorBase class for all Skill plugin errors.
- smarter.apps.llmtool.plugin.skill.should_log(level)[source]
Check if logging should be done based on the waffle switch.
Retrieval of remote Agent Skills for the SkillPlugin.
A SkillPlugin manifest can refer to a skill by URL rather than containing it verbatim.
See smarter.apps.llmtool.manifest.models.skill_plugin.source for the supported
URLs. The skill is retrieved when the manifest is applied, and a snapshot of it is stored
with the plugin, so that tool calls never depend on the availability of the remote host.
GitHub: the skill directory is listed with the GitHub git trees api, and SKILL.md and every file beneath the skill directory is downloaded from raw.githubusercontent.com. Files that are not UTF-8 text, such as images and fonts, are recorded without contents.
Any other https URL: SKILL.md is downloaded, along with the bundled files that it refers to by relative path. Files that cannot be downloaded are recorded without contents.
Warning
Skill source URLs are user supplied, so requests are made with
smarter.apps.llmtool.plugin.safe_http, which restricts them to https, to hosts
whose addresses are all public, and to a bounded number of redirects and response sizes,
in order to prevent server-side request forgery and resource exhaustion.
Note
GitHub api requests are unauthenticated, and so are rate limited to 60 per hour per client IP address. One api request is made per GitHub-sourced skill, per apply.
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.llmtool.plugin.skill_sources.MAX_GITHUB_TREE_BYTES = 20000000
The maximum size of a GitHub git tree listing, in bytes.
- smarter.apps.llmtool.plugin.skill_sources.MAX_RESPONSE_BYTES = 2000000
The maximum size of any single response, in bytes.
UTF-8 characters are at most 4 bytes.
- smarter.apps.llmtool.plugin.skill_sources.MAX_TOTAL_RESOURCE_BYTES = 10000000
The maximum combined size of a skill’s bundled files, in bytes.
- smarter.apps.llmtool.plugin.skill_sources.REQUEST_TIMEOUT = 15
Seconds to wait for each remote request.
- class smarter.apps.llmtool.plugin.skill_sources.RetrievedSkill(location, document, resources=<factory>, retrieved_at=<factory>)[source]
Bases:
objectA skill retrieved from a remote source.
- Variables:
location – The resolved source location.
document – The parsed SKILL.md document.
resources – The bundled files, keyed by path relative to the skill root. A
Nonevalue denotes a file whose contents are unavailable, such as a binary asset.retrieved_at – When the skill was retrieved.
- __init__(location, document, resources=<factory>, retrieved_at=<factory>)
- document: SkillDocument
- location: SkillSourceLocation
- smarter.apps.llmtool.plugin.skill_sources.fetch(url, max_bytes=2000000, headers=None)[source]
Download a remote file, safely.
- Parameters:
- Return type:
- Returns:
The response body.
- Raises:
SkillSourceError – If the URL is not a public https URL, the request fails or times out, the response is not 200 OK, or the response is too large.
- smarter.apps.llmtool.plugin.skill_sources.fetch_text(url, max_bytes=2000000)[source]
Download a remote text file.
- Return type:
- Returns:
The file contents, or None if the file is not UTF-8 text, such as an image.
- Raises:
SkillSourceError – If the file cannot be downloaded.
- smarter.apps.llmtool.plugin.skill_sources.list_github_skill_files(location)[source]
List the files beneath a skill directory in a GitHub repository.
- Return type:
- Returns:
The (path relative to the skill root, size in bytes) of each file, excluding SKILL.md.
- Raises:
SkillSourceError – If the repository, ref or directory cannot be found.
- smarter.apps.llmtool.plugin.skill_sources.retrieve_skill(url)[source]
Retrieve a skill and its bundled files from a remote source.
Retrieved skills are cached for
PluginCacheTtl.SKILLseconds, keyed on the URL, so that applying the same skill for many users downloads it once. Failures raise, and so are never cached. Applying a SkillPlugin manifest invalidates its skill first, withretrieve_skill.invalidate(url), so that an account admin always gets the current skill.- Parameters:
url (
str) – A skill source URL. Seeparse_source_url().- Return type:
- Returns:
The retrieved skill.
- Raises:
SkillSourceError – If the skill cannot be retrieved.
SkillDocumentError – If the retrieved SKILL.md is invalid.
Example:
skill = retrieve_skill("https://github.com/anthropics/skills/tree/main/skills/pdf") skill.document.name # 'pdf' list(skill.resources) # ['LICENSE.txt', 'forms.md', 'reference.md', 'scripts/...', ...]
- smarter.apps.llmtool.plugin.skill_sources.validate_public_https_url(url)[source]
Validate that a URL is https, and that every address its host resolves to is public.
- Raises:
SkillSourceError – If the URL is not https, has no host, cannot be resolved, or resolves to a loopback, private, link-local, reserved or otherwise non-public address.
- Return type: