feat: ship Slice J1 — pbrain integration (skills + CLI allowlist + auto-onboard)#82
Merged
Conversation
…uto-onboard) Mission Control gains first-class pbrain access through skills + CLI rather than MCP — keeping the per-turn schema cost off the chat-lane baseline while making pbrain operations available on demand. - @mc/core/config gains a pbrain block (env-driven PBRAIN_ROOT, default ~/code/pbrain, validated against <root>/skills/), discriminated union mirroring discord/memory.vec - @mc/core/pbrain (new) ships pbrainBashAllowlist (a CanUseTool gate that permits only `pbrain` invocations + denies shell metacharacters) and runProjectOnboard (one-shot Claude SDK call bound to the pbrain project-onboard skill, bounded by maxTurns + abortSignal) - chat-bridge composes the brainstorm prompt internally now (caller passes the base prompt + pbrain config once); pbrain-enabled chat-no-project routes cwd to the skills tree instead of the daemon's data dir to avoid exposing MC internals via SDK auto-allowed reads under cwd - mc project add runs the onboarder after registry.add() succeeds (--no-pbrain to skip; pbrain failure never inverts add's exit code) - mc project pbrain-backfill [--slug X | --all] retroactively onboards existing projects; continues iterating past per-project failures All four gates green: 1340 tests, build, typecheck, biome clean.
Review feedback: exposing all 27 pbrain skills to the chat-lane was overkill for a Socratic brainstorming persona, and the onboarder didn't need read access to skills it wouldn't invoke. - New @mc/core/pbrain/skills.ts: CHAT_LANE_SKILLS = ['query','brain-ops', 'briefing'] (single source of truth for the curated trio); ONBOARD_SKILL = 'project-onboard'; chatLaneSkillDirs + onboardSkillDir helpers. - chat-bridge: additionalDirectories now contains exactly the curated trio (and cwd, for the chat-no-project case, becomes the first curated skill dir rather than the broad skillsRoot). Other pbrain skills (ingestion, migration, scheduling, daily ops) stay invisible to the chat agent — direct CLI use only. - onboarder: additionalDirectories narrowed from [skillsRoot] to [skillsRoot/project-onboard]; the SKILL.md probe + run still work unchanged. - Brainstorm system prompt updated: names the three available skills explicitly and tells the agent to point users at the pbrain CLI for workflows outside chat scope. All 4 gates green: 1345 tests, build, typecheck, biome clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@mc/core/pbrain(new) shipspbrainBashAllowlist(Bash-only,pbrain *allowlist with shell-metachar denial) andrunProjectOnboard(one-shot Claude SDK call bound to the pbrainproject-onboardskill, bounded by maxTurns + abortSignal).mc project add <path>now runs the onboarder afterregistry.add()succeeds —--no-pbrainto skip; pbrain failures never invert add's exit code. Newmc project pbrain-backfill [--slug X | --all]retroactively onboards existing projects.additionalDirectories: [skillsRoot],Bash(pbrain:*)allowlist viacanUseTool, brainstorm prompt augmented with a "Pbrain access" section). The chat-no-project + pbrain case routescwdto the pbrain skills tree to avoid exposing MC internals (state.db, dashboard.token) via the SDK's cwd auto-allow.@mc/core/config.pbrain(new) — env-drivenPBRAIN_ROOT(default~/code/pbrain), validated against<root>/skills/; discriminated union mirrorsdiscord/memory.vec.Why this shape
Skills + CLI over MCP. Pbrain ships a
pbrain serveMCP with ~30 tools. Wiring that into chat-bridge would tax every chat turn ~2.4k tokens (80 tokens × 30 schemas) for occasional-use operations. Skills + Bash-allowlist load on demand (~500–1500 tokens per invocation) and match how pbrain itself is designed to be consumed by agents. The in-processmc-memoryMCP from I1b stays for its hot-path single-tool case — the tradeoff is asymmetric for the right reasons.CLI runs the onboarder, not the daemon. Mission Control's
EventBus<ProjectEvent>already publishesproject.addedfromregistry.add()— but the bus lives in whichever process called the registry, not across the CLI/daemon boundary. So a daemon-side subscriber wouldn't fire onmc project add. The CLI runs the onboarder itself (using a hoisted sharedcliAgentRunner), which keepsmc project addself-contained and works whether or not the daemon is up.Bash allowlist via
canUseTool, notallowedTools. The SDK'sallowedTools: ['Bash']would auto-allow any shell command, anddisallowedToolsis a name-only blocklist.canUseToolis the only surface that expresses "Bash, but onlypbrain *" — and we defend against shell metacharacter injection (pbrain query x; rm -rf /) with a regex on the trimmed command. Single-user dev tool, no privilege boundary, but a clean allowlist still bounds the agent's blast radius if a prompt-injection convinces it to try shelling out.assistant_text_deltain onboarder is gone./simplifyquality review caught that the onboarder'sassistant_text_deltacase was overwritingsummarywith the most recent partial delta, thencompleted.resultwould replace it with the full text — but if an out-of-order delta arrived aftercompleted, it would silently overwrite the good summary. Removed the case; rely oncompleted.result.composeBrainstormPromptlives in chat-bridge, not compose.ts./simplifyflagged that having bothpbrain?: PbrainEnabledConfigand a pre-composedbrainstormSystemPromptonChatBridgeOptsmade callers responsible for synchronizing two views of the same state. Moved composition inside the bridge — caller passes the base prompt + pbrain config once. Tests still pin a stub via thebasePromptoverride.Test status
pnpm build,pnpm typecheck,pnpm lint,pnpm testall green locally/simplifyran (3 reviewers in parallel); applied 11 findings (assistant_text_deltabug fix, cwd-leak fix in chat-no-project + pbrain,OnboardProject→Pick<Project,…>, hoistedpbrainBashAllowlistto a const, dropped narrative slice/swarm comments per CONTRIBUTING, etc.)Test plan
pnpm test(1340/1340)pnpm build(all packages)pnpm typecheck(all packages)./node_modules/.bin/biome check .(clean)mc project add ~/code/<some-repo>against the user's local pbrain — verify the pbrain skill kicks off, summary line prints, project still registers on pbrain failuremc project add --no-pbrain ~/code/<some-repo>— verify no pbrain outputpbrain query "<x>"works in a chat sessionDeferred / additive
/doresumes the same SDK session, so a task already inherits chat's pbrain context).pbrain serve) — one-line addition next to the existingmc-memoryMCP if a high-frequency loop ever justifies the schema cost.agentRunner.run(), capture terminal event" helper — chat-bridge, summarize-handler, and onboarder all do roughly this./simplifyflagged it; deferring until a fourth call site appears so the abstraction has real shape.👍→/do) from I1's deferred list./do.