agenticros 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +18 -3
  2. package/dist/util/skill-manifest.d.ts.map +1 -1
  3. package/dist/util/skill-manifest.js +22 -1
  4. package/dist/util/skill-manifest.js.map +1 -1
  5. package/package.json +1 -1
  6. package/runtime/BUNDLE.json +1 -1
  7. package/runtime/README.md +31 -6
  8. package/runtime/docs/cli.md +1 -1
  9. package/runtime/docs/robot-setup.md +1 -1
  10. package/runtime/packages/agenticros/openclaw.plugin.json +147 -1
  11. package/runtime/packages/agenticros/src/__tests__/capabilities-plugin.test.ts +2 -0
  12. package/runtime/packages/agenticros/src/routes.ts +4 -3
  13. package/runtime/packages/agenticros/src/tools/index.ts +6 -5
  14. package/runtime/packages/agenticros/src/tools/mission-pause.ts +49 -0
  15. package/runtime/packages/agenticros/src/tools/mission-resume.ts +41 -0
  16. package/runtime/packages/agenticros/src/tools/ros2-mission.ts +33 -84
  17. package/runtime/packages/agenticros-claude-code/README.md +2 -0
  18. package/runtime/packages/agenticros-claude-code/dist/tools.d.ts.map +1 -1
  19. package/runtime/packages/agenticros-claude-code/dist/tools.js +130 -111
  20. package/runtime/packages/agenticros-claude-code/dist/tools.js.map +1 -1
  21. package/runtime/packages/agenticros-claude-code/src/tools.ts +140 -99
  22. package/runtime/packages/agenticros-gemini/package.json +2 -0
  23. package/runtime/packages/agenticros-gemini/src/find-object/coco-classes.ts +38 -0
  24. package/runtime/packages/agenticros-gemini/src/find-object/find-object.ts +191 -0
  25. package/runtime/packages/agenticros-gemini/src/follow-me/controller.ts +109 -0
  26. package/runtime/packages/agenticros-gemini/src/follow-me/depth-loop.ts +452 -0
  27. package/runtime/packages/agenticros-gemini/src/follow-me/detector.ts +303 -0
  28. package/runtime/packages/agenticros-gemini/src/follow-me/loop.ts +359 -0
  29. package/runtime/packages/agenticros-gemini/src/tools.ts +351 -90
  30. package/runtime/packages/core/README.md +1 -1
  31. package/runtime/packages/core/package.json +1 -1
  32. package/runtime/packages/core/src/__tests__/config-persistence.test.ts +26 -0
  33. package/runtime/packages/core/src/__tests__/external-capability.test.ts +72 -0
  34. package/runtime/packages/core/src/__tests__/heartbeat-fleet.test.ts +152 -0
  35. package/runtime/packages/core/src/__tests__/mission-bindings.test.ts +101 -0
  36. package/runtime/packages/core/src/__tests__/mission-pause.test.ts +104 -0
  37. package/runtime/packages/core/src/capabilities.ts +38 -3
  38. package/runtime/packages/core/src/capability-schema.ts +58 -0
  39. package/runtime/packages/core/src/config.ts +20 -0
  40. package/runtime/packages/core/src/discovery.ts +21 -3
  41. package/runtime/packages/core/src/external-capability.ts +219 -0
  42. package/runtime/packages/core/src/fleet-config.ts +91 -0
  43. package/runtime/packages/core/src/heartbeat.ts +167 -0
  44. package/runtime/packages/core/src/index.ts +55 -0
  45. package/runtime/packages/core/src/mission-bindings.ts +189 -0
  46. package/runtime/packages/core/src/mission-registry.ts +31 -3
  47. package/runtime/packages/core/src/mission.ts +64 -7
  48. package/runtime/packages/core/src/robots.ts +6 -2
  49. package/runtime/packages/core/src/transport/rosbridge/client.ts +7 -0
  50. package/runtime/pnpm-lock.yaml +6 -0
  51. package/templates/skills/camera/package.json +1 -1
  52. package/templates/skills/depth/package.json +1 -1
  53. package/templates/skills/robot/package.json +1 -1
