| 2026-04-20 |
Fix clipboard copy on HTTP — fallback to execCommand
...
navigator.clipboard is only available in secure contexts (HTTPS/localhost).
Added textarea+execCommand fallback for plain HTTP deployments.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 20 Apr
|

Planning debug panel, todo auto-populate, scratchpad/persona improvements
...
- Planning debug panel: new Planning tab in debug/index.html shows raw
phase 1/2 outputs and token counts per planning run, stored in
session.planning_logs (new column in both SQLite and PostgreSQL)
- New GET /sessions/{id}/planning API endpoint
- PlanningDebugData internal event wires _run_planning() output into
session storage; never forwarded to WebSocket clients
- Phase 3 (plan critic) disabled — to be reworked with reflect integration
- Todo tool: auto-populated from plan steps after phase 2; model only
needs to call update/view, not set
- Scratchpad: clarified description and persona instructions; removed
context_transfer from user-facing docs (internal mechanism only)
- web_search: switched to ddgs package, SearXNG as primary backend,
DDG html-only fallback; added find_up action to filesystem tool
- Persona: added SCRATCHPAD and TODO sections with clear usage rules;
added NAVI.md project context instructions
- chat.js: fixed subagent planning event fallthrough into parent UI;
statusLabel cleared on first stream delta
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 20 Apr
|
| 2026-04-17 |
Strip spurious separator rows from GFM tables in markdown renderer
...
Model often emits | --- | --- | --- | rows as visual dividers between
table body rows. fixTables() now tracks whether the header separator has
been seen; any subsequent all-separator pipe row is dropped rather than
passed through to marked.js where it renders as a data row with --- content.
Existing fixes (missing separator injection, mixed row repair) are preserved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|

