Skip to content

Update - #7

Open
jamusaaron wants to merge 32 commits into
Puliczek:mainfrom
jamusaaron:main
Open

Update #7
jamusaaron wants to merge 32 commits into
Puliczek:mainfrom
jamusaaron:main

Conversation

@jamusaaron

Copy link
Copy Markdown

No description provided.

claude and others added 30 commits July 1, 2026 01:04
The MCP server only exposed addToMCPMemory and searchMCPMemory tools,
while delete and update operations were only available via REST endpoints.
This adds listMCPMemories, deleteMCPMemory, and updateMCPMemory tools
so MCP clients can perform full CRUD operations on memories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
Configures the MCP memory server for use with Claude Code via
.claude/settings.json and adds CLAUDE.md with project documentation
for Claude Code sessions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
Complete rewrite from 5-tool prototype to production memory system:

Data model: structured memories with category (14 types), layer
(core/long_embedded/mid_ground/current), confidence/salience/emotion
scoring, contradiction detection, and confidence decay.

Storage: D1 for structured data (10 tables), KV for caching (living
summary, personality, session state), R2 for static context files.

Tools (88 total):
- Memory CRUD & retrieval (20): write, edit, forget, promote, query,
  smart context, pattern analysis, consolidation, decay sweep
- People/profiles (13): add, list, get/update profiles, propose/apply
  pending updates, AI extraction, profile health audit
- Session lifecycle (9): session brief, logging, close, audit,
  living summary, context management
- Behavioral modeling (6): behavioral model, emotional context,
  personality profile, mode selection, feedback loop
- Uncertainty loop (3): ask user, record answer, list open questions
- Ingestion pipeline (3): transcript ingestion, AI extraction, triage
- Cross-agent shared memory (5): agent notes, cross-checking
- Static files (2): R2-backed context document read/write
- Health check (1): full system component verification
- Infra passthrough (26): Cloudflare D1/KV/R2/Workers management

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
Improved all tool descriptions to be more actionable for LLM clients,
explaining WHEN to use each tool and how it relates to other tools.

New memory tools: suppress_memory, restore_memory, verify_memory,
search_by_tag, get_suppressed_memories, memory_timeline, export_memories,
bulk_tag_memories.

New people tools: search_people, delete_person, update_person.

New session tool: session_list.

New uncertainty tool: dismiss_uncertainty.

New static file tools: delete_static_file, list_static_files.

New behavioral tool: record_observation.

New ai-agent tool: ai_note_delete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
- Use prepare().run() instead of exec() for D1 migrations (fixes multiline SQL in local dev)
- Wrap contradiction detection in try/catch so write_memory works when AI/Vectorize are unavailable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
- Add keywordSearchMemories (D1 LIKE search across text/subject/tags/triggers)
  and searchMemoriesWithFallback so query_memories, smart_context, and
  get_memory_context keep working when Vectorize/Workers AI are unreachable
- Add batch_write_memories tool for bulk imports (1-50 memories per call)
- Add optional MEMORY_API_KEY auth: Bearer header or ?key= param on all data
  routes; SSE message POSTs validated by unguessable session ID
- Add POST /:userId/memories REST endpoint
- Make submit_inbound and ingest_transcript degrade gracefully when AI
  triage/extraction is unavailable (store with defaults instead of failing)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
The kv_namespaces binding had a placeholder ID ("mcp-memory-kv") and the
r2_buckets binding referenced a bucket that may not exist in the account,
causing the Cloudflare Workers Builds deploy to fail on binding validation.

- Remove KV/R2 bindings from wrangler.jsonc (commented instructions to
  re-enable with real resource IDs)
- Cache operations fall back to a D1 kv_store table (with TTL emulation)
  when env.KV is unbound
