> ## Documentation Index
> Fetch the complete documentation index at: https://docs.generalrobotics.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Navigation API contract

> Remote call signatures, lifecycle, side effects, results, and errors.

This is the experimental **Nexus** navigation surface. The robot serves PointNav
methods dynamically. Use `from grid_nexus_client.nav import make_nav` and pass
the `RemoteRobot` returned by `grid_nexus_client.make_robot`.

Return types below describe the current implementation; see [data schemas](/navigation/data-types).

## Attach and inspect

`make_nav(robot, cfg=None, **options) -> RemoteNav`

A new instance is cold. A no-option attach can also return an existing instance,
including one already running a mission. Check `nav.status()` before changing it.
This call does not start navigation motion, but creates or attaches runtime state.

| Input | Contract |
| - | - |
| `robot` | A `RemoteRobot`, not a name or a raw session handle. |
| `cfg` | Optional config dictionary or YAML path **on the robot**. Validated there. |
| `profile`, `config_dir`, `omni` | Robot profile selection, robot-side profile directory, and optional profile omni overlay. |
| `backend` | `"mppi"` (default) or `"dwa"`. |
| `record` | Recording channel selection; default `"default"`; use `"off"` to disable. |
| `run_name` | Artifact label; default `"nav"`. |
| `enable_cloud_replan` | Boolean, default `False`; global replanning during missions is opt-in. |
| `stream_viz_grx`, `stream_viz_port` | Optional GRX streaming controls; defaults `False` and `None`. Not required for the CLI viewer. |
| `overrides` | Dictionary of dotted configuration fields and values. |
| `config` | Compatibility alias for `cfg`; do not pass both. |

With no config, the robot uses its `GRID_NAV_CONFIG` path when set, otherwise
the bundled profile for its robot type. Resolution applies schema defaults,
profile/config values, dotted overrides, then explicit construction keywords.
Avoid copying controller or localization tuning from a different robot. Follow
[Configure navigation](/navigation/configuration) for examples, YAML shape,
precedence, validation, and a complete downloadable config/schema.

Options require updated Edge Comms and PointNav (attach capability version 2
or later). **Any settings supplied while a Nav already exists are refused**,
even if identical. `stop()` does not release the instance. Coordinate with
other users, call `shutdown()`, and construct a new Nav to change settings.

`nav.config` is the resolved configuration as a plain dictionary (or `None`
if the robot did not report one). Editing it does not reconfigure the robot.
`nav.instance` and `nav.robot_instance` identify the instances the handle owns.
`nav.robot` is the borrowed robot proxy.

## Catalogs and localization

| Call | Returns | Requirements and effects |
| - | - | - |
| `list_maps(*, page=1, limit=50)` | `list[NavMapInfo]` | Reads one page, including unfinished jobs. Select `status == "COMPLETED"`. No map selection or warm-up. |
| `list_paths(map_id, *, page=1, limit=100)` | `list[NavPathInfo]` | `map_id` must be a GRID cloud UUID. Metadata only; does not load routes or move. |
| `start(map_id=None, *, timeout_s=30.0)` | `NavState` | Supply the map UUID. Warms sensors, controller, and localization; waits for a valid pose. Repeating for the active map is idempotent. Does not launch motion. |
| `status()` | `NavState` | Reads lifecycle and localization health; valid before start. |
| `localize(*, timeout_s=30.0)` | `NavPose` | Requires active localization. Waits for an accepted cloud fix from a query submitted after this call. No motion. |
| `pose()` | `NavPose` | Reads the latest localized map pose without waiting for a fresh fix. Raises if unavailable. |
| `get_pose()` | `dict` with `x`, `y`, `yaw`, or `None` | Compatibility read; prefer the typed `pose()` contract. |
| `get_position()` | `(x, y)` or `None` | Latest XY in metres. |
| `get_orientation()` | `float` or `None` | Latest yaw in radians. |
| `set_map(map_id, *, timeout_s=30.0)` | `NavState` | Requires active Nav. Stops the current runtime and mission, switches map, and localizes again. |

Pagination is explicit: `page` is an integer starting at 1 and `limit` is an
integer from 1 to 100. Continue until a page contains fewer than `limit`
records. Names need not be unique; prefer IDs. `start` and `set_map` accept
positive `timeout_s` or `None` for no localization deadline. This does not
disable independent network timeouts.

## Lookup, planning, and motion

