Skip to main content

A standalone skills execution engine for LLM agents

Project description

SkillEngine

A framework-agnostic skills execution engine for LLM agents

CI PyPI Python License


Build Claude Code-like experiences with automatic skill discovery, on-demand loading, tool execution, and multi-provider support.

pip install skillengine

Highlights

  • Progressive Disclosure — Only skill names + descriptions in the system prompt; full content loaded on-demand via the skill tool
  • Multi-Provider — OpenAI, Anthropic, Google, DeepSeek, MiniMax + any OpenAI-compatible endpoint
  • Plugin Everything — Loaders, filters, runtimes, adapters, extensions — all swappable
  • Production Ready — Sessions, context compaction, cost tracking, prompt caching, sandbox isolation, event hooks, hot-reload

Quick Start

import asyncio
from pathlib import Path
from skillengine import create_agent

async def main():
    agent = await create_agent(
        skill_dirs=[Path("./skills")],
        system_prompt="You are a helpful assistant.",
    )

    response = await agent.chat("Help me create a PDF report")
    print(response.content)

    # Slash commands invoke skills directly
    response = await agent.chat("/pdf extract text from invoice.pdf")
    print(response.content)

asyncio.run(main())

Installation

pip install skillengine                # Core
pip install skillengine[openai]        # + OpenAI adapter
pip install skillengine[anthropic]     # + Anthropic adapter
pip install skillengine[openai,anthropic,websockets,memory,web,sandbox]  # Everything

Architecture

                        ┌─────────────────────────────┐
                        │         AgentRunner          │
                        │  on-demand skills · slash    │
                        │  commands · fork isolation   │
                        │  per-skill model & tools     │
                        └──────────┬──────────────────┘
                                   │
                        ┌──────────▼──────────────────┐
                        │        SkillsEngine          │
                        │                              │
                        │  Loader → Filter → Runtime   │
                        │         ↓                    │
                        │    SkillSnapshot             │
                        └──────────┬──────────────────┘
                                   │
          ┌────────┬───────┬───────┼───────┬──────────┐
          │        │       │       │       │          │
       OpenAI  Anthropic Google DeepSeek MiniMax   Custom
Layer Base Class Built-in Purpose
Loader SkillLoader MarkdownSkillLoader Parse SKILL.md (Markdown + YAML frontmatter)
Filter SkillFilter DefaultSkillFilter Eligibility: bins, env vars, OS, config
Runtime SkillRuntime BashRuntime CodeModeRuntime BoxLiteRuntime Execute with timeout, streaming, sandboxing
Adapter LLMAdapter OpenAIAdapter AnthropicAdapter Provider integration with tool calling

Defining Skills

Create skills/my-skill/SKILL.md:

---
name: my-skill
description: "Does useful things"
model: claude-sonnet-4-20250514   # Per-skill model override
context: fork                      # Isolated subagent
allowed-tools: [Read, Grep, Glob]  # Tool restrictions
user-invocable: true               # Enable /my-skill slash command
argument-hint: "<query>"

metadata:
  emoji: "🔧"
  primary_env: "API_KEY"
  requires:
    bins: ["git"]              # ALL must exist
    any_bins: ["npm", "pnpm"]  # At least ONE
    env: ["GITHUB_TOKEN"]
    os: ["darwin", "linux"]
---

# My Skill

Instructions for the LLM when this skill is loaded.

Process: $ARGUMENTS
Current branch: !`git branch --show-current`
Placeholder Replaced with
$ARGUMENTS Full argument string
$1 $2 ... $N Positional arguments
${CLAUDE_SESSION_ID} Session ID
!`cmd` Command stdout (before sending to LLM)

Core API

AgentRunner (high-level)

from skillengine import AgentRunner, AgentConfig, create_agent

config = AgentConfig(
    model="gpt-4o",
    api_key="...",
    max_turns=20,
    thinking_level="medium",        # off / minimal / low / medium / high / xhigh
    skill_description_budget=16000, # Max chars for skill metadata in system prompt
)
agent = AgentRunner(engine, config)

response = await agent.chat("Hello")                        # Single turn
async for chunk in agent.chat_stream("Explain this"):       # Streaming
    print(chunk, end="")
await agent.run_interactive()                                # REPL

SkillsEngine (low-level)

from skillengine import SkillsEngine, SkillsConfig

engine = SkillsEngine(config=SkillsConfig(
    skill_dirs=[Path("./skills")],
    watch=True,
    prompt_format="xml",  # xml / markdown / json
))

snapshot = engine.get_snapshot()
print(snapshot.prompt)                           # Inject into your system prompt
result = await engine.execute("echo hello")      # Execute a command

Key Features

Model Registry & Cost Tracking

Built-in catalog for 12+ models across 5 providers with pricing, context windows, and capabilities.

from skillengine import ModelRegistry, TokenUsage

