Newer
Older
navi-1 / docs / mechanics.md
@Eugene Sukhodolskiy Eugene Sukhodolskiy 2 days ago 43 KB Add NAVI_AUTH_ENABLED switch for optional auth

Mechanics Catalog

Master catalog of every mechanism, feature, behavior, and configurable flag in the Navi project.

Use this document before designing a new feature to check whether an existing mechanism can be reused, extended, or should be replaced.


How to read this catalog

Column Meaning
Mechanic Short name. Click the source file link to see the implementation.
Description What it does and when it triggers.
Config / Flags .env variables or config.json profile fields that control it.
Files Primary implementation file(s).
Docs = documented in docs/. = not documented anywhere yet. ⚠️ = partially documented.

Agent Loop (navi/core/agent.py)

Mechanic Description Config / Flags Files Docs
Streaming entry point run_stream() — yields AgentEvent objects in real time. Loads session, runs planning (if enabled), tool loop, workers. profile.max_iterations, profile.llm_backend, profile.model, profile.temperature agent.py
Non-streaming entry point run() — same loop but returns plain string. No planning phase, no events. Same as above agent.py
Streaming guard wrapper Wraps llm.stream_complete() with two safety layers: (1) polls stop_event every second during prefill so the Stop button works even when the model emits no chunks, and (2) hard first_chunk_timeout/chunk_timeout deadlines that close the HTTP connection to Ollama so GPU load drops. LLM_STREAM_FIRST_CHUNK_TIMEOUT, LLM_STREAM_CHUNK_TIMEOUT agent.py
Subagent thinking stall detector Monitors subagent streaming; if only thinking output is emitted for 60 s or 12 000 chars without text/tool calls, aborts the subagent to prevent endless internal-token loops on local models. Hard-coded _SUBAGENT_THINKING_STALL_SECONDS=60.0, _SUBAGENT_THINKING_STALL_CHARS=12000 agent.py
Cooperative stop Checks current_stop_event (asyncio.Event) before each LLM call, during streaming, and after tool execution. Uses clean generator close — never task.cancel(). None agent.py
First-message forced planning Planning phase always runs on the first user message in a session regardless of profile.planning_enabled. profile.planning_enabled (only affects subsequent turns) agent.py
Profile reload mid-session After each tool execution batch, checks DB for profile ID change (e.g. from switch_profile). If changed, reloads profile, tools, schemas, and backend for next iteration. None agent.py
Pre-turn context compression Before assistant reply, checks session.context_token_count against threshold and compresses if exceeded. CONTEXT_COMPRESSION_ENABLED, OLLAMA_NUM_CTX, CONTEXT_COMPRESSION_THRESHOLD agent.py
Mid-turn context compression On iterations > 0, estimates tokens and triggers compression with keep_recent_messages=max(12, CONTEXT_KEEP_RECENT*2). For long autonomous loops where the entire conversation is one turn. Same as above + CONTEXT_KEEP_RECENT agent.py
Context size check with output reserve Raises ContextTooLargeError if estimated input tokens exceed OLLAMA_NUM_CTX - OUTPUT_RESERVE_TOKENS. Images counted at 500 tokens each. OLLAMA_NUM_CTX, OUTPUT_RESERVE_TOKENS agent.py ⚠️
Local token estimation Conservative estimate: chars // 4 + imgs * 500. Used for preflight context size checks. None agent.py
Anti-stall detection Tracks two signals: (1) consecutive iterations with no todo status change, (2) identical tool call signatures. When either hits threshold, injects a hard warning system message. profile.anti_stall_enabled, profile.anti_stall_threshold agent.py
Adaptive replan on failure Detects newly-failed todo steps after each tool batch and queues a re-planning system message for the next iteration. profile.adaptive_replan_enabled agent.py
Goal anchoring Injects [Goal anchor] system message with original request + todo state every N iterations. profile.goal_anchoring_enabled, profile.goal_anchoring_interval agent.py
Todo status snapshot Captures frozenset of (task_text, status) before each iteration so anti-stall can detect progress. None agent.py
Todo failed-steps tracking Captures frozenset of (index, text) for failed steps, used by adaptive replan. None agent.py
Todo progress message injection Injects compact system reminder with current todo state and discipline notes at start of every iteration. None agent.py
Memory facts deduplication Tracks _injected_fact_ids across a single run_stream call so the same memory fact is not injected twice in one turn. None agent.py
Context injection collection (parallel) Fires _collect_context_injections and _memory_facts_msg concurrently before each turn. profile.context_providers agent.py
MCP server group expansion Resolves profile.mcp_servers: * expands to all tools for that server; named groups resolve via mcp_manager.resolve_group. profile.mcp_servers agent.py ⚠️
User-enabled tools merge Loads extra tool names from tools/enabled.json and appends to profile's enabled_tools. settings.tools_dir agent.py ⚠️
Recall message wrapping When is_recall=True, prefixes user message with [Scheduled recall — execute this task]\n\n. None agent.py
Per-tool-call event sink Creates asyncio.Queue for each tool call so subagents can emit events back to parent in real time. None agent.py
Display vs context message splitting Accepts separate display_message (shown in UI) and user_message (sent to LLM, may contain injected hints). None agent.py
Post-turn workers Runs registered workers sequentially after StreamEnd. None agent.py

