* skills: delete deprecated install tombstone (frontmatterless SKILL.md breaks plugin skill scanners)
The skills/install/ dir was a deprecation pointer to the setup skill with no
YAML frontmatter — absent from skills/manifest.json and unreachable via the
resolver, but visible to any harness that scans skills/ for SKILL.md files.
Codex errors at session start on frontmatterless skills (the same class is
recorded for an external stray copy in TODOS.md), so it must not ship in the
plugin lanes. skills.lock.json regenerated by the commit gate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* skills: portability, consent, and privacy sweep for the plugin lanes (10 skills, 50 fixes)
Prepares the sweep set (the 8 openclaw-excluded host-inversion skills plus
cold-start, signal-detector, eiirp, gbrain-upgrade) for publication to plugin
consumers who own their brain but are not gbrain-repo developers:
- setup: sanctioned global pinned install command; synthetic example names;
daemon-only prose generalized; repo-relative doc refs resolved; the invalid
discovery-loop bash fixed; PGLite-first framing restored
- cold-start: raw OAuth-token curl path deleted; ClawVisor phases labeled as
host-integration-only with offline (Takeout) equivalents leading
- signal-detector + eiirp: first-fire consent announcement + per-user off
switch; always-on reframed as a harness convention, not a runtime guarantee
- smoke-test: 'gbrain smoke-test' is the user entrypoint; container paths and
OpenClaw-service checks labeled conditional
- schema-author/schema-unify/skill-optimizer/frontmatter-guard/gbrain-upgrade:
repo-relative links, internal review-provenance citations, container paths,
and read-only-snapshot caveats cleaned
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* plugin-tree: curated skill tree for the codex/claude plugin lanes (generator + committed tree + drift gate)
One publication decision per lane, review-visible: lane set = (openclaw
bundle minus repo-dev exclusions) plus the 8 host-inversion additions —
skills/plugin-lanes.json is the curation record (a reason per entry),
scripts/generate-plugin-tree.ts emits the committed plugin/ tree (65 skills,
shared conventions/_*.md deps, generated README with the CLI-primary starter
note), and scripts/check-plugin-tree.sh byte-diffs tree-vs-generator (the
check-bootstrap-templates part-c posture). The starter_gaps snapshot pins
each bundled skill's beyond-starter MCP ops (computed from frontmatter
tools:, namespace-filtered) so a new gap is a conscious curation event —
every gap op has a first-class gbrain CLI path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* serve: --source-guard fail-closed write routing for user-global plugin serves
A plugin-managed MCP server runs with the plugin snapshot as its cwd, so the
dotfile and local-path source-resolution tiers lose their meaning — an
ambient-tier resolution could silently route writes into whatever source it
fell through to (worst case: a registered source whose local_path contains
the snapshot dir). Under the flag, dispatch blocks write/admin ops with an
actionable source_binding_required envelope unless the winning tier proves
the binding deliberate (flag/env/dotfile/brain_default) or unambiguous
(sole_non_default; seed_default while 'default' is the sole source). Reads
pass on every tier; sole-source brains are a pure no-op; engine errors fail
closed. Both plugin manifests pass the flag; hand-run serves are untouched.
- src/core/source-resolver.ts: WRITE_SAFE_SOURCE_TIERS + sourceGuardBlocksWrite
- src/mcp/dispatch.ts: the gate (before validation, so a blocked caller
learns the routing rule, not the op's parameter shape); verb envelopes
carry protocol_version
- src/mcp/server.ts: resolveMcpStdioSourceScope now reports the winning tier
- src/commands/serve.ts: flag parse + seam type; flag registry regenerated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* codex-plugin,claude-plugin: lane manifests, shared launcher, manifest contract test
One repo, two plugin lanes:
- codex: .agents/plugins/marketplace.json (codex-native marketplace) +
.codex-plugin/plugin.json (skills → the curated plugin/ tree; mcpServers →
.codex-plugin/mcp.json, deliberately NOT a repo-root .mcp.json — a root
file would auto-offer a checkout-controlled launcher to every contributor's
session) + mcp.json serving --surface starter --source-guard with a
code-derived env_vars passthrough contract
- claude code: .claude-plugin/marketplace.json (content-equivalent so codex's
dual-format marketplace reading cannot fork the install) + plugin.json with
the inline env-OBJECT-shape MCP declaration via ${CLAUDE_PLUGIN_ROOT}
- .agents/gbrain-launcher (sh, 755, Unix-only): GBRAIN_BIN → PATH →
~/.bun/bin resolution with one stderr resolution line, GBRAIN_SURFACE
substitute-or-append override (serve argv only), actionable exit-127
recovery copy, no auto-install by design
test/codex-plugin-manifest.test.ts pins the whole contract: 4-manifest
version lockstep, exact MCP declarations, marketplace equivalence, launcher
statics + all seven resolver/override branches behaviorally (HOME pinned to
a tempdir in every case), curated-tree membership algebra, scanner guards,
env_vars ⊇ derived set, and a generator round-trip. Wired into the skills
commit gate alongside the openclaw manifest test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* bootstrap,doctor: plugin-lane coexistence — the plugin as a third owner of the gbrain MCP name
Detectors (src/core/bootstrap/harness.ts, all fail-open): codexPluginProvidesName
(line-anchored [plugins."<name>@<mkt>"] header + enabled=true — commented
lookalikes and next-table enabled keys never match), claudePluginProvidesName
(~/.claude/settings.json enabledPlugins, the shape verified on a live install),
and the doctor-side any-registration scans that DELIBERATELY count foreign/
manual entries (codexBlockOwnsName's managed-block scope is the wrong question
for coexistence).
runHooks: a healthy plugin-owned skip is a NEW state, not mcpSkipped (which
means host-failure and exits 2) — the MCP substep skips registration argv +
smoke (plugin MCP servers are invisible to mcp get/list), hooks and every
other phase proceed, exit 0, receipt records plugin ownership
('plugin-mcp' / 'hooks+plugin-mcp'). --mcp-even-if-plugin forces the
hand-wired registration (plugin enabled is a config signal, not health).
Harness lane: WARN (never refuse) when wiring the codex managed block next to
an enabled plugin — two same-name servers in different layers is host-defined
behavior; both off-ramps named.
Doctor: plugin_lane_collision (ops category, registered in doctor-categories)
— rows emitted ONLY when a gbrain plugin is enabled: warn on a real
double-registration, ok when the plugin is sole owner; runs before the
bootstrap-state gate (a manual mcp add + plugin needs no bootstrap to
collide).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(helpers): agent-harness oracle fixes for the plugin doors
- parseCodexJsonl retains mcp_tool_call items ({server, tool}, best-effort
field fallbacks) — e2e assertions no longer regex raw JSONL lines
- claudeHeadlessTurn / codexExecTurn spawn the RESOLVED binary path: the
hermetic child env can make a bare 'claude'/'codex' resolve differently
than the resolver the skip-gate consulted
- codexSupportsPlugins / claudeSupportsPlugins probes ('plugin --help'
exit 0) for the plugin-door skip-gates
- mcpToolsListProbe: deterministic MCP surface oracle — spawns a stdio MCP
server command, runs the initialize handshake, returns the advertised tool
names via a real tools/list (never an LLM-output assertion)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(e2e): codex + claude plugin doors — install, oracle, guard, coexistence, smoke
codex door (INSTALL verified GREEN against the real codex 0.147.0 in ~10s):
clean-tree staging via git archive HEAD (a dirty worktree never enters the
snapshot), marketplace add + plugin add, snapshot assertions (curated skills
present, repo-dev skills absent, NON-ROOT .codex-plugin/mcp.json honored,
launcher exec bit survives the copy), add-twice idempotency + exactly-one-row
dual-marketplace probe, deterministic tools/list surface oracle == the starter
surface through the SNAPSHOT launcher, cold-home fast-fail ('No brain
configured. Run: gbrain init'), --source-guard block/allow through the real
MCP pipe, hand-wired-next-to-plugin coexistence probe (succeeds — the doctor
warn scenario is real), marketplace-qualified removal. SMOKE (auth-gated):
plugin-provided server → seeded fact via mcp_tool_call evidence + the
recovery-loop probe (missing binary degrades, never bricks the session).
claude door: validate --strict (marketplace description added to pass),
marketplace add + install → enable entry in the exact claudePluginProvidesName
shape, uninstall clears it; SMOKE via claude -p with the plugin-launched
server. Harness: CodexTurnResult carries mcpToolCalls; extraEnv threads
GBRAIN_* through both turn helpers into plugin-launched servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci,dx: non-vacuous plugin-doors job + dx-explore codex-plugin-install scenario
heavy-tests.yml plugin-doors job (grok-door posture, EV11): PROVISIONS pinned
npm codex + claude binaries with version-output asserts (refuse on drift),
runs both INSTALL tiers, and refuses green unless the expected pass counts
executed — zero-pass/partial-pass never reports green. INSTALL tiers are
secretless by design; the auth-gated SMOKE tiers self-skip inside the suites
with the skip accounted for in the expected shape (integrity-metadata pinning
deliberately omitted: this job carries no secrets).
dx-explore codex-plugin-install: the plugin lane's first-run journey under a
real PTY — the two documented install commands up front, then an interactive
codex session answering a seeded brain question through the plugin-provided
MCP server; friction events recorded against docs/mcp/CODEX.md's plugin
section. Claude SMOKE oracle fixed to the observed plugin-namespaced tool
shape (mcp__plugin_gbrain_gbrain__*).
Both SMOKE doors verified GREEN live on this machine (codex attempt 1:
usedMcp=true gotFact=true; claude attempt 1 after the namespace fix).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* release: publish the slim codex-plugin dist branch on every release (EV4)
Force-publishes a history-less commit to the codex-plugin branch carrying
exactly the plugin artifacts (manifests + shared launcher + curated plugin/
tree) so 'codex plugin marketplace add garrytan/gbrain@codex-plugin' downloads
the plugin, not the dev repo. Gated on the same generator byte-diff as the
verify-time drift check; exec bit asserted before push; same force-advanced
trust model as latest-stable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: plugin install paths, routing + surface guidance, tag-check Rule 4, five-way version lockstep
- docs/mcp/CODEX.md: plugin install headlined (@codex-plugin slim ref +
from-source form), prerequisites (binary + gbrain init, never the squatted
npm name), what ships (starter surface, host-inversion note), launcher
resolution + GBRAIN_BIN/GBRAIN_SURFACE, routing under the plugin lane
(dotfiles dead; source axis env/--source; brain axis env ONLY;
--source-guard semantics), one-owner-per-name + enabled≠healthy, both
upgrade halves, removal
- docs/mcp/CLAUDE_CODE.md: Option 0 plugin section (permissions.allow
pre-approval stays bootstrap-lane-only)
- README + INSTALL_FOR_AGENTS: plugin as the lightweight funnel next to the
bootstrap paste block; MCP table rows updated
- docs/guides/bootstrap.md degradation row + harness one-owner note;
BOOTSTRAP_FOR_AGENTS.md codex preflight covers the plugin-owned skip
- scripts/check-bootstrap-tag.sh Rule 4: marketplace refs in docs must pin
@latest-stable or @codex-plugin
- KEY_FILES entries for every new artifact; CLAUDE.md version-locations row
(five-file lockstep) + llms bundles regenerated; CHANGELOG under
[Unreleased]; TODOS: Windows launcher, keyless cold-home auto-init,
future harness lanes, post-release marketplace-upgrade probe
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(gates): flag-registry regen, serial-rename the source-guard test, register check-plugin-tree in the guards manifest
- cli-flag-registry regenerated (picks up --mcp-even-if-plugin and the other
new bootstrap flag literals added after the commit-3 regen)
- test/serve-source-guard.test.ts → .serial.test.ts (R1: it mutates
process.env.GBRAIN_SOURCE in its env-fallback cases)
- guards-manifest.tsv: check-plugin-tree.sh classified buildfresh/exempt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: pre-landing review fixes (1 critical + 13 hardening items from the specialist army)
- CRITICAL: claude plugin SMOKE door gains its missing auth skip-gate
(hasClaudeAuth) — an unauthed machine burned 2×230s live-turn attempts and
hard-failed instead of skipping
- source-guard probe: bounded LIMIT-1 existence query + memoized schema-shape
probe (a legacy pre-archived-column brain paid an exception per guarded
write); dispatch imports sourceGuardBlocksWrite statically (was a dynamic
import per call); serve warns loudly that --source-guard is stdio-only when
combined with --http (the --log-full-params posture precedent)
- generate-plugin-tree: canonical parseSkillFrontmatter replaces the
hand-rolled block-only parser (which silently missed inline tools: lists —
proven immediately by multi-word CLI entries surfacing), plus a
GBRAIN_PLUGIN_TREE_ROOT fixture seam; three negative-fixture tests prove
the curation gate can actually fail (short reason, addition-in-base, stale
starter_gaps)
- tests: parseCodexJsonl mcp_tool_call field-fallback unit cases; legacy-
schema fallback + memoization tests for the guard; dead var + unused import
dropped from the door tests
- check-bootstrap-tag: Rule 4 moved before the status block (no more
ok-then-FAIL transcripts); bare-form scope recorded as a deliberate
decision (Claude marketplaces have no ref-pin syntax)
- check-plugin-tree wired into bun run verify (the comment now tells the
truth); plugin-doors CI pins EXACT pass counts (grok-door posture);
release publish job checkout gets persist-credentials:false;
claudeUserMcpConfigPath() helper replaces the inline ~/.claude.json path;
dx-explore fails fast when the paid scenario's seed write fails
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: bump version and changelog (v0.46.7.0)
Five-file lockstep (VERSION, package.json, openclaw.plugin.json, both plugin
manifests) + runbook stamp + template-repo regen + bun.lock + llms bundles.
User-pinned slot past the 0.46.2-0.46.6 in-flight queue.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix: adversarial + red-team review fixes (2 critical + coexistence/guard hardening)
Cross-model review (Claude adversarial + Codex adversarial + red team) after
the merge surfaced two real criticals and a set of correctness/honesty gaps —
all fixed:
- CRITICAL (red team): the e2e source-guard block-probe seeded a sole-source
brain, which resolves to the unambiguous sole_non_default tier (WRITE_SAFE,
correctly NOT blocked) — a latent CI redliner. The guard DESIGN is right
(one real source can't be misrouted); the test now seeds a genuinely
ambiguous 2-source brain, and the CHANGELOG/CODEX.md wording drops the
"more than one source" overclaim for "multiple sources to choose from".
Re-verified live: INSTALL door green, block+unblock both assert.
- CRITICAL (Claude): the plugin-mcp receipt marker was write-only — uninstall
ran `mcp remove gbrain` for it, which would delete a user's later
hand-wired registration bootstrap never created. Uninstall now skips the
mcp-remove for plugin-owned receipts (hooks half still removed).
- launcher resolution prefers ~/.bun/bin over PATH (a hostile repo's
node_modules/.bin gbrain can't shadow the sanctioned install with all the
forwarded provider creds); GBRAIN_BIN stays the escape hatch.
- claudeAnyRegistrationExists scans projects.<path>.mcpServers (the LOCAL
scope `claude mcp add` defaults to) so doctor stops printing a false
"sole owner"; claudeUserMcpConfigPath honors CLAUDE_CONFIG_DIR.
- --source-guard: local_path now blocks only when another source exists (a
sole-source brain whose local_path contains the serve cwd is unambiguous);
the shape memo caches 'legacy' only on a genuine missing-column error (not
a transient blip); GBRAIN_SOURCE=__all__ writes get a sentinel-specific
block; a malformed GBRAIN_SOURCE no longer launders through as tier 'env'.
- claude manifest pins cwd=${CLAUDE_PLUGIN_ROOT} so the guard's
"cwd is meaningless" premise holds on both lanes.
- release publish job: GIT_ASKPASS instead of token-in-argv, ships LICENSE;
check-plugin-tree drops the now-permanent SKIP fail-open + guards mktemp;
mcpToolsListProbe races reads against the deadline (no silent-child hang);
env derivation covers transcription.ts (DEEPGRAM_API_KEY); removal-command
copy unified to gbrain@gbrain; plugin/ added to the version-lockstep
(CLAUDE.md + RELEASING); receipt-provenance edge filed as a P3 TODO.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: sync plugin docs to shipped behavior for v0.46.7.0
Post-ship /document-release cross-referenced every plugin doc against the
code and fixed eight drift points:
- starter surface is 26 ops, not "~20" (CODEX.md, plugin/README, generator
template + regenerated tree, derive-starter-ops comment)
- the plugin stdio serve binds the source axis from GBRAIN_SOURCE env, NOT a
--source flag (resolveMcpStdioSourceScope passes explicit=null) — dropped the
over-promised --source from CODEX.md, CHANGELOG, and both source-guard
dispatch envelopes
- --source-guard gates write AND admin ops (say "write/admin", not "write-only")
- Claude Code Remove section gains the Option 0 plugin uninstall command
- codex plugin remove is marketplace-qualified (gbrain@gbrain, not bare gbrain)
- BOOTSTRAP_FOR_AGENTS plugin-owned skip note now covers Codex AND Claude
- version-locations table: "six/trio" -> "seven files"; stale 0.46.1.0 example
- KEY_FILES: Claude manifest has no env block (command/args/cwd only)
CLAUDE.md edited -> llms bundle regenerated in the same commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci: silence intentional SC2016 in the codex-plugin publish job
actionlint (via shellcheck) flagged the single-quoted $GH_TOKEN in the
GIT_ASKPASS heredoc of publish-codex-plugin. The non-expansion is the
point — the askpass script must carry the literal variable so /bin/sh
expands it at git prompt time, never in the workflow shell. Add the same
shellcheck disable=SC2016 directive the publish-template job already
carries for its identical pattern. actionlint now green across all
workflows locally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>