Skills
core-agent loads SKILL.md bundles from .agents/skills/<name>/. The schema mirrors Anthropic’s published skills format so existing skill bundles drop in directly.
Directory layout
Section titled “Directory layout”.agents/└── skills/ ├── echo/ │ └── SKILL.md ├── jira-triage/ │ ├── SKILL.md │ └── examples/ │ └── ticket.md └── data-export/ ├── SKILL.md └── helpers/ └── export.pyEach subdirectory of .agents/skills/ is one skill. A skill must contain a SKILL.md at its root; the directory name is the skill’s identifier (and what the agent invokes by). Other files in the directory are referenced from SKILL.md and loaded on demand.
SKILL.md format
Section titled “SKILL.md format”Standard YAML frontmatter + a markdown body. The frontmatter declares the skill’s identity and surface; the body is the prompt content the agent reads when it invokes the skill.
---name: jira-triagedescription: Triage a Jira ticket — read it, classify, recommend next action.---
When asked to triage a Jira ticket:
1. Read the ticket via the `jira_get_issue` tool.2. Classify by severity using the rubric in `examples/severity.md`.3. Suggest the next action: assign, request more info, or close.
Always include the ticket key (e.g. `PROJ-123`) in your response.Required frontmatter
Section titled “Required frontmatter”| Field | Notes |
|---|---|
name | Skill identifier. Should match the directory name. |
description | One-line summary the agent sees in its tool list. Used by the model to decide when to invoke. |
Optional frontmatter
Section titled “Optional frontmatter”The Anthropic SKILL.md spec allows additional fields (allowed_tools, version, etc.). core-agent parses the name and description for its own metadata; the rest is preserved verbatim and passed through to the underlying ADK skilltoolset.
Body conventions
Section titled “Body conventions”- Write in second person, addressed to the agent (“When asked X, do Y”).
- Reference sibling files with relative paths — they’re loaded lazily when the skill is invoked, so a large bundle doesn’t blow up cold-start.
- Keep frontmatter terse; details belong in the body.
Discovery
Section titled “Discovery”At startup, core-agent reads skills from three roots in precedence order and merges them into one virtual filesystem. On name collision the higher-precedence source wins.
| Precedence | Path | Scope |
|---|---|---|
| 1 (highest) | <agentsDir>/skills/ (typically <project>/.agents/skills/) | Project — checked in to the repo |
| 2 | ~/.agents/skills/ | Portable user assets |
| 3 (lowest) | ~/.core-agent/skills/ | User-global fallback |
~/.agents/ is the portable user root — the same layout you’d use inside a project’s .agents/ but at $HOME. Drop a skill there once and every project picks it up, even in harness setups (e.g. scion) that pre-create a workspace .agents/skills/ that would otherwise shadow it. ~/.core-agent/skills/ remains supported as a lower-precedence fallback.
The loader:
- Stats each of the three
skills/directories. Missing directories are silently skipped (most operators have none or one populated). - Lists frontmatters via ADK’s
skill.NewFileSystemSourceover the merged view. - If at least one valid frontmatter is found, builds a
skilltoolsetand registers it as a single ADK Toolset. - If a permission gate is configured, wraps the toolset with the gate under the
skillnamespace.
The Skills returned by skills.Load carries:
Toolset— pass toagent.WithToolsets(...).Infos []Info— name + description for each discovered skill, suitable for rendering a/skillsview in your host.
loaded, err := skills.Load(ctx, agentsDir, gate)if err != nil { ... }if !loaded.Empty() { opts = append(opts, agent.WithToolsets([]adktool.Toolset{loaded.Toolset}))}Permission gating
Section titled “Permission gating”When a gate is supplied to skills.Load, every skill invocation goes through it under the skill namespace. Allowlist patterns look like:
{ "permissions": { "allow": ["skill:jira-triage", "skill:data-export"] }}The detail string surfaced in prompts is <skill_name> <json-args> (truncated). Skip gating entirely with permissions.mode: yolo.
Empty bundles
Section titled “Empty bundles”A .agents/skills/ directory that exists but contains no valid SKILL.md bundles is treated as a no-op (returns an empty Skills). No error, no toolset registered. This means you can scaffold the directory in advance and add bundles incrementally.
The same holds for the fallback roots — an empty ~/.agents/skills/ or ~/.core-agent/skills/ contributes nothing to the merged view, so scaffolding one root before populating it is safe.
What’s not covered today
Section titled “What’s not covered today”- Hot reload — adding a new skill requires restarting the process.
- Per-skill permission scopes — gating is
skill:<name>granular; sub-tool gating within a skill bundle isn’t exposed. - Versioning —
SKILL.mdmay carry aversionfield, butcore-agentdoesn’t currently surface or enforce it. Use the bundle’s directory layout (e.g. one directory per major version) if you need version pinning.
These could land in a later milestone if downstream consumers ask. See the Roadmap.