Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 36 additions & 33 deletions .agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,38 @@ This directory contains Agent Skills following the [Agent Skills standard](https
```
.agents/
├── README.md # This file
└── skills/ # Agent Skills directory
├── add-ros2-package/
│ └── SKILL.md # Create new ROS 2 packages
├── add-task-executor/
│ └── SKILL.md # Implement a task executor as a ROS 2 action server
├── integrate-module-into-layer/
│ └── SKILL.md # Integrate modules into layer bringup
├── write-isaac-sim-scene/
│ └── SKILL.md # Create Isaac Sim simulation scenes
├── debug-module/
│ └── SKILL.md # Autonomous debugging strategies
├── update-documentation/
│ └── SKILL.md # Document modules and update mkdocs
├── test-in-simulation/
│ └── SKILL.md # End-to-end simulation testing
└── add-behavior-tree-node/
└── SKILL.md # Create behavior tree nodes
└── skills/ # One directory per skill
└── <skill-name>/
├── SKILL.md # YAML frontmatter + step-by-step instructions
└── assets/ # (optional) templates and reference files
```

## Skills Overview

Each skill is a directory containing a `SKILL.md` file with:
- **YAML frontmatter:** Name, description, license, metadata
- **Markdown body:** Step-by-step instructions for the workflow

### Available Skills
## Available Skills

| Skill | Purpose |
|-------|---------|
| [add-ros2-package](skills/add-ros2-package) | Create a new ROS 2 package for the autonomy stack |
| [add-task-executor](skills/add-task-executor) | Implement a task executor as a ROS 2 action server |
| [integrate-module-into-layer](skills/integrate-module-into-layer) | Integrate a module into layer bringup |
| [write-isaac-sim-scene](skills/write-isaac-sim-scene) | Create custom simulation environments |
| [debug-module](skills/debug-module) | Systematically debug ROS 2 modules |
| [update-documentation](skills/update-documentation) | Document modules and update mkdocs |
| [test-in-simulation](skills/test-in-simulation) | Test modules in Isaac Sim |
| [add-behavior-tree-node](skills/add-behavior-tree-node) | Create behavior tree nodes |
| [add-behavior-tree-node](skills/add-behavior-tree-node) | Create behavior tree nodes for high-level mission logic |
| [add-ros2-package](skills/add-ros2-package) | Create a new ROS 2 package (module) from the template |
| [add-task-executor](skills/add-task-executor) | Implement a task executor as a ROS 2 action server (`tasks/*`) |
| [add-unit-tests](skills/add-unit-tests) | Add co-located Python/C++ unit tests and register them for CI |
| [attach-gossip-payload](skills/attach-gossip-payload) | Broadcast custom ROS messages to peers via PeerProfile gossip payloads |
| [bump-version-and-release](skills/bump-version-and-release) | Bump `.env` VERSION + CHANGELOG to clear the version-check gate |
| [capture-discovered-knowledge](skills/capture-discovered-knowledge) | Persist hard-won discoveries to AGENTS.md or a skill |
| [configure-multi-robot](skills/configure-multi-robot) | Multi-robot setup: replicas, ROBOT_NAME, ROS_DOMAIN_ID |
| [create-module](skills/create-module) | Author a thin module repo (module.yaml manifest, CI, test_stack) |
| [create-stack](skills/create-stack) | Create a stack folder: `airstack stack new`, wiring bootstrap, split stacks + bridge.yaml, doctor |
| [debug-module](skills/debug-module) | Systematic autonomous debugging of ROS 2 modules |
| [docker-build-profiles](skills/docker-build-profiles) | Build-time validation for Docker compose profiles and build args |
| [integrate-module-into-layer](skills/integrate-module-into-layer) | Integrate a module into a **stack** (stack entry include, canonical defaults, wiring.md regen, lint) — the layer-bringup workflow is legacy |
| [run-system-tests](skills/run-system-tests) | Run/extend the pytest system-test harness (marks, MetricsRecorder, /pytest) |
| [test-in-simulation](skills/test-in-simulation) | End-to-end module testing in Isaac Sim |
| [update-documentation](skills/update-documentation) | Document modules and update mkdocs navigation |
| [use-airstack-cli](skills/use-airstack-cli) | The `airstack` CLI and the non-interactive `docker exec` pattern |
| [use-feature-notebook](skills/use-feature-notebook) | Local notebook/ entry (design spec + results) for every feature |
| [visualize-in-foxglove](skills/visualize-in-foxglove) | Add topic visualization to Foxglove/GCS |
| [write-isaac-sim-scene](skills/write-isaac-sim-scene) | Create custom Isaac Sim scenes on pegasus_app |
| [write-launch-file](skills/write-launch-file) | Launch-file conventions: canonical-default topic args, ROBOT_NAME namespacing, single-locus rule |
| [write-mkdocs-documentation](skills/write-mkdocs-documentation) | Writing effective MkDocs documentation |

## Usage

Expand All @@ -62,12 +57,20 @@ When adding new skills:
2. Add `SKILL.md` with proper YAML frontmatter
3. Follow Agent Skills format specification
4. Reference related skills using relative paths (`../other-skill/`)
5. Update this README with the new skill
5. Update this README **and** the skills table in [AGENTS.md](../AGENTS.md)

Skills ship with the mechanism, not after it (RFC #379 §10): when a workflow
changes (e.g. layer bringups → stacks), update the affected skills in the same
PR as the machinery, or every agent session will faithfully reintroduce the
old pattern.

## References

- **Main Guide:** [AGENTS.md](../AGENTS.md)
- **Agent Skills Spec:** [https://agentskills.io](https://agentskills.io)
- **System Architecture:** [docs/robot/autonomy/system_architecture.md](../docs/robot/autonomy/system_architecture.md)
- **Interface Conventions Spec:** [docs/robot/autonomy/interface_conventions.md](../docs/robot/autonomy/interface_conventions.md)
- **Integration Checklist:** [docs/robot/autonomy/integration_checklist.md](../docs/robot/autonomy/integration_checklist.md)
- **Stacks Guide:** [docs/development/stacks.md](../docs/development/stacks.md)
- **Modules Guide:** [docs/development/modules.md](../docs/development/modules.md)
- **AI Agent Guide:** [docs/development/ai_agent_guide.md](../docs/development/ai_agent_guide.md)
45 changes: 26 additions & 19 deletions .agents/skills/add-ros2-package/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,33 +354,40 @@ Create `config/<package_name>.yaml` with default parameters:

### 8. Create Launch File

Create `launch/<package_name>.launch.xml` with topic remapping:
Create `launch/<package_name>.launch.xml` following the canonical module
launch pattern (RFC #379 §4 — see `.agents/skills/write-launch-file`):

```xml
<launch>
<!-- Launch arguments for topic remapping -->
<arg name="odometry_topic" default="/robot/odometry" />
<arg name="output_topic" default="/robot/cmd_vel" />
<arg name="config_file" default="$(find-pkg-share your_package_name)/config/your_package_name.yaml" />

<node pkg="your_package_name"
exec="your_node_name"
name="your_node_name"
output="screen">

<!-- Load parameters -->
<param from="$(var config_file)" allow_substs="true" />

<!-- Remap topics -->
<remap from="odometry" to="$(var odometry_topic)" />
<remap from="cmd_vel" to="$(var output_topic)" />
</node>
<!-- Prefixed, described args; defaults = the CANONICAL topic names -->
<arg name="your_module_odometry_topic" default="/$(env ROBOT_NAME)/odometry"
description="Input odometry (nav_msgs/Odometry)" />
<arg name="your_module_output_topic" default="/$(env ROBOT_NAME)/cmd_vel"
description="Output velocity command" />
<arg name="your_module_config"
default="$(find-pkg-share your_package_name)/config/your_package_name.yaml"
description="Node parameter YAML (loaded with allow_substs)" />

<group>
<!-- Bind the node's relative topic names to the declared args -->
<set_remap from="odometry" to="$(var your_module_odometry_topic)" />
<set_remap from="cmd_vel" to="$(var your_module_output_topic)" />

<node pkg="your_package_name"
exec="your_node_name"
name="your_node_name"
output="screen">
<!-- Load parameters -->
<param from="$(var your_module_config)" allow_substs="true" />
</node>
</group>
</launch>
```

**Key points:**
- Use `allow_substs="true"` to enable environment variable substitution in config files
- Define launch arguments for all topic names (enables flexible remapping)
- Declare a prefixed launch argument (with `description=`) for every topic endpoint, defaulting to the canonical name — never generic names like `config_file` (launch configurations leak across sibling includes)
- Use `set_remap` inside the module's group; module launch files never use `remap` tags — cross-module rewiring lives in the stack entry file (`stacks/<name>/launch/`), enforced by the single-locus lint (`tests/meta/test_launch_single_locus.py`)
- Use `$(var arg_name)` to reference launch arguments
- Use `$(env VAR_NAME)` for environment variables in configs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,12 @@ ros2 launch your_package your_package.launch.xml

# With custom config
ros2 launch your_package your_package.launch.xml \
config_file:=/path/to/custom/config.yaml
your_module_config:=/path/to/custom/config.yaml

# With topic remapping
# With custom topic wiring (prefixed args; in a stack these are include args)
ros2 launch your_package your_package.launch.xml \
odometry_topic:=/robot/custom_odom \
output_topic:=/robot/custom_output
your_module_odometry_topic:=/robot/custom_odom \
your_module_output_topic:=/robot/custom_output
```

### Integrated in Autonomy Stack
Expand Down
Original file line number Diff line number Diff line change
@@ -1,68 +1,77 @@
<!--
your_package_name : canonical module launch file (RFC #379 §2/§4).

Conventions this template follows (see .agents/skills/write-launch-file):
- Every topic endpoint is a declared <arg> with a description= and a
default equal to the CANONICAL topic name (docs/robot/autonomy/
integration_checklist.md), so a bare include means "wired canonically".
- Args are PREFIXED with the module name (never generic names like
`config_file` or `namespace` — generic launch configurations leak
across sibling includes in the same launch scope).
- Wiring uses set_remap inside the module's namespace group. Module launch
files never use remap tags — cross-module rewiring lives in the stack
entry file (stacks/<name>/launch/), the single-locus rule enforced by
tests/meta/test_launch_single_locus.py.
-->
<launch>
<!-- ============================================ -->
<!-- Launch Arguments -->
<!-- Launch Arguments (all prefixed + described) -->
<!-- ============================================ -->

<!-- TODO: Add launch arguments for configurability -->

<!-- Input topics (for remapping) -->
<arg name="odometry_topic" default="/$(env ROBOT_NAME)/odometry"
description="Odometry input topic"/>
<arg name="sensor_topic" default="/$(env ROBOT_NAME)/sensors/data"
description="Sensor data input topic"/>

<!-- Output topics (for remapping) -->
<arg name="output_topic" default="/$(env ROBOT_NAME)/your_module/output"

<!-- TODO: rename the your_module_ prefix to your module name -->

<!-- Namespace -->
<arg name="your_module_namespace" default="your_module"
description="Namespace to run in"/>

<!-- Input topics -->
<arg name="your_module_odometry_topic" default="/$(env ROBOT_NAME)/odometry"
description="Input odometry (nav_msgs/Odometry)"/>
<arg name="your_module_sensor_topic" default="/$(env ROBOT_NAME)/sensors/data"
description="Input sensor data"/>

<!-- Output topics -->
<arg name="your_module_output_topic" default="/$(env ROBOT_NAME)/your_module/output"
description="Module output topic"/>

<!-- Configuration -->
<arg name="config_file"
<arg name="your_module_config"
default="$(find-pkg-share your_package_name)/config/template.yaml"
description="Path to configuration file"/>

<!-- Namespace -->
<arg name="namespace" default="your_module"
description="Namespace for the node"/>

description="Node parameter YAML (loaded with allow_substs)"/>

<!-- Other options -->
<arg name="enable_debug" default="false"
<arg name="your_module_enable_debug" default="false"
description="Enable debug mode"/>

<!-- ============================================ -->
<!-- Node Launch -->
<!-- ============================================ -->

<group>
<!-- Apply namespace -->
<push-ros-namespace namespace="$(var namespace)" />

<push-ros-namespace namespace="$(var your_module_namespace)" />

<!-- Bind the node's relative topic names to the declared args.
Sources are the names the node uses in code (relative, resolved in
its namespace); targets are the absolute arg values. -->
<set_remap from="odometry" to="$(var your_module_odometry_topic)" />
<set_remap from="sensor_data" to="$(var your_module_sensor_topic)" />
<set_remap from="output" to="$(var your_module_output_topic)" />

<!-- TODO: Replace with your package/node name -->
<node pkg="your_package_name"
exec="your_node_name"
<node pkg="your_package_name"
exec="your_node_name"
name="your_node_name"
output="screen">

<!-- Load parameters from config file -->
<!-- allow_substs="true" enables environment variable substitution -->
<param from="$(var config_file)" allow_substs="true" />
<param from="$(var your_module_config)" allow_substs="true" />

<!-- Override specific parameters from launch args -->
<param name="enable_debug" value="$(var enable_debug)" />

<!-- ======================================== -->
<!-- Topic Remapping -->
<!-- ======================================== -->

<!-- Remap input topics -->
<remap from="odometry" to="$(var odometry_topic)" />
<remap from="sensor_data" to="$(var sensor_topic)" />

<!-- Remap output topics -->
<remap from="output" to="$(var output_topic)" />

<!-- TODO: Add additional topic remappings as needed -->

<param name="enable_debug" value="$(var your_module_enable_debug)" />

</node>
</group>

</launch>
Loading
Loading