Skip to content

feat(core): generate brains-write capability artifact [BRNS-CORE-008] - #17

Merged
stefan-ssv-labs merged 7 commits into
mainfrom
feat/generated-capability-catalog
Jul 30, 2026
Merged

feat(core): generate brains-write capability artifact [BRNS-CORE-008]#17
stefan-ssv-labs merged 7 commits into
mainfrom
feat/generated-capability-catalog

Conversation

@stefan-ssv-labs

@stefan-ssv-labs stefan-ssv-labs commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What and why

Publishes the public brains-write face generated by BRNS-CORE-008's typed
capability catalog. The renderer-v2 manifest binds the artifact to the exact
catalog and artifact SHA-256 digests. Installation remains fully local: there
is no runtime or install-time fetch from the monorepo.

The generated contract fails closed for undeclared side effects and preserves
the canonical retry, verification, confirmation, and rate-limit rules without
maintaining a sixth hand-written copy.

Mandatory precedence — satisfied

The required cross-repository order is now complete:

  1. ssvlabs/brains#1066 was released to main/production.
  2. ssvlabs/brains-plugins#16 then merged as 50424b21.
  3. companion catalog PR ssvlabs/brains#1069 merged into brains stage as
    signed squash commit 58cabc5f.
  4. this branch merged latest plugins main (including fix(brains): Codex owns the MCP credential via its own OAuth login #16), regenerated from
    #1069's landed catalog, and revalidated the generated outputs.

No additional production release of #1069 is required before this PR merges.
The remaining merge gates are the normal current-head teammate approval and
green CI checks.

Final provenance receipt

  • Source repository: https://github.com/ssvlabs/brains
  • Source PR: https://github.com/ssvlabs/brains/pull/1069
  • Landed source commit: 58cabc5f306601c8871c0b35cb6fa9dddbfb6d6c
  • Landed source tree: d80a29e7047841b3e1da679110a9f8a7aa72d2ea
  • Final plugin head: 1a67c3b2e5a9ba7f695d1fc1bcc17b76175d148c
  • Renderer version: 2
  • Catalog SHA-256:
    c46b9cf2f88ed3cefe0f5766665c12f06dafaa0e56dba1f5586ab9cd56c39ac2
  • Artifact SHA-256:
    f14839e4ed852771fc8dd91b0196f9caeeb63ce56dead747a53d83fd83dd9475
  • Binding authority: the content digests above. The manifest is intentionally
    commit-free because squash merge changes commit identity.

Verification

  • monorepo generator write + --check --plugin-root — 7/7 outputs fresh
  • generated manifest digest matches the committed public skill
  • bun run tests/plugin-contract/run.ts
  • bun run tests/inbox-v2/run.ts
  • bun run tests/tool-error/run.ts
  • signed commit range contains no unsigned or bad commits

Product decisions and one pending input — @RaekwonIII

Calling out @RaekwonIII explicitly:

  1. The static-scrape prototype is superseded by the live-registry generator;
    only its source revision remains pending for historical comparison.
  2. Future sync should use a dedicated release/deploy-owned GitHub App with
    repository-limited, short-lived write/PR tokens. It opens a PR and never
    auto-merges.
  3. Keep the generated artifact committed here until a second or non-TypeScript
    consumer exists; then revisit a versioned, language-neutral GitHub Release
    that installations still vendor locally.

None of these product inputs blocks this bounded first slice.

@RaekwonIII RaekwonIII left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed with the companion hub PR ssvlabs/brains#1069 — the full technical review and my answers to the three product questions live there. Comment, not approval.

This side checks out:

  • The committed capability-catalog.json is byte-identical to the brains-side manifest.json, and the contract test now recomputes sha256(skills/brains-write/SKILL.md) and asserts it equals b040… — so the artifact is bound to its source by content, and installation stays fully local (no runtime/install-time fetch). Good.
  • The internal-capability leak guard (!/automation_secret|adminPool|handler_source|telegram_push|grant_token/) plus keeping the independent semantic assertions (digest proves provenance, not that the canonical source kept its load-bearing safety rules) is the right belt-and-braces.
  • The two new result kinds (clarification, noop) are added consistently with the other faces.

One cosmetic note on provenance: #1069 merges by squash into stage, so the source commit b039b7d… cited in this PR's "Provenance and ordering" section won't exist on stage afterward (squash mints a new commit; the PR branch is deleted). That's harmless — the manifest binds by catalog_sha256 / artifact_sha256, i.e. content, not commit sha, and there's no source_commit field in the committed manifest. Just don't rely on that commit reference resolving after the squash; the digests are the real binding.

Ordering otherwise as you documented: land after (or immediately before) #1069 as the compatible public face.

@stefan-ssv-labs stefan-ssv-labs left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ review-pr (self-review, cannot approve own PR): no blockers on this side. One cross-repo note.

Reviewed against BRNS-CORE-008 at head b54a31b, alongside the hub PR ssvlabs/brains#1069. This side is clean and the provenance design is right.

Verified ✅

  • The digest binding is enforced, not declared. tests/plugin-contract/run.ts recomputes createHash("sha256").update(writeSkill) and asserts it equals the committed artifact_sha256. I confirmed independently: shasum -a 256 plugins/brains/skills/brains-write/SKILL.md = b0401fca…, matching both this repo's capability-catalog.json and the brains-side manifest.json — which are byte-identical to each other. Running the hub generator with --check --plugin-root <this checkout> reports 7 generated outputs are fresh, so the two repos agree at these exact heads.
  • Semantic assertions were kept alongside the digest. The comment gets the reasoning exactly right — "digest equality proves provenance, not that the canonical source itself kept the load-bearing safety rules." A hash check alone would have happily ratified a regenerated artifact that dropped the no-blind-retry rule. Keeping both is the correct belt-and-braces, and adding the clarification and noop kind assertions closes the gap where only some kinds were covered.
  • Version pinning is complete. schema_version, catalog_schema_version, and renderer_version are all asserted, so a future incompatible catalog or renderer revision fails loudly here rather than silently shipping a mismatched public face.
  • The leak guard is real. !/automation_secret|adminPool|handler_source|telegram_push|grant_token/ mirrors the monorepo-side check. I also read SKILL.md in full: no internal or admin tools, no credentials or env values, no handler source, no user data. It reads as a genuine public face.
  • Installation stays local. No runtime or install-time fetch of a mutable artifact; the manifest travels with the skill.

Note — provenance binds by content, and the manifest is correctly commit-free

Worth recording since the PR body's "Provenance and ordering" section cites source commit b039b7d: that reference will not resolve on stage after #1069 squash-merges, and #1069's own head is now 33ff83b regardless. This is harmless, and I want to be clear it is not a finding — the committed manifest has no source_commit field at all, binding only by catalog_sha256 / artifact_sha256. I verified the digests are unaffected: git diff b039b7d1 33ff83bf -- packages/capability-catalog gbrain/src/core/generated docs/mcp-tool-reference.md is empty.

That is the better design, and it is why the stale pointer costs nothing. The only thing to avoid is treating that commit sha as a resolvable reference in future prose; the digests are the binding.

Merge ordering

Nothing in this PR depends on #1069 landing first — the artifact and its manifest are self-contained here, and the contract test verifies them without reaching into the other repo. So this can land in either order.

One caveat on sequencing: #1069 currently has a blocker (a bare @brains/capability-catalog import in the Deno automation sandbox that fails module resolution at runtime — details on that PR). Fixing it does not touch the catalog, the renderers, or any generated artifact, so it should not change artifact_sha256 and this PR should stay aligned. Worth re-running --check --plugin-root after that fix to confirm the digests still match before merging the pair.

@stefan-ssv-labs

Copy link
Copy Markdown
Contributor Author

Review follow-up: the PR body no longer treats the pre-squash source commit as durable provenance. It now names the content digests as the binding authority (matching the intentionally commit-free manifest), records @RaekwonIII’s resolved product decisions, and retains the explicit #1066 → production → #16 plus final #1069 → regenerate/rebase gates. No generated plugin bytes changed in this follow-up.

@stefan-ssv-labs stefan-ssv-labs left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ review-pr (self-review, cannot approve own PR): re-review at f28d324f. No blockers, no critical issues.

Re-review at the new head. The only change since the previous pass is fix(core): regenerate action safety contract [BRNS-CORE-008], which regenerates the two committed artifacts to carry the upstream catalog fix from ssvlabs/brains#1069.

What I verified

This PR's contract is that its content is generated, never hand-edited, and provably tied to the upstream catalog. Both halves hold at this head:

  • plugins/brains/skills/brains-write/SKILL.md is byte-identical to the artifact generated from ssvlabs/brains#1069 at 014309fb.
  • Its actual SHA-256 (52f9f4f6…) equals the artifact_sha256 recorded in plugins/brains/generated/capability-catalog.json, and that manifest is identical to the brains-side manifest — same catalog_sha256 (3dbd82bd…), same renderer_version: 2.
  • Running the upstream generator with this checkout passed as --plugin-root reports all 7 outputs fresh, so neither repository has drifted from the other.

The upstream change this regeneration carries — the restored auto_failed retry precondition and the verify-mode noop semantics — is reviewed on ssvlabs/brains#1069, where the catalog source lives. Reviewing that prose here would be reviewing a build output.

Validation

CI at f28d324f is 3/3 green (cross-client plugin contract, inbox-v2 contract, tool-error contract) and I reused it per the CI-first rule. Local checks added the byte-identity, digest, and cross-repo freshness proofs above, which CI cannot provide on its own because they span two repositories. No stage or production data was read or mutated.

No findings of this PR's own: its correctness is entirely a function of the upstream catalog, and the provenance binding that makes that checkable is intact.

@Ravid-SSVLabs

Copy link
Copy Markdown

QA review — artifact verified; hold for the release order

Verified at head ae41e56 against brains#1069 head 461d41fe. The provenance mechanism works end to end, and I checked it rather than trusting the receipt:

Claim How I checked Result
artifact_sha256 = 4f8a8da0… shasum -a 256 on the committed SKILL.md ✅ exact match
catalog_sha256 = b4846aca… recomputed independently from #1069's catalog ✅ exact match
artifact ≡ the monorepo's generated copy byte diff across both repos byte-identical
manifest ≡ the monorepo's manifest byte diff ✅ identical
regenerates from #1069's catalog --check --plugin-root against this checkout 7/7 fresh
plugin-contract ran ✅ PASS
inbox-v2 32/32 · tool-error 14/14 ran ✅ 32/0 and 14/0

I also verified all four declared gates independently, and the description's self-assessment is accurate on every one:

Gate Status
1. brains#1066 released stagemain ❌ merged to stage 2026-07-28, but merge commit 9c64d3cd is not an ancestor of origin/main
2. brains-plugins#16 → plugins main ❌ still OPEN
3. brains#1069 → brains stage ❌ still OPEN
4. regenerate from final #1069 + combined contract correctly pending

So the hold is right, and it's the reason not to merge — not a defect in this diff.

🟠 MEDIUM — catalog_sha256 is asserted here but unverifiable here

The new assertions cover schema_version, catalog_schema_version, renderer_version, capability_id, artifact_path, and artifact_sha256 — the last recomputed from the file, which correctly makes hand-editing the public skill tamper-evident. That's the right local check to have.

Nothing verifies catalog_sha256, and nothing can from this repo. I confirmed CI here is a single tests.yml with no reference to catalog_sha256, --plugin-root, or the generator; brains#1069 has the mirror gap (its codegen-check.yml runs --check without --plugin-root, so 5 of 7 targets — I measured both numbers).

Net: a stale-but-internally-consistent artifact passes every automated check in both repos, as would one regenerated from a different catalog with both the file and its digest updated together. The manifest's headline property — bound to the exact catalog — is a trust-me field here.

Architectural rather than a flaw in this diff, and the fix belongs on the monorepo side; raising it here because this is where the unverifiable claim gets committed.

🟠 MEDIUM — the semantic assertions are coupled to exact generated English, across a repo boundary

About fifteen assertions now string-match generated prose:

assert(
  writeSkillNormalized.includes("its `install_id`, `action_name`, and structured `input` in `act_on_integration`") &&
    writeSkillNormalized.includes("this tuple is the only call shape"),
  "structured action tuple missing",
);
assert(writeSkillNormalized.includes("| `rate_limited` | Nothing ran and no upstream call occurred."), );
assert(writeSkillNormalized.includes("Don't blind-retry"), );

The wording is authored in the monorepo catalog; these assertions live here. A routine rewording in brains therefore breaks brains-plugins CI, with no signal in the monorepo, and the fix has to land in a second repo. The last example is coupled even to markdown table punctuation.

The intent in the comment — "so a future compaction cannot drift independently again" — is right, but matching English substrings trades silent drift for cross-repo brittleness, and the resulting failures ("someone reworded a table cell") will be opaque to whoever hits them.

Suggestion: keep the digest and leak checks here — they're repo-local and correct — and move the semantic assertions into the monorepo beside the catalog, or assert against a machine-readable rule summary (the catalog already carries structured result_semantics) instead of rendered prose.

🟡 LOW — the digest-bound artifact has no trailing newline

Verified: SKILL.md ends …forwarding a thread. with no final \n, while the sibling generated manifest.json does have one.

Because the artifact is digest-bound, any standard final-newline normalisation — .editorconfig insert_final_newline, prettier, an eol-last rule, or several editors on save — silently changes the digest and fails the contract with generated brains-write artifact digest mismatch, in a repo that doesn't contain the generator that produced it. This repo has no such tooling today, so it's latent. Worth emitting a trailing newline from the generator (brains#1069) for consistency with the manifest. It changes both digests, so it should land before gate 4's regeneration rather than after.

🟡 LOW — the compaction dropped two concrete safety details, and the digest check can't evaluate that

The rewrite is mostly a gain: it adds the inline-external-write examples (rsvp_event, create_draft, add_labels), the explicit "do not infer safety from read vs write", the fail-closed null/absent side_effect rule, and two previously-undocumented result kinds (clarification, noop with the verify_mode: distinction).

Two things went away:

  • the enumeration of what sits behind requires_confirmation: true"Destructive sends (email, calendar invite, doc create) live here";
  • the emphatic closing directive — "Always relay a destructive action's preview and confirmation hint, then leave the decision to the user's out-of-band approval surface." The mechanic survives in the table ("Relay the preview and hint, then stop"), but the standalone imperative is gone.

Probably neutral-to-positive on balance. Raising it because this is safety-critical model-facing guidance, the digest proves provenance but says nothing about adequacy, and the contract test's stated purpose is to stop compaction drift while this PR is a compaction. Worth an explicit confirmation that both omissions are intended.

🟡 LOW / informational — my verification doesn't carry past the gates

The values above are correct at today's heads. Gate 4 regenerates from #1069's final content, which will change both digests if the catalog moves at all — as the description already notes. Flagging only that this review's provenance check will need re-running at that point; it's the step that matters most.

Missing tests

  • a cross-repo check that catalog_sha256 matches a real monorepo catalog
  • an explicit final-newline contract, or a round-trip test through whitespace normalisation
  • assertions expressed against structured catalog semantics rather than rendered English
  • a check that the manifest's source_generator path still exists in the monorepo — it's free text today and would silently rot after a generator move

Verdict

Hold — do not merge, for the release-order reason the description already gives. On the diff's own merits this is approve-after-gates, conditional on: re-running the provenance verification at the final heads; confirmation that the two prose omissions above are intentional; and the two Mediums addressed or ticketed. Neither Medium blocks this merge, though the second will start costing time on the first catalog rewording after it lands.

Worth crediting: recomputing artifact_sha256 from the file inside the contract test is the right check and makes hand-edits tamper-evident, which is precisely the failure that motivated the ticket; the leak assertion (automation_secret|adminPool|handler_source|telegram_push|grant_token) is a good guard for a public artifact; keeping it committed and vendored with no install-time fetch of mutable remote content is the correct call for something users install; and the declared cross-repo order isn't just documented but verifiably accurate, including the non-obvious "#1066 is on stage but not in main."

@stefan-ssv-labs

Copy link
Copy Markdown
Contributor Author

Review follow-up at 1aa2662 from brains source head ae7887de:

  • regenerated the public skill and manifest from the final reviewed catalog; the two repositories are 7/7 fresh and digest-identical;
  • added the final newline and an explicit newline contract;
  • expanded the local plugin safety assertions for both confirmation branches, partial-tuple errors vs legacy clarification, 30/install/60s rate context, draft-only confirm_hint, past-tense auto_executed, and [DRY RUN] suppression;
  • plugin-contract, tool-error 14/14, and inbox-v2 32/32 pass locally.

The two Medium architecture items remain the documented release/deploy follow-up: a dedicated GitHub App should open reviewed cross-repo sync PRs, and the machine-readable catalog stays committed in brains until that workflow exists. They do not weaken the current content-digest or local semantic gates.

Mandatory order is unchanged and explicit in the PR body: #1066 must reach production, then plugin #16 merges, then brains #1069 merges, then this branch merges latest plugin main, regenerates again, passes checks, receives current approval, and only then may #17 merge.

@nir-ssvlabs nir-ssvlabs left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the generated brains-write face at head 1a67c3b2. Verified the binding end-to-end rather than trusting the receipt:

  • The digest binding holds and is enforced, not just declared. I recomputed sha256(SKILL.md) on the committed artifact = f14839e4…, which equals the artifact_sha256 in the committed capability-catalog.json and the provenance receipt; catalog_sha256 = c46b9cf2… matches too. The contract test recomputes this exact digest (createHash("sha256").update(writeSkill).digest("hex")) and asserts equality, so a hand-edit to the committed SKILL that skipped regeneration fails CI. The manifest fields the test pins (schema 1 / catalog_schema 1 / renderer 2 / capability_id: integration-actions / artifact_path) all match.
  • No internal capability leaked into the public face — 0 matches for automation_secret/adminPool/handler_source/telegram_push/grant_token, and that exclusion is a test assertion.
  • The independent semantic safety assertions all resolve against the whitespace-normalized artifact (the tuple-only call shape, "no source-enum fallback", both requires_confirmation branches, rate_limited/dry_run/clarification/noop result kinds, the self-confirm_action prohibition, the discard_action path, and the unknown-outcome guidance). That layer matters precisely because digest equality proves provenance but not that the source kept the safety rules — and here it did. The assertion set was broadened in this diff (added clarification/noop/dry_run/partial-tuples/rate-limit-context), not narrowed, so no rule was silently dropped alongside the regeneration; stale fields (audit_id, the legacy source-enum pointer) stay absent and the trailing newline is present.

Design is sound: installation is fully local (artifact committed, bound by content digest, no runtime/install-time fetch), and the commit-free manifest correctly binds by digest rather than commit id given squash merges. The cross-repo sequencing and the "no extra prod release of #1069 needed" call are flagged to @RaekwonIII and are a release-governance decision, not a defect in this diff.

Not duplicating @RaekwonIII's byte-identity check of the catalog vs the hub manifest — I confirmed the other half (SKILL → digest binding + the semantic safety coverage). LGTM.

@RaekwonIII RaekwonIII left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at head 1a67c3b. This has flipped from my earlier hold to approve — every blocker that was open then is now cleared, and I verified each independently rather than trusting the receipts.

Gates — all four now met (verified)

  • Gate 1 — #1066 on production. 9c64d3cd is on origin/main via the #1090 stage→main promotion. ✅
  • Gate 2 — #16 on plugins main. Merged; and origin/main is an ancestor of this branch, so #17 carries it. ✅
  • Gate 3 — #1069 on brains stage. Merged. ✅
  • Gate 4 — regenerated from the final catalog. The brains-stage manifest is byte-identical to this PR's capability-catalog.json (catalog_sha256 c46b9cf2…, artifact_sha256 f14839e4…, renderer_version 2), and I recomputed sha256 of the committed SKILL.mdf14839e4…, matching both the manifest and the brains-side generated body. So the artifact is byte-identical to what the merged #1069 generator produces. ✅

Upstream Critical resolved

The architectural concern on #1069 (the seven faces were hand-authored literals, not projected from the structured catalog) was fixed structurally — renderIntegrationActionContract is now the single common projector all adapters call — and #1069 merged. renderer_version: 2 here reflects that; this artifact is the unified-projector output.

Ravid's QA items

  • Trailing newline (LOW) — fixed; SKILL.md now ends in \n and a newline contract was added.
  • Dropped safety clauses (LOW) — the safety-critical substance is present and if anything stronger: the inline-fire enumeration (rsvp_event / create_draft / add_labels) with "do not infer safety from read vs write", the auto_failed unknown-outcome / don't-blind-retry rule, "never confirm_action yourself — only the out-of-band surface holds the secret", and the restored rate-cap / dry_run / verify_mode: clauses. The two dropped phrasings were the safe-direction enumeration and a bolded restatement whose mechanic survives in the draft row. Reads as intentional compaction, not a regression — flagging for an explicit nod, not blocking.
  • MEDIUM 1 (catalog_sha256 not auto-verified cross-repo) — I confirmed it matches brains stage manually today, so the claim holds now; the systemic fix (automated cross-repo verification) is the documented GitHub-App follow-up. Accepting as ticketed.
  • MEDIUM 2 (semantic assertions string-match generated English across the repo boundary) — real maintainability cost: the first reword in brains will break plugins CI with an opaque failure and a two-repo fix. Conscious tradeoff with a documented follow-up (move the semantic gate monorepo-side / assert against structured result_semantics). Worth keeping the ticket warm — it will bite once — but not a merge blocker.

The digest recompute (tamper-evident hand-edits), the internal-capability leak guard, and vendoring-with-no-install-time-fetch remain the right calls.

Verdict

Approve. Merge order is satisfied (all upstream gates green), the artifact is provably bound to the merged catalog, and the safety contract is intact. The two Mediums are legitimate follow-ups, not blockers — MEDIUM 2 especially is worth doing before the first catalog reword.

@stefan-ssv-labs
stefan-ssv-labs merged commit ab4de6d into main Jul 30, 2026
3 checks passed
@stefan-ssv-labs
stefan-ssv-labs deleted the feat/generated-capability-catalog branch July 30, 2026 11:26

## Live Gmail search

`gmail-inbox` ships `search_emails` with `requires_confirmation:false`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Names the gmail-inbox live-search action search_emails, but plugins/brains/skills/brains-read/SKILL.md:58 calls the same action query_emails and points the reader here for the details. One of the two makes the agent dispatch a non-existent action_name. Settle which is real and align both — this file is generated, so the fix belongs in the upstream catalog.

);
assert(
capabilityManifest.artifact_sha256 ===
createHash("sha256").update(writeSkill, "utf8").digest("hex"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The digest pin hashes writeSkill raw, while every other content pin in this file goes through normalizeRegion (line 123), which explicitly collapses \r\n. A checkout with core.autocrlf=true therefore fails generated brains-write artifact digest mismatch with no fixable cause — and .gitattributes is listed in .gitignore, so line endings can't be pinned per-repo either. Hash writeSkill.replace(/\r\n?/g, "\n") (or reuse normalizeRegion's EOL step) to match the generator's byte assumption.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants