jeevesagent.skills

Skills — packaged, on-demand instructions for agent tasks.

Anthropic Agent Skills (Oct 2025) plus the LangChain DeepAgents extensions, implemented over our existing primitives:

  • A Skill is a directory containing SKILL.md plus optional supporting files (additional markdown docs, scripts, templates).

  • The agent sees every registered skill’s NAME + DESCRIPTION at startup (~50 tokens per skill in the system prompt).

  • When the user’s request matches a skill’s description, the model calls a load_skill(name) tool to read the full body — the recipe — into context.

  • Bundled supporting files are read via the standard read_tool / bash_tool the agent already has; we don’t need a new filesystem abstraction for skills.

Multi-source layering with last-source-wins override:

agent = Agent(
    "...",
    skills=[
        "~/.jeeves/skills/system/",           # base
        "~/.jeeves/skills/user/",             # user override
        ("./.jeeves-skills/", "Project"),      # project, labelled
    ],
)

Inline skills (no folder needed):

agent = Agent(
    "...",
    skills=[
        Skill.from_text('''---
        name: standup-format
        description: Format a daily standup update.
        ---
        # Standup
        Always 3 sections: Yesterday, Today, Blockers.
        '''),
    ],
)

Public surface:

  • Skill — one loadable skill

  • SkillSource — a directory of skills with optional label

  • SkillRegistry — collection with override semantics

  • SkillMetadata — startup-loaded descriptor

  • SkillError — raised on bad SKILL.md or unknown skill name

  • make_load_skill_tool() — internal: builds the load_skill tool the framework injects into agents that have skills configured

Submodules

Attributes

SkillSpec

Anything an Agent's skills= argument accepts.

Exceptions

SkillError

Raised on invalid skill construction or frontmatter.

Classes

Skill

A loadable agent skill.

SkillMetadata

Lightweight skill descriptor — what loads at startup.

SkillRegistry

A keyed collection of Skill instances.

SkillSource

A folder of skills + an optional label.

Functions

make_load_skill_tool(→ jeevesagent.tools.registry.Tool)

Build the load_skill tool for a given registry.

Package Contents

exception jeevesagent.skills.SkillError[source]

Bases: ValueError

Raised on invalid skill construction or frontmatter.

Initialize self. See help(type(self)) for accurate signature.

class jeevesagent.skills.Skill(path: str | pathlib.Path, *, source_label: str | None = None)[source]

A loadable agent skill.

classmethod from_text(text: str, *, source_label: str | None = None) Skill[source]

Build an inline skill from a SKILL.md-formatted string.

No filesystem path; bundled scripts and tools.py aren’t accessible. Useful for one-off skill definitions in code.

list_files() list[pathlib.Path][source]

Enumerate every file bundled with this skill.

load_body() str[source]

Return the full SKILL.md body (without frontmatter).

property description: str
metadata
property name: str
path
property pending_tools: list[jeevesagent.tools.registry.Tool]

The Tool instances this skill will register on load.

Both Mode B (Python @tool from tools.py) and Mode C (subprocess wrappers from frontmatter tools: manifest) contribute to this list. Empty for pure markdown skills.

class jeevesagent.skills.SkillMetadata[source]

Lightweight skill descriptor — what loads at startup.

The body is NOT in here; it’s read on demand via Skill.load_body(). Keep this small — it lives in the system prompt for the entire agent’s lifetime.

to_catalog_line() str[source]

One-line catalog entry for the system prompt.

allowed_tools: list[str] | None = None
compatibility: str | None = None
declared_tool_count: int = 0
description: str
extra: dict[str, Any]
has_python_tools: bool = False
license: str | None = None
name: str
source_label: str | None = None
class jeevesagent.skills.SkillRegistry(items: collections.abc.Iterable[SkillSpec] | None = None)[source]

A keyed collection of Skill instances.

add(skill: jeevesagent.skills.skill.Skill) None[source]

Append (or override) a single skill after construction.

catalog_section() str[source]

The markdown bullet list that gets appended to the agent’s system prompt.

Empty registry → empty string (so the constructor can unconditionally call this without polluting the system prompt with a blank “Available skills” header).

get(name: str) jeevesagent.skills.skill.Skill | None[source]
is_loaded(name: str) bool[source]

Whether the skill’s pending tools have been registered.

load(name: str) str[source]

Return the full body of a skill (the load_skill tool’s result). Raises SkillError for unknown names so the model gets a clear error in the tool result.

Does NOT register pending Tools. For the full load-and- register flow, see load_with_tools().

load_with_tools(name: str) tuple[str, list[jeevesagent.tools.registry.Tool]][source]

Return (body, newly_pending_tools) — the body of the skill plus the Tool instances the framework should register with the agent’s tool host on this load.

Idempotent: subsequent calls for the same skill return the body and an empty tool list, since registration only needs to happen once.

metadata_map() collections.abc.Mapping[str, jeevesagent.skills.skill.SkillMetadata][source]

All currently-registered skills’ metadata, keyed by name. Cheap to compute — used to build the catalog section.

names() list[str][source]
remove(name: str) jeevesagent.skills.skill.Skill | None[source]

Drop a skill by name. Returns the removed instance or None if no such skill was registered.

class jeevesagent.skills.SkillSource[source]

A folder of skills + an optional label.

classmethod coerce(item: SkillSource | str | pathlib.Path | tuple[str | pathlib.Path, str]) SkillSource[source]

Normalize one user-supplied source spec.

Accepts: * SkillSource(...) — used as-is * str / Path — bare path, no label * (path, label) — path with explicit label

discover() list[jeevesagent.skills.skill.Skill][source]

Find every SKILL.md under this source directory.

Recurses one level (most common layout: skills/<name>/SKILL.md) but also handles deeper nesting. Each SKILL.md becomes one Skill instance with this source’s label attached.

label: str | None = None
path: pathlib.Path
jeevesagent.skills.make_load_skill_tool(registry: jeevesagent.skills.registry.SkillRegistry, *, host: jeevesagent.core.protocols.ToolHost | None = None, tool_name: str = 'load_skill') jeevesagent.tools.registry.Tool[source]

Build the load_skill tool for a given registry.

When host is provided, the tool will register a skill’s pending Tools (from Mode B / Mode C) with the host on first load — making them callable on subsequent turns. Without a host, load_skill only returns the body (skill brings no tools, or the framework integration handles registration elsewhere).

jeevesagent.skills.SkillSpec

Anything an Agent’s skills= argument accepts.