↓Skip to main content

Authoring Guidance

·10 mins
For AI agents: a documentation index is available at /llms.txt — markdown versions of all pages are available by appending index.md to any URL path.

This guidance is derived from the automated findings in the platform comparison (check list 0.4, tested in headless mode against Antigravity CLI 1.2.11, Claude Code 2.1.274, Codex CLI 0.157.0, and GitHub Copilot CLI 1.0.88; each platform report lists the releases behind its findings). Untested platforms may behave differently, so this guidance is likely to change as we study more harness skill implementations. The terms used here (push harness, pull harness, canary phrase, and more) are defined in the glossary.

Naming and identity #

Make the frontmatter name match the directory name exactly. The spec requires it. In platforms under test, we’ve observed they don’t enforce this convention, nor resolve it the same way. Codex, Antigravity, and Copilot CLI activate the skill by its frontmatter name (Codex and Copilot CLI also show the directory name in their listings, because the listed path contains it, but activating by that name fails), while Claude Code lists and activates it under the directory name only. A mismatched skill answers to different names on different platforms. Anything that references it by name, such as documentation, other skills, or user habit, breaks on whichever platform chose the other identity (name-directory-mismatch).

Follow all of the name rules, not just the ones your platform enforces. Enforcement varies by rule: every tested platform tolerated uppercase letters and consecutive hyphens in a skill name, but a name over the spec’s 64-character limit is rejected by Codex and Copilot CLI while Claude Code and Antigravity load it anyway. A rule-breaking name works where you tested it and vanishes elsewhere, with no error (invalid-name-tolerance).

Keep names ASCII. The spec allows “unicode lowercase alphanumeric characters” and then parenthesizes an ASCII range, and platforms have read that both ways. Copilot CLI drops any non-ASCII name from its catalog, even a 16-character Greek one. Codex accepts Greek and astral-plane lowercase letters and counts the 64-character cap in code points, the same unit as the spec’s reference validator. Claude Code and Antigravity accept them and enforce no cap at all. A name in a non-Latin script is therefore invisible on one of four tested platforms, and the counting-unit question that bites descriptions never has to arise for names if the name is ASCII, where every unit agrees (name-length-unit).

Expect your skill’s name to be the only thing that identifies it. Two skills with the same name installed at different scopes, or under different roots of the same project, resolve differently on every tested platform, and never with a warning. Pick names that are unlikely to collide with anything a user already has, and never ship two skills with the same name yourself (name-collision-precedence, multi-root-collision-precedence). The installation side of this is on the installing page.

Frontmatter #

Always include a description, and quote any value containing a colon. Codex doesn’t register skills with no description. Claude Code, Antigravity, and Copilot CLI load them anyway, but with no description, these harnesses don’t know when to invoke the skill. So a missing description means your skill does not exist for some users (missing-description-handling). In YAML formatting tests, an unquoted colon in a description is invalid YAML that Codex and Claude Code tolerate, but the Antigravity and Copilot CLI catalogs reject (malformed-yaml-tolerance).

Do not put load-bearing information only in frontmatter. Claude Code and Copilot CLI strip frontmatter before injecting skill content, and their skill listings carry only names and descriptions, so compatibility notes and metadata values never reach the model through any platform channel. The model can still stumble on the raw file; skills live at conventional paths it can guess, and project skills sit inside the working tree; but nothing guarantees it will. On pull harnesses (Antigravity, Codex CLI), the model sees frontmatter only because it reads the file itself. If the model must know something (requirements, warnings, version constraints), state it in the body (frontmatter-handling, compatibility-field-behavior, discovery-listing-fields).

Keep the description under 1024 characters, and put the activation cues early. Enforcement of the spec’s limit ranges from none to total: Claude Code injects the full over-limit value into its listing, Antigravity loads the skill too, Codex truncates the description partway through, and Copilot CLI drops the skill from its catalog entirely. Anything past Codex’s truncation point, including trailing “use when” sentences, never reaches the model, and on Copilot CLI the whole skill is gone (oversize-description-handling). The two enforcing platforms even measure the limit differently: Codex counts Unicode code points and Copilot CLI counts UTF-16 code units, so a description heavy in emoji or CJK text can pass on one and fail on the other (description-length-unit). An over-limit compatibility value also loaded everywhere (oversize-compatibility-handling).

Do not rely on allowed-tools to pre-approve anything. The spec marks the field experimental, and no tested platform demonstrably acted on it: the instructed command ran with and without the field on three platforms, and was blocked with and without it on Copilot CLI, each under the platform’s normal headless permission posture. On Claude Code the value never reaches the model at all (allowed-tools-behavior). Spelling the value the platform’s way does not help either: Copilot CLI blocked the command under Bash(printf:*), bash, and shell alike, and the other platforms ran it under every spelling, so no tested platform demonstrably matches the field against its own tool names (allowed-tools-name-matching).

Expect nonstandard fields to be ignored. No tested platform acted on requires, depends-on, or priority, even with the named dependencies installed (nonstandard-dependency-fields). Since Claude Code and Copilot CLI don’t see metadata fields at all, and Antigravity and Codex CLI only see frontmatter when the model reads the file, tested harnesses do not benefit from any values in nonstandard fields.

Layout #

Ship a flat layout: one skill directory with SKILL.md at its top. Codex and Copilot CLI scan the skills root recursively, but Claude Code and Antigravity see only direct children, so a skill that expects to live in a grouping folder (skills/data-tools/my-skill/) vanishes from their catalogs (recursive-root-discovery). Document the install path as a direct child of the skills directory.

Do not ship a SKILL.md inside another skill’s directories. Codex registers any SKILL.md it finds under the skills root as a separate, invocable skill, including one inside your references/ folder. An example or vendored skill shipped as documentation becomes a live skill on Codex and stays invisible on the other platforms (nested-skill-discovery).

Keep the skill directory lean. Copilot CLI injects the full path of every file under the skill directory at every activation, dotfiles and binaries included; a vendor/ tree was the one thing it left out. The other tested platforms list nothing. Scratch files, fixtures, and test data cost tokens on every activation there and are invisible everywhere else (bundled-file-enumeration-scale). Measured on five public catalogs, each shipped file costs about 20 tokens per activation on Copilot CLI, half of it the install path. A lone evals/evals.json, the skill-creator convention, costs about 20 tokens; an evaluation fixture tree inside the skill can cost thousands, more than the body in the worst cases. Keep the JSON and move fixtures out. For more details, refer to ( the audit).

Deep resource nesting is safe on the tested platforms. Reference files up to five directory levels deep were reachable everywhere (resource-nesting-depth). The spec’s “one level deep” language concerns chains of references between files, not directory depth.

Paths and resources #

Do not expect SKILL.md-relative paths to resolve as written. The spec instructs skill authors “when referencing other files in your skill, use relative paths from the skill root.” But on Antigravity, Claude Code, and Copilot CLI, a bare path like references/setup-guide.md failed when used from the working directory, and the model recovered at the cost of a failed read and re-qualifying the path against the skill directory. On Codex the model qualified every path itself from the start, so the platform’s own resolution was never exercised. Recovery is model behavior in every case, not a platform guarantee (path-resolution-base). Telling the model explicitly that relative paths resolve against the skill’s own directory costs one sentence and removes the guesswork. That sentence has an anchor on Claude Code and Copilot CLI, which both state the skill’s base directory at the top of the injected content. Codex’s listing carries only an aliased location and Antigravity’s injection cannot be observed, so on those the model has to find the directory itself (activation-location-disclosure).

Resources load only when the model reads them. No tested platform pre-fetches markdown-linked files or loads directory contents at activation, and only one enumerates them: Copilot CLI wraps the injected body in a header that lists the full path of every file under the skill directory, spec directories and nonstandard ones like resources/ or templates/ alike, but loads none of them. Antigravity, Claude Code, and Codex list nothing, so on those platforms the agent doesn’t know what extra files ship with your skill (resource-enumeration-behavior, eager-link-resolution, unrecognized-directory-handling). If a file matters, instruct the model to read it. A mention is not a load, and a listing is not a load either.

Treat scripts as an enhancement with a prose fallback. The spec presents scripts/ as code agents can run, but whether that holds depends on the platform’s permission posture, not on your skill. Our bundled script ran and returned output on Codex and Antigravity; on Claude Code and Copilot CLI, the permission system blocked it in a headless session and the model could only report the denial (bundled-script-execution). Some users may be subject to workplace-dictated policies that prevent script execution, such as enterprises setting a policy of not letting agents execute scripts. If a step exists only inside a script, describe in the SKILL.md body what the script does and what to do when it cannot run. Interactive users may be able to approve the command where headless sessions cannot, so it also matters whether you expect your users to run skills in interactive sessions or in autonomous headless agent sessions.

Name shared resource files distinctively. Two active skills both shipping references/API.md did not shadow each other in our runs, but only because the models qualified every path themselves. The platforms’ handling of a truly ambiguous path went unexercised. Distinct filenames remove the risk outright (cross-skill-resource-shadowing).

Composition and lifecycle #

Skill-to-skill chains work today, but guards are the model’s, not the platform’s. Three-skill invocation chains completed on all platforms, in English and Japanese, and prose-expressed dependencies were resolved (invocation-depth-limit, invocation-language-sensitivity, informal-dependency-resolution). Circular references were stopped by the model choosing to stop, not by any platform mechanism, so do not design skills that rely on a platform catching a cycle (circular-invocation-handling).

Missing dependencies fail visibly. When a skill references an uninstalled skill, every tested platform surfaced the failure. On Claude Code and Copilot CLI the skill tool returned an explicit error. On Codex and Antigravity nothing platform-side signaled the absence: the model reported it, after searching for the skill on Codex and without attempting on Antigravity, and which of those a model does can vary between runs. None hallucinated compliance in our runs, which is the good outcome. But the failure is still a runtime discovery your user makes, not something any platform checks at install time (missing-dependency-behavior, cross-scope-dependency).

Expect edits to reach the model on the next activation only where something re-reads the file. Claude Code, Copilot CLI, and Antigravity served fresh content after SKILL.md was edited mid-session. On Codex, the model reused the copy already in context on every run and never saw the edit, so freshness there rests on the model choosing to re-read (reactivation-freshness). The same choice sets the reactivation cost: Claude Code and Copilot CLI re-inject the full body on every activation as platform behavior, Antigravity’s model re-read the file in our runs, and Codex’s did not (reactivation-deduplication). Keep the body short enough that a second or third activation is affordable, and when iterating on a skill, start a new session so the edit lands.