Skip to content

Skill Lifecycle

This guide walks through how a shared skill flows from mirai-agent-core's router all the way to a tool result, and where each architectural decision in this catalog plugs in. It's the page to read when you want to understand "what actually happens at runtime when my agent uses AgenticRAGSkill".

End-to-end flow

1. Import time
   import mirai_shared_skills
   ├─► _registry.bootstrap([...])           ADR-0004
   │     populates _REGISTRY with 8 descriptors
   └─► every skill class is now importable
       (no instantiation yet)

2. Client construction (downstream code)
   skill = AgenticRAGSkill(graph=…, vector=…)   ADR-0002 (provider DI)
   gated = SecureSkill(skill, policy={…})       agent-core ADR-0012
   engine.attach(gated)                         agent-core API
   engine accepts a list[BaseSkill]

3. Per-turn — agent-core territory
   user message
   GuardrailsManager (regex fast-path)          agent-core ADR-0002
   SemanticRouter selects active skills          agent-core ADR-0008
   │     output: RouteSelection(active=[gated_rag, gated_browser, …])
   ephemeral Pydantic AI Agent constructed
   │     tools = sum(s.get_tools() for s in active)
   │     each get_tools() returns Tool objects
   │     built via tool_from_function           ADR-0007
   SecureSkill.get_tools() filters/wraps        ADR-0001 + agent-core ADR-0012
   │     BLOCKED tools: dropped
   │     REQUIRES_HITL tools: wrapped with with_hitl_approval
   │     SAFE tools: pass through
   Agent runs the turn, possibly calling tools
   tool result returned through AG-UI stream    agent-core ADR-0003

Where each ADR fires

Phase ADR What happens
Import ADR-0004 bootstrap([...]) registers every descriptor. find-skills is now usable.
Import ADR-0003 If a backend extra is missing, constructing a provider raises *UnavailableError — but importing the package doesn't.
Construction ADR-0002 Concrete providers passed to AgenticRAGSkill.__init__.
Construction ADR-0001 Client decides whether to wrap in SecureSkill. raw skills MUST wrap; standard MAY wrap for defense in depth.
Construction ADR-0007 Skill's get_tools() returns Tool objects built from plain async methods.
Per-turn ADR-0008 LLM may call load_skill_instructions to fetch long-form guidance from a references/ file.
Per-turn ADR-0005 If an HTTP-using skill returns 401/403, agent calls inspect_status_code then request_credential_handoff.
Per-turn ADR-0006 AgenticRAGSkill enforces token budget on retrieved chunks before returning.

Where SecureSkill fits

SecureSkill is part of mirai-agent-core (agent-core ADR-0012) — not part of this catalog. The two work together:

  • The catalog says (via SkillDescriptor.category) "this skill needs wrapping".
  • SecureSkill says (via per-tool SecurityLevel) "and here's the policy for each tool".

The catalog cannot ship a SecureSkill directly because the right policy depends on the client's schema, client's threat model, client's user identity, etc. The two-tier design (catalog category × runtime per-tool level) cleanly separates "what this skill does" from "what this client allows".

Common patterns

"Wrap everything by default"

A defensive client wraps every skill — not just raw ones — with conservative defaults:

def harden(skill: BaseSkill) -> SecureSkill:
    # Default-deny: any tool not explicitly listed is BLOCKED.
    return SecureSkill(skill, policy=allowlist_for(skill))

"Audit which skills are raw"

from mirai_shared_skills import all_descriptors

raw_skills = [d for d in all_descriptors() if d.category == "raw"]
print(f"Raw skills requiring wrapping: {[d.name for d in raw_skills]}")

"Subscribe to credential handoffs"

When AuthenticationGatesSkill emits a CredentialHandoff, the AG-UI stream surfaces it to the calling system. The UI renders it as an approval prompt; the user supplies the credential; the agent's turn resumes.