feat(cohort): local-AI cohort chat + daily connection-graph engine#497
feat(cohort): local-AI cohort chat + daily connection-graph engine#497Mikeishiring wants to merge 7 commits into
Conversation
1. Connection engine - a daily routine (build-cohort-connections.mjs) runs the operator's own local AI CLI over the cohort markdown to compute reasoned 'who should talk to whom' edges, published to public_cohort_connections (6th Supabase overlay). The app only ever reads precomputed edges; per-team detail pages show them in the 'who should talk next' inspector. Deterministic engine is the reliable fallback. 2. Cohort chat - 'ask the cohort' panel runs the member's own local AI CLI (claude/codex/ollama, no API key), grounded in the live surface + connection edges, streaming answers. Ctrl/Cmd+Shift+K. Tests + renderer bundle + privacy/surface scans green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ebd47bb62c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // their OWN local CLI to draft a profile update. Raw never leaves the box; | ||
| // only the member-approved field delta is written, via the existing editor. | ||
| // See self-report-node.js + apps/os/src/renderer/self-report.js. | ||
| const selfReport = require("./self-report-node"); |
There was a problem hiding this comment.
Add the missing self-report module
In every Electron startup, this unconditional require resolves relative to apps/os/main.js, but a repo-wide search for self-report-node, scanLocalSessions, and runSynthesis only finds this new call/preload stubs and no apps/os/self-report-node.js, so Node throws MODULE_NOT_FOUND before any window is created. Either include the module or gate/remove these IPC handlers until it exists.
Useful? React with 👍 / 👎.
The daily connection routine, run with Claude (this session) as the LLM: 5 agents reasoned over every team's seeking/offering/skills/journey/dependencies to produce 130 grounded, often non-obvious who-should-talk-to-whom edges (live integrations, declared deps, exact need↔offer matches), each with a written reason. This is the committed offline baseline; the live public_cohort_connections row is the runtime overlay. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ine baseline) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Live state (applied 2026-06-25): the |
main.js unconditionally require()'d ./self-report-node and registered fg:self-report:* handlers, but that module lives on the Your-Mirror branch (#504) and does not exist here — so the Electron main process threw at boot and the app never started. The block leaked from a shared base; nothing in this PR's two features (connections engine, cohort chat) uses it, and no renderer references the preload entries. Remove the require + both handlers from main.js and the bridge entries from preload.js. All 7 local requires in main.js now resolve. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…connections # Conflicts: # apps/os/src/cohort-surface.json
…wable Folds the load-bearing privacy engineering from the Hermes "Ask Cohort" PR (#417) into this chat, which the review flagged as lacking an enforced public/private boundary on its CLI spawn: - Provider-key stripping: cohort-chat-node.js spawnEnv() and the build side's local-ai-cli.mjs stripProviderKeys() now drop ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN / CLAUDE_CODE_OAUTH_TOKEN / OPENAI_API_KEY[_PATH] from the spawn env (opt back in with COHORT_CHAT_USE_ENV_KEYS=1). This also fixes the flagged full-`process.env` passthrough — the member's CLI now rides THEIR login/subscription, never a key inherited from us. - Data-sensitivity gate: assertBackendAllowed(dataMode, backend) blocks non-public grounding from reaching a remote backend (claude/codex); ollama (local) may receive anything. cohort grounding is public today, so this is structural defense-in-depth, not a behaviour change. - 5 unit tests lock the gate + strip (the spawn path was untested before). Also replaces the engine's 8 literal NUL-byte composite-key separators with "::" (verified: no record id contains a colon), so git stops classifying cohort-connections-engine.mjs as binary and the deterministic scorer is actually reviewable in the diff. 12/12 engine tests unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regression guard for the boot crash fixed earlier in this PR: a stray
require("./self-report-node") for a file that existed only on another
branch threw at Electron main-process boot, and nothing in the suite
caught it (renderer/unit tests and static asar analysis never load the
main process). This test reads main.js + preload.js, extracts every
local require("./…"), and asserts each resolves — failing loudly if a
future change references a module that isn't on the branch.
Verified end-to-end alongside this: `electron . --smoke-test` boots
clean (PASS, exit 0) on this branch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Boot verified end-to-end. After removing the stray The main process loads, preload runs, and boot.js completes every checkpoint. ( Also in this pass: harvested #417's provider-key stripping + data-sensitivity gate into the chat spawn (5 new tests), and replaced the engine's 8 NUL-byte composite keys with |
Two features on the read-side of the cohort value loop — both designed around bring-your-own local AI (no API keys) and precompute-then-read (the app never calls an LLM at runtime).
1. Daily connection engine → per-team "who to talk to"
A precomputed "who should talk to whom" graph, surfaced per team and as chat grounding.
scripts/lib/cohort-connections-engine.mjs— pure, deterministic scorer: normalizes every team/person toseeks/offers/skillstoken bags and scores directional edges from seeking↔offering matches, skill overlap, shared clusters, and declared dependencies — each with a written reason. 445 edges over current data.scripts/build-cohort-connections.mjs— the daily routine: runs the operator's own local AI CLI (claude/codex/ollama, auto-detected, orCOHORT_LLM_CMD) over the corpus + deterministic candidates to refine reasons. Falls back to the deterministic graph when no CLI/bad JSON. No API key.publish-connections-to-supabase.mjs+ migrationpublic_cohort_connections(anon-read/service-write) + readersupabase-connections.mjs+applyConnectionsOverlay— the 6th live overlay (same pattern as the release feed; committedcohort_connectionsis the offline baseline)..github/workflows/cohort-connections-sync.yml— hourly publish of the committed artifact (no LLM in CI). (Not in this commit — needs a workflow-scoped token to push; see below.)npm run build:connections(local AI) → commit → workflow publishes. Ornpm run build:connections:publishto do both locally.2. "Ask the cohort" chat
apps/os/cohort-chat-node.js— spawns the member's local AI CLI one-shot, pipes a grounded prompt to stdin, streams tokens back (mirrorsswarm-node.js). No API key.cohort-chat-context.mjs— retrieval-ranks the live surface into a compact grounded prompt: team profiles + the connection edges, distilled session insights, recent activity. The two features share one matching brain.cohort-chat.js/.css+ markup), opened via the "ask the cohort" button or Ctrl/Cmd+Shift+K.Verification
claude -p/ollama runread stdin cleanly; Codex reads its prompt as an argument, so set the command explicitly in chat settings.Follow-ups
cohort-connections-sync.ymlis omitted from this commit — pushing.github/workflows/needs aworkflow-scoped token. Add it once the token allows (gh auth refresh -h github.com -s workflow), or merge it via the GitHub UI.build:connections:publish(queued behind this landing).🤖 Generated with Claude Code