{"slug": "cordane-run-coding-agents-on-machines-you-own-no-open-ports", "title": "Cordane – run coding agents on machines you own, no open ports", "summary": "Cordane launched a self-hostable control plane for AI coding agents such as Claude Code that runs workers on user-owned machines and has each worker dial out to a central hub over a single outbound WebSocket Secure (WSS) connection, so machines behind corporate NAT or a home router are reachable from any browser with no inbound ports, VPN or SSH configuration. The hub is a single Go binary that can run on a small VPS with two containers or as a managed service, and Cordane offers every feature free forever when self-hosted. The product adds persistent PTY terminals that survive laptop closes, network drops and hub restarts, a kanban board that cuts a git worktree and boots a dev server on its own port for each ticket, scheduled runs in the user's time zone, and a full audit trail of each run's prompt, diff and checks.", "body_md": "**Run your team's coding agents from anywhere — on machines you own.**\n\nCordane is a self-hostable control plane for AI coding agents (Claude Code and\nfriends) and the terminals, dev servers, and tickets around them. Workers run on\nyour hardware and dial **out** to the hub over a single outbound connection — so\nyou can reach a box behind corporate NAT or a home router from any browser, with\nno inbound ports, no VPN, no SSH config.\n\n🌐 **[cordane.ai](https://cordane.ai)** · 📖 **[Docs](https://cordane.ai/docs)** ·\n🗺 **[Roadmap](https://cordane.ai/roadmap)** · 🔒 [Security](https://github.com/cordane/cordane/blob/main/SECURITY.md)\n\n**Free forever, self-hosted, every feature.** Try it on your own machine in one\ncommand ([`cordane up`](#try-it-on-your-machine)), run two containers on a small\nVPS for your team ([quickstart](#self-hosting)), or let us run the hub for you:\nsee [pricing](https://cordane.ai/#pricing).\n\n<sub>A real run, not a rehearsal — [watch the full 3:36](https://www.youtube.com/watch?v=3IyaGPtSgRw) · [30+ one-feature walkthroughs](https://www.youtube.com/@cordanehq)</sub>\n\n```\nflowchart LR\n    subgraph anywhere[\"Any browser, anywhere\"]\n        B[\"You + your team<br/>(laptop, phone)\"]\n    end\n    subgraph hub[\"Hub — one Go binary<br/>(your VPS or managed cloud)\"]\n        H[\"Web UI · board · proxy\"]\n    end\n    subgraph yours[\"Machines you own (behind NAT/firewall)\"]\n        W1[\"Worker: terminals · agents · apps\"]\n        W2[\"Worker: terminals · agents · apps\"]\n    end\n    B -->|HTTPS| H\n    W1 -.->|\"dials OUT (WSS)\"| H\n    W2 -.->|\"dials OUT (WSS)\"| H\n```\n\n**Persistent terminals, one browser tab away.** Real PTYs on your machines —\nyour login shell, your dotfiles, true color — that survive closing the laptop,\nnetwork drops, and hub restarts. Reattach from any browser, including your\nphone (with a touch key bar for ctrl/esc/arrows). Two people can attach to the\nsame live terminal. If you live in tmux: sessions map to *spaces*, panes to\nside-by-side terminals, and *space definitions* (saved layout + working dir +\ncommand per pane) respawn your setup on demand — an alternative, not a drop-in\nreplacement (no tmux keybindings or copy-mode). Files move without `scp`: a\n**files** menu on the space browses the machine, downloads a file or a whole\nfolder (videos, PDFs, images and logs also open in a tab), and takes drops to\nupload; `cordane get report.pdf` typed in a terminal\noffers that file to whoever may download it. Owner-only unless you say\notherwise.\n\n**A board that runs the work.** Drop a ticket on the kanban board and Cordane\ncuts a git worktree, boots the dev server on its own port, and turns your\ncoding agent loose — while the whole team watches live. Or give the ticket a\nstart time — 07:00, in *your* time zone, not the server's — and it runs itself\novernight, so the branch and the diff are waiting when you sit down. Review a\ndiff and a green-checks badge, then merge — from your phone if that's where you\nare. Not right yet? **Request changes**: write what to fix, click lines of the\ndiff to pin notes to them, and send it back — to the agent in the ticket's\nspace (the same session, if the space is still open) or as a background pass\non the same branch. A project can also send failing checks back to the agent on\nits own: the failing commands and the tail of their output, up to a retry\nbudget you set (off by default), after which the ticket waits in review for\nyou. Review on GitHub instead? A *changes requested* on the PR becomes the same\nkind of round, read with the worker's own `gh` and only from the repo's\ncollaborators. Anything the agent leaves in `.cordane/outputs/` — a screenshot\nof the feature, a report — is attached to the ticket when its run ends. Agents\nknow both channels without being told: the hub installs a [skill](https://github.com/cordane/cordane/blob/main/skills) on\nevery worker that Claude Code, Codex, opencode and pi read at session start.\nEvery run keeps its full audit trail: exact prompt, exact diff, what checks ran.\nKeep your tracker — this is the execution layer where agent work happens, not a\nproject-management tool. Tickets come in from **Sentry, Jira, GitHub Issues or\nLinear** (paste an issue URL, or let a filter create them), and the upstream\nissue is closed when the ticket is done.\n\n**More than one agent, more than one ticket.** A ticket can wait on others\n(*blocked by*), and a plan too big for one pass splits into sub-tickets that\ncan run one after another. Not sure which agent will do it best? **Race** two or three on the\nsame ticket — each in its own worktree on its own branch — compare their diffs\nand checks side by side, and keep the winner. **Detect from repo** reads your\nmanifests on the worker and proposes the setup, start and check hooks, so a new\nproject doesn't start from a blank form.\n\n**Told when it matters, and what it cost.** An agent stuck on a permission\nprompt, a failed run, a plan waiting for approval, work ready for review:\nCordane tells the person whose agent it is — in the browser, through a webhook\n(presets for ntfy, Slack and Discord), or by email when the hub has SMTP.\nAgents can speak up mid-run too: `cordane mcp` gives the agent working a ticket\ntools to read it, comment, file a follow-up, attach a file or flag it for a\nhuman. Each headless run records the usage its agent CLI reports — tokens, and\ncost from Claude Code and opencode — and a per-project **Insights** page shows\nruns, success rate, time and spend by agent.\n\n**Terminals an agent — or your laptop — can drive.** In a space, the same\n`cordane mcp` server lets an agent work the space's other terminals: run a\ncommand and get back its output and exit code, type keys, wait for output, or\nhand the agent in another pane a task. It reaches only its own space, and by\ndefault an agent working a ticket imported from Sentry, Jira, Linear or GitHub\n— or one that has read such a ticket — may only read its neighbours. With a\npersonal API token (**Settings → API tokens**), an MCP client on your laptop —\nClaude Code or Cursor over `https://<hub>/api/v1/mcp`, Claude Desktop by\nsigning in — can start and stop spaces, define layouts, run worker apps, share\nspaces and drive their terminals. Admins can turn tokens off or limit them to\nadmins; terminal input is written to the audit log.\n\n**Preview links without a tunnel.** Apps on a worker get a stable subdomain\n(`myapp--worker.your-domain`) served through the worker's outbound connection —\nno ngrok, no rotating hostnames, no per-seat paywall. Auth on by default;\nflip an app to **Public** to share it with anyone, no account needed. Ticket\npreviews stay team-only. (For sharing previews — Cordane is not an inbound\ntunnel for webhooks.)\n\n**Teams on your terms.** GitHub sign-in with an admin-managed allowlist,\nprojects shared across a team, each member running work on their own private\nworker. Self-host the hub on a $5 VPS, or use the managed cloud\n(`your-team.cordane.app`) — workers stay on your hardware either way. Your\ncode, secrets, and compute never leave machines you control.\n\nOne short video per feature, nothing staged — the agent output is whatever the model produced on the day it was filmed.\n\n| [Close your laptop, keep your shell](https://www.youtube.com/watch?v=fQDuRSfVSUs) · 1:26 | a process on your machine survives a closed tab **and a hub restart** — timestamps prove it | \n| [Handing a ticket to a coding agent](https://www.youtube.com/watch?v=3IyaGPtSgRw) · 3:36 | Plan cuts a worktree and hands Claude Code the ticket; the plan lands back on the card | \n| [Self-hosting a worker](https://www.youtube.com/watch?v=7rDSToBdE4o) · 1:16 | one command behind NAT, then `ss -ltnp` shows it listens on nothing | \n| [Port forwards — no ngrok](https://www.youtube.com/watch?v=GhaUgoS6QBQ) · 3:20 | a stable link for any port, and a share link that needs no account | \n| [Cordane on a phone](https://www.youtube.com/watch?v=B18gW68vpBg) · 0:35 | the whole hub, not a cut-down app — a PR reviewed and merged from a phone | \n\nAll of them, by topic: [@cordanehq](https://www.youtube.com/@cordanehq). How it\nworks under the hood: [One outbound WebSocket](https://cordane.ai/blog/outbound-websocket).\n\n- **One Go binary, two roles** :`cordane server` (hub) and`cordane worker` .\n- **Workers dial out** over WebSocket; the hub never connects in. Nothing to\nport-forward, nothing inbound to firewall.\n- **SQLite** for all hub state — trivial backups (built-in Litestream\nreplication to any S3-compatible bucket), no database server, easy export.\n- Joining a machine is one command:\n\n```\ncordane worker join https://your-team.cordane.app --token crdjt_…\n```\n\nOne command, no server, no DNS, no GitHub app:\n\n```\ncurl -fsSL https://cordane.ai/install.sh | sh   # the `cordane` binary (Linux, macOS)\ncordane up\n```\n\nOr both in one go, which also works before `~/.local/bin` is on your `PATH`:\n`curl -fsSL https://cordane.ai/install.sh | sh -s up`.\n\n`cordane up` starts a hub on `localhost` with this machine as its worker, signs\nyou in, and opens the board in your browser. It's a single-user hub that\nlistens only on loopback: sign-in links come from the terminal (`cordane login`\nprints a fresh one), and app previews open at\n`http://<app>--<worker>.localhost:8080` in Chrome, Firefox or Edge\n(`--path-previews` covers Safari). Everything lives in `~/.cordane-local`, so\n`rm -rf ~/.cordane-local` starts over. Terminals and agents run while the\ncommand does, and Ctrl-C stops them; `cordane up --install-service` keeps it\nrunning in the background instead (a systemd user service or launchd agent that\nstarts at login). When you want it on your phone, for a\nteam, or always on, self-host a hub (below) or use\n[managed cloud](https://cordane.ai/#pricing). Your machine stays the worker\neither way.\n\nTwo containers on one small VPS: the hub, plus Caddy for automatic TLS. Images\nare public on GHCR, so you need nothing installed but Docker. First point a DNS\n`A` record for your hub's hostname (e.g. `cordane.example.com`) at the box.\n\n```\ngit clone https://github.com/cordane/cordane.git\ncd cordane/deploy\ncp .env.example .env         # fill in the values below, then:\ndocker compose up -d\ndocker compose logs -f       # both containers; Ctrl-C once the hub is listening\n```\n\nFive values in `.env` get you running — your hub's URL, a secret key, and a\nGitHub OAuth app's id/secret for sign-in:\n\n| Var | What | \n|---|---|\n| `EXTERNAL_URL` /`CONTROL_HOST` | your hub's URL / hostname | \n| `CORDANE_SECRET_KEY` | `openssl rand -base64 32` —**back this up** | \n| `CORDANE_GITHUB_CLIENT_ID/SECRET` | a GitHub OAuth app ( [create one](https://github.com/settings/applications/new) ): homepage = your`EXTERNAL_URL` , callback`${EXTERNAL_URL}/api/v1/auth/github/callback` ; then*Generate a new client secret* | \n\nThat's simple mode: one hostname, a normal certificate, previews at\n`/w/{worker}/{app}/`. Wildcard preview subdomains need a DNS API token —\nswitching is three lines in `.env`, see [` deploy/README.md`](https://github.com/cordane/cordane/blob/main/deploy/README.md).\n\nOpen your `EXTERNAL_URL` and sign in with GitHub — **the first account to sign\nin becomes the admin**, so do it right away. Then connect a machine:\n\n```\ncurl -fsSL https://<your-hub>/install.sh | sh            # installs the `cordane` binary\ncordane worker join https://<your-hub> --token crdjt_…   # token from the hub's Workers page\n```\n\n`join` enrolls the machine and keeps running as the worker; to keep it up after\nyou log out, run it under systemd/launchd (`cordane worker run` — see\n[`deploy/README.md`](https://github.com/cordane/cordane/blob/main/deploy/README.md#keep-the-worker-running)).\n\n1. **On the worker** , install the agent you want and sign in once in a normal\nterminal — e.g.`claude` (Claude Code),`codex` ,`opencode` or`pi` . Cordane\ndrives the agent that's there; it doesn't bring its own login.\n2. **New project** : pick your worker and a repo (an SSH/HTTPS URL it can clone,\nor a checkout already on the worker). For implementing, tick**Allow the\nagent to run commands** — off by default, because a background (headless)\nimplement runs the agent without permission prompts.\n3. **New ticket** →**▶ Plan** : the ticket's space opens with the agent working.\nWhen the plan lands,**✓ Approve → Implement** . These buttons drive the agent\nlive in the space, so it asks you there for any permission it needs — answer\nin the pane (or set the project's agent command to skip them, e.g.`claude --dangerously-skip-permissions` ). When the agent finishes, the ticket\nmoves to review with its diff, and a PR if the worker has`gh` .\n\nBackups to any S3-compatible bucket and the wildcard mode are in\n[`deploy/README.md`](https://github.com/cordane/cordane/blob/main/deploy/README.md).\n\n**No license key required.** The Community tier — 1 worker, 1 project, 2 users,\n3 concurrent agent runs, and *every* feature — is free forever and makes no\nlicense calls; the only request a keyless hub sends us is an update check\n(release channel name only — `CORDANE_UPDATE_CHECK=off` turns it off). Paid keys\nlift the caps and keep working offline within a grace window, so a Cordane\noutage never blocks you. See [pricing](https://cordane.ai/#pricing).\n\nThis is Cordane's public home — bug reports and feature requests are welcome in\n[Issues](https://github.com/cordane/cordane/issues). For anything security-related, see\n[SECURITY.md](https://github.com/cordane/cordane/blob/main/SECURITY.md).\n\nThe contents of **this repository** — documentation and deployment\nconfiguration — are MIT-licensed ([LICENSE](https://github.com/cordane/cordane/blob/main/LICENSE)). Copy, fork and adapt them\nfreely.\n\nThe **container images** they deploy (`ghcr.io/cordane/cordane`,\n`ghcr.io/cordane/caddy`) are proprietary software owned by Sitedity SRL, free to\nrun on the Community tier and otherwise governed by the\n[Terms](https://cordane.ai/terms). [`NOTICE`](https://github.com/cordane/cordane/blob/main/NOTICE) spells out the split.", "url": "https://wpnews.pro/news/cordane-run-coding-agents-on-machines-you-own-no-open-ports", "canonical_source": "https://github.com/cordane/cordane", "published_at": "2026-10-27 12:56:46+00:00", "updated_at": "2026-10-27 13:13:02.295301+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["Cordane", "Claude Code", "Codex", "opencode", "pi", "GitHub"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/cordane-run-coding-agents-on-machines-you-own-no-open-ports", "markdown": "https://wpnews.pro/news/cordane-run-coding-agents-on-machines-you-own-no-open-ports.md", "text": "https://wpnews.pro/news/cordane-run-coding-agents-on-machines-you-own-no-open-ports.txt", "jsonld": "https://wpnews.pro/news/cordane-run-coding-agents-on-machines-you-own-no-open-ports.jsonld"}}