Skillpack Publish + Registry + Install Spec (post-v0.36.0.0)
⚠️ Needs v0.36 realignment. This spec was written assuming the pre-v0.36 managed-block install model (which v0.36.0.0 retired in favor of scaffold + reference + harvest). The strategic decisions remain sound — third-party publish + registry + doctor + rubric + tarball + TOFU + sandbox + CI workflow split + anti-typosquat — but the verbs and integration points change:What stays verbatim: registry atthebuildceo/modusbrain-skillpack-registry, rubric, doctor, anatomy doc, tarball determinism, TOFU + SHA pinning, endorsement tiers, sandbox + env scrub, CI workflow split, anti-typosquat. Seedocs/guides/skillpacks-as-scaffolding.md(the v0.36 canonical model) for the contract this spec must align to before implementation. See [README at top of file for status; full spec preserved below as the strategic record.]
Context
After v0.36.0.0 (Hindsight Calibration), modusbrain has a mature skillpack system — but it only knows how to install the one bundle declared inopenclaw.plugin.json at modusbrain’s own repo root. We want to ship a
“hackathon-evaluation” skillpack as a standalone artifact, any modusbrain user
should be able to discover + install it, and the ecosystem should grow
without hand-curating every README. That requires five new capabilities:
- Publish — a documented repo layout + manifest format that anyone can point a git repo at and call “a skillpack.”
- Distribute — a transport from one user’s machine to another. Git + tarball, no centralized hosting infra.
- Install — extend
modusbrain skillpack installto accept a third-party source, with trust posture appropriate for installing markdown/SKILL.md files into a workspace that an agent then routes through. - Discover + curate — a canonical catalog at
github.com/thebuildceo/modusbrain-skillpack-registry(the Printing Press library pattern) with endorsement tiers, security gating, and programmatic search. Third-party packs live in their authors’ repos; the registry is aregistry.jsonmanifest pointing at them. - Cross-distribute — list in
mvanhorn/printing-press-libraryas a sister registry, AND use Printing Press to generate an agent-native CLI wrapper around modusbrain’s HTTP MCP so non-modusbrain agents can hit a modusbrain instance remotely. Doubles the discovery surface.
modusbrain skillpack install hackathon-evaluation
resolves through the registry, clones the source repo (or fetches the
pinned tarball), validates the manifest, drops the skill files into the
workspace, and routes them via RESOLVER.md / AGENTS.md — same code paths as
the bundled install today, just with a remote source and a registry catalog
in front.
Landscape (informs every design choice below)
agentskills.iois the open SKILL.md standard adopted across Claude Code / Codex / Cursor / Gemini CLI / OpenClaw. The format is solved.- ~2,500 Claude Code marketplaces already exist (claudemarketplaces.com). Hosting is solved 2,500 times over. The moat is curation + quality bar.
- 13% of skills in existing marketplaces carry critical vulnerabilities (per tech-leads-club, May 2026). Security gating at publish time is a real differentiator, not a vanity feature.
mvanhorn/cli-printing-press(~1.4k stars) splits the engine from the library exactly the way this plan proposes. The publish-skill pattern (/printing-press-publish) is the load-bearing UX move — no contributor hand-runs git. We replicate it.- modusbrain skillpacks have a runtime contract (they assume
modusbrain query,put_page, sources, takes, hindsight calibration). They are not portable to a generic agent harness without modusbrain installed. That’s what justifies a dedicated registry instead of mirroring agentskills.io — the validation surface is modusbrain-shaped.
Today’s baseline (what exists, won’t be re-built)
BundleManifestschema insrc/core/skillpack/bundle.ts:13-20(name,version,description,skills[],shared_deps[],excluded_from_install?[]). Reuse + extend; do not re-invent.installer.ts:259-293— cumulative-slugs receipt embedded in the managed block (<!-- modusbrain:skillpack:manifest cumulative-slugs="..." version="..." -->). Single source of truth for “what’s installed from modusbrain.”installer.ts:376-402— per-file byte-compare gate before install / uninstall (D11). Refuses to clobber user edits without--overwrite-local.installer.ts:180-253— atomic lockfile with 10-min stale threshold and PID liveness check. Concurrency safety.src/core/git-remote.ts— SSRF-hardenedcloneRepo/pullRepowithhttps://-only scheme allowlist, no submodules, no redirects, noprotocol.file/protocol.ext. Same primitive remote-sources uses.src/core/url-safety.ts:isInternalUrl— blocks RFC1918 / CGNAT / metadata-IP / IPv6-loopback. Already wired throughparseRemoteUrl.src/core/resolver-filenames.ts— RESOLVER.md / AGENTS.md filename fallback chain. Per-skill rows live in a managed block inside one of these files.
Recommended design
Distribution: git + tarball, v1
A skillpack is a git repo withskillpack.json at root + a skills/
directory. A .tgz of that same tree is an offline-transportable form
of the same thing. Both paths land in the same installer.
modusbrain skillpack install <owner>/<repo>— clones via existinggit-remote.tsSSRF-hardened path.modusbrain skillpack install <url.git>— verbatim https URL.modusbrain skillpack install <path/to/pack.tgz>— extract to cache dir, install from extracted tree. Useful inside corporate orgs / corp networks that block direct GitHub access, or for air-gapped distribution.modusbrain skillpack install <path/to/repo>— local path (skill authors testing).modusbrain skillpack pack [--out <path>]— publisher-side command that validates the manifest, runs the fullpack --dry-runpipeline, and emits<name>-<version>.tgz. SHA-256 of the tarball is recorded in the TOFU receipt so re-install of the same tarball is silent, but a tampered tarball with the same filename fails loud.- Tarball schema: gzipped tar with
skillpack.jsonat the top level andskills/...beneath it. No symlinks, no executables, no dotfiles outside an allowlist (.gitignore,.gitattributes). Validator runs on extract.
enumerateBundle + applyInstall pipeline runs.
Registry: github.com/thebuildceo/modusbrain-skillpack-registry
A separate git repo Shubham controls. Not a hosting layer — a catalog. Skillpacks live in their authors’ own repos; the registry points at them. Two files at the registry repo root:-
registry.json— the live catalog. Schema: -
endorsements.json— Shubham-controlled. The single source of truth for which entries get theendorsedtier. Decoupling the endorsement decision from the catalog write means a contributor’s PR can land a catalog entry at thecommunitytier; promotion toendorsedis a separate, smaller, Shubham-only commit.
endorsed— Shubham has used it, it works, it’s in his pinned set. Listed first inmodusbrain skillpack searchoutput. Manual promotion.community— passed the publish-gate validation, lives in the catalog, but Shubham hasn’t personally vetted it. Default tier on first PR.experimental— author self-flagged as in-development. Listed last, with a stderr warning at install time.
--url defaults to https://raw.githubusercontent.com/thebuildceo/modusbrain-skillpack-registry/main/registry.json.
Operators inside corp networks can point at a fork. The registry URL is
recorded in ~/.modusbrain/config.json under skillpack.registry_url.
modusbrain skillpack install starter-pack resolves a special bundles array
in registry.json (a named list of skillpack names) and installs each in
order. Shubham curates the starter pack.
First-install identity confirm + anti-typosquat (codex G4):
modusbrain skillpack install <name> on first install of a given source
surfaces a confirm prompt with full identity:
--trust flag and prints the same
block to stderr.
Subsequent installs of the same <author>/<name> pair at the same
pinned commit + tarball SHA skip the prompt (already trusted).
Different pinned commit re-prompts. Different author with the same
name re-prompts (someone may have transferred / forked the pack).
Registry-side anti-typosquat gate: the publish-gate (post-merge
workflow) rejects new submissions whose name is within Damerau-
Levenshtein edit-distance 2 of any existing endorsed-tier pack
name. Community-tier packs do NOT block (the registry shouldn’t be
the typosquat arbiter for low-tier packs; the install-time confirm
is the user-facing defense). Effort: ~0.5d to wire the distance check
into the validate-pr.yml manifest scan; uses an off-the-shelf
distance algorithm (no external dep).
Bundle atomicity contract (per eng-review D3): per-pack independent.
Each pack in a bundle install is its own transaction in the managed
block. Mid-bundle failure leaves earlier successful packs installed,
skips later packs, and prints a summary:
endorsements.json with schema validation. Hand-editing remains
possible (it’s just JSON), but the command is the canonical path.
thebuildceo/modusbrain-skillpack-registry. Steps:
- Read + validate current
endorsements.jsonagainst the schema. - Confirm
<name>exists inregistry.json. - Update or insert the entry with the new tier.
- Write back with stable key ordering (so diffs are clean).
- Stage + create a one-line conventional commit:
endorse: <name> -> <tier>. - If
--push, push tomain. Otherwise print “now run git push” hint.
Publish-gate skill: /modusbrain-skillpack-publish
Mirrorsmvanhorn/cli-printing-press’s /printing-press-publish exactly.
No contributor hand-runs git. The skill drives:
-
Local validation (
modusbrain skillpack pack --dry-run):skillpack.jsonschema check- SKILL.md frontmatter on every listed skill
- File-type allow-list (no
.env,.ssh,.pem, no executables) - Slug-collision sweep against the live
registry.json modusbrain check-resolvablecleanmodusbrain routing-evalclean (structural layer)
-
Security gates (publish-gate v1, see decision Q3):
- Static analysis on any embedded scripts (shellcheck for
.sh, a heuristic JSON/YAML safety pass on data files) - Dependency declaration check — every external resource referenced
in SKILL.md must be in a declared
external_resources:array - Trial install: extract pack into a tempdir, run
modusbrain skillpack install <tempdir>against an ephemeral PGLite-backed modusbrain (mirrors thetest/e2e/longmemevalephemeral-PGLite pattern atsrc/eval/longmemeval/harness.ts), assertmodusbrain check-resolvablestays clean and the skill rows appear in the managed block. - Trial install runs with
MODUSBRAIN_SKILLPACK_SANDBOX=1, which disables any operation that writes outside the workspace or hits the network.
- Static analysis on any embedded scripts (shellcheck for
-
Test + eval suite execution (DX-review decision: run everything
in the sandbox so endorsement signals are measurable):
- Unit tests: walk every
unit_tests[]glob inside the sandbox, run viabun test, collect pass/fail per file. - E2E tests: if a
DATABASE_URLis exposed inside the sandbox (Linux:unshare’d PG socket; macOS: docker-bridged); skip-gracefully when not. - LLM-judge evals: load each
*.judge.json, run the cross-modal pipeline with__setChatTransportForTestsstubbed gateway so the publisher pays zero LLM cost during the publish gate. The publisher ran real-gateway evals before submitting; the validation log links to their results. Sandbox re-runs against the stubbed gateway prove the pipeline runs end-to-end and the eval JSON is well-formed. - Routing evals: structural matching via the existing
modusbrain routing-evalcommand. Asserts everyintentinrouting-eval.jsonlresolves to the declaredexpected_skillgiven the skill’striggers:frontmatter. - Coverage score: published as a single percentage in the
validation log. Drives tier eligibility:
endorsed: routing + runbooks + >=95% pass.community: routing + install runbook + >=80% pass.experimental: anything that passes structural validation.
- Failed eval / test surfaces actionable line: each failure
in the validation log includes the file path, the assertion, and
a paste-ready re-run command (
bun test <file>ormodusbrain routing-eval skills/<name>/routing-eval.jsonl).
- Unit tests: walk every
-
Tarball + hash:
modusbrain skillpack pack --out skillpack-<name>-<version>.tgz- SHA-256 recorded for registry pin
-
Registry PR (Printing Press pattern verbatim):
- Fork
thebuildceo/modusbrain-skillpack-registryif not already forked - Branch
add-<name>-<version> - Append catalog entry to
registry.jsonwith tier=community, pinned commit, tarball SHA-256, validated_at timestamp, and avalidation_run_idthat points at a JSON log committed to avalidation-runs/<run-id>.jsonfile under the registry repo so anyone can audit what was checked - Open PR against
thebuildceo/modusbrain-skillpack-registry:mainwith the validation log in the body - Stretch: Shubham’s
endorse <name>command flips the entry toendorsedvia a one-line commit onendorsements.json
- Fork
skills/modusbrain-skillpack-publish/SKILL.md. Invokable from any agent
harness that loads modusbrain skills.
Printing Press cross-distribution
Two-direction integration (decision Q2):- Cross-list: open a PR against
mvanhorn/printing-press-libraryregisteringthebuildceo/modusbrain-skillpack-registryas a sister-registry in their catalog (their library has asister_registries:section per their AGENTS.md). Their 1.4k-star audience discovers modusbrain through the same search surface they already use. - Generate: run
printing-press printagainstmodusbrain serve --http’s OpenAPI spec (modusbrain’s HTTP MCP exposes a JSON-RPC surface with stable tool definitions). The output is amodusbrain-cliagent-native binary with SQLite mirror that any agent — not just modusbrain users — can use to hit a remote modusbrain. Submitted back tomvanhorn/printing-press-libraryas a published CLI, credited to Shubham. Doubles distribution surface and turns modusbrain into something Printing Press users can route through.
Manifest schema: skillpack.json (cathedral artifact)
A modusbrain skillpack is a full software package, not just markdown.
Same shape as npm/cargo: code, tests, evals, runbooks, changelog. This
is the differentiation moat per the DX review: nobody else ships AI
evals and agent-readable install/upgrade runbooks as first-class
package artifacts.
api_version— forward-compat key; installer refuses unknown. Schema isgbrain-skillpack-v1. Codex outside-voice gap: singleapi_versiondoesn’t cover runbook/eval/sandbox schema evolution. Manifest also carriesrunbook_schema_version(default 1) +eval_schema_version(default 1). Installer accepts a configured range per dimension; rejects manifests declaring a newer schema than the local modusbrain supports with a paste-readymodusbrain upgradehint. Refuses silent downgrade.modusbrain_min_version— fail-fast version gate (existing semver helper).name— must match the directory name; unique in registry namespace.skills[]— relative paths from repo root; same as today’senumerateBundle.unit_tests[]— glob(s) discovered in the sandbox and run during the publish gate. Pure Bun unit tests, no DB.e2e_tests[]— glob(s) for integration tests. Run ifDATABASE_URLis reachable inside the sandbox (skip-gracefully otherwise).llm_evals[]— cross-modal eval configs in the modusbrain v0.27.x format (task/output prompt with multi-model judging). Run with a stubbed gateway in the publish-gate sandbox so no real API spend; the publisher’s machine runs real-gateway evals before submitting.routing_evals[]—routing-eval.jsonlfiles with{intent, expected_skill, ambiguous_with?}rows. Structural matching against the skill’striggers:frontmatter. The single highest-leverage eval type for an agent-routed skillpack: proves user phrases actually fire the right skill.runbooks.{install, uninstall}— agent-readable markdown (see format below).runbooks.upgrades— glob expanding toupgrade-<from>-to-<to>.mdfiles; the agent picks the right one based on the version recorded in the resolver receipt.changelog— required; the agent surfaces “what changed” at upgrade time directly from this file.
endorsedtier requires: routing-evals AND runbooks AND >=95% pass on declared tests + evals.communitytier requires: routing-evals AND install.md AND >=80% pass on declared tests + evals.experimentaltier accepts anything that passes structural validation.
experimental only.
The publish-gate emits a one-line score summary so the publisher sees
exactly what’s blocking promotion.
Install/upgrade trust model: per-step approval, not auto-walk (codex T1)
The DX review’s first cut hadmodusbrain skillpack install <name> auto-
walk runbooks/install.md after dropping files. Codex pointed out
that this runs trusted-path (remote=false) modusbrain CLI calls against
the user’s brain on every install — a malicious community-tier pack
mutates brain state on first install. v1 fix: runbook executor
defaults to per-step approval.
modusbrain skillpack install <name>ALWAYS drops files + updates the resolver block. That part is content-only; the trust gates (TOFU- content-hash + endorsement tier) already cover it.
- After file-drop, if
runbooks/install.mdexists, the install command prints each step + waits for explicit y/N on a TTY. Three step kinds (agent:,show user:,ask user:) all surface the literal text before execution. --runbook-apply-allflag bypasses the per-step prompt for CI / unattended agent use. Loud stderr line on first use:[skillpack] applying runbook unattended; this skillpack is community tier — confirm trust by inspecting <pack-dir>/runbooks/install.md.--runbook-skiplands the files without executing any runbook step (the publisher gets file-drop only; everything else is the user’s decision).endorsedtier eligible for an auto-walk-after-N-installs UX in v1.1 (after the user has confirmed N runbook walks of that pack succeed, prompt drops). Out of scope for v1.
Agent runbook format (runbooks/install.md, uninstall.md, upgrade-*.md)
Mirrors modusbrain’s ownskills/migrations/v0.21.0.md pattern — markdown
that an agent reads top-to-bottom and executes step-by-step.
agent:— the calling agent runs the command verbatim.show user:— display the message to the user (no action).ask user:— require user confirmation; the next step is gated.
upgrade-<from>-to-<to>.md) follow the same shape
with extra frontmatter (from_version, to_version) so the
upgrade-walker picks the right runbook when stepping multi-version
upgrades (e.g., v0.1 → v0.2 → v0.3 walks two runbooks in sequence).
Quality rubric + doctor + reference pack
A skillpack is only as good as the agent’s ability to tell whether it’s ready. Three artifacts close the loop: 1. Declarative rubric —src/core/skillpack/rubric.ts
Single source of truth. The doctor walks it; the anatomy doc is
auto-generated from it; tests pin every dimension. When the rubric
evolves (v1.1 adds dimensions, v2 changes scoring), one file moves
and docs stay in sync. Same pattern as gstack’s
scripts/question-registry.ts.
10/10→ endorsed-eligible (paired with the publish-gate’s >=95% test+eval pass)8-9→ community-tier eligible, doctor prints paste-ready fixes for the misses5-7→ experimental-tier only, doctor lists required fixes<5→ doctor refuses to score, prints “this isn’t a skillpack yet — runmodusbrain skillpack initand try again”
modusbrain skillpack doctor
Two modes; the agent picks which one based on workflow phase:
--quick(default): structural-only sweep. Walks the rubric. ~5 seconds. No sandbox, no LLM, no DB. The right command during iteration — save a file, run doctor, see your new score.--full: equivalent tomodusbrain skillpack pack --dry-run— runs the sandbox, the tests, the LLM-judge evals, the routing-evals against a trial install, the security gates. ~minutes. The right command before invoking the publish skill.--fix: auto-scaffold missing pieces. Callsmodusbrain skillify scaffoldfor missing skills, drops runbook stubs from templates, generates a CHANGELOG entry from VERSION + git log. Destructive on the file tree: prints"this will create the following N files, proceed? [y/N]"confirm prompt; non-TTY requires explicit--yes. Refuses to overwrite any file whose mtime is newer than the manifest’s modified-at (heuristic for “user hand-edited this”).--json: stable JSON envelope for agent consumption.
docs/skillpack-anatomy.md AND in
skills/_brain-filing-rules.md):
- After every meaningful edit during pack development:
modusbrain skillpack doctor --quick --json. Target a 10/10 before ever invokingpack --dry-run. - Before publishing:
modusbrain skillpack doctor --fullto catch what the structural pass can’t. - If doctor flags
auto_fixable: truedimensions, the agent runsmodusbrain skillpack doctor --fix --yesand re-runs--quick.
experimental; it just shows visible
“no-badges” flags in the registry so consumers can decide.
Required core (5 dimensions): manifest_valid, skills_have_skill_md,
routing_evals_present (>=5 intents per skill), check_resolvable_clean,
changelog_present_and_current. Quality badges (5 dimensions):
routing_evals_clean (LLM-judge layer), unit_tests_present,
llm_eval_present, install_runbook_present, uninstall_runbook_present.
The doctor still reports a 10/10 score (badges are display +
tier-gating, not rubric-replacement). A publisher who stubs all 5
badges with empty fixtures gets a visible “stubbed-eval-detected”
flag from the publish-gate’s content scan (e.g., 0 unique assertion
strings in an eval, or a passing test with no
expect() calls).
Cathedral scaffold from modusbrain skillpack init still drops all 10
dimensions by default; the floor for publish is lower.
3. Reference pack + anatomy doc
examples/skillpack-reference/— a real, working 10/10 pack living in the modusbrain repo. Doubles as an integration-test fixture for the doctor + publish-gate test suite. Includes 2 skills, 2 routing-eval.jsonl files, 3 unit tests, 1 LLM-judge eval, full runbook set, CHANGELOG.bun run buildincludescd examples/skillpack-reference && modusbrain skillpack doctor --quickas a pre-commit assertion so the reference pack never regresses.docs/skillpack-anatomy.md— one-page reference. Tree diagram + rubric table + paste-ready commands. Auto-generated fromsrc/core/skillpack/rubric.tsviabun run build:skillpack-anatomy. Diagram + tree are hand-curated; rubric table is machine-generated; CI fails if generated section is out of sync.
openclaw.plugin.json set, plus
any future bundles like starter-pack, founder-pack) MUST score
10/10 on modusbrain skillpack doctor --quick. This is a regression
guard, not a target:
scripts/check-bundled-skillpacks-rubric.shruns in CI andbun run verify. Iterates every pack the modusbrain repo ships and runsmodusbrain skillpack doctor --quick --json, asserts every score is 10.- New modusbrain releases that drop a bundled-pack score below 10 fail
CI loud. The cost of fixing is a few
modusbrain skillify scaffoldcalls; the cost of skipping is that modusbrain ships skillpacks that fail the bar modusbrain demands of third parties — credibility-poison. - Today’s openclaw.plugin.json set is not yet at 10/10 (no per-skill unit tests, no LLM-judge evals, no runbooks). Bringing it to 10/10 is in-scope for v1 — wave W4.5 (added below).
Scaffold: modusbrain skillpack init <name> (cathedral defaults)
Lands the complete tree out of the box. modusbrain skillpack pack --dry-run
on the scaffold passes immediately; developer deletes what they don’t
need.
modusbrain init which seeds
configuration + storage tiers + a starter source instead of asking
the user 15 questions.
Slug collision: auto-suffix, agent-resolves
Agents are the primary installer. Forcing them to pick a side on every collision adds friction without adding safety. Auto-resolve instead:- Flat namespace, auto-suffix on collision. When the incoming pack
ships a slug already claimed by a different installed source, the
installer appends
-2(then-3, etc.) to the incoming slug and proceeds. Loud stderr line:[skillpack] renamed judge-submission → judge-submission-2 (collides with hackathon-judging). - Suffix is durable, not cosmetic. The renamed slug goes into the
source’s per-source
cumulative-slugsreceipt AND a siblingrename-map="judge-submission:judge-submission-2,..."attribute on the source sub-header. Uninstall reads the rename map and removes the suffixed file + row, never the original. - Triggers (the user-facing routing surface) are untouched. Slugs are
identifiers; agents route via the SKILL.md
triggers:frontmatter and the RESOLVER.md description column. A renamed slug still matches the same user phrases. - Reserved suffix range.
-2..-99is the auto-rename range. A pack authored withjudge-submission-2as its own canonical name (rare) still installs fine; collision logic only fires on the bare-name collision, and a subsequent collision onjudge-submission-2itself walks to-3. The collision-walk is bounded at-99and fails loud beyond that (defensive cap; you don’t have 99 packs shipping the same slug).
check-resolvable, routing-eval, or
filing-audit — they all parse whatever slug they see, no namespacing
required.
Install state: ~/.modusbrain/skillpack-state.json (codex G1)
The DX-review-locked design had TOFU SHA-256, pinned commit, rename
maps, and per-source receipts living inside markdown comments in the
RESOLVER.md managed block. Codex flagged that as a fragile trust
store — any agent or human edit to the resolver file silently
corrupts provenance. v1 fix: split human-readable rows from machine-
owned state.
~/.modusbrain/skillpack-state.json(machine-owned, agent-readable): the source of truth for TOFU SHA-256, pinned commit, source URL, rename map, install timestamp, version, tier_when_installed, endorsement-tier-at-install. One entry per installed source. Atomic update via.tmp+rename(). Read on every install / uninstall / update; resolver block is rendered from this.- Resolver-block sub-headers (in RESOLVER.md / AGENTS.md) carry only
human-readable identity:
name,version,tier, and the cumulative-slugs list (still needed for uninstall to know what to remove without consulting state.json — defense in depth against a corrupted state.json). Receipt comment shape:<!-- modusbrain:skillpack:source name="..." version="..." tier="..." cumulative-slugs="..." -->. - Mismatch between state.json and resolver-block (e.g., resolver lists
a source not in state.json, or state.json’s cumulative-slugs differs
from the rendered rows) fails loud at install-time and refuses
further mutations until reconciled by
modusbrain skillpack reconcile. - Schema:
skillpack-state.jsonhasschema_version: "modusbrain-skillpack-state-v1"for forward-compat; mirrors the installer.ts cumulative-slugs receipt evolution story.
Resolver-block: one block per source
The managed block in RESOLVER.md / AGENTS.md grows a source-keyed sub-section header so multiple packs can coexist without rewriting the whole block on every install. Cumulative-slugs receipt is per-source:tofu-sha256 is the resolved-commit SHA (git source) or tarball SHA-256
(tarball source). Re-install / update compares the new resolution against
the recorded value; mismatch = re-prompt (TTY) or refuse without
--update (non-TTY).
Per-source receipt means uninstalling one pack doesn’t touch another pack’s
rows or D11 hash budget.
Trust posture
- Default: TOFU. First install of a given repo URL prompts via
AskUserQuestion-equivalent CLI flow (“you are about to install skillpack<name>from<url>at commit<sha>. Trust this source?”). TTY-only; non-TTY requires explicit--trustflag. - Pin the commit SHA into the per-source resolver receipt. Re-install
/ upgrade refuses to silently advance the SHA without user consent (same
prompt or
--update). --allow-private-remotesflag pipes through togit-remote.ts’sMODUSBRAIN_ALLOW_PRIVATE_REMOTESfor internal/Tailscale skillpacks.- Signing (minisign / cosign) is a v2 escape hatch; not in scope for v1.
CLI surface
<source> accepts:
garrytan/repo→https://github.com/garrytan/repo.githttps://github.com/.../...git→ verbatim, SSRF-checked./path/to/pack.tgz→ tarball; extract to cache, install from tree./path/to/repo→ local filesystem dir (for skill authors testing locally; same trust posture as today’s--skills-dir)
Publisher workflow (the “make a skillpack” path)
modusbrain skillpack init <name>— scaffoldsskillpack.json+skills/+RESOLVER.md(skillpack-internal) +.gitignore.- Author writes skills using existing
modusbrain skillify scaffoldpatterns. modusbrain skillpack pack --dry-run— runs the full validate pipeline:skillpack.jsonschema check- every listed skill has SKILL.md + valid frontmatter
modusbrain check-resolvablecleanmodusbrain routing-evalclean (structural layer)- no banned file types in any skill dir (no
.env,.ssh, executables) - returns structured pass/fail JSON
git pushto publish. Distribution is the git remote.
Critical files to add / modify
New
src/core/skillpack/manifest-v1.ts— Zod-equivalent runtime validator forskillpack.json. Owns theSkillpackManifesttype.src/core/skillpack/remote-source.ts— wrapsgit-remote.tsfor the skillpack use case: shallow clone to a cache dir under~/.modusbrain/skillpack-cache/<host>/<owner>/<repo>/<sha>/, resolves HEAD SHA, supports update viapullRepo.src/core/skillpack/tarball.ts—packTarball(dir, outPath)+extractTarball(tgzPath, cacheDir). Tar entries validated against allowlist (no symlinks, no executables, no traversal). SHA-256 computed on the gzipped output for TOFU pinning. Deterministic tarball spec (codex outside-voice gap): SHA-256 is only stable if the tarball is byte-deterministic. The packer enforces: (a) entries sorted by path (lexicographic), (b) all mtimes fixed to1970-01-01T00:00:00Z(or the commit’s mtime if available, but reproducibly), (c) uid=0/gid=0, mode normalized (0644 for files, 0755 for directories), no pax headers, (d) gzip withmtime=0, no original-filename header. Reject on extract: symlinks, hardlinks, device files, FIFOs, any non-regular non- directory entry. Caps on extract: max 5000 files, max 100MB decompressed total, max 1MB per file, max path length 255 chars, max compression ratio 100:1 (compression-bomb defense). Pinned bytest/skillpack-tarball-determinism.test.ts(pack the same dir twice on different days → same SHA).src/core/skillpack/collision-resolver.ts— pure functionresolveSlugCollisions(incoming: string[], existing: Set<string>): { finalSlugs: string[], renameMap: Record<string,string> }. Bounded walk to-99. Pinned by unit tests.src/core/skillpack/multi-source-receipt.ts— parse + serialize the per-source resolver-block sub-headers. Pure functions; pinned by tests.src/core/skillpack/trust-prompt.ts— TOFU prompt + TTY/non-TTY branching. Mirrors v0.32.4 install-picker prompt shape.src/core/skillpack/registry-client.ts— fetch + cache the liveregistry.jsonover HTTPS. HonorsIf-None-Matchetag for cheap polling. Validates schema before use. Caches under~/.modusbrain/skillpack-cache/registry-<sha256-of-url>.jsonwith a 1-hour soft TTL. Offline-safe: on fetch failure (network down, GitHub 5xx, DNS miss), falls back to the on-disk cache and emits a single stderr line per process:[skillpack] registry fetch failed, using cache from <fetched_at> (N hours old). If cache is >7 days old, the warning escalates tocache is stale, run 'modusbrain skillpack registry --refresh' when back online. Hard-fail only when there is no cache at all (first-run + offline).--no-cacheflag forces network and fails loud on miss. The cache file’sfetched_atis wall-clock time; clock skew is non-issue because we never compare cached fetched_at against the registry’supdated_atfor freshness — only against current wall-clock for age display.src/core/skillpack/registry-schema.ts— runtime validators forregistry.json+endorsements.jsonshapes. Single source of truth used by bothmodusbrain skillpack searchand the publish-gate skill.src/core/skillpack/sandbox.ts— subprocess-isolated trial-install harness with a per-platform fallback chain.- Linux:
bwrap → unshare → docker. Triesbwrap(bubblewrap) first — most portable, on every recent distro’s repo, ~100ms spinup. Falls back tounshare --net + --mountwhen bwrap is missing but the kernel allows unprivileged user namespaces (covers stock Debian/Ubuntu/Arch). Falls back todocker run --rm --network=none --volume <tempdir>:/work --workdir /workfor RHEL/Rocky/CentOS where unprivileged userns is disabled by sysctl. Pure-tree: no minimal Linux image without bwrap AND without docker — fails loud with a paste-ready apt/yum install hint. - macOS:
sandbox-exec → docker. Tries Apple’s built-insandbox-execfirst with a per-publish.sbprofile (filesystem write confined to tempdir, network denied, no IPC). ~50ms spinup. Falls back to Docker Desktop only whensandbox-execis unavailable (rare; Apple keeps deprecating it but hasn’t pulled it). macOS publishers without Docker can still publish via sandbox-exec. - Inside the sandbox, an ephemeral in-memory PGLite modusbrain runs the
trial install, reuses the pattern from
src/eval/longmemeval/harness.ts. ExposesrunTrialInstall(packPath, opts): Promise<TrialResult>consumed by the publish-gate. - Bun’s
child_processspawn with the chosen backend’s wrapper argv; abort signal kills the wrapper which cascades to the child. - Env scrub (codex G2): the spawned process inherits a CLEAN
env (only
PATH,LANG,TZpass through). Explicitly stripped:GITHUB_TOKEN,GH_TOKEN,OPENAI_API_KEY,ANTHROPIC_API_KEY,VOYAGE_API_KEY,GROQ_API_KEY, all*_API_KEY/*_TOKEN/*_SECRETvariables,SSH_AUTH_SOCK,SSH_AGENT_PID,GIT_*(no GIT_ASKPASS, no GIT_SSH),NPM_TOKEN,BUN_INSTALL_TOKEN, plus an explicit denylist defined as a pure-function constant insrc/core/skillpack/sandbox-env.ts. - HOME override:
HOME=<tempdir>/sandbox-home(empty dir). Side effects: no~/.modusbrainaccess, no~/.gitconfig(credential helper disabled), no~/.netrc, no~/.npmrc, no~/.bunfig.toml. The publish-gate’s PGLite + LLM-judge stubs were already designed to not need real credentials; this just enforces it. - Read-only mounts (bwrap / docker; sandbox-exec uses
deny-write profiles): only the pack tempdir is read-write; every
other path is read-only or unmounted.
/procmasked where bwrap supports it (--proc /proc --new-session). - Pinned by
test/skillpack-sandbox-env-scrub.test.ts: 8 cases asserting each known-credential env var is stripped, HOME is overridden, the denylist constant matches the test fixture.
- Linux:
src/core/skillpack/sandbox-profiles/macos.sb— sandbox-exec policy file (allow read/write only within${TEMPDIR}, deny network, deny process-fork beyond the trial-install Bun process, deny mach lookups except the minimum set Bun needs to start).src/core/skillpack/sandbox-probe.ts— pre-flight: detects which sandbox backend is available, in order. Emits a structuredSandboxBackend = 'bwrap' | 'unshare' | 'sandbox-exec' | 'docker' | 'none'discriminator. Backend choice persists per-process (avoid re-probing on every trial).modusbrain doctorsurfaces the chosen backend as info.src/core/skillpack/security-gates.ts— static-analysis pipeline.runShellcheck(files)(shells out if shellcheck is installed; degrades to a built-in regex pass naming the offending patterns when not),scanForbiddenFiletypes(tree),validateExternalResources(skill),checkFrontmatter(skill). Each returns structured findings.src/commands/skillpack-init.ts—modusbrain skillpack init <name>scaffold command.src/commands/skillpack-pack.ts—modusbrain skillpack packvalidator AND tarball emitter. Single command,--dry-runskips the tarball.src/commands/skillpack-info.ts+skillpack-update.ts.src/commands/skillpack-search.ts—modusbrain skillpack search <query> [--tier ...] [--json]reads the registry, ranks by tier then tag match, prints a table.src/commands/skillpack-registry.ts—modusbrain skillpack registry [--url X] [--refresh]show/set the configured registry URL, optionally force a fresh fetch.src/commands/skillpack-endorse.ts—modusbrain skillpack endorse <name> [--tier endorsed|community|experimental] [--push] [--dry-run]. Runs in a clone of the registry repo; validates<name>againstregistry.json; reads, updates, schema-validates, and writesendorsements.jsonwith stable key ordering; stages + commits with a one-line conventional-commit messageendorse: <name> -> <tier>; optionally pushes. Refuses if not inside a registry-shaped repo.src/core/skillpack/runbook-parser.ts— parsesrunbooks/install.md,uninstall.md, andupgrade-*.mdfiles. Validates frontmatter (runbook_kind,modusbrain_version_range,skillpack,skillpack_version, plusfrom_version/to_versionfor upgrades). Tokenizes each numbered step as one of three kinds:agent:/show user:/ask user:. Returns a strongly-typedRunbookvalue. Pure function; pinned by unit tests with malformed- runbook fixtures.src/core/skillpack/runbook-walker.ts— executes a parsed runbook against a calling context. Dispatches each step kind:agent:runs the modusbrain CLI subcommand (only modusbrain CLI; not arbitrary shell);show user:writes to stdout;ask user:blocks on a TTY confirm (non-TTY requires a--yesflag and refuses-confirmation steps cause failure). Returns a structuredRunbookResultso callers can see which steps ran. Test seam:opts.shellTransportlets tests drive without real subprocess spawn.src/core/skillpack/upgrade-planner.ts— given the resolver receipt’s recordedskillpack_versionfor a pack and the new version’supgrade-*.mdset, computes the upgrade walk path (e.g., v0.1 → v0.3 might walkupgrade-0.1-to-0.2.mdthenupgrade-0.2-to-0.3.md). Refuses if no path exists; refuses to downgrade silently; pure function.src/commands/skillpack-test.ts—modusbrain skillpack test [pack-dir]runs the publisher-side full test+eval suite OUTSIDE the publish gate so a publisher can iterate fast before invoking the publish skill. Real gateway (publisher pays the real LLM cost on their machine, not the publish gate). Outputs the same JSON shape the publish gate’s validation log uses, so the publisher sees exactly what the gate will see.src/commands/skillpack-init.ts(extended scope from earlier section) — scaffolds the full cathedral tree above.--minimalflag drops test/, e2e/, evals/ for power users who explicitly opt out.src/core/skillpack/rubric.ts— declarativeSKILLPACK_RUBRIC_V1array ofRubricDimension(see schema above). Pure-data + check functions that take a parsed pack and return{ passed: boolean, detail: string }. Single source of truth for doctor + anatomy doc + tests.src/core/skillpack/doctor.ts—runDoctor(pack, opts: {mode: 'quick' | 'full', fix: boolean, autoYes: boolean}): Promise<DoctorResult>. Walks the rubric, dispatches each check, computes score + tier eligibility, emits paste-ready fixes.--fixpath dispatches per-dimension auto-scaffold (callsmodusbrain skillify scaffoldfor missing skills, writes runbook stubs from a template baked into the bundle, generates CHANGELOG entries from VERSION +git log --since=<last-version-tag>). Refuses to overwrite files whose mtime is newer thanskillpack.json’s mtime (heuristic for “hand-edited since last manifest update”).src/commands/skillpack-doctor.ts— CLI wrapper. Reads flags, resolves the pack (file or dir or tarball), callsrunDoctor, formats JSON or human output. Exit codes: 0 if score=10, 1 if score 6-9, 2 if score 0-5 or refused.scripts/build-skillpack-anatomy.ts— generates the rubric-table section ofdocs/skillpack-anatomy.mdfromsrc/core/skillpack/rubric.ts.bun run build:skillpack-anatomy. CI guardscripts/check-anatomy-fresh.shruns inverifyto detect drift between rubric and committed doc.scripts/check-bundled-skillpacks-rubric.sh— CI guard. Walks every bundled skillpack (today:openclaw.plugin.jsonset; future: anyexamples/skillpack-*and any bundled starter pack), runsmodusbrain skillpack doctor --quick --jsonagainst each, asserts score=10. Fails the build loud on regression. Wired intopackage.json’sverifyscript.
New (in github.com/thebuildceo/modusbrain repo, examples + docs)
examples/skillpack-reference/— a real, working 10/10 reference skillpack that lives in the modusbrain repo. Two skills, 2 routing-eval.jsonl files (5 intents each), 3 unit tests, 1 LLM-judge eval (3 cases), full runbooks (install / uninstall / upgrade-template), CHANGELOG, README, LICENSE. The reference pack is the integration-test fixture for the doctor + the publish-gate full-suite E2E test, AND it’s whatmodusbrain skillpack doctor --quickis regression-tested against.docs/skillpack-anatomy.md— one-page agent + human reference. Contains: (a) tree diagram of the cathedral scaffold, (b) auto- generated rubric table fromrubric.ts, (c) paste-ready commands for every step frominit→doctor --quick→doctor --fix→pack --dry-run→publish. Auto-generated header + manual prose- auto-generated rubric body; a marker block guards the generated section.
src/core/skillpack/audit.ts— JSONL audit at~/.modusbrain/audit/skillpack-YYYY-Www.jsonl(ISO-week rotated, mirrorssrc/core/audit-slug-fallback.ts+src/core/rerank-audit.ts).logSkillpackEvent({event, source_kind, name, version, pinned_commit, tier_when_installed, outcome, error?})called by install / uninstall / update / search-resolve paths. Best-effort — never throws, logs stderr warning on write failure.readRecentSkillpackEvents(days)is the readback path formodusbrain doctor’s newskillpack_activitycheck (info-level: “installed N packs in the last 7 days, all from endorsed tier” or “installed 2 community-tier packs in the last 24h — review at <audit-path>”).skills/modusbrain-skillpack-publish/SKILL.md— the publish-gate skill itself. Lives in the bundled skillpack so every modusbrain install ships with it. Walks the contributor through:- Validate locally (
modusbrain skillpack pack --dry-run) - Run security gates
- Pack tarball + compute SHA
- Fork
thebuildceo/modusbrain-skillpack-registryif needed (gh repo fork) - Branch, append catalog entry, commit validation-run JSON
- Push + open PR via
gh pr create - Print the PR URL and remind the contributor “Shubham endorses separately; check back for the tier flip.”
- Validate locally (
New (in github.com/thebuildceo/modusbrain-skillpack-registry, separate repo)
registry.json— the catalog (schema above)endorsements.json— Shubham-only file controlling theendorsedtiervalidation-runs/<run-id>.json— one file per published validation, immutable, content-addressable. Anyone auditing a skillpack can pull the corresponding run JSON.tarballs/<name>-<version>.tgz— registry-mirrored tarball, written by CI at PR-merge time as the durable copy. Each tarball is content-addressed by the SHA-256 already recorded inregistry.json. Tarballs use git LFS to keep the registry clone small (a 1GB registry would be miserable to clone). Per-pack soft cap of 5MB; packs larger than 5MB are stored as link-only (the registry entry records asource_only: trueflag and skips the tarball mirror).- CI durability job (
.github/workflows/mirror-tarball.yml): on every PR merge, clones the pinned commit of the new entry, regenerates the tarball, verifies it matches the registry’s recorded SHA-256, then commits totarballs/. Belt-and-suspenders: if the source-repo SHA was a lie at PR-time, the mirror job fails loudly and the registry entry is reverted. - CI liveness job (
.github/workflows/liveness-check.yml): weekly, walks every registry entry and verifies the source URL still resolves to the pinned commit. Unreachable entries get alast_alive: <date>field but are NOT auto-tombstoned — Shubham decides whether to deprecate. README.md— explains the tier system, links to the publish skill, documents how to fork + submit- Two-workflow CI split (codex G3) — registry-side CI separates
static-only PR validation from any dangerous execution:
.github/workflows/validate-pr.ymlruns onpull_request(NOTpull_request_target). Permissions:contents: read, pull-requests: readonly. NO GitHub token write scopes, NO LFS write, NO repo PAT. Does: manifest schema check, file-type allowlist scan, slug uniqueness vsregistry.json, dependency declaration check. Pure static. Cannot exfiltrate anything because it has nothing to exfiltrate..github/workflows/post-merge-validate.ymlruns onpushtomainwith the new entry’s commit. Permissions:contents: write(only for the new tarballs/ file). Executes the publish-gate’s test + LLM-judge-stub + routing-eval suite inside the registry’s own sandbox (samebwrap/sandbox-execprofile documented above; same env-scrub posture). If validation fails after merge, the workflow opens a follow-up PR reverting the registry entry and posts a comment naming the failure. Slow path but isolated..github/workflows/mirror-tarball.yml(third workflow): runs afterpost-merge-validate.ymlpasses, with a deploy key scoped totarballs/only. Commits the SHA-256-verified tarball. Cannot writeregistry.json,endorsements.json, or anything outsidetarballs/.- The standard supply-chain posture: PR-time = static, never executes contributor code. Post-merge = isolated, never has privileged tokens. Mirror commit = least-privilege deploy key.
bundles.json(or abundlessection inregistry.json) — named bundles likestarter-pack,founder-pack,journalist-packtest/skillpack-manifest-v1.test.ts,test/skillpack-multi-source-receipt.test.ts,test/skillpack-remote-source.test.ts,test/skillpack-collision-resolver.test.ts(covers-2walk, the pack-authored--2corner case, the-99cap),test/skillpack-tarball.test.ts(round-trip, allowlist enforcement, symlink rejection, SHA-256 stability),test/skillpack-pack.test.ts,test/skillpack-registry-client.test.ts(etag handling, schema rejection on malformed registry, stale-cache behavior, network-down graceful fallback to last good cache),test/skillpack-registry-schema.test.ts(every tier valid, missing required field caught, unknown tier rejected),test/skillpack-search.test.ts(tier ordering, tag rank, JSON shape),test/skillpack-sandbox.test.ts(trial install creates + tears down PGLite cleanly, network-disabled assertion fires),test/skillpack-security-gates.test.ts(forbidden filetypes caught, shellcheck path AND fallback regex path both work, external_resources declaration enforced),test/e2e/skillpack-third-party.test.ts(PGLite-only, noDATABASE_URLrequired; uses both a local-filesystem source fixture AND a local-tarball source fixture so both install paths are pinned),test/e2e/skillpack-registry-install.test.ts(PGLite-only; serves a fixtureregistry.jsonvia a localhost HTTP harness, installs by short name, asserts the right pack lands; covers missing-pack-name error path and stale-pin error path),test/skillpack-publish-preflight.test.ts(T-GAP-1 from eng review:gh not installedANDgh not authedboth surface actionable errors with paste-ready install/login commands),test/skillpack-sandbox-network-block.test.ts(T-GAP-2 from eng review: synthetic pack inside sandbox attemptsfetch(...)andhttps.request(...)— both must be rejected by the chosen backend. Runs against every sandbox backend the test host can spin up; skips gracefully when a backend is unavailable.),test/e2e/skillpack-bundle-atomicity.test.ts(T-GAP-3 from eng review: 5-pack starter-pack fixture where pack #3 has a synthetic failure; asserts per-pack-independent contract — packs 1-2 land, pack-3 reported failed, packs 4-5 skipped, retry hint printed, managed block intact for packs 1-2 only),test/skillpack-uninstall-renamed.test.ts(T-GAP-4 from eng review: install pack-A withjudge-submission, install pack-B which auto-renames tojudge-submission-2via the rename map. Uninstall pack-B and assert it removes the-2row, not the bare-name row. Then uninstall pack-A and assert clean state),test/skillpack-runbook-parser.test.ts(frontmatter validation, three step kinds parsed correctly, malformed runbook fails loud, upgrade-runbook frontmatter requires from_version + to_version),test/skillpack-runbook-walker.test.ts(each step kind dispatches to the right handler;ask user:honors —yes in non-TTY; refused confirmation halts the walk and reports which step refused; agent step that fails halts the walk and surfaces the failing CLI exit code),test/skillpack-upgrade-planner.test.ts(single-hop path v0.1->v0.2; multi-hop path v0.1->v0.2->v0.3; refuses when no path exists; refuses silent downgrade),test/skillpack-coverage-score.test.ts(tier eligibility math: endorsed needs routing + runbooks + >=95%; community needs routing + install + >=80%; everything else falls to experimental),test/e2e/skillpack-publish-gate-full-suite.test.ts(PGLite-only; synthetic pack with declared unit tests + LLM-judge evals + routing evals, publish gate runs the suite inside the sandbox with stubbed gateway, produces validation log with coverage score, tier assignment matches expectations),test/skillpack-rubric.test.ts(every dimension inSKILLPACK_RUBRIC_V1has a check function that returns{passed, detail}; pure-function tests against fixture packs that pass / fail each dimension individually + a known-bad pack that triggers all 10 fixes simultaneously),test/skillpack-doctor-quick.test.ts(the--quickmode runs in < 1s on the reference pack; produces stable JSON envelope; refuses scores < 5; exit codes correct per band),test/skillpack-doctor-fix.test.ts(--fixscaffolds missing pieces; respects the mtime-vs-manifest heuristic and refuses to overwrite hand-edited files; confirm prompt fires on TTY;--yesskips it; non-TTY without--yesrefuses),test/e2e/skillpack-reference-is-ten.test.ts(regression guard:modusbrain skillpack doctor --quick --json examples/skillpack-referencealways scores 10/10; if a future PR drops the reference pack below 10, this test fails loud and CI rejects),test/skillpack-anatomy-fresh.test.ts(assertsscripts/check-anatomy-fresh.shpasses: the rubric section ofdocs/skillpack-anatomy.mdmatches whatbun run build:skillpack-anatomywould emit from the current rubric.ts; future-edit-of-rubric without doc-regen fails the build).
Modified
src/commands/skillpack.ts— extendinstallto dispatch on source shape (bundled vsowner/repovs URL vs local path).src/core/skillpack/installer.ts— thread asource: {name, version, pinnedCommit?}discriminator throughapplyInstall/applyUninstall. Read + write per-source managed sub-blocks.src/core/skillpack/bundle.ts— accept either today’sopenclaw.plugin.jsonshape OR the newskillpack.json, normalize internally so the rest of the pipeline doesn’t care.src/commands/skillpack-check.ts— surface per-source health in the agent-readable report.CLAUDE.mdKey Files section.- New
docs/skillpack-authoring.md— the human-readable spec for publishers (not a marketing doc; reference doc). docs/skillpack-distribution.md— registry-shape discussion + versioning policy.
Verification
End-to-end:- Publisher path:
modusbrain skillpack init hackathon-evaluationin a tempdir → add a synthetic skill →modusbrain skillpack pack --dry-run→ expect pass. - Install from local path:
modusbrain skillpack install <tempdir>in a fresh workspace → resolver-block shows the new source sub-block →modusbrain check-resolvableclean. - Install from git (E2E, optional): clone a known-good public sample repo → same assertions.
- Multi-pack coexistence: install the bundled modusbrain set AND the sample skillpack into the same workspace → both rows present in the managed block, neither’s cumulative-slugs receipt touches the other.
- Collision auto-rename: install a second pack that ships a slug
already present (
judge-submission) → installer auto-suffixes tojudge-submission-2, emits a stderr line, records the rename in the source receipt. Triggers still match the same user phrases. - Uninstall safety: edit one skill file in the third-party pack →
modusbrain skillpack uninstall hackathon-evaluation→ refuses without--overwrite-local(D11 contract holds across sources). - TOFU: first-time install of a new URL prompts; second install of same URL + SHA does not.
- Registry resolution:
modusbrain skillpack install hackathon-evaluationagainst a localhost-served fixtureregistry.jsonresolves the right git URL, verifies the pinned commit, lands the pack. Pin mismatch produces a loud refusal. - Search:
modusbrain skillpack search yc --jsonreturns the entry,endorsedtier sorts beforecommunitysorts beforeexperimental. - Bundle install:
modusbrain skillpack install starter-packwalks the bundle list in order; mid-bundle failure unwinds cleanly with no half-installed entries in the managed block. - Publish-gate (sandbox): a synthetic skillpack with a forbidden
file type (
.env) AND a synthetic pack with a malicious shell script both get rejected by the publish-gate. A clean pack passes every gate and produces a tarball + SHA + PR-ready validation log. - Trial install sandbox isolation: the ephemeral PGLite the
publish-gate spins up does NOT touch
~/.modusbrain. Tear-down is clean — no file artifacts, no DB connections left behind. - Runbook execution end-to-end:
modusbrain skillpack install hackathon-evaluationlands the pack AND walksrunbooks/install.mdstep-by-step. Eachagent:step runs; eachshow user:step prints; eachask user:step blocks on TTY confirm or honors--yes. Failed agent step halts the walk and surfaces the failing command. - Upgrade walk multi-hop: install pack@v0.1, publish v0.2 with
upgrade-0.1-to-0.2.md, then v0.3 withupgrade-0.2-to-0.3.md. Upgrade from v0.1 directly to v0.3 walks BOTH runbooks in sequence. Mismatch between recorded version and available runbooks fails loud with paste-ready fix. - Tier eligibility: a pack with routing evals + runbooks +
100% pass earns
endorsedeligibility; same pack with one eval failing drops tocommunity; pack with no routing evals drops toexperimentalregardless of other coverage. modusbrain skillpack testruns against a freshly-scaffolded pack and exits 0 (the scaffold’s example tests pass out of the box, the example LLM-judge eval passes with the real gateway whenANTHROPIC_API_KEYis set, and--no-llmskips the LLM-judge path cleanly).
- All unit tests pass:
bun run test - E2E gate:
bun run test:e2e(Tier 1, no API keys) - Typecheck clean:
bun run typecheck scripts/check-test-isolation.shclean (no new allowlist entries)
Out of scope (deferred)
- Cryptographic signatures (minisign / cosign / Sigstore). The registry’s content-hash pin + Shubham-controlled endorsement file is the v1 trust posture; signatures are a v2 layer on top.
- Dependency resolution between skillpacks (
pack A depends on pack B). v1 declares dependencies as informational metadata only. - Versioning constraints richer than
modusbrain_min_version(no semver range matching, no^0.36). - Auto-update / background pulls.
modusbrain skillpack updateis manual. - A central web UI (modusbrain.dev/skillpacks). The registry repo’s GitHub page IS the web UI in v1.
- Payment / monetization. Skillpacks are free / open source by default.
- Print-press CLI generation against modusbrain HTTP MCP — explicitly IN scope per Q2 but listed here for clarity: it’s a separate one-week effort that lives in a sibling branch, not blocking on the v1 registry ship.
Sequencing — what ships in what order
Six discrete waves. Each lands independently; later waves don’t block earlier ones from shipping value:- W1: Single-pack install — manifest schema, tarball pack, install from git URL / tarball / local path, multi-source resolver block, auto-rename collision resolver, TOFU prompt + commit pinning. Ships the floor: Shubham can hand-distribute hackathon-evaluation today.
- W2: Registry catalog —
thebuildceo/modusbrain-skillpack-registrycreated,registry.jsonschema + endorsements.json, registry-client with stale-cache fallback,modusbrain skillpack search+install <short-name>+info. Initial catalog seeded with bundled modusbrain skills + hackathon-evaluation + maybe one community pack. - W3: Publish-gate skill —
/modusbrain-skillpack-publishskill, security-gates module, sandbox-probe, subprocess-isolated trial install with Docker fallback on macOS. The contributor flow goes from “fork + commit + hope” to “run one skill, get a PR.” - W4: Audit + doctor integration —
~/.modusbrain/audit/skillpack-*JSONL,modusbrain doctorcheck,modusbrain skillpack historyreader. - W5: Printing Press cross-list — open the PR against
mvanhorn/printing-press-librarylistingthebuildceo/modusbrain-skillpack-registryas a sister registry. ~1 day. - W6: Generated modusbrain-cli (Printing Press) — run printing-press against modusbrain’s HTTP MCP, ship the resulting agent-native CLI to their library. Independent week of work; doesn’t block W1-W5.
openclaw.plugin.json set is missing per-skill unit tests (most
have routing-eval.jsonl already from v0.19, missing LLM-judge evals
and per-skill runbooks). The CI guard
scripts/check-bundled-skillpacks-rubric.sh will fail the build
until every shipped pack scores 10. Effort: human ~3 days / CC ~3
hours across the ~25 bundled skills. Doctor’s --fix auto-scaffold
reduces this to mostly “review the auto-generated stubs and fill in
the prose.”
W1 is the floor for “Shubham can ship hackathon-evaluation.” W2 is the
floor for “anyone can discover it without reading Shubham’s README.”
W3 is the floor for “anyone can publish without hand-running git.”
W4-W6 are quality layers on a working system.
GSTACK REVIEW REPORT
Eng-review decisions locked this run:
- Linux sandbox chain:
bwrap → unshare --net → docker. bwrap preferred (most portable, ~100ms); unshare covers stock kernels; docker as heavyweight fallback for RHEL/Rocky/CentOS where unprivileged userns is disabled. - macOS sandbox:
sandbox-exec → docker. Apple’s built-insandbox-execis the primary path (~50ms, no Docker dep); Docker is the rare fallback. macOS publishers without Docker can still publish. - Bundle install atomicity: per-pack independent (option γ). Failures inside a bundle leave earlier successful packs installed, skip later packs, print a summary with retry hint.
- Deleted source repo durability: registry CI mirrors tarballs to
tarballs/<name>-<version>.tgzvia git LFS at PR merge time. 5MB per-pack cap; larger packs flaggedsource_only: true. - Endorsement workflow:
modusbrain skillpack endorse <name> [--tier ...] [--push]CLI command with schema validation; hand-editing remains valid.
- A1: Linux sandbox fallback chain underspecified → locked (#1).
- A2: Docker-on-macOS as a contributor cliff → locked (#2, sandbox-exec preferred).
- A3: Registry source-repo-deleted doom path → locked (#4, tarball mirror).
- C1: Bundle install atomicity unspecified → locked (#3).
- E1: Endorsement workflow unspecified → locked (#5).
- T-GAP-1:
ghnot-installed / not-authed branches in the publish skill. - T-GAP-2: sandbox network-block assertion (fetch + https.request both rejected) across every backend the host can spin up.
- T-GAP-3: starter-pack bundle mid-failure (5-pack fixture, pack-3 fails) → per-pack-independent contract verified.
- T-GAP-4: uninstall a pack whose slug was auto-renamed via the rename map →
-2row removed, not bare-name.
- Lane A (W1: single-pack install): manifest, tarball, collision-resolver, multi-source-receipt, install paths. Sequential; shared
src/core/skillpack/namespace. - Lane B (W2: registry catalog): registry-client, registry-schema, search/info commands. Can run parallel to A after manifest schema lands.
- Lane C (W3: publish gate): publish skill, security gates, sandbox + sandbox-probe + macOS profile. Parallel to A+B but depends on tarball from A.
- Lane D (W4: audit + doctor): audit.ts + doctor check. Parallel to everything else.
- Lane E (W5: Printing Press cross-list): a single docs PR against
mvanhorn/printing-press-library. ~1 day, fully independent. - Lane F (W6: generated modusbrain-cli): independent week of work; spawns its own branch.
- Artifact scope: full cathedral.
skillpack.jsondeclaresskills[],unit_tests[],e2e_tests[],llm_evals[],routing_evals[],runbooks{install, uninstall, upgrades},changelog. The differentiation moat — nobody else ships AI evals + agent runbooks as first-class package artifacts. - Publish gate runs everything in the sandbox. Unit + E2E (when DB available) + LLM-judge (stubbed gateway, zero cost) + routing-evals. Coverage score drives tier eligibility:
endorsedrequires routing + runbooks + >=95% pass;communityrequires routing + install + >=80%;experimentalaccepts structural-only. - Runbook format: agent-readable markdown with three step kinds (
agent:,show user:,ask user:). Separateinstall.md,uninstall.md,upgrade-<from>-to-<to>.mdper version. Mirrors modusbrain’s ownskills/migrations/v0.21.0.mdpattern. modusbrain skillpack initscaffolds the cathedral by default. Full tree (skills, tests, e2e, evals, runbooks, CHANGELOG, README, LICENSE) lands out of the box;modusbrain skillpack pack --dry-runpasses immediately.--minimalflag for power users opting out.
modusbrain skillpack doctor --quick (~5s structural sweep, walks the rubric, no sandbox/LLM/DB) for rapid iteration; --full (runs the full publish-gate suite) for ship-readiness. Two-tool design; agent picks the mode per workflow phase. The user noted: agents do the operating, so the cognitive cost of two flags is irrelevant as long as the docs teach the agent when to use which.
6. Rubric as declarative spec: src/core/skillpack/rubric.ts exports SKILLPACK_RUBRIC_V1 — 10 binary dimensions (manifest valid / SKILL.md complete / routing-evals present + clean / check-resolvable clean / unit test present / LLM-judge eval present / install + uninstall runbooks / CHANGELOG current). Single source of truth: doctor walks it, anatomy doc is auto-generated from it, tests pin each dimension.
7. doctor --fix auto-scaffold: Calls modusbrain skillify scaffold for missing skills, drops runbook stubs, generates CHANGELOG entries from VERSION + git log. Confirm prompt on TTY; --yes skips; refuses to overwrite files whose mtime is newer than skillpack.json’s.
8. Reference pack + anatomy doc + 10/10 invariant for EVERY bundled modusbrain skillpack: ship examples/skillpack-reference/ (real working 10/10 pack) AND docs/skillpack-anatomy.md (one-page reference, auto-generated rubric section from rubric.ts). NEW INVARIANT (the user’s strongest line): every modusbrain-shipped skillpack must score 10/10 on --quick. scripts/check-bundled-skillpacks-rubric.sh is wired into bun run verify + CI. Bringing today’s openclaw.plugin.json set to 10/10 is wave W4.5 — blocking on W3 (doctor) but required before v1.0 ship. Credibility-poison if modusbrain ships skillpacks below the bar modusbrain demands of third parties.
DX scorecard (after both DX rounds):
Magical moment (locked from DX 0D):
modusbrain skillpack install <name> lands the pack AND walks runbooks/install.md AND the agent immediately knows what triggers fire, what tools the skill exposes, and how to upgrade later. Zero “where are the docs?” moment.
Second magical moment (Round 2): modusbrain skillpack doctor --quick --json prints a 10/10 score with paste-ready fixes for the misses. The agent reads the JSON, runs --fix --yes to auto-scaffold, re-runs --quick, and the score climbs. The first time an agent gets from 6/10 to 10/10 in 30 seconds via three modusbrain commands is the moment the “skillpacks are real software packages” claim becomes felt rather than asserted.
Lake Score: 25/27 — every cathedral-leaning recommendation accepted across CEO + Eng + DX (both rounds) + 8 codex outside-voice questions. The 2 holds are deliberate: T2 (kept cathedral scope vs codex’s minimal v1) and T3 (kept the 10/10 bundled invariant vs codex’s defer-to-v1.1). Both defenses were on locked product-strategy decisions; the cathedral moat is the thing.
CODEX (outside voice) — 20 findings, 8 surfaced for decision:
- T1 (RUNBOOK TRUST) — adopted: per-step approval replaces auto-walk;
--runbook-apply-allfor CI;--runbook-skipfor file-drop-only. NPM-postinstall lesson applied. - T2 (SCOPE) — held: cathedral is the moat; minimal v1 forfeits curation+evals+runbooks differentiation; without those modusbrain skillpacks are just another agentskills.io mirror.
- T3 (10/10 BUNDLED) — held: shipping modusbrain’s own packs below the bar modusbrain demands is credibility-poison; W4.5 retrofit costs ~3d with —fix autoscaffold, slips v1 by a week.
- T4 (GAMEABLE CATHEDRAL) — adopted: rubric splits into required core (5 dimensions: manifest + SKILL.md + routing-evals + check-resolvable + CHANGELOG) and quality badges (5: routing-evals-clean + unit tests + LLM-judge + install + uninstall runbook). Endorsed needs all badges; community needs 3/5; experimental needs core only. Plus stubbed-eval detection in publish-gate content scan.
- G1 (TRUST STORE) — adopted:
~/.modusbrain/skillpack-state.jsonmachine-owned (TOFU pins, hashes, rename maps); resolver markdown stays render-only (rows + cumulative-slugs). Mismatch fails loud. - G2 (ENV SCRUB) — adopted: clean env (only PATH/LANG/TZ), HOME override to empty
<tempdir>/sandbox-home, explicit denylist (*_API_KEY/*_TOKEN/*_SECRET/ SSH_AUTH_SOCK / GIT_* / NPM_TOKEN / BUN_INSTALL_TOKEN). Read-only mounts + masked/procwhere bwrap supports it. - G3 (CI SUPPLY CHAIN) — adopted: three-workflow split. validate-pr.yml is static-only on
pull_request(no privileged tokens, no LFS write). post-merge-validate.yml runs the heavy suite inside the registry’s own sandbox after merge. mirror-tarball.yml commits the tarball with a least-privilege deploy key scoped totarballs/. - G4 (NAMESPACE / TYPOSQUAT) — adopted: first-install identity confirm prompt showing author/source/commit/SHA/tier; subsequent same-author-same-pin installs skip. Registry rejects new endorsed-tier names within Damerau-Levenshtein edit-distance 2 of any existing endorsed pack.
- Tarball determinism: sorted entries, fixed mtimes, gzip mtime=0, no symlinks/hardlinks/devices/FIFOs, extract caps (5000 files / 100MB total / 1MB per file / 255-char paths / 100:1 ratio).
- check-resolvable pack-local isolation: doctor + publish-gate wrap
check-resolvablein a tempdir fixture containing ONLY the pack’s RESOLVER.md + skills/, so verdict is pack-local not workspace-global. - Versioning beyond
modusbrain_min_version: manifest also carriesrunbook_schema_version+eval_schema_version; installer rejects newer-than-supported with paste-ready upgrade hint.
- T2 scope and T3 bundled-invariant are product-strategy decisions where codex’s argument (ship simpler v1 faster) lost to the user’s argument (the differentiation IS the cathedral; shipping below your own bar is credibility-poison). Codex was right on every supply-chain finding; the disagreement on scope is taste, not correctness. Documented here so future maintainers see the trade.
- /codex consult as an outside voice on the locked-in plan; the artifact-as-software-package framing deserves an independent challenge.
- /devex-review after implementation lands — the boomerang. Plan says TTHW < 5min; reality check post-ship.