Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@brianlovin/notion-skills) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
notion-skills
Sync agent skills from a Notion database to Claude Code, Codex, OpenCode, Cursor, and Gemini CLI.
What is this?
Modern AI coding agents (Claude Code, Codex, OpenCode, Cursor, Gemini CLI) all read skills — directories with a SKILL.md file that tells the agent what to do and when to do it. They all use the same convention but each looks in a different folder, and authoring skills as files in your ~/.claude/skills/ directory means using a code editor + git for what's basically content management.
notion-skills lets your team author skills as rows in a Notion database, then syncs them down to whichever agent CLIs you use:
- ✏️ Author in Notion's UI — page title is the skill name, properties map to frontmatter, page body is the SKILL.md content. No git, no markdown editor, no PR review.
- 👥 Share across a team — point teammates at the same Notion DB; each runs
syncto get the same skills. - 🎯 Multi-agent — one source of truth, fan out to every agent CLI you use. Skills land via symlinks so an edit in Notion updates every CLI on the next sync.
- 🔍 Selectively sync — tag-based filtering means a 200-skill team DB can hand each engineer just the 30 they care about.
Prerequisites
You need three things before installing:
- macOS or Linux. Windows isn't supported yet (symlinks need admin/dev mode).
- Node.js 18+. Check with
node --version. ntn0.12 or newer +ntn login. This is Notion's official CLI;notion-skillspiggybacks on it for all API access (no separate OAuth flow, no integration to register).
Install and authenticate ntn
# Install ntn (one of):
brew install ntn
# or download from https://github.com/makenotion/ntn-cli
# Verify version
ntn --version
# → ntn 0.12.0 (or newer)
# Log in to your Notion workspace
ntn login
# Confirm everything's wired up
ntn doctor
# → CLI version ✔
# → Default workspace ✔
# → Token valid ✔If ntn doctor is green, you're ready.
Install
npm install -g @brianlovin/notion-skills
notion-skills --version
# → 0.1.0Quick start
The fastest path from zero to skills syncing in under five minutes:
# 1. Install ntn + log in (see Prerequisites)
brew install ntn && ntn login
# 2. Install notion-skills
npm install -g @brianlovin/notion-skills
# 3. Run the wizard — it does everything
notion-skills initinit is a guided wizard. It asks:
- Scope — global (per-machine, syncs to
~/.claude/skills/etc.) or project (per-repo, syncs to<repo>/.claude/skills/). - Database — paste the URL of an existing Notion database, or create a fresh one under a parent page.
- Schema upgrade — auto-runs if your DB is missing the properties skill spec needs.
- Targets — which agent CLIs to sync to (Claude Code, Codex, OpenCode, Cursor, Gemini).
- Tag filter — optional. Pick include/exclude tags so you only get the skills you care about.
- Migrate locals — if you already have skills in
~/.claude/skills/, it offers to push them up to Notion. - First sync — pulls everything down as symlinks.
Now you can:
- Edit skills in Notion's UI.
- Run
notion-skills syncto pick up changes. - Type
/skill-namein any of your agent CLIs to use them.
What's a "skill"?
A skill is a directory containing a SKILL.md file. The frontmatter tells the agent CLI what the skill does and when to use it; the body is the content the agent reads when invoked.
---
name: deslop
description: Remove AI-generated code slop from the current branch. Use after writing code to clean up unnecessary comments, defensive checks, and inconsistent style.
---
# Remove AI code slop
Check the diff against main and remove all AI-generated slop introduced in this branch...In Notion, that becomes a database row:
- Page title:
deslop - Description property: the one-liner that goes in the frontmatter
- Page body: the markdown content
notion-skills sync reads each row and writes a SKILL.md to your central store, then symlinks it into every target CLI's directory.
Commands
| Command | What it does |
|---|---|
notion-skills init |
Guided wizard for first-time setup. |
notion-skills sync [names…] |
Pull pages, write skills, reconcile target dirs. Skips unchanged pages. |
notion-skills status |
Show auth, scope, filter, per-target symlink health. |
notion-skills doctor [--fix] |
Inspect for drift; safe auto-repairs with --fix. |
notion-skills list |
Print every page in the DB with status: ✓ synced / ✗ filtered / ○ available / ! invalid. |
notion-skills upgrade |
Add any missing skill-spec properties to your Notion DB schema. |
notion-skills migrate [--from <path>] [--overwrite] [--dry-run] |
Push existing local skills into Notion, sync back as symlinks. |
notion-skills tags |
Interactive include/exclude tag filter editor. |
notion-skills login / logout |
Thin wrappers over ntn login / ntn logout. |
Run any command with --help for full options.
init — first-time setup
notion-skills init # auto-detect scope (project if found, else global)
notion-skills init --global # force global scope (~/.notion-skills/scope.json)
notion-skills init --project # force project scope (./notion-skills.json)sync — pull skills from Notion
notion-skills sync # sync the active scope
notion-skills sync docker terraform # one-off: force-include these skills for this run
notion-skills sync --global # sync the global scope explicitly
notion-skills sync --project # sync the project scope explicitly
notion-skills sync --all # sync both global and project (rare)sync is incremental — it only re-fetches pages whose last_edited_time or properties have changed since the last sync.
migrate — move existing skills into Notion
If you already have skills authored on disk:
notion-skills migrate # scans your scope's target dirs
notion-skills migrate --from ~/Developer/skill-repo # plus an extra source
notion-skills migrate --overwrite # replace existing Notion pages
notion-skills migrate --dry-run # preview, don't write anything
notion-skills migrate -y # skip confirmationmigrate writes Notion pages first; only after every page is created does it move local copies to a backup at ~/.notion-skills/backup/migrate-<timestamp>/. A failure mid-flight leaves locals untouched.
doctor — diagnose drift
notion-skills doctor # read-only: prints status of every check
notion-skills doctor --fix # auto-fix safe issues (interactive y/n per fix)Checks: ntn install + auth, scope existence, schema match, manifest vs central-store consistency, per-target symlink health.
Concepts
Two scopes
Global scope is per-machine. State lives at ~/.notion-skills/ and syncs to your home-dir agent paths (~/.claude/skills/, ~/.codex/skills/, etc.). Configured via notion-skills init (default).
Project scope is per-repo. State is split:
<repo>/.notion-skills.json— committable config (database ID, filter)<repo>/.notion-skills.lock— local sync manifest (gitignore me)<repo>/.claude/skills/<name>/— generated skills (gitignore me)
Use project scope to share a fixed skill set across a team via the repo. Configured via notion-skills init --project.
Five supported agents
| Agent | Skills directory |
|---|---|
| Claude Code | ~/.claude/skills/ |
| Codex CLI | ~/.codex/skills/ |
| OpenCode | ~/.config/opencode/skills/ |
| Cursor | ~/.cursor/skills/ |
| Gemini CLI | ~/.gemini/skills/ |
Pick any combination during init. Adding a new agent is one entry in src/known-targets.ts — PRs welcome.
Filtering — only the skills you care about
A team's Notion DB might have hundreds of skills. Edit ~/.notion-skills/scope.json to filter:
{
"filter": {
"include_tags": ["frontend", "tooling"],
"exclude_tags": ["legacy"],
"include_skills": ["docker"], // always include, regardless of tags
"exclude_skills": ["broken"] // always exclude
}
}Resolution order: exclude_skills → include_skills → include_tags → exclude_tags → keep.
Or use the interactive editor:
notion-skills tagsSchema
init and upgrade provision/maintain these Notion database properties. You don't author them by hand.
| Property | Frontmatter key | Type |
|---|---|---|
Name |
name (slugified from title) |
title |
Description |
description |
rich_text |
When To Use |
when_to_use |
rich_text |
Argument Hint |
argument-hint |
rich_text |
Arguments |
arguments |
rich_text (space-sep) |
Allowed Tools |
allowed-tools |
rich_text (space-sep, paren-aware) |
Paths |
paths |
rich_text (comma-sep) |
Disable Model Invocation |
disable-model-invocation |
select (default/true/false) |
User Invocable |
user-invocable |
select (default/true/false) |
Model |
model |
select (self-healing) |
Effort |
effort |
select |
Context |
context |
select |
Agent |
agent |
select (self-healing) |
Shell |
shell |
select |
Tags |
(internal — used for filtering) | multi_select |
Self-healing selects (Model, Agent) auto-add new options when migrate encounters them — so you can use agent: my-custom-subagent without pre-registering the option.
Spec defaults for Disable Model Invocation, User Invocable, Shell, etc. are encoded as a default option. Empty cells also count as default — both omit the frontmatter key when syncing back to disk.
Common workflows
Adding a new skill
- In Notion, add a row to your skills DB.
- Set
Name(becomes the slug),Description(the when-to-use hint), and any other properties you care about. - Write the skill instructions in the page body.
- Run
notion-skills sync(or wait until your next sync).
Editing a skill
- Edit the page in Notion.
- Run
notion-skills sync.
sync is incremental — only edited pages are re-fetched.
Sharing a curated skill set with a team via a repo
cd my-team-repo
notion-skills init --project
# pick the team's Notion DB
# pick targets and tags
# config gets written to ./.notion-skills.json
git add .notion-skills.json
echo ".notion-skills.lock" >> .gitignore
echo ".claude/skills/" >> .gitignore
git commit -m "Configure notion-skills"Teammates clone the repo and run notion-skills sync — they get the same skill set under <repo>/.claude/skills/.
Migrating from ~/.claude/skills/ files
If you've been authoring skills as files (or symlinks from a shared repo like agent-config), upload them into Notion in one shot:
notion-skills migrate # scan your scope's target dirs
notion-skills migrate --from ~/Developer/agents # plus a custom pathLocals are moved to ~/.notion-skills/backup/migrate-<ts>/ after Notion confirms each write. The next sync re-creates them as symlinks pointing at your central store.
Files this CLI touches
~/.notion-skills/
├── scope.json # global: db, targets, filter
├── manifest.json # global sync state (atomic writes)
├── skills/<name>/ # global central source-of-truth
└── backup/migrate-<ts>/ # local copies displaced during migrate
~/.claude/skills/<name> → symlink → ~/.notion-skills/skills/<name>
~/.codex/skills/<name> → symlink → ~/.notion-skills/skills/<name>
~/.cursor/skills/<name> → symlink → ~/.notion-skills/skills/<name>
~/.config/opencode/skills/<name> → symlink → ~/.notion-skills/skills/<name>
~/.gemini/skills/<name> → symlink → ~/.notion-skills/skills/<name>
<repo>/.notion-skills.json # project: committable scope config
<repo>/.notion-skills.lock # project sync state (gitignore me)
<repo>/.claude/skills/<name>/ # project skills (gitignore me)Auth lives in ntn's store (OS keychain by default). rm -rf ~/.notion-skills wipes notion-skills state without affecting auth.
Troubleshooting
notion-skills doctor is the first stop. It reports status across ntn auth, scope, schema, manifest consistency, and symlink health.
Common errors
Errors print a one-line summary plus a suggested next command. The most common cases:
| Error | Fix |
|---|---|
| "Notion auth has expired" | ntn login |
| "Schema doesn't match" | notion-skills upgrade |
| "isn't configured yet" | notion-skills init |
| "Could not find database" | Check the URL/ID; ensure ntn is in the right workspace (ntn doctor). |
| "ntn is too old" | ntn update |
| "Couldn't reach the Notion API" | Check your network. |
Resetting from scratch
# Wipe all notion-skills local state (keeps auth and your Notion DB intact)
rm -rf ~/.notion-skills
notion-skills initRestoring a migrate backup
migrate moves originals to ~/.notion-skills/backup/migrate-<ts>/. To restore:
ls ~/.notion-skills/backup/
# pick the timestamp you want to restore from
mv ~/.notion-skills/backup/migrate-<ts>/<skill-name> ~/.claude/skills/Limitations
- macOS and Linux only. Windows symlink support is on the list.
- Round-trip normalisation. Notion's markdown parser normalises some content on ingest:
- YAML wraps long descriptions across lines
- Multi-line markdown paragraphs become separate Notion blocks
- Code-language aliases get expanded (
ts→typescript) - Table separators get standardised
- Bare domains (
example.com) get auto-linked
- Performance. Each Notion call shells out to
ntn, which adds ~50–100ms per call. A sync of 100 skills with deeply-nested blocks takes a few minutes. Subsequent syncs are fast (incremental). - Auth scope.
notion-skillssees whateverntnis logged into. Switch workspaces withntn login.
Contributing
git clone https://github.com/brianlovin/notion-skills
cd notion-skills
npm install
npm run build
npm test # 105 tests
npm link # use the local build globallySource layout:
src/cli.ts— commander entry pointsrc/commands/— one file per CLI subcommandsrc/notion.ts— Notion API client (shells out tontn)src/sync.ts,src/migrate.ts— pure logic; importable from anywheresrc/schema.ts— single source of truth for the property → frontmatter mappingsrc/known-targets.ts— the registry of supported agent CLIssrc/errors.ts— friendly error translator
Adding a new agent: append a TargetDef to KNOWN_TARGETS in src/known-targets.ts. Tests in test/known-targets.test.mjs will pin the change.
License
MIT