lean-memory-console: agent-first memory verification console (local viewer + observing MCP + single-tenant Docker + Claude Code plugin)#2
Merged
Conversation
…tion UI Approved brainstorming output for the Memory UI packet (lane D): self-hostable Docker service, MCP-over-HTTP data plane with per-tenant API keys, event log for verification, read-only web console. Zero core-library changes; adversarial self-review findings applied (reserved-namespace guard, t_ref exposure, delete lifecycle, pagination envelope, plane-scoped credentials). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BBi51vMHM2617zHTYt77R
…erving MCP + plugin; Docker single-tenant in Tier 1; multi-tenant platform deferred to Tier 2 Rethought after the external strategy review: v1's multi-tenant service becomes Tier 2; Tier 1 is lean-memory-console (transient local viewer + observing stdio MCP wrapper writing an _events.db trace sidecar) plus a single-tenant Docker mode, distributed primarily as a Claude Code plugin. v2 adversarial self-review applied: engine has no busy_timeout (console owns cross-process retry contract), mode=ro error-14 claim failed empirical repro (open strategy now error-driven), token-in-URL hygiene, atomic event retention, whoami mode probe, compose-path single source of truth, installed-package schema fingerprint tripwire. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BBi51vMHM2617zHTYt77R
Backend (scaffold/config, events sidecar, fixture + inspect_sql, engine gateway, observing MCP + parity, views app, data plane, CLI), frontend (Vite/Bun/React scaffold + four pages), distribution (Docker slim/full, Claude Code plugin + marketplace, README + E2E gate). Code blocks baked from real engine source; fixture empirically validated against the stub engine; compose file single-ownership reconciled during self-review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013BBi51vMHM2617zHTYt77R
…pwires Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…perator keywords Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ost guard, test-search) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… with bearer gate Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…allowlist Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…for remote Docker deployments Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mpose-path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fact_id Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sion Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…test search Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed into wheel Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… /mcp with 405 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…trypoint
The container CMD ran `serve`, which hardcoded load_config("local"): the
shipped image ignored LM_API_KEY, never mounted /mcp (bearer-gate/redirect
stack was dead code), and the local Host guard 403'd LAN clients. Add an
explicit --docker flag (no env magic) that selects load_config("docker")
(LM_API_KEY required -> exit 2), binds 0.0.0.0, and skips browser-open; point
the Dockerfile CMD at `serve --docker`. Verified from the host: /views/whoami
reports mode=docker, POST /mcp without bearer -> 401, with bearer -> 200.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The full stage ran `pip install '.[models]'`, letting pip resolve the default CUDA torch (torch + nvidia-cudnn + cuda-toolkit) for a 5.47GB image on a CPU-only target. Install torch from the PyTorch CPU wheel index first, so the [models] extra finds it satisfied and skips the CUDA wheels. Verified: image drops to 1.46GB, `torch.__version__` == 2.13.0+cpu, cuda.is_available() False, and the container still boots docker mode (whoami=docker, /mcp 401→200). Adds a static regression test asserting the CPU index precedes the [models] install. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rketplace manifest Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… manual E2E checklist
engine.py hard-coded Memory(root=...) — stub backends only, config.models dead. Mirror the core engine's mcp_server._build_memory wiring: models='stub' forces deterministic offline stubs; 'auto' upgrades to real embedder/reranker (and GLiNER2 extractor) when the optional extras are importable, else falls back gracefully. Add resolved_models_mode() for the whoami view. Tests: stub yields FakeEmbedder; auto degrades to stubs in a stub-only venv; selection logic asserted via monkeypatched import success. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add resolved models mode ('real'|'stub') to GET /views/whoami — the resolved
backend selection, not the raw env. Thread it through the WhoAmI TS type and
render a slim spec §11 advisory banner on the Overview and Activity pages when
models === 'stub' (semantic scores are stub-generated).
Bundles FIX 6 (Activity poll cancelled-flag guard on all setState paths) and
FIX 7 (App.tsx activeNs revalidation — drop a namespace that disappeared).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sweep _is_authenticated (bearer + local token paths) and the /mcp bearer gate to secrets.compare_digest, guarding None/type so a missing credential or unconfigured secret never authenticates. Removes timing side-channels on the session token and API key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
memory-status.md invoked a nonexistent 'serve --print-status' flag (and a '|| mcp --help' no-op) — replace with the working resolved-root echo. Correct memory-ui.md's 'run in the background' wording: serve blocks until Ctrl-C, so instruct a background job with '&' explicitly. Add a regression assertion that '--print-status' appears nowhere under plugin/. Align the console package version to 0.1.0, matching the plugin manifest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
Implements the Memory UI packet (lane D):
lean-memory-console— agents write memories through an observing MCP wrapper or HTTP data plane; the human opens a read-only web console to verify what was stored, watch supersessions on a timeline, and inspect per-hit score decompositions.docs/superpowers/specs/2026-07-10-memory-ui-design.md(design v2, externally reviewed)docs/superpowers/plans/2026-07-10-memory-ui-console.md(17 tasks, subagent-driven with per-task review gates + final whole-branch review: ready to merge).superpowers/sdd/progress.mdrecords every adjudicated plan deviation and deferred minorWhat's in the box
console/— Python package: config + sanitizer mirror w/ fail-loud fingerprint tripwires,_events.dbtrace sidecar (atomic retention),EngineGateway(single-worker thread pinning, retry-on-busy, supersession detection, opportunistic real-model wiring), read-only inspect SQL, FastAPI app (local-token / docker-bearer dual-mode auth, constant-time compares),/viewsAPI,/v1REST mirror, streamable-HTTP MCP mount (transport-security allowlist +LM_MCP_ALLOWED_HOSTS), CLI (serve [--docker],mcp,--print-compose-path)ui/— React 18 + TS SPA (Bun + Vite + Tailwind v4): Overview, Memories + supersession timeline, Episodes, Activity & Traces w/ score decomposition + test-search; stub-scores honesty bannerdeploy/— multi-stage Dockerfile (slim 365 MB stub / full 1.46 GB CPU-torch) + compose (single-tenant,LM_API_KEYrequired)plugin/+.claude-plugin/— Claude Code plugin (stdio MCP entry,/memory:ui|status|server-up|server-down) with the repo as its marketplace;claude plugin validatecleansrc/lean_memory/,bench/, roottests/, rootpyproject.toml(lane-D discipline, fingerprint-guarded)Verification
whoami→mode:docker,models:realon full;POST /mcpbearer gate 401/200)console/README.md🤖 Generated with Claude Code