Subagent (navi/core/agent.py run_ephemeral)

Mechanic Description Config / Flags Files Docs
Ephemeral execution Runs tool loop without persistent session, temporary in-memory context. Returns (result_text, completed_normally). max_iterations param, timeout_seconds param agent.py
Inherit system prompt When inherit_system_prompt=True, prepends parent's profile.system_prompt as base layer, then subagent specialization on top. inherit_system_prompt param agent.py
Context transfer priming If context_transfer provided, injects it as synthetic user/assistant exchange before task message. context_transfer param agent.py
Wall-clock timeout Monitors elapsed time; aborts and returns [Sub-agent timed out] if exceeded. timeout_seconds param (default 300.0) agent.py
Subagent planning phase Optionally runs full 3-phase planning before tool loop for subagents. profile.subagent_planning_enabled agent.py
Parent session ID passthrough Sets session ContextVar to parent's ID so session-aware tools resolve paths correctly. parent_session_id param agent.py
Dedicated subagent tool list Uses profile.subagent_tools if non-empty; falls back to profile.enabled_tools. profile.subagent_tools agent.py
ContextVar restoration Saves/restores current_session_id, current_model, current_user_id, current_user_role, current_user_info in finally block. None agent.py

Planning Pipeline (navi/core/planning.py)

Mechanic Description Config / Flags Files Docs
3-phase planning engine Orchestrates Phase 1 (analysis), Phase 2 (review), Phase 3 (execution plan) as async generator. profile.planning_phase1_enabled, profile.planning_phase2_enabled, profile.planning_phase3_enabled, profile.planning_mandatory, profile.planning_enabled planning.py
Phase 1 — Task analysis LLM call reformulates task, identifies subtasks, unknowns, resources. Can output DIRECT to skip planning. profile.think_enabled, profile.planning_phase1_enabled planning.py
Phase 2 — Structured review One critique pass when planning_phase2_enabled=True and Phase 1 outputs REFLECT: yes. Returns Critic/Pragmatist/Detailer/Plan Adjustments. profile.planning_phase2_enabled planning.py
Phase 3 — Execution plan Produces milestones + numbered steps with executor assignments (TOOL:, AGENT:, SELF). Enforces comma-test splitting. profile.planning_phase3_enabled planning.py
Auto-populate todo from plan Parses Phase 3 steps and calls todo.set_tasks() to initialize session todo list. None planning.py
Plan step parser Regex extracts numbered step lines from **Steps:** section. None planning.py
Planning debug data logging Accumulates per-phase outputs, tokens, timestamps into _dbg dict and yields PlanningDebugData. None planning.py
Knowledge store rules Hard-coded prompt rules distinguishing memory vs MCP knowledge servers vs docs. None planning.py

Context Builder (navi/core/context_builder.py)

