Skill LLMTool Plugin

Technical References

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

  1. Smarter Skill Plugin: The plugin that contains, or refers to, an Agent Skill: a SKILL.md document plus any bundled files.

  2. 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:

  1. The skill’s description is the description of the plugin’s tool, which tells the LLM what the skill does and when to use it.

  2. When the LLM invokes the tool, it receives the skill’s instructions and the paths of its bundled files.

  3. The LLM invokes the tool again, with a resource path, to read a bundled file only when the instructions call for it.

1.) Example Skill Plugin Manifest, containing a SKILL.md verbatim
---
# 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.
2.) Example Skill Plugin Manifest, referring to a skill on GitHub
---
# 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
3.) Example LLMClient Manifest
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, ![description](https://...).
      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

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: PluginBase

Implements 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.md document, 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

PluginBase PluginDataSkill PluginSkillSerializer smarter.apps.llmtool.plugin.skill_sources OpenAI 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 manifest argument. 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_id or a PluginMeta instance via plugin_meta to load an existing plugin from the database.

  • YAML/JSON manifest initialization:

    Supply a YAML or JSON string (or dictionary) via the data argument to create a plugin from a manifest representation.

See ./data/sample-plugins/everlasting-gobstopper.yaml for 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 optional resource parameter, whose enum is 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 None if 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:

dict[str, Any] | None

See Also:

  • SAMSkillPlugin

  • SkillData

  • smarter/apps/llmtool/data/sample-plugins/skill-*.yaml for more examples.

property kind: str

Returns the kind identifier for this plugin.

Returns:

The string identifier representing the plugin kind.

Return type:

str

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 its source, as the manifest author wrote it.

Returns:

The manifest, or None if 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, None is returned.

Returns:

The skill data, or None if 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 PluginDataSkill fields, or None if 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 None if 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.skillData is rendered as the manifest author wrote it: source for a remotely sourced skill, otherwise the verbatim skill and its resources.

Parameters:

version (str) – The API version to use for serialization. Only “v1” is supported.

Returns:

A dictionary representing the plugin in JSON format, or None if the plugin is not ready.

Return type:

dict[str, Any] | None

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 resource set to one of those paths, it returns that file. See PluginDataSkill.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:

dict[str, Any] | list | str

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: SmarterPluginError

Base 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: object

A 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 None value 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
resources: dict[str, str | None]
retrieved_at: datetime
smarter.apps.llmtool.plugin.skill_sources.fetch(url, max_bytes=2000000, headers=None)[source]

Download a remote file, safely.

Parameters:
  • url (str) – The https URL to download.

  • max_bytes (int) – The maximum size of the response body.

  • headers (dict[str, str] | None) – Additional request headers.

Return type:

bytes

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:

str | None

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:

list[tuple[str, int]]

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.SKILL seconds, 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, with retrieve_skill.invalidate(url), so that an account admin always gets the current skill.

Parameters:

url (str) – A skill source URL. See parse_source_url().

Return type:

RetrievedSkill

Returns:

The retrieved skill.

Raises:

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:

None