Commit graph

73 commits

Author SHA1 Message Date
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
Viktor Barzin
ba9d31f479
fix pre-existing test failures blocking CI
- test_sync: URL-decode before asserting since param (percent-encoded +)
- test_api: already fixed in previous commit (included for completeness)
2026-03-15 22:44:16 +00:00
Viktor Barzin
dbbacd75c2
fix delete tests to match idempotent endpoint behavior
The delete endpoint intentionally returns 200 (not 404) when a memory
is already deleted, to prevent retry loops in old clients. Tests were
asserting 404 incorrectly.
2026-03-15 22:41:10 +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
b6869ef496
ci: trigger rebuild with URL-decode fix 2026-03-15 15:29:08 +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
4456922294
add fallback chain for judge: claude CLI → ollama → heuristic
- claude CLI: run from /tmp to avoid internet-mode-used marker prompts
- ollama: try small local models (qwen2.5:3b, llama3.2:3b, etc.)
- heuristic: pattern matching for corrections, preferences, decisions
- better JSON extraction: handles markdown fences and surrounding text
2026-03-15 11:15:14 +00:00
Viktor Barzin
a8679d6cfb
enhance auto-learn hook: multi-turn extraction, dedup, and auto-memory files
- Deep extraction every 5 turns: reads last 5 exchanges for debugging
  insights, workarounds, architectural patterns, and operational knowledge
- Single-turn extraction on every other turn (cheap, corrections/prefs only)
- State tracking per session: turn counter, content hashes for dedup
- Writes to both memory API/SQLite AND auto-memory markdown files
- Expanded judge prompt: now catches debugging (error→cause→fix),
  workarounds, and operational knowledge — not just corrections/facts
- Auto-cleanup of state files older than 24 hours
2026-03-15 10:59:15 +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
be9e6352c3
Rewrite README to showcase plugin functionality
Lead with value prop and install command, add conversation example,
restructure around features/hooks/auto-behaviors, consolidate env
vars and API reference into clean tables, move API server docs below
plugin setup since it's optional.
2026-03-14 14:52:09 +00:00