Help us shape the future of Go! Take the 2026 Go Developer Survey

ccshelf

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT

README

ccshelf

Profiles and a plugin catalog for Claude Code. Unofficial: not affiliated with Anthropic.

Status: implemented and under adversarial review; stable releases are available. The launcher, catalog, Action and starter template build for all six targets; the test suites pass on native macOS, Linux and Windows CI runners. Phase 0 evidence items (routing eval, adopt-or-build and bundle prototype) are still open; see the roadmap. Start with docs/README.md and the decision log. The interactive report is docs/report.html, generated from the Markdown.

Install

Install the latest release with the platform-specific script below, or build from source (Go 1.27 or newer):

go install github.com/yorch/ccshelf/cmd/ccshelf@latest
ccshelf --version

Or clone the repository and run go build -o ccshelf ./cmd/ccshelf.

The installers below fetch the latest release. Both verify the download before installing anything, never need administrator rights, send no telemetry and write only into the install directory (created with any missing parent folders) and a private temporary directory that is removed afterwards. The Windows script edits your user PATH only with -AddToPath. install.sh needs curl (for example apk add curl or apt install curl); it ignores ~/.curlrc, honors the usual proxy and CA environment variables and never turns TLS verification off.

Linux and macOS (amd64 and arm64; WSL counts as Linux). Installs into ~/.local/bin:

curl -fsSL https://github.com/yorch/ccshelf/releases/latest/download/install.sh | sh

Pin a version, choose a directory, or require the signature check (options go after sh -s --):

curl -fsSL https://github.com/yorch/ccshelf/releases/latest/download/install.sh | sh -s -- --version v0.2.0 --bin-dir "$HOME/bin" --require-signature

Prefer to read it first? curl -fsSLO https://github.com/yorch/ccshelf/releases/latest/download/install.sh, read it, then sh install.sh. sh install.sh --help lists every option (--base-url for a mirror of the public release, such as one hosted on your GitHub Enterprise Server, --dry-run, --quiet, --force). A mirror is trusted to serve the release you ask for, and its latest can name an older release that is still validly signed. --cosign-identity and --cosign-issuer matter only for a release you signed yourself; a mirror of the public release is checked with the default identity.

Windows (amd64 and arm64; Windows PowerShell 5.1 or PowerShell 7). Installs into %LOCALAPPDATA%\Programs\ccshelf:

irm https://github.com/yorch/ccshelf/releases/latest/download/install.ps1 | iex

With options (-Version, -BinDir, -BaseUrl, -RequireSignature, -AddToPath, -DryRun, -Force). The irm | iex form leaves your session alone: it defines no variable or function and changes no preference. -AddToPath writes your user PATH back as an expandable value, so %VARIABLE% entries stay as they are:

