Constructdocs
section · decisions

0013 Skills On Disk Layout

2 min read·decisions / adr / 0013-skills-on-disk-layout

ADR 0013: Skills on-disk layout

Date: 2026-05-27 Status: Accepted Deciders: Construct·Engineer


Context

Skills live under skills/\<category>/\<name>.md as plain markdown files. As Construct has expanded to support multiple agent runtimes (Claude Code, Codex, OpenCode, Copilot), a cross-tool standard has emerged: the SKILL.md directory format. In this format a skill is a directory \<name>/ that contains a SKILL.md file and may contain additional artifacts (scripts, fixtures, tests).

Two problems existed before this decision:

  1. Skills were only synced to .claude/skills/ during construct sync. Codex agents at $HOME/.agents/ had no access to the same skills.
  2. The flat \<name>.md form prevents a skill from bundling any supporting files alongside its documentation.

Decision

Source of truth stays at skills/

The canonical skill files are skills/\<cat>/\<name>.md (existing) or skills/\<cat>/\<name>/SKILL.md (new directory form). Neither .claude/skills/ nor .agents/skills/ is a source of truth. Both are derived sync targets and must never be hand-edited.

SKILL.md is the cross-tool standard

New skills should use the directory form (skills/\<cat>/\<name>/SKILL.md). Existing flat files (skills/\<cat>/\<name>.md) remain valid for one minor release. The migration script scripts/migrate-skills-to-skill-md.mjs converts them on demand with --apply.

Both .claude/skills/ and .agents/skills/ are sync targets

construct sync writes each skill to:

  • ~/.claude/skills/\<cat>/\<name>/SKILL.md
  • ~/.agents/skills/\<cat>/\<name>/SKILL.md

Both targets receive identical content prepended with a # Generated by construct sync header. The header is the canonical marker that a file was produced by sync and should not be edited in place.

Loader falls back to flat form for one minor release

lib/mcp/tools/skills.mjs resolves a skill id by checking candidates in order:

  1. skills/\<path>.md (existing flat form)
  2. skills/\<path>/SKILL.md (new directory form)

The first path that exists wins. This fallback is removed in the next minor release after the migration script has been run.

This decision does not relocate the source of truth

Skills stay under skills/ in the Construct repository. Moving source files to .claude/skills/ or .agents/skills/ would invert the sync direction and break the "derived targets are never hand-edited" invariant.

Consequences

Positive

  • Skills are available to all supported runtimes after a single construct sync
  • The directory form lets a skill bundle scripts or fixtures alongside its docs
  • A single migration script handles the cut-over safely and idempotently
  • The fallback loader means no agent breaks on the first day of rollout

Negative

  • Two on-disk representations exist during the transition window
  • audit-skills.mjs and validators/skills.mjs must eventually be updated to understand the directory form (tracked as a follow-up)

Mitigation

  • scripts/migrate-skills-to-skill-md.mjs --dry-run makes the transition scope visible before any files are touched
  • The fallback in the loader is explicitly temporary; its removal is a named gate in the next minor release
  • Sync targets are gitignored in user home directories and regenerated on every construct sync, so a bad write is always recoverable