Skill Release
Treat every change to a user-managed skill as a release. The local checkout is
the source of truth; GitHub mirrors it. Do not use broad git add, a temporary
clone, or manual git pull/push instead of the helper.
Required workflow
Name the exact top-level skills being released. Keep unrelated edits out of the working tree.
Before editing, run:
cd ~/.codex/skills python3 tools/skill_release.py preflight --skill <skill-name>Proceed only on
READY. It fast-forwards a clean local source automatically. OnBLOCKED, stop and report the reason; never overwrite or reset files.Make the scoped change and run the owning skill's relevant tests/validator.
Release only after fresh verification:
python3 tools/skill_release.py release \ --skill <skill-name> \ --message "type: concise change"For a separately tested candidate tree, let the helper adopt complete folders:
python3 tools/skill_release.py release \ --source-root /path/to/candidate-skills \ --skill <skill-name> \ --message "type: concise change"Call the release complete only when the helper reports
DEPLOYED. This proves a clean localHEADequalsorigin/main.PUBLISH_PENDINGandBLOCKEDare not completion; preserve evidence and request resolution.
Claude symlink guard
Codex reads ~/.codex/skills directly, but Claude only sees a skill once it is
symlinked into ~/.claude/skills. A skill you build but forget to link is
invisible to Claude — the whole effort is wasted until the link exists.
To make that impossible to forget, every successful release and publish
automatically re-checks all source skills and creates or repairs any missing
or broken ~/.claude/skills link, then reports the result under
claude_symlinks in the JSON output. It sweeps the whole skill set, not just the
one you released, so a link missed on an earlier release is caught too. On a
machine with no ~/.claude/skills (e.g. Codex-only) it is a silent no-op
("status": "SKIPPED"). It never deletes a real directory: if a real folder
occupies a skill's name it reports CONFLICT for you to resolve by hand.
Read claude_symlinks in the release output. OK or FIXED is healthy;
CONFLICT needs manual attention.
Run the same check on its own at any time (independent of git):
cd ~/.codex/skills
python3 tools/skill_release.py symlinks # create/repair links, then report
python3 tools/skill_release.py symlinks --check # report only; change nothing
Scope exceptions
For repository-level release tooling or documentation, enumerate every intended
path explicitly with --path; never widen the commit to absorb unrelated work.
Use python3 tools/skill_release.py sync only to fast-forward a clean source
without publishing a change.
Work already committed locally
release stages, commits and pushes in one step, and refuses to start unless the
checkout still mirrors origin. So a skill edit that was already committed — for
instance because a project's own commit protocol asked for a checkpoint first —
cannot go out that way. Publish those commits instead of resetting them or
pushing by hand:
python3 tools/skill_release.py publish
It requires a clean tree that is strictly ahead of origin/main, pushes, and
then proves the same clean-mirror guarantee. DEPLOYED is still the only
completion. Prefer the normal release flow: leave skill edits uncommitted and
let the helper own the commit.