The robotics platform for the AI era.
Pronounced "go-ray" (like "sting-ray")
A robot is a distributed system — so build it like one. Even a "single" robot is already a network of MCUs, SBCs, sensors, and sometimes a base station. Gorai stops pretending otherwise: every sensor and actuator is a service on a NATS mesh — discovered at runtime, addressed by name, never wired by hand. The discipline that built reliable cloud systems — service discovery, location transparency, health checks, fan-out, replay — is exactly what a real robot needs.
Capabilities, not wiring. Sensors are resources you read; actuators are tools you call. Any agent on the mesh can perceive the world and change it — the capability model MCP gives AI agents, delivered natively over NATS with no MCP server in the path. We call it NCP, the NATS Capability Protocol.
One robot can be many machines. Because capabilities are addressed by name and not by location, a single logical robot can span a rover, a drone, a sensor mast, and a compute box — composed at runtime, degrading gracefully as platforms join and leave. This is the Composite Robot, and it's the whole point.
Autonomy without replay is folklore. Action logs, state streams, and replay are first-class platform concerns — not add-ons. AI execution is welcome but never trusted: safety is enforced at the capability node, not the agent. Agent-compatible, not agent-dependent — deterministic state machines and rule-based planners drive the same capabilities.
Build robots like software. Run them like systems. Opinionated, pragmatic, operational. If you already think in APIs, distributed systems, and deployments, you'll be productive in days, not months.
Read the north star: VISION.md.
Full documentation lives at gorai-docs. Strategy, architecture, specifications, hardware analysis, a 20-chapter book, and implementation guides — all indexed for both humans and AI agents. Point your AI agent at that repo and it will navigate 100+ documents via
CLAUDE.mdandINDEX.mdautomatically.
gorai Is (and Isn't)There are two different binaries in a Gorai project, and it's important not to confuse them:
Your robot binary — the program that runs on the Pi and does the robot stuff. This is your own Go module: a main.go that blank-imports the components you want and calls gorai.Run(). Its embedded NATS server, the mesh, and every component compile into this one static binary. It is fully self-contained and needs nothing from the gorai tool at runtime — you copy it to the robot and run it.
The gorai CLI — a developer and operator tool you run at your workstation. It never runs on the robot in production. Think of it as kubectl + a build wrapper + a package helper, rolled into one command.
So yes — you could just go build . your robot project and scp the result to the Pi. The gorai CLI earns its place by doing the things around that binary that a plain go build does not:
| What you want to do | gorai command | What it actually does |
|---|---|---|
| Catch config errors before deploying | gorai validate robot.json | Validates your RDL (schema, deprecations) so you don't ship a broken config to the field |
| Iterate fast without cross-compiling | gorai run robot.json | Runs the same runtime your robot binary uses, in the foreground — skips the compile-and-copy loop |
| Produce a deployable binary | gorai build robot.json --target linux/arm64 | Wraps go build with validation, cross-compile ergonomics, version stamping, and deploy hints |
| Find and add components | gorai component search/add | Wraps go get and edits the blank-import list in main.go (the Caddy model — see below) |
| See what's running on a live mesh | gorai mesh services / watch / schemas | Connects to a running NATS mesh and introspects it — your service-discovery browser for a robot or fleet in the field |
The first three are conveniences over the Go toolchain. The mesh commands are the part you genuinely cannot replicate with go build — they observe and debug a running system, which is what you reach for once a robot (or several) is live.
The rest of this README covers how to install the CLI, define a robot, and build it.
Build a robot in under an hour. Write JSON, get a binary, deploy to a Linux host (Raspberry Pi/Orange Pi/etc).
# 1. Install the CLI (a dev/operator tool — not the robot itself)
go install github.com/emergingrobotics/gorai/cmd/gorai@latest
# 2. Create a robot project from the template
git clone https://github.com/emergingrobotics/gorai-robot-template.git my-robot
cd my-robot
# 3. Edit robot.json, then validate and run
gorai validate robot.json
gorai run robot.json
# 4. Build for deployment
gorai build robot.json -o robot --target linux/arm64
scp robot pi@raspberrypi:~ && ssh pi@raspberrypi ./robot
No containers. No K8s. No external services — just a single binary on a Raspberry Pi 5 or Orange Pi 5. That's the simple case, not the ceiling: point several binaries at a shared NATS bus (or a leaf node) and the mesh ties multiple platforms into one logical robot — same code, no rewrite.
Gorai targets prosumer-accessible field robots across marine, surface, underwater, and land domains — autonomous submersibles, autonomous surface vessels, and land robots. An autonomous submersible, for example, runs gorai run on a Linux host (Raspberry Pi/Orange Pi/etc) inside a pressure housing.
Gorai uses the Caddy model for component packaging: your robot project is a standard Go module, and the import list in main.go is the component manifest. Each component self-registers via init() calling registry.RegisterComponent(). There is no custom package manager -- Go modules handles everything.
A robot's main.go declares which components to include via blank imports:
package main
import (
gorai "github.com/emergingrobotics/gorai/pkg/gorai"
// Remote proxy components from GoRAI core
_ "github.com/emergingrobotics/gorai/components/motor/remote"
_ "github.com/emergingrobotics/gorai/components/camera/remote"
// Third-party component from the ecosystem
_ "github.com/someone/gorai-component-lidar/rplidar"
// Custom component in this repo
_ "my-robot/components/ballast"
)
func main() {
gorai.Run()
}
The Go import list replaces package.json, requirements.txt, or any custom manifest. What you import is what gets compiled into the binary.
gorai component search lidar # Find components in the ecosystem
gorai component add sensor/rplidar # go get + add blank import to main.go
gorai build robot.json # Single binary with everything included
Custom components are ordinary Go packages in your project's repo. Write a package with an init() function that calls registry.RegisterComponent(), add a blank import in main.go, and it compiles into the binary alongside everything else.
Sharing a component means publishing a Go module. Extract the package into its own repo, push to GitHub, and anyone can gorai component add it. No registry servers, no package approval process -- standard Go module hosting.
This is a key advantage of choosing Go as the platform language. The single-binary story extends all the way to the component ecosystem: no runtime dependency resolution, no DLL hell, no version conflicts at deploy time. Every dependency is resolved at build time by the Go toolchain, and the result is one static binary you copy to the robot.
Non-Go components (Python vision pipelines, C++ SLAM) run as external services communicating via NATS. They do not compile into the binary. This is Phase 2 complexity.
For the full design, see docs/package-dev-approach.md.
Use Gorai if you:
Use ROS 2 if you:
We're not replacing ROS 2 — we're targeting a different market. Think "ROS 2 for prosumers," with an AI-first design for the next wave of autonomous systems.
Robotics is shifting because decision-making is moving up the stack: autonomy is no longer only hand-authored logic. Perception, planning, and task selection are increasingly learned, probabilistic, or agentic. That shift—physical AI—changes what a platform must provide.
What the future market is:
Why Gorai is built for it:
We are not trying to serve every robot. We are building the default platform for teams that ask: "How do we safely decide what the robot should do next—and scale that across systems?"
For the full strategic context, see Gorai Overarching Strategy in the gorai-docs repository.
You need Go 1.25+ to build gorai. That's it.
macOS:
brew install go
Ubuntu/Debian:
sudo apt update && sudo apt install -y golang-go
Or download from https://go.dev/dl/ for the latest version.
NATS is embedded in the gorai binary -- no external message broker to install.
The NATS CLI lets you subscribe to messages and debug your robot:
macOS:
brew install nats-io/nats-tools/nats
Linux:
go install github.com/nats-io/natscli/nats@latest
go install github.com/emergingrobotics/gorai/cmd/gorai@latest
# Clone the template (or click "Use this template" on GitHub)
git clone https://github.com/emergingrobotics/gorai-robot-template.git my-robot
cd my-robot
# Update the module path to your own
go mod edit -module github.com/yourorg/my-robot
The template includes a skeleton robot.json. Add components as needed:
{
"version": "2",
"robot": {"name": "my-robot", "description": "My first robot!"},
"nats": {"embedded": true, "url": "nats://localhost:4222"},
"dashboard": {"enabled": true, "listen": ":10101"},
"components": []
}
make validate # Check configuration
make run # Run in development mode
The embedded NATS server starts automatically -- no separate process needed.
# Build for Raspberry Pi
make build TARGET=linux/arm64
# Deploy
make deploy DEPLOY_HOST=pi@raspberrypi
For multi-robot deployments or shared brokers, point at an external NATS server:
{
"nats": {
"url": "nats://nats-server.local:4222",
"external": true
}
}
When external is true or the URL points to a non-local address, gorai connects to the external server instead of starting its own.
| Platform | AI Performance | Cost | Best For |
|---|---|---|---|
| Raspberry Pi 5 (8GB) | External (Hailo 13-26 TOPS) | ~$160 | Primary platform, best ecosystem |
| Raspberry Pi 5 (4GB) | External (Hailo 13-26 TOPS) | ~$100 | Budget builds |
| Orange Pi 5B (8GB) | 6 TOPS (built-in NPU) | ~$145 | Budget AI builds |
Not supported: Pi 3, Pi Zero
See Hardware Requirements in the gorai-docs repository for details.
Gorai supports two patterns for accessing hardware. Both produce components with identical interfaces — application code doesn't know or care which is used.
Co-processor (RP2040 via GSP/2): An RP2040 microcontroller handles real-time hardware I/O (PWM, motor control, encoders). The RPi communicates with it over USB serial using the Gorai Serial Protocol v2. Best for timing-critical control, isolating hardware from Linux scheduler jitter, and reliability-critical applications (e.g., an autonomous submersible — motor control must not glitch underwater).
Native RPi hardware (GPIO/I2C/SPI): Direct access to Raspberry Pi GPIO pins, I2C buses, and SPI buses from Go code. Best for simple sensors, I2C devices, prototyping, and cost-sensitive builds where an RP2040 is unnecessary.
Both patterns can be used simultaneously — e.g., RP2040 handling motors while the Pi reads I2C sensors directly.
| Command | Description |
|---|---|
gorai validate <config> | Validate RDL configuration |
gorai run <config> | Run robot in development mode |
gorai build <config> | Build standalone binary |
gorai components | List available component types |
gorai version | Show version information |
gorai migrate | Migrate RDL v1 config to v2 format |
| Command | Description |
|---|---|
gorai component search | Search for third-party components |
gorai component info | Show component information |
gorai component add | Add component to project |
| Command | Description |
|---|---|
gorai mesh services | List running services in the mesh |
gorai mesh channels | List registered NATS channels |
gorai mesh schemas | List or show message schemas |
gorai mesh watch | Watch for services joining/leaving |
gorai mesh summary | Show mesh state summary |
gorai mesh robots | List robots with registered services |
gorai mesh init | Initialize predefined schemas |
gorai mesh reset | Reset mesh (delete all data) |
The core repo provides component interfaces, remote proxies (for multi-robot mesh access), and fakes (for testing). Hardware-specific implementations live in external Go modules.
arm, base, camera, gripper, input, link, motor, power, pwm, sensor, servo, space, stepper, thruster, valve
camera/remote, gpio/remote, input/remote, motor/remote, pwm/remote, sensor/encoder/remote
camera/fake, motor/fake, pwm/fake, servo/fake
Hardware-specific implementations are installed with gorai component add:
gorai-picarx - SunFounder PiCar-X robot kitgorai-driver-hcsr04 - HC-SR04 ultrasonic distance sensorGorai uses a message-based architecture where all components communicate via an embedded NATS server:
┌──────────────────────────────────────────────────────┐
│ Your Robot Binary │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ GPS │ │ Motor │ │ Sensor │ ... │
│ │Component│ │Component│ │Component│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ └───────────┴─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Message │ │
│ │ Router │ │
│ └─────┬─────┘ │
│ │ NATS Protocol │
│ ┌─────▼─────┐ │
│ │ Embedded │ │
│ │ NATS │ (JetStream enabled) │
│ └───────────┘ │
└──────────────────────────────────────────────────────┘
Key principles:
| Example | Description | Status |
|---|---|---|
| blinky | LED blink demo | Working |
| gps-tracker | GPS tracking robot | Working |
| gsp-pico | GSP/2 Pico co-processor | Working |
| hello-camera | Camera streaming | Working |
| pwm-controller | PWM control via gorai-gsp | Working |
Gorai includes a built-in service mesh for runtime discovery across independent processes. This enables:
┌─────────────────────────────────────────────────────────────────────────┐
│ NATS JetStream KV │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ gorai-services (TTL: 30s) → Active service registrations │ │
│ │ gorai-channels (persistent) → Channel/subject descriptors │ │
│ │ gorai-schemas (persistent) → Message schemas (JSON Schema) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
// Register a service
client, _ := mesh.NewClient(natsConn)
reg, _ := client.Register(ctx, mesh.ServiceDescriptor{
Name: "motor-controller",
Type: mesh.TypeComponent,
Subtype: "motor",
RobotID: "robot-alpha",
})
defer reg.Deregister()
// Discover other services
motors, _ := client.FindServices(ctx, mesh.Query{Subtype: "motor"})
# List all running services
gorai mesh services
# Watch for changes in real-time
gorai mesh watch
# List available channels
gorai mesh channels robot-alpha
See the mesh service discovery specification in the gorai-docs repository for complete documentation.
Gorai supports hybrid static/dynamic configuration. Define structure in RDL, discover hardware at runtime.
Traditional approach requires declaring every device in config:
{
"components": [
{"name": "motor1", "type": "motor/pwm", "config": {"pin": 18}},
{"name": "motor2", "type": "motor/pwm", "config": {"pin": 19}}
]
}
What if you don't know what devices will be connected? What if devices are hot-plugged?
Define discovery rules instead of individual devices:
{
"gateways": [
{
"name": "usb-gateway",
"type": "gateway/gsp",
"config": {
"discovery": {"enabled": true, "patterns": ["/dev/ttyACM*"]}
}
}
],
"discovery": {
"enabled": true,
"auto_adopt": true,
"rules": [
{"match": {"capability": "PWM"}, "adopt_as": {"type": "motor"}},
{"match": {"capability": "IMU"}, "adopt_as": {"type": "sensor", "subtype": "imu"}}
]
},
"services": [
{
"name": "patrol",
"type": "behavior/patrol",
"depends_on": ["@discovered:motor/*", "@discovered:sensor/imu/*"]
}
]
}
What happens:
@discovered: dependencies resolveSee the dynamic discovery specification in the gorai-docs repository for complete documentation.
| Pattern | ROS 2 | Gorai | Benefit |
|---|---|---|---|
| Message Broker | DDS peer-to-peer | NATS server | Decoupled, easy monitoring |
| Event Sourcing | rosbag (manual) | JetStream (built-in) | Replay, time-travel debug |
| Observability | Custom diagnostics | Prometheus /metrics | Industry-standard tools |
| Package Management | Custom (rosdep, colcon) | Go modules | Standard tooling, no custom manager |
NATS has clients for 40+ languages. Use the best tool for each job.
Version: 0.1.0 (Early Development)
The current focus is a zero-dependency, single-binary deployment model:
GoRAI uses the Caddy model for component distribution. Each hardware driver is a standalone Go module. A user's robot project has a main.go that imports the GoRAI core plus blank imports for each component needed. go build produces a single binary with exactly those components compiled in. See REQUIREMENTS.md for details.
All documentation has moved to the gorai-docs repository, including:
Gorai is built with Claude Code. We believe AI-assisted development is the future — the project is organized for both humans and AI to reason about effectively.
Apache 2.0
Go
96.7%
JavaScript
1.7%
The robotics platform for the AI era.
Pronounced "go-ray" (like "sting-ray")
A robot is a distributed system — so build it like one. Even a "single" robot is already a network of MCUs, SBCs, sensors, and sometimes a base station. Gorai stops pretending otherwise: every sensor and actuator is a service on a NATS mesh — discovered at runtime, addressed by name, never wired by hand. The discipline that built reliable cloud systems — service discovery, location transparency, health checks, fan-out, replay — is exactly what a real robot needs.
Capabilities, not wiring. Sensors are resources you read; actuators are tools you call. Any agent on the mesh can perceive the world and change it — the capability model MCP gives AI agents, delivered natively over NATS with no MCP server in the path. We call it NCP, the NATS Capability Protocol.
One robot can be many machines. Because capabilities are addressed by name and not by location, a single logical robot can span a rover, a drone, a sensor mast, and a compute box — composed at runtime, degrading gracefully as platforms join and leave. This is the Composite Robot, and it's the whole point.
Autonomy without replay is folklore. Action logs, state streams, and replay are first-class platform concerns — not add-ons. AI execution is welcome but never trusted: safety is enforced at the capability node, not the agent. Agent-compatible, not agent-dependent — deterministic state machines and rule-based planners drive the same capabilities.
Build robots like software. Run them like systems. Opinionated, pragmatic, operational. If you already think in APIs, distributed systems, and deployments, you'll be productive in days, not months.
Read the north star: VISION.md.
Full documentation lives at gorai-docs. Strategy, architecture, specifications, hardware analysis, a 20-chapter book, and implementation guides — all indexed for both humans and AI agents. Point your AI agent at that repo and it will navigate 100+ documents via
CLAUDE.mdandINDEX.mdautomatically.
gorai Is (and Isn't)There are two different binaries in a Gorai project, and it's important not to confuse them:
Your robot binary — the program that runs on the Pi and does the robot stuff. This is your own Go module: a main.go that blank-imports the components you want and calls gorai.Run(). Its embedded NATS server, the mesh, and every component compile into this one static binary. It is fully self-contained and needs nothing from the gorai tool at runtime — you copy it to the robot and run it.
The gorai CLI — a developer and operator tool you run at your workstation. It never runs on the robot in production. Think of it as kubectl + a build wrapper + a package helper, rolled into one command.
So yes — you could just go build . your robot project and scp the result to the Pi. The gorai CLI earns its place by doing the things around that binary that a plain go build does not:
| What you want to do | gorai command | What it actually does |
|---|---|---|
| Catch config errors before deploying | gorai validate robot.json | Validates your RDL (schema, deprecations) so you don't ship a broken config to the field |
| Iterate fast without cross-compiling | gorai run robot.json | Runs the same runtime your robot binary uses, in the foreground — skips the compile-and-copy loop |
| Produce a deployable binary | gorai build robot.json --target linux/arm64 | Wraps go build with validation, cross-compile ergonomics, version stamping, and deploy hints |
| Find and add components | gorai component search/add | Wraps go get and edits the blank-import list in main.go (the Caddy model — see below) |
| See what's running on a live mesh | gorai mesh services / watch / schemas | Connects to a running NATS mesh and introspects it — your service-discovery browser for a robot or fleet in the field |
The first three are conveniences over the Go toolchain. The mesh commands are the part you genuinely cannot replicate with go build — they observe and debug a running system, which is what you reach for once a robot (or several) is live.
The rest of this README covers how to install the CLI, define a robot, and build it.
Build a robot in under an hour. Write JSON, get a binary, deploy to a Linux host (Raspberry Pi/Orange Pi/etc).
# 1. Install the CLI (a dev/operator tool — not the robot itself)
go install github.com/emergingrobotics/gorai/cmd/gorai@latest
# 2. Create a robot project from the template
git clone https://github.com/emergingrobotics/gorai-robot-template.git my-robot
cd my-robot
# 3. Edit robot.json, then validate and run
gorai validate robot.json
gorai run robot.json
# 4. Build for deployment
gorai build robot.json -o robot --target linux/arm64
scp robot pi@raspberrypi:~ && ssh pi@raspberrypi ./robot
No containers. No K8s. No external services — just a single binary on a Raspberry Pi 5 or Orange Pi 5. That's the simple case, not the ceiling: point several binaries at a shared NATS bus (or a leaf node) and the mesh ties multiple platforms into one logical robot — same code, no rewrite.
Gorai targets prosumer-accessible field robots across marine, surface, underwater, and land domains — autonomous submersibles, autonomous surface vessels, and land robots. An autonomous submersible, for example, runs gorai run on a Linux host (Raspberry Pi/Orange Pi/etc) inside a pressure housing.
Gorai uses the Caddy model for component packaging: your robot project is a standard Go module, and the import list in main.go is the component manifest. Each component self-registers via init() calling registry.RegisterComponent(). There is no custom package manager -- Go modules handles everything.
A robot's main.go declares which components to include via blank imports:
package main
import (
gorai "github.com/emergingrobotics/gorai/pkg/gorai"
// Remote proxy components from GoRAI core
_ "github.com/emergingrobotics/gorai/components/motor/remote"
_ "github.com/emergingrobotics/gorai/components/camera/remote"
// Third-party component from the ecosystem
_ "github.com/someone/gorai-component-lidar/rplidar"
// Custom component in this repo
_ "my-robot/components/ballast"
)
func main() {
gorai.Run()
}
The Go import list replaces package.json, requirements.txt, or any custom manifest. What you import is what gets compiled into the binary.
gorai component search lidar # Find components in the ecosystem
gorai component add sensor/rplidar # go get + add blank import to main.go
gorai build robot.json # Single binary with everything included
Custom components are ordinary Go packages in your project's repo. Write a package with an init() function that calls registry.RegisterComponent(), add a blank import in main.go, and it compiles into the binary alongside everything else.
Sharing a component means publishing a Go module. Extract the package into its own repo, push to GitHub, and anyone can gorai component add it. No registry servers, no package approval process -- standard Go module hosting.
This is a key advantage of choosing Go as the platform language. The single-binary story extends all the way to the component ecosystem: no runtime dependency resolution, no DLL hell, no version conflicts at deploy time. Every dependency is resolved at build time by the Go toolchain, and the result is one static binary you copy to the robot.
Non-Go components (Python vision pipelines, C++ SLAM) run as external services communicating via NATS. They do not compile into the binary. This is Phase 2 complexity.
For the full design, see docs/package-dev-approach.md.
Use Gorai if you:
Use ROS 2 if you:
We're not replacing ROS 2 — we're targeting a different market. Think "ROS 2 for prosumers," with an AI-first design for the next wave of autonomous systems.
Robotics is shifting because decision-making is moving up the stack: autonomy is no longer only hand-authored logic. Perception, planning, and task selection are increasingly learned, probabilistic, or agentic. That shift—physical AI—changes what a platform must provide.
What the future market is:
Why Gorai is built for it:
We are not trying to serve every robot. We are building the default platform for teams that ask: "How do we safely decide what the robot should do next—and scale that across systems?"
For the full strategic context, see Gorai Overarching Strategy in the gorai-docs repository.
You need Go 1.25+ to build gorai. That's it.
macOS:
brew install go
Ubuntu/Debian:
sudo apt update && sudo apt install -y golang-go
Or download from https://go.dev/dl/ for the latest version.
NATS is embedded in the gorai binary -- no external message broker to install.
The NATS CLI lets you subscribe to messages and debug your robot:
macOS:
brew install nats-io/nats-tools/nats
Linux:
go install github.com/nats-io/natscli/nats@latest
go install github.com/emergingrobotics/gorai/cmd/gorai@latest
# Clone the template (or click "Use this template" on GitHub)
git clone https://github.com/emergingrobotics/gorai-robot-template.git my-robot
cd my-robot
# Update the module path to your own
go mod edit -module github.com/yourorg/my-robot
The template includes a skeleton robot.json. Add components as needed:
{
"version": "2",
"robot": {"name": "my-robot", "description": "My first robot!"},
"nats": {"embedded": true, "url": "nats://localhost:4222"},
"dashboard": {"enabled": true, "listen": ":10101"},
"components": []
}
make validate # Check configuration
make run # Run in development mode
The embedded NATS server starts automatically -- no separate process needed.
# Build for Raspberry Pi
make build TARGET=linux/arm64
# Deploy
make deploy DEPLOY_HOST=pi@raspberrypi
For multi-robot deployments or shared brokers, point at an external NATS server:
{
"nats": {
"url": "nats://nats-server.local:4222",
"external": true
}
}
When external is true or the URL points to a non-local address, gorai connects to the external server instead of starting its own.
| Platform | AI Performance | Cost | Best For |
|---|---|---|---|
| Raspberry Pi 5 (8GB) | External (Hailo 13-26 TOPS) | ~$160 | Primary platform, best ecosystem |
| Raspberry Pi 5 (4GB) | External (Hailo 13-26 TOPS) | ~$100 | Budget builds |
| Orange Pi 5B (8GB) | 6 TOPS (built-in NPU) | ~$145 | Budget AI builds |
Not supported: Pi 3, Pi Zero
See Hardware Requirements in the gorai-docs repository for details.
Gorai supports two patterns for accessing hardware. Both produce components with identical interfaces — application code doesn't know or care which is used.
Co-processor (RP2040 via GSP/2): An RP2040 microcontroller handles real-time hardware I/O (PWM, motor control, encoders). The RPi communicates with it over USB serial using the Gorai Serial Protocol v2. Best for timing-critical control, isolating hardware from Linux scheduler jitter, and reliability-critical applications (e.g., an autonomous submersible — motor control must not glitch underwater).
Native RPi hardware (GPIO/I2C/SPI): Direct access to Raspberry Pi GPIO pins, I2C buses, and SPI buses from Go code. Best for simple sensors, I2C devices, prototyping, and cost-sensitive builds where an RP2040 is unnecessary.
Both patterns can be used simultaneously — e.g., RP2040 handling motors while the Pi reads I2C sensors directly.
| Command | Description |
|---|---|
gorai validate <config> | Validate RDL configuration |
gorai run <config> | Run robot in development mode |
gorai build <config> | Build standalone binary |
gorai components | List available component types |
gorai version | Show version information |
gorai migrate | Migrate RDL v1 config to v2 format |
| Command | Description |
|---|---|
gorai component search | Search for third-party components |
gorai component info | Show component information |
gorai component add | Add component to project |
| Command | Description |
|---|---|
gorai mesh services | List running services in the mesh |
gorai mesh channels | List registered NATS channels |
gorai mesh schemas | List or show message schemas |
gorai mesh watch | Watch for services joining/leaving |
gorai mesh summary | Show mesh state summary |
gorai mesh robots | List robots with registered services |
gorai mesh init | Initialize predefined schemas |
gorai mesh reset | Reset mesh (delete all data) |
The core repo provides component interfaces, remote proxies (for multi-robot mesh access), and fakes (for testing). Hardware-specific implementations live in external Go modules.
arm, base, camera, gripper, input, link, motor, power, pwm, sensor, servo, space, stepper, thruster, valve
camera/remote, gpio/remote, input/remote, motor/remote, pwm/remote, sensor/encoder/remote
camera/fake, motor/fake, pwm/fake, servo/fake
Hardware-specific implementations are installed with gorai component add:
gorai-picarx - SunFounder PiCar-X robot kitgorai-driver-hcsr04 - HC-SR04 ultrasonic distance sensorGorai uses a message-based architecture where all components communicate via an embedded NATS server:
┌──────────────────────────────────────────────────────┐
│ Your Robot Binary │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ GPS │ │ Motor │ │ Sensor │ ... │
│ │Component│ │Component│ │Component│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ └───────────┴─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Message │ │
│ │ Router │ │
│ └─────┬─────┘ │
│ │ NATS Protocol │
│ ┌─────▼─────┐ │
│ │ Embedded │ │
│ │ NATS │ (JetStream enabled) │
│ └───────────┘ │
└──────────────────────────────────────────────────────┘
Key principles:
| Example | Description | Status |
|---|---|---|
| blinky | LED blink demo | Working |
| gps-tracker | GPS tracking robot | Working |
| gsp-pico | GSP/2 Pico co-processor | Working |
| hello-camera | Camera streaming | Working |
| pwm-controller | PWM control via gorai-gsp | Working |
Gorai includes a built-in service mesh for runtime discovery across independent processes. This enables:
┌─────────────────────────────────────────────────────────────────────────┐
│ NATS JetStream KV │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ gorai-services (TTL: 30s) → Active service registrations │ │
│ │ gorai-channels (persistent) → Channel/subject descriptors │ │
│ │ gorai-schemas (persistent) → Message schemas (JSON Schema) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
// Register a service
client, _ := mesh.NewClient(natsConn)
reg, _ := client.Register(ctx, mesh.ServiceDescriptor{
Name: "motor-controller",
Type: mesh.TypeComponent,
Subtype: "motor",
RobotID: "robot-alpha",
})
defer reg.Deregister()
// Discover other services
motors, _ := client.FindServices(ctx, mesh.Query{Subtype: "motor"})
# List all running services
gorai mesh services
# Watch for changes in real-time
gorai mesh watch
# List available channels
gorai mesh channels robot-alpha
See the mesh service discovery specification in the gorai-docs repository for complete documentation.
Gorai supports hybrid static/dynamic configuration. Define structure in RDL, discover hardware at runtime.
Traditional approach requires declaring every device in config:
{
"components": [
{"name": "motor1", "type": "motor/pwm", "config": {"pin": 18}},
{"name": "motor2", "type": "motor/pwm", "config": {"pin": 19}}
]
}
What if you don't know what devices will be connected? What if devices are hot-plugged?
Define discovery rules instead of individual devices:
{
"gateways": [
{
"name": "usb-gateway",
"type": "gateway/gsp",
"config": {
"discovery": {"enabled": true, "patterns": ["/dev/ttyACM*"]}
}
}
],
"discovery": {
"enabled": true,
"auto_adopt": true,
"rules": [
{"match": {"capability": "PWM"}, "adopt_as": {"type": "motor"}},
{"match": {"capability": "IMU"}, "adopt_as": {"type": "sensor", "subtype": "imu"}}
]
},
"services": [
{
"name": "patrol",
"type": "behavior/patrol",
"depends_on": ["@discovered:motor/*", "@discovered:sensor/imu/*"]
}
]
}
What happens:
@discovered: dependencies resolveSee the dynamic discovery specification in the gorai-docs repository for complete documentation.
| Pattern | ROS 2 | Gorai | Benefit |
|---|---|---|---|
| Message Broker | DDS peer-to-peer | NATS server | Decoupled, easy monitoring |
| Event Sourcing | rosbag (manual) | JetStream (built-in) | Replay, time-travel debug |
| Observability | Custom diagnostics | Prometheus /metrics | Industry-standard tools |
| Package Management | Custom (rosdep, colcon) | Go modules | Standard tooling, no custom manager |
NATS has clients for 40+ languages. Use the best tool for each job.
Version: 0.1.0 (Early Development)
The current focus is a zero-dependency, single-binary deployment model:
GoRAI uses the Caddy model for component distribution. Each hardware driver is a standalone Go module. A user's robot project has a main.go that imports the GoRAI core plus blank imports for each component needed. go build produces a single binary with exactly those components compiled in. See REQUIREMENTS.md for details.
All documentation has moved to the gorai-docs repository, including:
Gorai is built with Claude Code. We believe AI-assisted development is the future — the project is organized for both humans and AI to reason about effectively.
Apache 2.0
Go
96.7%
JavaScript
1.7%