One source of truth for all your coding agents.
Skills, subagents, slash commands, MCP servers, hooks — curated once in a single repo you own, then projected into every coding agent on your machine: Claude Code, OpenAI Codex, GitHub Copilot CLI, OpenCode, Pi, and VS Code.
npx osprey-cli init
Every coding agent invents its own config layout: ~/.claude/skills,
~/.codex/config.toml, ~/.copilot/mcp-config.json, .agent.md here, TOML
there. Keeping five agents' skills, subagents, and MCP servers in sync by hand
doesn't scale past day one — and loading everything into every session burns
your context window.
osprey gives you:
- A library, a switchboard, and a runtime. Your
assets/folder holds every skill/agent/command you've ever collected (the library).registry/active.jsonnames the curated active subset (the switchboard).osprey syncprojects only the active set into each agent home (the runtime) — selective symlinks, so one edit in your repo applies everywhere instantly, and inactive assets cost zero tokens. - Format translation where formats differ. SKILL.md is a shared standard, so
skills symlink everywhere. Subagents are rendered per runtime: Claude-style
.md, Copilot.agent.md, Codex.toml. MCP servers live in one canonicalmcp.jsonand are rendered + merged into each agent's native config — add-only by default, your hand-written servers are never touched. - Safety as a default. Every command is a dry-run until
--apply. Every file osprey replaces gets a timestamped backup beside it. Files you edited by hand are never deleted.osprey doctoraudits the whole setup read-only.
# one-shot, no install
npx osprey-cli init
# or in a clone of your osprey repo
npm install && npm run build && node dist/cli.js initThe public osprey repo is a starter: the CLI plus a seed asset library. Your customizations belong in a private mirror (GitHub forks of public repos are always public, so mirror instead):
git clone https://github.com/<public>/osprey.git my-agent-stack
cd my-agent-stack
gh repo create <you>/my-agent-stack --private --source . --push
git remote rename origin upstream # public repo becomes upstream
gh repo set-default <you>/my-agent-stack
npx osprey-cli init # detect agents, seed registryFrom then on:
- your skills/agents/commands/MCP config live in your private repo
osprey updatefetches the public repo's improvements (CLI, starter assets) and merges them under your customizationsosprey sync --applyrolls any change out to every managed agent
| Command | What it does |
|---|---|
osprey init |
Interactive: choose the save location, detect agents, pick targets, symlink vs copy, seed registry, git init + optional private GitHub repo |
osprey import [--from <dir>] [--apply] |
Pull your EXISTING world in: every live agent's MCP servers (unioned, conflicts reported), skills/agents/commands (symlinks resolved to their real sources), plus any legacy workspace via --from. What's live becomes the active set. --prefer theirs lets live sources refresh stale library copies (with backups) |
osprey status |
Detected agents, managed targets, active asset counts, git-based out-of-sync state |
osprey list [class] |
Library vs active view for agents/skills/commands/hooks |
osprey add <class> <id> |
Activate a library asset |
osprey remove <class> <id> |
Deactivate (library keeps the source) |
osprey sync [--apply] [--target <id>] |
Project active set into agent homes (dry-run by default) |
osprey doctor [--json] |
Read-only health check: registry, symlinks (including legacy links into old workspaces), MCP configs, cruft |
osprey update |
Merge public-repo improvements into your private mirror |
If your agent homes already symlink into an old hand-rolled workspace:
osprey import --from /path/to/old-workspace --prefer theirs # review the dry-run
osprey import --from /path/to/old-workspace --prefer theirs --apply
osprey sync --apply # repoints every agent home at THIS workspace (backups kept)
osprey doctor # flags anything still referencing the old workspaceAfter doctor is clean, the old workspace has no live references and can be
archived. Every dir osprey replaced sits beside its original as a
.backup-<ts> / .wholesale-backup-<ts> sibling until you delete it.
osprey records the git commit + dirty state at every sync --apply
(.osprey/state.json). osprey status compares that snapshot to the current
repo: new commits or uncommitted asset changes ⇒ "out of sync — run
osprey sync --apply". Not a git repo ⇒ tracking disabled (init offers to fix).
Every target ships with built-in surface links (see the matrix below): whenever
the matching assets/ source exists, osprey sync projects it into the agent
home — rules, hooks, plugins, workflows, global instructions, the lot. No
configuration needed; missing sources are skipped silently.
To override a default (or add a surface osprey doesn't know about), give the
target an extraLinks entry — same home path wins over the built-in:
Re-running osprey init preserves extraLinks; unpicked targets are kept but
disabled.
Secrets:
osprey importcopies MCP env values verbatim intoassets/mcp/mcp.json, which is git-tracked. Before pushing anywhere, replace literal keys with${ENV_VAR}references and export the real values in your shell profile.
osprey.json # which agents are managed, symlink/copy mode (tracked)
registry/active.json # the curated ACTIVE set (tracked)
assets/
skills/<id>/SKILL.md # shared skill standard — symlinked everywhere (tracked)
agents/<id>.md # Claude-style source of truth — rendered per target
commands/*.md # slash commands (wholesale symlink)
hooks/ # hook packages (roadmap: settings.json merge)
mcp/mcp.json # canonical MCP servers (Claude-native shape)
.osprey/state.json # what osprey deployed where (untracked)
| skills | subagents | commands | rules / instructions | hooks | plugins | mcp | |
|---|---|---|---|---|---|---|---|
| claude | symlink | symlink (.md) |
symlink commands/ |
rules/, AGENTS.md, CLAUDE.md |
symlink hooks/ |
symlink plugins/ (native marketplace layout) |
merge ~/.claude/mcp/mcp.json |
| codex | symlink | render .toml |
symlink prompts/ (flat *.md) |
AGENTS.md (~/.codex/rules/ is Starlark execpolicy — never linked) |
symlink hooks/ scripts dir (hooks.json stays user-authored) |
codex plugin CLI + config.toml; cache not symlinkable |
merge ~/.codex/config.toml |
| copilot | symlink | render .agent.md |
— (no user command dir) | copilot-instructions.md → AGENTS.md, symlink instructions/ |
per-file links: hooks/*.json (user hook files preserved) |
copilot plugin install → installed-plugins/; not symlinkable |
merge ~/.copilot/mcp-config.json |
| opencode | symlink (also auto-reads ~/.claude/skills) |
symlink (.md) |
symlink commands/ |
AGENTS.md + rules/*.md merged into the instructions config array |
— | JS/TS plugin system — Claude-style plugins incompatible, never linked | merge opencode.jsonc |
| pi | symlink | symlink (.md) |
symlink commands/ |
AGENTS.md |
— | — | merge ~/.pi/agent/mcp.json |
| vscode | — | — | — | per-file links: instructions/*.instructions.md → User/prompts/ |
— | Extensions view (@agentPlugins), VS Code-managed |
merge user mcp.json |
Claude also gets its extended surfaces wholesale: workflows/, scripts/,
extensions/, plans/, context-mode/.
Plugins are deliberately NOT one-size-fits-all: only Claude Code loads a
plugins directory osprey can own via symlink. Codex and Copilot CLI manage
plugin installs through their own CLIs (both can point at a local marketplace,
so the workspace's assets/plugins/ marketplaces remain the shared source),
OpenCode plugins are JS modules with an incompatible format, and VS Code
installs them as extensions.
MCP quirks are handled per target: env-var secret syntax (${VAR} vs
{env:VAR} vs raw name), argv merging for OpenCode, remote-server dropping for
stdio-only Pi, streamable_http for Codex. Anything a target can't express is
reported, never silently lost.
osprey import— scan live agent homes and pull existing configs into the workspace (union + conflict report; the Python reference inassets/scripts/already proves the approach)- hooks/settings.json merge for Claude Code hook packages
- per-project scope (
.claude/,.github/) alongside user scope - usage audit: mine session transcripts to suggest what to activate/deactivate
npm install
npm run build # tsc -> dist/
npm test # vitest (tests/, sandboxed — never touches your real homes)The Python scripts in assets/scripts/ are the proven reference implementation
this CLI was ported from; assets/docs/ documents each agent's config surface.