Agents: real ClawBrainHub integration (list + pull brains → trading cards)
CI / policy (push) Has been cancelled
CI / backend (push) Has been cancelled
CI / profile (push) Has been cancelled
CI / mobile (push) Has been cancelled

Backend:
- brainhub.rs: BrainHubClient trait + HttpBrainHubClient (public discovery API,
  optional Bearer token) + FakeBrainHubClient. Lists the user's brains
  (CLAWBRAINHUB_OWNER, default "omar") + redclawsystems reference brains, and
  pulls a .brain JSON, parsing identity/skills/tools into card fields
  (tagline, skills, tools, capabilities). 2 parser unit tests.
- Routes GET /v1/brainhub/brains + /v1/brainhub/pull (rate-limited); wired into
  AppState + main (HttpBrainHubClient) + test harness (FakeBrainHubClient).

Mobile:
- src/api/brainhub.ts (listBrains/pullBrain), draftStore.pendingAgentBrain.
- app/pick-brain.tsx: pick a brain → pull → hand to the agent-card editor.
- Agents "+ New agent" now opens the brain picker; demo.tsx adopts the pulled
  brain (name, tagline, skill bars, tools, capabilities) for the flip side.

Verified live against clawbrainhub.com (omar's brains + reference brains list;
general-assistant pull yields real skills). Token stays server-side/env only.
Gate: mobile 28, backend 123.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-06 00:50:16 -05:00
co-authored by Claude Opus 4.8
parent d30deaf857
commit 9765a08a5a
13 changed files with 611 additions and 3 deletions
+24
View File
@@ -107,6 +107,15 @@ function buildDemoCard(
};
}
/** "general-assistant" → "General Assistant". */
function prettifyBrainName(name: string): string {
return name
.split(/[-_\s]+/)
.filter(Boolean)
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
.join(" ");
}
export default function CardEditorScreen() {
const router = useRouter();
const { cardId, kind: kindParam } = useLocalSearchParams<{ cardId?: string; kind?: string }>();
@@ -173,6 +182,21 @@ export default function CardEditorScreen() {
setShowing(false);
draft.setPendingVideoUri(null);
}
// A brain pulled from ClawBrainHub → prefill the agent card's flip side.
if (draft.pendingAgentBrain) {
const b = draft.pendingAgentBrain;
setCardKind("agent");
setName(prettifyBrainName(b.name));
setTitle(`v${b.version} · @${b.owner}`);
setAgentMeta({
tagline: b.tagline,
skills: b.skills.map((s) => ({ name: s, level: 4 })),
tools: b.tools,
capabilities: b.capabilities,
});
setShowing(false);
draft.setPendingAgentBrain(null);
}
}, []),
);