| 2026-10-08 |

profiles: tool_developer folds into developer
...
The profile was a duplicate on every axis we could measure. 22 of its 26
native tools were already developer's; the four it alone held —
reload_tools, create_mcp_server, test_mcp_tool, mcp_status — are 2.9 KB of
schema. Its model chain was the same seven models. Of its 14 KB prompt,
about 8 KB was copied verbatim from developer's (the whole `## Orchestration
model` block and everything from `## Editing policy` down), and most of the
remainder restated manuals/create_mcp_server.md, which already carried the
same ten-step workflow in more detail. It was not a specialisation, it was a
snapshot: `git log -S '"reload_tools"'` shows the tool lived in developer
until 61fa370 rewrote that profile around MCP and cut it off.
What kept it alive was a premise that no longer holds — that Navi's own
capabilities would be written as in-repo tools. They are MCP servers now,
and an MCP server is not a file in this repository with a life of its own:
it is an isolated process registered from mcp_servers.d/. So there is no
reason left for a profile whose only distinct feature is a toolset a general
developer profile can hold, and every reason to stop maintaining a second
prompt that drifts against the first.
- developer: + reload_tools, create_mcp_server, test_mcp_tool, mcp_status
(24 → 28 native). Its sub-agent gains tool_manual, which is what it
actually needed to reach the manual while writing a server — the previous
tool_developer sub-agent had it, developer's did not.
- server_admin: + reload_tools only (24 → 25). Adding a third-party MCP
server is something this profile does as often as developer does.
Deliberately not to its sub-agent: reconnecting the MCP manager is a
process-wide operation belonging to the main agent.
- The prompt and the manual took on what the deleted profile knew and
create_mcp_server.md did not: reload_tools before the first test_mcp_tool
(a freshly registered server is not connected, so the test fails and the
iteration is wasted), the smoke test read by exit code — 124 means timeout
killed a server still running, 0 means it exited on its own, usually a
main() without parentheses — absolute command/cwd, mcp_status as discovery
only, and the steps that stay inline instead of going to a sub-agent.
mcp_status and test_mcp_tool were built without an MCP manager, and their
fallback did `from navi.api.deps import _mcp_manager` — a name that does not
exist, so a live call raised ImportError rather than the intended "MCP
manager not available". The tools always passed a manager in tests, which is
why nothing caught it. Both now receive the manager at construction and fall
back to the live one lazily.
Sessions and profile_overrides are reassigned before the restart: agent.py
resolves the session's profile without a guard, so a deleted profile turns
every session that referenced it into an uncaught ProfileNotFound. Nothing
in the test suite pins the profile inventory, and profiles are read once at
import time — reload_tools does not re-read them — so this ships as a
restart, and the restart is also what makes it take effect.
Eugene Sukhodolskiy
committed
4 hours ago
|

