Commit graph

29 commits

Author SHA1 Message Date
Viktor Barzin
cf9baf4b8e
fix: add return type annotation to ui_root for mypy 2026-03-22 21:14:31 +02:00
Viktor Barzin
78e737146e
add web management UI for browsing, searching, and visualizing memories
Alpine.js + Tailwind CSS (CDN) served by FastAPI StaticFiles — no build step,
zero Docker changes. Features: memory browser with inline edit/delete, full-text
search with debounce, D3.js force-directed graph, Chart.js stats dashboard.
New endpoints: GET /api/stats, GET /api/categories, pagination on GET /api/memories.
2026-03-22 21:10:53 +02:00
Viktor Barzin
6e2e57b443
fix: add type: ignore for asyncpg import in permissions.py
Matches the pattern used in database.py for untyped asyncpg stubs.
2026-03-22 15:42:19 +02:00
Viktor Barzin
983e592083
add sharing tools to stdio MCP server for API-connected clients
- 7 new tools: memory_share, memory_unshare, memory_share_tag,
  memory_unshare_tag, memory_update, memory_shared_with_me, memory_my_shares
- Tools only advertised when API key is configured (HTTP_ONLY or HYBRID mode)
- SQLite-only mode stays unchanged — sharing requires the API server
- Tool handlers proxy to REST API endpoints
2026-03-22 15:36:15 +02:00
Viktor Barzin
f45e8ce2b3
add multi-user memory sharing with r/w permissions
- New migration 004: memory_shares and tag_shares tables with indexes
- Share individual memories or entire tags with other users (read/write)
- Tag shares are live rules: future memories with shared tags auto-visible
- Recall query merges own + shared memories via UNION, returns shared_by field
- Owner-only delete enforcement (403 for non-owners, even with write access)
- PUT /api/memories/{id} update endpoint with permission checks
- 5 new MCP SSE tools: memory_share, memory_unshare, memory_share_tag,
  memory_unshare_tag, memory_update
- Permission helper checks ownership, individual shares, and tag shares
2026-03-22 15:34:01 +02:00
Viktor Barzin
1a275e976c
fix: mypy type annotations for MCP auth middleware 2026-03-18 22:52:14 +00:00
Viktor Barzin
48df739c82
add MCP SSE transport for direct Claude Code connection
Adds SSE endpoint at /mcp/sse so Claude Code can connect over HTTPS
without needing a local Python bridge script. Benefits:
- No local files or sandbox permission issues
- Works from any machine (OpenClaw, DevVM)
- No startup delay or stderr suppression hack
- Auth via Bearer token in request headers
2026-03-18 22:44:57 +00:00
Viktor Barzin
e47efee6b6
resilient memory sync: decouple push/pull, startup full resync, auth failure handling
- Decouple push and pull in _sync_once() so pull always runs even if push fails
- Add startup full resync to catch drift from other agents and schema changes
- Add periodic full resync every ~10 minutes for continuous drift correction
- Add auth failure detection (401/403) with graceful SQLite-only degradation
- Add /api/auth-check endpoint for lightweight key validation
- Add retry cap (5 attempts) on pending ops to prevent infinite queue buildup
- Add orphan reconciliation: push local-only records with content dedup
- Add memory_count MCP tool for sync diagnostics
- Add version-based SQLite schema migration (PRAGMA user_version)
- Fix API key in ~/.claude.json to match server
- Update README with sync resilience docs, test structure, project layout
- Add 30 new tests covering all new behaviors (155 total, all passing)
2026-03-16 18:37:59 +00:00
Viktor Barzin
da9b4716c2
fix last mypy error: asyncpg import-untyped ignore 2026-03-15 23:39:56 +00:00
Viktor Barzin
d370855abf
fix mypy across all source files, remove || true from CI
- Add type annotations to all FastAPI endpoints in api/app.py
- Fix bare list/dict generics in sync.py and app.py
- Fix no-any-return in vault_client.py and sync.py
- Remove mypy || true from GitHub Actions CI — mypy is now clean
2026-03-15 23:36:34 +00:00
Viktor Barzin
678d50654b
fix all mypy errors in mcp_server.py
- Add type annotations to all _sqlite_* private methods
- Type sqlite_conn as sqlite3.Connection | None with assert narrowing
- Fix _api_request return type (dict[str, Any])
- Add return type to _init_sqlite
- Fix tool_name type in handle_tools_call
- Import sqlite3 at module level
2026-03-15 23:33:05 +00:00
Viktor Barzin
2fbca35e77
fix: remove extraneous f-string prefixes to pass ruff lint 2026-03-15 22:50:57 +00:00
Viktor Barzin
17206cd855
improve search relevance: hybrid scoring + AND-then-OR matching
- Blend BM25/ts_rank relevance with importance instead of sorting by one
  dimension only. Default mode: 40% relevance + 60% importance. Relevance
  mode: 70% relevance + 30% importance.
