Skip to content

lean-memory-console: agent-first memory verification console (local viewer + observing MCP + single-tenant Docker + Claude Code plugin)#2

Merged
Wuesteon merged 36 commits into
mainfrom
worktree-memory-ui
Jul 14, 2026
Merged

lean-memory-console: agent-first memory verification console (local viewer + observing MCP + single-tenant Docker + Claude Code plugin)#2
Wuesteon merged 36 commits into
mainfrom
worktree-memory-ui

Conversation

@Wuesteon

Copy link
Copy Markdown
Owner

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.

  • Spec: docs/superpowers/specs/2026-07-10-memory-ui-design.md (design v2, externally reviewed)
  • Plan: 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)
  • Ledger: .superpowers/sdd/progress.md records every adjudicated plan deviation and deferred minor

What's in the box

  • console/ — Python package: config + sanitizer mirror w/ fail-loud fingerprint tripwires, _events.db trace 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), /views API, /v1 REST 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 banner
  • deploy/ — multi-stage Dockerfile (slim 365 MB stub / full 1.46 GB CPU-torch) + compose (single-tenant, LM_API_KEY required)
  • plugin/ + .claude-plugin/ — Claude Code plugin (stdio MCP entry, /memory:ui|status|server-up|server-down) with the repo as its marketplace; claude plugin validate clean
  • Zero changes to src/lean_memory/, bench/, root tests/, root pyproject.toml (lane-D discipline, fingerprint-guarded)

Verification

  • Console suite 125 passed; core suite 141 passed (unchanged)
  • Docker: slim + full images built and smoke-verified live (whoamimode:docker, models:real on full; POST /mcp bearer gate 401/200)
  • Live browser walkthrough on the committed fixture: all four pages render, supersession timeline (Acme→Globex) and score table verified visually
  • Remaining manual E2E (real Claude Code session via the plugin): checklist in console/README.md

🤖 Generated with Claude Code

Wuesteon and others added 30 commits July 13, 2026 14:57
…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>
Wuesteon and others added 6 commits July 13, 2026 20:47
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>
@Wuesteon
Wuesteon merged commit 9d840b6 into main Jul 14, 2026
6 checks passed
@Wuesteon
Wuesteon deleted the worktree-memory-ui branch July 14, 2026 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant