The machine that should run five agents, five dev servers, and a test suite is
often not the laptop in front of you. Because archcar owns all the state and
every surface is a client of it, moving execution to a server is a deployment
choice rather than a different product.
Nothing here requires a display on the server. It has no GUI dependency at all.
What ends up where
Agent CLI authentication and gh auth login have to happen on the server.
Authenticating on your laptop does nothing for a server-hosted session.
Set up the server
Install the CLI and daemon by whichever channel you prefer — the tarball, CLI
AppImage, AUR package, Nix, Homebrew, or the APT/DNF archductor package all
ship both archductor and archcar. Then:
That installs the background service (a systemd user unit on Linux, a launchd
agent on macOS, a Task Scheduler logon task on Windows), starts it, provisions
an access token, and reports whether the daemon can reach the tools it needs.
Add --listen 0.0.0.0:7420 only if clients will use the TCP transport. For
SSH, which is what you should use, omit it — SSH needs no open port.
service setup exits non-zero if the daemon did not start, so a provisioning
script can trust its status, and it refuses to print connection instructions
for a listener that is not actually up.
Two things it handles that are easy to get wrong by hand:
Surviving logout. systemd stops a user manager when the user’s last login
session ends, so a unit you install over SSH dies the moment you disconnect.
Install runs loginctl enable-linger and tells you if it could not.
archductor service status reports boot_persistent.
The daemon’s PATH. launchd gives a job /usr/bin:/bin:/usr/sbin:/sbin,
and a systemd user unit is barely richer. Neither can see Homebrew, a version
manager, or ~/.local/bin, so the daemon fails to find codex even though your
shell finds it instantly. Install probes your login shell and bakes the
resulting PATH into the unit.
service doctor is the check that distinguishes “the service is running” from
“the service is usable”. Run it after any change to how tools are installed.
- macOS: a launchd agent starts at login, not at boot. On a headless Mac,
log in once after a reboot, or install a root-owned LaunchDaemon yourself.
- Windows: logon tasks have the same scope. Running while logged off means
storing the account password in Task Scheduler, which Archductor will not do
on your behalf.
- AppImage: install refuses to write a unit pointing into an AppImage’s
temporary mount (
/tmp/.mount_*), because that unit works right up until the
next reboot. Extract or install properly on a server.
Connect from a client machine
connect verifies the daemon responds before saving, so a typo fails fast
instead of half-configuring the machine.
One profile moves the whole machine: the CLI, the desktop app (Settings →
Remote daemon), and archductor mcp serve all follow it. The desktop app will
not spawn a local sidecar while a remote is configured.
Resolution order, highest first:
ARCHDUCTOR_ARCHCAR_REMOTE / ARCHDUCTOR_ARCHCAR_TOKEN in the environment
- The saved profile (
$XDG_STATE_HOME/archductor/remote.json, owner-only)
- The local daemon
Why SSH rather than the token
ssh:// runs archductor archcar stdio-proxy on the far side and pipes the
protocol through the SSH connection. The destination is handed to ssh
verbatim, so ~/.ssh/config applies — host aliases, jump hosts, and per-host
keys all work.
If archductor is not on the non-interactive PATH over SSH, give the path
explicitly:
On the TCP transport. It is a shared bearer token in cleartext: no TLS, no
per-client identity, and rotating the token revokes every client at once. A
bare port (--listen 7420) binds loopback only; anything else must sit behind
a VPN, an SSH tunnel, or a TLS reverse proxy. Use ssh:// and none of this
applies.
Several daemons
Save more than one and switch between them — a work server, a home box, and
your laptop.
The label is what appears in the app’s switcher.
Working against a remote
Most commands behave the same; paths are the exception, because they resolve on
the daemon’s filesystem, not yours.
archductor repo add is refused while a remote profile is active — it takes a
local path that means nothing on the server. Use the daemon-side command
instead:
Two commands answer “is the server healthy”, as opposed to this machine:
archductor service status and archductor service doctor, without archcar,
always answer for the machine you typed them on. That distinction matters when
you are debugging a session that will not start.
Pulling a workspace back to your machine
You reviewed something on the server and now want it locally — same branch,
same conversation. remote import reads from the remote and writes to your
local daemon, matching repositories by clone URL rather than by path. Both
daemons are contacted; neither talks to the other.
Omit --thread-id to import the workspace without a chat. --name and
--branch rename it locally.
Without --clone-into the import stops and asks rather than picking a directory
on your disk. With it, the whole first-time flow is one command — which matters
precisely here, since repo add is refused while a remote profile is active.
In the app this is “Copy to this machine” on a workspace’s right-click menu,
shown only while a remote client is selected.
MCP against a remote
Because MCP tools are archcar requests, an MCP client pointed at a machine with
a saved remote profile drives the server’s daemon:
Your local Claude Code can now read and drive the server-hosted workspaces.
Prefer the default session profile over --full unless you specifically want
an agent that can create and archive workspaces.
Protocol details
docs/api.md
documents the transports, the envelope format, the workflow objects, and the
stability policy. Read it if you are writing a client rather than operating one.