registry = ModelRegistry()
model = registry.get("gpt-4o")
# model.context_window → 128000
# model.cost.input → 2.5 ($/M tokens)

cost = registry.calculate_cost("gpt-4o", TokenUsage(input_tokens=1000, output_tokens=500))

Extended Thinking

Maps thinking budgets across providers transparently.

AgentConfig(model="claude-opus-4-20250514", thinking_level="high")
Level Anthropic budget OpenAI effort
minimal 1,024 low
low 2,048 low
medium 4,096 medium
high 8,192 high
xhigh 16,384 high

Events

13 lifecycle events for observability and control flow.

from skillengine import EventBus, BEFORE_TOOL_CALL

bus = EventBus()

@bus.on(BEFORE_TOOL_CALL)
async def guard(event):
    if "rm -rf" in event.arguments.get("command", ""):
        return ToolCallEventResult(block=True, message="Blocked")

Events: AGENT_START AGENT_END TURN_START TURN_END BEFORE_TOOL_CALL AFTER_TOOL_RESULT INPUT CONTEXT_TRANSFORM TOOL_EXECUTION_UPDATE SESSION_START SESSION_END MODEL_CHANGE COMPACTION

Context Compaction

from skillengine import TokenBudgetCompactor, SlidingWindowCompactor

compactor = TokenBudgetCompactor(max_tokens=100_000)  # Token budget
compactor = SlidingWindowCompactor(window_size=50)     # Keep N recent messages

Sessions

JSONL append-only tree with branching.

from skillengine.session import SessionManager

mgr = SessionManager(store_dir=Path("./sessions"))
session = mgr.create_session()
branch = mgr.branch(session.id, entry_index=5)  # Fork from earlier point

CodeModeRuntime

Cloudflare code-mode-mcp pattern: 2 tools (search + execute) instead of N. Token cost O(1).

from skillengine import CodeModeRuntime

runtime = CodeModeRuntime(spec=openapi_spec, ctx={"client": httpx.Client()})
await runtime.search("[p for p in spec['paths'] if '/users' in p]")
await runtime.run("result = ctx['client'].get('/users')")

Sandbox Execution

VM-level isolation via BoxLite micro-VMs.

from skillengine import BoxLiteRuntime, SecurityLevel, SandboxedAgentRunner

runtime = BoxLiteRuntime(security_level=SecurityLevel.STANDARD)
agent = SandboxedAgentRunner(engine, config)  # Full agent in sandbox

Built-in Tools

Tool Purpose Tool Purpose
bash Shell commands read Read files
write Write files edit Text replacement
grep Pattern search find File discovery
ls Directory listing skill On-demand skill loading

Extensions

# ~/.skillengine/extensions/my_ext.py
def extension(api):
    api.on("turn_end", my_hook)
    api.register_command("/my-cmd", handler, description="...")
    api.register_tool("my_tool", schema, handler)
    api.register_adapter("my-provider", MyAdapter)

Execution Modes

Mode Protocol Use case
Interactive TUI (stdin/stdout) Terminal REPL
JSON JSONL to stdout Pipelines
RPC JSON-line stdin/stdout Programmatic control

CLI

skills list -d ./skills           # List skills
skills show pdf -d ./skills       # Show detail
skills prompt -d ./skills -f xml  # Generate prompt
skills exec "echo hello"          # Run command
skills validate -d ./skills       # Validate
skills watch -d ./skills          # Watch + hot-reload

Extending

Every layer is pluggable. Implement the base class and pass to the engine:

from skillengine.loaders import SkillLoader
from skillengine.filters import SkillFilter
from skillengine.runtime import SkillRuntime

class MyLoader(SkillLoader):       # Custom file format
    def can_load(self, path): ...
    def load_skill(self, path, source): ...

class MyFilter(SkillFilter):       # Custom eligibility
    def filter(self, skill, config, context): ...

class MyRuntime(SkillRuntime):     # Custom execution
    async def execute(self, command, cwd, env, timeout): ...

Development

git clone https://github.com/sawzhang/skillengine.git
cd skillengine
uv sync

uv run pytest                # 1083 tests
uv run ruff check src/       # Lint
uv run ruff format --check src/  # Format check
uv run mypy src/             # Type check

CI runs on every push and PR: lint + format + mypy on Python 3.12, tests on 3.10/3.11/3.12.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

skillengine-0.2.1-py3-none-any.whl (218.3 kB view details)

Uploaded Python 3

File details

Details for the file skillengine-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: skillengine-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 218.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for skillengine-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 dd5d79e725628a1a16eadade35bfa455cfbd395203c972db46acee3629abb8b2
MD5 9565ed34f7eb7be36e07821dfcbbba3b
BLAKE2b-256 c590d76c221cdd664a6c28f97d0d29b1209d897afb5cf0cc2553fb4772960c14

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page