| 2026-07-13 |

tui: copy chat to system clipboard via reading mode + selection fixes
...
Two ways to copy chat content out of the TUI now work:
1. In-app selection (Ctrl+C, OSC 52): _ChatItemView.render() now builds a
selection-aware Content from the rich renderable instead of letting Static
wrap a Panel into a non-selection-aware RichVisual — so the magenta
drag-select highlight actually renders and get_selection returns clean,
chrome-free text. rich Segment styles are converted to Textual Style
(Style.from_rich_style) so the selection_style merge doesn't crash, and
None segment styles are guarded. get_content_height is overridden to
compute auto-height straight from the rich renderable; without it the
width-keyed Content churned new Visual objects per width change and spread
the layout-settling cascade across refreshes, leaving a deferred scroll_end
at an intermediate max_scroll_y (chat no longer stuck to bottom). Theme
defines screen-selection-background/foreground so the highlight is visible.
2. Reading mode (Ctrl+R) for terminals without OSC 52 (e.g. GNOME Console,
TERM_PROGRAM=kgx, which silently ignores OSC 52 so Ctrl+C never reaches the
OS clipboard). Toggling the app's reading-mode class hides the chrome around
the chat (right status/todo column, input prompt, status bar, chat outer
border) and re-renders every message without its Panel borders via the
registry's new render_plain — so Shift+drag + Ctrl+Shift+C copies just the
conversation text to the system clipboard. ContentRenderer.render_plain
defaults to unwrapping Panel/Padding(Panel) to its body; assistant messages
and plan_ready override it to raw Text(content) so rich Markdown doesn't
re-wrap fenced code blocks in their own bordered Panels. ChatPanel tracks
reading mode and re-renders visible widgets in place (scroll preserved);
new streamed items pick up the mode on mount.
Help (/help) now lists keys and documents both copy paths.
Tests: render_plain parametrized across all item types, message renderer
plain tests, chat panel reading-mode toggle (borders off/on, scroll kept,
new items borderless), tui_app reading-mode chrome hide, plus the existing
selection suite. Full suite green (922 passed, 1 skipped).
Eugene Sukhodolskiy
committed
14 hours ago
|
tui: make chat content selectable/copyable without bubble chrome
...
Chat items render rich Panels (rounded borders + Navi/You titles), but the
base Widget.get_selection only extracts text from widgets whose render is
Text/Content -- Panels return None, so a drag-select over a message or tool
output copied nothing (the highlight showed the borders, but Ctrl+C yielded
no message content).
Override _ChatItemView.get_selection: re-render the item's renderable via
the app console at the widget width (line layout identical to the screen),
strip the outer panel border lines and the │ / │ gutters, and remap the
mouse offsets onto the clean content so a partial-line selection lands on
the right characters. Plain renderables (status, turn_meta, filesystem tool
output) have no chrome and map 1:1. Ctrl+C (Screen.copy_text) then copies
the clean text via OSC 52.
Eugene Sukhodolskiy
committed
16 hours ago
|
tui: restore tool args/metadata, assistant-then-tool order, turn_meta on resume
...
ChatModel.load_history rebuilds the resumed session so the chat renders the
same way as a live turn:
- Recover tool-call args via tool_call_id (the persisted tool message stores
only the result, not the call args) and forward the stored metadata. Without
this the filesystem renderer saw args={} -> action=None and fell back to a
plain, un-highlighted result -- the resume "no syntax highlighting" symptom.
- Emit assistant_message BEFORE tool_started when an assistant message has both
text and tool_calls, matching the live stream where stream_delta precedes
tool_started; previously the answer was stranded under its own tool cards.
- Append a turn_meta item when the persisted assistant message carries
elapsed_seconds, reproducing the single duration line stream_end appends.
is_subagent for resumed tool calls is intentionally deferred (needs storage).
Eugene Sukhodolskiy
committed
16 hours ago
|
tui: let the user scroll up while the agent streams + keyboard scroll bindings
...
ChatPanel._sync called scroll_end on every WS event (every stream_delta),
yanking the view back to the bottom on each token — impossible to scroll up
and read earlier messages during a response. Stick-to-bottom: capture
is_vertical_scroll_end before any DOM change and only scroll_end when the
user was already at the bottom; auto-follow resumes when they scroll back.
Add app-level keyboard bindings so the chat scrolls without leaving the
input box: Ctrl+Shift+Up/Down (one line), Ctrl+End (jump to bottom). These
keys are not claimed by TextArea (it uses shift+up/down for select and
ctrl+e/end for line end), so they bubble from the input to the app.
Eugene Sukhodolskiy
committed
16 hours ago
|
compressor: target hysteresis — shrink to 65% after compression, not just below the trigger
...
Compression triggered at 90% but left the context just under the trigger, so a
fixed keep_recent (navi_code: 12 turns ≈ 104 messages) re-triggered a couple
of messages later — the context yo-yoed at the trigger line instead of gaining
headroom. Add context_compression_target (0.65): in turn-based (preturn) mode
compress_context shrinks keep_recent until the verbatim kept region fits 65% of
the window, folding the extra turns into the same single summary LLM call; a
safety net in compress_session token-budget-truncates if the kept region alone
still exceeds the target (midturn kept a huge in-flight turn, or the
keep_recent floor can't fit). Trigger 90% → target 65% leaves real headroom.
Eugene Sukhodolskiy
committed
16 hours ago
|
filesystem: strip trailing newline in _number_diff so diff lines aren't blank-separated
...
_unified_diff (used by edit_lines / smart_edit) feeds difflib with
"line + \n" so difflib does not emit a "\ No newline at end of file" marker.
With lineterm="" difflib keeps that trailing "\n" on content lines, so the
final "\n".join produced "\n\n" between every diff line — a blank line
between each, bloating the model-facing output and rendering with double
spacing in both clients. Strip the trailing "\n" in _number_diff before
processing; no-op for the _diff action, whose lines come from splitlines()
without trailing newlines.
Eugene Sukhodolskiy
committed
16 hours ago
|
renderers: colour diff line numbers + read line numbers, keep content neutral
...
Standard for diff and read output: the line number (and the +/- marker for
diffs) is the coloured anchor; the content itself reads plainly.
diff: "{num} {marker} {content}" with num+marker in the marker colour
(green/red), content neutral. Fixed the number-column regex to "^( +)(\d+)|"
so files with more than 9 lines (width > 1) still match — the old
single-space pattern silently fell back to whole-line colouring.
read: "{num}: {content}" with the number in the accent colour, content
neutral (was dim number).
Applied to both clients: the TUI diff/filesystem renderers and the webclient
ToolCard (renderDiff / renderRead). The model-facing text from the server is
unchanged — this is display-only.
Eugene Sukhodolskiy
committed
16 hours ago
|
tui: render markdown at the panel's available width, not the terminal width
...
Long assistant messages vanished past the chat panel's right edge instead
of wrapping: ThemedMarkdownRenderable built its rich Console at
console.width, which is the physical terminal width (e.g. 80), but the
markdown lives in a narrower Panel. options.max_width holds the real
available columns (panel inner width minus borders/padding); rich wrapped
to the terminal width while the visible area was narrower, so the right
side of every long line was cut off. Use options.max_width, falling back to
console.width only when it is unset.
Eugene Sukhodolskiy
committed
16 hours ago
|
tui: sort milestone groups by status rank so finished ones sink
...
Todo widget already sorted steps within a milestone by status, but the
milestone groups themselves stayed in plan order — a done milestone sat
mid-list while its steps were pushed down. Group milestones by their
worst step status (in_progress < pending < failed/skipped/done) with a
stable sort that preserves plan order within equal rank; the unnamed
(legacy, no-milestone) group participates in the same ranking.
Eugene Sukhodolskiy
committed
16 hours ago
|

Автономность мелких моделей: OUTPUT DISCIPLINE, milestone-todo, перехват финала хода
...
Два последовательных захода над одной проблемой — мелкие модели (12–30B) в navi_code
теряют автономность на трудных шагах: «остановился поболтать» вместо действия и
слишком большое расстояние между пунктами плана.
Заход 1 (З1–З3):
- З1: OUTPUT DISCIPLINE в системном промпте navi_code — «act, don't announce»,
без few-shot антипримеров. Контракт хода: ответ без tool_calls = конец хода, поэтому
объявление намерения текстом убивает автономность; правила заставляют вызывать
инструмент в том же ходе.
- З2: плоский todo + метка группы milestone + декомпозиция. _parse_plan_steps
возвращает list[tuple[milestone, text]]; milestone — метка группировки (не сущность,
без статуса), «done» вычисляется при рендеринге; подшаги = больше плоских шагов
(без вложенности). TUI side-panel группирует по milestone (плоский фолбэк при пустом
milestone). Plan depth: max 15→20 + правило декомпозиции.
- З3: adaptive re-plan «длинный шаг» — nudge «разбей шаг» при in_progress ≥ порога
итераций без смены todo (порог 4, раньше общего anti-stall warning на 8).
Заход 2 (шаги 1–3, после cloud-теста 31b vs 12b):
Корневая структурная причина: весь спасательный механизм (anti-stall warning с явным
предложением reflect, adaptive re-plan) живёт только внутри tool-цикла — nudge
инжектируется в pre_turn *следующей* итерации, которой при «остановился поболтать»
нет (ход закрылся по return до post_turn). 31b застревала через «продолжаю
tool-итерации» → дожала до warning → спаслась; 12b — через «замолчала текстом» → мимо
всех nudge.
- Шаг 1: перехват финала хода. Если модель выдала bare-text, но в todo есть открытые
шаги (pending/in_progress) и лимит не исчерпан — НЕ эмитить StreamEnd, а сохранить
ассистентский текст в session.context, поставить системный nudge и continue
(без StreamEnd, без workers — консистентно с multi-iteration tool-турами). Счётчик
final_interceptions на AgentTurnContext, лимит final_intercept_limit (default 2),
эскалация жёсткости (мягкий → «second stop»). has_open_steps в todo.py: пустой
todo → False (защита casual-сообщений), failed/skipped терминальны. Профильные
флаги final_intercept_enabled/limit в base.py + loader + admin.
- Шаг 2: жёсткий reflect-триггер в промпте — «~3 tool attempts on the same step
without progress → call reflect IN THIS TURN (tool call, not reasoning aloud)».
- Шаг 3: открыть replan для застревания — «call replan when reflect showed the whole
approach is dead (not one failed step, but the approach itself)».
Тесты: 874 passed, 1 skipped. Новые — has_open_steps (5), final intercept (5),
milestone-группировка, adaptive long-step nudge, парсер шагов с milestone-маркером.
cloud: navi_code model → gemma4:31b-cloud для тестирования догадки (31b признала
застревание, 12b — нет); .env cloud-host уже gitignored.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
18 hours ago
|
| 2026-07-12 |
config: raise context compression threshold 0.70 -> 0.90
...
Midturn compression now splits the in-flight turn correctly, so it's safe to
let the context grow closer to the limit before compressing. 0.90 gives the
model more raw context per turn and trips the compressor less often.
Worker test context_tokens bumped 50_000 -> 60_000 (76% -> 91.5%) to stay
above the new threshold; other compression tests pass the threshold as an
explicit argument and are unaffected.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

filesystem: show real file line numbers in unified diffs
...
_number_diff parses @@ hunk headers and prefixes each content line with its
real file line number: removed/context lines use the old (from) number,
added lines use the new (to) number, in `{marker} {num}│ {content}` form
(marker first so existing startswith highlighting stays valid; column
right-aligned to the largest line number). Hunk/file headers and the
`\ No newline` marker are left unchanged.
Applied in _unified_diff (covers edit / edit_lines / smart_edit) and the
`diff` action — a single server-side change, so both the TUI and the web
client receive numbered diffs in the tool result text.
TUI highlight_unified_diff renders the `{marker} {num}│` column dim and the
content in the marker color, so the number reads as meta, not as part of the
added/removed text. Lines without the prefix (standalone `diff` event, older
callers) are still colored whole.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

compressor: split in-flight turn in midturn mode + flush incrementally
...
Two related fixes for long autonomous turns in planning profiles (navi_code):
A1 — partition_messages turn-based branch held the in-flight (current) turn
verbatim when turns > keep_recent, so midturn compression was shallow
(e.g. 150 -> 141 messages). Now, when keep_recent_messages is set, the
in-flight turn is split like partition_current_turn_messages: head (user
request) + tail (recent tool steps) kept, middle summarized. The adaptive
swap is disabled in midturn mode (it could move the in-flight turn into
old_turns and summarize the current request whole). First branch
(len(turns) <= keep_recent) is untouched, so locked-in midturn tests hold.
B1 — agent.run_stream had no try/finally around the for-loop, so an
asyncio.CancelledError (server restart/shutdown) unwound the stack with no
flush: all in-memory turn messages (sequence_number < 0) were lost, only the
user message survived. Add incremental save() after planning, after the
assistant tool-call decision, and after each tool result, so a crash loses at
most the single in-flight tool call, not the whole turn. B2 (try/except
safety-net) was dropped: B1 leaves no window where an append is unsaved.
Tests: midturn split with many turns (partition + compress_session), and
crash/cancel persistence via a snapshot session store that mirrors the DB
boundary.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

permissions: remove broken client-side gate; add backend design doc
...
The terminal-TUI permission gate was a race: _execute_tools_with_sink
emits ToolStarted and starts the tool on the backend immediately, so by
the time the client dialog appeared the destructive action had already
run -- 'deny' could only stop the session, not un-execute the tool. It
also existed only in the terminal TUI (webclient/android had nothing),
and the system-prompt 'Strict Confirmation' nudge was an unreliable
duplicate.
Remove the broken machinery for a clean slate and plan the real
replacement from zero:
- delete clients/terminal/tui/permissions.py, screens/permission_dialog.py
and their tests
- strip tui_app.py (engine, _deny_tool, _show_permission_dialog,
_confirm_shell_command, _stop_session_worker, on_permission_request,
tool_started gate) and the PermissionRequest TUI event; !cmd now runs
directly (user-typed, no agent gate)
- drop the 'Strict Confirmation' prompt rule from navi_code/developer/
tool_developer
- add docs/permissions.md: authoritative backend gate design (engine +
registry + event + endpoint + agent gate + postgres policy + global
rules config, sub-agents gated) -- design only, not yet implemented
- update docs/index.md, navi_code_cli.md, profiles.md, testing.md
Until Phase 1 lands there is no destructive-action confirmation -- a
conscious period without the false security of the old race-gate.
Eugene Sukhodolskiy
committed
1 day ago
|
replan: integrated mid-task re-planning tool
...
Add a replan tool that re-runs the planner over the live session context
+ todo + scratchpad when the plan's structure is stale due to discoveries
(NOT failed steps -- that stays [Adaptive re-plan]). Integrated approach:
PlanningEngine.run gains is_replan/replan_context (suppresses DIRECT
shortcut and observe-skip, frames Phase 1 as a revision); ReplanRunner
packs reason/goal/todo/findings/errors and captures PlanReady; the tool
is exposed to navi_code/developer/tool_developer via a
current_replan_runner ContextVar set per-iteration in run_stream (correct
after switch_profile). New plan replaces the todo. Lazy events import
breaks the navi.tools -> navi.core -> navi.tools cycle.
Eugene Sukhodolskiy
committed
1 day ago
|

profiles: port context-org/planning instructions to developer & tool_developer
...
Port the context-organization and planning-machinery framing accumulated
in navi_code to the developer and tool_developer profiles, adapted per
profile:
- Working state & memory (todo/scratchpad/context_transfer/schedule_recall/
reflect/memory) replaces the stale "Context drift recovery" section.
- System signals subsection names the runtime-injected messages each profile
actually receives: [Goal anchor], [Anti-stall warning], [Adaptive re-plan]
(adaptive_replan is on for both), [Iteration N/M]. [Scope boundary] is
omitted — scope_boundary_enabled is off on these profiles.
- Reading & searching, Editing policy (tool_developer), Safety Rules, Git
discipline, and Project environments (isolated venv) added.
- developer: Workflow rewritten planner-aware with an observe carve-out
(observe_skips_plan now on); Project knowledge replaced by docs-first
Documentation; sub-agent briefing gains context_transfer + restricted-toolset
bullets.
- tool_developer: keeps its MCP-specific 10-step workflow and prerequisites;
sub-agent briefing gains context_transfer + restricted-toolset bullets
(sub-agent cannot reload_tools/test_mcp_tool/mcp_status — run those inline).
- config: observe_skips_plan_enabled=true on both, so observe requests skip
phase3 (no plan/todo for read/explain/inspect) — enables the Workflow
observe carve-out and saves an LLM call on info requests.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
navi_code: prefer isolated project envs and bootstrap NAVI.md when absent
...
Add a "Project environments" section steering the agent toward the
project's existing isolated env (venv/uv/node_modules/target) — use it,
don't duplicate or bypass it — and only create a project-local one when
deps are needed and none exists; never install system-wide (system-wide
changes still require explicit confirmation). Also nudge the agent to
create NAVI.md when it's absent after real orientation work on a
non-trivial task, seeding the pointer structure so the next session
starts oriented.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
navi_code: enable planning phase 2 (structured review)
...
phase1 already emits REFLECT: yes|no, but with phase2 off the flag was a
dead-end. Enabling phase2 runs a Critic/Pragmatist/Detailer review pass
before phase3 whenever phase1 flags the task as complex (REFLECT: yes),
feeding "Plan Adjustments" into the execution plan. Skipped for simple
tasks and subagents (gated on `needs_reflect and not is_subagent`), so
the extra LLM call only lands on complex parent-agent work.
Resolves F8 machinery-gap G.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
navi_code: frame planning machinery in system prompt (F8)
...
Workflow "Plan" no longer duplicates the planner (phase1/3 already build a
structured plan and auto-populate todo); adds an observe/act carve-out so
observe requests don't get pushed to create a todo. New "System signals
you'll see" subsection names the runtime-injected messages ([Goal anchor],
[Scope boundary], [Anti-stall warning], [Iteration N/M]) so the model
recognises them as machinery and responds correctly — and corrects the
factual error that the goal anchor reads scratchpad `goal` (it reads the
original request + live todo). Closing paragraph warns that thinking isn't
re-injected and the plan's per-step executor assignments are lost to
compression, so conclusions/assignments should go in scratchpad.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

