Augments LabsAugments ADK

๐ŸŽ’ Skills

A skill is a composable bundle of instructions, tools, resources, and governance that you attach to an Agent. Where a tool is a single Python callable, a skill is a full capability stack โ€” domain expertise (markdown instructions), the functions that realise it (tools), the policies that govern those functions (guardrails, timeouts, retry budgets), and optional reference material (resources).

Skills implement the composition-over-inheritance principle: building a "research-capable agent" means attaching a ResearchSkill, not subclassing Agent.


Anatomy of a skill

Skill is a plain dataclass under src/augments/adk/skills/skill.py. Every field is shown below alongside its purpose.

FieldTypePurpose
namestrUnique identifier. Required.
descriptionstrShort summary used by discovery tools and SkillSet.find().
instructionsstr | NoneMarkdown injected into the agent's system prompt on activation.
toolslist[Tool]Tools merged into the agent's tool list on activation.
guardrailsToolGuardrails | NoneSkill-level input/output guardrails prepended to each tool's own guardrails.
enabledbool | Callable[[RunContext], bool]Static flag or dynamic predicate that controls whether the skill is active.
metadataSkillMetadata | NoneVersion, author, tags, license โ€” used for discovery and filtering.
governanceSkillGovernance | NoneDefault timeout, max_result_tokens, and max_retries applied to every tool in the skill.
resourcesdict[str, str] | NoneNamed files or content strings accessible via SkillDiscoveryToolset.
resource_rootPath | NoneAbsolute root that bounds resource path resolution (set by directory loaders).

Two companion types carry optional detail:

  • SkillMetadata(version, author, tags, license) โ€” immutable, used for cataloguing and SkillSet.filter_by_tag().
  • SkillGovernance(timeout, max_result_tokens, max_retries) โ€” values act as defaults; a tool's own setting always takes precedence.

Minimal example

from augments.adk.agents import Agent
from augments.adk.llms import LLMConfig
from augments.adk.run import Runner
from augments.adk.skills import Skill, SkillGovernance
from augments.adk.tools import function_tool
 
 
@function_tool(name="fetch_article", description="Fetch the text of a web article by URL.")
def fetch_article(url: str) -> str:
    """Return article body (stub)."""
    return f"[article at {url}]"
 
 
@function_tool(name="summarise", description="Summarise a block of text in one paragraph.")
def summarise(text: str) -> str:
    """Return a one-paragraph summary (stub)."""
    return f"Summary of: {text[:80]}โ€ฆ"
 
 
research_skill = Skill(
    name="research",
    description="Web research and summarisation",
    instructions="""When researching a topic:
1. Fetch the most authoritative source with `fetch_article`.
2. Summarise the result with `summarise`.
3. Cite the source URL in your reply.""",
    tools=[fetch_article, summarise],
    governance=SkillGovernance(
        timeout=30.0,
        max_result_tokens=1024,
        max_retries=2,
    ),
)
 
agent = Agent(
    name="Research Assistant",
    system_prompt="You are a research assistant. Use your tools to answer questions.",
    skills=[research_skill],
    llm_config=LLMConfig(temperature=0.2),
)
 
result = Runner.run(agent, "Summarise the main claims in https://example.com/paper")
print(result.final_output)

Agent(skills=[research_skill]) is the only declaration needed. The Runner unpacks the skill at run time โ€” merging research_skill.tools into the agent's tool list and injecting research_skill.instructions into the system prompt.


Skill vs Tool

[!TIP] Quick rule

Reach for a tool when you need to expose a single function. Reach for a skill when you need a full capability stack โ€” instructions that teach the LLM how to use the tools, governance that constrains them, and guardrails that protect them.

AspectSkillTool (FunctionTool)
GranularityBundle of related capabilities.Single callable.
InstructionsMarkdown injected into the system prompt.Description string only.
GovernanceSkillGovernance applied as defaults to every bundled tool.Per-tool only.
GuardrailsSkill-level guardrails prepend each tool's own list.Per-tool only.
ReuseOne Skill instance, many agents.One FunctionTool per site unless explicitly shared.
CompositionMultiple skills per agent; skills may share tools.Multiple tools per agent.

A tool is a primitive; a skill is a package. A skill may contain zero tools (instructions-only), many tools, or tools that a bare agent also carries.

For the full treatment see the Concepts page: Concepts.


Skill activation strategies

The SkillActivation enum (exported from augments.adk.skills) controls when skill instructions enter the system prompt.

LAZY (default on Agent.skill_activation)

Instructions are injected only when one of the skill's tools is called for the first time. Tool descriptions are always visible in the tool list, so the LLM can discover them without any extra overhead. Turns that never call a skill's tools pay nothing for that skill's instruction text.

