No description
  • Go 98.3%
  • Nix 1%
  • Shell 0.5%
  • Swift 0.2%
Find a file
Lenora Pondigo 264601a66f feat: refactor agent commands, add tmux control, display_spawn, OCR actions
Separate agent_spawn into coding-agent lifecycle (configurable types via
~/.config/nro-node/agents.json) vs display_spawn for GUI apps on remote
displays. Add agent_tell, agent_clear for session communication. Add
unified tmux MCP tool with send/read/scroll/list/resize/split/select
actions and matching CLI commands. Add OCR-based find/click_text interact
actions for remote X11. Filter SSH certificate noise in stderr. Update
all MCP prompts for new tool names and add agent-session, tmux-control
prompts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 11:54:50 -06:00
cmd/nro-node Add MCP server with 13 tools and 6 workflow prompts 2026-04-19 02:31:53 -06:00
helpers initial commit 2026-04-14 17:48:13 -06:00
internal feat: refactor agent commands, add tmux control, display_spawn, OCR actions 2026-04-24 11:54:50 -06:00
scripts feat: auto-version from VERSION file + git rev 2026-04-19 19:54:12 -06:00
vendor initial commit 2026-04-14 17:48:13 -06:00
.gitignore Add MCP server with 13 tools and 6 workflow prompts 2026-04-19 02:31:53 -06:00
flake.lock initial commit 2026-04-14 17:48:13 -06:00
flake.nix fix: inject version via ldflags and fix devbox detection 2026-04-19 21:08:52 -06:00
go.mod Add MCP server with 13 tools and 6 workflow prompts 2026-04-19 02:31:53 -06:00
go.sum initial commit 2026-04-14 17:48:13 -06:00
README.md Add host_ls and host_show MCP tools 2026-04-19 19:26:08 -06:00
VERSION feat: add record_start, record_stop, record_status MCP tools 2026-04-21 15:05:04 -06:00

nro

A wrapper CLI for orchestrating virtual displays, headless agents, and tool interactions across your hosts.

nro ties together BetterDisplay, X11, tmux, SSH, xdotool, axcli, and FFmpeg behind a single CLI so that AI agents can spin up displays, launch apps, interact with GUIs, and record screens on any node in your mesh — local or remote, same commands.

It was born from a practical need: I have a Hetzner NixOS instance and a local NixOS server, and I need to manage headless agents on them — create X11 displays over VNC, spawn tools, screenshot results, all without being physically there. On Darwin, BetterDisplay (paid license) adds virtual displays so agents can test GUI apps without touching your physical screens. That part is an extra — the core is about giving agents eyes and hands on remote hosts, switching to edge computing when needed or delegating to a remote node.


What's in the box

  • Virtual displays — create, show, hide, resize, screenshot. BetterDisplay on macOS, x11-manager daemon on NixOS/Linux. Same CLI on both.
  • Agent sessions — named tmux (local) or x11-manager (remote) sessions, each bound to a display.
  • App interaction — keyboard, mouse, accessibility automation. axcli on macOS, xdotool on Linux.
  • Screen recording — FFmpeg-based capture of any display (AVFoundation on macOS, xwd on Linux).
  • VNC tunneling — SSH tunnel lifecycle + viewer launch, for when you actually want eyes on a remote session.
  • Host management — list configured hosts, inspect displays/agents/tunnels per host.
  • Multi-host — everything works local or remote transparently via [host] <name> convention.

Architecture

nro is the project. nro-node is what runs on each host.

nro-node                ← Single binary, runs on every host.
  ├─ darwin support     ← BetterDisplay + axcli + AVFoundation
  └─ nixos/linux        ← x11-manager + xdotool + xwd

Platform differences are handled internally — the CLI surface is the same everywhere.


Quick start

Install

Nix (NixOS / Linux / macOS):

# Run directly
nix run git+https://git.pondi.app/nro/nro-node

# Or add to your flake inputs
{
  inputs.nro-node.url = "git+https://git.pondi.app/nro/nro-node";
}

Host setup

Each host needs nro plus its platform dependencies:

NixOS (server):

