Brainblast Scout
End-to-end pipeline for an agent to go find a new "silent footgun" in some
external SDK/protocol, turn it into a proven brainblast knowledge pack, and
submit it — the same workflow used to produce
packs/jupiter-quote-zero-slippage and packs/spl-transfer-not-checked-in-payout.
Default scope is Phases 1–4 — they are entirely no-spend (research → prove →
package → submit). They are all you need to produce and sell the data: a pack
that lands in packs/ flows straight into the corpus and the storefront via
npm run intake (gen:vti → pack:dataset → corpus → catalog), no $BRAIN
required. Phase 5 (stake) is OPTIONAL and opt-in — a quality bond layered on
top, run only when the operator has set up the capped ops-wallet + caps. This is
a core marketplace invariant (ROADMAP.md, Lane 4): data intake never blocks on spend.
Each phase fails closed: if a phase doesn't produce a clean result, stop and surface a draft for human review rather than forcing it through.
Stop after Phase 4 by default. Only proceed to Phase 5 if the user has explicitly asked to stake AND the ops-wallet env (
AGENT_OPS_WALLET_SECRET+ caps) is configured. Producing the data does not require it.
Fleet mode (the fast path — prefer this)
The fleet (fleet/, npm run fleet) automates prove → promote → intake →
score, so a scout run is just: pick a work-order, drop a candidate, run the
fleet.
- Target a work-order. Run
npm run fleet -- --dry-run(or readdatasets/COVERAGE.md) and pick an uncovered class or thin cell from the scoreboard — that's where a new trap is worth most. - Write a candidate
fleet/candidates/<id>.json(a Finding — seefleet/README.mdfor the template). Prefer the vettedobject-arg-property-forbidden-literalchecker (flags an options-object property set to a forbidden string/number/boolean literal — the shape of most insecure-default footguns); no new checker code needed. - Run the fleet.
npm run fleetproves every candidate RED→GREEN, auto-promotes the proven ones topacks/, regenerates the corpus + storefront, and prints what landed + the next work-orders. A candidate that doesn't reproduce is reported DRAFT and never lands.
That's the whole no-spend loop. The detailed Phases below are the reference for
how a Finding is shaped and what the gate checks; for routine sourcing, use
fleet mode. (Phases 2b/3 — manual synth + cp into packs/ — are what the
fleet now does for you.)
Phase 1 — Scout
Research one external SDK/protocol (Solana programs, payment SDKs, etc.) for a pattern where the happy path compiles and runs but silently does the wrong thing — wrong constant, missing check, unchecked return value, misordered calls. Good sources: official docs changelog, GitHub issues tagged "footgun"/"gotcha", postmortems, audit reports.
Use /browse for any web research (per the user's global gstack
instructions — never drive Chrome directly).
Output: a candidate description in plain English — the SDK, the call/shape that's wrong, why it's wrong, and what the fixed version looks like. This is NOT yet a Finding JSON; it's the raw idea.
Phase 2 — Synthesize into a Finding
Turn the candidate into a Finding (see
packages/core/src/synth/types.ts) and write it to
packages/core/findings/<id>.json. Required:
binding.check.kindMUST be one ofcheckerKindsinpackages/core/src/checkers/index.ts— if your pattern needs a new checker kind, that's a separate, larger task (see howliteral-multiplier-wrong-constantandfee-allocation-shapewere added historically); don't invent an unvetted kind here.binding.test.kindsimilarly must be intestKinds.fixtures.vulnerable/fixtures.fixedare full file contents — write real, minimal, compilable-looking code demonstrating the trap and its fix.
Then run, from packages/core/:
npm run synth -- findings/<id>.json
- exit 0 (PROVEN): rule + fixtures staged in
.synth/, ready to promote. Continue to Phase 3. - exit 2 (DRAFT): written to
packages/core/drafts/<id>/for human review. STOP here — do not proceed to packaging or staking on a draft. - exit 1: bad input, fix the Finding JSON and retry.
Phase 3 — Package as a pack
Create the standalone pack directory:
npx brainblast pack init packs/<pack-id> --id <pack-id> --name "<name>" \
--author <your-handle> --version 0.1.0 --description "<one-line>"
Copy the PROVEN rule YAML and vulnerable/fixed fixtures from .synth/
into packs/<pack-id>/rules/ and packs/<pack-id>/fixtures/<pack-id>/...
(mirror the layout of packs/jupiter-quote-zero-slippage). Write a short
README covering: what the trap is, why it's silent, the fix.
Validate:
npx brainblast pack validate packs/<pack-id>
Must pass before continuing.
Phase 4 — Submit
-
Push
packs/<pack-id>as its own repo (or a subdirectory PR to this repo, matching how the existing packs were added). -
Open a PR against
brainblast-pack-registryadding an entry topacks.json(pack_id,name,repo_url,author,description,latest_version) — same shapelib/sync.ts'ssyncPackRegistry()expects. -
The registry's daily cron (
/api/cron/sync) will pick it up automatically once the PR merges — no manual sync call needed. -
Run intake so the pack becomes sellable data (no-spend). Once the pack is in
packs/, frompackages/core/:npm run intake -- --pack ../../packs/<pack-id>This validates the pack RED→GREEN, then runs the conveyor (
gen:vti → pack:dataset → corpus → catalog) so the new trap lands in the seed lot, the packaged/sellable lots, the corpus index, and the storefront (datasets/CATALOG.md) in one step. Confirmnpm run slastill passes. This is the end of the no-spend default path — the data is now produced and sellable.
Phase 5 — Stake $BRAIN (OPTIONAL — opt-in bond, spends funds)
Skip this unless the user explicitly asked to stake and the ops-wallet is configured. Staking is a quality bond, not a requirement: the data is already produced and sellable after Phase 4's intake. The reproduction gate intake just ran is the same RED→GREEN check a stake would be slashed against.
Security model: staking is paid from a small, dedicated "ops wallet" —
not the user's main wallet. The user funds this wallet periodically (e.g.
$20-50 of $BRAIN/SOL). scripts/agent-stake/stake.ts enforces a
per-transaction cap (AGENT_STAKE_MAX_USD, default $25) and a cumulative
session cap (AGENT_STAKE_SESSION_CAP_USD, default $50) before sending
anything. The secret key is read only from AGENT_OPS_WALLET_SECRET (env
var) and is never logged or written to disk. Worst case if this wallet is
compromised: whatever it currently holds — never the user's main holdings.
- Decide
stake_usdfor the pack (reasonable default: $10-25). - Determine
brain-amount— the $BRAIN token amount equivalent tostake_usd(with the 10% $BRAIN discount), via a price lookup (e.g. Jupiter price API forBRAIN_MINT). This script does not fetch prices itself — compute it first. - Run:
cd scripts/agent-stake
npm install # first time only
AGENT_OPS_WALLET_SECRET=*** AGENT_STAKE_MAX_USD=25 AGENT_STAKE_SESSION_CAP_USD=50 \
npx tsx stake.ts --pack-id <pack-id> --rule-id <rule-id> \
--stake-usd <usd> --brain-amount <amount>
If either cap would be exceeded, the script refuses and exits 1 — do not raise the caps from inside this skill; that's a human decision (the caps are read from env vars the user sets when funding the wallet).
Done
Report: pack id, PROVEN/DRAFT status, PR URL(s) opened, stake tx signature (if Phase 5 ran), and current session spend vs. cap.
微信扫一扫