chain-hub
v0.5.3
Published
Chain Hub CLI — manage AI agent skills across IDEs
Readme
Chain Hub CLI
Site: chainhub.one · Repository: github.com/martijnbokma/chain-hub
Manage AI agent skills and IDE symlinks from one place with Chain Hub. Published as chain-hub on npm; the executable name is chain.
Requirements
- Node 20+ for the published npm CLI — including
chain hubandchain mcp(HTTP mode) - Bun (recommended for repo dev/tests; optional for end users — uses
bun:sqlitefor Brain when present)
Install (end users)
Recommended on macOS and Linux (one command; fixes common EACCES when npm tries to write under /usr/local):
curl -fsSL https://www.chainhub.one/install.sh | bash
chain init
chain setupAlternative if npm install -g already works on your machine:
npm install -g chain-hub
chain init
chain setup- Permission denied on macOS? Do not use
sudo npm install. Run the install script above or see Troubleshooting. - Before
install.shis on chainhub.one and merged tomain: clone the repo and runbash scripts/install-chain-hub.sh, or use a raw GitHub URL for the branch that contains that file (notmainuntil merged —mainreturns 404 today).
Installation (from this repo)
Replace <REPO_ROOT> with wherever you cloned the repository (for example ~/Code/side-projects/chain-hub).
cd <REPO_ROOT>/cli
bun installRun without a global install — add to ~/.zshrc or ~/.bashrc (set CHAIN_HUB_REPO once so moving the clone only updates one line):
export CHAIN_HUB_REPO="$HOME/Code/side-projects/chain-hub"
alias chain="bun run $CHAIN_HUB_REPO/cli/chain.ts"Or build a single file and put it on your PATH:
cd <REPO_ROOT>/cli
bun build --target=node --outfile dist/chain.js chain.ts
# Executable: node dist/chain.js — or use `bun build --compile` if you prefer a native binaryKeeping the CLI up to date (npm)
The chain binary comes from the chain-hub package. Re-run the install script or global npm install when you want a newer CLI:
curl -fsSL https://www.chainhub.one/install.sh | bash
# or: npm install -g chain-hub
chain --versionAfter upgrading the CLI, run chain init so CHAIN_HOME/core/ matches the bundled core shipped with that version. Run chain setup again if release notes say IDE symlink layouts changed.
Skills you installed from the registry or from configured GitHub bundles are updated separately with chain update.
Beta Pro licenses (Brain)
Maintainer — issue a key:
chain pro issue-key --note "Colleague name"
chain pro issue-key --note "Colleague" --github their-username # legacy: also invite on private repo
chain pro issued # optional: list keys issued from this machineUser — activate (no env vars):
chain pro activate CHAIN-XXXX-XXXX-XXXX-XXXX
chain hub # Brain → Memory + PipelineKeys are verified offline using a bundled beta secret in the CLI (not for public commerce). Send keys privately, not in Slack.
User — install Pro pack (hub Dashboard button or CLI):
chain pro install-pack
chain pro refresh-pack # after install, when a newer release is published
# Hub: Dashboard / Settings → Pro — **Update Pro pack** when a release is newerTwo delivery modes (see specs/2026-06-04-pro-pack-artifact-distribution.md):
| Mode | Config | User needs |
|------|--------|------------|
| github (default) | CHAIN_HUB_PRO_PACK or pro_pack_github | Collaborator on private chain-hub-pro + gh auth login |
| artifact | pro_pack_manifest_url, env, or built-in default (packages.chainhub.one) | HTTPS manifest + tarball only (no user GitHub) |
# Artifact channel (after maintainer publishes manifest + pack tarball)
chain config set pro_pack_manifest_url https://packages.example.com/pro-pack/manifest.json
chain config set pro_pack_channel artifact # optional; manifest URL alone selects artifact
chain pro install-packLicense-gated downloads (hide public manifest/tarball; hub proxies after Pro check):
chain config set pro_pack_license_gate true
chain config set pro_pack_upstream_manifest_url https://packages.chainhub.one/pro-pack/manifest.json
chain hub # clients use http://127.0.0.1:2342/api/pro/pack/manifestTroubleshooting: Bun is not defined when running chain hub
This means the installed chain-hub build still starts the dashboard with Bun.serve() only (broken on npm install -g where Node runs the binary). Fixed in [email protected]+ via a Node-compatible HTTP server.
- Upgrade (recommended):
curl -fsSL https://www.chainhub.one/install.sh | bash— installs latestchain-hubvia npm and configuresPATHwhen needed. Alternative:npm install -g chain-hub. - Verify:
chain --version(expect 0.4.5 or newer) thenchain hub(should printRunning at http://127.0.0.1:…without a stack trace). Open a new terminal ifchainis missing after the script. - Until a build with Node hub support is on npm: install Bun and run
bun "$(npm root -g)/chain-hub/dist/chain.js" hub.
Troubleshooting: ERR_UNSUPPORTED_ESM_URL_SCHEME / Received protocol 'bun:'
This means Node is loading a build that still imports bun:sqlite at startup (broken on npm global installs). Fixed in [email protected]+ (split chunks) and hardened in 0.4.3+ (dist/run.mjs bin guard + node:sqlite backend on Node).
Confirm the installed version and which binary runs:
chain --version npm list -g chain-hub (Get-Command chain).SourceExpect
0.4.2(or newer) and a shim that runs…\node_modules\chain-hub\dist\chain.js.Confirm the on-disk bundle is the split layout (not a single monolithic
chain.jsfrom 0.4.1):$pkg = "$env:APPDATA\npm\node_modules\chain-hub" (Get-ChildItem "$pkg\dist\*.js").Count Select-String -Path "$pkg\dist\chain.js" -Pattern 'bun:sqlite' -Quiet0.4.2+: many
dist/*.jsfiles;bun:sqliteonly in abrain-db-bun-*.jschunk;Select-Stringonchain.jsshould be$false.Clean reinstall:
npm uninstall -g chain-hub npm cache clean --force npm install -g chain-hub@latestIf
chainstill fails but the files look correct, bypass the shim:node "$env:APPDATA\npm\node_modules\chain-hub\dist\chain.js" initOr install Bun and run:
bun "$env:APPDATA\npm\node_modules\chain-hub\dist\chain.js" init
Environment
| Variable | Default | Description |
|---------------|-------------|-------------|
| CHAIN_HOME | ~/chain-hub | Canonical user hub: skills, agents, workflows, rules, skills-registry.yaml, and (after chain init) the core/ subtree. |
Resolution priority for hub location:
--chain-home <path>flag (per command)CHAIN_HOMEenvironment variablechain config set chain_home <path>(persisted user config)- default
~/chain-hub
Hub layout (recommended model)
- One root: All user data for Chain Hub lives under
CHAIN_HOME. The npm package (or a local source checkout for development) only delivers thechainbinary and bundledcore/source packaged into the CLI; it is not your personal library location unless you deliberately setCHAIN_HOMEinside a checkout. - Core vs user:
CHAIN_HOME/core/is the protected copy installed bychain init. Your skills, agents, workflows, and custom rules belong inCHAIN_HOME/skills/,agents/,workflows/,rules/(plus registry files at the hub root). This matches common “flat top-level folders +skills/<slug>/SKILL.md” patterns used by agent tooling ecosystems. skills-registry.yamlbuckets:corelists bundled/protected skills mirrored underskills/(optional; keeps them distinct frompersonal).chain_hublists skills installed viachain addfrom the Chain Hub registry index.personalis for your own scaffolds / ad-hoc GitHub installs / manual entries.packsis for curated multi-skill bundles (for example a premium pack): install withchain add github:org/repo --packso skills stay out ofcore, appear under the pack label inchain list, and refresh together viagithub_sourcesonchain update. Addcreditsin YAML for attribution.~/.agents: Some adapters symlink hubskills/andagents/into~/.agents/for tools that expect that layout. Treat~/.agentsas an IDE-facing mirror, not a separate primary library — edit and back upCHAIN_HOME.- Sandboxes: For contributors or experiments, point
CHAIN_HOMEat a throwaway directory sochain init/chain addnever touch another hub or a git working tree you care about.
export CHAIN_HOME="$HOME/chain-hub"
# Optional XDG-style example (create the directory first):
# export CHAIN_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/chain-hub"First-time setup
chain init— copies packagedcore/intoCHAIN_HOMEand ensuresskills-registry.yaml.chain setup— symlinksskills,agents,workflows, and supported paths into detected IDEs.chain list/chain validate— inspect and verify the tree.
chain init
chain setup
chain list
chain validateIf chain validate reports a missing skills-registry.yaml, run chain init first.
When CHAIN_HOME is a Chain Hub source checkout (the git clone that contains cli/chain.ts and cli/core/registry.yaml), chain setup installs git hooks under .git/hooks/:
| Hook | Purpose |
|------|---------|
| pre-commit | Runs chain validate with CHAIN_HOME set to the repo root (skips if chain is not on PATH) |
| commit-msg | Requires feat: / fix: / revert: when staging cli/ or apps/hub/ (changelog option A) |
| post-commit | Runs changelog, sync:roadmap-changelog, and generate:roadmap after feat/fix/revert commits touching cli/, apps/web/, or apps/hub/ (installed by default) |
Reinstall hooks: cd cli && bun run install:git-hooks. Commit checklist: CONTRIBUTING.md § Before you commit. Hubs that are not a source checkout do not receive these hooks.
Usage in projects
You typically do not install the CLI per project. After chain setup, IDEs read skills from CHAIN_HOME via symlinks.
Commands (overview)
| Command | Purpose |
|--------|---------|
| chain setup | Create or refresh IDE symlinks (--ide <name> for one IDE) |
| chain status | Show symlink health per IDE |
| chain list | List skills with registry labels and optional GitHub bundle info |
| chain search <query> / chain find <query> | Search the Chain Hub registry and the skills.sh open directory (GET /api/search, same backend as npx skills find). find is an alias of search. Use --hub-only to skip the directory. Override directory host with SKILLS_API_URL. Live hub index: registry/index.yaml on GitHub main; if that fetch fails, the CLI uses a bundled copy from the last package build. |
| chain add <slug> | Install from registry or github:owner/repo (use --pack for curated GitHub bundles / premium packs) |
| chain update | Refresh registry and GitHub-bundle skills from their sources |
| chain remove <slug> | Remove a registry-installed skill |
| chain new <slug> | Scaffold a skill under CHAIN_HOME/skills/ and register it under personal in skills-registry.yaml |
| chain rules/agents/workflows list | List non-skill assets from CHAIN_HOME/<type>/ with core/user markers |
| chain rules/agents/workflows new <slug> --content "<md>" | Create a new rule/agent/workflow (rules also support --ext .mdc) |
| chain rules/agents/workflows edit <slug> --content "<md>" | Update an existing rule/agent/workflow |
| chain rules/agents/workflows remove <slug> | Remove a user-owned rule/agent/workflow |
| chain validate | Validate skills and workflows (built-in checks; use --fix where supported) |
| chain capture | Append one learning event to learnings/queue/inbox.jsonl (--event, --skill, --summary; optional --repo, auto-filled from cwd when omitted) |
| chain active-project | Register which repo the editor is working in (touch, show, from-stdin for hooks, hook-path) |
| chain reflect | Turn the inbox into learnings/drafts/distill-*.md and archive the queue (--dry-run to preview only) |
| chain memory init | Create .chain/config.json in the current project with a workspace id |
| chain memory sync | Sync memory rules from CHAIN_HOME/memory/ into supported IDEs (Cursor, Claude Code, Windsurf, Gemini) |
| chain capture --rule | Capture a memory rule (--content, --scope global\|workspace) instead of a learning event |
| chain fix | Auto-fix some frontmatter/section issues |
| chain init | Install/update protected core assets into CHAIN_HOME |
| chain hub | Start the local Chain Hub dashboard (http://127.0.0.1:2342 by default). Binds to loopback only unless you pass --host 0.0.0.0. If 2342 is busy and you did not pass --port, it auto-selects an available port. |
| chain config list | List supported keys in ~/.config/chain-hub/config.json |
| chain config get <key> | Show one persisted value (e.g. chain_home, pro_pack_manifest_url) |
| chain config set <key> <value> | Persist hub path, Pro pack delivery, roadmap edit key, etc. |
| chain config unset <key> | Remove a persisted value (falls back to env/default) |
Config keys: chain_home, roadmap_edit_key, pro_pack_manifest_url, pro_pack_github, pro_pack_channel, pro_pack_license_gate, pro_pack_upstream_manifest_url, pro_pack_hub_origin. Pro license data lives under the pro object (set via chain pro activate, not config set).
Supported IDEs include Cursor, Windsurf, Claude Code, Antigravity (antigravity.google), Gemini CLI, Trae, Kiro, Mistral Vibe (~/.vibe/skills), and a Universal .agents/ fallback — see chain setup --help. chain status and chain setup print that link when Antigravity is configured.
Examples
chain setup
chain setup --ide cursor
chain --chain-home ~/.chain-sandbox init
chain config set chain_home ~/my-chain-home
chain add github:owner/repo
chain add github:your-org/private-skill-pack --pack
# Private pack repos: export GITHUB_TOKEN or GH_TOKEN, or use `gh auth login`
# Then merge the pack registry snippet from your internal docs (see docs/p4-pro-pack-manifest.md) into skills-registry.yaml
chain rules list
chain rules new custom-rule --content "# Rule"
chain agents new planner --content $'---\nname: planner\ndescription: Planner agent.\n---\n'
chain find typescript
chain hub
chain hub --port 0
chain memory init
chain memory sync
chain active-project show
chain validate
chain validate --fixMemory sync (chain memory sync)
Rules live under CHAIN_HOME/memory/ (global identity + per-workspace). chain memory sync writes active rules into IDE-specific files for detected adapters that implement memory sync:
| Editor | Project / workspace target |
|--------|----------------------------|
| Cursor | .cursor/rules/<id>.mdc |
| Claude Code | CLAUDE.md |
| Windsurf | .windsurfrules |
| Gemini CLI | GEMINI.md |
| Antigravity | GEMINI.md (project context) |
| Trae | .trae/project_rules.md |
| Kiro | .kiro/steering/chain-hub-memory.md |
| Mistral Vibe | AGENTS.md |
Setup only (no syncMemory): Universal (Internal & Agents) — symlinks via chain setup only.
Context7 MCP Server (Upstash)
To ensure that AI agents have access to the latest API documentation (e.g., Tailwind v4, Drizzle, Supabase) and prevent code-generation errors from outdated models, we recommend setting up the Context7 MCP server.
Installation & Configuration
Add the following configuration to your editor's MCP server settings (e.g., Cursor, Windsurf, or Antigravity configuration):
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7"]
}
}
}Usage
When pair-programming, agents can run Context7 tools such as resolve-library-id or query-docs to retrieve current library details and official documentation before generating frontend code.
Active project (hub + editor)
The hub’s This project views (Brain → Memory and Pipeline inbox) need to know which repo you are in. Chain Hub records that in CHAIN_HOME/.chain/active-project.json.
| Source | When it updates |
|--------|-----------------|
| Cursor hooks | workspaceOpen, sessionStart, or beforeSubmitPrompt → chain active-project from-stdin --editor cursor |
| chain capture | Every learning capture (also sets repo_hint when you omit --repo) |
| chain memory init | When you link a project workspace |
| chain active-project touch | Manual, from the repo root |
Resolution when chain hub runs:
- If you start the hub inside a repo that has
.chain/config.json(chain memory init), that repo wins. - Otherwise the hub uses the last entry in
active-project.json(from hooks or capture).
One-time Cursor setup — add to .cursor/hooks.json (project or ~/.cursor/hooks.json):
{
"version": 1,
"hooks": {
"workspaceOpen": [{ "command": "chain active-project from-stdin --editor cursor" }],
"sessionStart": [{ "command": "chain active-project from-stdin --editor cursor" }],
"beforeSubmitPrompt": [{ "command": "chain active-project from-stdin --editor cursor" }]
}
}Example bundled in core/hooks/cursor-hooks.example.json. Requires chain on PATH in the hook environment. Inspect with chain active-project show.
Premium packs: see the Pro pack manifest in the private chain-hub-internal-docs repo (docs/p4-pro-pack-manifest.md after clone) and chain add github:… --pack.
Typical workflow on a new machine
npm install -g chain-hub
# Optional: point CHAIN_HOME at a dedicated directory
export CHAIN_HOME="$HOME/chain-hub"
echo 'export CHAIN_HOME="$HOME/chain-hub"' >> ~/.zshrc
chain init
chain setup
chain statusTo upgrade an existing install: npm install -g chain-hub, then chain init (and chain setup if needed). Use chain update for registry/GitHub skills.
Development
cd cli
bun test # full test suite
bun run dev -- --help # run CLI via Bun
bun run build # emit dist/chain.js
bun run pack:check # verify cli/core/, build, sync registry index, verify package filesBefore npm publish
Publishing is what makes a version real for npm install -g chain-hub and for the hub’s CLI update check. A git tag or shippedIn in roadmap.yaml alone does not update npm users. See CONTRIBUTING.md § Git tag vs npm.
Checklist (from cli/, version = X.Y.Z):
Automated prep (changelog, roadmap shippedIn, bundledIn from git tags, registry/index.yaml, validation, git add):
cd cli
bun run release:prepare -- --bump=patch # or: npm version patch (runs the same hooks via `version` script)Manual steps that remain:
- Review staged
CHANGELOG.md,roadmap.yaml, andcore/registry.yaml(bundledIn/updatedIn). - Add roadmap refs in changelog bullets where needed:
_(roadmap:direction/item-id)_, then re-runbun run sync:roadmap-changelogif you edit bullets. - Re-audit all skills from git when unsure:
bun run sync:bundled-in:all. - Commit:
feat(cli): release vX.Y.Z(project conventional-commit rules). cd ../apps/hub && bun run buildwhen hub UI changed, then back tocli/.bun test— same gate as CI.bun run release:publish—pack:check,smoke:package,npm publish(prepublishOnlyrebuildsdist/before upload).git tag vX.Y.Zand push the tag (after a successful publish; never tag without publishing to npm).
Prefer bun run release:publish over bare npm publish. Bare npm publish still rebuilds via prepublishOnly, but skips pack:check / smoke unless you ran them yourself.
Verify: npm view chain-hub version should print X.Y.Z. Restart running chain hub processes so they pick up the new global install.
Optional: install the .tgz from npm pack in a throwaway environment and run chain init / chain validate.