- Try AND-match first for precise results, fall back to OR-match when too
  few results are found. Prevents single-word matches from flooding results.
- Applied to both SQLite (local) and PostgreSQL (API) search paths.
2026-03-15 22:36:35 +00:00
Viktor Barzin
5a73dff622
add 800-char memory limit and optimize for focused recall
- Add MAX_MEMORY_CHARS=800 Pydantic validation on MemoryStore.content
- Update auto-learn judge prompts: "ONE topic per event", 100-500 chars,
  include the WHY not just the WHAT
- Split 9 mega-memories (800-2400ch) into 70 focused memories (100-500ch)
  via migration script

Before: median 331ch, 11 memories >800ch, recall wastes 84% of returned tokens
After: median 213ch, 2 memories >800ch (dense single-topic refs), recall returns
only the relevant knowledge

Trade-off research: PostgreSQL ts_rank gives the same score regardless of
document size, so a 2400-char memory with 12 topics gets recalled for any
of its 12 topics but wastes context with the other 11. Focused memories
(100-500ch) give higher signal-to-noise per recall.
2026-03-15 15:51:18 +00:00
Viktor Barzin
6aa4d31170
fix: make DELETE idempotent — return 200 for already-deleted memories
Old sync clients without 404 handling get stuck in infinite retry
loops when trying to delete an already-deleted memory. Making the
endpoint idempotent (returning success regardless) fixes this for
all existing clients without requiring client upgrades.
2026-03-15 15:32:41 +00:00
Viktor Barzin
e22a8f743a
fix: 404 retry loop on delete and URL-encode since param
Three fixes for high 4xx alert rate:
1. Catch urllib.error.HTTPError (not just RuntimeError) for 404 on
   DELETE in pending_ops — was causing infinite retry loop for
   already-deleted memories
2. try_sync_delete: treat 404 as success instead of enqueuing
   a retry that will also 404 forever
3. URL-encode the `since` query param to prevent `+` in timezone
   offset being decoded to a space (the asyncpg-string-timestamp
   pattern applied to the sync client)
2026-03-15 15:28:19 +00:00
Viktor Barzin
9b618711ee
fix: handle URL-decoded '+' in timezone offset for sync endpoint
The '+' in '+00:00' timezone offsets gets URL-decoded to a space,
causing datetime.fromisoformat() to fail with ValueError. Replace
spaces back to '+' before parsing.
2026-03-15 02:33:52 +00:00
Viktor Barzin
a52afe050d
Fix MCP server startup for Claude Code compatibility
- Suppress stderr output (Claude Code rejects servers with stderr)
- Make SyncEngine.start() non-blocking (blocking sync caused 15s+ timeout)
- Skip Content-Length header lines gracefully (NDJSON transport)
- Silently ignore malformed JSON lines instead of sending error responses
2026-03-14 16:05:35 +00:00
Viktor Barzin
0d1cff3038
Add Claude Code plugin scaffold for single-repo install
Consolidates plugin components (hooks, commands, skills, MCP config)
into this repo so it can be installed with:
  claude plugins install github:ViktorBarzin/claude-memory-mcp