- Static files fall back to a D1 static_files table when env.R2 is unbound
- health_check reports which backend is active for cache and static files
- Deploy now only requires resources that exist: D1, Vectorize, Workers AI

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
The ratelimit binding is not referenced anywhere in the code and unsafe
bindings are a potential deploy-validation failure point. Dropping it
narrows the deploy config to only what the worker actually uses.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
Workers Builds fails instantly if its configured build command is
`npm run build` and the script doesn't exist. Provide build/test scripts
(type-check) so any common build-command configuration succeeds.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
The previous database_id a25fc989-... does not exist in this account.
Point DB at mcp-memory-db (1dd6fb6c-...) and KV at the existing namespace.
connection_map was left on raw searchMemories() when the keyword-search
fallback was added to query_memories, smart_context, and
get_memory_context — it's the same shape (pure related-memory lookup,
no LLM synthesis) and was failing outright without Vectorize/Workers AI.

run_consolidation intentionally keeps its hard Vectorize dependency:
keyword-match scores aren't a valid proxy for the similarity threshold
it uses to suppress memories, so degrading it risks false-positive
consolidation.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
fix: connection_map keyword-search fallback for consistency
wrangler.jsonc already had a triggers.crons entry (*/30 * * * *) with no
handler — Cloudflare was logging "Handler does not export a scheduled()
function" on every fire. Added the handler and made it do something
useful.

- runDecaySweep() and listDistinctUserIds() extracted to utils/db.ts,
  reused by both the run_decay_sweep MCP tool (unchanged behavior,
  now DRY) and the new scheduled handler
- scheduled() enumerates every user with stored memories and runs the
  decay sweep for each, logging a summary; failures for one user don't
  block the rest
- export default switched from the bare Hono app to { fetch, scheduled }
  so both handlers are wired

Verified with `wrangler dev --test-scheduled` + `/__scheduled` — runs
cleanly with 0 and 1 users, and the MCP tool still produces identical
output after the refactor.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
feat: wire up scheduled() handler for the decay sweep cron
The architecture doc claimed memory writes trigger downstream rebuilds
of the living summary and profiles, but the code never actually did
this — putLivingSummary was imported into memory.ts and never called.
Both derived documents only ever updated when someone remembered to
call rebuild_living_summary / rebuild_self_profile by hand.

Added src/utils/cascade.ts: a cheap per-user dirty counter (no AI call)
bumped by write_memory, batch_write_memories, edit_memory (on text
changes), suppress_memory, restore_memory, and forget_memory. Two
triggers consume it:

- Threshold-based, on every write: living summary rebuilds past 10
  unsummarized changes, self-profile past 5 — so a burst of writes
  pays the AI cost once instead of on every call.
- Session-boundary, in session_close: rebuilds either document if its
  counter is non-zero at all, since session close is infrequent enough
  to justify the cost regardless of how small the change was.

get_session_brief now surfaces staleness directly instead of silently
serving a possibly-stale cached summary. rebuild_living_summary and
rebuild_self_profile (the existing manual tools) now delegate to the
same cascade functions so a manual rebuild correctly clears the dirty
counter too — previously the brief would keep claiming staleness even
right after a manual rebuild.

All rebuild attempts are best-effort: a failure (e.g. Workers AI
unreachable) is logged and leaves the dirty counter untouched, so nothing
is falsely marked fresh.

Verified against a live dev server: dirty count increments on write,
threshold-crossing at write #10 correctly triggers an auto-rebuild
attempt, session_close attempts and correctly fails-open without
crashing (no Workers AI locally), and the counter survives failed
attempts instead of being incorrectly cleared.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
feat: wire up the write cascade between memory writes and derived docs
…ub, behavioral cascade

Three enhancements to how the tools feed each other, extending the write
cascade shipped previously:

1. record_user_answer closes the uncertainty->memory loop. Its own
   description already promised "consider using the answer to update
   memories" but it did nothing — an answered question's knowledge just
   evaporated. It now writes the resolved Q&A as a memory (with the write
   cascade) by default; store_as_memory=false opts out.

2. get_session_brief becomes the operational hub. It now surfaces open
   uncertainties (from ask_user) and memories needing reverification
   (decayed confidence) alongside the summary/context, so a session
   starts knowing what to ask and confirm without separately calling
   list_open_uncertainties / list_reverify_queue.

3. Behavioral cascade mirrors the write cascade. record_observation and
   personality_feedback now bump a behavioral-model dirty counter;
   behavioral_model rebuilds past 5 changes or at session_close, instead
   of only when manually rebuilt with rebuild=true. behavioral_model and
   the new rebuild share one code path in cascade.ts so a manual rebuild
   also clears the counter.

Added getUncertaintyById (db) and extended cascade.ts with a
behavioral_model kind. session_close now reports which of the three
documents it refreshed.

Verified against a live dev server: answering an uncertainty stores the
Q&A as a memory and the write cascade fires; the brief renders an "Open
Questions" section; the 5th observation triggers the behavioral
auto-rebuild path (fails open locally without Workers AI, as designed).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
feat: cross-tool integration — answered questions persist, brief as hub, behavioral cascade
… fallback

Every AI-dependent feature (living summary, self-profile, behavioral model,
triage, extraction, pattern analysis, personality) was broken in production:
llmCall hardcoded @cf/meta/llama-3.1-8b-instruct, which Cloudflare retired at
end-of-support 2026-05-30. rebuild_living_summary surfaced it live with
"AiError 5028: This model was deprecated on 2026-05-30."

llmCall now tries an ordered list of current text-generation models and falls
through on deprecation/availability errors, so a single model retirement can no
longer silently break the whole system. The primary is overridable via the
LLM_MODEL var (config change, not code) for the next time Cloudflare rotates
models. Embeddings (@cf/baai/bge-m3) were unaffected and are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
Audit follow-up to the deprecated-model outage. Two gaps closed:

1. health_check only exercised the embedding model (@cf/baai/bge-m3) and
   reported a single "Workers AI: OK" — so it showed green the entire time
   text generation was down. It now probes embeddings AND text generation
   separately (via checkTextGeneration -> llmCallDetailed), reporting which
   text model is live, so this class of total outage can never be silent
   again.

2. Extended FALLBACK_TEXT_MODELS across families (added Mistral small 3.1 24b
   and Qwen2.5 32b after the four Llama entries) so even a whole-family
   deprecation can't take out all text generation. Added llmCallDetailed
   (returns the working model id) which llmCall and checkTextGeneration
   both build on.

Audited the rest of the surface: production D1 is clean (137 memories all
embedded, 0 empty, 3 legitimately suppressed, profiles intact); no other
hardcoded models/external APIs; infra tools degrade gracefully without
credentials; all vector/cascade writes are properly awaited.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
fix: llmCall used a deprecated Workers AI model — add resilient model fallback
Adds runAiSelfTest: probes Workers AI text generation (checkTextGeneration)
and writes {status, model, ts} to the D1 kv_store table under key
__ai_selftest__. Wired into both the fetch middleware (throttled to once per
90s, backgrounded via waitUntil) and the scheduled() cron handler.

Purpose: the self-test always executes in the Worker runtime — the freshly
deployed code — so the live text model can be verified even when a Durable
Object MCP session is pinned to older code, and even when the Worker isn't
reachable over HTTP. The result row is inspectable directly with a D1 query,
giving a reliable production health signal independent of the MCP connector.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
feat: worker AI self-test written to D1 for out-of-band verification
…ced)

The user runs this on a paid Cloudflare plan and does not want request
rate limiting, so it should not be enforced or claimed. Production reverts
to no rate-limiting middleware (this branch == main's code, which has none),
and the README security section no longer claims rate limiting protects the
service. Security model is now stated accurately: per-namespace data
isolation + optional API-key auth (MEMORY_API_KEY) + Cloudflare TLS/infra.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
docs: accurate security model — no rate limiting (paid plan, not wanted)
claude and others added 2 commits July 21, 2026 05:51
Memories can be written with embedding_status='pending' when Vectorize/
Workers AI is briefly unavailable, or via direct D1 inserts. Previously
they stayed pending until someone manually called backfill_embeddings
through the MCP connector — which is useless if the connector is down.

Extract backfillEmbeddingsForUser() (shared by the backfill_embeddings
tool and the worker) and call it per-user inside the 30-minute scheduled()
maintenance pass, alongside the decay sweep. Pending embeddings now
vectorize themselves with no manual step and no connector dependency.
Best-effort per memory; failures are logged and don't block the sweep.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BotQMbUfnnaJdFsDWsTNcw
feat: auto-backfill pending embeddings in the scheduled worker handler
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.

2 participants