Skip to content

Skills format

A skill is a markdown file with a YAML frontmatter header. This page is the formal spec. For the broader picture, see Skills system.

---
name: <slug>
description: <one-line summary>
triggers:
- <keyword>
- <keyword>
engine: <unity | godot | web> # optional
engine_version: <constraint> # optional
version: "<semver string>" # optional
always_on: <true | false> # optional, default false
---
<markdown body>

The --- lines delimit the YAML block. Everything after the second --- is the skill body that gets injected into the agent’s developer instructions when the skill matches.

A unique slug. The filename should match (unity.mdname: unity). Used for the Settings → Skills list and as the directory name for auto-skills.

Required.

One-line summary. Shown in the skills manifest the agent always sees, even when no triggers fire. Make it specific so the agent knows what’s in the body without loading it.

Required.

Array of strings. The agent’s prompt and active file are scanned for case-insensitive matches against any trigger. A single match fires the skill. An empty array (triggers: []) means the skill never fires on triggers; combine with always_on: true for skills that always inject.

Required field, but the array can be empty.

One of unity, godot, web. Restricts the skill to projects in that engine mode. Skills without an engine field fire in any project type.

Optional.

Pairs with engine. Version constraint string. Supported formats:

  • >=4.5: this version or newer.
  • <6: older than this version.
  • ==4.5: exactly this version.
  • 4.5: bare version, treated as ==4.5.

If the project’s engine version can’t be parsed, the constraint fails open (the skill still fires) so skills don’t silently disappear on unusual builds.

Optional. Ignored if engine is not set.

Skill content version. When this bumps, factory skills overwrite their on-disk copy on the next launch. Auto-skills track version through the auto/<name>/v<n>.md directory layout instead of this field.

Use a string ("1.0", "2.1"). Numeric values work but YAML may interpret them surprisingly.

Optional. Defaults to "1.0" for matching purposes.

Boolean. When true, the skill body is injected on every turn, regardless of triggers. Use sparingly. The two factory always-ons are forge-self (Forge’s identity and conventions) and windows-environment (OS-specific guidance).

Optional. Defaults to false.

Plain markdown. No length cap, but every word goes into the developer instructions on every matching turn, so be terse. Aim for under 500 lines. Reference external docs for things the agent can look up itself.

Headings, code blocks, lists, and tables all render correctly in the agent’s context. Inline images and link metadata don’t (the agent sees the markdown source, not the rendered HTML).

Auto-skills (those under ~/.forge/skills/auto/<name>/) follow the same format but are stored differently:

  • The latest version lives at ~/.forge/skills/auto/<name>/v<N>.md.
  • A stats.json sidecar tracks currentVersion, invocations, successes, createdAtMs, lastUsedAtMs.
  • The success_rate is successes / invocations. Auto-skills with invocations >= 5 and success_rate < 0.7 are filtered out at trigger-matching time.

The Settings → Skills panel handles version history, promotion (move to flat ~/.forge/skills/<name>.md), and deletion.

For each turn:

  1. Load every skill from ~/.forge/skills/ and ~/.forge/skills/auto/.
  2. For each auto-skill: skip if invocations >= 5 && success_rate < 0.7.
  3. For each skill with engine set: skip if the project’s engine doesn’t match.
  4. For each skill with engine_version set: parse the constraint and skip if the project version doesn’t satisfy it. Fail open on parse errors.
  5. Build the candidate set: skills with always_on: true plus any skill where at least one trigger appears (case-insensitive substring match) in the user’s message or active file path.
  6. Concatenate the bodies of matching skills, joined by blank lines.
  7. The full manifest (name, description for every loaded skill, ignoring filters above) is also included so the agent knows the broader library.

The result is injected into Codex’s developerInstructions parameter at thread start.