- .claude-plugin/plugin.json: manifest with all hook events
- mcp/memory-mcp.json: MCP server config using existing src/
- hooks/: compaction survival, auto-recall, auto-learn, auto-approve
- commands/: /remember and /recall slash commands
- skills/: memory-management skill
- Bump MCP server to v2.0.0 with metaclaw migration fallback
- Update README with quick install and plugin hooks docs
2026-03-14 14:49:18 +00:00
Viktor Barzin
e08486f2bd
fix: parse since param to datetime for asyncpg compatibility
asyncpg requires datetime objects, not strings, for timestamptz params.
Also use Z suffix in tests to avoid URL-encoding issues with +00:00.
2026-03-14 13:13:48 +00:00
Viktor Barzin
0a4aed9e1b
fix: resolve ruff lint errors (unused imports and variables) 2026-03-14 13:04:40 +00:00
Viktor Barzin
cd80a67dfa
feat: add local SQLite cache with background sync and HA deployment
- Add SyncEngine for background sync between local SQLite cache and
  remote API with pending_ops queue for offline resilience
- Refactor MCP server to support three modes: SQLite-only, hybrid
  (local cache + sync, new default), and HTTP-only (legacy)
- Add GET /api/memories/sync endpoint for incremental sync
- Change DELETE to soft delete (set deleted_at) for sync support
- Add deleted_at IS NULL filters to all read queries
- Scale API deployment to 2 replicas with pod anti-affinity, PDB,
  and startup probe for high availability
- Add migration 003 for deleted_at column and updated_at index
- Add comprehensive tests for sync engine and API sync endpoint
2026-03-14 12:42:39 +00:00
Viktor Barzin
fe55ac634b
fix: add psycopg2-binary for Alembic and add connection retry logic 2026-03-14 12:05:41 +00:00
Viktor Barzin
58ea218044
fix: add preview to delete response for MCP server compatibility 2026-03-14 11:14:05 +00:00
Viktor Barzin
4c75e9d801
fix: wrap recall/list responses in {memories: []} and update README
- API recall and list endpoints now return {"memories": [...]} matching
  the format expected by the MCP server
- Rewrote README with comprehensive setup instructions for new agents,
  accurate API reference, migration docs, and multi-user setup guide
2026-03-14 10:39:12 +00:00
Viktor Barzin
8a7239fb77
feat: add Alembic for database migrations
Replace inline migration logic with proper Alembic migrations:
- 001: Initial schema (creates memories table with FTS)
- 002: Add multi-user and secrets columns (user_id, is_sensitive,
  vault_path, encrypted_content)

Migrations run automatically on app startup. Existing databases
are handled gracefully with IF NOT EXISTS / column existence checks.
2026-03-14 10:34:45 +00:00
Viktor Barzin
63205dbd0c
fix: add migration logic for existing databases without new columns 2026-03-14 10:22:14 +00:00
Viktor Barzin
eba5cf6a82
fix: resolve ruff lint errors (unused imports and variables) 2026-03-14 10:01:41 +00:00
Viktor Barzin
0ed5e1e016
feat: standalone claude-memory-mcp with multi-user support and Vault integration
Extracted from private infra repo into standalone open-source project.

Three operating modes:
- Local: SQLite + FTS5 (zero dependencies)
- Server: PostgreSQL via HTTP API with multi-user auth
- Full: PostgreSQL + HashiCorp Vault for secret management

Features:
- MCP stdio server with 5 tools (store/recall/list/delete/secret_get)
- FastAPI HTTP API with multi-user Bearer token auth (API_KEYS JSON map)
- Regex-based credential detection with auto-redaction
- AES-256-GCM encryption fallback for non-Vault deployments
- Vault KV v2 client (stdlib urllib, K8s SA auto-auth)
- Per-user data isolation (all queries scoped by user_id)
- Secret migration endpoint for existing plain-text credentials
- Backward-compatible env var aliases (CLAUDE_MEMORY_API_URL)

Infrastructure:
- Docker + docker-compose (API + PostgreSQL + optional Vault)
- Woodpecker CI (test → build → push → kubectl deploy)
- GitHub Actions CI (Python 3.11/3.12/3.13) + Release (GHCR + PyPI)
- Helm chart + raw Kubernetes manifests

96 tests passing across 6 test files.
2026-03-14 09:42:05 +00:00