{"id":51385935,"url":"https://github.com/agent-rt/arc","last_synced_at":"2026-07-03T20:33:28.430Z","repository":{"id":368326799,"uuid":"1284608490","full_name":"agent-rt/arc","owner":"agent-rt","description":"Remote control for Agents — end-to-end-encrypted remote control of another machine by an AI agent, over a relay or Tailscale-direct.","archived":false,"fork":false,"pushed_at":"2026-06-30T04:43:17.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-30T05:18:14.152Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agent-rt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-30T03:13:59.000Z","updated_at":"2026-06-30T04:43:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/agent-rt/arc","commit_stats":null,"previous_names":["agent-rt/arc"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/agent-rt/arc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agent-rt%2Farc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agent-rt%2Farc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agent-rt%2Farc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agent-rt%2Farc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agent-rt","download_url":"https://codeload.github.com/agent-rt/arc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agent-rt%2Farc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35101093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-03T20:33:27.947Z","updated_at":"2026-07-03T20:33:28.425Z","avatar_url":"https://github.com/agent-rt.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# arc\n\n[![CI](https://github.com/agent-rt/arc/actions/workflows/ci.yml/badge.svg)](https://github.com/agent-rt/arc/actions/workflows/ci.yml)\n\n**Agent remote control.** Let an AI agent on one machine (e.g. Claude Code on\nmacOS) drive another machine (e.g. Windows) over an encrypted link — build and\nrun apps, operate GUIs, move files — through **semantic, structured tools**, not\na pixel stream.\n\nIt is *not* a remote desktop: there's no screen-sharing for humans. The agent\ncalls tools — run a command, list/click UI elements, type, screenshot, transfer\nfiles — over an end-to-end-encrypted channel. Part of\n[`agent-rt`](https://github.com/agent-rt) (`rt` = runtime).\n\n## Install\n\n**Controller** (macOS / Linux) — the `arc` CLI, which is also the MCP server:\n\n```bash\nbrew install agent-rt/tap/arc\n```\n\n**Runner** (Windows) — the machine being driven:\n\n```powershell\nwinget install agent-rt.arc-runner\n```\n\n## Quickstart\n\nOver Tailscale (recommended — no relay, no pairing code to copy):\n\n1. On the **Windows** runner, register it (autostarts at logon). On Tailscale\n   it's one flag — `--tailscale` auto-detects the tailnet IP and restricts\n   access to this machine's Tailscale owner:\n\n   ```powershell\n   arc-runner install --tailscale\n   ```\n\n   (Equivalent to `--listen \u003ctailnet-ip\u003e:8787 --trust-tailnet --allow \u003cowner\u003e`,\n   still passable explicitly; `--allow-any` permits any tailnet peer, `--port`\n   changes the port, `--dry-run` previews.) It mints credentials and prints a\n   ready-to-paste `[targets.win]` block.\n\n2. On the **controller**, drop that block into `~/.config/arc/config.toml`:\n\n   ```toml\n   default = \"win\"\n\n   [targets.win]\n   direct = \"\u003ctailnet-ip\u003e:8787\"\n   trust_tailnet = true\n   ```\n\n3. Drive it:\n\n   ```bash\n   arc -t win shell --cmd 'ver'\n   ```\n\n`arc-runner uninstall` removes the task; `arc-runner upgrade` self-updates it to\nthe latest release (download → validate → swap → restart). For relay mode\ninstead of Tailscale, use `arc-runner install --relay \u003cws-url\u003e`.\n\n\u003e Coming from `ssh` + `scp`? See **[docs/from-ssh.md](docs/from-ssh.md)** for a\n\u003e side-by-side migration of the common workflow.\n\n## Usage\n\n```bash\narc shell --cmd 'dotnet build'      # run a command (streams live; --timeout \u003csecs\u003e)\narc run ./fix.ps1 -Port 8788        # ship \u0026 run a local script (.ps1/.bat); args pass through\narc push ./app C:/work/app          # send a tree up (incremental, .gitignore-aware)\narc watch ./app C:/work/app --on-change 'cargo build'   # auto-push + rebuild on every save\narc pull C:/work/app/bin ./bin      # fetch a tree (or file) back\narc cat C:/work/app/log.txt         # print a remote file\narc tail C:/work/app/log.txt -f     # follow a remote log (streams new lines)\narc shot ui.png --launch notepad    # launch → wait for render → screenshot, one shot\narc screencap shot.png --window N   # screenshot to a file (.png/.webp by extension)\narc screencap now.png --window N --baseline before.png --diff diff.png   # regression diff\narc windows --filter notepad        # list top-level windows (--json for structured)\narc elements \u003chwnd\u003e --json          # list a window's UI Automation elements\narc find \u003chwnd\u003e --type Button --name Save   # query elements by attribute (no full dump)\narc wait \u003chwnd\u003e --name Done --timeout 30     # block until a matching element appears\narc open notepad                    # launch an app\narc activate \u003chwnd\u003e                 # restore + foreground a window (before capture/input)\narc ps notepad                      # list remote processes; arc kill \u003cpid|name\u003e\narc click \u003celement-id\u003e              # click a UI element (from `elements`)\narc read \u003celement-id\u003e               # read one control's text (verify without a screenshot)\narc set \u003celement-id\u003e 'text'         # set a control's value directly\narc type 'hello' --into \u003celement-id\u003e   # focus an element, then type into it\narc type \"$(cat big.txt)\" --into \u003cid\u003e --paste   # paste long text via clipboard (fast)\narc key ctrl+a delete --into \u003cid\u003e   # key chords in sequence (--into focuses an element first)\narc mouse drag 40 80 300 400        # move / click / down / up / scroll / drag\narc clip get                        # read the remote clipboard; arc clip set 'text'\narc agents-md                        # full Markdown command reference for an AI agent\n```\n\n### Connecting\n\n`arc` finds a runner via a saved **named target** (`-t \u003cname\u003e`, or the config's\n`default`), explicit flags (`--direct` / `--relay` / `--session` / `--pairing`),\nor env vars (`ARC_DIRECT` / `ARC_RELAY_URL` / `ARC_SESSION` / `ARC_PAIRING`).\nConfig lives in `~/.config/arc/config.toml`:\n\n```toml\ndefault = \"win\"\n\n[targets.win]                  # Tailscale-direct, identity-authenticated\ndirect = \"100.x.y.z:8787\"\ntrust_tailnet = true\n\n[targets.public]               # over a relay\nrelay   = \"wss://relay.example/v1/relay\"\nsession = \"0011…ffff\"\npairing = \"XXXX-XXXX\"\n```\n\n### Files \u0026 the dev loop\n\n`push`/`pull` are direction-by-verb (controller→runner / runner→controller). A\nsingle file is copied wholesale; a **directory transfers incrementally** —\ncontent-hashed with one round-trip to skip unchanged files, never walking build\ndirs (`target`/`bin`/`obj`/…). Flags: `--delete` (mirror the source),\n`--dry-run`, `--whole` (skip the diff). `arc watch` keeps a tree mirrored live\n(debounced, build-churn-ignoring); add `--on-change '\u003cbuild\u003e'` to rebuild on the\nbox after every sync — a zero-ssh edit → build → run → screenshot loop. To run a\nlocal script on the box,\n`arc run ./script.ps1 [args]` ships its contents and executes it (interpreter by\nextension; `.ps1` runs with `-ExecutionPolicy Bypass`) — no `push` first, no\ncross-shell quoting to escape, args passed straight through.\n\n\u003e The model is *code lives on your Mac; the Windows box is a build/run\n\u003e container.* With **Windows App SDK 2.x** an unpackaged WinUI 3 app builds with\n\u003e just the .NET SDK (no Visual Studio), so a fresh runner + .NET SDK builds WPF /\n\u003e WinForms / console / WinUI 3.\n\n### MCP\n\nThe same `arc` binary runs as a stdio MCP server with `arc --mcp`, exposing every\ncapability as a tool (`run_command`, `run_script`, `screenshot`, `list_windows`,\n`list_elements`, `find_elements`, `click`, `type_text`, `set_value`, `read_file`,\n`write_file`, …). Register it with, e.g.,\n[`mcpctl`](https://github.com/agent-rt/mcpctl):\n\n```bash\nmcpctl server add arc --command arc --args --mcp \\\n  --env ARC_DIRECT=\u003ctailnet-ip\u003e:8787 --env ARC_PAIRING=XXXX-XXXX\n```\n\nIt connects lazily on the first tool call and reconnects on drops. `run_command`\nstreams output (relayed as MCP progress when the client supplies a\n`progressToken`), so an agent can watch a long build in real time.\n\n## Modes\n\nThe relay exists to solve NAT traversal; on a shared private network it's\nunnecessary.\n\n- **Direct** (recommended on Tailscale / LAN): the runner listens\n  (`arc-runner --listen \u003cip\u003e:8787`) and the controller dials it — no relay, no\n  extra process, lower latency.\n- **Relay**: both peers dial an `arc-relay`, which matches them by `SessionId`\n  and forwards opaque ciphertext (it holds no key).\n- **Trusted-tailnet auto-pairing** (`trust_tailnet = true`): the runner\n  authenticates each caller by **verified Tailscale identity** (`tailscale\n  whois`, optionally restricted to `allow_logins`), so no pairing code is\n  exchanged — authentication is the WireGuard transport plus identity, with a\n  fixed public key for the (defense-in-depth) Noise channel.\n\n## Architecture\n\n```\n controller (macOS/Linux)        relay (optional)           runner (Windows)\n┌────────────────────┐  wss  ┌──────────────┐  wss  ┌──────────────────────┐\n│  arc  /  arc --mcp  │──────►│  arc-relay   │──────►│  arc-runner          │\n│  (CLI / MCP server) │◄──────│ opaque relay │◄──────│ shell·UIA·input·     │\n└────────────────────┘       │  (no key)    │       │ screenshot·files     │\n         └────────── L2: Noise channel, end-to-end encrypted ──────────┘\n```\n\n- **L1 — relay** (`proto::relay`): `Hello` + `SessionId` + `Role`, then opaque\n  `Relay{data}` frames forwarded between the session's two peers. Zero-knowledge.\n  Skipped entirely in direct mode.\n- **L2 — end-to-end** (`proto::wire`): `Request` / `Response` / `Event` carrying\n  `Command`s, sealed in a Noise channel (`proto::crypto`) and chunked through the\n  32 MiB frame cap.\n\nBoth transports share one `Session` (`arc-net`), used by the CLI, the MCP\nserver, and the runner.\n\n### Capability tiers (by session state)\n\n| Capability | Mechanism | In a detached session? |\n|---|---|---|\n| `list_*`, `set`, element `click` | UI Automation (COM) | ✅ works |\n| single-window `screencap` | GDI `PrintWindow` | ✅ works |\n| `type`, `key`, coordinate `mouse`, full-screen `screencap` | `SendInput` / DXGI | ⚠️ needs an active console/RDP session |\n\nUIA *pattern-based* control works headlessly; raw input and full-screen capture\nneed a connected desktop. `ElementId` is `\"\u003chwnd\u003e:\u003cRuntimeId\u003e\"`, resolved by\nRuntimeId identity — it keeps pointing at the same control across tree changes,\nor returns `NotFound`.\n\nThe runner serves requests **concurrently** (a hung command never blocks the\nlink or other commands) and enforces a default 10-minute command deadline\n(`--timeout \u003csecs\u003e`; `0` to disable).\n\n## Security\n\nThe relay sees only ciphertext. The low-entropy pairing code is never used as a\nkey directly: both peers run a symmetric **SPAKE2** PAKE to derive a\nhigh-entropy key that keys `Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s`. Recording\nthe handshake gives no offline dictionary attack; a wrong code makes the Noise\nhandshake fail. In `trust_tailnet` mode the boundary is Tailscale ACLs plus\nverified identity.\n\n## Build from source\n\n```bash\njust build      # release `arc` (CLI + MCP server)\njust lint       # clippy -D warnings (host crates)\njust test\n```\n\n| Crate | Role |\n|---|---|\n| `arc-proto`  | wire protocol, CBOR framing, Noise channel (chunked), SPAKE2 |\n| `arc-net`    | shared client transport — relay/direct `Session` |\n| `arc-relay`  | zero-knowledge `wss` relay (`axum`) |\n| `arc-runner` | Windows runner: shell, screenshot, UI Automation (`windows-rs`), input (`enigo`) — **Windows-only** |\n| `arc-cli`    | the `arc` binary: CLI **and** `arc --mcp` server |\n\n`arc-runner` builds only on Windows (`windows-rs`, `xcap`); the controller\ncrates build everywhere. Release/packaging is in [`RELEASING.md`](RELEASING.md).\n\n## License\n\nMIT OR Apache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagent-rt%2Farc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagent-rt%2Farc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagent-rt%2Farc/lists"}