navi_code: give the sub-agent operational wisdom (editing/reading/todo)
...
By default (inherit_system_prompt=False) the sub-agent got only the 17-line
subagent_system_prompt — none of the parent's editing/reading/context
discipline. So a sub-agent with a clean context would still burn it: pulling
whole files into read, over-using smart_edit, not tracking steps. The clean
context is the sub-agent's main advantage — keep it clean.
Expand subagent_system_prompt.txt with a compact operational core:
- Editing: prefer edit/edit_lines (deterministic); smart_edit as last resort
(extra LLM call, reads the whole file) — the same policy the parent now has.
- Reading: info before read, offset/limit to the region, grep/find/query to
locate — don't read a file just to search it.
- Track steps with todo and record findings in scratchpad (durable within the
run; context can be compressed).
inherit_system_prompt stays False: the full parent prompt carries orchestration
and spawn_agent sections that are irrelevant to a sub-agent and references
tools it lacks. The sub-agent keeps its own focused, self-contained prompt.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

navi_code: brief sub-agent on its restricted toolset + context_transfer
...
The sub-agent briefing section told the model to "give the sub-agent
everything it needs" but never said which tools the sub-agent lacks or how
context actually reaches it — so briefings could ask the sub-agent to use
memory, spawn further agents, or switch profiles, all of which it can't.
- context_transfer: write the context the sub-agent needs (files, snippets,
how to verify) into the scratchpad `context_transfer` section before
spawning — it is injected automatically; the sub-agent does not inherit
short-term memory or conversation history.
- Restricted toolset: the sub-agent has todo/scratchpad/reflect/filesystem/
code_exec/terminal/list_tools but NOT memory/switch_profile/spawn_agent/
schedule_recall/manage_recall — brief it to use only what it has (e.g.
record findings in scratchpad, not memory).
The profile list is not duplicated — spawn_agent's own description carries it.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

recall: carry self-instruction (message) on the recall_update wire
...
The recall card could show call_type/trigger_at but not the self-instruction
(additional_context_message) — it was absent from RecallUpdate.to_wire, so
the user couldn't see what future-self was about to do at the scheduled or
fired moment. Extend the wire payload.
- events.RecallUpdate: add `message` field; to_wire emits "message".
- scheduler._publish_recall_update: accept and forward `message`.
- Publish sites carry message=recall.additional_context_message:
schedule_recall (scheduled) and orchestrator._finalize_recall
(rescheduled / fired / cancelled). manage_recall cancel/skip omit it
(no recall object handy; already visible in the prior scheduled card).
- TUI RecallRenderer: preview the message (first line + "(+N lines)",
capped at 80) on a `msg:` body line when present.
- Tests: RecallUpdate.to_wire carries message (defaults None); renderer
preview (single/multiline/truncate/empty) and scheduled-card renders it.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

navi-code TUI: render schedule_recall lifecycle (recall_update)
...
The scheduler/orchestrator already push RecallUpdate (wire type
"recall_update") for the schedule_recall lifecycle, but the TUI had no
mapping or renderer — every event fell to the unknown-event catch-all and
rendered as a raw dict dump. Wire it into a dedicated card.
- chat_model: add a "recall" ChatItem kind and a recall_update branch
(before the catch-all) that keeps the wire fields in meta.
- chat_panel _item_msg: reconstruct {"type": "recall_update", **meta}
for a recall item so the registry sees it.
- renderers/recall.py: new RecallRenderer — a compact, color-coded card
per action (⏰ scheduled/info, ▶ fired·resuming/accent, ✕ cancelled/error,
↻ skipped/warning, ↻ rescheduled/info) showing call_type and a trimmed
trigger_at. Registered before the generic renderers.
- tests: 10 tests covering accepts, each action's title/border color,
trigger formatting, empty body, chat_model mapping, and _item_msg
round-trip.
MVP only — the self-instruction (additional_context_message) is not on the
wire, so it remains visible in the schedule_recall tool-call card above;
extending RecallUpdate.to_wire to carry it is a follow-up.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

