# Remote host commands

> Set up a headless remote host, scope device grants, configure a private relay, and recover uncertain remote requests.

Remote control is an alpha feature. The host owns accepted work independently
of the controlling connection. For the app workflow, see
[Remote access](https://www.hansard.dev/sync/remote-access/).

Install Hansard and authenticate the required agent CLIs on the host first.
The host supplies the working files, agent sign-in, and permission settings.
Sharing an archive through Personal Sync grants no execution access.

## Register a host and project

On the host:

```sh
hansard remote host init --label "Workstation"
hansard remote host project sample --cwd /srv/projects/sample
hansard remote host start
```

Use an existing checkout for `--cwd`. `hansard remote host run` runs an
attended foreground host instead. A detached host started through the CLI or
app returns after a restart, logout, or crash while the watcher runs.
`hansard remote host stop` stops the host and its active work and clears that
restart choice.

The host offers the harnesses enabled under **Settings → Handoff & helpers**.
`hansard remote status` reports each host's installed agents and known sign-in
state. Claude Code and Codex checks run offline. A sign-in that Hansard cannot
inspect is unknown, rather than a confirmed usable credential.

## Pair over Tailscale

On the host:

```sh
hansard remote host direct on
hansard remote host pair --projects sample
```

On the controlling computer, use the address and one-time code the host prints:

```sh
hansard remote pair workstation --address workstation.example.ts.net --code XXXX-XXXX-XXXX-XXXX
```

Codes work once and expire after ten minutes. Direct connections listen on port
47821 of the host's Tailscale address by default. They wait while Tailscale is
disconnected. Each grant or pairing code supplies the key for its encrypted
connection. Host administration stays local.

Run `remote host pair`, `remote host link`, and `remote host revoke` in your
own interactive terminal. They refuse to run in an agent's shell, and so does
`remote host grant`, which needs no terminal because SSH enrollment runs it.

`--network any` on `remote host direct on` listens on every network interface.
`--bind` selects one address. Use these only for the network exposure intended
for that host. They do not remove the grant requirement.

## Enroll through SSH

An SSH controller can use a grant file instead of a pairing code. On the host:

```sh
hansard remote host grant --label "Laptop" --projects sample --output controller.json
```

The enrollment file contains a secret. Keep it readable only by its owner and
transfer it securely. On Windows, keep it inside a private directory as well.
Authenticate the SSH alias in a trusted terminal before adding it to Hansard.

On the controller:

```sh
hansard remote add workstation --ssh workstation --enrollment controller.json
hansard remote status workstation
```

SSH automation uses strict host-key checking and batch mode. It does not ask
for passwords or MFA, install software, or repair SSH. SSH remote commands
require a POSIX host shell. Windows hosts use authenticated named pipes locally
and direct TLS between computers.

## Grant the intended project scope

Without a scope, a grant reaches the registered shared projects and the
host archive's 200 most recent project folders, leaving out folders that are an
agent's own working space: temporary folders, Claude Code scratch workspaces,
projectless chat folders, and agent worktrees. `--projects` limits it to named
registered projects. `--portfolio` applies a portfolio's rules each time the
device asks.

`hansard remote projects workstation` lists every folder the host offers, a
page at a time; `--query` finds folders by name or path. `hansard remote
devices` shows each paired device's state, Hansard version, ready agents, and
projects, and `hansard remote check workstation` runs the quick check from
Settings, a read-only run that reports whether an agent there answers.

Project grants restrict where work starts and which runs a device can see.
They do not confine an agent's filesystem access. The agent keeps its native
permissions. The composer lists permission modes supported by the host.
A Codex conversation retains the mode of its first message.

Remove a saved controller connection with `hansard remote remove workstation`.
This does not revoke its host grant. Revoke on the host with
`hansard remote host revoke <controller-id>` or **Allowed devices → Remove**.
Accepted work continues until separately stopped.

## Configure internet access

Internet access needs an explicitly configured tunwg relay. Hansard provides
no public relay and does not provision one. The relay needs a public DNS name,
TCP ports 80 and 443, its chosen UDP port, and wildcard DNS for device URLs.

On an initialized host with a registered project:

```sh
hansard remote host relay --api relay.example.com --auth-file relay-key.txt
hansard remote host access on
hansard remote host access status
```

Keep the credential file private. Wait for `online`, which requires a successful
public HTTPS check. Then create a link that names what the phone can work in:

```sh
hansard remote host link --projects sample
```

Use `--all` for every project folder on the host, or `--portfolio <id>` for
the folders one configured portfolio matches. A link takes exactly one of
these. The link works once and expires after ten minutes. A browser opens the dedicated
conversation page. Its session lasts up to thirty days unless revoked or signed
out. Another Hansard installation can read a privately transferred link from a
file or stdin:

```sh
hansard remote connect workstation --link-file -
```

The gateway exposes pairing and control, not the local viewer or host
administration. It listens on loopback, and the tunnel connects outward.
Hansard verifies the pinned tunnel executable's SHA-256 before running it.
Relay TLS traffic passes through to the host's tunnel process.

`--tcp` forces the HTTPS tunnel fallback. Failed UDP connections also try that
fallback. Retry delays double up to five minutes, and access reports offline
after six failures. Omitting `--auth-file` preserves a saved credential only
when the relay hostname stays unchanged. Relay credentials never enter
Personal Sync.

`hansard remote host access off` closes internet and direct listeners while
accepted work continues. SSH remains governed by SSH sign-in and host grants.
`HANSARD_REMOTE_CONTROL=0` disables all remote access and new execution.
The explicit host-stop command remains available.

## Recover an uncertain request

Start a synthetic example request with an operation identifier:

```sh
hansard remote start workstation --project sample --provider codex \
  --prompt "Explain the test layout" --operation-id sample-request-1
hansard remote receipt workstation --operation-id sample-request-1
```

`hansard remote follow workstation --project sample --run <run-id> --wait 20000`
reads a run's status, latest reply, and requests waiting for the person.

Keep each operation identifier and its exact input when retrying. Hansard does
not automatically queue or replay prompts after a disconnect. Inspect the
receipt and current events first because accepted work can still be running.
Follow event pages using `next_after` while `has_more` is true.

Approvals and answers bind to the current host process, conversation turn,
request, and controller lease. The app can retain pending action identifiers
across reloads and recover their receipt. It does not save prompt text,
answers, or attachment bytes for replay after a reload.

Uploads are limited to 512 KiB per file and ten attachments per message.
They belong to one controller and registered project. A controller's local
path never becomes a host path.

## Storage and cluster limits

Use one Hansard installation for a provider store. Its execution owners must
use the same private runtime directory. `HANSARD_REMOTE_RUNTIME_DIR` selects
it, with `HANSARD_RUNTIME_DIR` as fallback. The controller's `--runtime-dir`
must name the same directory for its SSH bridge.

Keep mutable SQLite databases, locks, and active provider state on node-local
storage. Changing only the remote socket directory does not make a shared
cluster home safe. Keep pending archive and upload data on storage that survives
the allocation. Cluster allocation recovery and Slurm scheduling remain planned.
Setup submits no jobs and makes no cluster connection.

For a host that only publishes history, see
[Publish from a dedicated host](https://www.hansard.dev/sync/personal-sync/#publish-from-a-dedicated-host).
