Skip to main content
ClaudeWave
ES, Spanish
Skill215 estrellas del repoactualizado 4mo ago

new-system

# new-system This Claude Code skill scaffolds a complete Gazebo Sim system plugin by generating directory structure, C++ header and source files with lifecycle hooks (Configure, PreUpdate, PostUpdate), CMakeLists.txt integration, plugin registration boilerplate, and a test stub. Use it when building custom simulation behaviors that need to hook into the Gazebo Sim update loop via ISystem interfaces.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/harunkurtdev/ros2-claude-code-template /tmp/new-system && cp -r /tmp/new-system/.claude/skills/new-system ~/.claude/skills/new-system
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Adding a new system plugin

A system in gz-sim is a shared library that implements one or more of
`ISystemConfigure`, `ISystemPreUpdate`, `ISystemUpdate`, `ISystemPostUpdate`,
`ISystemReset` and gets loaded via SDF `<plugin>` or `<server_config>`.

Directory convention: `src/systems/<snake_case>/<CamelCase>.{hh,cc}`.

## Step 1 — pick the directory + filename

* Directory: `snake_case` matching the plugin's purpose (e.g.
  `fancy_drive`, `wheel_slip`).
* Class: `CamelCase` matching the directory (e.g. `FancyDrive`).
* SDF plugin name: `gz::sim::systems::<CamelCase>`.

## Step 2 — header template (`FancyDrive.hh`)

```cpp
#ifndef GZ_SIM_SYSTEMS_FANCYDRIVE_HH_
#define GZ_SIM_SYSTEMS_FANCYDRIVE_HH_

#include <memory>

#include <gz/sim/System.hh>
#include <gz/sim/config.hh>
#include <gz/utils/ImplPtr.hh>

namespace gz::sim
{
inline namespace GZ_SIM_VERSION_NAMESPACE {
namespace systems
{
  class FancyDrivePrivate;

  /// \brief One-paragraph description of what this system does.
  ///
  /// SDF parameters:
  ///   <param_a>  — what it does (default: ...)
  ///   <param_b>  — what it does (default: ...)
  class FancyDrive
    : public System,
      public ISystemConfigure,
      public ISystemPreUpdate,
      public ISystemPostUpdate
  {
    public: FancyDrive();
    public: ~FancyDrive() override;

    // System hooks
    public: void Configure(const Entity &_entity,
                           const std::shared_ptr<const sdf::Element> &_sdf,
                           EntityComponentManager &_ecm,
                           EventManager &_eventMgr) override;

    public: void PreUpdate(const UpdateInfo &_info,
                           EntityComponentManager &_ecm) override;

    public: void PostUpdate(const UpdateInfo &_info,
                            const EntityComponentManager &_ecm) override;

    /// \brief Private data via PIMPL.
    GZ_UTILS_UNIQUE_IMPL_PTR(dataPtr)
  };
}
}
}

#endif
```

## Step 3 — source template (`FancyDrive.cc`)

```cpp
#include "FancyDrive.hh"

#include <gz/plugin/Register.hh>
#include <gz/sim/Model.hh>
#include <gz/sim/components/JointVelocityCmd.hh>

namespace gz::sim::systems
{
class FancyDrivePrivate
{
  public: Model model{kNullEntity};
  // …cached handles, sdf params, transport node, etc.
};

FancyDrive::FancyDrive() : dataPtr(gz::utils::MakeUniqueImpl<FancyDrivePrivate>())
{
}

FancyDrive::~FancyDrive() = default;

void FancyDrive::Configure(const Entity &_entity,
                           const std::shared_ptr<const sdf::Element> &_sdf,
                           EntityComponentManager &_ecm,
                           EventManager &/*_eventMgr*/)
{
  this->dataPtr->model = Model(_entity);
  if (!this->dataPtr->model.Valid(_ecm))
  {
    gzerr << "FancyDrive should be attached to a model entity. "
          << "Failed to initialize." << std::endl;
    return;
  }
  // parse _sdf params here…
}

void FancyDrive::PreUpdate(const UpdateInfo &_info,
                           EntityComponentManager &_ecm)
{
  if (_info.paused) return;
  // mutate _ecm: set joint velocity cmds, etc.
}

void FancyDrive::PostUpdate(const UpdateInfo &_info,
                            const EntityComponentManager &_ecm)
{
  // read-only — publish telemetry, log, etc.
}
}  // namespace gz::sim::systems

GZ_ADD_PLUGIN(gz::sim::systems::FancyDrive,
              gz::sim::System,
              gz::sim::systems::FancyDrive::ISystemConfigure,
              gz::sim::systems::FancyDrive::ISystemPreUpdate,
              gz::sim::systems::FancyDrive::ISystemPostUpdate)

GZ_ADD_PLUGIN_ALIAS(gz::sim::systems::FancyDrive,
                    "gz::sim::systems::FancyDrive")
```

