Skip to content

[FEATURE] Implement skills #486

@edenreich

Description

@edenreich

Summary

Anthropic (Claude Code), OpenAI (Codex CLI / ChatGPT) and Google (Gemini CLI) have all converged on the same "Agent Skills" contract over the last 6 months. Skills are now a de-facto standard: a folder containing a SKILL.md with YAML frontmatter that the agent loads as metadata at startup and reads in full only when relevant.

The CLI should adopt the same on-disk format so users can drop an existing skill folder authored for Claude / Codex / Gemini into .infer/skills/ and have it just work — that is the "seamless transition" goal.

Prior art (must stay compatible with)

Provider User dir Project dir Entry file Required frontmatter
Anthropic Claude Code ~/.claude/skills/<name>/ .claude/skills/<name>/ SKILL.md name, description
Google Gemini CLI ~/.gemini/skills/ or ~/.agents/skills/ .gemini/skills/ or .agents/skills/ SKILL.md name, description
OpenAI Codex CLI ~/.codex/skills/<name>/ (n/a) SKILL.md name, description

References:

Convergent contract (shared by all three)

  1. A skill is a directory (not a single file) — so it can ship scripts/, references/, assets/.
  2. Entry file is SKILL.md (uppercase, exact name).
  3. YAML frontmatter with at minimum name and description between --- delimiters at the very top of the file.
  4. Progressive disclosure: only name + description go into the system prompt at startup; the body is read lazily when the model decides to activate the skill.
  5. Two scopes: user-global (~/.<vendor>/skills/) and project-local (.<vendor>/skills/).

Design

Locations (mirroring the convention):

  • Project: .infer/skills/<skill-name>/SKILL.md
  • User-global: ~/.infer/skills/<skill-name>/SKILL.md
  • Project skills override user-global skills with the same name.

SKILL.md format (identical to Anthropic / Gemini / Codex):

---
name: my-skill-name
description: One-paragraph description that tells the model both WHAT this skill does and WHEN to use it. Used for routing — make it specific.
---

# My Skill

Step-by-step instructions, examples, and references for the model to follow
once this skill is activated.

Frontmatter validation (match Anthropic's spec to maximise portability):

  • name: required, ≤64 chars, lowercase letters + digits + hyphens only, must equal the directory name, must not contain infer / claude / anthropic / gemini / openai.
  • description: required, non-empty, ≤1024 chars.
  • Unknown frontmatter keys are tolerated (forward-compat with vendor extensions like Gemini's disabled: flag).

Skill directory contents (all optional except SKILL.md):

.infer/skills/pdf-processing/
├── SKILL.md            # required: frontmatter + instructions
├── references/         # optional: extra .md files the body links to
├── scripts/            # optional: executable helpers (run via Bash tool)
└── assets/             # optional: templates, fixtures, etc.

Progressive disclosure (the whole point of the format — must be implemented this way, otherwise we burn context):

  1. Startup: scan both skill dirs, parse frontmatter only, inject a single block into the agent system prompt listing each enabled skill's name, description, and absolute path. Body of SKILL.md is not loaded.
  2. Runtime: the model decides to use a skill and reads SKILL.md (and any referenced files) using the existing Read tool. No new tool needed — Read already covers it.
  3. The injected system-prompt block must include a short instruction telling the model how to activate a skill (e.g. "When a task matches a skill's description, read <path>/SKILL.md first, then follow its instructions").

Configuration (do not introduce .infer/skills/config.yaml — that diverges from every other CLI). Instead extend the existing config layout:

# .infer/config.yaml
agent:
  skills:
    enabled: false        # disabled by default (see acceptance criteria)
    disabled_skills: []   # optional per-skill opt-out by name

Env override: INFER_AGENT_SKILLS_ENABLED=true.

When enabled: false, the scan is skipped entirely — zero token cost, no system-prompt block injected.

Acceptance Criteria

  • Skills are loaded from .infer/skills/<name>/SKILL.md (project) and ~/.infer/skills/<name>/SKILL.md (user-global). Project wins on name collision.
  • infer init creates an empty .infer/skills/ directory and an example .infer/skills/example/SKILL.md (commented "delete me") so the format is discoverable.
  • agent.skills.enabled is added to config.yaml defaults as false. Skill loading is a no-op when disabled.
  • On startup (when enabled), the agent's system prompt includes a block listing each enabled skill's name, description, and absolute path to its SKILL.md, plus a short "how to activate" instruction.
  • Skill bodies are not loaded at startup — the model reads SKILL.md on demand via the existing Read tool (progressive disclosure, matches Anthropic / Gemini / Codex behaviour).
  • Frontmatter validation matches the spec above (name charset + length, description length). Invalid skills are skipped with a warning log, never crash startup. Directory whose name doesn't match name frontmatter is rejected.
  • disabled_skills: [foo, bar] in config skips those skills by name.
  • An existing Anthropic / Gemini / Codex skill folder copied into .infer/skills/ works without modification (verified by test using a sample from github.com/anthropics/skills).
  • New infer skills list command shows discovered skills, scope (project/user), enabled state, and any validation errors. Mirrors the existing infer agents / infer mcp patterns.
  • Documentation added at docs/skills.md covering: format, locations, enabling, authoring tips, security note (skills can instruct the model to run code — only use trusted sources), and a portability note pointing at the three vendor docs.
  • Unit tests cover: frontmatter parsing (valid + each invalid case), project-overrides-user precedence, disabled-skills filter, system-prompt injection format, and the "no-op when disabled" path.

Out of scope (for this issue)

  • A dedicated activate_skill tool (Gemini-style). The model can use Read directly; revisit if we observe activation issues.
  • Skill marketplace / remote install. Skills are filesystem-only for v1.
  • Skill execution sandboxing beyond what the existing tool-approval system already provides.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    Status

    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions