Keep Claude Code Remote Control alive on your machine — many projects, one supervisor, and a desktop app to drive it all. Windows, Linux and macOS.
Product page · Download · Report a bug
Claude Code Remote Control lets you drive a Claude Code session running on your own machine from claude.ai or the Claude mobile app. The catch: it is a foreground process in a terminal. Close the window, hit a crash, reboot the machine — and your phone loses the machine.
LiveClaude turns that into infrastructure:
- Multiple agent products — Claude Code Remote Control and Cursor My Machines workers today, each behind its own late-loaded assembly with product-specific session options.
- One long-lived process per session entry, with product-native flags (Claude spawn/capacity/permission; Cursor --name/--worker-dir/ auth).
- A supervisor that restarts a process when it dies (exponential backoff), at sign-in, and after a reboot — hosted by whatever your operating system offers: a Scheduled Task or a Windows Service, a systemd user or system unit, a LaunchAgent or a LaunchDaemon.
- A desktop app to create, edit and remove sessions, watch their state live, read their logs, and install or remove the supervisor. One Avalonia application, the same on all three systems.
- An embedded terminal — a real pseudo terminal (ConPTY on Windows, a pty pair elsewhere) rendered by a VT emulator written from scratch in C# — so the one-time flows that need a terminal (workspace trust, Remote Control confirmation, agent login) happen inside the app, and so you can attach to a running process and type into it.
Everything is C#. No Node, no Python, no tmux, no browser control.
Everything that has to differ between operating systems — the pseudo terminal, autostart, elevation,
the IPC transport, where files live — sits behind one contract and lives in its own assembly, loaded
by name at run time. Agent products (LiveClaude.Product.Claude, LiveClaude.Product.Cursor) ship
the same way. LiveClaude.Core has no compile-time dependency on either.
Claude Code's real TUI rendered inside the app's terminal tab — the trust prompt, and anything else that needs a terminal.
winget install LeandroCannizzaro.LiveClaude- Download LiveClaude-win-x64.zipfrom the latest release.
- Unblock and extract it anywhere.
- Run LiveClaude.exe.
The -selfcontained zip has no prerequisites. The plain zip needs the .NET 10 Desktop Runtime.
Open LiveClaude.application — it installs for the current user and checks for updates on every launch. The manifests are unsigned, so SmartScreen asks once.
Already running 1.x? That channel is frozen at 1.0.15 and keeps working. 2.0 is published to a channel of its own, so a 1.0.15 install is never carried onto it by an update check — install 2.0 alongside, and remove 1.x once you are happy. They are different applications underneath: 1.x is the Windows-only WPF program, 2.x is the cross-platform one.
curl -fsSL https://leandrocannizzaro.github.io/LiveClaude/install.sh | shPicks the .deb, .rpm or tarball for your machine, installs to /opt/liveclaude, and puts
liveclaude and liveclaude-supervisor on your PATH with a desktop entry. x86_64 and arm64,
self-contained — no .NET runtime needed.
By hand, if you prefer:
sudo apt install ./liveclaude_<version>_amd64.deb # Debian, Ubuntu
sudo dnf install ./liveclaude-<version>-1.x86_64.rpm # Fedora, RHEL, openSUSE
tar -xzf LiveClaude-<version>-linux-x64.tar.gz -C ~/liveclaudecurl -fsSL https://leandrocannizzaro.github.io/LiveClaude/install-macos.sh | shDownloads the .dmg for your Mac, copies the app to /Applications and clears the quarantine flag.
Apple silicon and Intel.
Installing the .dmg by hand works too, but the app is not notarised yet: Gatekeeper refuses a
normal double-click, so right-click the app and choose Open the first time. Clearing that flag is
the only reason the script above is worth having.
git clone https://github.com/LeandroCannizzaro/LiveClaude.git
cd LiveClaude
dotnet build -c Release
dotnet run --project src/LiveClaude.AppBuilding a Windows package needs a Windows machine — LiveClaude.Platform.Windows targets
net10.0-windows — but the Linux and macOS packages cross-build from anywhere.
- Open LiveClaude → Sessions → New session.
- Pick the project directory, give it a name, choose spawn and permission mode. The command preview shows exactly what will run.
- Click Trust this directory… — the embedded terminal opens and runs claudethere so you can accept the one-time workspace-trust prompt, then type/exit.
- Click Run remote-control once… the first time, to accept Enable Remote Control? (y/n).
- Save session, then go to Service & startup → Install / update.
The server now shows up at claude.ai/code and in the Claude mobile app, and comes back on its own after a crash, a sign-out or a reboot.
Every system offers two places to register the supervisor, and LiveClaude uses both. The card on the left of Service & startup is always the recommended one.
Starting before anyone signs in is the one thing that works differently everywhere, and each platform says so in the UI rather than quietly installing something that will not do it:
- Windows only lets an administrator register a task with a boot trigger, so installing asks for elevation. Decline it and the task is installed with the logon trigger only.
- Linux needs lingering (loginctl enable-linger <you>) so systemd runs your user manager without a session. LiveClaude offers to enable it; decline and the unit still starts at login.
- macOS cannot do it with a LaunchAgent at all — an agent belongs to the GUI session. The LaunchDaemon can, but the login Keychain stays locked until somebody signs in, and that is where Claude Code keeps its token.
Both scopes are installed from the app, or from the CLI:
LiveClaude.Service install-autostart # your session
LiveClaude.Service install-autostart --scope system --user you
LiveClaude.Service statusinstall-task and install-service are kept as aliases for --scope user and --scope system, so
the Windows documentation, the winget package and anyone's scripts keep working:
LiveClaude.Service.exe install-task
LiveClaude.Service.exe install-service --account "DOMAIN\you" --password "<windows password>"Why installing may ask for elevation (Windows). Windows only lets an administrator register a task
that triggers at system startup: as a normal user, schtasks answers ERROR: Access is denied. The app
therefore asks for elevation through the supervisor executable — the app itself stays asInvoker, which
also means a ClickOnce install (which cannot be launched elevated) works fine. Decline the prompt and the
task is still installed with the logon trigger only: everything works except starting before anyone signs
in. The task is always registered for your account, even when UAC is answered with a different one.
Elsewhere the same prompt comes from pkexec (or sudo) on Linux and from the standard
authentication sheet on macOS, and declining has the same consequence.
What the Windows service needs. Installation is elevated (UAC, again through the supervisor
executable). Running it under your own account additionally needs the Log on as a service right —
sc create obj= does not grant it, and without it the service is created and then refuses to start
with error 1069. LiveClaude grants it during the elevated install. The account also needs a real
password: Windows never lets a user account log on as a service with a blank one.
Who actually runs. The zip and winget packages register LiveClaude.Service.exe. A ClickOnce
install ships that executable without its runtime configuration — .NET then refuses to start it — so
there LiveClaude registers itself instead (LiveClaude.exe --supervise), which hosts the same
supervisor windowlessly. Only one supervisor runs at a time: a second one stops with a note in
logs\supervisor.log rather than supervising the same directories twice.
Installs that move (Windows only). ClickOnce and winget put the app in a folder that is replaced on every update,
which would leave the task or service pointing at an executable that no longer exists. When LiveClaude
detects such a location it first copies the supervisor to %LOCALAPPDATA%\LiveClaude\supervisor and
registers that copy — one path, so the registration survives updates. Because the supervisor runs
from there and holds its own files open, everything running from that folder is stopped before the
copy is refreshed; without that, an update cannot replace the executable and the registration keeps
running the previous build. Linux and macOS install to paths that do not move — /opt/liveclaude and
the .app bundle — so nothing is copied there.
The app talks to whichever supervisor is running over the platform's own channel, so you can close the
window and the servers keep running — and reopen it later to find them. On Windows that is a named
pipe (\.\pipe\LiveClaude.v1), shared across the machine. On Linux and macOS it is a Unix domain
socket in a private per-user directory, created mode 0700 — which makes the "only one supervisor" rule
per-user there, the right answer on a machine two people share.
Every claude remote-control process registers a bridge environment on Anthropic's side, and the
registration outlives the process. Stop a server and start it again and you get a second entry for the
same directory; do it three times and the picker in Claude Desktop shows the project three times, one
live and the rest dead. Archiving conversations does not touch them — they are environments, not
sessions (claude-code#50884).
LiveClaude handles both ends of that:
- It stops servers the way a person would. Stopping sends Ctrl+C and waits (12 s by default, in Service & startup) before terminating, so the CLI gets its chance to deregister. The previous behaviour — a hard kill — is exactly what creates the dead entries.
- It knows which environment is which. When a server comes up, LiveClaude asks the API which bridge environment it just registered and remembers it, so a live entry can never be mistaken for a leftover. Turn this off with Track which environment each server registers to stay fully offline.
- The Environments tab cleans up the rest. It lists the bridge environments on your account
grouped by directory, marks each one live / stale / untracked, and deletes the ones you pick:
- Select duplicates keeps the live one — or the newest — for each directory and selects the
others. This is the answer to "three doG, one alive".
- Select stale picks the environments whose directory LiveClaude supervises but which have no server behind them.
- An environment in use is never selectable, and deletion always asks first. Protection does not depend on the API lookup succeeding: a directory with a running server protects every registration made during that run, including one the server creates again after a delete. Stop the session in the Dashboard to clear those. Leftovers from earlier runs of the same directory stay deletable while the server runs.
- Select duplicates keeps the live one — or the newest — for each directory and selects the
others. This is the answer to "three
The API answers 409 Conflict when an environment still has session records attached:
Environment has 1 active sessions. Use force=true to delete anyway.
Those sessions are themselves leftovers of servers that were killed rather than stopped. LiveClaude
shows the reason on the row and in a panel above the list — with Anthropic's request-id — and offers
a Force delete button that retries with force=true, deleting the environment together with its
session records. Every call, successful or not, is appended to
%ProgramData%\LiveClaude\logs\environments.log; Open log in the toolbar goes straight there.
Not every entry in the picker is a bridge environment: the ones Claude Code on the web creates are
anthropic_cloud environments and are perfectly alive. Tick Show non-bridge environments to see
them.
The tab uses your own Claude Code sign-in (~/.claude/.credentials.json) against
api.anthropic.com/v1/environments with the environments-2025-11-01 beta header. That API is in
beta and undocumented: if Anthropic changes it, the tab reports the error and the rest of LiveClaude
keeps working.
To keep the count down without any cleanup, restart a server within Remote Control's four-hour window
so --continue reattaches instead of registering a fresh environment.
Each session maps one-to-one onto claude remote-control flags:
About the 4-hour window: claude remote-control --continue can only bring back the sessions a stopped server was serving for about four hours. LiveClaude records the stop time per instance and reattaches when it still can; past that it starts a fresh session. The conversations themselves are never lost — they stay resumable locally with claude --resume.
┌─────────────────────────────┐
claude.ai / mobile ───┤ Anthropic Remote Control │
└──────────────┬──────────────┘
│ outbound HTTPS only
┌────────────────────────────────────┼───────────────────────────────┐
│ your machine │ │
│ ▼ │
│ ┌──────────────┐ pipe / socket ┌─────────────────────────────┐ │
│ │ LiveClaude │◄──────────────►│ LiveClaude.Service │ │
│ │ desktop app │ status, │ (task · service · systemd · │ │
│ │ (Avalonia) │ terminal I/O │ LaunchAgent · LaunchDaemon) │ │
│ │ Dashboard │ │ Supervisor │ │
│ │ Sessions │ │ ├── instance "LivePlatform" │ │
│ │ Terminal ───┼────────────────┼──►│ └── pty ─ claude │ │
│ │ Logs │ │ ├── instance "beELive" │ │
│ │ Settings │ │ │ └── pty ─ claude │ │
│ └──────┬───────┘ └───────────┬─────────────────┘ │
│ │ │ │
│ └──────────► LiveClaude.Platform.<OS> ◄────────────────────┤
│ loaded by name at run time │
│ pty · autostart · elevation · paths · IPC │
└────────────────────────────────────────────────────────────────┘
Nothing references a platform assembly at compile time. PlatformLoader probes for
LiveClaude.Platform.<OS>.dll next to the application and loads it by path — by path, because an
assembly nothing references is absent from deps.json and the default resolver would never find it
sitting right there. Delete that file from a published folder and the app stops with one sentence
naming it, which is the cheapest possible proof that the seam is real.
On Windows, a process that owns a console hands its console to every child it starts, and Windows then ignores the pseudo-console attribute — the child's output never reaches your pipes. That is why the supervisor and the app are both windowless executables there, and why the supervisor only borrows the caller's console for one-shot CLI commands. If you ever host the supervisor yourself from a console process, the dashboard will tell you: "this process owns a console…". POSIX has no such rule, so the supervisor is an ordinary console program on Linux and macOS.
On POSIX, the child is started with posix_spawn, never fork. Forking a multi-threaded .NET
process leaves the child holding locks that nothing will ever release, and any managed code running
before exec can deadlock. posix_spawn does the whole open/dup2/exec sequence inside libc. It also
sets a new session, and opening the pty slave without O_NOCTTY makes it the controlling terminal —
which is what turns the 0x03 byte into a real SIGINT. Without a controlling terminal it would be
just a byte, the server would have to be killed, and killing it is exactly what leaves dead bridge
environments in the session picker.
LiveClaude.Service status prints the paths for the machine you are on. In short:
Inside the log directory: <name>-<id>.log per instance, supervisor.log, and install.log —
which is what the elevated install commands printed, since they run in a window nobody sees.
Why the socket is not with everything else. A Unix domain socket path is limited to 104 bytes on
macOS and 108 on Linux, terminator included — and
/Users/<you>/Library/Application Support/LiveClaude/run/ spends more than half of that before the
file name. So the socket goes in a short per-user directory created 0700, the way tmux does it:
$XDG_RUNTIME_DIR/liveclaude/ on Linux when the session has one, /tmp/liveclaude-<uid>/ otherwise
and on macOS. A directory other users cannot traverse is what protects the socket.
Windows keeps one machine-wide root so a service running under another account reads the same
configuration the app writes. POSIX has no equivalent that both a daemon and a desktop user can
reach, so Linux and macOS are per-user. A system-scope daemon opts into a shared root through
LIVECLAUDE_ROOT, which every platform honours. The systemd system unit pins it to
/var/lib/liveclaude (created by StateDirectory=) only when it runs as root; with a named account
it uses that account's home, the same configuration the app writes.
"Needs attention" on a session. Claude Code is waiting for a human: workspace trust, the Remote Control confirmation, or a sign-in. Open the Terminal tab, attach to the instance and answer it — you are typing straight into the running server.
The server exits immediately. Read the instance log. The usual causes are an untrusted directory, a missing sign-in (claude /login in the embedded terminal, or claude setup-token), ANTHROPIC_BASE_URL pointing somewhere other than api.anthropic.com, or DISABLE_TELEMETRY / DO_NOT_TRACK switched on — Remote Control needs the feature-flag check those disable.
The machine-wide host is installed but nothing starts. It is almost certainly running as the
system account. Reinstall it naming your own (--user you) so it uses your profile, where the Claude
credentials live.
Linux: "Failed to connect to bus". systemctl --user needs a session bus, which does not exist
over ssh or in a container. Run loginctl enable-linger <you> so systemd keeps your user manager
running without an interactive session, or use the system unit instead.
macOS: the Environments tab says you are not signed in. Claude Code keeps its token in the login Keychain there. The first read shows an "allow access" prompt — if it was refused, allow LiveClaude in Keychain Access. A LaunchDaemon cannot read it at all before somebody signs in.
The machine sleeps and the sessions go offline. Remote Control needs the machine awake. Disable sleep — on Windows you can also enable Wake the computer to run this task on the scheduled task.
dotnet build # build everything for this machine
dotnet test # 117 tests, no network needed
dotnet run --project src/LiveClaude.App
dotnet run --project src/LiveClaude.Service -- statusThe build picks the platform assembly for the machine you are on, or for the -r you pass:
dotnet publish -r linux-x64 from a Mac produces a Linux package. The one exception is a Windows
package, which needs a Windows machine — LiveClaude.Platform.Windows targets net10.0-windows, and
the build says so rather than producing something half-right.
LiveClaude --terminal <directory> opens the app straight into the embedded terminal for that folder
— the fastest route to a trust prompt.
Issue #1 is the build log: one comment per phase, from the first question to v1.0.15, including the bugs that reported success while doing nothing. Worth reading before changing the hosting, deployment or environment code — most of those decisions look arbitrary until you know what they are guarding against.
Issue #2 is the plan the cross-platform rework followed, including the traps it was written to avoid.
Issues and pull requests are welcome. Keep the C#-only rule: no Node, no web views, no native
dependencies beyond each platform's own libc or Win32. And keep the seam: new platform code belongs
in a platform assembly, and LiveClaude.Core stays free of operating-system conditionals.
MIT © Leandro Cannizzaro
LiveClaude is an independent project. It is not affiliated with, endorsed by, or sponsored by Anthropic.