The alias is what users actually type in their `<plugin filename="..."
name="gz::sim::systems::FancyDrive">` tags — keep it stable across releases.

## Step 4 — local CMake (`src/systems/fancy_drive/CMakeLists.txt`)

```cmake
gz_add_system(fancy-drive
  SOURCES
    FancyDrive.cc
  PUBLIC_LINK_LIBS
    gz-common${GZ_COMMON_VER}::gz-common${GZ_COMMON_VER}
    gz-math${GZ_MATH_VER}::gz-math${GZ_MATH_VER}
    gz-transport${GZ_TRANSPORT_VER}::gz-transport${GZ_TRANSPORT_VER}
)
```

Use existing sibling directories as the source of truth — the macro name
and link-libs list differs by feature set.

## Step 5 — register with parent CMake (`src/systems/CMakeLists.txt`)

Add an `add_subdirectory(fancy_drive)` entry alphabetically.

## Step 6 — integration test (`test/integration/fancy_drive_system.cc`)

Minimum viable test:

```cpp
#include <gtest/gtest.h>
#include <gz/sim/Server.hh>
#include <gz/sim/TestFixture.hh>

TEST(FancyDriveTest, LoadsCleanly)
{
  gz::sim::TestFixture fixture("test/worlds/fancy_drive.sdf");
  fixture.Server()->Run(true, 100, false);
  // assertions on telemetry / final pose
}
```

Add the target in `test/integration/CMakeLists.txt`.

## Step 7 — example world

Add `examples/worlds/fancy_drive.sdf` with the minimum SDF a user needs
to try the system, and reference it from a short tutorial under
`tutorials/`.

## Step 8 — `Migration.md`

If the system is publicly named or replaces an older one, append a note
to `Migration.md`.

## Don't forget

* `pre-commit run --files <changed files>` before declaring done.
* Add the new system to `Changelog.md` under the upcoming-release section.
behaviortree_node_creationSkill

Scaffold a Behavior Tree leaf node — plain BehaviorTree.CPP (SyncActionNode / StatefulActionNode / ConditionNode) or a BehaviorTree.ROS2 wrapper (RosActionNode / RosServiceNode / RosTopicPubNode / RosTopicSubNode) — with ports, factory/plugin registration, and XML v4 usage. Trigger when the user asks to write a behavior-tree node (not Nav 2-specific).

behaviortree-reviewerSubagent

Use proactively before opening a PR that adds or changes BehaviorTree.CPP nodes or BehaviorTree.ROS2 wrappers (RosActionNode/RosServiceNode/RosTopicPub/SubNode, TreeExecutionServer). Reviews a diff against BT.CPP v4 conventions — node base-class choice, non-blocking ticks, ports/blackboard typing, factory/plugin registration, XML v4, and the ROS 2 wrapper contract. Returns a punch list with file:line anchors, not a rewrite.

buildSlash Command

Build the colcon workspace (optionally a single package) and report the outcome.

clean-arch-architectSubagent

Use when a design decision touches Clean Architecture boundaries in a ROS 2 project — which layer a new behaviour belongs to, whether a port belongs in domain or application, whether a new node should be lifecycle-managed, whether to compose nodes or split packages. Returns an architectural recommendation with trade-offs, not implementation.

commandsSkill

Author a new skill under .claude/skills/<name>/SKILL.md with valid frontmatter, following the template conventions, and index it in CLAUDE.md + README.md.

ecs-architectSubagent

Use when a design decision touches the gz-sim ECS — where new state should live, which system phase should write it, how to avoid coupling, whether to add a component vs. a member variable, whether a new system should be split or merged with an existing one. Returns an architectural recommendation with trade-offs, not implementation.

extending_claude_configSkill

Author a new asset for this .claude/ template — a rule, skill, slash command, or sub-agent — following the project's conventions and wiring it into the CLAUDE.md / README.md indexes. Trigger when the user wants to add or extend a command, skill, agent, or rule (make the template itself extensible).

gz-buildSkill

Configure and build gz-sim from source using either CMake/Ninja directly or a colcon workspace. Trigger when the user asks to build, recompile, configure, or set up the gz-sim binary tree.