Mechanic Description Config / Flags Files Docs
System prompt caching Caches built system prompt per profile ID to avoid rebuilding on every turn. Provides invalidate_system_prompt_cache(). None context_builder.py
Persona + profile construction Prepends global NAVI_PERSONA to profile's system_prompt, separated by ---. NAVI_PERSONA_FILE context_builder.py
Cross-profile awareness Appends ## Available profiles block listing all other profiles with descriptions. None context_builder.py ⚠️
Memory summary message Injects ## What I remember about the user if memory store has a summary. None context_builder.py
Memory facts message Searches memory facts from user message. Skips messages ≤20 chars or <2 words. Limits: 1 fact for <50 chars, 2 for ≤150, 3 otherwise. Deduplicates. None context_builder.py
Context provider injection Injects global providers unconditionally, profile-named providers only if listed in profile.context_providers. profile.context_providers context_builder.py ⚠️
Goal anchor builder Constructs [Goal anchor] system message with original request + todo lines. None context_builder.py
Security policy message Injects [Security policy] based on current_user_role: admin = full access; user = sandbox + terminal allowlist. TERMINAL_ALLOWED_COMMANDS context_builder.py
User context message Builds [User context] from current_user_info (display_name, email, locale, etc.). None context_builder.py
MCP context message Combines MCP server instructions from handshake with overlay instructions from mcp_servers.d/*.json. profile.mcp_servers context_builder.py
Iteration budget message Appends [Iteration N/M — K after this one] with escalating urgency when ≤2 or ≤5 remaining. profile.iteration_budget_enabled context_builder.py
Session context injection Appends session ID and exact session_files_dir/{session_id}/ path. SESSION_FILES_DIR context_builder.py

Context Compression (navi/core/compressor.py)

Mechanic Description Config / Flags Files Docs
Threshold-based trigger Returns True when context_tokens >= max_context_tokens * threshold. CONTEXT_COMPRESSION_THRESHOLD compressor.py
Turn-based partitioning Groups messages into turns. Keeps last keep_recent turns verbatim; older go to summarization. Tool call groups never split. CONTEXT_KEEP_RECENT compressor.py
Mid-turn fallback partitioning For long autonomous loops where entire conversation is one turn: keeps current request + newest N messages verbatim, summarizes older messages from same turn. keep_recent_messages param compressor.py
Summary input formatter Renders messages as plain text for summarizer: preserves summaries, notes image counts, renders tool calls compactly, collects base64 images for vision models. None compressor.py
Summary input truncate Hard cap of 24 000 chars on formatted input sent to summarizer LLM. Hard-coded _MAX_SUMMARY_INPUT_CHARS=24000 compressor.py
LLM-based summarization Calls LLM with structured summarization prompt and replaces old messages with is_summary=True user message. CONTEXT_SUMMARY_TEMPERATURE, CONTEXT_SUMMARY_MAX_TOKENS compressor.py

Tool Execution (navi/core/tool_executor.py)

Mechanic Description Config / Flags Files Docs
Tool name resolution Resolves exact names, then falls back through 3 MCP alias heuristics: (1) bare suffix match, (2) dash→underscore, (3) old underscore format. None tool_executor.py
Sequential execution Gathers all tool calls with asyncio.gather and returns (tool_msgs, image_msgs). None tool_executor.py
Streaming execution Same as sequential but yields ToolEvent objects alongside messages for UI rendering. None tool_executor.py
Middleware hooks Calls before_execute and after_execute on all registered middlewares around each tool call. None tool_executor.py
Image message generation If tool result has metadata.is_image + metadata.base64, synthesizes vision user message for next LLM call. None tool_executor.py

AI Helper (navi/core/ai_helper.py)

Mechanic Description Config / Flags Files Docs
Single-turn wrapper Thin reusable wrapper over LLMBackend for tools needing quick LLM call. Uses current_model ContextVar with fallback. default_model param, temperature param (default 0.1) ai_helper.py
ask() with timeout Non-streaming call with 120-second asyncio.wait_for timeout. Hard-coded 120 ai_helper.py
ask_json() Calls ask() then parses JSON, handling markdown code fences automatically. None ai_helper.py
Token usage emission Emits AIHelperTokensUsed into current_event_sink for parent session metrics. None ai_helper.py
JSON extractor Strips code fences, tries direct parse, then bracket-matching to find outermost [] or {}. None ai_helper.py

Orchestrator (navi/core/orchestrator.py)

Mechanic Description Config / Flags Files Docs
Orchestrator stub Placeholder class for future multi-agent orchestration. Raises NotImplementedError if instantiated. None orchestrator.py

Event Bus (navi/core/event_bus.py)

Mechanic Description Config / Flags Files Docs
Async pub/sub Type-specific subscription plus catch-all. Publishes by creating asyncio.Task per subscriber and gathering with return_exceptions=True. None event_bus.py
Global singleton Lazy-initialized default bus via get_event_bus(); replaceable via set_event_bus(). None event_bus.py

Registries (navi/core/registry.py)

Mechanic Description Config / Flags Files Docs
ToolRegistry Holds built-in, user-defined, and external/MCP tools. Supports hot-reload without touching builtins. settings.tools_dir registry.py
ProfileRegistry Holds agent profiles. Supports lookup and in-memory replacement. None registry.py
BackendRegistry Holds LLM backend instances (Ollama, OpenAI, fallback). OLLAMA_BACKENDS_FILE, OLLAMA_HOST, OPENAI_API_KEY, etc. registry.py
build_default_registries() Composition root. Discovers backends, creates AIHelper, registers all tools, loads user tools, wires cross-references. settings.tools_dir, settings.context_providers_dir registry.py

Tools (navi/tools/)

Mechanic Description Config / Flags Files Docs
FilesystemTool Read/write/append/edit/list/find/move/copy/delete/exists/mkdir + AI query/smart_edit + grep/diff. Path restrictions via allowlist. FS_ALLOWED_PATHS, FS_ALLOWED_PATHS_LIST filesystem.py
TerminalTool Run shell commands. Unrestricted for admins; sandbox + allowlist for users. TERMINAL_ALLOWED_COMMANDS, TERMINAL_USER_ALLOWED_COMMANDS terminal.py
SshExecTool SSH exec and SCP file transfer. Connection pool per-session with 20-min TTL. SSH_HOSTS_FILE ssh_exec.py
CodeExecTool Run Python in subprocess sandbox. Non-admin sandboxed to user_data/<user_id>/. None code_exec.py
ImageViewTool Load image from path/URL → resize to 1024px, JPEG, return base64 for LLM. None image_view.py
MemoryTool Save/search/forget/list user facts. Dual search: semantic (cosine) + ILIKE fallback. None memory.py
TodoTool Session-scoped task tracker. Set/view/update/clear. Auto-populated from planning. None todo.py
ScratchpadTool Session-scoped working notes. Write/append/read/clear per section. None scratchpad.py
SpawnAgentTool Spawn isolated subagent with own tool loop. Supports inherit_system_prompt, briefing, profile_id. None spawn_agent.py
SwitchProfileTool Switch active profile for session. Blocks is_subagent_only profiles. None switch_profile.py
ListProfilesTool List all profiles with descriptions. Shows [subagent only] tag. None list_profiles.py
ReflectTool 3 parallel AI calls (Critic/Pragmatist/Detailer) to challenge assumptions. None reflect.py
ShareFileTool Copy file into session directory, return public download link. PUBLIC_URL, SESSION_FILES_DIR, SHARE_FILE_MAX_SIZE_MB share_file.py
ContentPublishTool Register session file for inline viewing in chat. SESSION_FILES_DIR content_publish.py
ToolManualTool Return manuals/{tool}.md or auto-generate from schema. MANUALS_DIR tool_manual.py
ListToolsTool Return tools enabled for a profile, including MCP group expansion. tools/enabled.json list_tools.py
ReloadToolsTool Hot-reload user tools, context providers, and MCP servers without restart. settings.tools_dir, settings.context_providers_dir reload_tools.py
ScheduleRecallTool Schedule headless callback (once/recurring/immediate). None schedule_recall.py
ManageRecallTool Cancel/skip/list scheduled recalls. None manage_recall.py
McpStatusTool List MCP servers, connection status, exposed tools. None mcp_status.py
CreateMcpServerTool Scaffold new MCP server directory with boilerplate. None create_mcp_server.py
TestMcpToolTool Execute single MCP tool call in isolation for diagnostics. None test_mcp_tool.py

Tool Internals (navi/tools/_internal/)

Mechanic Description Config / Flags Files Docs
Tool ABC Abstract base. Self-describes via name, description, parameters. None base.py
ToolResult Standard return container: success, output, error, metadata. None base.py
ContextVars Async-safe vars set before each tool call: current_session_id, current_event_sink, current_stop_event, current_model, current_user_id, current_user_role, current_user_info. None base.py
Tool loader Discovers module-level (name, description, parameters, execute) and class-based tools. Errors isolated per file. None loader.py
ToolMiddleware Pre/post execute hooks for logging/metrics/rate limiting. None middleware.py
LoggingMiddleware Logs every tool execution with duration and result summary. None logging_middleware.py
Time parser Parses natural-language times: ISO, relative (2d 6h), in 3 hours, tomorrow at 09:00. None time_parser.py

MCP Subsystem (navi/mcp/)

Mechanic Description Config / Flags Files Docs
McpClient Official MCP SDK wrapper. stdio or SSE transport. None client.py ⚠️
McpServerConfig Pydantic model for server config. Auto-migrates legacy mcp_servers.jsonmcp_servers.d/. mcp_servers.d/ directory config.py ⚠️
McpManager Pool of McpClient instances. Lifecycle management, group resolution, tool listing. config_path manager.py ⚠️
McpTool proxy Tool subclass forwarding to MCP server. Namespaced as mcp__<server>__<tool>. None tools.py

Sessions (navi/core/session.py, navi/core/pg_session_store.py)

Mechanic Description Config / Flags Files Docs
Session model Dual-buffer design: messages (display, never compressed) and context (LLM input, compressible). None session.py
InMemorySessionStore Dict-backed ephemeral store for testing. None session.py
PgSessionStore PostgreSQL-backed store. Auto-DDL, JSON serialization, full-text search. DATABASE_URL pg_session_store.py
Session file storage Per-session directory on disk. Safe filename sanitization, forbidden extension blocking, orphan cleanup. SESSION_FILES_DIR, SESSION_FILES_MAX_SIZE_MB, SHARE_FILE_MAX_SIZE_MB session_files.py
Content store Registers session files for inline viewing via DB metadata. PUBLIC_URL content_store.py ⚠️

Memory System (navi/memory/)

Mechanic Description Config / Flags Files Docs
MemoryStore Composite: EmbeddingMixin + FactMixin + SummaryMixin + SessionStateMixin. Lazy-initializes pool, auto-creates tables. DATABASE_URL, EMBEDDING_MODEL, EMBEDDING_DIMENSIONS store.py
EmbeddingMixin Generates embeddings via LLM backend. Single or batch. Backfills missing. EMBEDDING_MODEL, EMBEDDING_OLLAMA_HOST, EMBEDDING_OLLAMA_API_KEY _embeddings.py
FactMixin CRUD + dual search: vector (cosine, cutoff 0.3) then ILIKE fallback. Upsert, delete, list, count, categories. None _facts.py
SummaryMixin Per-user narrative summaries. Deterministic PK via zlib.crc32. None _summary.py
SessionStateMixin Tracks which sessions already processed for fact extraction. Prevents duplicates. None _session_state.py
Fact extraction Post-session background extraction from transcripts. LLM parses JSON, upserts facts with confidence, regenerates summary. Temperature 0.1, summary temperature 0.3, _MAX_TRANSCRIPT_CHARS=12000 extractor.py
DDL builder Conditionally generates DDL based on pgvector availability. Creates tables, indexes, constraints. EMBEDDING_DIMENSIONS _ddl.py ⚠️
Backfill embeddings script Batch-generates embeddings for existing facts without them. 8 per batch, 2s sleep. DATABASE_URL, EMBEDDING_MODEL backfill_embeddings.py
Migrate pgvector script Adds missing pgvector columns and indexes to existing tables. DATABASE_URL migrate_pgvector.py

Context Providers (navi/context_providers/)

Mechanic Description Config / Flags Files Docs
ContextProviderRegistry Loads built-in + user providers. Validates exports. Supports hot-reload. CONTEXT_PROVIDERS_DIR _loader.py
public_url provider Injects server's public URL into LLM context as system message. PUBLIC_URL public_url.py

Workers (navi/workers/)

Mechanic Description Config / Flags Files Docs
Worker base class Abstract base for post-response background tasks. Receives WorkerContext, may mutate session, return events. None base.py ⚠️
CompressionWorker Post-turn compression. Replaces old context with summary, resets token count, appends marker. CONTEXT_COMPRESSION_ENABLED, CONTEXT_COMPRESSION_THRESHOLD, CONTEXT_KEEP_RECENT, CONTEXT_SUMMARY_TEMPERATURE, CONTEXT_SUMMARY_MAX_TOKENS compressor.py
Worker auto-discovery Scans navi/workers/*.py and auto-instantiates non-abstract Worker subclasses. None __init__.py

KV Store (navi/store/)

Mechanic Description Config / Flags Files Docs
KvStore PostgreSQL-backed key-value persistence scoped by (user_id, session_id, scope, key). Auto-creates table/index. DATABASE_URL __init__.py

WebSocket (navi/api/websocket.py)

Mechanic Description Config / Flags Files Docs
Streaming protocol Full-duplex: client sends message, server emits stream_start, thinking_delta, stream_delta, tool_call, stream_end, etc. _HEARTBEAT_INTERVAL=20.0, _MAX_REPLAY_EVENTS=500, _MAX_IMAGES=10, _MAX_IMAGE_BYTES=5MB websocket.py
Stop session POST /sessions/{id}/stop sets stop_event cooperatively. None websocket.py
Reconnect/replay On connect, if run active, replays buffered events before live stream. _MAX_REPLAY_EVENTS=500 websocket.py
Image upload validation Max 10 images, 5MB each. Strips data:...;base64, prefix. _MAX_IMAGES=10, _MAX_IMAGE_BYTES=5242880 websocket.py
Image context annotation Appends note telling model that N images are already in multimodal context. None websocket.py
File context annotation Appends [Uploaded files on disk: ...] to user content. None websocket.py ⚠️
Concurrent run guard Rejects new messages if _runs or _busy_sessions already contains session ID. None websocket.py
Heartbeat keepalive Sends heartbeat every 20 seconds during idle. _HEARTBEAT_INTERVAL=20.0 websocket.py
User ContextVar propagation Sets current_user_id, current_user_role, current_user_info from resolved User before agent run. None websocket.py
Recall update forwarding Subscribes to RecallUpdate events and forwards to open WebSockets for affected session. None websocket.py

REST API (navi/api/routes/)

Mechanic Description Config / Flags Files Docs
List profiles GET /agents/profiles — filters is_admin_only for non-admins. None agents.py
List system prompts GET /agents/prompts — returns fully built prompt per profile. None agents.py
List tools GET /agents/tools — all registered tools with schemas. None agents.py
List MCP servers GET /agents/mcp_servers — servers, groups, instructions, tools. None agents.py
OAuth login redirect PKCE + state, stores platform metadata for Android. GNAUTH_CLIENT_ID, GNAUTH_REDIRECT_URI auth.py
OAuth callback Exchanges code, fetches user, upserts navi_users, encrypts tokens, sets cookie or redirects to mobile bridge. GNAUTH_CLIENT_ID, GNAUTH_CLIENT_SECRET, NAVI_AUTH_ENCRYPTION_KEY auth.py
Mobile auth bridge HTML bridge page with Chrome Intent URL auto-redirect. None auth.py
Session CRUD Create, list (paginated/search/sort), get, pin, delete. DATABASE_URL sessions.py
Session context/planning (debug) GET /sessions/{id}/context and /planning — admin only. None sessions.py
Session file upload Multipart upload with size/type validation. SESSION_FILES_MAX_SIZE_MB sessions.py
Session file download Inline or attachment. Path-traversal guarded. None sessions.py
Generate session name Auto-generates display name from user messages via LLM. None sessions.py
Recall endpoints Get, cancel, skip recalls for session. None sessions.py
Admin session management List all sessions, full details, bypass-ownership delete. None admin.py
Admin user management List, detail, role update. None admin.py
Admin memory view All memory facts with pagination/search. Requires navi.memory.read_all. None admin.py
Admin profile toggle Toggles is_admin_only and persists to profile_overrides table. None admin.py
Admin profile detail/update GET/PUT profile config, writes back to disk, updates in-memory registry. None admin.py
Admin Ollama blacklist clear Clears dead-server and dead-model blacklists. None admin.py
Admin MCP config Bulk get/put, per-server CRUD. None admin.py
Admin MCP reconnect Drops old client, unregisters tools, connects fresh, re-registers. None admin.py
Admin MCP status/test Status listing and isolated tool execution. None admin.py
Admin profile MCP mapping GET/PUT mcp_servers dict per profile. None admin.py
Admin recall listing All scheduled recalls with pagination/filtering. None admin.py
Gnexus-auth webhook Receives user.blocked/archived/deleted, auth.global_logout, session.revoked, client.roles_changed. None webhooks.py

Dependency Injection (navi/api/deps.py)

Mechanic Description Config / Flags Files Docs
Lazy singleton initialization get_session_store(), get_memory_store(), get_kv_store(), get_scheduler(), get_registries(), etc. Module-level caching. DATABASE_URL, EMBEDDING_OLLAMA_HOST, EMBEDDING_OLLAMA_API_KEY deps.py ⚠️
MCP manager & tool registration get_mcp_manager() lazily initializes and loads all servers. Clears and re-registers mcp__* tools. None deps.py
Embedding backend wiring Dedicated OllamaBackend for embeddings (if EMBEDDING_OLLAMA_HOST set) or falls back to main chat backend. Injected into memory store. EMBEDDING_OLLAMA_HOST, EMBEDDING_OLLAMA_API_KEY, EMBEDDING_MODEL deps.py ⚠️

Scheduler / Recall (navi/core/scheduler.py)

Mechanic Description Config / Flags Files Docs
Recall scheduling Inserts pending recall into session_recalls. One pending per session via partial unique index. None scheduler.py
Recall cancellation Marks pending recalls as cancelled. None scheduler.py
Recall skip Advances recurring recall by interval_seconds using GREATEST(trigger_at, now). None scheduler.py
Recall listing Filter by session_id, user_id, with admin override. None scheduler.py
Pending recall queries get_pending_recalls(before), get_next_trigger_at(), get_pending_session_ids(). None scheduler.py
Background loop recall_scheduler_loop() polls for due recalls, fires up to 3 concurrently (semaphore), sleeps until next trigger. None scheduler.py
Headless fire _fire_recall() defers if WebSocket run active, loads session, sets ContextVars, registers headless _AgentRun, streams events, handles success/failure/MaxIterationsReached, reschedules recurring, sends session_sync. None scheduler.py

Main Application (navi/main.py)

Mechanic Description Config / Flags Files Docs
FastAPI app setup Creates app, includes routers, mounts static dirs. None main.py
CORS middleware Allows all origins, credentials, methods, headers. None main.py
Static file mounting /assets, /images, /content-viewers, /content, /debug, /debug/eval, /admin. None main.py
Startup lifecycle Ensures auth tables, content store tables, initializes registries, connects MCP, applies profile overrides, checks embedding health, starts file cleanup + recall scheduler. Retries table creation 5× with 2s sleep for Docker races. None main.py
Shutdown lifecycle Closes SSH connections, disconnects MCP servers, cancels scheduler task. None main.py

Configuration (navi/config.py)

Mechanic Description Config / Flags Files Docs
Settings model Pydantic-settings from .env. Covers LLM, embedding, web search, sandboxing, SSH, DB, logging, tools, session files, public URL, Gmail, OAuth, cookies, timeouts, compression, persona. ~60 env vars config.py
Persona file loader @model_validator reads navi_persona_file into navi_persona if inline value empty. NAVI_PERSONA_FILE config.py
Computed path/command lists Parses comma-separated strings into lists. FS_ALLOWED_PATHS, TERMINAL_ALLOWED_COMMANDS, etc. config.py

Auth System (navi/auth/)

Mechanic Description Config / Flags Files Docs
User model Pydantic User with id, email, profile, role, permissions, has_permission() helper. None auth/__init__.py
Auth DDL & boot-time migrations Creates navi_users, user_auth_sessions, migrates missing columns. None auth/_ddl.py
GAuthClient singleton Shared state/PKCE stores, builds per-redirect_uri GAuthClient. GNAUTH_CLIENT_ID, GNAUTH_CLIENT_SECRET auth/client.py
Token encryption Fernet encrypts/decrypts OAuth tokens before DB storage. NAVI_AUTH_ENCRYPTION_KEY auth/encrypt.py
Current user resolution Reads cookie, decrypts token, refreshes if expired, fetches from gnexus-auth, upserts navi_users, caches in conn.state.user. Short-circuits to fixed anonymous admin when NAVI_AUTH_ENABLED=false. NAVI_AUTH_ENABLED auth/deps.py
Permission guards require_user (401), require_admin (403), require_permission(permission) (403). When auth disabled, all return anonymous admin. NAVI_AUTH_ENABLED auth/deps.py
Session access control check_session_access(): legacy sessions (user_id=None) admin-only; owned sessions accessible to owner/admin/explicit permission. Bypassed when auth disabled. NAVI_AUTH_ENABLED auth/deps.py

Profiles (navi/profiles/)

Mechanic Description Config / Flags Files Docs
AgentProfile model Full agent config: identity, LLM settings, tools, thinking mechanics, planning flags, subagent config, visibility flags. All fields in config.json profiles/base.py
Profile loader Auto-discovers subdirs with config.json + system_prompt.txt. Validates keys, loads optional subagent_system_prompt.txt, migrates planning_reflect_enabledplanning_phase2_enabled. None profiles/loader.py
Profile saver Writes config.json, system_prompt.txt, optional subagent_system_prompt.txt. None profiles/loader.py
Runtime profile overrides profile_overrides table persists is_admin_only changes across restarts. Loaded at startup. None profiles/_overrides.py

Undocumented Mechanics Summary

These mechanisms have no documentation in docs/:

  1. Streaming guard wrapper (agent.py) — prefill polling + hard timeouts
  2. Subagent thinking stall detector (agent.py) — aborts subagent after 60s/12k chars of pure thinking
  3. Memory facts deduplication (agent.py) — _injected_fact_ids per turn
  4. Mid-turn context compression (agent.py) — compression during autonomous loops with doubled keep-recent
  5. Context injection collection (parallel) (agent.py) — concurrent context providers + memory
  6. Security policy message (context_builder.py) — dynamic sandbox/allowlist message
  7. User context message (context_builder.py) — injects user profile data
  8. MCP context message (context_builder.py) — combines handshake + overlay instructions
  9. Memory facts message (length limits) (context_builder.py) — skip short messages, limit results
  10. System prompt caching (context_builder.py) — per-profile cache
  11. Goal anchor builder (context_builder.py) — constructs goal anchor message
  12. Session context injection (context_builder.py) — injects session files path
  13. Turn-based partitioning (compressor.py) — turn grouping for compression
  14. Mid-turn fallback partitioning (compressor.py) — same-turn compression for long loops
  15. Summary input formatter (compressor.py) — message rendering for summarizer
  16. Summary input truncate (compressor.py) — 24k char cap
  17. Tool name resolution (MCP aliases) (tool_executor.py) — 3 heuristic fallbacks
  18. Tool middleware hooks (tool_executor.py) — before/after execute
  19. Image message generation (tool_executor.py) — synthesizes vision message from tool result
  20. Streaming tool execution (tool_executor.py) — yields ToolEvent alongside messages
  21. AIHelper single-turn wrapper (ai_helper.py)
  22. AIHelper ask() timeout (ai_helper.py) — 120s hard limit
  23. AIHelper ask_json() (ai_helper.py)
  24. AIHelper token usage emission (ai_helper.py)
  25. AIHelper JSON extractor (ai_helper.py)
  26. Orchestrator stub (orchestrator.py)
  27. EventBus pub/sub (event_bus.py)
  28. Image upload validation (websocket.py) — 10 images, 5MB each
  29. Image context annotation (websocket.py) — note about inline images
  30. File context annotation (websocket.py) — uploaded files list
  31. Concurrent run guard (websocket.py)
  32. User ContextVar propagation (websocket.py)
  33. MCP manager & tool registration (deps.py) — lazy init + clear/re-register
  34. Worker auto-discovery (workers/__init__.py)
  35. ToolMiddleware ABC (tools/_internal/middleware.py)
  36. LoggingMiddleware (tools/_internal/logging_middleware.py)
  37. Profile overrides persistence (profiles/_overrides.py) — DB table for admin toggles
  38. Plan step parser (planning.py)
  39. Planning debug data logging (planning.py)
  40. Knowledge store rules (planning.py)
  41. Context transfer priming (agent.py subagent)
  42. ContextVar restoration (agent.py subagent)
  43. FastAPI CORS (main.py)
  44. Static file mounting (main.py)
  45. Startup lifecycle (main.py) — table creation retries, MCP connect, override apply
  46. Shutdown lifecycle (main.py)
  47. Local token estimation (agent.py)
  48. Recall message wrapping (agent.py)
  49. Cross-profile awareness (context_builder.py)
  50. MCP context message (context_builder.py)

Cross-Reference Index

"I want to build X — which existing mechanics might help?"

Desired Feature Reusable Mechanic(s)
Rate-limit tool calls ToolMiddleware hooks (before_execute/after_execute)
Log tool metrics LoggingMiddleware (already exists)
Inject dynamic context per session Context providers (ContextProviderRegistry)
Inject dynamic context per turn ContextBuilder._collect_context_injections + context providers
Sandbox file access for users FS_ALLOWED_PATHS + _check_path() in FilesystemTool
Sandbox shell commands for users TERMINAL_ALLOWED_COMMANDS + dangerous pattern blocklist
Track task progress across turns TodoTool + planning auto-populate
Detect model looping Anti-stall detector + todo snapshot comparison
Auto-replan on failures Adaptive replan + todo failed-steps tracking
Compress long conversations CompressionWorker + compress_context()
Summarize old turns compress_context() with LLM-based summarization
Schedule future work RecallScheduler + schedule_recall / manage_recall tools
Run headless agent Agent.run_stream() with is_recall=True
Stream events to client _AgentRun queue + WebSocket protocol
Delegate to specialist agent SpawnAgentTool + run_ephemeral()
Switch agent personality mid-chat SwitchProfileTool + profile reload mid-session
Store per-session state across restarts KvStore (session_store table)
Persist user facts across sessions MemoryStore + FactMixin + extractor
Search memory semantically EmbeddingMixin + pgvector cosine distance
Hot-reload without restart ReloadToolsTool + ToolRegistry.reload_user_tools()
Multi-server LLM fallback FallbackOllamaBackend + blacklist clearing
Auth with external OAuth GAuthClient + _resolve_user() + token refresh
Permission-based access control require_permission() + check_session_access()
Auto-generate tool docs ToolManualTool (manuals/ → auto-generate fallback)
Add new capability without code CreateMcpServerTool + MCP proxy tools
Monitor external services McpStatusTool + McpManager.get_all_tools()
Run isolated Python code CodeExecTool with sandbox
Transfer files to/from remote SshExecTool with connection pooling
Process images for LLM ImageViewTool preprocessing pipeline
Validate planning assumptions ReflectTool (Critic/Pragmatist/Detailer)
Control planning depth Planning flags: planning_phase1/2/3_enabled, planning_mandatory
Prevent model drift Goal anchoring + iteration budget injection
Stop long-running generation Cooperative stop via current_stop_event
Handle model prefill hangs Streaming guard wrapper
Handle model streaming stalls Chunk timeout in streaming guard
Abort stuck subagents Subagent thinking stall detector
Cache expensive prompts System prompt caching in ContextBuilder
Parallelize independent LLM calls asyncio.gather pattern (used in context injection, reflect tool)
Handle JSON from unreliable LLM AIHelper.ask_json() + bracket-matching extractor
Track token usage AIHelperTokensUsed event emission
Replay events on reconnect WebSocket replay mechanism
Keep connection alive WebSocket heartbeat
Prevent concurrent runs Concurrent run guard
Handle mobile auth Mobile auth bridge with Chrome Intent
Persist admin toggles profile_overrides table
Auto-apply schema migrations DDL builder + boot-time retries
Backfill missing data backfill_embeddings.py pattern
Clean up old session files Startup file cleanup loop

Generated 2026-05-16. To update after adding a new mechanic: add a row to the appropriate section and update the cross-reference index if relevant.