# Integration

> >

- **Type:** Skill
- **Install:** `agentstack add skill-robium-ai-robium-1-0-0`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [robium-ai](https://agentstack.voostack.com/s/robium-ai)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [robium-ai](https://github.com/robium-ai)
- **Source:** https://github.com/robium-ai/robium/tree/main/archive/integration/1.0.0
- **Website:** https://robium.ai

## Install

```sh
agentstack add skill-robium-ai-robium-1-0-0
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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](https://docs.ros.org/) and the
  [ros2/rmw_zenoh](https://github.com/ros2/rmw_zenoh) 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 rmw_zenoh 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 rmw_zenoh | 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: host` is 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 rmw_zenoh instead in that case; [this Husarnet
  writeup](https://husarnet.com/blog/ros2-docker) 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_ID` collisions 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),
  [rmw_zenoh](https://github.com/ros2/rmw_zenoh), [Fast DDS Discovery
  Server](https://fast-dds.docs.eprosima.com/en/latest/fastdds/ros2/discovery_server/ros2_discovery_server.html),
  [Docker Compose networking](https://docs.docker.com/compose/how-tos/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](https://github.com/robium-ai)
- **Source:** [robium-ai/robium](https://github.com/robium-ai/robium)
- **License:** MIT
- **Homepage:** https://robium.ai

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-robium-ai-robium-1-0-0
- Seller: https://agentstack.voostack.com/s/robium-ai
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
