Skip to main content

ROBOT.md: The Session-Start File for Every Agent That Drives a Robot

8 min read By Craig Merry
robot-md opencastor rcan robotics claude agents standards

Claude Code loads CLAUDE.md plus the current git state at session start. The planner begins warm: it knows the project conventions, the file layout, what not to touch, and how the codebase talks to itself. It doesn’t have to rediscover context — it arrives with it. That’s the whole trick, and it’s not magic. It’s just giving the model the right context before it starts work.

So what’s the robotics equivalent?

Not AGENTS.md (too configuration-y). Not URDF (describes what the robot is, not what it can do). Not the ROS parameter server (volatile, no history). Not event logs (no LLM context window can absorb 48 hours of raw motor telemetry). A single file at the robot’s root — declarative, schema-validated, read once at session start.

We shipped it today. It’s called ROBOT.md.

If you’ve ever written a CLAUDE.md, you already know how to write one.

What’s in one

Here’s the smallest valid ROBOT.md — a minimal wheeled robot with two degrees of freedom and a software E-stop:

---
rcan_version: "3.0"
metadata:
  robot_name: my-robot
physics:
  type: wheeled
  dof: 2
capabilities:
  - nav.move
safety:
  estop: { software: true, response_ms: 200 }
---

# my-robot

## Identity
Minimum robot for testing.

## What my-robot Can Do
- Drive forward/backward/turn.

## Safety Gates
- Stops on software E-stop within 200 ms.

Two blocks. YAML frontmatter on top — machine-readable, JSON-Schema-validated identity, physics, capabilities, safety. Markdown body underneath — the human and LLM-readable narrative the planner reads at session start.

A more substantial example — Bob, our reference 6-DOF arm:

---
rcan_version: "3.0"
metadata:
  robot_name: bob
  rrn: RRN-000000000003
physics:
  type: arm+camera
  dof: 6
drivers:
  - { id: arm_servos, protocol: feetech, port: /dev/ttyUSB0, count: 6 }
capabilities:
  - arm.pick
  - arm.place
  - vision.describe
safety:
  payload_kg: 0.5
  max_joint_velocity_dps: 180
  estop: { software: true, response_ms: 100 }
  hitl_gates:
    - { scope: destructive, require_auth: true }
---

That’s identity, capability, and safety envelope. Everything else is optional. One file. The whole declaration.

Why session-start is the right primitive

The adoption argument writes itself once you look at which agent harnesses already support session-start context injection:

  • Claude Code. A SessionStart hook in ~/.claude/settings.json runs a shell script before the first turn. Its stdout lands in the session context. Our v0.1 ships exactly this — a 15-line session-start.sh that runs robot-md context ./ROBOT.md and emits a block Claude reads immediately.
  • ChatGPT custom GPTs. An instructions field. Paste the prose body of ROBOT.md. Three clicks.
  • Gemini (AI Studio / Vertex). A system-instructions field. Same paste model.
  • Ollama. A SYSTEM directive in a modelfile. Same.
  • LangChain / AutoGen / CrewAI / Letta. A system-prompt slot. Same.

Every agent harness worth shipping already has a session-start slot. ROBOT.md fills it with the robot. No new SDK. No new protocol. No dependency on any particular runtime.

Three tiers of runtime. Pick whichever.

The point you’re about to read is the one I’d underline twice if I could: OpenCastor is optional. ROBOT.md ships to work with Claude Code alone, and for a single robot that’s genuinely all you need.

Three tiers, each with a different trade:

  • Tier 0 — Claude Code alone. A ROBOT.md at the robot’s root + the SessionStart hook. Claude’s Bash tool is the dispatch path — lsusb to discover hardware, a serial write to command a servo, a curl to post to an MQTT broker, i2cdetect to find a sensor. Planner and executor are one process. No SDK to install, no gateway to stand up, no runtime process. This is the under-60-second flow for a single robot.
  • Tier 1 — Claude Code + your own scripts. When shell-round-trip latency isn’t fast enough — a servo-control loop that needs 100 Hz, say — add Python or Bash drivers next to your ROBOT.md. Still no formal runtime process. Just Claude plus the files you’d already write.
  • Tier 2 — OpenCastor. Production fleets, regulated deployments, reactive VLA control, P66 hardware interlocks, EU AI Act audit, 7,800+ tests. Open-source, Claude Opus 4.7 as reference planner. Opt-in when you need the batteries; skip it when you don’t.

ROBOT.md works the same way on all three tiers. You don’t re-author the file when you graduate upward; you only add layers below it.

Where it sits in the stack

Four layers, each independently useful:

  ROBOT.md        →  what the robot IS       (RobotRegistryFoundation/robot-md)
  OpenCastor      →  what the robot RUNS     (craigm26/OpenCastor)
  RCAN            →  what the robot SPEAKS   (rcan.dev)
  Robot Registry  →  where the robot LIVES   (robotregistryfoundation.org)

No layer depends on the others. You can have a robot that speaks RCAN but has no ROBOT.md. A ROBOT.md that’s never registered with RRF. An OpenCastor runtime with no public registration. Compose the subset you need.

Adoption path for providers

If you ship an agent harness, ROBOT.md is a free upgrade to your robotics story that doesn’t require you to build anything. Point your session-start primitive at the file. That’s the whole integration.

The CLI has three verbs — validate, render, context — all three are small, focused, and forkable. If you want to ship your own implementation in your harness’s native language, please do. We’d rather see five clean parsers than wait for one blessed SDK.

Three Claude surfaces, three integration patterns:

  • Claude Code — SessionStart hook (shipping in v0.1 today).
  • Claude Desktop — MCP server wrapping ROBOT.md as resources + an invoke_skill tool (documented pattern; code lands in v0.2).
  • Claude Mobile — URL-fetch pattern with ROBOT.md hosted at a stable public URL (documented pattern; reference Cloudflare Worker lands in v0.2).

Governance

No provider should own the file format their competitors’ agents have to read. That’s why ROBOT.md’s home, from day one of the public launch, is the Robot Registry Foundation — the same neutral body that stewards the robot registry itself. Not a vendor, not a single-maintainer account, not a working handle that gets transferred later.

What’s shipping when

Today (v0.1): format spec, JSON Schema, four worked examples (minimal, SO-ARM101, TurtleBot 4, and Bob), Python CLI, Claude Code SessionStart hook, documented MCP and URL-bridge patterns, landing page at robotmd.dev.

Next two weeks (v0.2): robot-md register for RRF integration, working Claude Desktop MCP server, Cloudflare Worker serving robotmd.dev/r/<rrn> as a stable public URL per robot, TypeScript port for npm.

Q3 2026 (v1.0): format freeze, conformance test suite, multi-language bindings, potentially a formal SDO submission.

Try it in 60 seconds

The Tier 0 adoption flow, from zero to “robot answers your first prompt”:

# 1. Install the CLI + the Claude Code SessionStart hook. (~15 sec)
pip install git+https://github.com/RobotRegistryFoundation/robot-md.git#subdirectory=cli
mkdir -p ~/.claude/hooks
curl -fsSL https://robotmd.dev/hook > ~/.claude/hooks/robot-md.sh && chmod +x ~/.claude/hooks/robot-md.sh
# Add the hook to ~/.claude/settings.json — one line; see the repo's integrations/claude-code/README.md.

# 2. cd to your robot's repo. Start Claude. Ask it to write ROBOT.md. (~30 sec)
cd ~/my-robot
claude
#  > Scan the hardware connected to this machine and write a ROBOT.md per
#  > the spec at https://robotmd.dev/spec/v1. Use lsusb, i2cdetect, and
#  > dmesg for discovery, and validate when you're done.
#
# Claude's Bash tool does the discovery — USB servo buses, I2C sensors,
# serial ports, cameras — and writes the manifest. One tool, one session,
# one file out.

# 3. You're ready.
robot-md validate ROBOT.md          # green check

From here, Claude Code operates the robot directly. Its Bash tool dispatches commands — a Feetech WRITE_POS over /dev/ttyUSB0, a frame pulled from an OAK-D over HTTP, an MQTT publish, whatever your hardware listens to. No separate runtime process. The planner and the executor are one. That’s Tier 0.

Want a public identity for your robot? robot-md register ROBOT.md (shipping in v0.2, this month) posts to the Robot Registry Foundation and writes the assigned RRN-XXXXXXXXXXXX back into your manifest — the robot now has an entry at robotregistryfoundation.org, signs its messages under that identity, and speaks RCAN to any other registered robot on the network.

Want production-grade fleet orchestration, reactive VLA control, P66 hardware interlocks, or EU AI Act audit? Add OpenCastor (Tier 2) when you need them. Until then, ROBOT.md plus Claude Code is all a single-robot setup requires.

That’s the whole trick.


ROBOT.md lives at RobotRegistryFoundation/robot-md. The ecosystem it composes with: OpenCastor (runtime), rcan.dev (wire protocol), robotregistryfoundation.org (registry).