google/dev-skills
How AI agent skills work -- discovery, loading, triggering, format, and organization. Use when building Capsem's skills system, implementing skill discovery for guest AI agents, or understanding how Claude Code, Gemini CLI, Codex, and Cursor consume SKILL.md files. Covers the SKILL.md format, discovery mechanics, progressive disclosure, naming conventions, and lessons learned from setting up this project's skills.
npx skills add https://github.com/google/capsem --skill dev-skills
This documents everything we know about how skills work across Claude Code,
Gemini CLI, Codex, and Cursor, learned from building and organizing this
project's skills. This knowledge will inform Capsem's own skills system for
guest AI agents.
.claude/skills/ (project) and ~/.claude/skills/ (global)<name>/SKILL.md -- one level of nesting onlycategory/skill/SKILL.md) are NOT discovered.claude/skills -> ../skills to share with Gemini.agents/skills/ or .gemini/skills/<name>/SKILL.md format as Claude Code.agents/skills -> ../skills and .gemini/skills -> ../skillssymlinks
.codex/skills/ and .cursor/skills/ point to the sharedskills/ directory so those clients consume the same project skills.
bootstrap.sh creates .claude, .agents, .gemini, .codex, and.cursor skill symlinks non-destructively.
skills/dev/testing/SKILL.md is not found by either CLISKILL.md in a directory are not discovered as skillsDo not add alternate skill/bootstrap validation modes named fast, check, or
dry-run behind separate flags. Forked verification paths are how projects lose
the real contract. The shared skill rail must be fast, hermetic, and complete
enough to run every time; if it is not, fix the rail instead of adding a bypass.
Every feature owes a pure black-box ledger test. The test must exercise the
public path end to end and account for the exact input and output: client-visible
result, parsed event facts, security decision, detection/enforcement records,
protocol rows, structured logs, counters, and route/UI JSON when those surfaces
exist. No feature is done with a single-entry proof. What goes in must come out
exactly, and every transformation must be accounted for.
When image-build work touches config/profiles/<profile_id>/build.sh, load the
build-images skill. build.sh is not an installer, setup step, boot hook, or
runtime customization rail. It is the profile-owned rootfs build hook executed
by the admin/just image pipeline before EROFS assets are produced. The profile
ledger owns the file descriptor, and the change is only real in a VM after the
profile assets are rebuilt through that same pipeline.
Use build.sh only for rootfs construction work that cannot live in the boring
profile package files: vendor shell installers, binary tarball installs,
system-path wrappers, and build-time cleanup. Do not put credentials, corp
policy, provider state, MCP decisions, runtime settings, or user repair logic
there. After changing it, run capsem-admin profile check, rebuild assets,
boot a fresh VM, and pay the Ironbank proof for the user-visible behavior.
Never hand-edit profile payload hashes or sizes; if validation fails, fix the
source contract or the materialization rail with tests.
config/skills is not a development skill location. Read config/README.md
before adding any profile-owned skill payload, and keep repository development
skills in top-level skills/.
---
name: skill-name
description: When to trigger and what it does. Be specific and pushy -- Claude undertriggers.
---
# Skill Title
Instructions the agent follows when triggered.
name (required) -- skill identifier, should match directory namedescription (required) -- this is the PRIMARY trigger mechanism. Claude sees name + description in its skill list and decides whether to load the full body. Everything about "when to use" goes here.user-invocable: true -- lets users invoke with /skill-nameallowed-tools -- restrict which tools the skill can usecontext: fork -- run in a subagentClaude undertriggers skills by default. Descriptions must be:
Bad: "Frontend development guide"
Good: "Capsem frontend design system. Use when building UI components, styling views, working with the design system, choosing colors, or understanding the component library."
Three loading tiers:
references/, scripts/, assets/ subdirs, loaded on demandThis means: keep SKILL.md lean. Put detailed wire formats, API docs, and large references in references/ with clear pointers from the SKILL.md body.
Flat directory structure with naming convention for categories:
skills/
dev-testing/SKILL.md dev category
dev-debugging/SKILL.md dev category
build-images/SKILL.md build category
release-process/SKILL.md release category
meta-find-skills/SKILL.md meta category
Categories we use: meta-*, dev-*, build-*, release-*, site-*,
frontend-*.
skill-name/
SKILL.md Main instructions (<500 lines)
references/
wire-format.md Detailed protocol docs
community-skill.md Fetched from npx skills / GitHub
scripts/
helper.sh Executable automation
assets/
template.html Templates, icons
Reference from SKILL.md with: "Read references/wire-format.md for the full protocol details."
The npx skills CLI (skills.sh) discovers community skills. To use one:
npx skills find <query> # Search
# Then manually fetch and place:
curl -sL https://raw.githubusercontent.com/<owner>/<repo>/main/<path>/SKILL.md \
-o skills/<name>/references/<topic>.md
We place community skills as references (not top-level SKILL.md) because:
Quality bar: prefer official sources (anthropics/, sveltejs/, google-gemini/) or 1K+ installs. Verify content before bundling.
Skills in ~/.claude/skills/ are available across all projects. We install meta skills globally:
meta-find-skills -- discover community skillsmeta-organize-skills -- skill conventionsmeta-skill-creation -- create/iterate skillsfor Claude Code, Gemini CLI, Codex, and Cursor. No duplication needed.
failed only in CI because the doctor required
x86_64-linux-musl-gcc on an arm64 runner even though the native musl-gcc
installed by musl-tools was the real build contract. The local
Docker rail had tested package installation but not that exact doctor
predicate. Whenever CI exposes a missing dependency or runner assumption,
execute the same production entrypoint or shared predicate locally in
Docker when possible, add a regression, and audit sibling workflows before
retrying CI. Record any unavoidable platform boundary explicitly.
When a rule keeps being broken, the first move is a function that makes the
break unrepresentable -- not a lint that scolds. Add the guard to stop
regressions *after* the wrapper exists, and point it at the wrapper.
A guard must be precise before it is useful. Ours needed four iterations, each
failing the same way: too coarse. It flagged prose for containing a retired
term inside a current one; it flagged whole files for containing two shapes
that never met; it flagged a variable named path in one function because
another function had a parameter of that name. A guard with false positives
teaches people to add exemptions, and the pressure is always to narrow its
scope to fit the code rather than fix the code.
Before trusting a new guard: run it, read every hit, and confirm each is real.
Then break the rule deliberately and confirm it fails. A guard that has never
been red is a guard you have not tested.
Take google/dev-skills from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npx.
Without those the skill loads but fails at the first command.