Author your project's agent skills as plain markdown in docs/, and have them materialize as both Claude Code skills and OpenAI Codex skills kept in sync automatically via symlinks.
SaferSkills independently audited docs-to-claude-skills (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
One markdown file. Two AI agents. Zero dependencies. Zero duplication.
Author your team's agent skills as plain markdown anywhere under docs/, and have them materialize as both Claude Code skills and OpenAI Codex skills — kept in sync automatically via symlinks.
docs/database.md ──┬──▶ .claude/skills/database/SKILL.md (Claude Code)
└──▶ .agents/skills/database/SKILL.md (OpenAI Codex)Edit the doc once, both agents see the change. No duplicate copies, no "which version is current" confusion.
Security-conscious by default:
or copies under .claude/skills/ and .agents/skills/.
Claude Code and OpenAI Codex agree on the SKILL.md contract:
| Field | Claude Code | OpenAI Codex |
|---|---|---|
| File | SKILL.md | SKILL.md |
| Required metadata | name, description (frontmatter) | name, description (frontmatter) |
| Repo location | .claude/skills/<name>/ | .agents/skills/<name>/ |
Same file, two locations. Rather than maintain duplicates, keep the canonical content in docs/ and let this tool wire up the symlinks. Your existing repo documentation becomes your skill library.
Published on npm: docs-to-claude-skills. Zero runtime dependencies.
# project-local (recommended)
npm install --save-dev docs-to-claude-skills
# or with your package manager of choice
pnpm add -D docs-to-claude-skills
yarn add -D docs-to-claude-skills
bun add -d docs-to-claude-skills
# or one-shot, no install
npx docs-to-claude-skills
# or globally
npm install -g docs-to-claude-skillsRequires Node.js ≥ 18.
# 1. install (or use npx)
npm install --save-dev docs-to-claude-skills
# 2. scaffold a starter doc
npx docs-to-skills init
# 3. generate skills for both Claude Code and Codex
npx docs-to-skillsThat's it. Re-run npx docs-to-skills anytime you add or edit a doc.
You don't need to install from npm — the tool has zero runtime dependencies, so a clone or a direct npx from GitHub is enough.
npx github:funsaized/docs-to-claude-skills --cwd .npx fetches the repo, runs the bin, and cleans up. Good for trying it out or wiring into CI without committing a dependency.
git clone https://github.com/funsaized/docs-to-claude-skills.git
cd docs-to-claude-skills
node bin/docs-to-skills.mjs --helpUse the --cwd flag to target any other project from the clone:
node /path/to/docs-to-claude-skills/bin/docs-to-skills.mjs --cwd ~/my-projectThis is handy when you're hacking on the tool itself and want to try changes against a real repo without publishing.
docs-to-skills)git clone https://github.com/funsaized/docs-to-claude-skills.git
cd docs-to-claude-skills
npm link
# now available globally, pointing at your clone
cd ~/my-project
docs-to-skillsEdits inside the clone are picked up immediately on the next invocation — no rebuild step (the source is plain ESM .mjs, no compile).
npm test15 tests under test/, all using Node's built-in test runner. No deps to install.
Drop a markdown file in docs/ with YAML frontmatter:
---
name: postgres-migrations
description: Use when the user asks to add, run, or rollback a database migration. Triggers on "migration", "drizzle", "db:migrate", schema changes.
---
# Postgres migrations
Workflow:
1. Edit `src/database/schema.ts`
2. Run `bun db:add-migration <name>`
3. Run `bun db:migrate`
...Run docs-to-skills and it shows up at:
.claude/skills/postgres-migrations/SKILL.md.agents/skills/postgres-migrations/SKILL.mdThe description is what each runtime uses to decide when to activate the skill. Be concrete with keywords your team actually says.
Got a repo with a docs/ folder full of architecture notes, runbooks, and how-tos? Most of them already make great agent skills — they just need frontmatter.
Step 1. Add a single dev dependency:
npm install --save-dev docs-to-claude-skillsStep 2. Pick the docs you want exposed as skills and add frontmatter to the top of each one:
+---
+name: deploy-staging
+description: Use when deploying to staging, debugging deploys, or asked about the staging release process.
+---
# Deploying to staging
...Files without frontmatter are quietly skipped, so you can roll this out incrementally. Start with two or three high-value docs; add more as you go.
Step 3. Add a script to package.json:
{
"scripts": {
"skills": "docs-to-skills"
}
}Step 4. Ignore the generated directories (they're symlinks, regeneratable):
.claude/skills/
.agents/skills/Or commit them — your call. Symlinks are version-controlled fine on macOS and Linux. On Windows, prefer --mode copy and commit the result.
Step 5. Run it locally and in CI:
npm run skillsWire it into a postinstall or pre-commit hook if you want it always fresh:
{
"scripts": {
"postinstall": "docs-to-skills --quiet"
}
}That's the whole adoption path. Existing docs keep working as docs; the ones with frontmatter additionally become skills.
docs-to-skills [command] [options]
commands
generate generate skills (default)
init scaffold docs/example.md
options
--docs <dir> source docs directory (default: ./docs)
--target <t> claude | codex | both (default: both)
--mode <m> symlink | copy (default: symlink)
--clean remove all managed skills before regenerating
--dry-run preview actions without modifying anything
--quiet suppress per-file output
--cwd <dir> project root (default: process.cwd())
-h, --helpdocs-to-skills --target claude # only .claude/skills/
docs-to-skills --target codex # only .agents/skills/
docs-to-skills --target claude,codex # both (same as --target both)Useful on Windows without developer mode, on filesystems that disallow symlinks, or when you want to commit the resulting SKILL.md files verbatim:
docs-to-skills --mode copySymlink mode is the default and falls back to copy automatically if symlink creation is denied (EPERM/EACCES).
docs-to-skills --clean # nuke and rebuild--clean only touches skills whose SKILL.md is a symlink pointing into your docs/ directory — hand-written or third-party skills under .claude/skills/ and .agents/skills/ are left alone.
import { generateSkills } from 'docs-to-claude-skills'
const stats = await generateSkills({
cwd: process.cwd(),
docsDir: 'docs',
targets: ['claude', 'codex'],
mode: 'symlink',
clean: false,
dryRun: false,
})
console.log(stats)
// { created: 4, updated: 0, unchanged: 0, skipped: 1, removed: 0, actions: [...] }Other exports:
parseFrontmatter(content) → { data, body, raw } | nullisValidSkillFrontmatter(data) → booleanTARGETS → metadata for the supported runtimesresolveTargets(input) → normalize a target argtargetSkillsDir(cwd, targetId) → resolve the output directorydocs/*.md.name and description.<target-dir>/<name>/SKILL.md is a symlinkpointing to the source doc. If one exists with the right target, leave it (no churn). If wrong, replace it.
SKILL.md symlink resolvesinto your docs/ directory. Anything else is left alone.
The symlink-only-prune rule is what makes this safe to run alongside hand-authored skills. Your agent-creator skill from another plugin won't get nuked because its SKILL.md doesn't link into docs/.
Why symlinks? A copy means you have two sources of truth and one will go stale. A symlink means edits to docs/database.md are instantly visible to the agent the next time it loads the skill. Use --mode copy if your filesystem or VCS workflow needs literal files.
Will the agent auto-detect new skills? Both Claude Code and Codex scan their skills directories on session start; some pick up changes without a restart, some don't. If a new skill doesn't show up, restart the session.
Can the same doc be a skill in one runtime but not the other? Not via this tool. The contract is identical between Claude Code and Codex; if you want runtime-specific instructions, write two docs.
Does it support nested skill assets (`scripts/`, `references/`)? Not yet. Today each skill is a single SKILL.md. The directory structure is in place, so adding sibling files is a small extension.
Why not just publish a package and `import` skills? Skills are filesystem artifacts — agents discover them by scanning conventional paths. This tool just maintains those paths from a single source.
The single-source-of-truth pattern with symlink-into-docs is taken from the Tamagui Takeout starter kit's tko skills generate command. This is a generalized, dependency-free re-implementation that also targets OpenAI Codex.
MIT © funsaized
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.