Skip to content

w159/osprey

Repository files navigation

🪶 osprey

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

Why

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.json names the curated active subset (the switchboard). osprey sync projects 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 canonical mcp.json and 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 doctor audits the whole setup read-only.

Install

# 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 init

The private-fork model

The 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 registry

From then on:

  • your skills/agents/commands/MCP config live in your private repo
  • osprey update fetches the public repo's improvements (CLI, starter assets) and merges them under your customizations
  • osprey sync --apply rolls any change out to every managed agent

Commands

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

Migrating from an existing setup

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 workspace

After 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.

Change detection

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).

Full-surface defaults + extraLinks overrides

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:

// osprey.json
"targets": {
  "claude": {
    "enabled": true,
    "mode": "symlink",
    "extraLinks": [
      { "home": "rules", "source": "my-other-rules" }   // beats the default assets/rules
    ]
  }
}

Re-running osprey init preserves extraLinks; unpicked targets are kept but disabled.

Secrets: osprey import copies MCP env values verbatim into assets/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.

Layout

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)

Per-target support matrix

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.mdAGENTS.md, symlink instructions/ per-file links: hooks/*.json (user hook files preserved) copilot plugin installinstalled-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.mdUser/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.

Roadmap

  • osprey import — scan live agent homes and pull existing configs into the workspace (union + conflict report; the Python reference in assets/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

Development

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.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors