agents/openai.yaml
interface:
display_name: "SRDF"
short_description: "Author and validate MoveIt2 SRDF semantics."
default_prompt: "Use $srdf to author and validate MoveIt2 SRDF files as direct XML paired with their URDF, then hand new or changed SRDFs to $cad-viewer for review and optional MoveIt2 controls."
LICENSE
MIT License
Copyright (c) 2026 Thompson Labs LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
references/authoring-contract.md
# SRDF Authoring Contract
Use this reference when writing or editing SRDF XML directly. The `.srdf` file is the source of truth and must be auditable on its own: planning intent and provenance live in the file, and the paired URDF is found by convention.
## File Shape
Every authored `.srdf` follows this shape, in this order:
1. XML declaration: `<?xml version="1.0"?>`.
2. Planning-ledger comment block (compact form of `references/planning-ledger.md`).
3. One `<robot>` root with the **same `name` as the paired URDF**: `<robot name="...">`.
4. `<virtual_joint>` elements, then `<group>`, `<group_state>`, `<end_effector>`, `<passive_joint>`, `<disable_collisions>` — grouped by element type, in that order.
Keep two-space indentation. Comment nontrivial decisions inline (why a chain tip, why a pair is disabled).
## URDF Pairing (non-negotiable)
An SRDF pairs with its URDF by **colocation and robot name** — nothing else:
- Save the `.srdf` in the **same folder** as the `.urdf` it describes.
- Both files declare the identical `<robot name="...">`.
- Exactly one `.urdf` in that folder may declare that robot name; the validator and the CAD Viewer resolve the pairing by scanning the folder, and they error when zero or several URDFs match.
- Matching basenames (`so101.srdf` next to `so101.urdf`) are conventional and recommended for readability, but the robot name is what pairs the files. Multiple SRDF planning variants for one robot (`so101_dual.srdf`, `so101_precise.srdf`) all pair with the same URDF through its name.
- There is no link element: an SRDF pairs with the same-folder URDF whose robot name matches.
## Names Come From the URDF Table
Every `link`, `joint`, `base_link`, `tip_link`, `parent_link`, and group-state joint name must be copied from the extracted URDF table (see `references/srdf-workflow.md`). Never type a name from memory or from a similar robot; near-miss names (`wrist_roll` vs `wrist_roll_joint`) are the most common SRDF defect and validation will reject them.
## Element Contract
- `<group>`: prefer exactly one `<chain base_link tip_link>` for a serial manipulator — base to tip must be a real parent→child path in the URDF tree. Use explicit `<joint>`/`<link>` members for non-chain groups (grippers, heads), and `<group>` subgroups for unions (dual-arm, whole-body). Do not mix representations in one group without reason.
- `<group_state name group>`: one `<joint name value>` per **movable, non-mimic** joint in the group. Radians for revolute/continuous, meters for prismatic, values within URDF limits.
- `<end_effector name parent_link group parent_group>`: the EE group must not share links with `parent_group`; `parent_link` belongs to the parent group (or is adjacent to the EE group) and is typically the attachment/flange link.
- `<virtual_joint name type parent_frame child_link>`: attaches the robot root to an external frame (`world`). `fixed` for fixed-base arms; `planar`/`floating` only when planning genuinely needs that freedom.
- `<passive_joint name>`: unactuated joints that planners must not command.
- `<disable_collisions link1 link2 reason>`: evidence-backed only; see `references/disabled-collisions.md`. No duplicate or reversed-duplicate pairs.
## Golden Skeleton
```xml
<?xml version="1.0"?>
<!--
srdf: example_arm | urdf: example_arm.urdf | task: arm IK + gripper control
groups: arm (chain base_link->tool0), gripper (joint members)
states: home, ready (radians, within URDF limits)
disabled collisions: URDF-adjacent pairs only (reason Adjacent)
assumptions: tool0 is the TCP; no sampled collision matrix yet
-->
<robot name="example_arm">
<virtual_joint name="world_to_base" type="fixed" parent_frame="world" child_link="base_footprint" />
<group name="arm">
<chain base_link="base_link" tip_link="tool0" />
</group>
<group name="gripper">
<joint name="finger_joint" />
</group>
<group_state name="home" group="arm">
<joint name="shoulder_pitch" value="0" />
<joint name="elbow_pitch" value="0" />
<joint name="wrist_roll" value="0" />
</group_state>
<end_effector name="gripper_eef" parent_link="tool0" group="gripper" parent_group="arm" />
<disable_collisions link1="base_link" link2="shoulder_link" reason="Adjacent" />
</robot>
```
## Helper Scripts
Adjacent-pair lists, subgroup unions for many-jointed robots, and degree-to-radian tables are computations: derive them with a short throwaway script over the URDF rather than by hand when the robot has more than a handful of joints. The script is scaffolding; the checked-in `.srdf` remains canonical.
references/disabled-collisions.md
# SRDF disabled collisions
Disabled collisions are planning-safety data. Treat them as derived evidence, not as decorative XML.
## Valid sources
Use one of these sources:
- adjacent-link policy from the URDF kinematic graph;
- MoveIt Setup Assistant self-collision matrix generation;
- sampled collision analysis from a known MoveIt configuration;
- explicit user-provided collision matrix;
- a manually reviewed pair with a specific rationale.
Do not infer disabled collision pairs from visual theme or vague prose.
## XML shape
```xml
<disable_collisions link1="base_link" link2="shoulder_link" reason="Adjacent"/>
```
The current runtime requires:
- `link1` and `link2`;
- both links to exist in the URDF;
- distinct link names;
- a non-empty `reason`;
- no duplicate or reversed duplicate pairs.
## Reason and provenance
Use truthful reasons. Examples:
| Reason | Typical source |
|---|---|
| `Adjacent` | URDF graph adjacency |
| `Never` | Setup Assistant sampled matrix |
| `Always` | Setup Assistant sampled matrix |
| `Default` | Setup Assistant sampled matrix |
| `Manual: tool fixture is outside workspace envelope` | Explicit human review |
The current parser classifies reasons into broad provenance buckets such as adjacent, sampled, setup assistant, manual, or assumed. Avoid `assumed` unless the user explicitly requested a provisional SRDF and the risk is reported.
## Review checklist
Before committing a disabled collision pair:
- Is the pair adjacent or sampled-safe?
- Does disabling the pair hide a possible real collision during the planned task?
- Was the pair generated with sufficient sampling density?
- Is the pair still valid after geometry, limits, or group membership changed?
- Was manual rationale written down?
If many manual pairs are present, prefer regenerating the self-collision matrix with MoveIt Setup Assistant.
references/end-effectors.md
# SRDF end effectors
Use this reference when creating or editing `<end_effector>` entries.
## Concept
An end effector is a semantic designation for a tool, gripper, sensor head, or other terminal group. It is typically connected to a parent planning group through a fixed joint or attachment link.
Typical shape:
```xml
<group name="gripper">
<joint name="finger_joint"/>
</group>
<end_effector
name="gripper_eef"
parent_link="tool0"
group="gripper"
parent_group="manipulator"/>
```
## Required ledger fields
Record:
- end-effector name;
- end-effector group;
- parent planning group;
- parent link where the end effector attaches;
- target/TCP link used for IK and planning;
- whether the end-effector group overlaps the parent group;
- whether the parent link is adjacent to the end-effector group in the URDF graph.
## Checks
Before authoring:
- The end-effector group exists.
- The parent group exists when specified.
- The parent link exists in the URDF.
- The end-effector group and parent group do not share links.
- The parent link is in the parent group or adjacent to the end-effector group.
- The target/TCP link is explicit when it differs from the inferred group tip.
The current runtime enforces several of these checks, but target/TCP choice remains a semantic decision. Do not rely on inference when planning to a tool center point.
## Handoff
When handing an SRDF to another tool or reviewer, state the intended target/TCP link explicitly whenever it differs from the inferred group tip — target choice is a semantic decision no consumer can infer.
references/planning-ledger.md
# SRDF planning ledger
Create or update this ledger before writing SRDF XML. The ledger makes planning assumptions explicit and helps prevent plausible but incorrect MoveIt configurations.
## URDF dependency
| Field | Value |
|---|---|
| URDF path | |
| SRDF output path | |
| Robot name | |
| URDF validated? | yes/no; tool/check |
| Root link | |
| Active joints | |
| Fixed joints | |
| Mimic joints | |
| Passive joints | |
| Links used for collision checking | |
| Known URDF limitations | |
## Planning task
| Field | Value |
|---|---|
| Main task | IK / plan-to-pose / gripper / mobile base / dual arm / other |
| Primary planning group | |
| Expected end-effector or TCP | |
| Required solver or planner | |
| Position-only IK? | yes/no; reason |
| Orientation constraints? | yes/no; representation |
## Virtual joints
| Name | Type | Parent frame | Child link | Required? | Rationale |
|---|---|---|---|---|---|
| | fixed / planar / floating | | | | |
Virtual joints describe the robot root pose relative to an external frame. Use fixed for fixed-base manipulators when the planning setup needs a world attachment; use planar/floating only when the robot model requires that planning freedom.
## Passive joints
| Joint | URDF type | Reason passive | Affected groups | Notes |
|---|---|---|---|---|
| | | | | |
Passive joints are unactuated. They should not be treated as controllable planning variables.
## Planning groups
| Group | Representation | Members | Base link | Tip link | Active joints | Excluded joints | Purpose | Solver expectation |
|---|---|---|---|---|---|---|---|---|
| | joints / links / chain / subgroups | | | | | | | |
For serial arms, prefer a chain only when the URDF graph has a real path from base link to tip link. For subgroup groups, check for cycles and duplicate semantics.
## End effectors
| Name | End-effector group | Parent group | Parent link | Target/TCP link | Overlap checked? | Adjacent? | Notes |
|---|---|---|---|---|---|---|---|
| | | | | | | | |
The end-effector group should normally not share links with its parent group. The target/TCP link should be explicit when it differs from the inferred group tip.
## Group states
| State | Group | Joint values | Unit check | Limit check | Purpose |
|---|---|---|---|---|---|
| | | revolute/continuous rad; prismatic m | | | |
Do not store degrees in SRDF group states. Do not set fixed or mimic joints in group states.
## Disabled collisions
| Link 1 | Link 2 | Reason | Source | Evidence | Risk note |
|---|---|---|---|---|---|
| | | Adjacent / Never / Always / Default / Manual | Setup Assistant / sampled / adjacency / user | | |
Do not infer disabled collisions from visual impression. Each pair needs a reason and provenance.
## MoveIt smoke tests
| Test | Group | Target link | Target pose/state | Expected result | Actual result | Notes |
|---|---|---|---|---|---|---|
| IK solve | | | | | | |
| Plan-to-pose | | | | | | |
| Named state | | | | | | |
| Collision check | | | | | | |
## Assumptions to report
List every guessed or inferred value:
- planning group membership;
- chain base/tip;
- target/TCP link;
- virtual joint attachment;
- passive joint classification;
- group-state value;
- disabled collision pair;
- solver or planner setting;
- orientation/position-only IK assumption;
- skipped MoveIt validation.
references/srdf-workflow.md
# SRDF Workflow
Use this reference when creating or editing MoveIt planning semantics for an existing URDF.
## Step 0: Extract the URDF Table
Do this before writing any SRDF XML. Parse the paired URDF (read it, or run a three-line ElementTree script for large robots) and write down:
- robot `name` (the SRDF must match it exactly);
- every link name;
- every joint: name, type, parent link, child link, lower/upper limits, and whether it has `<mimic>`;
- the root link and the main serial chains (walk parent→child).
Every name that appears in the SRDF is **copied from this table**. If a name you want is not in the table, the URDF is wrong or your assumption is — resolve that first with `$urdf`. This single habit eliminates the most common SRDF failure class: plausible near-miss names and chains that do not exist in the tree.
## Edit Loop
1. Confirm the URDF is valid (`$urdf` validator) and extract the URDF table.
2. Read or create the planning ledger (`references/planning-ledger.md`); keep the compact form as a comment block in the `.srdf`.
3. Author or edit the SRDF XML directly per `references/authoring-contract.md`, in element order: virtual joints, groups, group states, end effectors, passive joints, disabled collisions. Save it next to the URDF with the same robot name — colocation plus name match is how every consumer pairs the files.
4. Derive — do not invent — disabled collisions (`references/disabled-collisions.md`) and group-state values (URDF-native units, within limits).
5. Validate with `cadgen srdf validate <file.srdf>`; fix findings until clean.
6. Hand the file to `$cad-viewer` and return the live review link.
7. Run MoveIt smoke tests when a MoveIt environment is available; otherwise report them skipped.
8. Report assumptions: inferred TCP links, manual collision pairs, unverified planner behavior.
## Group Design
- **Serial manipulator** → one chain group, `base_link` at the mount, `tip_link` at the flange/TCP link. The validator rejects chains that are not a real parent→child path.
- **Gripper / hand** → joint-member group listing its actuated joints; it becomes the end-effector group.
- **Dual-arm / whole-body** → subgroup unions. Check for duplicate semantics (a joint reachable through two subgroups) and cycles.
- **Mobile base** → typically a planar/floating virtual joint plus a group for the base; do not model wheel joints as planning DOF unless the planner consumes them.
Fixed and mimic joints are never planning variables: they do not belong in group states, and chain-derived groups exclude them automatically.
## When the URDF Changes
Renamed links or joints, changed limits, or restructured chains invalidate the SRDF silently. After any URDF edit, re-run the SRDF validator on the paired `.srdf`, and re-check group states against the new limits. Treat URDF+SRDF as a pair in every task that touches either.
references/validation.md
# SRDF Validation and Verification
Every created or modified `.srdf` runs this recipe before the task is reported complete.
## Recipe
1. **Bundled validator** (always): `cadgen srdf validate path/to/robot.srdf`. It collects *all* findings in one pass (severity, code, XML path); fix them and re-run until clean. Use `--strict` to fail on warnings and `--json` for machine-readable output.
2. **Viewer review** (whenever `$cad-viewer` is available): load the SRDF, confirm the paired URDF resolves and renders, and exercise named group states.
3. **MoveIt smoke test** (when a MoveIt environment is available): load the URDF+SRDF pair in MoveIt Setup Assistant or a project launch; solve IK for the primary group; plan to a named state. Report as skipped when unavailable.
## What the Bundled Validator Checks
Structure and linkage:
- root is `<robot>` with a non-empty name;
- a paired URDF resolves: exactly one `.urdf` in the same folder declares the SRDF's robot name (`no_paired_urdf` / `ambiguous_paired_urdf` errors otherwise); a leftover `<tcad:urdf>`/`<explorer:urdf>` element warns as deprecated and is ignored;
- unique group, end-effector, group-state, and collision-pair identities.
Against the paired URDF:
- every group joint/link/subgroup name exists (joints in the URDF, links in the URDF, subgroups in the SRDF);
- every chain `base_link`/`tip_link` exists **and** the chain is a real parent→child path in the URDF tree;
- subgroup references contain no cycles;
- at least one planning group is defined;
- virtual joints: valid type (`fixed`/`floating`/`planar`), non-empty `parent_frame`, `child_link` exists in the URDF (name collisions with URDF joints warn);
- passive joints exist in the URDF and are never set by group states;
- end effectors: group exists, parent group exists when named, parent link exists, no link overlap between EE group and parent group, parent link in parent group or adjacent to the EE group;
- group states: group exists, each joint exists and belongs to the group, no fixed/mimic/passive joints, values within URDF revolute/prismatic limits; states that omit group joints warn (MoveIt fills them from the current state);
- disabled collisions: both links exist, distinct, non-empty reason, no (reversed) duplicates; pairs claiming reason `Adjacent` that are not actually joined by a URDF joint warn; warns when 25+ pairs are manually reasoned;
- unknown elements under `<robot>` or `<group>` warn — misspelled elements are otherwise silently ignored by MoveIt;
- a paired URDF that is not a single-rooted tree warns (chain/adjacency checks become unreliable).
## What Validation Cannot Prove
- That the planning group matches the user's task intent (right arm vs left arm).
- That the TCP/target link is the physically correct tool point.
- That disabled pairs are safe at every reachable configuration — only sampling (Setup Assistant) approaches that.
- That group-state poses are collision-free or useful.
These are semantic decisions: document them in the ledger and verify interactively in the viewer or MoveIt when confidence matters. Visual rendering review alone cannot prove planning correctness.
## Failure Handling
When validation fails against the URDF, decide which side is wrong before editing: a missing name may mean a typo in the SRDF **or** a rename in the URDF that invalidated existing semantics. Fix the owning file (`$urdf` for structure), then re-run the validator on the pair.
requirements.txt
cadgen[snapshot]==0.5.0
SKILL.md
---
name: srdf
description: MoveIt2 SRDF authoring, validation, and planning-semantics workflow. Use when creating, editing, inspecting, or validating `.srdf` files, MoveIt planning groups, virtual joints, passive joints, end effectors, group states, disabled collisions, URDF-paired planning semantics, or SRDF handoff for live review. Use the URDF skill for robot structure, the SDF skill for simulator descriptions, and the cad-viewer skill for rendering and live review links.
---
# SRDF
Provenance: maintained in [earthtojake/text-to-cad](https://github.com/earthtojake/text-to-cad).
Use the installed local skill files as the runtime source of truth; the
repository link is only for provenance and release review.
Use this skill for MoveIt semantic robot descriptions on top of an existing valid URDF. SRDF defines planning semantics; it does not define physical robot structure. The `.srdf` file is the source of truth: author and edit the XML directly. There is no `gen_srdf()` contract.
SRDF correctness is a **planning semantics** problem. The common failure is not invalid XML; it is a plausible SRDF that gives MoveIt the wrong planning group, wrong tool link, wrong default state, unsafe disabled-collision matrix, or wrong joint units. Because language models are weak at spatial and kinematic reasoning, derive planning groups, end effectors, group states, and disabled collisions from the URDF topology, MoveIt Setup Assistant output, sampled collision analysis, or explicit user data. Do not infer them from visual theme alone — and do not type any link or joint name from memory: extract the URDF's link/joint table first and copy names from it.
## Setup
This skill's commands are thin entrypoints over the `cadgen` distribution, which
carries the Python build runtime and the JavaScript it executes. Install it once:
```bash
python -m pip install -r requirements.txt
```
Rendering additionally needs a browser, which pip cannot supply:
```bash
python -m playwright install chromium
```
## Format boundary
- **URDF** owns physical robot structure: links, joints, geometry, inertials, limits, mimic joints, transmissions, and robot-state publishing.
- **SRDF** owns MoveIt semantics: virtual joints, passive joints, planning groups, group states, end effectors, and disabled collision pairs.
- **SDF** owns simulator/world semantics: physics, sensors, lights, plugins, worlds, and simulation-specific metadata.
Do not place geometry, inertials, joint origins, link poses, mesh references, physical joint limits, transmissions, or `ros2_control` interfaces in SRDF.
## CAD Viewer Handoff
After completing SRDF work that creates or modifies a `.srdf`, you must ALWAYS hand the explicit file path to `$cad-viewer` when that skill is installed. `$cad-viewer` must start CAD Viewer if it is not already running and return link(s) to the relevant created or updated file(s). If `$cad-viewer` is unavailable or startup fails, report that instead of silently omitting the handoff.
## Required workflow
1. **Start from a valid URDF.** Author or fix the URDF first with `$urdf` and validate it. The SRDF pairs with that URDF by colocation and robot name, and every name in the SRDF must exist in it.
2. **Extract the URDF table.** Before writing any SRDF XML, list the URDF's robot name, links, joints (with type, parent, child, limits, mimic flags). Copy names from this table only; never type them from memory. See `references/srdf-workflow.md`.
3. **Identify the planning task.** Record whether the goal is arm IK, gripper control, mobile base planning, dual-arm planning, tool use, or local smoke testing.
4. **Create or update the planning ledger.** Use `references/planning-ledger.md` before writing XML; keep a compact copy as a comment block in the `.srdf`.
5. **Pair with the URDF by colocation.** Save the `.srdf` in the same folder as its `.urdf`, with the same `<robot name>` — that is the only linking mechanism. The validator and the viewer both resolve the pairing by scanning the folder for the URDF whose robot name matches; exactly one URDF per robot name per folder. No metadata element links the files. See `references/authoring-contract.md`.
6. **Define virtual and passive joints deliberately.** Use them when needed by the robot model.
7. **Define planning groups from URDF topology.** Prefer chain groups for serial manipulators when base/tip form a real parent-to-child path in the URDF tree (the validator verifies this). Use joint/link/subgroup definitions only when they are deliberate.
8. **Define end effectors after group membership is known.** Avoid overlap between an end-effector group and its parent group. Record the actual target/TCP link.
9. **Define group states in URDF-native units.** Revolute and continuous values are radians; prismatic values are meters. Do not store degrees in SRDF. Values must lie within URDF limits and must not set fixed or mimic joints.
10. **Generate disabled collisions from evidence.** Use adjacency derived from the URDF joint table, MoveIt Setup Assistant sampling, or explicit user-provided collision matrices. Do not invent broad disable lists. See `references/disabled-collisions.md`.
11. **Validate every created or modified `.srdf`** with `cadgen srdf validate`; it cross-validates all names, chains, states, and pairs against the paired URDF. Fix findings and re-validate until clean.
12. **Run MoveIt smoke tests when available.** Use MoveIt Setup Assistant or a project MoveIt launch directly.
13. **Report assumptions and skipped checks.** Include incomplete validation, missing MoveIt environment, manually reasoned collision disables, and inferred target links.
## Commands
Run with the Python environment for the project or workspace. Treat `python` in examples as an interpreter placeholder; if bare `python` is unavailable, substitute `python3`, a project virtualenv interpreter, or the configured interpreter path. The validator uses only the Python standard library.
The validator shape is:
```bash
cadgen srdf validate path/to/robot.srdf
cadgen srdf validate path/to/robot.srdf --strict
cadgen srdf validate path/to/robot.srdf --json
```
The validator collects all findings in one pass (severity, code, XML path). It parses the SRDF, resolves the paired URDF (the same-folder `.urdf` whose robot name matches; none or several is an error), and cross-validates: group/joint/link/subgroup name existence, chain path resolvability, subgroup cycles, virtual/passive joints, end-effector topology, group-state membership/limits/completeness, disabled-collision pairs (including Adjacent-reason truthfulness), and misspelled elements. One run validates ONE file: `--strict` treats warnings as failures and `--json` emits the machine-readable findings document. It exits nonzero if the target fails. Relative targets resolve from the current working directory.
## Hard rules
- The SRDF lives in the same folder as its URDF and shares its `<robot name>`; that colocation-plus-name match is the only pairing mechanism, and exactly one URDF per robot name may exist in the folder.
- Every link, joint, group, and subgroup name must come from the URDF table or a group defined in the same file.
- Group states use URDF-native units: radians for revolute/continuous, meters for prismatic.
- Disabled collision pairs require truthful reasons and provenance.
- End-effector groups should not share links with their parent planning group.
- Visual rendering review is useful but cannot prove planning correctness.
## Snapshot Tool
`cadgen snapshot` renders the robot to a PNG still, using the same shared
CLI and headless browser runtime every rendering skill uses — so a snapshot matches what
the CAD Viewer shows.
```bash
cadgen snapshot path/to/robot.srdf review.png
```
Hand it the `.srdf`; it routes by suffix and renders the paired URDF's geometry. Pose the robot with `--joint-values` — `{joint: degrees}` JSON,
joints you do not name staying at the rest pose (the `"jointValues"` job field is the same
thing in a packet). Robots are authored in metres and are framed on the robot scene scale
automatically.
Theme settings live under one `--theme`, mirroring the viewer's Theme tab. The default
theme is `snapshot` — Workbench Light with the ground grid, origin axis and shadows
removed, because in a still image those read as geometry. Leave `--display` off: display
settings (mode, clip, exploded, edges) are CAD topology settings, and a robot carries none.
Link meshes are resolved relative to the description, so they must be present: an
unhydrated Git LFS pointer fails as "No link mesh loaded for robot". Run
`git lfs checkout <mesh dir>` first.
An SRDF's geometry comes from the URDF beside it, so it has no snapshot door of its
own; the polymorphic `cadgen snapshot` routes one by suffix. The grammar is
`cadgen snapshot TARGET [OUT] [flags]`, the same one every format door uses. Use
`cadgen snapshot --help` for the complete current interface.
## References
- Authoring contract (structure, URDF pairing, golden skeleton): `references/authoring-contract.md`
- SRDF workflow (URDF table extraction, edit loop): `references/srdf-workflow.md`
- Planning ledger: `references/planning-ledger.md`
- Validation and verification recipe: `references/validation.md`
- End effectors: `references/end-effectors.md`
- Disabled collisions: `references/disabled-collisions.md`