Skip to content

nSimonFR/amarre

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

45 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

amarre

French amarre β€” a mooring line. The bit of rope between a boat and the dock.

Tailnet-only WebSocket harness for driving one or more CLI coding agents (pi, claude-code, …) from a remote device. Self-hosted analogue of Anthropic's Claude Code Remote Control, no third-party relay. Multi-session: one server hosts up to N agent processes, each addressable by id.

Two agent adapters ship in-tree:

  • agents/pi/ β€” pi-coding-agent with a remote permission-approval extension.
  • agents/claude-code/ β€” Anthropic's claude CLI in stream-json mode (skip-permissions in v1).

AI Installation Prompt

Install amarre on a host that has Tailscale joined. Done when curl -s http://127.0.0.1:<port>/healthz returns 200 and the same URL is reachable from another Tailnet-joined device.

  1. Clone: git clone https://github.com/nSimonFR/amarre && cd amarre
  2. Read first: SPEC.md (the load-bearing component-by-component spec for agents β€” purpose, architecture, REST + WS surface, data model, push flow, env vars, invariants), then README.md, package.json, and docs/PROTOCOL.md for normative wire-format details. Toolchain is Bun (β‰₯ 1.x); do not substitute npm / pnpm / yarn β€” bun.lock is the lockfile.
  3. Install: bun install. Verify: bun run start --help (or --version) returns without error.
  4. Configure one or more agent instances. Each instance maps to a CLI binary already on PATH (e.g. pi, claude-code). The minimum config is one instance with { agent: "<bin>", port: <num> }. See src/ for the loader.
  5. Run: bun run start. Tail logs and confirm listening on <port> appears for each instance.
  6. From a remote Tailnet device, connect to ws://<this-host>:<port>/ and exchange frames per docs/PROTOCOL.md.
  7. NixOS hosts have a services.amarre module β€” see module.nix.

The server binds loopback only by design. The trust boundary is the Tailscale ACL, not auth tokens. Do not bind to 0.0.0.0 or expose any port publicly.

Layout

amarre/
β”œβ”€β”€ server/                # generic WS ↔ stdio proxy (~80 LOC, Bun)
β”œβ”€β”€ agents/                # agent adapter plugins
β”‚   β”œβ”€β”€ pi/                #   adapter for pi-coding-agent (+ permission-gate ext)
β”‚   └── claude-code/       #   adapter for Anthropic's claude CLI (stream-json)
β”œβ”€β”€ apps/                  # native / web client apps
β”‚   β”œβ”€β”€ expo/              #   Expo cross-platform client (active)
β”‚   └── ios/               #   parked SwiftUI placeholder
β”œβ”€β”€ tests/fixtures/        # echo-agent + echo-adapter for server tests
β”œβ”€β”€ docs/PROTOCOL.md       # full wire-format specification
β”œβ”€β”€ flake.nix              # packages.<system>.server + nixosModules.amarre + checks
└── module.nix

The server is agent-agnostic: it loads an adapter at startup based on AMARRE_AGENT (default pi) and proxies JSONL bidirectionally between WebSocket clients and per-session agent processes. Sessions are spawned/listed/killed via a small REST control plane on the same port. Agents are plugins under agents/. Apps consuming the protocol are separate projects under apps/.

Protocol

See docs/PROTOCOL.md (v2.0.0) for the full front/back specification β€” REST control plane, WebSocket data plane, framing, multi-client semantics, permission flow, error handling, conformance checklist, and a worked example.

Layer-summary: HTTP/WebSocket β†’ JSONL β†’ amarre envelope (transparent proxy + one amarre.session_event) β†’ agent's own RPC schema (e.g. pi's docs/rpc.md).

Run locally

With real pi:

bun install
bun test                          # server + multi-session + adapter tests
PI_BIN=$(which pi) bun run server/server.ts

With real claude-code:

AMARRE_AGENT=claude-code CLAUDE_BIN=$(which claude) \
  bun run server/server.ts

Then from another shell β€” spawn a session, connect to it:

ID=$(curl -s -X POST http://127.0.0.1:8341/sessions -d '{}' | jq -r .id)
websocat ws://127.0.0.1:8341/sessions/$ID
{"id":"1","type":"get_state"}

Other useful endpoints:

curl -s http://127.0.0.1:8341/sessions               # list
curl -s http://127.0.0.1:8341/sessions/$ID           # status
curl -s -X POST http://127.0.0.1:8341/sessions/$ID/restart
curl -s -X DELETE http://127.0.0.1:8341/sessions/$ID

Deploy via NixOS

Consumed as a flake input (github:nSimonFR/amarre). Module:

services.amarre = {
  enable      = true;
  agent       = "pi";       # default; matches agents/pi/
  port        = 8341;
  user        = "nsimon";
  maxSessions = 8;          # default; cap on concurrent agent processes
};

For multiple side-by-side adapter instances (e.g. separate CLAUDE_HOME per profile), use services.amarre.instances instead and route via the instanceId body field on POST /sessions (see docs/PROTOCOL.md Β§4.1):

services.amarre.instances = {
  personal = { agent = "claude-code"; env = { CLAUDE_HOME = "/home/me/.claude_personal"; }; };
  work     = { agent = "claude-code"; env = { CLAUDE_HOME = "/home/me/.claude_work"; }; };
  pi       = { agent = "pi"; };
};

The systemd unit runs as the configured user so it inherits home-dir agent config (~/.pi/agent/{settings.json,models.json,extensions/}, ~/.claude/). Pair with tailscale serve to expose the loopback port over the tailnet at HTTPS. Optional Expo push notifications are gated by services.amarre.push.enable (PROTOCOL Β§13).

Adding an agent

See agents/README.md. Each adapter is a small TypeScript module that knows how to spawn one specific CLI agent in stdio-streaming mode.

Adding a client

See apps/README.md. Speak the documented protocol β€” don't introduce alternative wire formats.

Status

v0.3 β€” multi-session, multi-client, tailnet-only (PROTOCOL.md v2.0.0). See docs/PROTOCOL.md Β§9 for planned extensions (state.json rehydrate, hello handshake, capability advertisement, auto-restart, push, binary media, multi-adapter-per-server).

About

πŸͺ’ Tailnet-only WS harness for CLI coding agents (pi, claude-code, …)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors