| 2026-05-09 |
Replace profile edit drawer with centered modal
...
The drawer was awkward on wide screens. Modal is centered, capped at
900px, with proper header/body/footer layout and scrollable content.
Model & Generation fields now render in a responsive row of 5 columns.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Add profile editing to admin panel
...
Backend:
- navi/profiles/loader.py: add save_profile_to_dir() to write config.json
and system_prompt.txt back to disk
- navi/core/registry.py: add ProfileRegistry.update() for in-memory updates
- navi/api/routes/admin.py: new endpoints GET /admin/profiles/{id} and
PUT /admin/profiles/{id} for reading and saving full profile config
Admin panel:
- Profiles table: add Edit button per row
- Drawer form with sections: Basic, Model & Generation, Thinking,
Planning, Sub-agent, Tools, System Prompt
- All fields editable inline (text inputs, checkboxes, textareas for lists)
- Save via PUT request, updates both disk and in-memory registry without
server restart
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Open admin panel in new browser tab from Android and webclient
...
Android:
- Add /admin path to shouldOpenExternally so admin links open in
the system browser instead of the WebView.
Webclient:
- Add target="_blank" and rel="noopener noreferrer" to the admin
link in AppSidebar.vue so it opens in a new tab.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Fix admin panel review findings
...
- Remove dead admin API functions from webclient/src/api/index.js
(admin is standalone now, no longer part of webclient)
- Harden esc() in admin/index.html to escape quotes (" / ')
- Add 401 redirect to '/' in admin API requests
- Add TypeError catch for offline/network errors with human message
- Remove redundant Yes/No text in profiles table (toggle switch is enough)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Document Android OAuth bridge page flow
...
- docs/auth.md: describe browser vs Android WebView flows, bridge page
mechanism, state metadata detection via NaviAndroid UA
- docs/api.md: add /auth/mobile-done endpoint reference
- docs/android-client.md: add OAuth/login section covering intent filter,
CookieManager injection, deep-link handling in onCreate/onNewIntent
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Style OAuth bridge page with gnexus UI kit design system
...
Redesigned /auth/mobile-done to match the Navi webclient visual
language (Tokyo Night cyberpunk palette):
- Dark background (#16161E), muted panel with green success accent
- Squared corners, uppercase headings, wide letter-spacing
- Spinner during auto-redirect, fallback button with left accent border
- Full hover states matching .btn-success from the kit
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Detect Android OAuth client via User-Agent header
...
WebView always sends NaviAndroid/1.0 in the HTTP User-Agent, while
navigator.userAgent in JS is unreliable. Backend now detects the
Android platform from the UA header when the ?platform query param is
absent, ensuring the bridge-page flow works regardless of webclient
version.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Improve OAuth bridge page with Chrome Intent URL + fallback button
...
/auth/mobile-done now tries Chrome Intent URL for automatic app
opening, and falls back to a styled button if the browser blocks
automatic navigation to custom schemes.
- Auto-redirect: intent://...#Intent;scheme=navi;package=com.navi.client;end
- Fallback UI: card with \"Open Navi App\" button after 1.5s timeout
- Works in both Chrome (auto) and DuckDuckGo (manual tap)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
Add Android deep-link OAuth bridge for WebView auth
...
Problem: Android WebView opens OAuth in external browser (Chrome).
After successful login, cookie stays in Chrome and WebView remains
unauthenticated because cookies are not shared between apps.
Solution: bridge page flow that avoids cookies entirely for mobile.
Backend:
- /auth/login accepts ?platform=android and ?return_to params
- /auth/callback detects android via state metadata, skips cookie,
redirects to /auth/mobile-done?sid=<session_id>
- /auth/mobile-done renders HTML that deep-links to navi://auth/callback
Webclient:
- login() detects NaviAndroid UA and adds ?platform=android
Android:
- MainActivity: handle incoming navi:// intent in onCreate and onNewIntent,
set cookie via CookieManager, reload WebView
- AndroidManifest: add intent-filter for navi://auth/callback and
singleTask launchMode
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 May
|
| 2026-05-08 |
Compact admin/logout buttons in sidebar footer
...
In sidebar-footer-actions, replace text+icon Admin and Logout buttons
with icon-only btn-icon buttons (shield-check and sign-out icons).
Add without-hover class to suppress the default icon rotation hover
animation. Keep the Login button unchanged (text + icon as before).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Add per-user sessions and memory filters in admin panel
...
Backend:
- GET /admin/memory now accepts user_id query param to filter facts
for a specific user instead of returning the global view.
Frontend:
- Users table now has "Sessions" and "Memory" buttons per row.
- Clicking "Sessions" switches to Sessions tab and pre-fills search
with the user id.
- Clicking "Memory" switches to Memory tab and passes user_id to the
API, showing only that user's facts.
- Manual tab clicks reset filters (search / userId) so the view
returns to unfiltered state.
Docs:
- docs/api.md updated with user_id param for GET /admin/memory.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Update docs for admin pagination, search, sorting and memory all_users
...
- docs/api.md:
- GET /admin/sessions: document pagination (limit/offset), search,
sort_by and sort_order query params; switch response to {total,
limit, offset, items} envelope.
- GET /admin/memory: same pagination/sort docs, {total, limit,
offset, items} envelope.
- docs/memory.md:
- get_all_facts signature now includes offset, search, sort_by,
sort_order and all_users parameters.
- docs/sessions.md:
- Document count_all and search_list store methods.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|

Fix admin memory showing 0 facts; add pagination/search/sort
...
Bug fix:
- get_all_facts(user_id=None) was filtering for user_id IS NULL only,
so admin panel showed 0 facts when facts had user_ids set.
- Added all_users parameter to get_all_facts and fact_count.
- Admin endpoint now passes all_users=True to return all facts.
Memory pagination:
- Extended get_all_facts with offset, search, sort_by, sort_order params.
- Extended fact_count with search and all_users params.
- /admin/memory endpoint now accepts limit, offset, search, sort_by,
sort_order and returns {total, limit, offset, items}.
Admin panel frontend:
- Added server-side search with debounce for memory facts.
- Added sortable column headers (category, key, source, confidence, updated).
- Added pagination controls (prev/next, page size selector).
- Switched memory display from grouped tables to flat sortable table.
Tests:
- Added unit tests for get_all_facts(all_users=True) and
fact_count(all_users=True).
- All 219 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Add pagination, search, and sorting to admin sessions
...
Backend:
- Add count_all and search_list abstract methods to SessionStore
- Implement count_all and search_list in PgSessionStore (SQL with ILIKE)
- Implement count_all and search_list in InMemorySessionStore
- Update /admin/sessions to accept limit, offset, search, sort_by, sort_order
- Return {total, limit, offset, items} from /admin/sessions
Frontend:
- Add search input for sessions in admin panel
- Add clickable sortable column headers with asc/desc toggle
- Add pagination controls (prev/next, page size selector, item count)
- Debounce search input (300ms)
Tests:
- Add integration tests for pagination, offset, search, and sorting
- All 217 tests pass
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Fix memory system bugs: deterministic summary id, skip legacy extraction
...
- _summary.py: replace non-deterministic hash() with zlib.crc32 so
summary id stays stable across server restarts, preventing duplicate
summary rows.
- extractor.py: skip memory extraction for legacy sessions (user_id=None)
— ON CONFLICT(user_id, category, key) does not catch NULL duplicates
in PostgreSQL (NULL != NULL).
- sessions.py: _process_stale_sessions skips legacy sessions.
- _facts.py: remove dead code (user_clause/user_param variables).
- test_extractor.py: add user_id to test sessions + new test for
legacy session skip.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Fix memory system multi-user bugs: summary PK conflict and vector search params
...
- _summary.py: generate deterministic per-user id (hash(user_id)+2) instead of
hardcoded id=1, preventing UniqueViolationError on memory_summary_pkey
for multi-user sessions.
- _facts.py: split vector search into user_id=None / user_id!=None branches
with correct parameter counts, fixing InterfaceError "expects 3 arguments".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Fix missing columns in navi_users: add boot-time ALTER TABLE migration
...
The navi_users table already existed on this deployment, so the updated
CREATE TABLE IF NOT EXISTS was a no-op. Run ALTER TABLE ADD COLUMN for
username, first_name, last_name, phone, birth_date, country, city, locale
if they are missing (checked via information_schema.columns).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Propagate user profile to LLM context via current_user_info ContextVar
...
- Extend User model: username, first_name, last_name, phone, birth_date,
country, city, locale (all from gnexus-auth profile)
- navi_users DDL: add new profile columns
- auth/deps + auth/callback: populate new fields on upsert
- /auth/me: return all profile fields
- Add current_user_info ContextVar for full user profile propagation
- websocket + messages: set current_user_info before agent.run()
- run_ephemeral: inherit and restore current_user_info
- ContextBuilder: _user_context_msg() injects [User context] with name,
email, location, locale, role into LLM system messages
- _security_policy_msg: reads user_id/role from ContextVar directly
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Add multi-user sandbox: filesystem, terminal, code_exec, security policy
...
- filesystem, share_file: sandbox non-admin users to user_data/<user_id>/
- terminal: working_dir sandbox + allowlist + dangerous pattern block for users
- code_exec: sandbox CWD and temp files to user_data/<user_id>/ for users
- context_builder: inject dynamic security policy into LLM context (user/admin)
- config: terminal_user_allowed_commands setting
- agent: wire user_id/user_role through ContextBuilder.build()
- base: add current_user_role ContextVar; run_ephemeral inherits role
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Add per-user filesystem sandbox via current_user_id ContextVar
...
- tools/base.py: add current_user_id ContextVar (set by Agent before
every tool call, cleared after)
- core/agent.py: set current_user_id in run_stream from session.user_id
and in run_ephemeral from parent_session.user_id; restore in finally
- tools/filesystem.py: _check_path resolves all paths inside
user_data/<user_id>/ when current_user_id is present; legacy mode
(no user_id) falls back to FS_ALLOWED_PATHS
- tools/share_file.py: validate source path is inside user sandbox
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Use configured GNAUTH_REDIRECT_URI instead of dynamic base_url
...
_get_redirect_uri was building the redirect_uri from request.base_url,
which returns the internal address when behind a reverse proxy. This
caused gnexus-auth to reject the redirect_uri as invalid.
Now _get_redirect_uri always returns settings.gnauth_redirect_uri,
so the public URL configured in .env is used consistently.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
Add missing playwright dependency to pyproject.toml
...
playwright is used by navi/tools/web_view.py but was not declared.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 May
|
| 2026-05-04 |
Fix stop_session 422: use get_current_user instead of get_current_user_ws
...
stop_session is an HTTP endpoint but was using Depends(get_current_user_ws),
whose websocket parameter caused FastAPI to demand it as a query param.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Fix NameError in run_ephemeral: session was undefined
...
run_ephemeral doesn't have a session variable. Pass user_id from the
parent session (looked up via parent_session_id) instead of referencing
non-existent session variable.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Dark login screen: #111 overlay, transparent card
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Add full-screen login overlay for unauthenticated users
...
- Backend: new endpoint GET /auth/status returns {configured: bool}
- Webclient auth store: add authConfigured ref + fetchStatus()
- LoginScreen.vue: centered card with logo, title, and login button
- App.vue: show LoginScreen overlay when auth is configured but
user is not authenticated (z-index 9999, blocks all UI)
- App.vue onMounted: fetch auth status before trying to resolve user
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Fix WebSocket 403 — bypass FastAPI Depends for WS auth
...
- websocket.py: resolve user by calling get_current_user_ws directly
inside the handler instead of using Depends(). This avoids FastAPI
returning HTTP 403 on the upgrade request when auth resolution fails.
- websocket.py: accept WebSocket before access check, close with 4003
for auth failures instead of HTTP 403.
- auth/deps.py: remove debug logging from get_current_user_ws.
- tests/conftest.py: monkeypatch get_current_user_ws directly since
Depends() is no longer used on the WebSocket endpoint.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Fix WebSocket 403 and restore dependency resolution for auth
...
- websocket.py: restore Depends(get_current_user_ws) in endpoint signature
so FastAPI dependency_overrides work correctly in tests
- websocket.py: accept WebSocket before access check; reject anonymous
only for owned sessions, allow anonymous for legacy (user_id=None)
- auth/deps.py: add info-level logging to get_current_user_ws entry/exit
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Fix WebSocket 403 by accepting before access check
...
- websocket.py: move await websocket.accept() before check_session_access
so auth failures close the WebSocket with 4003 instead of returning
HTTP 403 on the upgrade request
- Reject anonymous WebSocket connections explicitly (4003)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|
Fix legacy session visibility and add WebSocket auth debug logging
...
- pg_session_store: remove OR user_id IS NULL from list_all/list_page
so legacy sessions are no longer visible to all users
- auth/deps.py: add debug logging at every step of _resolve_user
- websocket.py: add debug logging at every stage of websocket_session
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 4 May
|