tool_manual: a manual the agent cannot reach is not a manual
...
tool_manual asked the filesystem for the exact string the model sent, then
fell back to registry.get(). The executor already tolerated the ways models
mangle MCP names; the tool that documents them did not, so the agent calling
mcp__navi-3d__compile_scad got a schema dump while manuals/compile_scad.md sat
there unread. Resolving a name now happens in one place — resolve_tool moved
out of the executor into navi/core/tool_utils.py — so a name that works when
the tool is *called* also works when it is *asked about*. A miss suggests the
closest names instead of "not found", and a tool that exists but is not enabled
for this profile says exactly that: documenting it is still the useful answer,
but the agent must not go on to call it. params["tool_name"] was also a crash
waiting to happen — KeyError with the key omitted, AttributeError on null or a
number — and now anything that is not a usable string means "no name given",
which returns the index of manuals grouped by source.
The generated manual now renders the whole schema. An array of objects showed
as "(array, optional)" with its item shape invisible, so a model that could not
see the fields guessed them; objects, array items, oneOf/anyOf branches, enums
and defaults are all spelled out now, depth-capped. The header names the source
(native / mcp__<server>__) and says the text is a parameter contract, not a
curated manual — otherwise a thin schema reads as "this tool is simple".
Then the manuals themselves. A manual is filed under the tool's own name, and
five of the sixteen were not: write_tool.md and write_mcp_server.md documented
tools that do not exist anywhere (the tools are reload_tools and
create_mcp_server), model_3d.md documented compile_scad, render_3d.md documented
render_stl, and write_context_provider.md documented no tool at all — it is a
guide, and now lives in manuals/guides/. The prompts pointed at the same wrong
names (tool_developer's system prompt, persona_navi_code, docs/context_providers),
so fixing the files without the callers would have moved the breakage rather
than removed it. On HEAD the probe was blunt: tool_manual("mcp__navi-3d__compile_scad")
returned None and the agent got the schema; now it returns the manual.
Nothing was enforcing any of this, which is how it drifted. tests/unit/tools/
test_manual_drift.py reads the real repository tree: every manuals/*.md must be
named after a tool that exists (built-ins and tools/*.py by their name
assignments, MCP tools by @mcp.tool(name=…) in the server sources and by the
mcp_servers.d groups, whose file name is the server name), every manual must be
reachable by both its bare name and its full MCP spelling, a guide must never
shadow a tool's name, and every manuals/<x>.md or tool_manual("x") cited in a
doc or a prompt must resolve. The next rename fails the suite instead of
quietly wasting a manual.
Finally, manuals for the built-ins the agent uses most — ssh_exec, todo, memory,
plan, filesystem, notify, code_exec — written from the current schemas and the
code paths that produce the errors, so the gotchas are the real ones (todo's
`done` validation is enforced; memory's `list` returns categories, not facts;
filesystem's `delete` removes a tree with no prompt). reload_tools.md absorbs
the file format from the deleted write_tool.md, which is where a self-extension
recipe belongs now.
1556 passed, 1 skipped. ruff delta zero.
Eugene Sukhodolskiy
committed
5 hours ago
|
| 2026-10-07 |

reload: pick up the new code, and drop MCP tools that are gone
...
reload_tools reported success while three separate things kept it from
doing what it says.
The bytecode cache is keyed on (mtime in whole seconds, file size), so a
tool edited to the same length inside the same second as its previous
load re-ran the OLD code — the reload was real, the new version was not
live. The loader now compiles the source itself instead of consulting
__pycache__ (importlib.invalidate_caches() does not help here).
MCP registrations only ever grew: register_mcp_tools called
register_external, and unregister_external was used in one place, so a
server removed from the config or a tool a server stopped exposing
stayed in the registry and failed only when the model called it. Reload
now clears external tools and rebuilds them.
enabled.json naming a tool that failed to load (the gmail/html2text case)
was visible only as a log line. It is now part of the report.
The reload itself moves to navi/core/reload.py, one implementation shared
by the tool and the admin route, so the two cannot leave different
toolsets behind. list_tools.py also read enabled.json through its own
cwd-relative path, which made it disagree with the real toolset, and the
class-based loader rejected execute(self, params, ctx=None) — the shape
every built-in uses.
Eugene Sukhodolskiy
committed
1 day ago
|
switch_profile: deliver profile_switched, report the new toolset
...
The tool took its sink as `ctx.event_sink if ctx else current_event_sink.get()`,
but the agent loop builds tool_ctx with event_sink=None — the ContextVar is the
real channel — so the branch always picked None, the event was silently
dropped, and the profile badge in the header never moved. plan.py already had
the fall-through (`if ctx and ctx.event_sink else current_event_sink.get()`);
this is the same fix.
The result also said nothing about what the switch changed, so the model kept
calling tools the target profile does not have (reload_tools after leaving
tool_developer). It now names the gained and lost tools, and the timing claim
is corrected: the new prompt and tools are in force from the next step of the
same turn, not "from the next message".
Eugene Sukhodolskiy
committed
1 day ago
|
| 2026-10-06 |
synapse reactions W3: reaction runner, notify tool, gateway hookup
...
- navi/synapse/reactions.py: fire-and-forget reaction run — per-user
reactions_enabled gate, one-shot dispatcher meta-pass (visible profiles
only, hidden dispatcher, secretary fallback), special=True session
headed by the resolved profile, headless agent run via the orchestrator
run registry, finalise: app push per completion_notify +
low-level reaction.finished/failed event to Synapse
- navi/synapse/outbound.py: source-side emit (syn_* key from env,
silent when not configured)
- navi/tools/notify.py: notify tool — message + level (info/warning/
intervention), both legs per push_target, honest delivered/skipped result
- push/service.py: notify_custom without cooldown
- gateway: verified + non-duplicate delivery schedules the reaction
- profiles: notify added to native tools (7 profiles)
Eugene Sukhodolskiy
committed
2 days ago
|
synapse reactions W2: hidden dispatcher profile + synapse_instructions tool
Eugene Sukhodolskiy
committed
2 days ago
|
| 2026-09-26 |
agent parallelism: background tools, bg spawn_agent, parallel tool batches, message queue
...
- backgroundable tools (terminal/ssh_exec/peer/spawn_agent/code_exec) detach
via TaskManager with per-session/global/spawn caps, rate limit and TTL
- completion delivery both ways: task_update event (out-of-band) + pending
notes injected into the next turn; tasks tool (list/check/wait/cancel)
- parallel tool-call batches (profile-level gate, off by default) with
ToolStarted up-front, tagged event mux, call-order results, one save,
plus dangling tool_call repair on session load
- user message queue instead of busy error: message_queued frame,
back-to-back drain on the same socket, headless fallback on disconnect
- pin mcp<2 (v2 renames FastMCP with breaking API changes)
- docs: tasks.md (new), websocket/api/agent/config updates, tasks manual,
spawn_agent background param, persona contract section
Eugene Sukhodolskiy
committed
12 days ago
|
| 2026-09-10 |
swarm stage 2: peer-to-peer channel — /peer endpoints + peer tool
...
Server side (navi/api/routes/peer.py, port 8099):
- GET /peer/hello — open discovery ping (name, uuid prefix, version)
- GET /peer/status — PSK; identity, uptime, machine facts, hive view
- POST /peer/ask — PSK; one-shot agent run under PEER_ASK_PROFILE
(default server_admin) answers, one concurrent ask at a time
- loop guard: answering agent runs without the peer tool (deterministic
recursion cut) + own-uuid asks refused with 409
- verify_swarm_key in navi/swarm.py accepts .swarm-key.previous
(rotation window, constant-time)
Client side (navi/tools/peer.py):
- peer tool: list (hive book, stale cache fallback marked), status,
ask by swarm name; asks go direct peer-to-peer, hive never on the
message path
- audit events on both sides (peer.ask_sent/received/answered/failed)
peer tool added to server_admin, navi_code, developer profiles.
Eugene Sukhodolskiy
committed
28 days ago
|
| 2026-09-09 |

planning: replace the mandatory pre-turn gate with an agent-invoked plan tool
...
- Phase 2 (critique) retired; observe/MODE and the top-level DIRECT shortcut
removed (sub-agents keep DIRECT for trivial subtasks)
- replan merged into plan: `reason` (+ updated_goal) packs the re-plan
context, without a reason it is fresh planning
- both phases call the LLM with think=False — cloud reasoning models leak
their chain-of-thought into structured output on non-streaming calls —
and strip the gemma "thought<channel|>" content artifact
- Phase 1 conversation windowed to ~20k chars, newest-first with the
original task pinned (28.7k-token prompts came back as 1-token output)
- confirmation by COMPLEXITY: the tool result tells the agent to present
complex plans and wait; sub-agents keep the execute-now injection
- PlanningStatus/PlanReady reach the UI mid-turn via current_event_sink
(ctx.event_sink is None in the agent loop — events silently never
reached the WS before)
- agent gate, casual-message detector and adaptive re-plan nudges removed;
anti_stall keeps only stall detection
Eugene Sukhodolskiy
committed
29 days ago
|

security: critical batch 1 — RCE/XSS/CORS/webhook hardening
...
Backend:
- auth/deps: fix refresh-lock clock race (cleanup now monotonic like the cache)
- core/registry: add missing structlog logger (NameError on fallback path)
- config: GNAUTH_WEBHOOK_SECRET, NAVI_ALLOWED_ORIGINS (+list property)
- webhooks: HMAC-SHA256 signature verification (503 unconfigured in auth mode,
unsigned+warning in no-auth mode, 403 bad/stale signature, 400 bad JSON)
- main: CORS from NAVI_ALLOWED_ORIGINS in auth mode (fail-fast on empty),
eval router behind require_admin, /debug only registered in no-auth mode
- auth routes: mobile-done sid validation (32 hex) + CSP header + safe JS
escaping (reflected XSS); Secure cookie flag via helper (https base URL)
- websocket: anonymous WS rejected in auth mode (closes legacy-session RCE);
socket registered only after access checks; stop_session auth gate
- messages: REST agent start now takes session lock + busy flag (409 on
active run), contextvars reset in finally
Webclient:
- useMarkdown: DOMPurify.sanitize on all rendered markdown (stored XSS),
image-URL scheme whitelist, delegated error listener (no inline onerror)
- html.html artifact viewer: sandbox without allow-same-origin (opaque origin)
- tests: DOMPurify runs under jsdom (happy-dom Node.prototype.nodeName getter
breaks DOMPurify); useWebSocket tests get localStorage stub + ui-kit alias
Tests: pytest 1049 passed, 1 skipped; vitest 61 passed
Eugene Sukhodolskiy
committed
29 days ago
|
| 2026-07-12 |
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
on 12 Jul
|
| 2026-05-26 |
Add persistent multi-session terminal tool with background support
...
- New TerminalManager module: named subprocess sessions per Navi session,
background readers, event-sink streaming, idle auto-cleanup
- Refactor terminal tool to multi-action: run, open, close, list,
status, send_input
- Add TerminalOutputDelta and TerminalClosed events for streaming
- Wire TerminalManager into AppContainer, orchestrator, and registry
- Persist session_metadata in Session model and pg_session_store
- Close all session terminals on session delete
- Webclient: handle terminal_output/terminal_closed WS events,
display live terminal output in tool cards
- Update unit tests for new terminal actions
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 26 May
|
| 2026-05-21 |
FallbackOllamaBackend: do not blacklist single server, empty file fallback
...
- When only one Ollama server is configured, LLMConnectionError no longer
adds it to the dead-server blacklist. This fixes the bug where a
transient failure permanently blocked all requests until server restart.
- LLMModelNotFoundError on a single server is also not blacklisted.
- _discover_backends now falls back to settings.ollama_host when the
ollama_backends_file is empty, missing, or returns no valid servers.
- Added unit tests covering single-server no-blacklist, multi-server
blacklist, model-not-found no-blacklist, and empty-file fallback.
400 passed, 1 skipped
Eugene Sukhodolskiy
committed
on 21 May
|
| 2026-05-18 |
Eliminate cross-registry patching in registry.py via proper creation order
...
- Reorder build_default_registries so profiles and cp_registry are created
BEFORE tools that need them
- All tools now receive full dependencies at construction time:
ListToolsTool(profile_registry=profiles, mcp_manager=mcp_manager)
SpawnAgentTool(backend_registry=backends, ...)
ReloadToolsTool(cp_registry=cp_registry, mcp_manager=mcp_manager)
- Remove all post-creation patch lines (_profile_registry, _backend_registry, _cp_registry)
- Add mcp_manager parameter to build_default_registries
- Update create_container to pass mcp_manager
392 passed, 1 skipped
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 18 May
|
| 2026-05-16 |
Enhance native toolset and add persistent KV store
...
- Add PostgreSQL-backed KvStore (navi/store/) for session-scoped data.
- Migrate todo and scratchpad from in-memory dicts to KvStore.
- Filesystem: add copy, grep, diff actions; compress description.
- CodeExec: remove language param, expose working_dir in schema.
- ImageView: resize to 1024px JPEG + Content-Type guard for URLs.
- Memory list: return distinct categories instead of all facts.
- SSH: add scp action with upload/download support.
- Update CLAUDE.md (Postgres-only), docs/tools.md, add docs/store.md.
- Fix agent/planning/context_builder async signatures for todo helpers.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 May
|
| 2026-05-15 |
cleanup: remove deprecated tools and orphaned memory tools
...
Removed (no profile used them, no cross-dependencies):
- write_tool.py, delete_tool.py, test_tool.py
- memory_save.py, memory_search.py, memory_forget.py
Updated:
- navi/core/registry.py — removed imports and registrations
- navi/tools/__init__.py — removed imports
- docs/tools.md — removed references, updated self-extension section to MCP
- navi/tools/tool_manual.py — updated example to create_mcp_server
Profile fixes:
- developer: +tool_manual, +ssh_exec
- discuss: +list_profiles
- tool_developer: +mcp_servers navi-web
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
Add self-recall (scheduled callback) system
...
Core features:
- schedule_recall tool: once/recurring/immediate callbacks
- manage_recall tool: cancel/skip/list scheduled recalls
- Natural-language time parser (ISO, relative, "tomorrow at 09:00")
- PostgreSQL-backed RecallScheduler with lazy pool init
- Background recall_scheduler_loop with asyncio.Semaphore(3)
- _busy_sessions guard prevents user messages during headless runs
- Agent.run() preserves thinking field for session history visibility
- API endpoints: GET/DELETE/POST for session recall, admin list
- Frontend: recall badge, filter, cancel/skip in sidebar and chat header
- Tests: parser, scheduler CRUD, tools, API, scheduler loop (53 tests)
- Manuals: schedule_recall.md and manage_recall.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
fix: wire test_mcp_tool into MCP manager startup injection
...
The startup loop in main.py assigns _mcp_manager only to tools that
have the attribute, but test_mcp_tool never declared it and mcp_status
used _manager instead of _mcp_manager — so both received None forever.
Changes:
- test_mcp_tool: add __init__(mcp_manager) with _mcp_manager, fallback
to module-level import if startup wiring skipped
- mcp_status: rename _manager → _mcp_manager, same fallback
- registry.py: register create_mcp_server and test_mcp_tool builtins
- main.py: include test_mcp_tool in startup wiring loop
- client.py: add 5s timeout to disconnect cleanup
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
| 2026-05-13 |
Add profile_id support to list_tools
...
ListToolsTool now accepts an optional `profile_id` parameter. When
provided, it returns only the tools enabled for that specific profile
(enabled_tools + user tools + resolved MCP tools). This helps the agent
preview what a profile can do before switching.
- Updated ListToolsTool.execute() with profile-aware filtering
- Patched _profile_registry in build_default_registries
- Patched _mcp_manager in main.py startup loop
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
Migrate web tools (web_search, web_view, http_request) to navi-web MCP server
...
New MCP server: mcp-servers/navi-web/
- app/search.py — SearXNG primary, DDG fallback, Brave tertiary
- app/browse.py — Playwright headless browser page extraction
- app/request.py — httpx raw HTTP requests
- app/mcp_server.py — FastMCP entry point with stdio transport
- pyproject.toml — deps: mcp, httpx, ddgs, playwright, pydantic
Changes:
- Added "navi-web" block to mcp_servers.json (stdio transport)
- Removed web_search, web_view, http_request from built-in registry
- Removed them from navi/tools/__init__.py
- Removed them from enabled_tools / subagent_tools in all profiles
- Added "navi-web": ["search", "browse", "request"] to mcp_servers
in all profiles (developer, secretary, server_admin, tool_developer,
modeler_3d, discuss)
Tests: 240 passed.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|

Migrate 3D modeling tools to standalone MCP server navi-3d
...
Phase 0 — Fix MCP error propagation:
- McpClient.call_tool now returns (output, is_error) tuple
- McpTool.execute sets success=False when MCP reports isError=True
- Fixes silent failures where MCP errors looked like success
Phase 1 — Create mcp-server-navi-3d:
- New standalone MCP server in mcp-servers/navi-3d/
- Tools: compile_scad, render_stl, lint_scad
- Session-scoped path resolution via SESSION_FILES_DIR env
- Anti-escape validation for security
- Includes tests/unit/test_scad_analyze.py
Phase 2 — Remove from Navi core:
- Deleted navi/tools/{model_3d,render_3d,scad_lint}.py
- Removed from registry.py builtins and navi/tools/__init__.py
- Updated pyproject.toml testpaths to exclude mcp-servers/
Phase 3 — Wire into Navi config:
- Added navi-3d block to mcp_servers.json (SSE on :8002)
- Updated modeler_3d profile: mcp_servers + updated system_prompt
- All old tool names replaced with mcp_navi-3d_* equivalents
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
| 2026-05-11 |
Fix ollama_backends / FallbackOllamaBackend issues
...
- registry.py: always use FallbackOllamaBackend (unified backend).
Enables model priority lists in all deployments, not just multi-server.
- agent.py: add missing think=profile.think_enabled to run() (REST endpoint).
- compressor.py: fix model param type (str → list[str] | str | None).
- fallback.py: harden load_servers_from_file against missing/bad JSON files
and entries without host. Add clear_blacklists() for manual reset.
- admin.py: add POST /admin/ollama/clear-blacklists endpoint.
- tech_debt_review: document dead stream() methods.
- tests: add tests for single-server fallback, bad file handling,
missing host skipping, and blacklist clearing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 11 May
|
| 2026-05-10 |
Add MCP server support and fix memory tools user isolation
...
MCP integration:
- New navi/mcp/ package: client, manager, config, tools
- ToolRegistry learns register_external() for MCP tools
- reload_tools reconnects MCP servers on hot reload
- New built-in mcp_status tool
- Startup/shutdown wiring for MCP connections
- 12 new tests (unit + integration with real stdio server)
Memory tools fix:
- memory, memory_save, memory_search, memory_forget now read
current_user_id from tool context and pass it to MemoryStore
- Fixes invisible facts for authenticated users
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 10 May
|
| 2026-05-09 |
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
|
| 2026-05-01 |
Improve 3D modeling validation prompts
Eugene Sukhodolskiy
committed
on 1 May
|
| 2026-04-30 |
Add 3D modeling profile with model_3d and render_3d tools
...
New profile:
- modeler_3d: 3D model design for 3D printing (OpenSCAD → STL)
New tools:
- model_3d: compile .scad → binary STL via OpenSCAD CLI
- render_3d: render PNG previews from STL (up to 3 views, 400×300)
Both tools return openscad_not_found error if OpenSCAD is not installed.
Docs:
- README.md: add modeler_3d to profile table
- docs/profiles.md: add modeler_3d to active profiles
- docs/tools.md: add model_3d and render_3d to builtin tools
- manuals/model_3d.md, manuals/render_3d.md: full usage manuals
- modeler_3d system_prompt.txt: OpenSCAD-first workflow with dedicated tools
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 30 Apr
|
| 2026-04-29 |
Align Ollama HTTP timeout with LLM timeouts
Eugene Sukhodolskiy
committed
on 29 Apr
|
Architecture extensibility — event bus, middleware, auto-discovery, Pydantic profiles
...
- EventBus: async pub/sub for AgentEvents, WebSocket subscribes instead of direct yield
- Declarative serialization: AgentEvent.to_wire() on all event types
- Auto-discovery for LLM backends (_discover_backends) and workers (scan navi/workers/*.py)
- AgentProfile: Pydantic BaseModel with extra='allow', @field_validator for model coercion
- Tool middleware chain: pre/post execute hooks via ToolRegistry.add_middleware()
- LoggingMiddleware: built-in, logs every tool call
- Fix pg_trgm DDL: conditional GIN indexes via DO $$ block, no CREATE EXTENSION
- New files: event_bus.py, middleware.py, logging_middleware.py
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 29 Apr
|
| 2026-04-28 |
Add content hosting system with inline viewers
...
Backend:
- Add navi/content/ directory for published files
- Add content_store.py with publish/list/delete/cleanup functions
- Add content_publish tool for publishing files as viewable content
- Add /content static file mount in main.py
- Add /content-viewers mount for viewer pages
- Extend ToolEvent with metadata field
- Forward metadata through websocket tool_call events
- Update Agent to include metadata in ToolEvent
Frontend:
- Add ContentCard.vue component for displaying published content
- Add viewer pages: stl.html (Three.js), svg.html, html.html, pdf.html
- Update AssistantMessage.vue to render ContentCard for content_publish
- Update chat store to preserve metadata in tool cards
- Update websocket protocol docs with metadata field
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 28 Apr
|
| 2026-04-25 |
Add context providers: dynamic system message injection per LLM call
...
- navi/context_providers/ registry + built-in public_url provider (global, always injected)
- context_providers/ user directory, hot-reloaded via reload_tools
- AgentProfile.context_providers field for per-profile opt-in providers
- Agent._collect_context_injections() called before every tool-calling loop
- reload_tools now reloads both user tools and user context providers
- manuals/write_context_provider.md for Navi, docs/context_providers.md reference
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 25 Apr
|