zettelkasten.synapse.navigate¶
zettelkasten.synapse.navigate ¶
Out-of-process synapse grounded-navigation loop (subprocess / CLI entrypoint).
The synapse navigate action steers an LLM through a knowledge substrate via
the in-process cursor-sdk agent bridge (:func:zettelkasten.llm_adapter.run_toolless_agent).
That bridge does NOT come up inside the stdio MCP server — whose stdin/stdout ARE
the JSON-RPC transport — nor inside the warm search/frame worker, which owns its
own stdin/stdout for a line protocol: in either host the bridge launches but its
completion never returns, hanging the process. Neighborhood assembly ALSO fans
out to native kglite embedding indexes (including always-cold federated peers)
whose first-access indexing has been observed to SIGSEGV, which would take the
stdio MCP server down with it.
Running the loop in a FRESH subprocess fixes both, exactly as
:mod:zettelkasten.synapse.build does for the typing bridge: a clean host with
ordinary stdio lets the agent bridge launch as it does for the dashboard/CLI, a
native crash kills only the child (the parent maps a killing signal to a clean
NativeCrash error), and a slow cold assembly is bounded by our own timeout
rather than the client's. :mod:faulthandler is enabled so a SIGSEGV dumps the
Python traceback (which in-scope source / native call it died in) to stderr,
which the parent captures — turning an opaque exit 139 into a located fault.
Usage::
python -m zettelkasten.synapse.navigate --payload-json '{"question": "...", ...}'
--payload-json is a JSON object with keys: question (required),
projects (null = configured intersection, [] = memory only, or a token
list), model (optional requested model id), max_nodes (-1 = the
default cap, 0 = no caller-specified count cap while retaining the
token-derived pre-assembly safety ceiling, >0 = an explicit hard cap), plus
hops / trace_floor / token_budget / render_max_body_chars (each
< 0 = use the substrate/router/navigator default;
render_max_body_chars == 0 disables body elision). Prints one
SYNAPSE_NAVIGATE_RESULT <json> line to
stdout (logs + any fault trace go to stderr). The result JSON is the navigation
verdict payload. Every accepted answer carries the versioned answer_surface
projection; every abstention/failure carries answer_surface: null. A
Python-level assembly/model/nav failure degrades to a clean labeled abstain here
(returncode 0); only an uncatchable native crash exits non-zero for the parent to
map.
NavigationValidationError ¶
NavDetail
dataclass
¶
The INTERNAL, benchmark-only detailed outcome of a navigation run.
This is the diagnostics seam behind :func:run_navigate: it pairs the EXACT
public verdict dict (:attr:public — byte-for-byte the same keys/values the
MCP handler, CLI, and :func:run_navigate ship) with the underlying
:class:~zettelkasten.synapse.navigation.NavResult and a wall-clock
:attr:elapsed_s so an in-process caller (the MemDSL Navigation Truth
Benchmark) can inspect what the public payload deliberately hides: the parsed
MemDSL :class:~zettelkasten.synapse.memdsl.schema.AgentOutput, parse-repair
count, the full navigation trace, and the router's per-node / per-claim
verdicts, honesty, and traceability reports (all carried on
nav_result.decision).
:attr:nav_result is None on the labeled-abstain failure path (assembly /
model / navigation raised): there is no run to inspect, so the benchmark reads
the labeled-abstain :attr:public payload and the :attr:error string alone.
:attr:public is ALWAYS populated (the honesty contract holds even when the
substrate is unavailable), so a benchmark can rely on it unconditionally.
This type is NOT part of the shipped MCP/CLI/run_navigate contract — it is
an internal seam. :func:run_navigate returns only :attr:public, keeping
the public schema untouched.
Source code in zettelkasten/synapse/navigate.py
validate_navigation_parameters ¶
validate_navigation_parameters(*, max_nodes: Any = -1, hops: Any = -1, token_budget: Any = -1, render_max_body_chars: Any = -1) -> dict[str, int]
Return validated public resource knobs or raise before any store/model work.
Source code in zettelkasten/synapse/navigate.py
validation_abstention ¶
Build the labeled public abstention returned for invalid resource inputs.
Source code in zettelkasten/synapse/navigate.py
run_navigate ¶
run_navigate(question: str, *, projects: list[str] | None = None, max_nodes: int = -1, hops: int = -1, trace_floor: float = -1.0, token_budget: int = -1, render_max_body_chars: int = -1, model: str = '', llm: 'Callable[[str, str], str] | None' = None) -> dict[str, Any]
Run the grounded cross-store navigation loop and return its verdict dict.
The stable PUBLIC entrypoint shared by the MCP handler (via the subprocess
launcher) and this module's CLI. It is a thin wrapper over the internal
:func:_run_navigate_detailed seam, returning ONLY the public verdict dict —
the exact keys/semantics the shipped MCP/CLI schema depends on. Accepted
answers add a nested, versioned answer_surface derived deterministically
from the parsed DAG, router decision, and final envelope; abstain/failure
results carry answer_surface=None. A projection inconsistency degrades to
a labeled abstain. The diagnostics the benchmark needs live on
:class:NavDetail behind that seam and never leak into this dict.
See :func:_run_navigate_detailed for parameter semantics (especially
max_nodes=-1 default / 0 no caller count cap but token-bounded
assembly / >0 explicit hard cap), requested model forwarding, the
injectable llm, and labeled-abstain degradation on any
assembly/model/navigation failure.