v0.42.2.0 feat: gbrain connect — one-command Claude Code onboarding from a bearer token#1683
Merged
Merged
Conversation
Extract parseAuthCreateArgs; only exclude the --takes-holders value from the positional search when the flag is present (rest[takesIdx+1] resolved to rest[0] when takesIdx === -1, silently dropping the name). Add regression test.
…er token New connect command prints a paste-ready claude-mcp-add block (or --install wires it + smoke-tests the token via a raw-bearer get_brain_identity probe). Direct HTTP MCP, literal-token default, URL normalization, token header-injection guard, --json redaction, execFileSync (no shell). Wired into CLI_ONLY + CLI_ONLY_SELF_HELP + handleCliOnly. 58 unit + 3 PGLite-E2E cases; e2e-test-map updated.
…ADME one-liner Regenerate llms-full.txt for the README change.
- DRY: single DEFAULT_PROBE_TIMEOUT_MS + shared isAuthErrorMessage predicate - reuse promptLine (shared stdin lifecycle) for the --install confirm - harden redactToken with a Bearer <value> scrub (defense in depth) - +8 tests: orchestrator guard paths, deterministic timeout, invalid --timeout-ms, Bearer-redaction
- probe: Promise.race the call against a real timer so a stalled connect()/SSE handshake (signal alone doesn't cover it) can't hang --install indefinitely - probe: close transport even if client.connect() throws - parseArgs: reject a missing/flag-shaped value (e.g. --token --install) - block link-local / cloud-metadata hosts (169.254/fe80:/fd00:ec2::254) — keeps localhost + RFC1918 LAN brains working - non-interactive --install now requires --yes - clearer message when --force removed then add failed +8 tests covering each
- POSIX single-quote the rendered claude-mcp-add command so a token with shell metacharacters ($(), backticks) can't trigger command substitution on paste - detect IPv4-mapped IPv6 metadata addresses (::ffff:169.254.x.x / ::ffff:a9fe:*) so they don't bypass the link-local guard +3 tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(v0.42.2.0) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n-client-onboard # Conflicts: # CHANGELOG.md # VERSION # package.json # src/cli.ts
--agent codex emits 'codex mcp add ... --bearer-token-env-var GBRAIN_REMOTE_TOKEN' (token read from the env var at runtime, never in Codex config; --install runs it). --agent perplexity prints the URL + token for the Settings → Connectors GUI (no --install). Generalized the command file: AGENT_SPECS table, buildCodexMcpAddArgv, cmdString(binary,argv), binary-generic ConnectDeps (hasBinary/runBinary/env), agent-aware buildConnectBlock/buildJson. +25 tests.
…OG, CLAUDE.md) Regenerate llms-full.txt for the CLAUDE.md/README edits.
…a live server Adds claude-code + codex cases to connect-bearer.test.ts that run the real 'claude mcp add' / 'codex mcp add' through 'gbrain connect --install' against a live 'gbrain serve --http' (sandboxed HOME/CODEX_HOME), then assert via 'claude mcp get' / 'codex mcp get' that the server registered (and codex's token stays out of config). Skips when the binary is absent. Perplexity is GUI-only so it's print-asserted. Regen llms for the CLAUDE.md note.
…exity feedback) PERPLEXITY.md now documents the host-side HTTP setup (gbrain serve --http --bind 0.0.0.0 --public-url, the v0.34 ECONNREFUSED footgun) and the OAuth 2.1 client_credentials path (gbrain auth register-client) alongside the legacy bearer token. The 'connect --agent perplexity' output points at the same bind/public-url requirement + PERPLEXITY.md.
…/generic OAuth is the correct path for a third-party cloud connector (Perplexity): instead of a long-lived full-access bearer token, the connector gets Issuer URL + Client ID + Client Secret and mints short-lived scoped tokens. --oauth --register mints a least-privilege client on the host (shells gbrain auth register-client); --oauth --client-id/--client-secret uses an existing one. Rejected for claude-code/codex (bearer) and with --install. Issuer derived from the mcp-url. New E2E proves the full chain: register → connect --oauth → OAuth discovery → /token client_credentials mint → get_brain_identity tool call against a live server. Docs: PERPLEXITY.md leads with OAuth; README + CLAUDE.md updated; +18 unit cases.
The remote-client onboarding command was documented in README/CLAUDE_CODE/CODEX/ PERPLEXITY but missing from INSTALL.md §3 (the natural 'how do I connect a client' home). Add the one-command connect how-to (claude-code/codex/perplexity) and the missing docs/mcp/CODEX.md link.
The self-orientation block told a connected agent that `capture` is an available MCP tool. It isn't — `capture` is a CLI-only convenience command; the MCP write tool is `put_page`. An agent that followed the instruction hit "unknown tool". Drop capture; put_page was already in the list. Adds a regression block to connect.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When mcp.publish_skills is OFF, connected agents can search/write but can't call list_skills/get_skill, so the host's skill catalog is invisible to them. The startup banner now shows a Skills: line, and a stderr nudge fires when off with the paste-ready fix. Pure skillPublishStatus() helper, unit-tested. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spawns real `gbrain serve` (stdio) against a freshly init --pglite brain and drives the official MCP SDK client through initialize -> tools/list -> tools/call (get_brain_identity + search). Pins the advertised core-tool set against what the server actually exposes (asserts capture is NOT advertised). This funnel had zero e2e coverage before. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 'no-op when audit dir does not exist' case called pruneOldBatchRetryAuditFiles(30) without a GBRAIN_AUDIT_DIR override, so it read the real ~/.gbrain/audit and flaked (kept:1) on any dev machine with a batch-retry-*.jsonl on disk. Point it at a guaranteed-missing temp subdir, matching this file's own hermetic-header contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New tutorial docs/tutorials/connect-coding-agent.md: Path A (connect to an existing brain) + Path B (start from nothing, local stdio), the brain-first protocol to paste into CLAUDE.md/AGENTS.md, and the four translatable habits. README gains a 'Quick start: Claude Code or Codex' fork separating lightweight retrieval from the full autonomous install. INSTALL.md shows the one-command wire-up at the standalone CLI section. mcp/CLAUDE_CODE + CODEX cross-link the tutorial + note publish_skills + capture-is-CLI-only. Tutorial promoted to Shipped in the tutorials index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mgunnin
added a commit
to mgunnin/gbrain
that referenced
this pull request
Jun 3, 2026
* upstream/master: v0.42.8.0 feat: content-quality gate on sync — quarantine junk + flag boilerplate (garrytan#1699) (garrytan#1756) v0.42.7.0 feat(extract): link/timeline extraction freshness watermark — gbrain extract --stale + doctor lag check (garrytan#1696) (garrytan#1755) v0.42.6.0 feat(enrich): gbrain enrich --thin — brain-internal grounded synthesis for stub pages (garrytan#1700) (garrytan#1757) v0.42.5.0 fix(minions): RSS watchdog opacity + pooler-reap self-heal + silent lens backlog + cycle lint DB-disconnect (garrytan#1678) (garrytan#1735) v0.42.4.0 fix: think --model fails loud — slash-form ids + never persist empty synthesis (garrytan#1698) (garrytan#1736) v0.42.3.0 feat(search): autocut — score-discontinuity result-sizing (garrytan#1663 wave 1) (garrytan#1682) v0.42.2.0 feat: gbrain connect — one-command Claude Code onboarding from a bearer token (garrytan#1683)
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
One command to wire a coding agent to a remote gbrain from a bearer token (or OAuth), for Claude Code, Codex, and Perplexity Computer.
gbrain connect <mcp-url>(src/commands/connect.ts) — turns a remote MCP URL + credential into a paste-ready setup block, or wires it up directly with--installand smoke-tests the credential before you walk away. Direct HTTP MCP, no local install/proxy. The printed block tells the agent to callget_brain_identity+list_skills.Per-agent (
--agent):claude mcp add ... -H "Authorization: Bearer <tok>".--installruns it.codex mcp add <name> --url <url> --bearer-token-env-var GBRAIN_REMOTE_TOKEN— Codex reads the token from the env var at runtime, so it never lands in Codex config.--installruns it.--install). Bearer works, but OAuth is the recommended path (it's a cloud service).Authorizationheader (or OAuth fields) for any other MCP client.OAuth 2.1 client credentials (
--oauth, perplexity/generic) — the correct path when the credential lives on a third-party cloud: least-privilege scopes + short-lived rotating access tokens instead of a long-lived full-access bearer.--oauth --registermints a client on the host in one command;--oauth --client-id X --client-secret Yuses an existing one (runs anywhere). Rejected for claude-code/codex (they consume bearer) and with--install.Raw-bearer MCP probe (
src/core/connect-probe.ts) —--install's smoke test does a realinitialize+tools/call get_brain_identityover the official SDK with a static Authorization header (not the OAuth-onlycallRemoteTool), bounded by aPromise.racetimeout so a stalled server can't hang it.gbrain auth createbugfix (src/commands/auth.ts) — the bare form (gbrain auth create <name>, no--takes-holders) silently dropped the name; fixed + extractedparseAuthCreateArgs.Wiring:
cli.tsdispatch (CLI_ONLY+CLI_ONLY_SELF_HELP+handleCliOnly, no-DB). Security: POSIX single-quoted commands (paste-safe), token header-injection validation, link-local/cloud-metadata exfil guard (incl. IPv4-mapped IPv6), token/secret redaction in errors +--json,--installrequires--yesnon-interactively.Test Coverage
test/connect.test.ts(100 cases): URL normalization, token/secret validation + redaction, all four agents' blocks + JSON, OAuth helpers (issuer derivation, register orchestration, BYO creds), everyrunConnectguard path (claude/codex--install, oauth rejections, arg-guard).test/auth-create-args.test.ts(6, bare-name regression).test/e2e/connect-bearer.test.ts(7) against a livegbrain serve --http(PGLite):get_brain_identity; wrong token →auth; unreachable →unreachable.claudeCLIclaude mcp addviaconnect --install→claude mcp getconfirms registration (sandboxedHOME).codexCLIcodex mcp add --bearer-token-env-var→codex mcp getconfirms (token stays out of config; sandboxedCODEX_HOME).connect --oauthformats it → OAuth discovery →/tokenclient-credentials mint →get_brain_identitytool call.bun run verify29/29; full unit suite green (one pre-existing, unrelatedbatch-retry-auditlocal-only test that passes in CI).Pre-Landing Review
Specialists (testing, maintainability, security, performance): 0 critical; all informational auto-fixed or documented.
Adversarial Review
Claude adversarial + Codex structured (
GATE: PASS, no [P1]). Real fixes: probePromise.racetimeout (a stalledconnect()could have hung--install), close transport on connect-throw, reject flag-shaped arg values, non-interactive--installrequires--yes, POSIX single-quote the command (paste-safety), IPv4-mapped IPv6 metadata guard.Plan Completion
5/5 in-scope tasks DONE; T6 (
--env-token) and T7 (Tier 2 local thin-client) deferred by design (filed in TODOS).TODOS
Added
## v0.42.2.0 gbrain connect follow-ups(T6--env-token, T7 Tier 2 bearer thin-client). No existing items completed.Documentation
gbrain connect, keeps local stdio path.--oauth --register),serve --bind 0.0.0.0 --public-urlECONNREFUSED footgun, both auth paths.gbrain connectfor all three agents + links CODEX.md.connect.ts+connect-probe.ts(multi-agent + OAuth);auth.tsbare-name fix. llms-full.txt regenerated.Coverage:
gbrain connecthas reference (README, CLAUDE.md, per-client docs), how-to (CLAUDE_CODE/CODEX/PERPLEXITY/INSTALL examples), and tutorial (CHANGELOG "To take advantage" walkthrough). No documentation debt.Documentation Debt
Test plan
bun test test/connect.test.ts100/100bun test test/e2e/connect-bearer.test.ts7/7 (real claude + codex + OAuth chain)bun run verify29/29claude/codexregistration against a live server🤖 Generated with Claude Code
Follow-up (this session): two-funnel onboarding + fixes
Extends the same v0.42.2.0 wave so the "use gbrain with my coding agent" story is complete and documented, not just the remote-connect mechanism.
connectLEARN_INSTRUCTION named a non-existent MCP tool (src/commands/connect.ts): the self-orientation block told connected agentscapturewas a core tool.captureis CLI-only, not exposed over MCP — an agent that followed it hit "unknown tool". Now namesput_page(the real MCP write tool). Regression block intest/connect.test.ts.serve --httpsurfaces skill-publishing status (src/commands/serve-http.ts): whenmcp.publish_skillsis OFF, connected agents can't calllist_skills/get_skill, so the host's skill catalog is invisible. Startup banner now shows aSkills:line; a stderr nudge fires when off with the paste-readygbrain config set mcp.publish_skills true. PureskillPublishStatus()helper, unit-tested (test/serve-skills-publish-nudge.test.ts, 6 cases).test/e2e/serve-stdio-roundtrip.test.ts, 3 cases): spawns realgbrain serve(stdio) against a freshlyinit --pglitebrain and drives the official MCP SDK client throughinitialize→tools/list→tools/call(get_brain_identity+search). Pins the advertised core-tool set against what the server actually exposes (assertscaptureis NOT advertised). This funnel had zero e2e coverage before.test/audit/batch-retry-audit.test.ts): the "audit dir does not exist" case read the real~/.gbrain/audit(no temp override) and flaked (kept:1) on any dev machine with abatch-retry-*.jsonlon disk. Now points at a guaranteed-missing temp subdir, matching the file's own hermetic-header contract. Pre-existing isolation bug; fixed since this branch lands next.docs/tutorials/connect-coding-agent.mdcovers Path A (connect Claude Code / Codex to a brain you already run) and Path B (start from nothing: local PGLite +claude/codex mcp add gbrain -- gbrain serve), plus the brain-first protocol to paste intoCLAUDE.md/AGENTS.mdand the four translatable habits (brain-first lookup, ambient capture, briefing-from-your-brain, whoknows). README gains a "Quick start: Claude Code or Codex" fork separating lightweight retrieval from the full autonomous install;INSTALL.mdshows the one-command wire-up at the standalone CLI section;mcp/CLAUDE_CODE.md+mcp/CODEX.mdcross-link the tutorial and note the publish_skills + capture-is-CLI-only gotchas; tutorial promoted to Shipped in the index.Test note
Affected files all green:
connect+serve-skills-publish-nudge+batch-retry-audit(120 unit) + the stdio e2e (3) +bun run verify(29/29) +typecheck. The full parallel unit suite was OOM-thrashing on this shared box (a sibling Conductor workspace was running its own suite concurrently); the only real failure surfaced was thebatch-retry-auditisolation bug, now fixed and confirmed hermetic.