skill_agent¶
Level 2 · Tools and Skills — managing reusable skills with SkillStore.
A skill is a named, reusable instruction block the agent can pull into its
prompt on demand. This example populates an InMemorySkillStore, filters skills
by relevance, and formats a matched set for prompt injection — the three
operations every skill-driven agent performs.
- Lines: ~42
- Prerequisites: none
- Key concepts:
SkillStore,Skill,filter_skills,format_skills_list
Run it¶
Installed via pip? Copy this example into your project with the CLI (no checkout needed):
Or, from a source checkout (run from the repo root):
Expected output:
Skills: ['summarize', 'translate', 'review']
Filtered 'code': ['review']
Prompt injection (<n> chars):
<formatted skill list>
Full code¶
"""Skill agent -- demonstrates SkillStore + skill-driven agent behavior.
Uses InMemorySkillStore to register and filter skills. <=50 lines,
InMemory only, zero external network calls.
Usage: python -m examples.skill_agent
"""
import asyncio
from symfonic.core import BaseAgentDeps
from symfonic.core.models import Skill
from symfonic.core.protocols import SkillStore
from symfonic.core.skills.filter import filter_skills
from symfonic.core.skills.formatter import format_skills_list
from symfonic.core.skills.in_memory import InMemorySkillStore
from symfonic.core.testing import MockModelProvider
async def main() -> None:
# 1. Populate skill store
store = InMemorySkillStore()
await store.create(Skill(name="summarize", description="Summarize text", content="Extract key points."))
await store.create(Skill(name="translate", description="Translate text", content="Convert languages."))
await store.create(Skill(name="review", description="Code review", content="Find bugs."))
# 2. Wire deps
deps = BaseAgentDeps(ModelProvider=MockModelProvider())
deps.register(SkillStore, store)
# 3. Demonstrate skill-driven behavior
all_skills = await store.list()
print(f"Skills: {[s.name for s in all_skills]}")
matched = filter_skills(all_skills, "code")
print(f"Filtered 'code': {[s.name for s in matched]}")
formatted = format_skills_list(all_skills)
print(f"Prompt injection ({len(formatted)} chars):\n{formatted}")
if __name__ == "__main__":
asyncio.run(main())
Step by step¶
1. Populate the skill store¶
store = InMemorySkillStore()
await store.create(Skill(name="summarize", description="Summarize text", content="Extract key points."))
await store.create(Skill(name="translate", description="Translate text", content="Convert languages."))
await store.create(Skill(name="review", description="Code review", content="Find bugs."))
A Skill has a name, a short description (used for matching), and a content
block (the instruction injected into the prompt). InMemorySkillStore is the
zero-infrastructure implementation of the SkillStore protocol — create is
async because real stores hit a database.
2. Register the store as a dependency¶
Just like documents and tools, the skill store is injected by protocol. An agent
node asks deps for a SkillStore; it neither knows nor cares that it's the
in-memory one.
3. List all skills¶
list() returns every stored skill. This is what a "show my capabilities" query
would enumerate.
4. Filter by relevance¶
matched = filter_skills(all_skills, "code")
print(f"Filtered 'code': {[s.name for s in matched]}") # ['review']
filter_skills narrows a skill set to those relevant to a query string. Here only
review (description "Code review") matches "code". In an agent turn you'd pass
the user's message so the prompt carries just the pertinent skills — not the whole
library — keeping token cost down.
5. Format for prompt injection¶
formatted = format_skills_list(all_skills)
print(f"Prompt injection ({len(formatted)} chars):\n{formatted}")
format_skills_list renders skills into the text block the prompt builder splices
into the system prompt. This is the bridge between stored skills and what the
model actually sees. In a full agent this is wired via a SkillsSection — see
e2e_basic_agent.
The pattern¶
Store many → filter to the relevant few → format into the prompt. This keeps the prompt focused: the agent has access to a large skill library but only pays for the handful each turn actually needs.
What to try next¶
- See skills composed into a real prompt → e2e_basic_agent
- Capability-filter tools the same way → tool_agent