from augments.adk.skills import SkillActivation
 
agent = Agent(
    name="Assistant",
    system_prompt="โ€ฆ",
    skills=[research_skill, billing_skill, safety_skill],
    skill_activation=SkillActivation.LAZY,  # default โ€” no need to set explicitly
)

EAGER

All skill instructions are concatenated into the system prompt before the first LLM call. Use this only when every skill is relevant to every turn โ€” for example an agent with a single, always-applicable skill.

agent = Agent(
    name="Research Assistant",
    system_prompt="โ€ฆ",
    skills=[research_skill],
    skill_activation=SkillActivation.EAGER,
)

The LAZY default is intentional: it aligns with the cost-conservative principle โ€” agents never pay per-turn token cost for capabilities the LLM didn't need.


How the Runner composes skills

When a run starts the Runner calls two composition functions inside the loop:

  1. resolve_system_prompt โ€” For EAGER activation, it appends all enabled skill instructions under an ## Available Skills heading. For LAZY, it excludes skill instructions at run start and tracks a skill_tool_map (tool name โ†’ skill name) for deferred injection.

  2. build_tools โ€” Merges skill tools with the agent's own tools. For each tool in each enabled skill, SkillGovernance values are applied as defaults (tool's own timeout, max_result_tokens, max_retries take precedence), and skill-level ToolGuardrails entries are prepended to each tool's guardrail list.

Name conflicts: if two skills declare a tool with the same name, the Runner merges them in declaration order โ€” the first tool with a given name wins. Design skills so their tool names are scoped (e.g. research_fetch_article, not fetch).

Dynamic enablement: Skill.enabled accepts a sync or async callable (RunContext) -> bool. The Runner evaluates this at activation time, so skills can be toggled by feature flags, tenant configuration, or run context.

Lifecycle hook: when LAZY activation fires on first tool call, the Runner emits on_skill_activated(context, agent, skill_name) so hooks can record telemetry or update audit logs without polling.


Built-in skills

No skills ship by default. The framework ships the skill machinery (Skill, SkillSet, SkillActivation, SkillGovernance, SkillDiscoveryToolset) but no pre-built capability stacks. Every skill in your application is user-defined, which keeps the surface minimal and the token budget in the developer's hands.


Per-skill governance and guardrails

SkillGovernance sets defaults for every tool bundled in the skill:

from augments.adk.skills import Skill, SkillGovernance
 
billing_skill = Skill(
    name="billing",
    description="Invoice lookup and payment operations",
    tools=[lookup_invoice, charge_card, issue_refund],
    governance=SkillGovernance(
        timeout=10.0,         # each tool gets 10 s unless it sets its own timeout
        max_result_tokens=512,
        max_retries=1,        # billing calls: fail fast, don't retry silently
    ),
)

Tool-level values override skill-level values โ€” governance is always a floor, never a ceiling.

Skill-level guardrails run before each tool's own guardrails:

from augments.adk.tools.tool_guardrails import ToolGuardrails, tool_input_guardrail, ToolInputGuardrailData, ToolGuardrailFunctionOutput
 
 
@tool_input_guardrail(name="billing_pii_check")
async def billing_pii_check(data: ToolInputGuardrailData) -> ToolGuardrailFunctionOutput:
    """Block raw card numbers from reaching billing tools."""
    if "4" in str(data.agent_output) and len(str(data.agent_output)) > 15:
        return ToolGuardrailFunctionOutput.reject_content("Raw card numbers are not accepted.")
    return ToolGuardrailFunctionOutput.allow()
 
 
billing_skill = Skill(
    name="billing",
    description="Invoice lookup and payment operations",
    tools=[lookup_invoice, charge_card, issue_refund],
    guardrails=ToolGuardrails(input=[billing_pii_check]),
)

Every tool inside billing_skill will have billing_pii_check prepended to its input guardrail chain. Per-skill governance and guardrails are the primary mechanism for the governance-bundling principle described in ๐Ÿ›ก๏ธ Governance.


Skill sources

Skills can be defined inline or loaded from external sources.

Inline (code-defined) โ€” the default for application code:

skill = Skill(name="research", description="Web research", tools=[fetch_article])

Directory โ€” load from a folder containing a SKILL.md file. Compatible with the LangChain / CrewAI / Google ADK skill directory format:

skill = Skill.from_directory("./skills/code-review/")

The SKILL.md file uses YAML front matter for metadata and a markdown body for instructions:

---
name: code-review
description: Expert Python code review with security focus
tags: python, security, review
---
 
When reviewing code:
1. Check for security vulnerabilities first.
2. Then check for performance issues.
3. Finally suggest style improvements.

The directory loader sets resource_root automatically so that any scripts under scripts/ are bounded within the skill tree.

Remote URL โ€” load from a SKILL.md hosted anywhere:

skill = await Skill.from_url("https://skills.example.com/research/SKILL.md")

Reusable skill libraries

Skills are plain dataclasses โ€” define them once in a shared module and import them wherever agents are built:

# myapp/skills/__init__.py
from augments.adk.skills import Skill, SkillGovernance, SkillMetadata
from myapp.tools.research import fetch_article, summarise
from myapp.tools.billing import lookup_invoice, charge_card
 
research_skill = Skill(
    name="research",
    description="Web research and summarisation",
    tools=[fetch_article, summarise],
    metadata=SkillMetadata(version="1.0.0", tags=("research",)),
    governance=SkillGovernance(timeout=30.0, max_result_tokens=1024),
)
 
billing_skill = Skill(
    name="billing",
    description="Invoice lookup and payment processing",
    tools=[lookup_invoice, charge_card],
    metadata=SkillMetadata(version="1.0.0", tags=("billing", "payments")),
    governance=SkillGovernance(timeout=10.0, max_retries=1),
)
# myapp/agents/support.py
from augments.adk.agents import Agent
from myapp.skills import billing_skill, research_skill
 
support_agent = Agent(
    name="Support",
    system_prompt="You handle customer support queries.",
    skills=[research_skill, billing_skill],
)
# myapp/agents/billing_only.py
from augments.adk.agents import Agent
from myapp.skills import billing_skill
 
billing_agent = Agent(
    name="Billing Specialist",
    system_prompt="You handle billing queries only.",
    skills=[billing_skill],
)

Use SkillSet to keep related skills together and query them at build time:

from augments.adk.skills import SkillSet
 
finance_skills = SkillSet(name="finance", skills=[billing_skill, tax_skill, fx_skill])
 
# Find by name
inv = finance_skills.find("billing")
 
# Filter by tag
payment_skills = finance_skills.filter_by_tag("payments")

LLM-driven discovery with SkillDiscoveryToolset

For agents that hold a large, open-ended library of skills, you can let the LLM itself decide which skill to load. SkillDiscoveryToolset generates FunctionTools that the LLM calls to introspect the skill catalogue:

from augments.adk.skills import Skill, SkillDiscoveryToolset
from augments.adk.skills import RECOMMENDED_SKILL_INSTRUCTIONS, prompt_with_skill_instructions
 
skills = [research_skill, billing_skill, safety_skill]
discovery = SkillDiscoveryToolset(skills=skills)
 
agent = Agent(
    name="General Assistant",
    system_prompt=prompt_with_skill_instructions(
        "You are a general-purpose assistant."
    ),
    skills=skills,
    tools=[*discovery.tools()],
)

The generated tools:

ToolWhat it does
list_skillsReturns names and descriptions of all skills.
load_skillReturns full instructions and tool list for a named skill.
load_skill_resourceReads a resource file from a skill (only generated if any skill has resources).
run_skill_scriptExecutes a Python or Bash script from a skill's resources. Disabled by default; set enable_scripts=True to opt in. Requires human approval on each call.

Discovery tools are strictly opt-in โ€” nothing is auto-injected. prompt_with_skill_instructions prepends the recommended usage instructions to any prompt string.


Common skill patterns

Research skill โ€” web search, article fetch, summariser, with a strict instruction chain (fetch โ†’ summarise โ†’ cite). Governance caps token output and timeout so a slow source doesn't stall the agent loop.

Safety-review skill โ€” instructions for how to evaluate text for policy violations; tools that call a moderation endpoint. Skill-level guardrails reject inputs that are obviously out of policy before they reach the tools. Can be combined with an on_skill_activated hook that logs every moderation invocation to an audit sink.

Billing skill โ€” payment and invoice tools with a tight governance budget (max_retries=1, timeout=10.0) so failures are loud and fast. A skill-level PII input guardrail blocks raw card numbers from ever reaching tool arguments. Shared across customer-facing and internal agents from a single definition in a finance skill library.


See also

  • Concepts โ€” Skills vs Tools comparison table (ยง "๐ŸŽ’ Skills vs ๐Ÿ”ง Tools")
  • ๐Ÿ›ก๏ธ Governance โ€” Audit substrate and tool permissions
  • examples/skills/ โ€” Runnable end-to-end examples (skills_agent_with_skills.py, skills_customer_support.py, skills_directory.py, skills_discovery.py)