navi_code: leverage context-org/planning tools in system prompt
...
Wire the KV-backed context/planning tools into the profile so the agent
uses them instead of relying on lossy conversation memory under compression.
- Workflow Plan: create a todo for non-trivial tasks.
- Workflow Test & verify: record the verification in the todo `validation`
field when marking done (structural form of "never claim done without
verification").
- Replace "Context drift recovery" with "Working state & memory":
- todo: plan + verification tracking.
- scratchpad: durable working memory across compression (sections
goal/findings/errors/artifacts); read before final report.
- Sub-agent handoff: write context to the scratchpad `context_transfer`
section before spawn_agent — it is injected into the sub-agent
automatically (the sub-agent does not inherit short-term memory).
- schedule_recall: continue after the iteration limit, offload heavy
work headlessly, poll builds/logs, chain multi-phase work.
- reflect: selectively, before complex plans or when stuck (3 LLM calls).
- memory: global cross-project facts, not a scratchpad/docs substitute.
- Drift recovery folded into a closing paragraph aligned with the
goal_anchoring machinery.
TUI visualization for schedule_recall is a follow-up task.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

navi_code: fix review findings 1-5 in system prompt
...
- spawn_agent default profile: correct the false "omit profile_id to use
this developer profile" — omitting profile_id inherits navi_code (the
parent), not developer; set profile_id explicitly to pick another profile.
- Safety Rules: scope strict confirmation to destructive/irreversible
operations (rm, delete, wholesale write overwrite, drop table, force-push);
state explicitly that routine edit/edit_lines do not require confirmation.
- Workflow Understand: soften the hard "start with docs/index.md" to a soft
"read notes/docs first (see NAVI.md and Documentation sections below)" so
it no longer conflicts with the NAVI.md-first entry point.
- Documentation: add a branch for projects with no docs/ — propose creating
one (with user approval) or record in NAVI.md that docs are absent/not
needed.
- Execution environment: document terminal action="run" for one-off commands
(tests, git status, lint, py_compile); persistent terminals only for
long-running processes.
Findings 6 (subagent briefing toolset), 7 (subagent delegation wording),
8 (planning/context-org tools) deferred for later work.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
navi_code: docs as living spec + NAVI.md hints file
...
Replace the Project knowledge section with two clearer sections:
- Documentation: docs/ is the project's living specification, not just
human reference — keep it current with code, and for non-trivial changes
align docs to the intended end state before implementing (docs-first).
- NAVI.md: a lightweight, pointer-shaped hints file at project root (not a
source of truth) that tells the agent where to look; capped at ~150 lines
with a defined structure (Project / Commands / Where to start / Docs index
/ Gotchas / Open decisions), kept distinct from docs/ (spec) and memory
(global cross-project facts).
Instruction-only: the agent reads NAVI.md via filesystem; no auto-inject.
Applies to navi_code only.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
filesystem edit: render red/green diff in TUI without changing model context
...
edit is now the primary editing method, yet its output was a dry one-line
status ("Edited …: replaced X B with Y B") while edit_lines/smart_edit showed a
highlighted unified diff. Carry the unified diff in ToolResult.metadata["diff"]
(kept out of the model-facing output, so the agent's context is unchanged) and
render it in the TUI: dim summary line plus highlighted diff (green +, red -,
dim @@). Falls back to plain text when no diff metadata is present.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
filesystem: make edit/edit_lines the default, smart_edit a last-resort fallback
...
Agent overused smart_edit (whole-file LLM call, weak context). Rewrite the
FilesystemTool description decision tree so edit (exact text) is the default and
edit_lines (by line numbers) is the deterministic option; smart_edit is reserved
for genuinely semantic changes that cannot be expressed as exact text or line
numbers. Strengthen the old_not_unique hint to steer back to edit/edit_lines
before smart_edit. Add an "Editing policy" section to the navi_code and
developer profile prompts reinforcing the same priority.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
tui: move filesystem tool_started info into the card body
...
Previously the action and primary path were crammed into the title
("→ filesystem read src/main.py") and the body only held the extra args,
so for simple actions (info/delete/mkdir/exists) the card body was empty.
Title is now compact ("→ filesystem <action>"). The body always carries
the information: "path: <path>" (accent) leads, "destination: <dest>"
(accent) follows for move/copy/diff, then the per-action args (range/
content/old+new/operations/instruction/pattern/question …) as before.
The card is never empty.
Tests updated: title carries action only (path is in the body),
destination lands in the body for move/copy/diff, info shows path in body,
path value is styled accent. 42 filesystem-renderer tests total. Full
suite 827 passed, 1 skipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

tui: styled filesystem tool_started card — compact args, action in title
...
The generic ToolStartedRenderer dumped all of args as JSON, so filesystem
cards showed "→ filesystem" with no action in the title and the full
content/old/new text for write/edit/smart_edit flooding the card.
New FilesystemToolStartedRenderer (clients/terminal/tui/renderers/filesystem.py):
- Title carries the action and primary path: "→ filesystem read src/main.py";
move/copy/diff also append "→ <destination>".
- Body is a compact per-action summary instead of JSON:
- read: range (offset–limit) + numbered flag
- write/append: content preview (first line + "(+N lines)" hint, not full)
- edit: old + new previews
- edit_lines: operations count + op kinds (replace/delete/insert, first 5)
- smart_edit: instruction preview
- grep: pattern + glob + regex flag
- find/find_up: pattern
- query: question preview
- list: recursive flag
- info/delete/mkdir/exists: empty body (path is in the title)
- Body keys render dim, values in text.
- Sub-agent cards indented, matching ToolStartedRenderer.
Registered before the generic ToolStartedRenderer (first-match wins). The
filesystem tool, WS protocol, and events are untouched.
13 new tests cover accepts, title (action/path/destination), empty body for
info, and per-action body summaries (read/write/edit/edit_lines/grep/
smart_edit/query), content preview truncation, subagent indent, and body key
styling. 42 filesystem-renderer tests total. Full suite 827 passed, 1 skipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|