# In your flake — the x11-manager daemon handles display/agent lifecycle
{
  inputs.nro-node.url = "git+https://git.pondi.app/nro/nro-node";
  # then in your config:
  services.nro-node.enable = true;
}

macOS (optional — for local virtual displays):

# BetterDisplay for virtual displays (paid license)
brew install betterdisplay
# axcli for accessibility-based app interaction
cargo install axcli

First commands

# Host management
nro host ls                          # list configured hosts
nro host show hetzner                # inspect host details + agents + tunnels

# List all displays and agents across hosts
nro ls
nro ls hetzner                       # filter to one host

# Virtual displays
nro display create my-display                              # local (BetterDisplay)
nro display create hetzner my-display --geometry 1920x1080 # remote (X11)
nro display show my-display                                # connect local display
nro display hide my-display                                # disconnect local display
nro display screenshot my-display                          # local screenshot
nro display screenshot hetzner my-display ~/shot.png       # remote screenshot
nro display geometry hetzner my-display 2560x1440          # resize remote display

# Agent sessions
nro agent create my-agent                                  # local tmux session
nro agent create hetzner my-agent --geometry 1920x1080     # remote via x11-manager
nro agent info hetzner my-agent                            # session details
nro agent spawn my-agent firefox                           # run tool locally
nro agent spawn hetzner my-agent firefox                   # run tool remotely
nro agent expose hetzner my-agent                          # expose agent to VNC
nro agent hide hetzner my-agent                            # hide from VNC
nro agent destroy hetzner my-agent                         # tear down

# Attach to tmux (local or remote, fzf picker)
nro attach
nro attach hetzner my-agent

# VNC tunneling
nro start hetzner 1                  # tunnel + viewer to display :1
nro start hetzner my-agent           # tunnel + viewer to agent's display
nro status                           # active tunnels
nro stop                             # tear down all tunnels
nro stop hetzner                     # tear down tunnels for one host

# Screen recording
nro record screen start my-display --fps 30
nro record screen start hetzner :1 --fps 10 --duration 60
nro record screen stop my-display
nro record screen status

# App interaction (macOS axcli / Linux xdotool)
nro interact Safari snapshot
nro interact Safari click 'AXButton[title="Send"]'
nro interact hetzner my-agent key Return
nro interact hetzner my-agent type "hello world"
nro interact list-apps                                     # list accessible apps (macOS)

MCP integration (Claude Code)

nro ships an MCP server that exposes every tool above, plus six workflow prompts.

Connecting

claude mcp add nro -- nro mcp

Or in your Claude Code config:

{
  "mcpServers": {
    "nro": {
      "command": "nro",
      "args": ["mcp"]
    }
  }
}

Tools

Tool Description
display_ls List displays (local BetterDisplay or remote X11)
display_create Create a virtual display
display_show Connect/show a virtual display
display_hide Disconnect/hide a virtual display
display_destroy Remove a virtual display
display_screenshot Screenshot a display (base64 PNG locally, remote path)
display_geometry Set remote X11 display resolution
agent_ls List agent sessions
agent_create Create an agent session
agent_destroy Destroy an agent session
agent_spawn Run a command in an agent session
agent_info Show agent session details
interact Drive apps via axcli (macOS) or xdotool (Linux)
host_ls List all configured remote hosts
host_show Show host details: config, displays, agents, tunnels

Prompts

Prompt When you'd use it
observe Screenshot a display and describe what's visible.
deploy-verify Deploy something, screenshot the result, verify visually.
interact-app Drive a GUI app end-to-end (click, type, wait, assert).
orchestrate Coordinate multiple agents across hosts for a larger task.
provision Set up a full environment: display + agent + tool in one shot.
watchdog Periodically observe a display, alert on anomalies.

Example flow

Ask Claude Code:

"Spin up a fresh display on hetzner, open Firefox, navigate to our staging URL, screenshot, and tell me if the header renders correctly."

Claude reaches for provision, creates the X11 display, spawns an agent, launches Firefox via agent_spawn, screenshots with display_screenshot, and reports back.


Status

nro is v0.x and the API will break. Use it, file issues, expect churn. If you want stability, pin a commit.


License

MIT. See LICENSE.

Copyright © 2026 Lenora