package/README.md CHANGED
@@ -3,12 +3,13 @@
3
3
  > agentic AI for ROS-powered robots
4
4
 
5
5
  `agenticros` is the unified command-line tool for AgenticROS — bring up a real
6
- robot or a simulated one, drive it from Claude Code, OpenAI Codex, Hermes Agent, or OpenClaw,
6
+ robot or a simulated one, drive it from Claude Code, OpenAI Codex, Hermes Agent, or OpenClaw
7
+ (with **local Ollama VLMs** or cloud models),
7
8
  and keep your workspace healthy from a single binary.
8
9
 
9
10
  ```bash
10
11
  # Brand new machine: one command end-to-end
11
- npx agenticros init # workspace + plugin + MCP clients + API key + doctor
12
+ npx agenticros init # workspace + plugin + MCP clients + optional API key + doctor
12
13
  agenticros # interactive menu
13
14
  agenticros mcp setup # register AgenticROS MCP for Codex, Hermes, and Claude
14
15
  agenticros up real # bring up the real-robot stack
@@ -31,6 +32,20 @@ npm tarball bundles those scripts plus the ROS 2 source packages and the
31
32
  pre-built MCP server, so `npx agenticros init` works on a fresh machine with
32
33
  no `git clone` step.
33
34
 
35
+ ## Local VLM (Ollama)
36
+
37
+ Run **without cloud LLM API keys** by pointing OpenClaw or Hermes at Ollama:
38
+
39
+ ```bash
40
+ ollama pull qwen3-vl:8b-instruct # or qwen3-vl:2b on smaller hardware
41
+ npx agenticros init # skip OpenAI key when prompted
42
+ # Point OpenClaw primary model at Ollama (see docs/local-vlm.md)
43
+ agenticros up sim-amr
44
+ ```
45
+
46
+ OpenClaw: web chat, teleop, messaging, skills. Hermes: terminal + Ollama. Full guide:
47
+ **[docs/local-vlm.md](../../docs/local-vlm.md)** (model picks, multimodal catalog patch, describer, Follow Me).
48
+
34
49
  ## Install
35
50
 
36
51
  Three ways, listed easiest first:
@@ -81,7 +96,7 @@ walks through:
81
96
  3. ROS 2 workspace build (`colcon build --symlink-install`)
82
97
  4. OpenClaw plugin install (`scripts/setup_gateway_plugin.sh`)
83
98
  5. Robot config (namespace, transport mode, sample `~/.agenticros/config.json`)
84
- 6. OpenAI API key (paste once `scripts/configure_agenticros.sh`)
99
+ 6. OpenAI API key (optional skip when using local Ollama; see [docs/local-vlm.md](../../docs/local-vlm.md))
85
100
  7. Codex MCP config (optional — `~/.codex/config.toml` and project `.codex/config.toml`)
86
101
  8. Hermes MCP config (optional — `~/.hermes/config.yaml`)
87
102
  9. Final `agenticros doctor` summary
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manifest.d.ts","sourceRoot":"","sources":["../../src/util/skill-manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAwDhE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,GACV;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CASzC"}
1
+ {"version":3,"file":"skill-manifest.d.ts","sourceRoot":"","sources":["../../src/util/skill-manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAoFhE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,GACV;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CASzC"}
@@ -39,7 +39,7 @@ export function validateManifest(raw) {
39
39
  }
40
40
  const coreDep = m.dependencies?.["@agenticros/core"];
41
41
  if (coreDep?.startsWith("file:")) {
42
- warnings.push("`@agenticros/core` is declared as a `file:` path. Publish a version from npm (e.g. `^0.5.0`) before others can install your skill.");
42
+ warnings.push("`@agenticros/core` is declared as a `file:` path. Publish a version from npm (e.g. `^0.6.0`) before others can install your skill.");
43
43
  }
44
44
  if (!block.description && !m.description) {
45
45
  warnings.push("Add a one-sentence `description` (top-level or in `agenticros`).");
@@ -47,6 +47,27 @@ export function validateManifest(raw) {
47
47
  if (!block.capabilities || block.capabilities.length === 0) {
48
48
  warnings.push("Declare at least one capability in `agenticros.capabilities` so the agent planner can reason about your skill.");
49
49
  }
50
+ else {
51
+ for (const cap of block.capabilities) {
52
+ if (!cap || typeof cap !== "object" || typeof cap.id !== "string") {
53
+ warnings.push("Each capability must be an object with a string `id`.");
54
+ continue;
55
+ }
56
+ const c = cap;
57
+ if (!c.verb || typeof c.verb !== "string") {
58
+ warnings.push(`Capability "${c.id}" should declare a string \`verb\`.`);
59
+ }
60
+ const impl = c.implementation;
61
+ if (impl && typeof impl === "object" && impl.kind === "external_ros_node") {
62
+ if (!impl.action && !impl.service && !impl.topic) {
63
+ warnings.push(`Capability "${c.id}" external_ros_node should set action, service, or topic.`);
64
+ }
65
+ if ((impl.action || impl.service || impl.topic) && !impl.msg_type) {
66
+ warnings.push(`Capability "${c.id}" external_ros_node should set msg_type for action/service/topic dispatch.`);
67
+ }
68
+ }
69
+ }
70
+ }
50
71
  if (!block.screenshots || block.screenshots.length === 0) {
51
72
  warnings.push("Add at least one entry to `agenticros.screenshots` so the marketplace card has a preview image.");
52
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manifest.js","sourceRoot":"","sources":["../../src/util/skill-manifest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skill-manifest.js","sourceRoot":"","sources":["../../src/util/skill-manifest.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenticros",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "type": "module",
5
5
  "description": "AgenticROS - agentic AI for ROS-powered robots. Single CLI to launch real-robot or simulated demos, manage configuration, and inspect status.",
6
6
  "keywords": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "packedAt": "2026-07-06T14:26:08.936Z",
2
+ "packedAt": "2026-07-09T19:39:11.659Z",
3
3
  "repo": "https://github.com/PlaiPin/agenticros",
4
4
  "note": "This directory is a snapshot of the agenticros monorepo source. `agenticros init` will copy it to ~/agenticros and run pnpm install + colcon build there.",
5
5
  "layout": {
package/runtime/README.md CHANGED
@@ -33,6 +33,29 @@ With AgenticROS, your robot can describe what it sees, follow intent ("go check
33
33
 
34
34
  AgenticROS is built so that new adapters (LangGraph, OpenAI, local models, voice stacks, etc.) can be added without touching the ROS 2 layer. The core transport and tool contract are platform-agnostic; adapters are thin shims that surface those tools to each agent runtime.
35
35
 
36
+ ## Local VLM (Ollama) — no cloud API required
37
+
38
+ Control your robot with a **local vision-language model** instead of OpenAI or other cloud APIs. AgenticROS robot tools work the same; you point **OpenClaw** or **Hermes** at Ollama on your machine.
39
+
40
+ ```bash
41
+ ollama pull qwen3-vl:8b-instruct # recommended: chat + tools + camera vision
42
+ # or: ollama pull qwen3-vl:2b # smaller hardware
43
+
44
+ npx agenticros init # skip the OpenAI key step when prompted
45
+ # Configure OpenClaw to use Ollama as primary model (see guide below)
46
+ agenticros up sim-amr # or: agenticros up real
47
+ ```
48
+
49
+ Then chat in OpenClaw web UI or Hermes: *"List ROS topics"*, *"drive forward slowly"*, *"what do you see?"*
50
+
51
+ | Path | Best for |
52
+ |------|----------|
53
+ | **OpenClaw + Ollama** | Web chat, teleop, messaging channels, skills |
54
+ | **Hermes + Ollama** | Terminal agent with any Ollama model |
55
+ | **NemoClaw + Ollama** | Sandboxed Jetson / edge (see [docs/nemoclaw.md](docs/nemoclaw.md)) |
56
+
57
+ **Full setup, model picks, multimodal catalog patches, describer, Follow Me VLM, and troubleshooting:** **[docs/local-vlm.md](docs/local-vlm.md)**
58
+
36
59
  ## Architecture
37
60
 
38
61
  ![AgenticROS architecture: agent platforms → adapter packages → shared TypeScript runtime → transports → ROS 2 workspace and robot](docs/images/agenticros-architecture.png)
@@ -103,6 +126,8 @@ On the ROS side, every robot publishes a 1 Hz heartbeat on `<ns>/agenticros/robo
103
126
 
104
127
  `mission_cancel({ mission_id })` flips an in-process cancellation token; the runner stops at the next step boundary and marks remaining steps `cancelled`. When the [shared memory backend](#memory-optional) is on, every step is also written to `mission:<id>` in long-term memory, tagged with `step:<status>` and `capability:<id>`. A different agent — different process, different vendor — can `memory_recall` later and reconstruct exactly what happened, so two agents can collaborate on or hand off a mission.
105
128
 
129
+ **How-to:** step-by-step fleet setup, declarative plans, NL goals, cancel, and handoff — **[docs/missions.md](docs/missions.md)**. Runnable walkthrough: **[examples/find-and-approach/README.md](examples/find-and-approach/README.md)**.
130
+
106
131
  Full architecture + design trade-offs: **[docs/strategy-ai-agents-plus-ros.md](docs/strategy-ai-agents-plus-ros.md)**.
107
132
 
108
133
  ## Repository layout
@@ -112,7 +137,7 @@ Full architecture + design trade-offs: **[docs/strategy-ai-agents-plus-ros.md](d
112
137
  - `**packages/agenticros-claude-code**` — MCP server for Claude Code + Claude desktop / Dispatch (tools only; no config UI).
113
138
  - `**packages/agenticros-gemini**` — Gemini CLI (function calling; no MCP).
114
139
  - `**ros2_ws/**` — ROS2 workspace: `agenticros_msgs`, `agenticros_bringup` (Gazebo + RViz + rosbridge launches), `agenticros_discovery`, `agenticros_agent`, `agenticros_follow_me`.
115
- - `**docs/**` — Architecture, skills, robot setup, Zenoh, teleop.
140
+ - `**docs/**` — Architecture, skills, robot setup, Zenoh, teleop, **[local VLM / Ollama](docs/local-vlm.md)**.
116
141
  - `**scripts/**` — Workspace setup, gateway plugin config, run demos.
117
142
  - `**docker/**` — Docker Compose and Dockerfiles for ROS2 + plugin images.
118
143
  - `**examples/**` — Example projects.
@@ -138,7 +163,7 @@ The first run launches the interactive menu:
138
163
  ? What would you like to do?
139
164
  Launch with real robot
140
165
  ❯ Launch with simulation
141
- First-time setup (workspace + OpenClaw plugin + Codex MCP + API key)
166
+ First-time setup (workspace + OpenClaw plugin + Codex MCP + optional API key)
142
167
  Manage skills (2 registered, 0 available, 0 broken)
143
168
  Stop everything
144
169
  Doctor (health check)
@@ -146,8 +171,8 @@ The first run launches the interactive menu:
146
171
  Tail logs
147
172
  ```
148
173
 
149
- Pick **First-time setup** once (workspace + OpenClaw plugin + optional Codex MCP + API key, all
150
- idempotent), then choose how you want to run:
174
+ Pick **First-time setup** once (workspace + OpenClaw plugin + optional Codex MCP + optional API key, all
175
+ idempotent). **Using local Ollama instead of OpenAI?** Skip the API key step — see **[Local VLM (Ollama)](#local-vlm-ollama--no-cloud-api-required)**. Then choose how you want to run:
151
176
 
152
177
  | You want to … | Pick |
153
178
  |---|---|
@@ -163,7 +188,7 @@ so **Stop everything** cleanly tears the demo down.
163
188
  Prefer scripted invocations? Every menu item maps to a direct command:
164
189
 
165
190
  ```bash
166
- npx agenticros init # one-time workspace + plugin + Codex/Hermes MCP + API key
191
+ npx agenticros init # one-time workspace + plugin + Codex/Hermes MCP (+ optional API key)
167
192
  agenticros codex setup # register AgenticROS MCP for OpenAI Codex CLI
168
193
  agenticros codex doctor # validate ~/.codex/config.toml
169
194
  agenticros hermes setup # register AgenticROS MCP for Hermes Agent
@@ -212,7 +237,7 @@ needing token auth: run `node scripts/agenticros-proxy.cjs 18790` and open
212
237
  See **[docs/openclaw-releases-and-plugin-routes.md](docs/openclaw-releases-and-plugin-routes.md)**
213
238
  and **[docs/teleop.md](docs/teleop.md)**.
214
239
 
215
- See **`docs/`** for robot setup, skills, teleop, simulation internals, and Docker.
240
+ See **`docs/`** for robot setup, **[missions](docs/missions.md)**, skills, teleop, simulation internals, and Docker.
216
241
 
217
242
  ## RViz2 and Gazebo (TurtleBot3 + rosbridge)
218
243
 
@@ -64,7 +64,7 @@ skipped (with a checkmark) when already done:
64
64
  3. ROS 2 workspace build (`colcon build --symlink-install`)
65
65
  4. OpenClaw plugin install (via `scripts/setup_gateway_plugin.sh`)
66
66
  5. Robot config (writes `~/.agenticros/config.json`)
67
- 6. OpenAI API key (paste once `scripts/configure_agenticros.sh`)
67
+ 6. OpenAI API key (optional skip when using local Ollama; see [local-vlm.md](local-vlm.md))
68
68
  7. MCP client config (optional — `agenticros mcp setup` for Codex, Hermes, and Claude)
69
69
  8. Final `agenticros doctor` summary
70
70
 
@@ -296,7 +296,7 @@ The message comes from **OpenAI's API limits**, not from AgenticROS. The gateway
296
296
  1. **Confirm it's OpenAI** — Check gateway logs:
297
297
  `journalctl --user -u openclaw-gateway.service -n 100 --no-pager | grep -i "429\|rate\|limit\|error"`
298
298
  2. **Check your OpenAI account** — [Usage](https://platform.openai.com/usage), [API keys](https://platform.openai.com/api-keys). Free/low tiers have strict RPM/TPM and can stay limited for a while.
299
- 3. **What helps** — Wait (RPM/TPM reset in minutes; daily limits at UTC midnight). Or in OpenClaw switch to a model with higher limits if available.
299
+ 3. **What helps** — Wait (RPM/TPM reset in minutes; daily limits at UTC midnight). Or switch OpenClaw to a **local Ollama VLM** — see [local-vlm.md](local-vlm.md). Or in OpenClaw switch to a model with higher limits if available.
300
300
  4. **AgenticROS** — We only trim context/tool output to use fewer tokens; we can't remove OpenAI's limits.
301
301
 
302
302
  ### 404 errors when installing rosbridge_suite
@@ -21,6 +21,8 @@
21
21
  "ros2_find_robots_for",
22
22
  "run_mission",
23
23
  "mission_cancel",
24
+ "mission_pause",
25
+ "mission_resume",
24
26
  "ros2_camera_snapshot",
25
27
  "ros2_depth_distance",
26
28
  "memory_remember",
@@ -30,7 +32,8 @@
30
32
  "follow_robot",
31
33
  "follow_me_see",
32
34
  "ollama_status",
33
- "find_object"
35
+ "find_object",
36
+ "scan_surroundings"
34
37
  ]
35
38
  },
36
39
  "configSchema": {
@@ -178,6 +181,149 @@
178
181
  }
179
182
  }
180
183
  },
184
+ "robots": {
185
+ "type": "array",
186
+ "description": "Multi-robot fleet list. When non-empty, used by ros2_list_robots and per-tool robot_id. When empty, the legacy config.robot entry is used. Manage via `agenticros robots` CLI.",
187
+ "default": [],
188
+ "items": {
189
+ "type": "object",
190
+ "required": [
191
+ "id"
192
+ ],
193
+ "properties": {
194
+ "id": {
195
+ "type": "string",
196
+ "description": "Stable identifier referenced by robot_id tool arguments"
197
+ },
198
+ "name": {
199
+ "type": "string",
200
+ "default": "Robot"
201
+ },
202
+ "namespace": {
203
+ "type": "string",
204
+ "default": ""
205
+ },
206
+ "cameraTopic": {
207
+ "type": "string",
208
+ "default": ""
209
+ },
210
+ "default": {
211
+ "type": "boolean",
212
+ "description": "When true, this robot is active even if not first in the list"
213
+ },
214
+ "kind": {
215
+ "type": "string",
216
+ "description": "Robot kind for ros2_find_robots_for (e.g. amr, arm, drone, rover)",
217
+ "default": "amr"
218
+ },
219
+ "sensors": {
220
+ "type": "object",
221
+ "properties": {
222
+ "has_realsense": {
223
+ "type": "boolean",
224
+ "default": false
225
+ },
226
+ "has_lidar": {
227
+ "type": "boolean",
228
+ "default": false
229
+ },
230
+ "has_arm": {
231
+ "type": "boolean",
232
+ "default": false
233
+ }
234
+ }
235
+ },
236
+ "capabilities": {
237
+ "type": "array",
238
+ "description": "Optional per-robot capability allowlist for ros2_find_robots_for",
239
+ "items": {
240
+ "type": "string"
241
+ }
242
+ },
243
+ "transport": {
244
+ "type": "object",
245
+ "description": "Per-robot transport override (inherits global transport when omitted)",
246
+ "properties": {
247
+ "mode": {
248
+ "type": "string",
249
+ "enum": [
250
+ "rosbridge",
251
+ "local",
252
+ "webrtc",
253
+ "zenoh"
254
+ ]
255
+ },
256
+ "zenoh": {
257
+ "type": "object",
258
+ "properties": {
259
+ "routerEndpoint": {
260
+ "type": "string"
261
+ },
262
+ "domainId": {
263
+ "type": "number"
264
+ },
265
+ "keyFormat": {
266
+ "type": "string",
267
+ "enum": [
268
+ "ros2dds",
269
+ "rmw_zenoh"
270
+ ]
271
+ },
272
+ "bridgeNamespace": {
273
+ "type": "string"
274
+ }
275
+ }
276
+ },
277
+ "rosbridge": {
278
+ "type": "object",
279
+ "properties": {
280
+ "url": {
281
+ "type": "string"
282
+ },
283
+ "reconnect": {
284
+ "type": "boolean"
285
+ },
286
+ "reconnectInterval": {
287
+ "type": "number"
288
+ }
289
+ }
290
+ },
291
+ "local": {
292
+ "type": "object",
293
+ "properties": {
294
+ "domainId": {
295
+ "type": "number"
296
+ }
297
+ }
298
+ },
299
+ "webrtc": {
300
+ "type": "object",
301
+ "properties": {
302
+ "signalingUrl": {
303
+ "type": "string"
304
+ },
305
+ "apiUrl": {
306
+ "type": "string"
307
+ },
308
+ "robotId": {
309
+ "type": "string"
310
+ },
311
+ "robotKey": {
312
+ "type": "string"
313
+ },
314
+ "iceServers": {
315
+ "type": "array",
316
+ "items": {
317
+ "type": "object"
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+ },
181
327
  "teleop": {
182
328
  "type": "object",
183
329
  "description": "Teleop web app: camera and twist controls",
@@ -131,6 +131,8 @@ test("plugin: register() is synchronous and produces the base 15-tool surface",
131
131
  "run_mission",
132
132
  // Phase 1.f — cancel an in-flight mission by id.
133
133
  "mission_cancel",
134
+ "mission_pause",
135
+ "mission_resume",
134
136
  ];
135
137
  for (const name of expected) {
136
138
  assert.ok(toolNames.includes(name), `Expected base tool ${name} in registered set`);
@@ -1,6 +1,6 @@
1
1
  import type { OpenClawPluginApi, HttpRouteHandler, HttpRouteResponse } from "./plugin-api.js";
2
2
  import type { AgenticROSConfig } from "@agenticros/core";
3
- import { parseConfig } from "@agenticros/core";
3
+ import { parseConfig, prepareConfigForPersistence } from "@agenticros/core";
4
4
  import {
5
5
  readOpenClawConfig,
6
6
  writeAgenticROSConfig,
@@ -172,8 +172,9 @@ export function registerRoutes(api: OpenClawPluginApi, config: AgenticROSConfig)
172
172
  api.logger.warn("AgenticROS config read failed: " + readMsg);
173
173
  return { success: false, error: readMsg, statusCode: 500 };
174
174
  }
175
+ let combined: Record<string, unknown>;
175
176
  try {
176
- const combined =
177
+ combined =
177
178
  existingAgenticROS && typeof existingAgenticROS === "object"
178
179
  ? mergeIncomingAgenticROSConfig(existingAgenticROS, body)
179
180
  : body;
@@ -192,7 +193,7 @@ export function registerRoutes(api: OpenClawPluginApi, config: AgenticROSConfig)
192
193
  merged.webrtc.robotKey = existingKey;
193
194
  }
194
195
  try {
195
- writeAgenticROSConfig(merged as unknown as Record<string, unknown>);
196
+ writeAgenticROSConfig(prepareConfigForPersistence(merged, combined));
196
197
  } catch (err) {
197
198
  const msg = err instanceof ConfigFileError ? err.message : (err instanceof Error ? err.message : "Failed to write config");
198
199
  api.logger.warn("AgenticROS config write failed: " + msg);
@@ -14,6 +14,8 @@ import { registerDiscoverRobotsTool } from "./ros2-discover.js";
14
14
  import { registerFindRobotsForTool } from "./ros2-find-robots-for.js";
15
15
  import { registerMissionTool, type ToolRegistry } from "./ros2-mission.js";
16
16
  import { registerMissionCancelTool } from "./mission-cancel.js";
17
+ import { registerMissionPauseTool } from "./mission-pause.js";
18
+ import { registerMissionResumeTool } from "./mission-resume.js";
17
19
 
18
20
  /**
19
21
  * Wrap the OpenClaw API so every registerTool() call is also recorded in
@@ -21,11 +23,8 @@ import { registerMissionCancelTool } from "./mission-cancel.js";
21
23
  * dispatch sub-tool calls by name (e.g. capability "drive_base" routes
22
24
  * to the registered "ros2_publish" tool's execute()).
23
25
  *
24
- * We keep this internal skills that register their own tools via
25
- * `api.registerTool` won't appear in the registry, which is fine for
26
- * v1: today the mission runner only supports the eight intrinsic
27
- * capability bindings declared in ros2-mission.ts. Phase 1.d will
28
- * extend this to capture skill-declared tools as well.
26
+ * Skill tools registered via `api.registerTool` are captured too, so
27
+ * `buildMissionBindings` can resolve `ros2_<capability_id>` when present.
29
28
  */
30
29
  function wrapApiWithToolCapture(api: OpenClawPluginApi): {
31
30
  wrappedApi: OpenClawPluginApi;
@@ -63,4 +62,6 @@ export function registerTools(api: OpenClawPluginApi, config: AgenticROSConfig):
63
62
  registerFindRobotsForTool(wrappedApi, config);
64
63
  registerMissionTool(wrappedApi, config, registry);
65
64
  registerMissionCancelTool(wrappedApi);
65
+ registerMissionPauseTool(wrappedApi);
66
+ registerMissionResumeTool(wrappedApi);
66
67
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Tool: mission_pause — pause a running mission at the next step boundary.
3
+ */
4
+
5
+ import { Type } from "@sinclair/typebox";
6
+ import type { OpenClawPluginApi } from "../plugin-api.js";
7
+ import { getMissionRegistry } from "../mission-registry.js";
8
+
9
+ export function registerMissionPauseTool(api: OpenClawPluginApi): void {
10
+ api.registerTool({
11
+ name: "mission_pause",
12
+ label: "Pause Mission",
13
+ description:
14
+ "Pause a mission that's currently running in this OpenClaw plugin process. " +
15
+ "Pass the mission_id returned by run_mission. The runner waits at the next step " +
16
+ "boundary until mission_resume (or mission_cancel). Idempotent if already paused.",
17
+ parameters: Type.Object({
18
+ mission_id: Type.String({
19
+ description: "The mission_id echoed by run_mission. Required.",
20
+ }),
21
+ reason: Type.Optional(
22
+ Type.String({
23
+ description: "Optional free-text reason — surfaced in the paused transcript entry.",
24
+ }),
25
+ ),
26
+ }),
27
+
28
+ async execute(_toolCallId, params) {
29
+ const missionId = typeof params["mission_id"] === "string" ? (params["mission_id"] as string).trim() : "";
30
+ if (!missionId) {
31
+ const text = "mission_pause requires 'mission_id' (a non-empty string returned by run_mission).";
32
+ return { content: [{ type: "text", text }], details: { success: false, error: text } };
33
+ }
34
+ const reason = typeof params["reason"] === "string" ? (params["reason"] as string) : undefined;
35
+ const outcome = getMissionRegistry().pause(missionId, reason);
36
+ const details = {
37
+ success: true,
38
+ mission_id: missionId,
39
+ found: outcome.found,
40
+ already_paused: outcome.alreadyPaused,
41
+ reason: reason ?? null,
42
+ };
43
+ return {
44
+ content: [{ type: "text", text: JSON.stringify(details) }],
45
+ details,
46
+ };
47
+ },
48
+ });
49
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tool: mission_resume — resume a paused mission.
3
+ */
4
+
5
+ import { Type } from "@sinclair/typebox";
6
+ import type { OpenClawPluginApi } from "../plugin-api.js";
7
+ import { getMissionRegistry } from "../mission-registry.js";
8
+
9
+ export function registerMissionResumeTool(api: OpenClawPluginApi): void {
10
+ api.registerTool({
11
+ name: "mission_resume",
12
+ label: "Resume Mission",
13
+ description:
14
+ "Resume a mission previously paused with mission_pause. Pass the mission_id " +
15
+ "returned by run_mission. Idempotent if the mission is not paused.",
16
+ parameters: Type.Object({
17
+ mission_id: Type.String({
18
+ description: "The mission_id echoed by run_mission. Required.",
19
+ }),
20
+ }),
21
+
22
+ async execute(_toolCallId, params) {
23
+ const missionId = typeof params["mission_id"] === "string" ? (params["mission_id"] as string).trim() : "";
24
+ if (!missionId) {
25
+ const text = "mission_resume requires 'mission_id' (a non-empty string returned by run_mission).";
26
+ return { content: [{ type: "text", text }], details: { success: false, error: text } };
27
+ }
28
+ const outcome = getMissionRegistry().resume(missionId);
29
+ const details = {
30
+ success: true,
31
+ mission_id: missionId,
32
+ found: outcome.found,
33
+ was_paused: outcome.wasPaused,
34
+ };
35
+ return {
36
+ content: [{ type: "text", text: JSON.stringify(details) }],
37
+ details,
38
+ };
39
+ },
40
+ });
41
+ }