https://github.com/funsaized/docs-to-claude-skills
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.
https://github.com/funsaized/docs-to-claude-skills
agent-skills ai-agents anthropic claude-code claude-skills cli codex llm-tools nodejs npx openai-codex prompt-engineering zero-dependencies
Last synced: about 10 hours ago
JSON representation
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.
- Host: GitHub
- URL: https://github.com/funsaized/docs-to-claude-skills
- Owner: funsaized
- License: mit
- Created: 2026-05-06T14:13:00.000Z (28 days ago)
- Default Branch: main
- Last Pushed: 2026-05-28T09:32:57.000Z (7 days ago)
- Last Synced: 2026-05-28T11:11:26.853Z (6 days ago)
- Topics: agent-skills, ai-agents, anthropic, claude-code, claude-skills, cli, codex, llm-tools, nodejs, npx, openai-codex, prompt-engineering, zero-dependencies
- Language: JavaScript
- Homepage:
- Size: 32.2 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# docs-to-claude-skills
[](https://www.npmjs.com/package/docs-to-claude-skills)
[](https://www.npmjs.com/package/docs-to-claude-skills)
[](./LICENSE)
[](https://nodejs.org)
> 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](https://docs.claude.com/en/docs/claude-code/skills)
and [OpenAI Codex skills](https://developers.openai.com/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:
- **Zero runtime dependencies** — no dependency tree to audit, pin, or patch.
- **Local-only execution** — reads markdown from your repo and writes symlinks
or copies under `.claude/skills/` and `.agents/skills/`.
- **No network calls, telemetry, or remote services** in the generator itself.
---
## Why this exists
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//` | `.agents/skills//` |
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.
---
## Install
Published on npm: [`docs-to-claude-skills`](https://www.npmjs.com/package/docs-to-claude-skills).
Zero runtime dependencies.
```bash
# 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-skills
```
Requires Node.js ≥ 18.
## Quick start
```bash
# 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-skills
```
That's it. Re-run `npx docs-to-skills` anytime you add or edit a doc.
## Running from source
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.
### Option A: one-shot via npx (no clone)
```bash
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.
### Option B: clone + run
```bash
git clone https://github.com/funsaized/docs-to-claude-skills.git
cd docs-to-claude-skills
node bin/docs-to-skills.mjs --help
```
Use the `--cwd` flag to target any other project from the clone:
```bash
node /path/to/docs-to-claude-skills/bin/docs-to-skills.mjs --cwd ~/my-project
```
This is handy when you're hacking on the tool itself and want to try changes
against a real repo without publishing.
### Option C: clone + npm link (global `docs-to-skills`)
```bash
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-skills
```
Edits inside the clone are picked up immediately on the next invocation —
no rebuild step (the source is plain ESM `.mjs`, no compile).
### Running tests
```bash
npm test
```
15 tests under `test/`, all using Node's built-in test runner. No deps to
install.
## Authoring a skill
Drop a markdown file in `docs/` with YAML frontmatter:
```markdown
---
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 `
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.md`
The `description` is what each runtime uses to decide *when* to activate the
skill. Be concrete with keywords your team actually says.
---
## Adopting in an existing project
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:
```bash
npm install --save-dev docs-to-claude-skills
```
**Step 2.** Pick the docs you want exposed as skills and add frontmatter to
the top of each one:
```diff
+---
+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`:
```json
{
"scripts": {
"skills": "docs-to-skills"
}
}
```
**Step 4.** Ignore the generated directories (they're symlinks, regeneratable):
```gitignore
.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:
```bash
npm run skills
```
Wire it into a `postinstall` or pre-commit hook if you want it always fresh:
```json
{
"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.
---
## CLI
```
docs-to-skills [command] [options]
commands
generate generate skills (default)
init scaffold docs/example.md
options
--docs source docs directory (default: ./docs)
--target claude | codex | both (default: both)
--mode symlink | copy (default: symlink)
--clean remove all managed skills before regenerating
--dry-run preview actions without modifying anything
--quiet suppress per-file output
--cwd project root (default: process.cwd())
-h, --help
```
### Targeting one runtime
```bash
docs-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)
```
### Copy instead of symlink
Useful on Windows without developer mode, on filesystems that disallow
symlinks, or when you want to commit the resulting `SKILL.md` files
verbatim:
```bash
docs-to-skills --mode copy
```
Symlink mode is the default and falls back to copy automatically if symlink
creation is denied (`EPERM`/`EACCES`).
### Cleaning up
```bash
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.
---
## Programmatic API
```js
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 } | null`
- `isValidSkillFrontmatter(data)` → `boolean`
- `TARGETS` → metadata for the supported runtimes
- `resolveTargets(input)` → normalize a target arg
- `targetSkillsDir(cwd, targetId)` → resolve the output directory
---
## How it works
1. Scan `docs/*.md`.
2. Parse YAML frontmatter; require `name` and `description`.
3. For each target runtime, ensure `//SKILL.md` is a symlink
pointing to the source doc. If one exists with the right target, leave it
(no churn). If wrong, replace it.
4. Prune stale entries — but **only** entries whose `SKILL.md` symlink resolves
into 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/`.
---
## FAQ
**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.
---
## Prior art / acknowledgments
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.
## License
MIT © funsaized