plugin-release
Skill1 starsChanged 14 days agoMITView on GitHub
Ships changes to Sphica's MCP servers, CLI, capture and delivery hooks, or plugin Skills and Agents to npm. Covers bundle entry points and the modules they depend on, matching versions, and confirming delivery to both Claude and Codex. For DB schema or role changes, use knowledge-schema first, then this Skill to ship.
- Installs packages
- Commits and pushes
5 other projects use a version of this.
Adopted by
Most recently taken up by
- accso/ai-monitoringtheir own version, first seen Nov 8, 2026
- Compound-Leverage/THINK-schooltheir own version, first seen Nov 1, 2026
- nowledge-co/communitytheir own version, first seen Oct 13, 2026
- NanmiCoder/dsh-agent-teamstheir own version, first seen Oct 8, 2026
- v11g/agents-rocktheir own version, first seen Sep 15, 2026
Other versions5 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 5
- NanmiCoder/dsh-agent-teams★ 2.8ksame name
- nowledge-co/community★ 204same name
- v11g/agents-rock★ 9same name
- accso/ai-monitoring★ 2same name
- Compound-Leverage/THINK-school★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository7 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- knowledge-schemaSkill
- plugin-agent-authoringSkill
- codex-reviewSkill
- eval-loopSkill
- fork-prSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. 0 are common, 3 are distinctive, and 11 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 55
After adding a dependency to server/, pass bun run notices.
- Distinctive: line 72
Do not merge Renovate's dependency PRs (1 a month) or lockfile maintenance PRs directly.
- Very specific: line 93
Do not put version directly under the marketplace entry.
- Very specific: line 105
Run git tag v<version> <head> on the PR head and push it.
- Distinctive: line 106
Only the owner's account can create tags (the ruleset limits it).
- Very specific: line 136
When a job fails, report-failure comments on the PR with the failed jobs and whether npm has the version (yes, no, or unknown.
- Very specific: line 146
Do not rerun publish after it succeeded
- Very specific: line 148
Start the scan on main by hand with gh workflow run <osv-scanner.yml or scorecard.yml> --repo iroha924/sphica --ref main and watch that run
- Very specific: line 161
Run it from the home directory too (cd ~ && npm i -g sphica@<version>): with a per-directory Node (mise), npm i -g inside this repository …
- Very specific: line 163
If the release changed the DB generation, copy ~/.sphica/sphica.db (with -wal and -shm) to a dated backup, move it aside, and run sphica …
- Very specific: line 189
Put the database at <tmp>/.sphica/sphica.db and run with HOME=<tmp>, CODEX_HOME=$HOME/.codex (the installed plugin and its trust), and the …
- Very specific: line 193
When changing aspects, read plugin-agent-authoring first too.
- Very specific: line 204
When checking after delivery, confirm in Codex that the body is read when explicitly started with $sphica:<skill> too
- Distinctive: line 206
Check the human-facing CLI output and the AI-facing MCP replies separately.
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Ship the package
Triggers
- Changing
server/src/mcp.ts,server/src/cli.ts,server/src/capture.ts,server/src/deliver.ts, or modules they import - Changing
plugin/hooks/hooks.json - Changing
plugin/skills/ - Bumping the shipped version, or publishing to npm
- Investigating why local changes do not reach Claude Code or Codex
Does not trigger
- Changing the DB schema or roles. Use
knowledge-schemafirst for that (the schema ships in the package, so the release uses this Skill)
Distribution path
The source of truth is a single npm package, and the Claude Code and Codex plugins point to it through the marketplace's npm source.
Claude Code resolves the package with the npm client and unpacks the tarball into the plugin cache.
- No install scripts run, and no dependencies are installed. The tarball must be self-contained
(it ships one file each, bundled with
bun build). The DB isnode:sqlite(built into Node), so there are no native dependencies sphica initreads the bundleddb/schema.sql. CI checks it by runninginitin a temporary HOME with the CLI from the unpacked tarballdist/holds 6 entries:cli.js(init, doctor, uninstall),mcp.js(the read MCP server),mcp-record.js(the record MCP server the trace, harvest, and glean Skills write through),capture.js(recording hooks),deliver.js(delivery hooks), andgit-worker.js(the child process that compares a work tree in a git directory Sphica writes;server/src/git-worker.tsholds the details)- The cache updates only when the version changes.
bun run bundleor a commit alone does not deliver anything; nothing arrives until publish - The CLI reads
dist/cli.jswhere it is run, so working in the CLI is no proof that it works in MCP - The hooks call
${CLAUDE_PLUGIN_ROOT}/dist/capture.jsanddist/deliver.js, so they too run at the cache's version - The hook entries run only when their own path matches
capture.(ts|js)/deliver.(ts|js). Renaming a bundle (to.mjs, say) turns the hook into a silent no-op: it exits 0 and prints nothing plugin/distis not tracked by git. The build is made at publish time
How Skills do their work
Plugin Skills do not call the CLI. They use MCP tools: the read server (sphica) and the record server (record). In Claude Code a plugin's tool is
named mcp__plugin_sphica_<server>__<tool>, and a Skill's allowed-tools lists the ones it uses. Codex uses the same servers from
plugin/mcp/codex.json.
npm's bin is for the sphica command users get from npm i -g; there is no contract that exposes it on the PATH inside the plugin.
Delivery hook speed
A delivery hook runs in a fresh node process per call under a 5-second limit, and there building a pattern costs far more than matching one.
A change to the matching in server/src/deliver.ts or server/src/review.ts runs node server/evals/scale/run.ts before and after the change and puts both tables in the PR body.
Adding dependencies
dist/ contains dependency code as is, so bundling to 0 npm dependencies does not remove the duty to include notices.
MIT requires the copyright notice and license text; Apache-2.0 section 4 requires a copy of the License and the contents of NOTICE (if any).
- After adding a dependency to
server/, passbun run notices. It fails if a package's SPDX cannot be read bun run bundlerebuildsplugin/THIRD_PARTY_NOTICES.mdfromnode_modules. It is untracked and ships in what is published- For packages that do not include their license text, supply a copy in
scripts/licenses/<SPDX>.txt. Where there is no copy, cite the source - Do not add GPL / AGPL / SSPL dependencies. They would stop us from shipping under MIT
Shipping
First, classify the change with bun run release:plan -- --base <previous release commit>. For a plugin release it also reads, with the owner's gh, the settings only an admin can see (immutable releases, SHA pinning required for actions) and fails unless both are on.
The owner does only one thing per release: approve the npm-release environment on the run page, plus /reload-plugins in open sessions after arrival.
That approval is the only gate before npm. Claude does not do it in the owner's place, neither on the page nor through the API (gh api .../pending_deployments), even though this machine's gh could.
Claude runs every other command exactly as written in the steps below.
| Step | What the owner does | Why |
| 6 | Open the run from the link the run comments on the PR, read the PR (including its Release notes) and the OSV scan in the run summary, and approve npm-release with Review deployments | The owner is the only reviewer, and the release publishes, merges, and creates the GitHub Release without asking again |
Do not merge Renovate's dependency PRs (1 a month) or lockfile maintenance PRs directly; pull them into a PR of this repository and close the original
after pulling it in (closed first, Renovate may ignore that update). A PR whose only package inputs are server/package.json and server/bun.lock needs no bump
when CI's static part (Node 24.15) finds the packed tarball the same as the last release apart from the version and README (scripts/release-verdict.mjs,
then check-mcp-version.mjs --verdict); pre-commit leaves that decision to CI (--defer-deps), and the push to main reuses the verdict of the pull request run same-tree reused (scripts/main-version-check.mjs). A tarball that differs, or a comparison that cannot run
(the registry unreachable, the base version unpublished), asks for a bump as before. Ship vulnerability fixes without waiting for the monthly one.
| Kind | Changes | Versions to move |
none | Dev docs that do not ship, repository dev Skills, tests only, a change to the root README.md alone (it goes into npm, but ships with the next release), and a change to the server's dependency files whose packed tarball CI found the same as the last release | None |
plugin | MCP, CLI, capture, hooks, plugin Skills and Agents, shared modules | Every place VERSION_SOURCES in scripts/lib/release-scope.mjs lists: the npm package and the 3 places of the plugin channel |
The source of truth for the classification is scripts/lib/release-scope.mjs; the version gate and
the release command read the same file.
- Decide the release version. For
plugin, bring all of these to it- npm's
package.json plugin/.claude-plugin/plugin.jsonplugin/.codex-plugin/plugin.json- The exact version of the marketplace's
npmsource (no ranges orlatest: the same commit would resolve different tarballs over time) - The git tag
- npm's
- Do not put
versiondirectly under the marketplace entry.plugin.jsonsilently wins, and a stale value hides updates Once, before the first release, the owner sets these up in the web UI (without them, the release stops or goes ahead unprotected).
- GitHub: the
npm-releaseenvironment: the owner as the only required reviewer, self-review prevention off (the owner's account pushes the tag), admin bypass off, deployments allowed only from tagsv*.scripts/release-env.mjsstops the release inprepareand again inpublishif any of this drifts - GitHub: a ruleset limiting creating, updating, and deleting tags
v*to the owner - npm: trusted publisher (repository
iroha924/sphica, workflowrelease.yml, environmentnpm-release, directnpm publishallowed), 2FA required, publishing with tokens disallowed. A connection cannot be edited: to change one, delete it and create it again
- Open a PR with the "Release notes" section filled in, and pass CI (
check,pr-body, andrelease, the dry run). Keep main merged into the PR branch (if main has moved ahead, the tree CI checked and the tag's tree do not match). Read the Codex review of the last head on the PR; fix or decline each finding and resolve every thread before tagging - Run
git tag v<version> <head>on the PR head and push it. Tagging the head, not main, lets the candidate be checked before the merge. Only the owner's account can create tags (the ruleset limits it). Claude pushes with the owner's credentials on this machine. From the tag push until the run finishes, push nothing to main, not even a README-only change: the run stops when the tag's commit no longer contains main (scripts/release-gate.mjs), and the finish fails when the merge's tree differs from the tag's .github/workflows/release.ymlruns.preparechecks that the tag matches every version, that the tag's commit is the head of an open PR into main, thatcheck,pr-body, andreleasesucceeded on that head, and that no review thread is left open (scripts/release-gate.mjs), and that only the owner can approvenpm-release(scripts/release-env.mjs); it does not rerunverify(the gate'scheckon the same head ran it on both Node lines), but bundles, runsnpm pack, and checks the result withscripts/check-tarball.mjs(the file list, starting outside the repository,initin a temporary HOME). The PR'sreleasedry run runs the same build path, so a tag never takes a path CI has not run. It also stops when the PR has no Release notes, and records a digest of the notes the owner is about to read. The SHA-512 appears in the job summary, and the run comments on the PR with its URL. Claude hands that URL to the owner. Besideprepare,osvscans the tag commit's dependencies with osv-scanner (scripts/osv-summary.mjs): the run summary shows the scanned SHA andfound(with a table of packages and IDs),none, orunavailable(the scanner did not finish, exited with a code other than 0 or 1, or left results that disagree with that code or cannot be read), and the PR comment carries the same one line. The scanner is the osv-scanner release binary checked against the SHA-256 pinned in release.yml (OSV_SCANNER_SHA256). Neither findings nor a failed scan stop the release;publishwaits only for the scan to finish. When the job fails before it can scan, the summary or the comment says so. Claude tells the owner the line when handing over the URL- The owner approves the
npm-releaseenvironment on the run page.publishthen runs both checks again, compares the SHA-512 of the same tarball, attests the SBOM, and runsnpm publish <tgz> --tag latest --provenance(trusted publishing, no token). The version is the default install from here mergemerges the PR withgh pr merge <PR> --merge --match-head-commit <head>using the run's token. A merge by that token starts no other workflow, sorefresh-scansthen startsosv-scanner.ymlandscorecard.ymlon main withgh workflow run(a dispatch by the token does start them) and lists each run's URL in its summary. A failed dispatch only warns; the release does not fail for itfinishrunsscripts/release-finish.mjs. npm serves a published version a few minutes later (2 min 15 s for 0.5.4, about 6 min for 0.5.5 and 0.5.6), so it first waits up to 12 minutes for it. Then: the merge commit's tree equals the tag's (git diff --exit-code <head> <merge commit>), the tarball npm serves has the SBOM attestation from this tag (gh attestation verify <tgz> --repo iroha924/sphica --predicate-type https://cyclonedx.org/bom --signer-workflow iroha924/sphica/.github/workflows/release.yml --source-ref refs/tags/v<version>), and npmlatestis the version. It then creates the GitHub Release from the PR body's "Release notes" section as is, only if the notes still match the digest from step 5 (gh release create v<version> --verify-tag --title v<version> --notes-file <file>; not git log, which OpenSSF Best Practices'release_notesdoes not accept) closes the issues the PR closes that are still open (a merge by the run's token does not close them), and comments the result on the PR- Claude follows the run with
gh run watch <run-id> --exit-status. When it succeeds, list npm's dist-tags, the remote tag, the global CLI, the marketplace, and the Claude/Codex caches withbun run release:status, and confirm no step remains. Items it failed to observe show asunknown, notnoneornot found. Then watch the two scan runsrefresh-scanslisted (gh run view <release run-id> --log --job <refresh-scans job id>shows the URLs) withgh run watch <id> --exit-status. A line without a URL is reported as not observed; do not take an earlier run of the same workflow in its place
Do not re-tag the same v<version>. A published version can never be published again, and provenance's references could no longer be followed.
When a job fails, report-failure comments on the PR with the failed jobs and whether npm has the version (yes, no, or unknown; for unknown, check npm view sphica@<version> version by hand).
preparestopped only because review threads are open: nothing shipped and the tag still points at the head. Resolve each (decline it in the PR body's "Declined findings"), then rungh run rerun <run-id> --failed, without bumping the version. If a finding needs a fix, the fix is a new head the tag does not point to: bump the version and tag again- npm does not have it (failed in
prepareorpublishfor any other reason): nothing shipped. Fix it, bump the version, and ship again with a new tag - npm has it but
mergefailed: the version is alreadylatestwhile main lacks it. The owner decides whether to putlatestback by runningnpm dist-tag add sphica@<previous good version> latestin their own terminal (the!prefix is only for this session's input box; in a shell,!inverts the exit code). That command asks for an OTP, which fails in a shell without a TTY such as Claude's. Fix the PR and ship a new version; never reuse the published one finishfailed after the merge: nothing is published again. If npm still did not serve the version after finish's wait, wait a few more minutes, then rerun the failed job withgh run rerun <run-id> --failed(creating the Release is skipped when it exists), or run the failed check by hand with the commands in step 8- Do not rerun
publishafter it succeeded refresh-scanswarned that a dispatch failed, or a scan run it started failed: npm and the merge are done, so nothing is released again. Start the scan on main by hand withgh workflow run <osv-scanner.yml or scorecard.yml> --repo iroha924/sphica --ref mainand watch that run
So that the marketplace never points to an unpublished version, the run publishes before it merges (steps 6 then 7).
Confirming it arrived
Claude runs every step here on the owner's machine, including the backup and moving an old-generation DB aside. Do not hand the owner a list of
commands (measured 2026-09-26: handed over, the owner answered that only /reload-plugins is theirs). The owner runs only /reload-plugins
in open sessions. sphica doctor shows "npm package versions" and "Plugin channel versions" separately.
- Run
npm i -g sphica@<version>. The CLI installed withnpm i -gis a separate path from the plugin cache, and host updates do not upgrade it. In a release that raised the DB revision, forgetting this leaves only the old CLI failing with "expects revision N" (measured: after moving to revision 5, the global CLI stayed at 0.32.0). Run it from the home directory too (cd ~ && npm i -g sphica@<version>): with a per-directory Node (mise),npm i -ginside this repository installs only into the Node itsmise.tomlpins, andsphicais then "command not found" everywhere else (measured 2026-09-28) - If the release changed the DB generation, copy
~/.sphica/sphica.db(with-waland-shm) to a dated backup, move it aside, and runsphica initin each registered repository (the old records are not carried over; say so in the report). A revision change within a generation needs the migrationknowledge-schemasays to design first A release that raises the revision migrates after step 3, not here. A connection checks the revision only when it opens, so a record server of the old version that is already running keeps saving into the migrated database, without what the new revision adds (after the move to revision 13 it would close a question and write nounit_answerrow). Update both plugins first (step 3), have the owner run/reload-pluginsin open sessions and close the others, then confirm withpgrep -fl mcp-recordthat no record server runs from the old version's cache. Codex starts it as./dist/mcp-record.jsfrom the plugin's directory, so its line shows no version: read that process's directory withlsof -a -p <pid> -d cwd. A list you cannot read, or a process whose version you cannot tell, is not "none": do not migrate. Only then runsphica initin each registered repository. Between the reload andinitthe read and record servers stop with "expects revision N"; capture keeps recording - Claude Code:
claude plugin marketplace update sphica && claude plugin update sphica@sphica. Codex:codex plugin marketplace upgrade sphica && codex plugin add sphica@sphica. Then ask the owner to run/reload-pluginsin open sessions. In sessions without an interactive terminal, MCP stays at the old version until the next session. In Codex, ask the owner to open/hooksand trust Sphica's hooks: Codex records trust per hook, so a hook added or changed by the update stays skipped until trusted (capture keeps running, which hides it) - In
sphica doctor, check that the npm package matches between the repository and the global CLI, that the plugin channel matches between the repository and both hosts' caches, and that no reconnect instruction remains for the running MCP - From a session after the update, call
statusandsearch, and check the contents of the changed MCP tools, Skills, and Agents. If capture changed, also check that this session's messages are found bysearchwithsources: true, and that the "Recording" line insphica doctorhas nothing waiting. If delivery changed, read and then edit a file with an anchored record and check the hook's context arrived (a read shows each record once per session) - Claude also runs the installed plugin headless, pointing
SPHICA_DBat a temporary database so the owner's~/.sphicais untouched: in a scratch repository with one anchored record,claude -p(a prompt that reads the file, and the user's own review command) andcodex exec(the same, after the owner trusted the hooks in/hooks;--dangerously-bypass-hook-trustshows only that the hooks work, not that they are trusted). Check the delivery rows, the first Sphica tool call, and the final answer. Report how many runs showed the behavior, not one run as proof Forcodex exec,SPHICA_DBis not enough: Codex starts MCP servers without it, soreadandsearchhit the owner's~/.sphica(measured 2026-09-27). Put the database at<tmp>/.sphica/sphica.dband run withHOME=<tmp>,CODEX_HOME=$HOME/.codex(the installed plugin and its trust), and the real Node directory first onPATH(mise shims look underHOME)
plugin/skills/review/reviewers/ also goes through the cache, so saving or restarting a session does not give the new text.
When changing aspects, read plugin-agent-authoring first too.
Plugin Skills
- For a Skill that should start only when explicitly called, pair
disable-model-invocation: truein SKILL.md (Claude Code) withpolicy.allow_implicit_invocation: falsein the Skill directory'sagents/openai.yaml(Codex). Codex does not read the former.verify:aichecks that Codex is never looser than Claude Code (it may be stricter, as trace is: Codex picks trace on its own only when the session-start notice names its file), and that the description says "Use only when the user explicitly asks" exactly for such a Skill (an agent decides from the description whether to start it) - Pre-approval of MCP tools in
allowed-toolsis unverified on a real host for the record server's tools. Check it after delivery withclaude -p "/sphica:<skill>" --plugin-dir <plugin> --permission-mode default --output-format jsonand an emptypermission_denials - When checking after delivery, confirm in Codex that the body is read when explicitly started with
$sphica:<skill>too
Check the human-facing CLI output and the AI-facing MCP replies separately.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