& ([scriptblock]::Create((irm https://github.com/yorch/ccshelf/releases/latest/download/install.ps1))) -Version v0.2.0 -AddToPath

What the installers check. The release's checksums.txt is fetched from the same release as the archive, the archive must match exactly one line in it (SHA-256, always), and the archive may contain only ccshelf (ccshelf.exe), LICENSE and README.md. When cosign is on your PATH the signature of checksums.txt is verified first against the release workflow's exact identity, and a failure stops the install; --require-signature (-RequireSignature) turns a missing cosign into an error too. Without cosign the installer says so: the checksum then detects corruption, not a tampered release, because both files come from the same place. See SECURITY.md for what this does and does not prove.

By hand. Download the archive for your platform, checksums.txt and checksums.txt.sigstore.json from the release page, then:

cosign verify-blob \
  --bundle checksums.txt.sigstore.json \
  --certificate-identity 'https://github.com/yorch/ccshelf/.github/workflows/release.yml@refs/tags/vX.Y.Z' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  checksums.txt
sha256sum --check --ignore-missing checksums.txt    # macOS: shasum -a 256 --check --ignore-missing checksums.txt
tar -xzf ccshelf_X.Y.Z_<os>_<arch>.tar.gz ccshelf   # Windows: Expand-Archive the .zip

On Windows, compare (Get-FileHash -Algorithm SHA256 <archive>).Hash with the archive's line in checksums.txt. Releases also carry a GitHub build provenance attestation (gh attestation verify <archive> --repo yorch/ccshelf) and an SBOM per archive.

Notes. The binaries are not notarized (macOS) or Authenticode-signed (Windows) yet. A file fetched by curl or the installers carries no quarantine mark, so Gatekeeper does not stop it; a browser download does, and macOS may ask you to allow it in System Settings (or run xattr -d com.apple.quarantine ccshelf). Windows SmartScreen may warn about a downloaded .exe. Unofficial; not affiliated with Anthropic.

Uninstall. Delete the binary (rm ~/.local/bin/ccshelf, or the directory you chose; on Windows delete %LOCALAPPDATA%\Programs\ccshelf and, if you used -AddToPath, its entry in your user PATH). Optionally remove ccshelf's own cache (~/.cache/ccshelf, or %LOCALAPPDATA%\ccshelf on Windows) and its configuration directory; nothing is ever written to ~/.claude.

A reusable GitHub Action is also available (action/).

Use

A profile is a named recipe of plugins, standalone skills and MCP servers. ccshelf run starts claude with exactly that set, so each terminal can run a different one.

ccshelf new sre-night --from base --plugin sre-kit@acme   # create a personal profile
ccshelf ls                                                # list profiles from every source
ccshelf show sre-night                                    # resolved plugins, MCP servers, trust closure
ccshelf dry-run sre-night                                 # print the exact claude command, run nothing
ccshelf run sre-night                                     # start claude with the profile
ccshelf run --account personal sre-night --resume         # ccshelf flags first, then claude's

Every command works with flags alone; on a terminal, missing values are asked for and the equivalent command is printed. Profiles from a shared source (a git repo of your organization) must be trusted first: ccshelf trust <profile> shows what the profile does, and nothing is ever accepted automatically (--yes does not accept trust). Exit codes: 0 ok, 1 failure, 2 usage, 3 policy, 4 trust required, 130 interrupted.

Update
ccshelf update --check     # current and latest version; exit 0 either way
ccshelf update             # verify (SHA-256, and cosign if installed), then replace this binary
ccshelf update --rollback  # restore the previous binary kept as ccshelf.old
ccshelf update --yes       # the scripted form: no question (the automatic update never acts in scripts)

The archive's SHA-256 must match checksums.txt of the same release; with cosign on PATH its keyless signature is checked too (--require-signature insists on it, and is checked before anything else). The signature must come from the release workflow of the repository this binary was built from, whatever base_url says; a fork that signs its own releases names itself in cosign_identity_repo. --force never installs an older release than the one you run; --allow-downgrade does. A copy installed with Homebrew, Scoop, WinGet or go install, and development builds, are left to their package manager (the command is printed; --force overrides). Nothing checks for updates by itself unless you opt in:

# config.toml
[update]
mode = "notify"   # off (default) | notify (one line when a release exists) | install (see below)
interval = "24h"

install takes only a newer stable release of the same major version (for 0.x, the same minor). Both modes act only in an interactive terminal (stdin, stdout and stderr all terminals), never in scripts, cron jobs or pipelines, never when CI is set, and CCSHELF_NO_UPDATE_CHECK=1 turns them off. Details: docs/design/update.md.

For organizations, ccshelf lint, compile, catalog build, search, recommend and doctor work on the org data repo (see examples/org-data-repo for a starter template). The design is in docs/.

Set up your org repo

ccshelf catalog init bootstraps the organization's data repo: a new one in an empty directory, or an existing marketplace repo (.claude-plugin/marketplace.json and/or plugins/), which it retrofits without changing any existing file. It prints a plan (create, skip-exists, needs-merge) and writes ccshelf.toml, a marketplace skeleton, a sidecar stub per plugin, CODEOWNERS, the pinned validate, catalog and release workflows, a README and .gitattributes. There are no built-in profiles. Placeholders (TODO(ccshelf)) are reported by ccshelf lint as warnings until you fill them in.

ccshelf catalog init ./acme-claude --marketplace-name acme --org "Acme Corp" \
  --platform-owners @acme/platform --dry-run          # print the plan, write nothing
ccshelf catalog init ./acme-claude --marketplace-name acme --org "Acme Corp" \
  --platform-owners @acme/platform --yes              # write it
ccshelf catalog init . --platform-owners @acme/platform --write-suggestions --yes   # adopt an existing repo

On a terminal, missing values are asked for. The design is in docs/design/catalog-and-org-repo.md.

The project website (static; the /docs pages are generated from the Markdown at build time) lives in site/; it is checked by make site-check and is deployed to GitHub Pages only by hand (.github/workflows/pages.yml, see site/README.md).

Licensed under the MIT License.

Directories

Path Synopsis
cmd
ccshelf command
Command ccshelf runs Claude Code with a named profile and lints and publishes an organization's plugin catalog.
Command ccshelf runs Claude Code with a named profile and lints and publishes an organization's plugin catalog.
internal
account
Package account manages named Claude Code accounts: a name that maps to a separate CLAUDE_CONFIG_DIR (launcher.md, "Combining profiles with accounts", way 2).
Package account manages named Claude Code accounts: a name that maps to a separate CLAUDE_CONFIG_DIR (launcher.md, "Combining profiles with accounts", way 2).
analytics
Package analytics reads optional plugin usage data.
Package analytics reads optional plugin usage data.
bundles
Package bundles compiles resolved profiles into generated profile bundles: dependency-only plugins that let a profile's plugins install natively from the org's marketplace (decision D-17).
Package bundles compiles resolved profiles into generated profile bundles: dependency-only plugins that let a profile's plugins install natively from the org's marketplace (decision D-17).
cache
Package cache manages the launcher's private cache directory and the content-addressed files in it (security requirement SR4).
Package cache manages the launcher's private cache directory and the content-addressed files in it (security requirement SR4).
catalog
Package catalog builds the plugin catalog of an org data repo: a merged, sanitized, deterministic view of the marketplace entries, their sidecar metadata, what inspecting the plugin directories found, and optional git history, plus renderers (catalog.json, CATALOG.md) and a text search.
Package catalog builds the plugin catalog of an org data repo: a merged, sanitized, deterministic view of the marketplace entries, their sidecar metadata, what inspecting the plugin directories found, and optional git history, plus renderers (catalog.json, CATALOG.md) and a text search.
catalog/catalogtest
Package catalogtest holds helpers shared by the tests of the catalog packages: the fictional org data repo fixture and small file helpers.
Package catalogtest holds helpers shared by the tests of the catalog packages: the fictional org data repo fixture and small file helpers.
catalog/codeowners
Package codeowners parses CODEOWNERS files and answers "who owns this path" with GitHub's semantics.
Package codeowners parses CODEOWNERS files and answers "who owns this path" with GitHub's semantics.
catalog/gitdata
Package gitdata collects optional history data for the catalog by running the user's git: the last commit date and the number of distinct authors of each plugin directory, the latest tag, and which plugin directories changed since a tag.
Package gitdata collects optional history data for the catalog by running the user's git: the last commit date and the number of distinct authors of each plugin directory, the latest tag, and which plugin directories changed since a tag.
catalog/lint
Package lint checks an org data repo against the catalog rules and reports stable, sorted findings.
Package lint checks an org data repo against the catalog rules and reports stable, sorted findings.
catalog/safepath
Package safepath confines file access to a repository root.
Package safepath confines file access to a repository root.
catalog/sidecar
Package sidecar reads the catalog-only metadata of plugins: one TOML sidecar file per plugin (catalog/plugins/<name>.toml), or, in single-file mode, the free-form "metadata" object of each marketplace entry, and the taxonomy file (catalog/taxonomy.toml).
Package sidecar reads the catalog-only metadata of plugins: one TOML sidecar file per plugin (catalog/plugins/<name>.toml), or, in single-file mode, the free-form "metadata" object of each marketplace entry, and the taxonomy file (catalog/taxonomy.toml).
catalog/site
Package site writes the static catalog site: four plain files that a web server, GitHub Pages or an internal static host can serve as they are.
Package site writes the static catalog site: four plain files that a web server, GitHub Pages or an internal static host can serve as they are.
claude
Package claude is everything ccshelf needs from the claude binary: finding it, asking it questions, parsing what it prints, and starting it.
Package claude is everything ccshelf needs from the claude binary: finding it, asking it questions, parsing what it prints, and starting it.
cli
Package cli assembles the ccshelf command tree: the global flags, the launcher commands and the org and catalog commands.
Package cli assembles the ccshelf command tree: the global flags, the launcher commands and the org and catalog commands.
cli/clicore
Package clicore holds the small, dependency-light pieces every ccshelf command shares: the global flags, the environment a command may touch, and the per-invocation Context that carries the terminal mode and the prompter.
Package clicore holds the small, dependency-light pieces every ccshelf command shares: the global flags, the environment a command may touch, and the per-invocation Context that carries the terminal mode and the prompter.
cli/launcher
Package launcher implements the launcher commands of ccshelf: run, dry-run, show, ls, diff, new, edit, init, trust, account, shell-init, version and completion.
Package launcher implements the launcher commands of ccshelf: run, dry-run, show, ls, diff, new, edit, init, trust, account, shell-init, version and completion.
cli/orgcmd
Package orgcmd implements the org and catalog commands of the ccshelf CLI: lint, compile, catalog build, search, recommend and doctor.
Package orgcmd implements the org and catalog commands of the ccshelf CLI: lint, compile, catalog build, search, recommend and doctor.
cli/updatecmd
Package updatecmd implements the "ccshelf update" command and the opt-in automatic update hooks around the other commands.
Package updatecmd implements the "ccshelf update" command and the opt-in automatic update hooks around the other commands.
config
Package config loads, validates and saves the user's ccshelf configuration file (config.toml) and resolves which Claude Code account a run uses.
Package config loads, validates and saves the user's ccshelf configuration file (config.toml) and resolves which Claude Code account a run uses.
config/tomlkeys
Package tomlkeys closes a gap in the TOML decoder: go-toml matches struct tags case-insensitively, so "Inherit_User_Settings = false" written after "inherit_user_settings = true" would silently override it and a reviewer reading the file would see two different spellings of one setting.
Package tomlkeys closes a gap in the TOML decoder: go-toml matches struct tags case-insensitively, so "Inherit_User_Settings = false" written after "inherit_user_settings = true" would silently override it and a reviewer reading the file would see two different spellings of one setting.
doctor
Package doctor analyzes an org's catalog, profiles and installed plugins and returns findings.
Package doctor analyzes an org's catalog, profiles and installed plugins and returns findings.
e2e
Package e2e holds end-to-end tests of the real ccshelf binary.
Package e2e holds end-to-end tests of the real ccshelf binary.
envpolicy
Package envpolicy decides which environment variable names a profile may set for a Claude Code session (security requirement SR1).
Package envpolicy decides which environment variable names a profile may set for a Claude Code session (security requirement SR1).
marketplace
Package marketplace reads a Claude Code plugin marketplace repository without running the claude binary.
Package marketplace reads a Claude Code plugin marketplace repository without running the claude binary.
orgconfig
Package orgconfig reads ccshelf.toml, the org config at the root of an organization's data repo.
Package orgconfig reads ccshelf.toml, the org config at the root of an organization's data repo.
policy
Package policy detects Claude Code managed policy on this machine and turns it into a capability matrix for the launcher (requirement R3, decision D-06).
Package policy detects Claude Code managed policy on this machine and turns it into a capability matrix for the launcher (requirement R3, decision D-06).
profile
Package profile parses profile manifests, resolves them across sources and computes the trust closure (SR1 to SR3).
Package profile parses profile manifests, resolves them across sources and computes the trust closure (SR1 to SR3).
profile/gitsource
Package gitsource provides a profile.Source backed by a pinned git repository: the shared "org data repo" that holds profiles/, mcp/registry.toml and prompts/ (security requirements SR2 and SR4).
Package gitsource provides a profile.Source backed by a pinned git repository: the shared "org data repo" that holds profiles/, mcp/registry.toml and prompts/ (security requirements SR2 and SR4).
profile/pluginsource
Package pluginsource provides a profile.Source that reads profiles from a Claude Code plugin that is already installed: the "data-only plugin" way of shipping an org's profiles.
Package pluginsource provides a profile.Source that reads profiles from a Claude Code plugin that is already installed: the "data-only plugin" way of shipping an org's profiles.
recommend
Package recommend suggests plugins and profiles for a directory.
Package recommend suggests plugins and profiles for a directory.
scaffold
Package scaffold plans and writes the files of an org data repo for "ccshelf catalog init": a new repository in an empty directory, or the missing pieces of an existing marketplace repository.
Package scaffold plans and writes the files of an org data repo for "ccshelf catalog init": a new repository in an empty directory, or the missing pieces of an existing marketplace repository.
settings
Package settings generates and validates the --settings JSON that ccshelf hands to Claude Code (security requirement SR1: a closed schema).
Package settings generates and validates the --settings JSON that ccshelf hands to Claude Code (security requirement SR1: a closed schema).
shellinit
Package shellinit generates the shell integration printed by "ccshelf shell-init <shell>": one small function per profile that runs "ccshelf run <profile>" with the rest of the command line passed through.
Package shellinit generates the shell integration printed by "ccshelf shell-init <shell>": one small function per profile that runs "ccshelf run <profile>" with the rest of the command line passed through.
testutil
Package testutil holds helpers shared by ccshelf's tests: a build of the fake claude (internal/testutil/fakeclaude), an isolated environment that cannot touch the real home directory, and small file helpers.
Package testutil holds helpers shared by ccshelf's tests: a build of the fake claude (internal/testutil/fakeclaude), an isolated environment that cannot touch the real home directory, and small file helpers.
testutil/fakeclaude command
Command fakeclaude is a test double of the claude binary, driven by environment variables and files, for ccshelf's tests.
Command fakeclaude is a test double of the claude binary, driven by environment variables and files, for ccshelf's tests.
trust
Package trust decides whether a resolved profile may run (SR2): it keeps the trust lockfile, compares a closure with what the user accepted, explains differences in plain words and tracks per-repository trust for project profiles.
Package trust decides whether a resolved profile may run (SR2): it keeps the trust lockfile, compares a closure with what the user accepted, explains differences in plain words and tracks per-repository trust for project profiles.
ui
Package ui is the terminal layer of ccshelf: how a command decides whether it may prompt, how it asks, how it prints, and how it exits (requirement R6).
Package ui is the terminal layer of ccshelf: how a command decides whether it may prompt, how it asks, how it prints, and how it exits (requirement R6).
update
Package update implements "ccshelf update" and the opt-in automatic update: discovering the latest release, downloading and verifying it, and replacing the running binary.
Package update implements "ccshelf update" and the opt-in automatic update: discovering the latest release, downloading and verifying it, and replacing the running binary.
update/updatetest
Package updatetest is a fake GitHub release server for tests of the update flow: it speaks the few REST routes ccshelf uses (latest, list, by tag) and serves real tar.gz and zip archives, a checksums.txt and, on request, a signature bundle placeholder.
Package updatetest is a fake GitHub release server for tests of the update flow: it speaks the few REST routes ccshelf uses (latest, list, by tag) and serves real tar.gz and zip archives, a checksums.txt and, on request, a signature bundle placeholder.
version
Package version reports the build identity of the ccshelf binary.
Package version reports the build identity of the ccshelf binary.
Package schema embeds the handwritten JSON Schema (draft 2020-12) files for ccshelf's three TOML formats: profile manifests, the user config and the MCP registry.
Package schema embeds the handwritten JSON Schema (draft 2020-12) files for ccshelf's three TOML formats: profile manifests, the user config and the MCP registry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL