FAQ
claude-ros2-skills is a Claude Code plugin with 2 hand-picked skills for development work, indexed on Flowy. Install it with the command on its page. It includes ros2-microros, ros2-troubleshooting. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
> /plugin marketplace add Leehyunbin0131/claude-ros2-skills> /plugin install claude-ros2-skills@claude-ros2-skills
Repo: Leehyunbin0131/claude-ros2-skills
Claude Code Skills for ROS 2 Jazzy Jalisco robotics development.
Skills that transform how AI agents approach ROS 2 development: identify unknown parameters upfront, verify settings against installed packages, and confirm execution through working evidence.
English | 한국어 | 中文 | 日本語 | Español | Français | Deutsch
| Skills | Always-loaded protocol | Doc links (CI-checked) | Physical robot checks |
|---|---|---|---|
| 2 | 30 lines | 6 | 4 scripts |
The most costly errors in AI-generated ROS 2 code are rarely syntax mistakes. Instead, they are subtle issues that appear correct at first glance:
| Failure | What you see | Why an agent encounters the issue |
|---|---|---|
| Middleware mismatch | ros2 topic hz shows 30 Hz; your callback never fires | A default RELIABLE subscriber cannot match a BEST_EFFORT publisher. It compiles, passes review, and fails below the application. rclpy does warn — offering incompatible QoS ... Last incompatible policy: RELIABILITY — but only at runtime, in the startup log, to whoever is reading it. |
| Wrong ground truth | /cmd_vel indicates forward motion and /odom reports forward motion, but the physical robot moves backward | The static TF frame is inverted relative to physical mounting. Downstream components compute correctly using the wrong transform, producing no obvious errors. |
| Outdated API | Code passes review but fails at runtime when calling an incorrect method | The agent uses deprecated Foxy or Humble API methods that were renamed or removed in Jazzy. |
| Invalid premise | The agent writes 200 lines of code based on an assumption that you could have corrected in a single sentence | No mechanism prompts the agent to verify missing details before generating code. |
Neither compilers, linters, nor log analyses detect these hidden issues. Resolving each error requires an extra feedback cycle: reviewing output, diagnosing the cause, explaining the fix, and re-generating code.
Four design rules govern every skill in this repository. They follow Anthropic's context-engineering guidance for Claude 5 generation models — which diagnoses over-constraining and conflicting instructions across a system prompt, CLAUDE.md and skills — and each one was then checked against this repository's own measurements. evals/AUTHORING.md keeps those two sources of authority apart, including where the guidance is followed but not yet measured here.
1. Identify unknown variables upfront. Key operational details often do not exist in documentation — such as whether the environment is real hardware or simulation, whether to extend an existing workspace or create a new one, which node already publishes a transform, or the robot's precise geometry. CLAUDE.md instructs the agent to clarify these unknowns before generating code.
2. Execute a structured loop with clear exit criteria. Every skill follows a verify → write → prove cycle: inspect system defaults on the installed environment, apply incremental changes, and confirm execution. A task completes only when supported by observed evidence — such as a successful build, active data on ros2 topic echo, or a passing verification script — rather than simply producing code files.
3. Say nothing the model already knows or CLAUDE.md already says. Every symptom→cause→action table previously included in this pack was benchmarked against an unassisted baseline agent. Descriptive prose never improved benchmark outcomes — the model either reaches the solution unaided, or requires a bundled executable script or a CLAUDE.md protocol constraint. See Evals.
4. Point at a runnable artifact, never describe one. Empirical testing showed that descriptive text explaining what a script would check produced no benchmark improvement. Only executable scripts with deterministic exit codes (scripts/check_*.py in ros2-troubleshooting) measurably changed model behavior.
Most robotics skill packs embed static API knowledge directly inside skill files. While initial usage is easy, this approach breaks when the underlying packages update — leaving outdated snippets that silently fail. This repository takes a dynamic, documentation-driven approach:
| Feature | Content-heavy skill packs | claude-ros2-skills |
|---|---|---|
| Knowledge location | Embedded in skill files (400–1,800 lines/skill) | Linked to official docs (~60-line skill bodies); detailed references read only when needed |
| Always-loaded context | Full SKILL.md files | 30-line core protocol |
| Handling Jazzy API updates | Snippets become outdated quietly; requires continuous manual test updates | Outdated snippet risk is minimized to entry-point links and symbol names — 6 documentation links verified weekly via CI |
| Verification method | Static code analysis or log checking | Physical & runtime verification: IMU gravity checks, directional odometry tests, TF frame alignment, DDS QoS compatibility |
| Distribution scope | Claims support for multiple ROS distros while targeting only one | ROS 2 Jazzy only, by design — no "works on Humble too" hedging |
This repository optimizes for a single outcome: minimizing the risk of generating plausible-looking code that fails to run on ROS 2 Jazzy.
The standard. A skill earns its place only if it supplies something the agent cannot reach on its own — with its own knowledge, web search, and a live Jazzy install in front of it. Text that only tells the agent what it would have done anyway is cost without benefit.
How it is measured. A real task in a clean container, ten runs with the piece under test and ten without, graded by running what came out — a build, a topic carrying data, an exit code — never by reading it. Fisher exact test, Benjamini–Hochberg across the round.
What that settled. Eight domains were put through a three-rung ladder — 24 rungs, each rung adding a named mechanism, each graded by a check that runs the artifact. The baseline agent reached every mechanism it was asked for:
| Domain | L1 → L2 → L3, mechanisms added per rung | Unaided |
|---|---|---|
| Packaging & build | ament_python/ament_cmake → cross-package .srv → composable node + colcon test | 190/190 |
| Simulation | SDF world + diff-drive → ros_gz_bridge + gpu_lidar → URDF spawn + use_sim_time | 108/110 |
| Executors | 1 s service from a timer → from a subscription + heartbeat → 5 concurrent calls | 110/110 |
ros2_control | mock hardware + broadcaster → 2nd controller claiming interfaces → custom C++ SystemInterface plugin | 90/90 |
| Testing | pytest colcon test runs → launch_testing on a live node → rosbag2 written and read back | 110/110 |
| MoveIt 2 | self-authored URDF+SRDF move_group loads → real GetMotionPlan → collision object in the scene | 100/100 |
| Core | static TF from parameters → dynamic TF + ExtrapolationException → lifecycle node silent until activated | 110/110 |
| Nav2 | parameter file the servers accept → stack driven to active → costmap marking live scan obstacles | see below |
| Perception | cv_bridge round trip → CameraInfo projection → 16UC1 depth → PointCloud2 | 106/120 |
Not one failure was closed by supplying information. Four gaps were found, all behavioural:
| What the model does not do unaided | Baseline | What closed it | After |
|---|---|---|---|
| Verify against the install instead of answering from memory | 2/10 | one paragraph of CLAUDE.md | 10/10 (q=0.002) |
| Produce an exit-coded verdict rather than "looks right" | 0/10 | a bundled runnable script | 10/10 (q<0.001) |
| Run the QoS code it writes before shipping it | 5/10 | CLAUDE.md's "Done means it ran" | 9/10 (underpowered) |
| Run the Nav2 config it writes before shipping it | 0/10 | a task that requires reaching active | 30/30 |
The last row illustrates this principle most clearly. When asked only for a Nav2 parameter file, all 10 evaluation runs produced configurations that Nav2 servers refused to load. However, when asked for the parameter file and required to bring the stack to an active state, every run encountered the exact same configuration error, diagnosed it from logs, fixed it, and passed. Same model, same misconception, zero difference in information — only the requirement to run and verify differed.
Consequence for this pack. Six domain skills were deleted in full, in addition to the two deleted earlier: the model already reaches their content independently, and no descriptive prose in this repository ever improved a benchmark check. What remains is a 30-line protocol, four runnable scripts, and the reference material behind them. Method, per-domain results, and raw runs: evals/.
Option A — Plugin Marketplace (Recommended):
/plugin marketplace add Leehyunbin0131/claude-ros2-skills
/plugin install claude-ros2-skills@claude-ros2-skills
Update installed plugins anytime with /plugin marketplace update.
Option B — Manual Installation:
git clone https://github.com/Leehyunbin0131/claude-ros2-skills.git
# Project-level installation (applies to the current project only)
mkdir -p your-project/.claude/skills
cp -r claude-ros2-skills/skills/* your-project/.claude/skills/
cp claude-ros2-skills/CLAUDE.md your-project/
# User-level installation (applies across all projects)
mkdir -p ~/.claude/skills
cp -r claude-ros2-skills/skills/* ~/.claude/skills/
Restart Claude Code (or start a new session) to apply the installed skills.
| Skill | Path | Coverage |
|---|---|---|
| ros2-troubleshooting | skills/ros2-troubleshooting/SKILL.md | Four runnable pass/fail checks — QoS compatibility, TF tree, IMU mount, odometry direction — plus REP 103/105 frame conventions, Jazzy runtime behaviour, and hardware odometry calibration behind them |
| ros2-microros | skills/ros2-microros/SKILL.md | micro-ROS Agent, rclc client API, custom transports, static memory |
Why only two. Every other skill was measured against a baseline agent that
had no skill loaded, and deleted when the agent produced the same result without
it — ros2-core, ros2-dev, ros2-control, ros2-moveit, ros2-perception,
ros2-testing, ros2-package and gazebo-sim, in that order of measurement.
ros2-microros is the one domain with no ladder: the hardware to run one
against is not available here, so it is kept and not claimed as verified.
See Evals.
These verification scripts are bundled within the ros2-troubleshooting skill (skills/ros2-troubleshooting/scripts/) and are included with every installation. They convert physical hardware checks into executable pass/fail verification steps (requires a sourced ROS 2 environment; return codes: 0 = PASS, 1 = FAIL, 2 = NO DATA):
| Script | Verifies |
|---|---|
check_imu_gravity.py | Validates that a robot at rest measures gravity at ~+9.81 m/s² along the +Z axis (REP 103). Detects inverted or misaligned IMU mountings. |
check_odom_direction.py | Validates that pushing the robot forward produces positive odometry displacement along its heading. Detects inverted motor directions, encoder polarity issues, or inverted TF setups. |
check_tf_tree.py | Verifies that map→odom→base_link resolves correctly; displays each sensor mounting offset in RPY degrees and highlights potential 180° orientation errors. |
check_qos_compat.py | Verifies QoS compatibility across all publisher/subscriber pairs on a topic using DDS rules. Prevents silent failures (such as a BEST_EFFORT publisher paired with a RELIABLE subscriber, or mismatches in durability, deadline, and liveliness). |
The core decision logic is unit-tested independently of ROS (python3 skills/ros2-troubleshooting/scripts/test_checks.py) and runs via continuous integration (CI) on every push.
flowchart LR
A["your request"] --> B["CLAUDE.md<br/>protocol + gates,<br/>no API details"]
B --> D["/opt/ros/jazzy/<br/>or official Jazzy docs"]
B -.runtime fault.-> C["ros2-troubleshooting<br/>runnable checks"]
C -.only if needed.-> R["references/<br/>frames, runtime,<br/>calibration"]
D --> E["code, then proof it ran"]
C --> E
R --> E
CLAUDE.md contains no specific API details. Instead, it establishes the operational protocol: verify settings against the local environment, identify operational unknowns up front, and consider a task finished only when execution is observed. Domain knowledge is left to the model and the installed environment, as empirical evals showed descriptive prose added no value. The ros2-troubleshooting skill is invoked only when a system appears healthy in logs but fails at runtime, providing actionable exit codes rather than descriptive text. See CLAUDE.md for details.
cd claude-ros2-skills
git pull
cp -r skills/* ~/.claude/skills/ # or your project's .claude/skills/
Summary: New skill content must prove its value against an unassisted baseline agent through empirical testing (a real task, 10 runs per condition, graded by executing the output). Content that the model generates unaided will not be included, regardless of correctness. Verification scripts must maintain pure decision logic so they can be unit-tested independently of ROS. For the evaluation protocol, checklists, and issue templates, see CONTRIBUTING.md.
Apache-2.0 — see LICENSE.
.claude-plugin/
marketplace.json
.github/
ISSUE_TEMPLATE/
skill-request.md
wrong-symbol-or-link.md
workflows/
ci.yml
.gitignore
assets/
eval-chart.svg
hero.png
CLAUDE.md
CONTRIBUTING.md
evals/
AUTHORING.md
CAPABILITIES.md
harness/
analyze_v2.py
camera_publisher.py
cor1_check.sh
cor2_check.sh
cor3_check.sh
ctl1_check.sh
ctl2_check.sh
ctl3_check.sh
dev1_check.sh
dev2_check.sh
dev3_check.sh
dev3_scenario.sh
fake_camera_pub.py
fake_imu_pub.py
fake_scan_pub.py
g1_check.sh
g2_check.sh
g3_check.sh
grade_v2.py
gzshim/
gz
heartbeat_monitor.py
isolate_cell.sh
isolate_guardrail.sh
mvt1_check.sh
mvt2_check.sh
mvt3_check.sh
per1_check.sh
per2_check.sh
per3_check.sh
qos_publishers.py
qos1_check.sh
README.md
reliable_image_sub.py
run_ab.sh
slow_trigger_server.py
summarize_run.py
t1_diffdrive_scenario.sh
t5_check.sh
t6_check.sh
t7_check.sh
task3_scenario.sh
tick_publisher.py
tr1_check.sh
tr2_check.sh
tr3_check.sh
tst1_check.sh
tst2_check.sh
tst3_check.sh
LADDER.md
runs/
2026-07-31-sweep-L1/
ctl1/
r1/
bringup.launch.py
bringup.log
bringup.sh
controllers.yaml
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
system.urdf
r10/
bringup.log
bringup.sh
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
r2/
bringup.sh
controllers.yaml
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
robot.urdf
r3/
bringup.log
bringup.sh
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
r4/
bringup.launch.py
bringup.log
bringup.sh
controllers.yaml
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
system.urdf
r5/
bringup.sh
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
r6/
bringup.sh
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
r7/
bringup.log
bringup.sh
controllers.yaml
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
mock_robot.urdf.xacro
r8/
bringup.log
bringup.sh
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
r9/
bringup.sh
ctl1-baseline_check.json
ctl1-baseline_final.md
ctl1-baseline_result.jsonl
mvt1/
mvt1-DISCARDED-mid-round-edit/
r1/
bringup.log
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r10/
mvt1-baseline_result.jsonl
r2/
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r3/
mvt1-baseline_result.jsonl
r4/
mvt1-baseline_result.jsonl
r5/
mvt1-baseline_result.jsonl
r6/
mvt1-baseline_result.jsonl
r7/
mvt1-baseline_result.jsonl
r8/
mvt1-baseline_result.jsonl
r9/
mvt1-baseline_result.jsonl
mvt1-rerun.log
r1/
bringup.sh
move_group.log
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r10/
bringup.sh
move_group.log
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r2/
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r3/
bringup.sh
move_group_bringup.log
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r4/
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r5/
bringup.log
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r6/
bringup.sh
move_group_bringup.log
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r7/
bringup.log
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r8/
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
r9/
bringup.sh
mvt1-baseline_check.json
mvt1-baseline_final.md
mvt1-baseline_result.jsonl
per1/
r1/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r10/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r2/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r3/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r4/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r5/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r6/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r7/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r8/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
r9/
node.py
per1_scenario.log
per1-baseline_check.json
per1-baseline_final.md
per1-baseline_result.jsonl
round.log
tst1/
r1/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r10/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r2/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r3/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r4/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r5/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r6/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r7/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r8/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
r9/
tst1-baseline_check.json
tst1-baseline_final.md
tst1-baseline_result.jsonl
2026-07-31-sweep-L2/
ctl2/
r1/
bringup.sh
controller_manager.log
controllers.yaml
ctl2-baseline_check.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
robot_state_publisher.log
robot.urdf
spawn_joint_state_broadcaster.log
spawn_position_controller.log
r10/
bringup.sh
controllers.yaml
ctl2-baseline_check.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
robot.urdf
r2/
bringup.sh
controllers.yaml
ctl2-baseline_check.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
robot.urdf
r3/
bringup_launch.py
bringup.log
bringup.sh
ctl2-baseline_check.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
r4/
bringup.launch.py
bringup.log
bringup.sh
controllers.yaml
ctl2-baseline_check.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
robot.urdf
r5/
bringup.sh
ctl2-baseline_check.json
ctl2-baseline_check.regraded.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
r6/
bringup.sh
controllers.yaml
ctl2-baseline_check.json
ctl2-baseline_check.regraded.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
mock_robot.urdf.xacro
r7/
ctl2-baseline_check.regraded.json
ctl2-baseline_result.jsonl
r8/
ctl2-baseline_check.regraded.json
ctl2-baseline_result.jsonl
r9/
bringup.sh
controllers.yaml
ctl2-baseline_check.json
ctl2-baseline_final.md
ctl2-baseline_result.jsonl
system.urdf
mvt2/
r1/
bringup.sh
move_group.log
... 865 more© 2026 Flowy · Free and open source
Built for Claude Code · Not affiliated with Anthropic