Install
$ agentstack add skill-robium-ai-robium-1-0-0 ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
integration
The glue-layer umbrella for robium. Once architect has picked a stack and environments has decided how a single module runs reproducibly, something has to decide how the modules find and talk to each other, and how they're packaged so the whole system starts up as one thing. This skill owns three tightly related decisions: where the module boundaries are, what comms crosses each boundary, and how Dockerfiles/docker-compose package and wire the result. It does not decide the stack (architect) or a single module's env reproducibility (environments) — it decides how already-chosen modules become a running system.
When to use this skill
- Wiring two or more components together and the question is "how should
these talk" — a planner to a controller, a perception node to a policy, a sim to an app container.
- The trigger phrases in the description: 'containerize this', 'dockerfile',
'docker compose', 'how should these modules talk', 'connect the planner to the controller'.
- Any multi-process or multi-container robotics system, even a simple
two-container sim+app pair.
- Cross-references — go to the sibling skill instead when the question is:
- The overall stack hasn't been chosen yet →
architect(load first; it
routes here once the stack and modules are known).
- A single module's reproducibility (uv vs Docker, GPU passthrough, base
image) rather than how modules talk to each other → environments. This skill assumes each module's own environment is already decided and focuses on cross-module wiring.
- ROS 2 package/node/launch-file internals within one module →
ros2. - Remote visualization transport (Foxglove bridge, rosbridge) →
foxglove.
Key directives
- Delegation posture: embed. Module-boundary heuristics, the comms
decision table, and Dockerfile/compose patterns for robotics workloads live in this skill and its references — this is core, every-multi-module- build content, not a thin pointer elsewhere.
- Prefer ROS 2 native comms inside a ROS system. If two modules are both
ROS 2 nodes in the same system, use topics/services/actions over DDS by default. Reach for a non-ROS transport (zenoh, gRPC, REST, shared memory) only when crossing a system boundary — a non-ROS peer, another team's service, a cloud endpoint, or a boundary DDS genuinely can't cross without extra config. Don't introduce a second transport inside a single ROS system "just in case."
- One process per container, unless there's a stated reason. Each
container should run one supervisable unit (one ROS 2 node, or one tightly coupled node group that only makes sense together). Bundling unrelated nodes into one container to save a Dockerfile hides failures and blocks independent scaling/restart — if you do it anyway, write down why in the compose file or brief.
- **DDS discovery across containers must be configured explicitly, never
assumed.** Docker's default bridge network does not forward the multicast UDP traffic DDS's default discovery relies on — "it worked when I ran both nodes on the host" does not imply it will work in compose. Pick and state one discovery mechanism (host networking, a Discovery Server, static peers, or a zenoh router) — see references/compose-patterns.md. This is the single most common integration bug in robium builds; treat an unconfigured discovery setup as a defect, not a "works on my machine" risk to defer.
- Never write RMW/DDS/zenoh version or default-status claims from memory.
These have changed release-to-release (zenoh support, discovery-server defaults). Verify against docs.ros.org and the ros2/rmwzenoh repo before repeating a claim in a real project — see references/comms-selection.md for what was verified and when.
Quick start
1. Confirm the prerequisites are settled. docs/architecture-brief.md should already record the chosen stack (architect) and each module's env strategy (environments). If either is missing, route back there first.
2. Decide module boundaries. Split by rate + failure domain — see Decision guidance below. Write the resulting module list into the brief's module-breakdown section.
3. Pick comms per module pair. Use the comms-choice table in Decision guidance; the default inside one ROS 2 system is native topics/services/ actions. See references/comms-selection.md for the full picture including zenoh, gRPC, REST, and shared memory.
4. Write one Dockerfile per module. Multi-stage: a build stage with the full toolchain (colcon, compilers, apt build deps), a slim runtime stage that copies only the built install/ output and runtime deps. See references/dockerfile-guide.md and examples/Dockerfile.multistage-ros2. This is a different concern from environments' Dockerfile.ros2 example (single-environment reproducibility) — this one is about build quality for a module that ships as part of a multi-container system.
5. Wire modules with docker-compose. One service per container, explicit network mode, explicit ROS_DOMAIN_ID, and an explicit DDS discovery mechanism. See references/compose-patterns.md and examples/docker-compose.ros2-app.yml.
6. Verify discovery, not just that containers start. docker compose up succeeding is not proof nodes can see each other — run ros2 topic list / ros2 node list from inside each container (or ros2 doctor --report) and confirm cross-container topics actually appear before calling the wiring done.
Decision guidance
Comms-choice table
| Relationship | Default choice | Why / when to deviate | |---|---|---| | Same process, same language | Direct call / shared object, no IPC | Don't wrap this in ROS 2 messaging "for consistency" — it adds serialization cost and a node boundary for no isolation benefit. | | Same-host, both ROS 2 nodes | ROS 2 topics/services/actions (default RMW, default DDS discovery) | Native; multicast discovery works unmodified on the host network or a single non-networked process. This is the default — deviate only for a stated reason. | | Cross-host or cross-container, both ROS 2 (one system) | Still ROS 2 topics/services/actions, but with discovery explicitly configured — host networking, a Fast DDS Discovery Server, static CycloneDDS peers, or rmwzenoh with a router | Multicast usually doesn't cross container/host boundaries by default. Don't reach for a non-ROS transport just because discovery needs setup — fix discovery, keep the transport native. See references/comms-selection.md. | | Cross-boundary to a non-ROS peer (another team's service, a cloud API, a system that doesn't speak ROS/DDS) | gRPC (typed, streaming-capable, low overhead) or REST (simplest, most interoperable) at the boundary | This is the one case where a non-ROS transport is the default, not the exception — don't leak DDS/RMW specifics across an org or system boundary. | | High-throughput same-host data (large images, point clouds, mostly within one host) | Shared memory: ROS 2 intra-process comms / loaned messages, or zenoh's SHM path if already on rmwzenoh | Adopt only when profiling shows serialization/copy overhead is the actual bottleneck — not a default starting point. |
Module-boundary heuristics: split by rate + failure domain
- Rate mismatch → split. A 1 kHz control loop and a 10 Hz planner have
no business sharing a process/executor; bundling them risks the slow one starving the fast one (or the fast one wasting the slow one's CPU budget). Each rate tier gets its own node/process so it can be scheduled and rate-limited independently.
- Failure domain → split. If module A crashing should not take down
module B (a perception model that OOMs shouldn't kill the safety controller; a sim shouldn't kill the app that drives it), they're separate processes/containers so a restart policy can target just the failed one.
- Neither applies → keep together. Two tightly coupled pieces with the
same rate and no independent failure story (e.g., a filter and the node that owns it, with no reason either would run or fail alone) add pure comms overhead if split — one node, one container, is the simpler and correct default.
- Write the resulting boundary list, and the rate/failure reasoning behind
each split, into the brief's module-breakdown section — an undocumented boundary decision gets silently re-litigated by the next person.
Platform gotchas
- Docker's default bridge network drops DDS multicast. The default
Simple Discovery Protocol most DDS implementations use relies on multicast UDP, and Docker's default bridge network does not forward it between containers — two ROS 2 nodes in separate docker compose services will not discover each other with zero extra config. Use network_mode: host (Linux only) for the simplest fix, or an explicit discovery mechanism (Discovery Server, static peers, zenoh router) when host networking isn't available. See references/compose-patterns.md.
network_mode: hostis Linux-only in the way this skill means it.
Docker Desktop on macOS/Windows does not give containers the host's real network namespace the way Linux does — don't rely on host networking as the discovery fix on a macOS/Windows dev machine (consistent with environments' "macOS has no native ROS 2" gotcha: Mac ROS 2 dev is already inside a VM/Docker layer). Use an explicit CycloneDDS peers list, a Discovery Server, or rmwzenoh instead in that case; this Husarnet writeup has a worked example of disabling multicast and pointing CycloneDDS at static peers.
- rmw_zenoh needs its own router process. Switching
RMW_IMPLEMENTATION
to rmw_zenoh_cpp doesn't work standalone — it requires a Zenoh router (ros2 run rmw_zenoh_cpp rmw_zenohd) running and reachable, or peer-to- peer config if deliberately skipping the router. In compose, that's its own service, not an assumption baked into one node's entrypoint. See references/comms-selection.md.
ROS_DOMAIN_IDcollisions are silent. Two unrelated ROS 2 systems on
the same host-network segment with the same (default 0) domain ID will discover and cross-talk with each other. Set an explicit, project-unique ROS_DOMAIN_ID in the compose file for every robium project, the same way you'd pick a non-default port.
Customization
- Fewer/more than two services: the compose example is a minimal
two-service (sim + app) shape; extend the same pattern — one service per module, shared ROS_DOMAIN_ID, one explicit discovery mechanism — for additional nodes rather than inventing a different wiring style per service.
- Adding a non-ROS peer: add the boundary transport (gRPC/REST) as its
own service or sidecar rather than piping it through the DDS network; keep the ROS-internal comms native per the key directive.
- Swapping the discovery mechanism:
references/compose-patterns.md
covers host networking, Fast DDS Discovery Server, static CycloneDDS peers, and rmw_zenoh — pick one per project based on whether it's same-host (host networking is simplest) or cross-host/cross-network (Discovery Server or zenoh scale better); don't mix mechanisms within one project.
- Heavier build (large ML deps in one module): extend
examples/Dockerfile.multistage-ros2's builder/runtime split rather than collapsing back to a single stage — see references/dockerfile-guide.md and cross-reference environments' Dockerfile.gpu-ml example for the GPU-specific multi-stage shape.
References
references/comms-selection.md— the full comms decision: ROS 2
topics/services/actions in depth, rmw_zenoh and zenoh-plugin-ros2dds status and setup, gRPC/REST for non-ROS boundaries, shared memory, with verified sources.
references/dockerfile-guide.md— Dockerfile quality for a robotics
module: multi-stage build/runtime split, one-process-per-container, layer-cache ordering, signal handling for ros2 launch.
references/compose-patterns.md— docker-compose wiring: network modes,
ROS_DOMAIN_ID, DDS discovery mechanisms across containers/hosts, depends_on/healthchecks, volumes.
examples/docker-compose.ros2-app.yml— minimal two-service (sim + app)
ROS 2 compose file with explicit DDS discovery config (status: unverified).
examples/Dockerfile.multistage-ros2— multi-stage build/runtime split
for one ROS 2 module, complementary to environments' Dockerfile.ros2 example (status: unverified).
- Upstream: [ROS 2 Topics vs Services vs
Actions](https://docs.ros.org/en/rolling/How-To-Guides/Topics-Services-Actions.html), rmwzenoh, Fast DDS Discovery Server, Docker Compose networking. Sibling skills: architect (routes here), environments (single-module env strategy — not duplicated here), ros2 (node/launch internals), foxglove (remote viz transport).
Changelog
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: robium-ai
- Source: robium-ai/robium
- License: MIT
- Homepage: https://robium.ai
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.