A `Target` is a semantic string, a `Waypoint`, or an `(x, y)` pair in **map
metres**. It is not a displacement relative to the robot.

| Call | Returns | Requirements and effects |
| - | - | - |
| `find(label, **query)` | `list[Waypoint]` | Active map required. Semantic map lookup, no motion. Empty list means no matches. |
| `plan(targets)` | `Path` | Active, localized map required. Accepts one target, a sequence, or a `Path`. Plans from the current pose; no motion. |
| `run_mission(mission, *, blocking=True, **overrides)` | `MissionResult` when blocking | Ready Nav with no active mission. `mission` is a shared `Path`, saved path ID, or unambiguous saved path name. **Moves the robot.** |
| `move_to(target, *, blocking=True)` | `MissionResult` when blocking | Plans one target and executes it. **Moves the robot.** |

`find` preserves server order, not nearest-first order, and currently returns
`confidence=None`. Inspect matches before selecting. A string passed to
`plan` or `move_to` resolves to the **first semantic match**, not a saved path
name or an authored waypoint-name lookup. No match raises `UnknownWaypoint`.
`run_mission("name")` instead resolves a saved mission on the active map.

`find` supports these keyword query controls:

| Keyword | Default | Meaning |
| - | - | - |
| `eps_multiplier` | `3.0` | Semantic clustering radius multiplier. |
| `min_samples` | `2` | Minimum samples for clustering. |
| `weight_threshold` | `5.0` | Semantic map weight threshold. |
| `tsdf_threshold` | `1.0` | TSDF filtering threshold. |
| `timeout` | `15.0` | Cloud query timeout in seconds. |

Planning can snap targets to navigable locations. Inspect the returned
`path.waypoints` and dense `path.route`. A sparse `Path` passed to `run_mission`
is planned before motion. A path with a dense route is validated and executed;
it is not automatically replanned from a new start. Map IDs must match, all
coordinates must be finite, and execution needs at least one waypoint and
a dense route with at least two points. Replan stored waypoints before reuse.

Serializable mission overrides include `record`, `run_name`, `enable_cloud_replan`,
`cloud_replan_cooldown_s`, `cloud_replan_timeout_s`, `stream_viz_grx`,
`stream_viz_port`, and `constraints`. See [per-mission options](/navigation/configuration#per-mission-options)
for meanings and the supported polygon-policy schema. They affect that run,
not `nav.config`. Do not pass robot-side worker objects or arbitrary controller
fields through Nexus. Use construction-time `overrides` for configuration.

## Non-blocking missions and completion

`run_mission(..., blocking=False)` and `move_to(..., blocking=False)` leave
execution on the robot. **Discard the return value over Nexus.** The local
PointNav `Run` object is not a remote handle; the current transport falls back
to its string representation. Do not call `.wait()` or `.cancel()` on it.

| Call | Returns | Meaning |
| - | - | - |
| `status()` | `NavState` | Poll `mission_running`. `mission_id` identifies the run, not the saved path ID. |
| `result()` | `dict` or `None` | Raw controller result for the current/last run. Not a `MissionResult`. `None` can mean no run, still running, or worker failure. |
| `events()` | `list[dict]` | Collected progress events; empty before a run. Event details are diagnostic and may evolve. |
| `cancel_mission()` | `None` | Requests cancellation and sends zero velocity. Keeps localization warm. Poll until `mission_running` is false before starting another run. |

The raw result includes `success: bool`, `exit_cause: str`,
`waypoints_reached: int`, and `total_waypoints: int`, plus diagnostics.
Require `success is True` to report success. A stopped mission alone does not
prove arrival. If the result is `None` after the run ends, inspect
`telemetry()["status"]["error"]` and the events. Read results before
`stop()`, `shutdown()`, or another mission replaces the current run.

A keyboard interrupt during a Nexus method call attempts cancellation, but
this is best-effort. Interrupting a camera or GRID cloud loop does not itself
cancel the mission. Wrap such loops in cleanup that calls `cancel_mission`.
A network timeout is not evidence that a motion request was rejected: inspect
status before deciding what to do. Nexus never automatically retries nav calls.

## Stop, restart, and finish

| Call | Returns | Effect |
| - | - | - |
| `stop(*, timeout_s=10.0, retain_localization=False)` | `NavState` | Cancels motion and closes navigation workers; retains a restartable instance. |
| `shutdown(*, timeout_s=10.0)` | `NavState` | Stops and permanently releases this Nav. `close()` is an alias. |

`stop` and `shutdown` accept a nonnegative stop timeout. `stop` can raise if
a mission has not joined by that deadline; inspect the state instead of
assuming teardown completed. A retained localization seed is inert while
stopped and only usable on the same map. Restart still needs a fresh accepted
cloud validation and never resumes the old mission.

These operations affect every client sharing the Nav. They leave the borrowed
robot connection available. Finish navigation first, then call
`robot.shutdown()` when done with the robot session. A stale Nav after shutdown,
or a stale robot after restart, produces an instance error; reconnect/reattach.

## Viewer and diagnostics

`view(open_browser=True) -> str` is client-side. It opens the local CLI viewer
and returns its URL; `False` only returns the URL. A CLI dev session on the
same computer must supply that URL. It does not start navigation.

`telemetry(since=0) -> dict` reads a bounded snapshot/delta without starting
navigation. Its envelope has `version`, `epoch`, `sequence`, `since`, `t_ns`,
`errors`, `log_id`, `streams`, and `status`. Start at zero, then use the returned
`sequence` for the next poll; reset to zero when `epoch` changes. `status`
contains the NavState fields plus `progress`, `result`, and `error` diagnostics.

`log_chunk(log_id, *, offset=None, before=None, limit=65536) -> dict` reads
bounded terminal text using the opaque `log_id` from telemetry. Omit cursors
for the tail, use `before` for history or `offset` to follow, never both.
`limit` is an integer from 1 to 65536 bytes; cursors are nonnegative byte
positions within the current log. The response has `log_id: str`, `start: int`,
`end: int`, `size: int`, and `text: str`. Use the returned `end` as the next
`offset`, or `start` as `before` to read older text. Boundaries are adjusted for
UTF-8. No filesystem path is accepted. Prefer the viewer for routine inspection.

## Errors

Import navigation errors from `grid_nexus_client.nav` (shared base errors also
live in `grid_types.nav_errors`). These derive from `NavError` / `RuntimeError`.

| Error | Meaning and response |
| - | - |
| `NavNotInstalled` | Attach found no nav surface or the robot could not import PointNav. Verify provisioning. |
| `NoConfig` | No usable robot profile/config. Supply the correct robot-side config. |
| `NoMapSet` | No map supplied to start. Discover and pass its UUID. |
| `NavNotStarted` | Operation requires active/ready navigation. Check lifecycle state. |
| `NotLocalized` | A valid pose is unavailable. Fix localization before planning or moving. |
| `LocalizationTimeout` | Localization did not meet the requested deadline. Check map and sensor health. |
| `UnknownWaypoint` | No semantic match for the target. Inspect `find` results. |
| `UnknownMission` | Saved mission missing or ambiguous. Use a path ID from the correct map. |
| `NavShutdown` | The local runtime is permanently finished. Reattach through Nexus. |
| `NavError` | Other robot-side errors, including validation errors without a named nav class. Read the message. |
| `RuntimeError` containing `[InstanceError]` | Stale handle or settings supplied to an existing Nav. Reconnect or deliberately replace the Nav. |

Transport errors and serialization errors can remain plain runtime exceptions;
catching `NavError` alone does not catch all failures. Invalid values can be
`ValueError` locally but become `NavError` across Nexus.

## Agent call sequence

1. Connect the explicitly selected robot and attach navigation. Inspect the
   served methods and current state; do not stop another run implicitly.
2. Discover a completed map and resolve IDs. Start that map and verify the
   localized pose against the physical robot.
3. Resolve target ambiguity, plan, and inspect the resulting path. Planning
   and semantic lookup do not authorize a new physical mission.
4. Execute the user-requested mission. Do not retry an uncertain motion
   request automatically. Observe status and verify its result.
5. Cancel or shut down when requested or when the owning workflow fails.

Nexus serves attach at `nav/{robot_name}/attach`, introspection at
`nav/{robot_name}/query/introspect`, and calls at `nav/{robot_name}/{method}`.
The SDK handles serialization and both instance IDs. These are Zenoh query
surfaces, not agent tool names or plain HTTP/JSON endpoints. Use the SDK for
these tutorials; use a future tool's own advertised schema when available.


## Related topics

- [Configure navigation](/navigation/configuration.md)
- [Navigation data schemas](/navigation/data-types.md)
- [Navigation through GRID CLI](/navigation/overview.md)
- [Navigation troubleshooting](/navigation/troubleshooting.md)
- [Configuration field reference](/navigation/config-reference.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.