diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 00000000..9191e7d5 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,104 @@ +{ + "name": "cortex", + "description": "Persistent memory for Claude Code — remembers across sessions automatically. Install and forget. Scientific retrieval backed by 41 published papers.", + "version": "3.14.13", + "author": { + "name": "Clement Deust", + "email": "admin@ai-architect.tools" + }, + "homepage": "https://github.com/cdeust/Cortex", + "repository": "https://github.com/cdeust/Cortex", + "license": "MIT", + "keywords": [ + "memory", + "persistent", + "mcp", + "claude-code", + "neuroscience", + "agents" + ], + "mcpServers": "./.mcp.json", + "postInstall": { + "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/install-plugin.sh", + "message": "Installing Cortex (PostgreSQL + pgvector + Python deps + embedding model) and removing any stale older Cortex installs..." + }, + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.session_start'", + "timeout": 30 + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.auto_recall'", + "timeout": 5 + } + ] + } + ], + "PostToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.post_tool_capture'", + "timeout": 10 + }, + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.preemptive_context'", + "timeout": 5 + }, + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.pipeline_impact_bump'", + "timeout": 5 + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.session_lifecycle'", + "timeout": 30 + } + ] + } + ], + "Notification": [ + { + "matcher": "compacted", + "hooks": [ + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.compaction_checkpoint'", + "timeout": 10 + } + ] + } + ], + "SubagentStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bash -c 'PY=$(command -v python3 || command -v python) && ROOT=\"${CLAUDE_PLUGIN_ROOT:-$PWD}\" && \"$PY\" \"$ROOT/scripts/launcher.py\" mcp_server.hooks.agent_briefing'", + "timeout": 5 + } + ] + } + ] + } +} diff --git a/.memsearch/.index.pid b/.memsearch/.index.pid new file mode 100644 index 00000000..9bbdaa5b --- /dev/null +++ b/.memsearch/.index.pid @@ -0,0 +1 @@ +51120 diff --git a/.memsearch/memory/2026-05-27.md b/.memsearch/memory/2026-05-27.md new file mode 100644 index 00000000..06f15275 --- /dev/null +++ b/.memsearch/memory/2026-05-27.md @@ -0,0 +1,60 @@ + +## Session 15:49 + +### 15:49 + +- User reported being unable to run commands due to network restrictions in Geneva; Claude Code attempted to probe login shell for PyPI credentials but was blocked by a guardrail that classified it as credential exploration. + +- Claude Code investigated the actual publishing situation and discovered PyPI publishing was deliberately removed on 2026-04-25 (ADR-0050), with Cortex using marketplace-only distribution; the real gap was that v3.17.1 shipped the security fix code but marketplace.json still advertised version 3.17.0, preventing update prompts. + +- Claude Code bumped `.claude-plugin/marketplace.json` (both version fields) and `pyproject.toml` from 3.17.1 to 3.17.2, committed as `e5d2e16`, and pushed to main. + +- Claude Code created and pushed tag v3.17.2, manually created a GitHub Release to trigger the marketplace publish workflow immediately, and verified the `publish-ccplugins.yml` run (26515060666) succeeded in 10s—the security fix is now advertised to the marketplace. + +- Claude Code restored the removed `build` and `publish-pypi` jobs into `release.yml` as a deprecated channel (reusing the existing OIDC trusted-publisher entry), updated README.md to clarify marketplace as the only supported path, closed PR #48, and committed as `9c9b659`. + +- Final state: main at `9c9b659`, marketplace advertises 3.17.2, security fix delivered via supported channel, PyPI reinstated as deprecated for next releases, no PyPI web-UI reconfiguration required. + + +## Session 15:55 + +### 15:55 + +- User requested Claude Code to credit the advisory and close it. +- Claude Code checked advisory GHSA-gvpp-v77h-5w8g state and found EQSTLab already credited+accepted as reporter, advisory published since 2026-05-27T12:12:49Z, CVE ID null. +- Claude Code clarified that "close" for a published advisory could mean withdraw (destructive) or request CVE (finalization), and asked user for disambiguation. +- User chose to request CVE while keeping the advisory published. +- Claude Code issued POST request to `/repos/cdeust/Cortex/security-advisories/GHSA-gvpp-v77h-5w8g/requests_for_cve` (202 Accepted); verified final state shows advisory published, EQSTLab credited, CVE request queued (async assignment pending). +- Claude Code summarized complete security work: fix merged (5d22091), v3.17.2 shipped, PyPI reinstated as deprecated, sibling repos audited clean. + + +## Session 16:53 + +### 16:53 + +- User requested that Claude Code clean up WIP branches to reduce clutter. +- Claude Code surveyed all branches and stashes, identified 4 unmerged local branches, checked PR merge status via git diff, and confirmed which were safe to delete. +- Claude Code deleted two merged branches (`security/ghsa-gvpp-v77h-5w8g` via PR #47, `fix/mcp-remember-recall-schemas` via PR #45) locally and remotely, and pruned stale remote refs. +- Claude Code characterized the two remaining WIP branches (`wip/layout-authority-sse-streaming` with 1 commit on graph-load streaming, `wip/conversational-theme-recall` with 5 commits on theme-grounded recall) and asked user whether to keep or delete each. +- User chose to keep `wip/layout-authority-sse-streaming` and delete `wip/conversational-theme-recall`; Claude Code deleted the latter locally and remotely. +- Claude Code dropped 3 junk stashes tied to now-deleted branches and merged PRs, preserved 2 stashes related to the layout-authority work, and left 2 large orphaned stashes untouched. + + +## Session 17:42 + +### 17:41 + +- User requested that Claude Code rebase the `wip/layout-authority-sse-streaming` branch onto main (122 commits behind) to enable a clean PR without losing the SSE/layout-authority work being modified. + +- Claude Code backed up the branch, applied two stashes (streaming refactor + cochrane doc, frontend bits), removed vendored `deps/` junk, squashed to one commit, and rebased onto main, resolving 3 conflicts in `http_standalone.py`, `polling.js`, and `unified-viz.html` by keeping both old and new route logic. + +- Verified rebase success: branch now 0 behind main with 2 commits, security fix intact, streaming work wired, all imports OK, 26/26 layout-authority tests pass. + +- Launched viz server to measure SSE streaming performance and discovered three bugs: (1) build never reached `baseline_ready` because `__global__` domain node was excluded from batches due to offset captured after `_ensure_domain`, (2) `_observe_pressure()` was O(N×files) summing `pending_symbols` on every emit (86k-edge batch pinned CPU for minutes), (3) native AST parse ran synchronously before streaming started. + +- Fixed all three bugs: moved offset capture before `_ensure_domain`, replaced `sum()` with O(1) counter (90k emits now 0.23s), deferred native AST parse in streaming mode; committed as `6283f3e`. + +- After fixes, graph completes and shows cleanly (135k–138k nodes, 166k–169k edges), but first-paint is ~100s on the large DB due to synchronous load/ingest of baseline (107k memories, 86k edges, 22k entities) before streaming begins; identified skeleton-first staging as the focused path to sub-second first-paint. + +- Branch is PR-ready; Claude Code asked user whether to push PR now or wire skeleton-first staging first. + diff --git a/.memsearch/memory/2026-05-28.md b/.memsearch/memory/2026-05-28.md new file mode 100644 index 00000000..1e546283 --- /dev/null +++ b/.memsearch/memory/2026-05-28.md @@ -0,0 +1,148 @@ + +## Session 09:22 + +### 09:22 + +- Human asked Claude Code to continue implementing skeleton-first staging to achieve sub-second first-paint for the graph visualization. +- Claude Code identified the root cause: the build progress callback was missing after `builder.build()`, causing the phase message to stick at the last source-loaded update (memory_entity_edges) while the full build ground on 107k memories. +- Claude Code implemented two-stage graph building by modifying `http_standalone_graph.py` to call `build_workflow_graph()` with stage="skeleton" first (≪1s, domains + setup only), then stage="full" for the complete build; updated `http_standalone_endpoints.py` to expose both stages. +- Claude Code verified that `appendGraphDelta()` in `unified-viz.html` deduplicates by node/edge ID, allowing safe dual fetches; updated the HTML fallback to render on both `baseline_ready` (skeleton) and `full_ready` (full) events. +- Claude Code launched the server, measured performance (baseline_ready=True at t=0s with 86 skeleton nodes), captured a headless Chrome screenshot, and verified the skeleton graph renders at first paint (~1s), then the full graph fills in as the build progresses in background (elapsed=92s). +- Claude Code committed across 5 files (workflow_graph.py, http_standalone.py, http_standalone_endpoints.py, http_standalone_graph.py, unified-viz.html) as commit `c672c05` with message "feat(viz): skeleton-first baseline so /cortex-visualize paints in ~1 s"; branch now 3 commits ahead of main with 0 behind and 26/26 layout tests passing. + + +## Session 09:26 + +### 09:26 + +- User invoked the `/cortex-visualize` skill to launch an interactive neural graph visualization. +- Claude Code killed the dev server, synced 55 cache roots from the dev branch (commit c672c05), and called `mcp__plugin_cortex_cortex__open_visualization()` to bootstrap the visualization server on port 3458. +- Claude Code probed the running servers and confirmed the skeleton-first baseline is working: `baseline_ready=True` in ~4 seconds with 86 skeleton nodes (domains + skills + hooks), with the full graph continuing to build in the background. +- Claude Code took a live screenshot of the plugin visualization server showing the current build state (elapsed=42s on memory_entity_edges phase) and graph cache (86 nodes/170 edges). +- Claude Code explained the rendering workflow: phase poller triggers build, skeleton renders in ~4s via `/api/graph` fallback, full graph (135k nodes) appends as build completes, with deduplication by node/edge ID. +- Branch `wip/layout-authority-sse-streaming` is confirmed PR-ready with 3 commits, all 26 layout-authority tests passing, and skeleton-first visualization working as designed. + + +## Session 09:44 + +### 09:44 + +- Human pointed out that Claude Code is showing the wrong visualization; the README displays a force-directed neural graph, not the current tilemap view. +- Claude Code searched the README for image references, identified `cortex-workflow-graph.png`, and discovered that `?viz=force` URL parameter and clicking the Graph tab control the force-directed view selector. +- Claude Code attempted multiple Chrome DevTools Protocol (CDP) driven screenshots; initial attempts failed because the dev server on port 3458 was no longer running; Claude Code relaunched the server. +- Claude Code successfully drove headless Chrome to navigate to `http://127.0.0.1:3458/?viz=force`, clicked the Graph button to set `activeView='graph'`, and captured a 674KB screenshot showing the force-directed workflow graph with 86 skeleton nodes and 170 edges. +- Claude Code verified the skeleton-first staging is working: `baseline_ready=True` within ~1s, full build continues in background with phase-polling at `memory_entity_edges`, and delivered the screenshot to the user with explanation of the complete visualization flow. + + +## Session 09:51 + +### 09:51 + +- User reported that the graph takes "ages to load," contradicting Claude Code's stated "200ms" latency claim. +- Claude Code identified two root causes: the handler was hardcoding `?viz=tilemap` (Datashader tile renderer, no skeleton-first fixes) instead of `?viz=force` (force-directed view with skeleton-first optimization), and the schema description misleadingly described handler-call latency rather than graph-build time. +- Claude Code modified `mcp_server/handlers/open_visualization.py` to change the default URL from `?viz=tilemap` to `?viz=force` and clarified the schema description to distinguish between handler warmup (~200ms) and DB-dependent graph build time (skeleton ~1s, full ~1-3 min). +- Claude Code updated `tests_py/handlers/test_open_visualization.py` to expect `?viz=force` in assertions (5 substitutions: URL checks and test docstring) and fixed a failing test assertion that checked for "tilemap" in the message by updating it to expect "Workflow graph" instead. +- Claude Code verified all 11 tests pass and committed as `8b2188f fix(viz): default /cortex-visualize to ?viz=force (the README hero view)`. +- Branch `wip/layout-authority-sse-streaming` is now 4 commits ahead of main with the correct default visualization endpoint. + + +## Session 10:05 + +### 10:05 + +- User requested a protocol to load graph data in 200ms instead of 45 minutes, emphasizing this was the original ask and previous work was tangential. +- Claude Code designed and implemented a CXGB binary snapshot protocol: fixed-width node/edge rows with deduplicated string pool (6.88 MB for 135k/166k) serializing in 279ms and deserializing in 310ms. +- Claude Code created `graph_snapshot.py` with binary format, added `/api/graph.bin` endpoint, integrated snapshot writer into build completion at both skeleton stage (~2s) and full stage, created `graph_snapshot.js` client decoder, and updated HTML to try binary path first with JSON fallback. +- Initial server launch showed full build took >270s without completing; Claude Code identified snapshot was only written after full merge, modified code to write skeleton snapshot immediately after skeleton merge stage instead. +- Measured performance on live server: `/api/graph.bin` (binary skeleton) = 0.8–1.7ms vs `/api/graph` (JSON) = 4.3ms, with skeleton snapshot appearing within ~2s (170× under 200ms target); full snapshot projected at ~110ms when background build completes. +- Claude Code committed across 6 files (graph_snapshot.py, http_standalone.py, http_standalone_endpoints.py, http_standalone_graph.py, unified-viz.html, graph_snapshot.js) in commit `0204da8`; branch now 5 commits ahead of main and PR-ready. + + +## Session 10:50 + +### 10:50 + +- User requested live streaming of graph visualization on first page visit instead of blocking until the full build completes, so nodes appear as files are processed. +- Claude Code created `graph_event_stream.py` for SSE event buffering and replay, wired `on_batch` callback in `http_standalone_graph.py`, added `/api/graph/events` endpoint in `http_standalone_endpoints.py`, and created frontend `graph_event_stream.js` subscriber with EventSource integration in `unified-viz.html`. +- Claude Code discovered the real bottleneck: `build_workflow_graph` loaded all PostgreSQL sources before emitting any events, causing ~100s latency before first visual update; restructured the function to interleave load+ingest+emit per source instead. +- Claude Code measured the final result: first SSE batch arrives at t=0.00s with 1,077 structural nodes (skills, hooks, agents, commands, discussions); full graph of 26,267 nodes streams in by t=25s; skeleton binary snapshot loads in 0.8–1.7 ms on subsequent visits. +- All 37 existing tests pass; Claude Code committed across 2 commits (`d9d8a98` for SSE infrastructure, `972bb9a` for interleaved load+ingest+emit), bringing branch to 7 commits ahead of main and PR-ready. + + +## Session 10:54 + +### 10:54 + +- Human asked where the visualization is, noting they haven't seen any output yet. +- Claude Code killed lingering dev servers (ports 3458, 60803), verified latest branch state (commit 972bb9a), dropped old skeleton snapshot, and invoked `open_visualization()` which returned `http://127.0.0.1:50408/?viz=tilemap`. +- Claude Code ran bash commands to verify both servers have latest endpoints; confirmed `/api/graph/events` and `/api/graph.bin` return HTTP 200, and build is actively running with skeleton snapshot (`base=True`, `phase='loading discussion_commands'`). +- Claude Code identified that the MCP handler is cached from session start and emits old `?viz=tilemap` URL, though the running server code IS the latest (commit 972bb9a) with working live-stream and snapshot paths. +- Claude Code offered two remedies: Option A—change URL bar from `?viz=tilemap` to `?viz=force`, or Option B—click the Graph tab in the toolbar; also noted restarting Claude Code would pick up new handler default but server-side features are already active. + + +## Session 11:07 + +### 11:07 + +- User reported that the graph visualization shows a progress bar but nodes never actualize while streaming. +- Claude Code traced the root cause: the `_startLiveStream` listener registration was running inline in the HTML `
` before `state.js` and `graph_event_stream.js` loaded, so `JUG.on` didn't exist when the code tried to register the event listener. +- Claude Code fixed the issue by moving the live-stream listener registration to a `