Commit graph

85 commits

Author SHA1 Message Date
Viktor Barzin
1fa6c2031e Phase 4: Forgejo only push (drop DockerHub from build pipeline)
Some checks failed
ci/woodpecker/push/deploy Pipeline failed
ci/woodpecker/push/build Pipeline failed
2026-05-07 23:28:11 +00:00
Viktor Barzin
377e89ead5 trigger after WP forge timeout fix 2026-05-07 23:27:08 +00:00
Viktor Barzin
516d08f43a [ci] Switch build to Woodpecker dual-push (DockerHub + Forgejo)
Phase 1 of the registry consolidation rolling out across the homelab —
infra/docs/plans/2026-05-07-forgejo-registry-consolidation-plan.md.

* New .woodpecker/build.yml runs the test suite, then dual-pushes to
  viktorbarzin/claude-memory-mcp on DockerHub AND
  forgejo.viktorbarzin.me/viktor/claude-memory-mcp.
* GHA ci.yml renamed to .disabled — its build job would otherwise
  race the Woodpecker build and clobber Forgejo with a stale image.
  Re-enable only on rollback.
* DockerHub remains the canonical pull source until Phase 3 flips
  infra/stacks/claude-memory/main.tf image= to Forgejo. Phase 3 also
  archives this GitHub repo and CLAUDE.md is updated to point
  `claude plugins install` at the Forgejo URL.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 15:58:55 +00:00
Viktor Barzin
473f11a766 bd init: initialize beads issue tracking 2026-04-09 23:20:55 +00:00
Viktor Barzin
0c64cb05e6 refactor: remove deprecated SSE transport, keep streamable-http only
SSE is deprecated per MCP spec. Both clients (wizard, emo) already use
type: "http" pointing to /mcp/mcp. Removes HandleSSE class,
SseServerTransport, and /mcp/sse + /mcp/messages/ routes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 19:57:18 +00:00
Viktor Barzin
73aefda82e feat: auto-split large memories at store time (>500 chars)
When content exceeds 500 chars, it's automatically split into multiple
memories on paragraph boundaries. Each chunk gets the same category,
tags (with part-N-of-M suffix), keywords, and importance. Removes the
old 800 char hard limit from the Pydantic model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:19:52 +00:00
Viktor Barzin
c88dd03cce fix: add OR-fallback to MCP memory_recall tool
The REST API /api/memories/recall already broadens to OR-match when the
strict AND full-text search returns too few results, but the MCP tool
handler was missing this fallback. Broad queries (many terms) produced
empty results because plainto_tsquery ANDs all terms and no single
memory contains every word.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:59:19 +00:00
Viktor Barzin
d03a77ac36 feat: raise default query limits to 10000 (effectively unlimited)
With 375 memories and 1M context window, low limits just hide results.
Agents can still pass a smaller limit when they want fewer results.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:56:12 +00:00
Viktor Barzin
43a5513f6c feat: make all memories public by default
All memories are now visible to all users in recall/list/count queries.
Each memory still has an owner (user_id) who retains exclusive delete
rights. This removes the need for explicit sharing — wizard and emo
automatically see each other's memories.

Changes:
- recall/list: single query without user_id filter, added owner field
- count: counts all memories globally
- REST categories/tags: show all users' data
- Delete/update: unchanged (owner-only or write-share)
- Sync: unchanged (stays user-scoped)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:27:58 +00:00
Viktor Barzin
03681aae49 fix: use StreamableHTTPSessionManager in stateless mode
The previous per-request transport implementation couldn't maintain
session state. Using the SDK's built-in SessionManager with stateless=True
means sessions start pre-initialized — tool calls work immediately
without the init handshake, avoiding the reconnection race condition.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:27:44 +00:00
Viktor Barzin
94330755d8 feat: add streamable-http MCP transport alongside SSE
SSE transport has reliability issues through Cloudflare/Traefik proxies
(connections drop, causing init failures on reconnect). Streamable HTTP
is stateless — each request carries its own session, avoiding persistent
connection issues.

