{"id":45697167,"url":"https://github.com/spianmo/ferryman","last_synced_at":"2026-03-13T04:06:26.046Z","repository":{"id":339158108,"uuid":"1160691550","full_name":"spianmo/Ferryman","owner":"spianmo","description":"Ferryman is a single-binary, single-process LAN remote access host built with C++20 and libhv, providing a browser control plane for file management, PTY terminal sessions, async task execution, audit logs, and real-time screen monitoring/remote control via WebRTC signaling and native streaming.  ","archived":false,"fork":false,"pushed_at":"2026-03-06T06:49:26.000Z","size":1206,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-06T11:03:23.952Z","etag":null,"topics":["cpp20","file-manager","libhv","pty","react","remote-control","screen-streaming","self-hosted","vite","webrtc"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spianmo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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-02-18T08:58:35.000Z","updated_at":"2026-03-06T06:49:31.000Z","dependencies_parsed_at":"2026-02-18T14:01:26.342Z","dependency_job_id":null,"html_url":"https://github.com/spianmo/Ferryman","commit_stats":null,"previous_names":["spianmo/ferryman"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/spianmo/Ferryman","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spianmo%2FFerryman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spianmo%2FFerryman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spianmo%2FFerryman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spianmo%2FFerryman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spianmo","download_url":"https://codeload.github.com/spianmo/Ferryman/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spianmo%2FFerryman/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30457987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T03:55:51.346Z","status":"ssl_error","status_checked_at":"2026-03-13T03:55:33.055Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cpp20","file-manager","libhv","pty","react","remote-control","screen-streaming","self-hosted","vite","webrtc"],"created_at":"2026-02-24T21:04:54.525Z","updated_at":"2026-03-13T04:06:26.040Z","avatar_url":"https://github.com/spianmo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"FurinaBanner.png\" style=\"border-radius: 12px;\" alt=\"Ferryman banner\"\u003e\n\u003c/p\u003e\n\n# Ferryman\n\n![C++20](https://img.shields.io/badge/C%2B%2B-20-00599C)\n![CMake](https://img.shields.io/badge/CMake-3.20%2B-064F8C)\n![React](https://img.shields.io/badge/React-18-61DAFB)\n![Vite](https://img.shields.io/badge/Vite-5-646CFF)\n![Native Stream](https://img.shields.io/badge/Native%20Stream-JPEG%2FH264%2FH265%2FVP8%2FVP9%2FAV1-0EA5E9)\n![Platforms](https://img.shields.io/badge/Platforms-macOS%20%7C%20Linux%20%7C%20Windows-334155)\n\nEnglish | [中文](README_CN.md)\n\nFerryman turns a machine you trust into a browser-accessible **AI coding control plane**.\nWhen Claude / Codex / Cursor / Gemini / OpenCode style CLI agents are running long tasks on a remote host, you should not need to babysit the machine or bounce between SSH, a web IDE, a remote desktop tool, and infra dashboards. AI also does not magically become self-explanatory just because you left your desk, grabbed coffee, or checked on it from your phone mid-walk. Ferryman keeps that workflow in one place: check progress, approve actions, browse and edit workspace files, take over the terminal, and jump into IDE, screen streaming, or host operations when needed.\n\nFerryman treats **mobile-friendly access** as a first-class requirement.\nWith a public FerrymanProxy or your own FerrymanProxy deployed on a public Linux server, you can bring your VibeCode terminal with you to practically any place with a browser. For developers who keep wondering whether the remote AI task back at home or in the office has started improvising, that peace of mind matters.\n\nIt is not just a web terminal and not just another remote desktop.\nFerryman is built for the new **AI agent + remote host** workflow: agents keep working, humans step in occasionally, and every intervention needs full context, enough control, and an auditable trail. It can also surface and import existing local Codex / Claude / Cursor / Gemini / OpenCode sessions so you can continue from the context already in your head instead of reconstructing it from memory.\n\n## Why Developers Care About Ferryman\n\n- **Built around AI coding rather than generic remote access**: CodeAgent, terminal, files, Git, attachments, event streams, and permission interactions live in one workflow.\n- **Mobile-friendly when you need to step in fast**: phones and tablets remain useful for checking, approving, and steering long-running tasks away from your desk.\n- **FerrymanProxy makes global reach practical**: once a public FerrymanProxy entry point is in place, the machine at home or in the office is no longer trapped inside one LAN.\n- **Local session continuation feels natural**: existing CLI-agent transcripts can be imported so the browser UI starts with real context instead of a blank slate.\n- **Brings development and operations into one entry point**: switch between `code-server`, screen control, Docker, VMs, tunnel management, and system monitoring from the same browser UI.\n- **Low-friction and self-host friendly**: single process, single binary, designed for LAN/private-network deployment with minimal runtime dependencies and clear auditability.\n\n## Coming Soon\n\n- **Ralph Wiggum Loop**: a clearer rhythm for agent collaboration, with less \"what is it secretly doing now?\" and more \"what is it about to do next?\"\n- **Developer Kanban**: a better surface for watching sessions, tasks, blockers, and next actions across multiple AI workstreams.\n\nFerryman combines:\n\n- a built-in **CodeAgent** panel for Claude / Codex / Cursor / Gemini / OpenCode session workflows\n- file browsing, file search, upload/attachment flow, and workspace-scoped read/write\n- PTY terminal sessions and async task execution\n- Git-oriented coding context such as status / diff browsing inside a session workspace\n- built-in **code-server** management and embedded IDE view\n- runtime logs and audit stream\n- WebRTC signaling + native screen streaming and remote input injection\n- Docker container management (lifecycle/metrics/logs/files)\n- Dockurr VM management (create/start/stop/restart/logs/inspect)\n- built-in tunnel mapping panel (FerrymanProxy integration)\n- realtime device monitor dashboard (CPU/GPU/memory/disk)\n\nThe project keeps frontend and backend in one repository, uses explicit HTTP/WebSocket contracts, and pulls remote AI coding, host control, and infrastructure operations into one self-hostable browser workspace.\n\n## Core Capabilities\n\n### Access and Session Model\n\n- First run bootstraps `~/.ferryman/config.ini` with a generated `access_key`.\n- Login uses access key + session token (`X-Session-Token`) for all protected HTTP/WS channels.\n- Multiple users can log in at the same time.\n- Terminal/task contexts are scoped by session token (`owner_token`) for isolation and traceability.\n- Login currently grants command/screen authorization by default (no extra manual approval step).\n\n### Remote AI Coding\n\n- **Built-in CodeAgent panel (hapi-compatible)**:\n  - integrated directly into Ferryman UI (`#/codeagent`), rendered without iframe, independent from `code-server`\n  - C++ backend endpoint set compatible with hapi web API (`/api/auth`, `/api/sessions`, `/api/events`, `/api/machines`, etc.)\n  - supports Claude / Codex / Cursor / Gemini / OpenCode command templates\n- **Session-based workflow**:\n  - create sessions by machine, workspace directory, agent flavor, model, and permission mode\n  - session lifecycle controls: resume / abort / archive / rename / delete\n  - runner/session state tracking with realtime event delivery\n- **Interactive coding controls**:\n  - permission approvals/denials from browser UI\n  - ask-user-input / question-answer flows for plan-mode style interactions\n  - per-session model controls, including reasoning effort and Codex fast mode\n- **Workspace context for coding**:\n  - directory tree, file read/browse, file search, and session file views\n  - file upload + attachment flow for prompts\n  - Git status / diff browsing in the session workspace\n  - dedicated session terminal over WebSocket\n- **External agent history discovery**:\n  - discover and import existing local transcripts from Codex / Claude / Cursor / Gemini / OpenCode\n  - continue remote work from previously created local CLI agent sessions\n\n### Runtime and Development Environment\n\n- **Transport layer**: `libhv` HTTP + WebSocket server (single listener; WS and HTTP share one port at runtime).\n- **JSON payloads**: parsed/serialized with `nlohmann/json`.\n- **File operations**: list/read/write under workspace root (`$HOME` by default), with path boundary checks.\n- **Terminal**: child process + PTY (`forkpty`), ANSI passthrough, browser rendering via `xterm.js` (including 256-color support).\n- **Tasks**: async command execution with status lifecycle (`queued/running/succeeded/failed`), polling and output retrieval.\n- **Logs**:\n  - immediate backend output (`stdout/stderr`)\n  - in-memory tail buffer via `/api/logs/tail`\n  - realtime WS push via `/ws/logs`\n- **code-server panel**:\n  - detect host install state and support one-click install from UI\n  - launch/restart `code-server` with configurable port and HTTP/HTTPS\n  - TLS modes: `ferryman`, `selfsigned`, `custom`; runtime log: `~/.ferryman/logs/codeserver.log`\n\n### Host and Infrastructure Operations\n\n- **Dockurr VM manager**:\n  - create/list/start/stop/restart Windows/macOS VMs\n  - startup/runtime logs and inspect output\n  - Linux hosts can trigger one-click KVM installation from UI when `/dev/kvm` is unavailable\n- **Docker manager**:\n  - container list + start/stop/restart\n  - CPU/memory/network/block I/O metrics and process view\n  - inspect/logs and in-container file list/read/write/upload/download\n- **Tunnel (NAT traversal) panel**:\n  - FerrymanProxy host/port/token configuration\n  - mapping CRUD (`tcp`/`udp`) with enable/disable + online test\n  - local listening ports table (address/port/process/pid)\n- **Realtime monitor panel**:\n  - device snapshots over `/ws/monitor`\n  - CPU/GPU/memory/disk cards and trend charts\n- **Screen + remote control**:\n  - WebRTC room signaling (`join` / `signal`) channel\n  - native screen stream over WS binary frames (`FRM1`)\n  - keyboard/mouse event uplink and native input injection\n  - soft-key combos for Ctrl/Alt/Meta plus Tab/Esc/system-attention shortcuts\n  - drag-and-drop file transfer with conflict strategy + chunked upload session APIs\n  - codec/fps/resolution/bitrate negotiation for native stream subscribers\n\n### Screen Backends\n\n- macOS: ScreenCaptureKit + ApplicationServices\n- Linux: X11 capture + XTest input\n- Windows: GDI capture + SendInput\n- Encoders:\n  - always available: `jpeg`\n  - when ffmpeg is available: `h264`, `h265`, `vp8`, `vp9`, `av1`\n- Runtime profiles:\n  - FPS: `1..60`\n  - Resolution tiers: `full(100%)`, `balanced(75%)`, `performance(50%)`\n  - Bitrate tiers: `sd(1.5Mbps)`, `hd(3Mbps)`, `uhd(6Mbps)`\n\n## Architecture\n\n```text\nBrowser (React/Vite)\n  |- /api/*  (HTTP)\n  |- /ws/terminal (WebSocket)\n  |- /ws/codeagent/terminal (WebSocket)\n  |- /ws/codeagent/events   (WebSocket)\n  |- /ws/webrtc   (WebSocket)\n  |- /ws/logs     (WebSocket)\n  |- /ws/dockurr  (WebSocket)\n  |- /ws/monitor  (WebSocket)\n  `- /ws/tunnel   (WebSocket)\n\nFerryman (single process)\n  |- SessionManager / Auth (access key)\n  |- CodeAgentManager\n  |- FileService\n  |- PtyManager\n  |- TaskManager\n  |- AuditLogger\n  |- DockurrManager\n  |- DockerManager\n  |- TunnelManager\n  |- SystemMonitor\n  |- WebRtcSignalingService\n  `- ScreenService + VideoEncoder (ffmpeg)\n```\n\n## CodeAgent Integration\n\n- The CodeAgent module is a standalone panel in Ferryman UI (`#/codeagent`) and serves as Ferryman's primary **remote AI coding workspace**.\n- The CodeAgent backend is fully implemented in C++ (`CodeAgentManager` + HTTP handlers in `ServerApp`) and runs in parallel with `code-server` without shared process/state coupling.\n- Copied hapi frontend source is merged into `frontend/src/codeagent*` and built together with Ferryman UI rather than embedded through an iframe.\n- Sessions can be created with explicit workspace, agent flavor, model, and permission mode, then controlled remotely through browser-based approvals, file views, Git context, terminal access, and realtime event streams.\n- Ferryman can also surface and import local agent transcripts, making the CodeAgent panel a bridge between existing CLI-agent workflows and browser-based remote continuation.\n\n## Repository Layout\n\n- `include/ferryman/*`: backend headers\n- `src/*`: backend implementation\n- `frontend/*`: Vite + React + TypeScript control panel\n- `cmake/EmbedAssets.cmake`: embed `frontend/dist` into generated C++ source\n- `scripts/make_deps.sh`: dependency bootstrap\n- `Makefile`: one-command workflows\n\n## Build and Run\n\n### 0) Install C++ dependencies (vcpkg)\n\n```bash\nmake deps\n```\n\n`make deps` includes:\n\n- local downloads cache: `.vcpkg-downloads`\n- local binary cache: `.vcpkg-binary-cache`\n- archive prefetch + SHA-512 verification (nlohmann-json / meson / ffmpeg), with mirror fallback URLs\n\nOptional proxy mode (if local `useProxy` command exists):\n\n```bash\nmake deps-proxy\n```\n\nOptional mirror/proxy envs:\n\n- `FERRYMAN_USE_PROXY=1`\n- `NLOHMANN_JSON_URL=\u003cmirror-url\u003e`\n- `MESON_URL=\u003cmirror-url\u003e`\n- `FFMPEG_URL=\u003cmirror-url\u003e`\n- `GITHUB_MIRROR_PREFIX=\u003cprefix\u003e`\n- `VCPKG_ASSET_SOURCES=\u003casset-source-config\u003e` (passed through to `X_VCPKG_ASSET_SOURCES`)\n\nFor Windows single-exe builds without third-party DLLs, use a static triplet:\n\n```powershell\n$env:VCPKG_TARGET_TRIPLET = \"x64-windows-static\"\ncmake -S . -B build -A x64 `\n  -DCMAKE_BUILD_TYPE=Release `\n  -DCMAKE_TOOLCHAIN_FILE=\"$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake\" `\n  -DVCPKG_TARGET_TRIPLET=$env:VCPKG_TARGET_TRIPLET\ncmake --build build --config Release --parallel\n```\n\n### 1) Build frontend assets\n\n```bash\nmake frontend\n```\n\n### 2) Build backend\n\n```bash\nmake build\n```\n\n### 3) Run\n\n```bash\nmake run\n```\n\nOn first run, Ferryman generates and prints an access key, and writes config to `~/.ferryman/config.ini`.\n\n### One-command release build\n\n```bash\nmake release\n```\n\n## Split Development Mode\n\nRun backend and frontend separately.\n\nTerminal 1:\n\n```bash\nmake dev-backend\n```\n\nTerminal 2:\n\n```bash\nmake dev-frontend\n```\n\nOpen:\n\n- `http://127.0.0.1:5173`\n\nOptional proxy override:\n\n```bash\ncd frontend\nVITE_BACKEND_HTTP_URL=http://127.0.0.1:28080 \\\nVITE_BACKEND_WS_URL=ws://127.0.0.1:28080 \\\nnpm run dev -- --host\n```\n\n## Runtime Configuration\n\nDefault config file: `~/.ferryman/config.ini`\n\n```ini\naccess_key=\u003cgenerated\u003e\nhttp_host=0.0.0.0\nhttp_port=18080\nhttps_enabled=false\nhttps_port=18443\ntls_cert_file=\ntls_key_file=\nws_port=18080\ncodeserver_port=13337\ncodeserver_https_enabled=true\ncodeserver_https_mode=ferryman\ncodeserver_https_cert_file=\ncodeserver_https_key_file=\ntunnel_proxy_host=\ntunnel_proxy_port=17000\ntunnel_proxy_token=\ntunnel_mappings_json=[]\n```\n\nNote:\n\n- HTTP and WebSocket share the same listener port at runtime.\n- `ws_port` is still written to config for backward compatibility, but runtime forces it to match `http_port`, so it is no longer independently configurable.\n- Set `https_enabled=true` to enable HTTPS/WSS. HTTP/WS stay available on `http_port`.\n- If `tls_cert_file`/`tls_key_file` are empty, Ferryman auto-generates `~/.ferryman/cert/server.crt` and `~/.ferryman/cert/server.key` on first HTTPS startup.\n- Auto-generated certificate paths are written back into `~/.ferryman/config.ini` (`tls_cert_file` / `tls_key_file`).\n- Ferryman also initializes `~/.ferryman/logs/` and reserves `audit.log` path for audit output.\n- `codeserver_port/codeserver_https_enabled/codeserver_https_mode/codeserver_https_cert_file/codeserver_https_key_file` are used by the built-in code-server panel.\n- `tunnel_proxy_host/tunnel_proxy_port/tunnel_proxy_token/tunnel_mappings_json` are used by the built-in tunnel panel for NAT traversal settings.\n\n## FerrymanProxy (Linux)\n\n`FerrymanProxy` is a standalone public proxy server (Linux-only) for Ferryman reverse TCP/UDP port mappings, and a key building block for making Ferryman feel natural on phones, tablets, and browsers outside your home network.\n\nBuild the standalone target:\n\n```bash\ncmake --build build --target FerrymanProxy -j\n# or\nmake build-proxy\n```\n\nRun the proxy server:\n\n```bash\n./build/FerrymanProxy --bind 0.0.0.0 --control-port 17000 --admin-host 127.0.0.1 --admin-port 17001 --log-file /var/log/ferryman-proxy.log\n```\n\nOne-click deployment on public Linux (install binary + systemd + firewall):\n\n```bash\nsudo ./scripts/deploy_ferryman_proxy.sh \\\n  --bin ./build/FerrymanProxy \\\n  --bind 0.0.0.0 \\\n  --control-port 17000 \\\n  --admin-host 127.0.0.1 \\\n  --admin-port 17001\n```\n\nCLI inspect current mappings and modes:\n\n```bash\n./build/FerrymanProxy --list --admin-host 127.0.0.1 --admin-port 17001\n./build/FerrymanProxy --status --admin-host 127.0.0.1 --admin-port 17001\n./build/FerrymanProxy --logs 200 --admin-host 127.0.0.1 --admin-port 17001\n```\n\nEnable at boot via systemd template:\n\n```bash\nsudo cp scripts/ferryman-proxy.service /etc/systemd/system/ferryman-proxy.service\nsudo systemctl daemon-reload\nsudo systemctl enable --now ferryman-proxy\nsudo systemctl status ferryman-proxy\n```\n\n## HTTP API\n\n### Core and Host Features\n\n| Method | Path | Description |\n|---|---|---|\n| `POST` | `/api/auth/login` | Access key login |\n| `GET` | `/api/session/me` | Session info + host capability flags (`host_os` / `docker_installed` / `codeserver_installed` / `kvm_installed`) |\n| `GET` | `/api/health` | Health check |\n| `GET` | `/api/files/list` | List directory |\n| `GET` | `/api/files/read` | Read file |\n| `POST` | `/api/files/write` | Write file |\n| `POST` | `/api/tasks/start` | Start async task |\n| `GET` | `/api/tasks/list` | List tasks |\n| `GET` | `/api/tasks/get` | Task detail/output |\n| `GET` | `/api/logs/tail` | Tail runtime audit logs |\n| `POST` | `/api/codeserver/config` | Update code-server port/TLS config, persist, and restart |\n\n### Dockurr and Docker\n\n| Method | Path | Description |\n|---|---|---|\n| `GET` | `/api/dockurr/list` | List Dockurr VMs |\n| `POST` | `/api/dockurr/create` | Create VM (windows/macos, version/ram/disk/persist/name) |\n| `POST` | `/api/dockurr/start` | Start VM |\n| `POST` | `/api/dockurr/stop` | Stop VM |\n| `POST` | `/api/dockurr/restart` | Restart VM |\n| `POST` | `/api/dockurr/delete` | Delete VM |\n| `GET` | `/api/dockurr/logs` | Get VM logs |\n| `GET` | `/api/dockurr/inspect` | Inspect VM metadata |\n| `GET` | `/api/docker/list` | List Docker containers |\n| `POST` | `/api/docker/service/start` | Attempt to start the local Docker service |\n| `POST` | `/api/docker/start` | Start container |\n| `POST` | `/api/docker/stop` | Stop container |\n| `POST` | `/api/docker/restart` | Restart container |\n| `GET` | `/api/docker/logs` | Container logs |\n| `GET` | `/api/docker/inspect` | Container inspect output |\n| `GET` | `/api/docker/stats` | Container CPU/memory/network/block metrics |\n| `GET` | `/api/docker/processes` | Container process list |\n| `GET` | `/api/docker/files/list` | List files inside container path |\n| `GET` | `/api/docker/files/read` | Read file inside container |\n| `POST` | `/api/docker/files/write` | Write file inside container |\n\n### Screen and Tunnel\n\n| Method | Path | Description |\n|---|---|---|\n| `GET` | `/api/screen/capabilities` | Screen capability negotiation |\n| `GET` | `/api/screen/sources` | List available local screens/monitors |\n| `POST` | `/api/screen/input` | Native input injection |\n| `POST` | `/api/screen/upload/preflight` | Check transfer conflicts before upload |\n| `POST` | `/api/screen/upload/begin` | Create upload session |\n| `POST` | `/api/screen/upload/chunk` | Append chunk to upload session |\n| `POST` | `/api/screen/upload/commit` | Finalize upload session |\n| `POST` | `/api/screen/upload/cancel` | Cancel upload session |\n| `GET` | `/api/tunnel/state` | Tunnel config + mapping runtime state |\n| `POST` | `/api/tunnel/config` | Update FerrymanProxy host/port/token and persist |\n| `POST` | `/api/tunnel/mapping/upsert` | Add or update one TCP/UDP mapping |\n| `POST` | `/api/tunnel/mapping/delete` | Delete one mapping |\n| `POST` | `/api/tunnel/mapping/test` | Test one mapping and return pass/fail detail |\n| `GET` | `/api/tunnel/ports` | List local listening ports/process/pid |\n\n### CodeAgent (hapi-compatible)\n\n| Method | Path | Description |\n|---|---|---|\n| `GET` | `/api/codeagent/runner/state` | Fetch aggregate runner state |\n| `POST` | `/api/bind` | Establish CodeAgent bearer binding |\n| `GET` | `/api/events` | Fetch CodeAgent event stream |\n| `POST` | `/api/visibility` | Update event visibility |\n| `GET` | `/api/sessions` | List sessions |\n| `GET` | `/api/sessions/{sid}` | Fetch one session |\n| `PATCH` | `/api/sessions/{sid}` | Rename session |\n| `DELETE` | `/api/sessions/{sid}` | Delete session |\n| `GET` | `/api/sessions/{sid}/messages` | Fetch session messages |\n| `POST` | `/api/sessions/{sid}/messages` | Send session message |\n| `POST` | `/api/sessions/{sid}/resume` | Resume session execution |\n| `POST` | `/api/sessions/{sid}/abort` | Abort current execution |\n| `POST` | `/api/sessions/{sid}/archive` | Archive session |\n| `POST` | `/api/sessions/{sid}/permission-mode` | Update permission mode |\n| `POST` | `/api/sessions/{sid}/model` | Update model |\n| `POST` | `/api/sessions/{sid}/reasoning-effort` | Update reasoning effort |\n| `POST` | `/api/sessions/{sid}/codex-fast` | Toggle Codex Fast mode |\n| `POST` | `/api/sessions/{sid}/permissions/{rid}/approve` | Approve permission request |\n| `POST` | `/api/sessions/{sid}/permissions/{rid}/deny` | Deny permission request |\n| `GET` | `/api/sessions/{sid}/slash-commands` | Fetch slash command list |\n| `GET` | `/api/sessions/{sid}/skills` | Fetch available skills |\n| `GET` | `/api/sessions/{sid}/git-status` | Fetch session Git status |\n| `GET` | `/api/sessions/{sid}/git-diff-numstat` | Fetch Git diff numstat |\n| `GET` | `/api/sessions/{sid}/git-diff-file` | Fetch one file diff |\n| `GET` | `/api/sessions/{sid}/file` | Read file in session workspace |\n| `GET` | `/api/sessions/{sid}/files` | Search files in session workspace |\n| `GET` | `/api/sessions/{sid}/directory` | List session workspace directory |\n| `POST` | `/api/sessions/{sid}/upload` | Upload attachment into session |\n| `POST` | `/api/sessions/{sid}/upload/delete` | Delete uploaded attachment |\n| `GET` | `/api/machines` | List available machines |\n| `POST` | `/api/machines/{mid}/spawn` | Spawn session on target machine |\n| `POST` | `/api/machines/{mid}/paths/exists` | Batch-check path existence |\n| `GET` | `/api/machines/{mid}/directory` | List target machine directory |\n\n### Push and Voice\n\n| Method | Path | Description |\n|---|---|---|\n| `GET` | `/api/push/vapid-public-key` | Fetch Web Push public key |\n| `POST` | `/api/push/subscribe` | Register Web Push subscription |\n| `DELETE` | `/api/push/subscribe` | Remove Web Push subscription |\n| `POST` | `/api/voice/token` | Fetch realtime voice session token |\n\n## WebSocket Channels\n\n### `/ws/terminal`\n\nActions:\n\n- `open`\n- `attach`\n- `input`\n- `resize`\n- `close`\n\n### `/ws/codeagent/terminal`\n\nActions:\n\n- `open`\n- `input`\n- `write`\n- `resize`\n- `close`\n\n### `/ws/codeagent/events`\n\nServer push only:\n\n- CodeAgent session / machine / global event stream\n- `heartbeat`\n\n### `/ws/webrtc`\n\nActions:\n\n- `join` (room signaling peer join)\n- `signal` (SDP/ICE payload forwarding)\n- `native_subscribe`\n- `native_unsubscribe`\n- `input_event`\n\n### `/ws/logs`\n\nActions:\n\n- `tail`\n- `snapshot`\n\n### `/ws/dockurr`\n\nActions:\n\n- `list`\n- `snapshot`\n- `create`\n- `start`\n- `stop`\n- `restart`\n- `delete`\n- `logs`\n- `inspect`\n\n### `/ws/monitor`\n\nActions:\n\n- `snapshot`\n- `refresh`\n- `ping`\n\nServer push:\n\n- `monitor_snapshot`\n\n### `/ws/tunnel`\n\nActions:\n\n- `snapshot`\n- `refresh`\n- `ping`\n\nServer push:\n\n- `tunnel_snapshot`\n\n## Native Screen Streaming\n\n- Transport: WebSocket binary packet (`FRM1` header)\n- Codec IDs:\n  - `1`: JPEG\n  - `2`: H.264\n  - `3`: H.265\n  - `4`: VP8\n  - `5`: VP9\n  - `6`: AV1\n- Backend negotiates codec/fps/resolution/bitrate based on active subscribers.\n\nIf ffmpeg is unavailable, native video encoding is disabled and capability negotiation falls back accordingly.\n\n## Security Model\n\n- LAN-oriented deployment (default host: `0.0.0.0`).\n- Access-key login required.\n- Session token required for protected HTTP/WS endpoints.\n- Login grants command/screen access by default (current behavior).\n- Key actions are auditable through:\n  - immediate backend console logs\n  - in-memory log tail (`/api/logs/tail`, `/ws/logs`)\n- Session-scoped ownership is applied to terminal/task operations.\n\n## Build Notes\n\n- `vcpkg` manifest mode via `vcpkg.json`\n- Frontend assets are embedded by `cmake/EmbedAssets.cmake`\n- If `libhv` is missing, backend still compiles but server startup fails with guidance.\n- On macOS, native screen and input features require system permissions:\n  - Screen Recording\n  - Accessibility\n\n## Contributing\n\nPlease read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a PR.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspianmo%2Fferryman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspianmo%2Fferryman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspianmo%2Fferryman/lists"}