| name | remotecmd-sidecar |
| description | Use this skill when pairing remotecmd into a Docker container via an HTTP sidecar endpoint (no terminal access), or when debugging/auditing the sidecar's security model, relay allowlist, or deployment wiring. |
remotecmd-sidecar Skill
Pair remotecmd into any app running in a Docker container — no terminal access needed. The sidecar is a tiny HTTP endpoint inside your app that downloads the rcmd binary and starts the daemon when triggered.
Architecture
localhost relay container (app + sidecar)
│ │ │
├─ rcmd pair listen │ │
│ --require-activation-key │ │
│ → code bb5f9f │ │
│ │ │
│ POST https://app.fr/__rcmd/pair │
│ {relayUrl, code, activationKey, name} │
│ ─────────────────────────────────────────→ download rcmd │
│ spawn daemon │
│ connect to relay│
│ │ ←── daemon registered │
│ ←── peer connected │ │
│ │ │
├─ rcmd exec --target <name> │ │
│ --cmd 'hostname' │ │
│ ─────────────────────────────→│──────────────────────→ sh -c │
│ ←── stdout │←────────────────────── │
│ │ │
├─ rcmd pair disconnect --target <name> │
│ ─────────────────────────────→│──────────────────────→ exit │
Components
1. Sidecar library (remotecmd-sidecar)
Repo: ~/ai/remotecmd-sidecar — two implementations:
- Node.js (
node/index.js) — raw HTTP handler, works with Express or plain http
- Go (
go/sidecar.go) — http.Handler interface, works with net/http
Both expose the same behavior:
POST /__rcmd/pair — downloads rcmd binary from GitHub releases, spawns daemon in background
- Rate limited: 1 valid request per minute (invalid/disallowed requests don't consume the token)
- Binary cached in
$TMPDIR/.rcmd-cache/
2. CLI commands (in remotecmd-cli)
# Start listening for a peer (generates pair code)
remotecmd-cli pair listen --name <target-name> --require-activation-key [--timeout <s>]
# Trigger sidecar endpoint to pair the container
remotecmd-cli sidecar activate \
--url https://app.example.com \
--relay http://relay:3032 \
--code <pair-code> \
--activation-key <key> \
--name <target-name> \
[--timeout <s>]
# Disconnect (kill switch — daemon exits with os.Exit(0))
remotecmd-cli pair disconnect --target <name>
Security model
Layer 1: Relay URL allowlist (sidecar-side)
RCMD_ALLOWED_RELAYS env var — comma-separated allowlist of relay URLs/patterns. The sidecar validates relayUrl before doing anything. Fail-closed if not set (defaults to *.intrane.fr).
| Pattern | Matches | Example |
|---|
*.intrane.fr | Any subdomain of intrane.fr | http://relay.intrane.fr:3032 |
intrane.fr | intrane.fr + any subdomain | http://intrane.fr:3032 |
http://92.113.145.178:3032 | Exact URL only | that exact URL |
* | Anything (testing only) | — |
Why this matters: Without the allowlist, an attacker who discovers the sidecar endpoint could POST their own relayUrl, causing the daemon to connect to the attacker's relay — granting them shell access. The activation key doesn't help because the attacker controls their own relay.
Validation order: allowlist check runs BEFORE the rate limiter, so rejected relay URLs don't consume the rate limit token.
Layer 2: Activation key (relay-side)
The relay enforces activation keys for pair acceptance. The joining daemon must present a valid key via --activation-key. Keys are managed on the relay:
remotecmd-cli relay add-key <key>
remotecmd-cli relay remove-key <key>
remotecmd-cli relay list-keys
Layer 3: Pair code (single-use, 300s TTL)
The pair code is generated by pair listen and is single-use with a 5-minute timeout. It's only useful in combination with a valid activation key and an allowed relay URL.
Integrating the sidecar into an app
Node.js / Express
const express = require('express');
const router = express.Router();
module.exports = router;
app.use("/__rcmd", require("./routes/sidecar"));
Go / net/http
import "github.com/javimosch/remotecmd-sidecar/go"
handler := sidecar.NewHandler()
http.Handle("/__rcmd/pair", handler)
Env vars
| Env var | Default | Description |
|---|
RCMD_ALLOWED_RELAYS | *.intrane.fr | Comma-separated relay URL allowlist |
RCMD_ENDPOINT_PATH | /__rcmd/pair | Override the endpoint path (library only) |
Full live test flow
remotecmd-cli relay add-key my-app-key-2026
remotecmd-cli pair listen --name my-app --require-activation-key --timeout 180
remotecmd-cli sidecar activate \
--url https://app.example.com \
--relay http://92.113.145.178:3032 \
--code <from-step-2> \
--activation-key my-app-key-2026 \
--name my-app
remotecmd-cli exec --target my-app --cmd 'hostname && ls /app'
remotecmd-cli pair disconnect --target my-app
Implementation details
- Daemon spawning: Uses
daemon start -daemon (background mode) with stdio: 'ignore' and detached: true so the daemon survives the HTTP request lifecycle. The child process is unref()'d so it's not tied to the parent.
- Disconnect behavior: The daemon calls
os.Exit(0) on receiving a disconnect message — it does NOT reconnect. This is intentional: disconnect is a kill switch.
- Binary download: Fetches from GitHub releases API, caches in
$TMPDIR/.rcmd-cache/. Supports linux/darwin amd64/arm64.
- Rate limiting: Only valid + allowed requests consume the rate limit token. Invalid JSON, missing fields, and disallowed relay URLs are rejected without consuming the token.
Testing
cd ~/ai/remotecmd-sidecar/go && go test -timeout 15s -v
cd ~/ai/remotecmd-sidecar/node && node test.js
Tests cover: allowlist matching (wildcard, exact domain, exact URL, multiple patterns, invalid URLs), rate limiting, handler integration, and the security rejection path (403 for disallowed relays).
Repositories
~/ai/remotecmd (a.k.a. remotecmd-cli) — the CLI, daemon, relay. Sidecar CLI commands: sidecar activate, pair listen, pair disconnect.
~/ai/remotecmd-sidecar — standalone sidecar library (Node.js + Go). Reusable across any app.
~/ai/supergato — supergato app with sidecar route at src/routes/sidecar.js.
~/pr/sso-server (branch rcmd-sidecar) — SSO server with sidecar route at src/routes/sidecar.js.