# Workspaces

import { Callout } from "nextra/components";

`runpane workspace` lets your own machines read files, write files, run commands, and drive each other's Pane over the Tailscale network you already use. There is no SSH, no keys, and no pairing code: each request is trusted because Tailscale says it comes from your own login.

```bash
runpane workspace list
runpane workspace <machine> read  <path>
runpane workspace <machine> write <path>          # content from stdin
runpane workspace <machine> exec -- <command>     # runs in that machine's shell
runpane workspace <machine> <runpane command>     # e.g. sessions list --json
```

The machine is its Tailscale name (`parsa-devbox`), a unique prefix (`devbox`), its MagicDNS name, or a Tailscale IP.

These commands ship in the npm CLI (`npm i -g runpane`, or `npx --yes runpane@latest workspace list`); the Python package doesn't run them. Passing a command through works for commands that talk to Pane, such as `sessions list`, `panes list`, or `workspace state`. Commands that only make sense where you type them, such as `doctor`, run on the other machine with `runpane workspace <machine> exec -- 'runpane doctor'`.

## Turning it on

Workspaces are on by default. When Tailscale is installed and signed in, desktop Pane joins your tailnet as it starts. It listens on `127.0.0.1` and runs `tailscale serve --bg --https=8443 http://127.0.0.1:<port>`, next to the [remote daemon](/docs/remote-daemon)'s port 443 handler if you have one. Nothing is opened to the public internet and no firewall rule is added.

`runpane --help`, `runpane doctor`, and `runpane agent-context` all print the current state:

```text
Workspaces: on (parsas-macbook-pro)
Other machines: parsa-devbox (Windows, online), parsas-macbook-air (macOS, offline)
Reach them: runpane workspace <machine> read|write|exec|<command>
```

When workspaces are off, the first line says why and gives the one step that fixes it:

| Reason | Fix |
|---|---|
| Tailscale is not installed | Install Tailscale from [tailscale.com/download](https://tailscale.com/download) and sign in. |
| Tailscale is signed out | Open Tailscale and sign in. |
| HTTPS certificates are off for the tailnet | Turn on HTTPS Certificates in the [Tailscale DNS settings](https://login.tailscale.com/admin/dns). |
| Pane is not running | Open Pane. |
| Turned off with `runpane workspace disable` | `runpane workspace enable` |

`runpane workspace disable` takes this machine off until `runpane workspace enable`. It can still reach your other machines while it's off. Pane must be running on a machine for the others to reach it.

## Try your other machine

Replace `my-windows-pc` with a name from `runpane workspace list`. These commands read a file, run a command, write a note, and show the Panes and panels on that machine:

```bash
runpane workspace my-windows-pc read '~/notes.md'
runpane workspace my-windows-pc exec -- 'git --version'
printf 'Check the Windows build\n' | runpane workspace my-windows-pc write '~/qa-note.txt'
runpane workspace my-windows-pc workspace state --json
```

The `printf` example runs from Bash or Zsh on the sending machine. The write replaces the destination file. `workspace list` lists machines; the nested `workspace state` reads the selected machine's Pane state.

These commands execute individual operations. To let a fresh agent take over a task with your branch and notes, use [Handoff](/docs/runpane-handoff). WSL reaching its own Windows host currently has a known daemon-routing failure; don't rely on that route yet.

## Who is trusted

Only your own Tailscale login is accepted. Tailscale Serve adds a `Tailscale-User-Login` header to each request after removing any copy the caller sent, and Pane compares it with the machine's owner from `tailscale status`.

- A device signed in as another Tailscale user, such as a teammate's Mac shared into your tailnet, is refused.
- A tagged device is refused, because Serve sends no identity for it.
- Browsers are refused, so a web page open on one of your devices can't send requests that Serve would sign with your login.
- Pane answers only requests that arrive through Serve. Serve's target path carries a secret that changes every launch, so another account on the same machine can't call the local port directly.
- Any device signed in as you, your phone included, is trusted. `runpane workspace list` shows only Macs, Windows PCs, and Linux machines, but that is a listing choice, not a block.
- Removing a device from Tailscale revokes it everywhere.

<Callout type="warning">
`write` and `exec` give your agents SSH-level control of every joined machine. A local agent's permission prompts and sandbox see only `runpane workspace ... exec`, not what runs on the other machine.
</Callout>

## Paths across Windows, WSL, and macOS

`read`, `write`, and `exec --cwd` take any path form and translate it on the machine that runs the request:

- `C:\Users\me\notes.md` and `/mnt/c/Users/me/notes.md` reach the same Windows file.
- On Windows, WSL paths such as `/home/me/repo/README.md` are read through `\\wsl.localhost\<distro>\...` with the default distribution (the one `wsl -l -v` marks with `*`).
- `~` is the home directory of the machine that runs the request.

`exec` runs in the shell Pane uses for terminals on that machine, prints stdout and stderr, ends with a line naming the machine, OS, shell, and exit code, and exits with the command's exit code. Add `--json` for all of these as fields. Pass the command as one quoted string, because several words after `--` are joined with spaces.

Without a machine name, `read`, `write`, and `exec --cwd` send a path that can't exist on this machine to the one joined machine it fits, so `C:\...` on a Mac goes to your Windows PC. When another command gets a missing file or Session that lives on another machine, its error names the machine and the exact `runpane workspace` command to use.

## Workspaces and pairing codes

| | Workspaces | Pairing codes |
|---|---|---|
| For | Your own machines, from the runpane CLI | Browsers, phones, desktop remote mode, and other people's devices |
| Trust | Your Tailscale login | A `pane-remote://` code per device |
| Serves | Desktop Pane's `~/.pane` | The [remote daemon](/docs/remote-daemon)'s data directory |
| Port | 8443 | 443 |
| Setup | None | `runpane setup`, then paste the code |

See the [runpane CLI](/docs/runpane-cli) for every other command.
