feat(skills): add Skill package schema and agent-side skill loading support #88

Open
opened 2026-07-31 18:08:19 +00:00 by CoreRasurae · 1 comment
Member

Metadata

  • Commit Message: feat(skills): add skill package schema and agent-side skill loading support
  • Branch: feature/skill-package-support

Background and context

The Package Registry Standard (§3.2) already defines
skill as a first-class package type (prefix pkg_skl_, description "Skill packages
defining capabilities for AI agents"), and it appears throughout the registry client docs
(docs/registry/*.md) as an example package type resolved through the same generic API as
actor, graph, agent, and template packages.

However, two things are missing:

  1. No normative Skill package schema. Unlike actor packages (which conform to the
    Actor Configuration Standard, docs/index.md), a skill package has no defined internal
    structure beyond the generic package requirements (name, description). There is no
    specification for what fields a skill must declare or how they should be interpreted.
  2. No agent-side consumption path. The Actor Configuration Standard (docs/index.md
    §4.4, LLM Agents) has no skills configuration field or any other mechanism for an Actor
    to reference and load a Skill package into an agent. The generic
    cleveractors.registry client (PackageContentResolver, RegistryCache,
    ReferenceResolver) can already fetch a skill-typed package by reference, but nothing in
    cleveractors.agents calls it — resolved skill content has nowhere to attach.

This Epic (#22) delivered the generic, package-type-agnostic registry client. This issue
covers extending that work so skill packages become a fully supported, structurally
defined, and actually consumable capability — not just an enum value used in examples.

External reference specification — agentskills.io

Before designing our own schema, the ADR must consult the open Agent Skills
format at https://agentskills.io/home and its normative specification at
https://agentskills.io/specification. This format was originally developed by
Anthropic, released as an open standard, and is now supported by a large number of
agentic clients (Claude Code, Claude, OpenAI Codex, Gemini CLI, Cursor, GitHub Copilot,
VS Code, Goose, OpenHands, and dozens of others — see the client showcase at
agentskills.io). Aligning with it (rather than inventing an incompatible schema) means
cleveractors could consume/produce skills that interoperate with this existing ecosystem.

Key points from the specification that the ADR must account for:

  • A skill is a directory, not a flat document. At minimum it contains a SKILL.md
    file; it may also contain scripts/ (executable code), references/ (additional
    docs), assets/ (templates/data), and arbitrary other files:
    skill-name/
    ├── SKILL.md          # Required: metadata + instructions
    ├── scripts/          # Optional: executable code
    ├── references/       # Optional: documentation
    ├── assets/           # Optional: templates, resources
    └── ...               # Any additional files or directories
    
    This is a structural mismatch with our Package Registry Standard, where every package
    is a single canonicalized YAML document, content-addressed as one SHA-1 blob
    (§6 of docs/actor-registry-standard.md). The ADR must resolve this — e.g. by
    defining a directory→single-document packing convention (inline file contents as a
    mapping field, tar+base64 encode the tree, extend canonicalization to hash a file
    tree, etc.) — before a pkg_skl_ package can faithfully round-trip an
    agentskills.io-conformant skill.
  • SKILL.md frontmatter fields (YAML frontmatter + Markdown body):
    Field Required Constraints
    name Yes 1-64 chars; lowercase alphanumeric + hyphens only; no leading/trailing/consecutive hyphens; must match the parent directory name
    description Yes 1-1024 chars; non-empty; should describe what the skill does and when to use it
    license No License name or reference to a bundled license file
    compatibility No 1-500 chars; environment requirements (product, system packages, network access)
    metadata No Arbitrary string→string map for additional, client-defined properties
    allowed-tools No Space-separated string of pre-approved tools (experimental; support varies by client)
  • Progressive disclosure — the loading model agents use, in three stages:
    1. Discovery (~100 tokens): only name + description loaded at startup, for all
      skills.
    2. Activation: the full SKILL.md body is loaded into context once a task matches
      a skill's description (recommended to stay under ~5000 tokens / 500 lines).
    3. Execution: bundled scripts//references//assets/ files are loaded/run only
      as needed.
  • Validation tooling: the reference implementation ships a skills-ref CLI
    (skills-ref validate ./my-skill) that validates frontmatter and naming conventions —
    worth evaluating as a dependency or as a model for our own validation.

Expected behavior

An Actor configuration author can declare skill references on a type: llm agent, e.g.:

agents:
  support_agent:
    type: llm
    config:
      provider: anthropic
      model: claude-3-5-sonnet-20241022
      skills:
        - "registry.example.com:acme/code-analysis@v1.0.0"
        - "ID:pkg_skl_a1b2c3d4e5f67890abcdef1234567890abcdef"

At agent-creation time, each reference resolves through the existing
cleveractors.registry client, the resolved content is validated against the Skill
package schema defined by the ADR (which must itself be grounded in the agentskills.io
specification — see above), and the skill's name/description/instructions
(and, per progressive disclosure, its bundled scripts/references/assets on demand) are
loaded into the agent.

Acceptance criteria

  • An ADR is written and accepted proposing the Skill package schema and the skills:
    LLM agent config field, per this project's Specification-First Development process
    (see ADR-2030 through ADR-2033 for the established ADR format and spec-extension
    precedent). The ADR must explicitly evaluate the agentskills.io Agent Skills
    specification (https://agentskills.io/specification) as the reference format,
    document how our pkg_skl_ package schema maps to/from a SKILL.md-plus-directory
    skill (including the single-document-vs-directory packaging question above), and
    justify any deviation from the open spec.
  • A normative Skill package schema is documented in docs/actor-registry-standard.md,
    specifying required/optional fields for skill-type packages, informed by the
    agentskills.io frontmatter fields (name, description, license, compatibility,
    metadata, allowed-tools) and the progressive-disclosure loading model.
  • LLM agent config (docs/index.md §4.4) documents a new optional skills field
    accepting a list of package references using the existing reference schemes
    (registry:, ID:, local:).
  • At agent creation, skills entries resolve via the existing cleveractors.registry
    client (ReferenceResolver + PackageContentResolver + RegistryCache) and validate
    against the Skill schema, raising a typed error consistent with the existing
    RegistryError/ExecutionError hierarchies on missing or invalid skill packages.
  • Resolved skill content is observably loaded into the agent (visible in agent metadata
    and/or effective system prompt), consistent with the progressive-disclosure model
    (name/description always available; full instructions loaded on activation).
  • BDD (Behave) scenarios cover: successful single- and multi-skill resolution, missing
    skill package, invalid skill package content (including name/description
    constraint violations per the agentskills.io rules), and a skill reference using each
    of the three reference schemes.
  • A Robot Framework integration test exercises an actor with a skills:-configured LLM
    agent resolving a skill package end-to-end.
  • Coverage remains >=97% (nox -s coverage_report); full nox suite passes.
  • MkDocs documentation (docs/registry/) is updated to reflect the Skill schema and
    usage.

Supporting information

  • docs/actor-registry-standard.md §3.2 (package types), §5.3 (reference formats),
    §6 (canonicalization — single-document, content-addressed model)
  • docs/index.md §4.4 (LLM agent config), §1.3 (extensibility clause used by prior ADRs)
  • docs/registry/index.md, docs/registry/integration.md (existing generic client usage
    of package_type="skill" as an illustrative example only — no schema behind it today)
  • https://agentskills.io/home and https://agentskills.io/specification — the
    open Agent Skills format (originally developed by Anthropic) that the ADR must
    consult and evaluate for alignment; see "External reference specification" above for
    the extracted normative details
  • ADR-2030, ADR-2031, ADR-2032, ADR-2033 — established precedent and format for
    specification-extension ADRs in this project
  • Epic #22 — delivered the generic, package-type-agnostic registry client this issue
    builds on

Subtasks

  • Read the Agent Skills specification at https://agentskills.io/specification (and
    overview at https://agentskills.io/home) and summarize its applicability/gaps
    relative to the Package Registry Standard's single-document packaging model
  • Write and get accepted an ADR proposing the Skill package schema and skills:
    LLM agent config field, grounded in the agentskills.io specification
  • Document the normative Skill package schema in docs/actor-registry-standard.md
    per the approved ADR
  • Document the skills field on type: llm agents in docs/index.md §4.4 per the
    approved ADR
  • Implement skill reference resolution at agent-creation time in cleveractors.agents
    (reusing the existing cleveractors.registry client)
  • Implement Skill package content validation against the new schema
  • Wire resolved skill content into the LLM agent's effective system prompt / capabilities
  • Tests (Behave): add scenarios for skill resolution success/failure and multi-skill agents
  • Tests (Robot): add end-to-end integration test for an actor using a resolved skill package
  • Update MkDocs documentation for the skills field and Skill package schema
  • Verify coverage >=97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • The ADR is accepted and the specification updates it prescribes are merged.
  • A Git commit is created where the first line of the commit message matches the
    Commit Message in Metadata exactly, followed by a blank line, then additional lines
    providing relevant implementation details.
  • The commit is pushed to the remote on the branch matching Branch in Metadata
    exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged
    before this issue is marked done.
## Metadata - **Commit Message**: `feat(skills): add skill package schema and agent-side skill loading support` - **Branch**: `feature/skill-package-support` ## Background and context The [Package Registry Standard](docs/actor-registry-standard.md) (§3.2) already defines `skill` as a first-class package type (prefix `pkg_skl_`, description "Skill packages defining capabilities for AI agents"), and it appears throughout the registry client docs (`docs/registry/*.md`) as an example package type resolved through the same generic API as `actor`, `graph`, `agent`, and `template` packages. However, two things are missing: 1. **No normative Skill package schema.** Unlike `actor` packages (which conform to the Actor Configuration Standard, `docs/index.md`), a `skill` package has no defined internal structure beyond the generic package requirements (name, description). There is no specification for what fields a skill must declare or how they should be interpreted. 2. **No agent-side consumption path.** The Actor Configuration Standard (`docs/index.md` §4.4, LLM Agents) has no `skills` configuration field or any other mechanism for an Actor to reference and load a Skill package into an agent. The generic `cleveractors.registry` client (`PackageContentResolver`, `RegistryCache`, `ReferenceResolver`) can already fetch a `skill`-typed package by reference, but nothing in `cleveractors.agents` calls it — resolved skill content has nowhere to attach. This Epic (#22) delivered the generic, package-type-agnostic registry client. This issue covers extending that work so `skill` packages become a fully supported, structurally defined, and actually consumable capability — not just an enum value used in examples. ## External reference specification — agentskills.io Before designing our own schema, the ADR **must** consult the open **Agent Skills** format at **https://agentskills.io/home** and its normative specification at **https://agentskills.io/specification**. This format was originally developed by Anthropic, released as an open standard, and is now supported by a large number of agentic clients (Claude Code, Claude, OpenAI Codex, Gemini CLI, Cursor, GitHub Copilot, VS Code, Goose, OpenHands, and dozens of others — see the client showcase at agentskills.io). Aligning with it (rather than inventing an incompatible schema) means cleveractors could consume/produce skills that interoperate with this existing ecosystem. Key points from the specification that the ADR must account for: - **A skill is a directory, not a flat document.** At minimum it contains a `SKILL.md` file; it may also contain `scripts/` (executable code), `references/` (additional docs), `assets/` (templates/data), and arbitrary other files: ``` skill-name/ ├── SKILL.md # Required: metadata + instructions ├── scripts/ # Optional: executable code ├── references/ # Optional: documentation ├── assets/ # Optional: templates, resources └── ... # Any additional files or directories ``` This is a structural mismatch with our Package Registry Standard, where every package is a **single** canonicalized YAML document, content-addressed as one SHA-1 blob (§6 of `docs/actor-registry-standard.md`). The ADR must resolve this — e.g. by defining a directory→single-document packing convention (inline file contents as a mapping field, tar+base64 encode the tree, extend canonicalization to hash a file tree, etc.) — before a `pkg_skl_` package can faithfully round-trip an agentskills.io-conformant skill. - **`SKILL.md` frontmatter fields** (YAML frontmatter + Markdown body): | Field | Required | Constraints | |---|---|---| | `name` | Yes | 1-64 chars; lowercase alphanumeric + hyphens only; no leading/trailing/consecutive hyphens; must match the parent directory name | | `description` | Yes | 1-1024 chars; non-empty; should describe what the skill does and when to use it | | `license` | No | License name or reference to a bundled license file | | `compatibility` | No | 1-500 chars; environment requirements (product, system packages, network access) | | `metadata` | No | Arbitrary string→string map for additional, client-defined properties | | `allowed-tools` | No | Space-separated string of pre-approved tools (experimental; support varies by client) | - **Progressive disclosure** — the loading model agents use, in three stages: 1. **Discovery** (~100 tokens): only `name` + `description` loaded at startup, for all skills. 2. **Activation**: the full `SKILL.md` body is loaded into context once a task matches a skill's description (recommended to stay under ~5000 tokens / 500 lines). 3. **Execution**: bundled `scripts/`/`references/`/`assets/` files are loaded/run only as needed. - **Validation tooling**: the reference implementation ships a `skills-ref` CLI (`skills-ref validate ./my-skill`) that validates frontmatter and naming conventions — worth evaluating as a dependency or as a model for our own validation. ## Expected behavior An Actor configuration author can declare skill references on a `type: llm` agent, e.g.: ```yaml agents: support_agent: type: llm config: provider: anthropic model: claude-3-5-sonnet-20241022 skills: - "registry.example.com:acme/code-analysis@v1.0.0" - "ID:pkg_skl_a1b2c3d4e5f67890abcdef1234567890abcdef" ``` At agent-creation time, each reference resolves through the existing `cleveractors.registry` client, the resolved content is validated against the Skill package schema defined by the ADR (which must itself be grounded in the agentskills.io specification — see above), and the skill's `name`/`description`/instructions (and, per progressive disclosure, its bundled scripts/references/assets on demand) are loaded into the agent. ## Acceptance criteria - An ADR is written and accepted proposing the Skill package schema and the `skills:` LLM agent config field, per this project's Specification-First Development process (see ADR-2030 through ADR-2033 for the established ADR format and spec-extension precedent). The ADR must explicitly evaluate the agentskills.io Agent Skills specification (https://agentskills.io/specification) as the reference format, document how our `pkg_skl_` package schema maps to/from a `SKILL.md`-plus-directory skill (including the single-document-vs-directory packaging question above), and justify any deviation from the open spec. - A normative Skill package schema is documented in `docs/actor-registry-standard.md`, specifying required/optional fields for `skill`-type packages, informed by the agentskills.io frontmatter fields (`name`, `description`, `license`, `compatibility`, `metadata`, `allowed-tools`) and the progressive-disclosure loading model. - LLM agent config (`docs/index.md` §4.4) documents a new optional `skills` field accepting a list of package references using the existing reference schemes (`registry:`, `ID:`, `local:`). - At agent creation, `skills` entries resolve via the existing `cleveractors.registry` client (`ReferenceResolver` + `PackageContentResolver` + `RegistryCache`) and validate against the Skill schema, raising a typed error consistent with the existing `RegistryError`/`ExecutionError` hierarchies on missing or invalid skill packages. - Resolved skill content is observably loaded into the agent (visible in agent metadata and/or effective system prompt), consistent with the progressive-disclosure model (name/description always available; full instructions loaded on activation). - BDD (Behave) scenarios cover: successful single- and multi-skill resolution, missing skill package, invalid skill package content (including `name`/`description` constraint violations per the agentskills.io rules), and a skill reference using each of the three reference schemes. - A Robot Framework integration test exercises an actor with a `skills:`-configured LLM agent resolving a skill package end-to-end. - Coverage remains >=97% (`nox -s coverage_report`); full `nox` suite passes. - MkDocs documentation (`docs/registry/`) is updated to reflect the Skill schema and usage. ## Supporting information - `docs/actor-registry-standard.md` §3.2 (package types), §5.3 (reference formats), §6 (canonicalization — single-document, content-addressed model) - `docs/index.md` §4.4 (LLM agent config), §1.3 (extensibility clause used by prior ADRs) - `docs/registry/index.md`, `docs/registry/integration.md` (existing generic client usage of `package_type="skill"` as an illustrative example only — no schema behind it today) - **https://agentskills.io/home** and **https://agentskills.io/specification** — the open Agent Skills format (originally developed by Anthropic) that the ADR must consult and evaluate for alignment; see "External reference specification" above for the extracted normative details - ADR-2030, ADR-2031, ADR-2032, ADR-2033 — established precedent and format for specification-extension ADRs in this project - Epic #22 — delivered the generic, package-type-agnostic registry client this issue builds on ## Subtasks - [ ] Read the Agent Skills specification at https://agentskills.io/specification (and overview at https://agentskills.io/home) and summarize its applicability/gaps relative to the Package Registry Standard's single-document packaging model - [ ] Write and get accepted an ADR proposing the Skill package schema and `skills:` LLM agent config field, grounded in the agentskills.io specification - [ ] Document the normative Skill package schema in `docs/actor-registry-standard.md` per the approved ADR - [ ] Document the `skills` field on `type: llm` agents in `docs/index.md` §4.4 per the approved ADR - [ ] Implement skill reference resolution at agent-creation time in `cleveractors.agents` (reusing the existing `cleveractors.registry` client) - [ ] Implement Skill package content validation against the new schema - [ ] Wire resolved skill content into the LLM agent's effective system prompt / capabilities - [ ] Tests (Behave): add scenarios for skill resolution success/failure and multi-skill agents - [ ] Tests (Robot): add end-to-end integration test for an actor using a resolved skill package - [ ] Update MkDocs documentation for the `skills` field and Skill package schema - [ ] Verify coverage >=97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - The ADR is accepted and the specification updates it prescribes are merged. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant implementation details. - The commit is pushed to the remote on the branch matching **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done.
CoreRasurae added the
State
Unverified
Type
Feature
Priority
Backlog
labels 2026-07-31 18:08:19 +00:00
CoreRasurae added
Priority
High
State
Verified
and removed
Priority
Backlog
State
Unverified
labels 2026-07-31 19:26:04 +00:00
CoreRasurae added this to the v2.1.0 milestone 2026-07-31 19:26:08 +00:00
CoreRasurae self-assigned this 2026-07-31 19:36:14 +00:00
CoreRasurae added
State
In Progress
and removed
State
Verified
labels 2026-07-31 19:36:20 +00:00
CoreRasurae added
State
In Review
and removed
State
In Progress
labels 2026-07-31 21:26:36 +00:00
Author
Member

Note: bundled scripts/ resources are readable, not directly runnable

A question came up after this PR landed: if a skill's instructions say something like "run scripts/extract.py <file.pdf>", how does the type: llm agent actually execute that script? Documenting the answer here since it's not obvious from the code alone.

What the skill tool actually gives the model is text, not a runnable file. Calling skill(skill_name="pdf-processing", resource="scripts/extract.py") returns the script's source as a string (cleveractors.agents.tool.ToolAgent._skill_tool, commit bf1f138) — formatted as [SKILL_RESOURCE_READ]...[FILE_CONTENT_START]...[FILE_CONTENT_END]. Nothing is ever written to a real filesystem path; resources live only in the in-memory _loaded_skills mapping threaded through context["_skills"]. This is intentional, per ADR-2034 D-5: resources are exposed for execution-stage reads "without touching the host filesystem," not for by-path execution.

How a bundled Python script can actually run today — no code changes needed, but it requires the model to inline the source rather than reference it by path:

  1. skill(skill_name="pdf-processing", resource="scripts/extract.py") → returns the source text
  2. python_exec(code="<that source text>") → executes it via cleveractors.agents.tool.ToolAgent._execute_python_code

This only works when the agent config sets exec_python: true. Worth flagging: that sandbox isn't airtight — its restricted-builtins dict still includes an unrestricted __import__, so executed code can import os / import subprocess and go beyond the tool's documented builtin list. Pre-existing behavior, not something this PR changed, but relevant to anyone relying on it as a security boundary for skill-provided code.

What does not work today: a bundled .sh script, or any Python script that assumes it's a real file on disk (relative imports, sibling files, real argv, real cwd). There's no materialized file for shell or a real interpreter invocation to point at. A model could try to smuggle the whole script into bash -c '<script>' via the shell tool (needs allow_shell: true), but that's fragile and wasn't a designed path — it just happens to be technically possible given shell's existing arbitrary-command argument.

If genuine file-backed execution is wanted (skill resources materialized to a real temp directory so shell/python_exec/file_read can operate on real paths), that's a new capability this issue didn't build. It would need its own small design decision — materialization lifecycle, cleanup, interaction with safe_mode/unsafe_mode — similar in shape to the pack_skill_directory follow-up already flagged in ADR-2034's "Follow-up Required" section. Happy to scope that as a separate issue if it's wanted.

## Note: bundled `scripts/` resources are readable, not directly runnable A question came up after this PR landed: if a skill's `instructions` say something like *"run `scripts/extract.py <file.pdf>`"*, how does the `type: llm` agent actually execute that script? Documenting the answer here since it's not obvious from the code alone. **What the `skill` tool actually gives the model is text, not a runnable file.** Calling `skill(skill_name="pdf-processing", resource="scripts/extract.py")` returns the script's source as a string (`cleveractors.agents.tool.ToolAgent._skill_tool`, commit `bf1f138`) — formatted as `[SKILL_RESOURCE_READ]...[FILE_CONTENT_START]...[FILE_CONTENT_END]`. Nothing is ever written to a real filesystem path; resources live only in the in-memory `_loaded_skills` mapping threaded through `context["_skills"]`. This is intentional, per ADR-2034 D-5: resources are exposed for execution-stage reads "without touching the host filesystem," not for by-path execution. **How a bundled Python script can actually run today** — no code changes needed, but it requires the model to inline the source rather than reference it by path: 1. `skill(skill_name="pdf-processing", resource="scripts/extract.py")` → returns the source text 2. `python_exec(code="<that source text>")` → executes it via `cleveractors.agents.tool.ToolAgent._execute_python_code` This only works when the agent config sets `exec_python: true`. Worth flagging: that sandbox isn't airtight — its restricted-builtins dict still includes an unrestricted `__import__`, so executed code can `import os` / `import subprocess` and go beyond the tool's documented builtin list. Pre-existing behavior, not something this PR changed, but relevant to anyone relying on it as a security boundary for skill-provided code. **What does *not* work today:** a bundled `.sh` script, or any Python script that assumes it's a real file on disk (relative imports, sibling files, real argv, real cwd). There's no materialized file for `shell` or a real interpreter invocation to point at. A model could try to smuggle the whole script into `bash -c '<script>'` via the `shell` tool (needs `allow_shell: true`), but that's fragile and wasn't a designed path — it just happens to be technically possible given `shell`'s existing arbitrary-`command` argument. **If genuine file-backed execution is wanted** (skill resources materialized to a real temp directory so `shell`/`python_exec`/`file_read` can operate on real paths), that's a new capability this issue didn't build. It would need its own small design decision — materialization lifecycle, cleanup, interaction with `safe_mode`/`unsafe_mode` — similar in shape to the `pack_skill_directory` follow-up already flagged in ADR-2034's "Follow-up Required" section. Happy to scope that as a separate issue if it's wanted.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: cleveragents/cleveractors-core#88