New endpoint: POST/GET/DELETE /mcp/mcp (streamable-http)
Existing: GET /mcp/sse + POST /mcp/messages/ (SSE, unchanged)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 10:55:21 +00:00
Viktor Barzin
4d7988b6ac fix: replace BaseHTTPMiddleware with pure ASGI to fix SSE streaming
BaseHTTPMiddleware buffers response bodies, which prevents SSE events
from streaming to the client in real time. This caused MCP initialization
to never complete, resulting in -32602 errors on all tool calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 10:45:20 +00:00
Viktor Barzin
aa219071f9
fix lint: remove unused FileResponse import, fix empty f-string 2026-03-23 00:53:57 +02:00
Viktor Barzin
745b6ceea8
add cache-busting query params to static assets
Generates a unique hash on app startup and appends it to all .js and
.css URLs in index.html. Forces browser to fetch fresh assets on redeploy.
2026-03-23 00:50:20 +02:00
Viktor Barzin
aa6760cb0f
fix fullscreen button: use x-show instead of x-if templates
x-if with template tags inside a button element causes scope issues.
Switch to x-show on SVG elements directly.
2026-03-23 00:42:10 +02:00
Viktor Barzin
f8bbb2e993
add fullscreen toggle to graph visualization
Expand/collapse button in bottom-right corner lets the graph fill the
entire viewport for better exploration. Escape key exits fullscreen.
Category filters overlay in top-left when fullscreen.
2026-03-23 00:37:24 +02:00
Viktor Barzin
f3e61d8c77
feat: add Tags browser tab with tag cloud and filtered memory view
Add GET /api/tags endpoint returning distinct tags with counts,
add ?tag= filter to GET /api/memories, and a new Tags tab in the
Neural Archive UI with searchable tag cloud and expandable memory cards.
2026-03-23 00:29:02 +02:00
Viktor Barzin
9edb381c85
fix: graph SVG fills container height, fallback to viewport calc 2026-03-23 00:06:55 +02:00
Viktor Barzin
e8ae2b50ea
fix: graph tab breaks out of max-w-7xl container for full-width layout 2026-03-23 00:03:21 +02:00
Viktor Barzin
44338d0eff
feat: fullscreen graph layout, category legend, and node labels
- Graph container fills viewport (calc(100vh - 180px)) instead of 500px
- Node detail panel overlays graph as absolute-positioned panel
- Category legend with colored dots fixed in SVG top-left corner
- High-importance nodes (>= 0.7) show truncated content labels
2026-03-22 23:55:51 +02:00
Viktor Barzin
20f2f02dea
add project CLAUDE.md [ci skip] 2026-03-22 23:44:38 +02:00
Viktor Barzin
e5a69d4e3e
fix: graph visualization not rendering due to x-show timing
- Replace $nextTick with setTimeout(100) for D3 render (same fix as dashboard)
- Re-render graph when switching back to tab (not just on first load)
- Fallback width from parent element when container clientWidth is 0
2026-03-22 23:43:05 +02:00
Viktor Barzin
c130bcff33
feat: sharing tests, property tests, tag-share UI, inline errors, route fix
- Add 10 sharing endpoint tests (share/unshare memory, tag shares, shared-with-me,
  my-shares, recall with shared, update permission checks)
- Add hypothesis property-based tests for model validation (roundtrip, bounds,
  enum, sort_by, limit)
- Tighten model validation: sort_by Literal, limit ge=1/le=500, tags/keywords max_length
- Fix dashboard shared_with_me stat to include tag-based shares
- Add tag-sharing management UI (share/remove tags, user typeahead)
- Replace alert() with inline error messages
- Fix route ordering bug: share-tag routes before {memory_id} parameterized routes
2026-03-22 23:36:13 +02:00
Viktor Barzin
688be268b9
fix: remove extraneous f-string prefix (ruff F541) 2026-03-22 23:01:33 +02:00
Viktor Barzin
f242c45c73
feat: multi-user MCP SSE support + shared memories in recall/list
- Use contextvars to resolve user identity from Authorization header
  in SSE connections, replacing hardcoded "default" user_id
- memory_recall now includes shared memories (individual + tag-based)
  with deduplication and shared_by attribution
- memory_list now includes shared memories with same approach
- All 11 MCP tool functions use _current_user contextvar
2026-03-22 22:50:18 +02:00
Viktor Barzin
95dd937765
UI improvements: add memory form, fix dashboard charts, Neural Archive theme
- Add "New Memory" button with collapsible form (content, category, tags, importance)
- Add share memory with user typeahead via new GET /api/users endpoint
- Fix dashboard charts not rendering (replace $nextTick with setTimeout for x-if timing)
- Redesign theme: warm walnut/amber palette, Playfair Display + JetBrains Mono fonts
- Update Chart.js and D3 graph colors to match warm theme
2026-03-22 21:30:58 +02:00
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
0e75b3f9e3
docs: add sharing feature to README
- Document 7 new MCP tools for memory sharing
- Add Memory Sharing section with usage examples and permission levels
- Update API Reference with 7 new sharing endpoints + PUT update
- Update migrations list with 004_add_sharing
- Add permissions.py to project structure
2026-03-22 19:58:30 +02:00
Viktor Barzin
e6dd89346f
fix: update tests for recall query changes and mypy asyncpg import
- Add shared_by/share_permission to mock row defaults
- Update recall tests to handle 3+1 fetch calls (own, shared, tag-shared, OR-fallback)
2026-03-22 15:45:38 +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
18e27d07d2
fix: remove slack notify from deploy pipeline to unblock manual triggers 2026-03-16 22:18:48 +00:00
Viktor Barzin
714fb366d0
fix: remove unused variable to pass ruff lint 2026-03-16 19:45:01 +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
a18b94d310 docs: expand README with search algorithm internals and secrets architecture
Add detailed Search Algorithm section covering FTS5/BM25 (SQLite) and
tsvector/ts_rank (PostgreSQL) backends, query construction, semantic
expansion at store time, and a comparison table. Also add Sensitive
Memory & Secrets section, Auto-Learn details, and Background Sync Engine
documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:24:02 +00:00
Viktor Barzin
673647710e
fix: use bitnami/kubectl:latest (1.32 has entrypoint issues) 2026-03-16 00:35:44 +00:00
Viktor Barzin
90759f5dfa
fix: change build-fallback event to deployment (prevents dual workflow on API trigger) 2026-03-16 00:15:45 +00:00
Viktor Barzin
1e100cefd1
fix: use Woodpecker repo ID in API URL, quote YAML commands
- Woodpecker API requires numeric repo IDs, not owner/name paths
- Quote kubectl commands to prevent YAML map parsing on empty vars
2026-03-16 00:06:26 +00:00
Viktor Barzin
7dc285a677
fix deploy.yml: accept push events, check IMAGE_TAG var 2026-03-15 23:58:09 +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
df1f36a4f8
make mypy non-blocking in CI (pre-existing errors) 2026-03-15 23:30:50 +00:00
Viktor Barzin
bfc20d2ce9
move Docker builds to GitHub Actions, Woodpecker becomes deploy-only
- GHA ci.yml: add build + deploy jobs (push to DockerHub, trigger Woodpecker)
- Drop test matrix to single Python 3.12, preserve mypy step
- Build/deploy gated on push to main (PRs still run tests only)
- Woodpecker: deploy.yml (manual event, kubectl set image + slack notify)
- Old pipeline preserved as build-fallback.yml (manual trigger)
2026-03-15 23:25:36 +00:00
Viktor Barzin
44e1b84a5a
fix CI deploy: use kubectl set image instead of rollout restart
rollout restart re-pulls the same tag without updating it. Use set image
with CI_PIPELINE_NUMBER to deploy the actual new build.
2026-03-15 22:51:20 +00:00
Viktor Barzin
2fbca35e77
fix: remove extraneous f-string prefixes to pass ruff lint 2026-03-15 22:50:57 +00:00