Route subagent planning events into spawn_agent card in the UI
...
Previously PlanningStatus/PlanReady had no is_subagent flag, so subagent
planning spinners and plan cards rendered as top-level Navi planning UI.
Backend:
- Add is_subagent field to PlanningStatus and PlanReady events
- _run_planning accepts is_subagent param, passes it through all yields
- run_ephemeral calls _run_planning with is_subagent=True
- websocket.py forwards is_subagent in planning_status and plan_ready messages
Frontend (chat.js):
- onPlanningStatus: if is_subagent, set planningLabel on the last spawn_agent
card instead of msg.statusLabel
- onPlanReady: if is_subagent, push plan into spawn card steps and clear
planningLabel; otherwise behave as before
Frontend (ToolCard.vue):
- Render subagent-planning-indicator (spinner + label) when planningLabel set
- Render plan cards inside subagent steps using the same plan-card pattern
Also includes leftover session changes: spawn_agent default 40 in description
and manual, updated manual content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Fix subagent planning isolation and raise default max_iterations to 40
...
- run_ephemeral signature default: max_iterations=20 → 40 (consistent
with spawn_agent's explicit default)
- _run_planning accepts system_prompt_override; when called from
run_ephemeral, passes the subagent's isolated system prompt instead of
_build_system_prompt(profile) which includes the full orchestrator
persona and profiles block — subagents now plan with only their own
executor context
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Remove context_transfer from all user-facing prompts — internal mechanism only
...
context_transfer is the scratchpad section name used internally by spawn_agent
to auto-inject parent state. Navi doesn't control it and doesn't need to know
about it. Removed from: persona, secretary, server_admin, spawn_agent description,
manual. Internal code (spawn_agent.py) still reads the section transparently.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|

Fix core subagent misuse: enforce 1 plan step = 1 spawn_agent call
...
Root cause: nowhere was it stated that each AGENT step in the plan
maps to a separate spawn_agent call. Navi was bundling all AGENT steps
into a single call, dumping the full plan on one subagent.
spawn_agent description:
- Lead with: "Delegate EXACTLY ONE step of your plan"
- Explicit: "3 AGENT steps = 3 spawn_agent calls"
- Remove "multi-step sub-task" wording that invited bundling
- briefing: clarify as static context only (credentials, paths, instructions)
Dynamic findings from prior steps → context_transfer, not briefing
Planning Phase 2 prompt:
- Add AGENT scoping rules: each step = one focused unit, not "do everything"
- Add good/bad examples of AGENT step granularity
- Show multiple AGENT steps in the format example
Secretary & server_admin system prompts:
- Add explicit 1:1 rule with counter-example
- Show correct multi-agent execution pattern with code example
- Clarify briefing vs context_transfer boundary everywhere
Persona:
- "ONE PLAN STEP = ONE spawn_agent CALL" as first sentence in SUB-AGENTS
- Field descriptions tightened: briefing = static, context_transfer = dynamic
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Fix subagent instruction conflicts across persona and profiles
...
Persona:
- Fix [STATUS: completed|limit_reached] reference (format was removed)
- Clarify three fields: task / briefing / system_prompt with distinct roles
- Clarify context_transfer vs briefing: transfer = working state, briefing = credentials
Secretary system_prompt:
- Replace vague "write all context to context_transfer" with explicit field breakdown
- task / briefing / system_prompt each described with their purpose
- context_transfer correctly limited to intermediate findings, not credentials
Server admin system_prompt:
- Same fix: explicit field breakdown for spawn_agent
- Remove dangling "see persona" reference for briefing ending
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Subagent system prompt rework: separate from parent, briefing as system context
...
run_ephemeral:
- Add briefing param (passed from spawn_agent, injected into system prompt)
- Subagent system prompt is now completely separate from parent's system_prompt:
1. profile.subagent_system_prompt (executor persona)
2. custom_system_prompt (role specialisation for this task)
3. briefing (task context as system-level instruction)
Fallback to profile.system_prompt only if subagent_system_prompt is not defined
spawn_agent:
- task → user message only (the goal)
- briefing → system prompt (credentials, context, instructions)
- system_prompt → role specialisation injected alongside briefing
- Removed old user-message composition (## Context / ## Task split)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Fix spawn_agent: restore briefing, fix status leakage, enable subagent planning
...
spawn_agent:
- Restore briefing param (task = goal, briefing = context — good separation)
- Add system_prompt as third param for role specialisation per task
- Remove [STATUS: ...] prefix that was leaking into Navi's responses and
causing hallucination — replaced with natural-language headers that are
less likely to be regurgitated verbatim
- completed → neutral header; limit_reached → explicit warning about incompleteness
Profiles:
- subagent_planning_enabled: false → true in all three profiles
(planning is on by default, disable per-profile if needed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Strengthen orchestration mandate: spawn first, inline last
...
secretary/server_admin system prompts:
- Explicit spawning rule: MUST spawn for any sub-task requiring 3+ tool calls
- Additional mandatory triggers listed (research, file processing, remote ops, large output)
- "If in doubt — spawn" as explicit fallback
- AGENT steps: "MANDATORY, never execute inline — defeats the orchestrator model"
- context_transfer pattern: write to scratchpad before spawning, injected automatically
persona.txt:
- Updated SUB-AGENT BRIEFING section: renamed to SUB-AGENTS
- Reflects new context_transfer automatic injection (no longer needs to be in task)
- Added: check [STATUS: ...] in result before deciding next action
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Fix NameError in _run_planning: session.context → context after refactor
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|

Improve subagent system: isolated tools, custom prompts, context transfer, timeout
...
AgentProfile:
- New fields: subagent_tools, subagent_planning_enabled, subagent_system_prompt
- loader.py: loads subagent_tools/subagent_planning_enabled from config.json,
reads optional subagent_system_prompt.txt per profile
Profiles:
- Each profile now has a dedicated subagent_tools list (focused subset, no admin tools)
- subagent_planning_enabled: false (configurable per profile)
- New subagent_system_prompt.txt per profile with executor-focused instructions
run_ephemeral:
- Uses profile.subagent_tools instead of enabled_tools
- Builds subagent context without persona or profiles block (focused executor)
- Injects subagent_system_prompt after profile.system_prompt
- Accepts context_transfer: priming exchange injected before task message
- Wall-clock timeout (default 5 min) checked per iteration
- Returns (result_text, completed: bool) instead of bare string
- Optionally runs planning phase if profile.subagent_planning_enabled
spawn_agent:
- Removed briefing param; task is now fully self-contained
- Added system_prompt param: custom injected prompt for this specific task
- Auto-reads parent scratchpad context_transfer section via get_section()
- Result prefixed with [STATUS: completed|limit_reached]
- Timeout 300s
scratchpad:
- Added get_section(session_id, section) helper for cross-session reads
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|

Planning phases, context compression, and tool improvements
...
Agent:
- Planning now a 3-phase async generator: Analysis → Execution plan → AIHelper critic
- Yield PlanningStatus events before each phase (UI progress labels)
- Phase 1 runs with think=True for deeper analysis
- Phase 2 includes available tool list so executor assignments are accurate
- Phase 3: independent critic pass validates and corrects TOOL: names against real tool list
- Planning converted from list return to async generator (fixes token accounting)
Backend:
- Context compression threshold: 80% → 70% to trigger earlier
- Compressor summary prompt: structured sections (goal, work state, key facts, outputs, errors)
- Terminal output capped at 5000 chars to prevent context flooding
- Web search: region=wt-wt for DDG, country=ALL for Brave, language=all for SearxNG
- Scratchpad: mandate writing a 'goal' section at start of multi-step tasks
- secretary max_iterations: 40→25, temperature: 0.7→0.5
- server_admin max_iterations: 40→20
Webclient:
- ThinkingCard strips <thought> XML tags leaked by Ollama
- planning_status WS event wired to chat.onPlanningStatus()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Webclient UI improvements + backend fixes
...
Webclient:
- Draft persistence across page refreshes (localStorage, reactive watch)
- Image lightbox modal using UI kit classes on thumbnail click
- Copy button on user and assistant messages
- Selection reply toolbar: select assistant text → quote inserted into input
- User message rendering: proper HTML escaping, styled blockquote for > replies
- Markdown table fix: preprocessor to inject missing separator rows
- Planning status labels (rebuild dist)
Backend:
- Developer profile: enable subagent delegation, increase max_iterations to 35
- share_file: updated description + manual with absolute path requirement and URL sharing
- persona.txt: instructions for quote replies and GFM table format
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Audit and trim system prompts (~470 tokens saved)
...
persona.txt:
- Shortened personality paragraph (~30% cuts, no content loss)
- Removed duplicate list_tools instruction
- Removed hardcoded 'developer' profile rule (handled by dynamic profiles block)
- Condensed EXECUTION MODES fundamental blockers to one sentence
- Moved sub-agent briefing boilerplate here (single source of truth)
- Trimmed REFLECTION section (tool description handles the how)
- Removed redundant RESPONSE HYGIENE explanation sentence
- Moved 'never assume file exists' into EXECUTION DISCIPLINE
- Removed DOCUMENTATION section
profiles (all three):
- Replaced ~100-token sub-agent briefing boilerplate with pointer to persona
- developer: removed data persistence code block (covered by _template.py)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
persona: add execution discipline — no false fix confirmations
...
Navi must call the tool before claiming a fix is done. Explicitly
forbids saying "I've fixed X" without a tool result in the same turn
confirming the change. Targets the common pattern of acknowledging
a problem in text without actually executing the correction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
reflect: force clarification when Detailer finds strategic ambiguity
...
Closing instruction now explicitly requires stopping to ask the user
if the Detailer identified ambiguities about core direction (what to
build, which approach, what the user actually wants). Prevents Navi
from using the Pragmatist's simplifications as an escape hatch when
the real problem is underspecified requirements.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Add reflect tool: three parallel expert perspectives
...
ReflectTool runs Critic / Pragmatist / Detailer advisors concurrently
via asyncio.gather() + AIHelper.ask(). Each role has a distinct system
prompt designed to produce genuinely different analysis:
- Critic: challenges assumptions, surfaces risks and logical gaps
- Pragmatist: finds the simplest path, cuts unnecessary complexity
- Detailer: spots missing requirements, edge cases, ambiguities
Parameters: situation (required), assumptions (required list — the key
input that forces Navi to surface implicit beliefs), tried (optional).
Registered as a builtin with AIHelper injection. Added to all three
profiles. Persona updated with guidance on when to use it (complex or
ambiguous tasks before planning, or when stuck mid-execution).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Add Prompts and Tools tabs to debug page
...
Backend:
- GET /agents/prompts — returns full built system prompt for every
profile, broken into sections (persona / profile / profiles block)
with char/token counts; mirrors Agent._build_system_prompt() exactly
- GET /agents/tools — now includes parameters schema alongside name
and description
Debug page:
- Tab bar: Context / Prompts / Tools
- Prompts tab: profile sidebar + collapsible sections per prompt part
(persona, profile prompt, profiles block), togglable tools list
- Tools tab: searchable list of all tools with description and
parameter table (name, type, description, required marker)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Add standalone debug page at /debug
...
Replaces the old_webclient/debug.html with a proper self-contained
tool at debug/index.html. New features over the old page:
- Sidebar session list with profile, message count, pin indicator
- Auto-refresh toggle (3s interval)
- Refresh button
- Renders thinking blocks, is_plan and is_summary tags
- Shows tool call name on tool result messages
- Clickable image thumbnails (open full-size)
- All new fields from the current LLM context API
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
| 2026-04-16 |
Handle heartbeat and session_sync on WS reconnect
...
- Ignore heartbeat events (server keep-alive pings)
- On session_sync after a reconnect: call reloadSession() to fetch
the latest saved history so the user sees the response even if
the agent finished while the client was disconnected
- Add chat.reloadSession(): force-reloads session from API bypassing
the same-id guard, also restores context token metrics
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Fix WS disconnect and missed stream on reconnect
...
Two related problems:
- During long AIHelper calls (non-streaming LLM), no data flows to the
WebSocket and browsers drop the connection after ~30-60s of inactivity.
Fixed with a 20s heartbeat: _stream_to_client now uses asyncio.wait_for
and sends {"type":"heartbeat"} on timeout to keep the connection alive.
- After reconnect, if the agent finished while the client was offline,
_runs no longer holds the session and no stream_start is sent. Client
would reconnect silently with no response shown. Fixed by sending
{"type":"session_sync"} on every new WS connection (after reattach
completes or immediately when no run is active) so the client knows
to reload session history.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Count AIHelper tokens in session metrics
...
Adds prompt/completion token fields to LLMResponse, populated by
OllamaBackend.complete(). AIHelper emits AIHelperTokensUsed into the
current event sink after each LLM call; run_stream drains it into
_subagent_tokens so AIHelper usage is reflected in the turn token delta.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Improve filesystem tool description: prioritize AI actions with examples
...
- Description now opens with explicit ALWAYS PREFER rule for query/smart_edit
- Each AI action has concrete examples (function lookup, renaming, config search)
- Standard actions demoted to 'use only when AI not applicable'
- question/instruction parameters include examples so the model understands
the full range of applicable cases
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|

Add AIHelper + filesystem query/smart_edit AI actions
...
AIHelper (navi/core/ai_helper.py):
- Reusable LLM utility for AI-enhanced tools: ask() and ask_json()
- Reads current_model ContextVar (set per-turn) so tools always use
the session's active model without extra wiring
- Robust JSON extraction: strips markdown fences, bracket-matching fallback
current_model ContextVar (navi/tools/base.py):
- New ContextVar set by run_stream() and run_ephemeral() after profile
is resolved; AIHelper reads it to pick the right model automatically
filesystem query action:
- Natural language question about any file, chunked at ~20k tokens of
content (~80k chars) with 30-line overlap between chunks
- Single-chunk: one LLM call; multi-chunk: partial answers accumulated
then synthesized in a final call
filesystem smart_edit action:
- Natural language edit instruction on files up to ~200k chars
- LLM outputs JSON patch ops: replace / delete / insert (1-based lines)
- Ops validated then applied bottom-up to preserve line numbers
- Returns unified diff of changes; preserves trailing newline
registry: AIHelper created once, OllamaBackend reused (no double init),
FilesystemTool receives ai_helper at construction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Make profile switching autonomous: switch immediately, inform after
...
Previously Navi asked for permission before switching profiles.
Updated both the injected profiles block in the system prompt and the
switch_profile tool description to explicitly say: switch on your own
judgment, do not ask, then inform the user which profile is active and why.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Add profile discoverability: list_profiles tool + system prompt injection
...
- AgentProfile: new short_description (1-line) and full_description (dict
with specialization / when_to_use / key_tools) fields
- All 3 profile configs: structured descriptions added; list_profiles added
to enabled_tools
- _build_system_prompt: now accepts full AgentProfile; injects compact
"Available profiles" block into every system prompt so Navi always knows
what other profiles exist and when to switch — dynamically, no hardcoding
- ListProfilesTool: new built-in; returns structured per-profile details
(specialization, when_to_use, key_tools); accepts optional profile_id
for single-profile lookup
- registry: register list_profiles_tool after profiles registry is built
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Fix UnicodeEncodeError for Cyrillic in email headers
...
_enc_header() checks if a value is ASCII-safe; if not, wraps it in
email.header.Header with utf-8 charset, producing RFC 2047 encoding
(=?utf-8?b?...?=). Applied to Subject and To in _build_mime — covers
both send and reply with Cyrillic subjects or display names.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Fix gmail auth: read credentials from settings, not os.environ
...
pydantic-settings loads .env only into the Settings object — it does not
populate os.environ. Added gmail_address and gmail_app_password fields to
Settings; gmail tool now reads from settings instead of os.environ.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|