# shell.online shell.online wraps a local terminal process and produces an unguessable browser link. The process remains on the local machine. Links can be interactive or server-enforced read-only. ## Noninteractive installation curl -fsSL https://shell.online/install | sh Supported platforms: macOS; Windows with native ConPTY; Linux across x86, ARMv5/6/7/64, MIPS/MIPSLE/MIPS64, PPC64, RISC-V 64, s390x, and LoongArch64; FreeBSD; OpenBSD; NetBSD; DragonFly BSD; and Solaris. Every Linux release artifact executes the full Go and PTY integration suite under QEMU; Windows amd64 runs a native ConPTY suite; other artifacts are build-verified. QEMU does not reproduce vendor firmware or kernel restrictions. This includes many OpenWrt and Ubiquiti-style Linux devices. The POSIX and PowerShell installers verify SHA-256, never invoke sudo, and print PATH instructions when needed. Full matrix: https://shell.online/platforms/ Windows PowerShell installation: irm https://shell.online/install.ps1 | iex Optional Homebrew installation (the tap lives in this repository): brew tap teoslayer/shell-online https://github.com/TeoSlayer/shell.online brew trust --tap teoslayer/shell-online brew install shell-online Homebrew 6 requires one-time trust for third-party taps. Tap-level trust persists across formula updates; review the repository before granting it. Older versions without `brew trust` do not require that line. After setup, use `brew install shell-online`, `brew upgrade shell-online`, or `brew uninstall shell-online`. Homebrew is not required; use the verified installer above on machines without it. The Homebrew formula builds locally: Brew fetches the checksum-pinned tagged source, installs Go as a build-only dependency when needed, runs go build, and links the result. Application modules are pinned by go.sum and resolved by Go during the build; there are no runtime package dependencies. The standalone installer uses a checksum-pinned release binary. To compile and run the tagged source outside either installation path: git clone --depth 1 --branch v0.15.1 https://github.com/TeoSlayer/shell.online.git cd shell.online go build -trimpath -ldflags="-X main.version=0.15.1" -o ./shell ./cmd/shell ./shell --version The source-build path requires Go 1.26.8 or newer, except Go 1.27.x is intentionally unsupported on MIPS64 because of go.dev/issue/80978. Keep using ./shell or move it to a directory on PATH. Agent skill file: https://shell.online/skill Current release metadata: https://shell.online/downloads/release.json SHA-256 manifest: https://shell.online/downloads/SHA256SUMS ## Agent usage Start a long-running process under shell.online: shell --json -- your-command --its-arguments For monitoring without browser input: shell --read-only --json -- your-command --its-arguments File access is disabled by default. Enable only the directory the operator has asked to expose: shell --files --json -- your-command --its-arguments shell --files-root ./artifacts --json -- your-command --its-arguments --files uses the process working directory; --files-root selects another root. The browser shows no Files control until the host opts in. Listings and file contents are requested on demand over the existing E2EE WebSocket. The CLI rejects parent traversal, non-regular files, and symlink escapes. File access cannot be combined with --no-e2ee. Every normal share is end-to-end encrypted automatically. When SHELL_ONLINE_E2EE_PASSWORD is unset, the CLI generates a cryptographically random ten-character Base64URL browser password. For sensitive or long-lived sessions, set a longer unique password before starting shell: SHELL_ONLINE_E2EE_PASSWORD='use-a-long-unique-password' shell --json -- your-command --its-arguments The URL contains only a random #salt= fragment; the CLI and browser derive the AES-256-GCM key locally with PBKDF2-HMAC-SHA256. The old --e2ee flag is accepted for compatibility but is redundant. Lost passwords cannot be recovered. Cloudflare sees authenticated ciphertext plus routing, traffic, IP, and lifecycle metadata. For deliberate compatibility or debugging only, `shell --no-e2ee ` disables payload E2EE. HTTPS/WSS still protects each transport hop, but Cloudflare can access terminal input and output while relaying it. This option conflicts with --e2ee, SHELL_ONLINE_E2EE_PASSWORD, and --persistent. The first stderr line is a JSON event: {"type":"session","session_id":"...","share_url":"https://shell.online/s/...#salt=...","e2ee_password":"Ab3dE7-_xY","read_only":false,"encrypted":true,"background":true,...} Send the complete share_url, including its fragment, and e2ee_password to the human operator through the agent's normal communication channel. For sensitive work, use separate operator-approved channels when possible. If the operator explicitly requested --no-e2ee, the event has encrypted=false and no e2ee_password; disclose that Cloudflare is then inside the content trust boundary. Prefer --read-only when the operator only needs to monitor progress. Read-only is fixed at session creation and enforced by the Worker. Inside Claude Code, use `shell --json -- claude` to hand off the current conversation. shell.online detects CLAUDE_CODE_SESSION_ID and starts `claude --resume --fork-session` inside the shared process. The new process keeps the conversation history and workspace; the original Claude process remains open, and new messages do not synchronize between them. Report this as a conversation fork, not as adoption of the original PID. Use `shell` with no command to share a fresh default shell. Use `shell --foreground command` to mirror output and accept input locally as well as in the browser. xterm.js is the default browser renderer. Refstream (unstable alpha) can be selected in the terminal settings without restarting the process. Its Connect agent flow creates a revocable invitation scoped to this one session. Read access permits terminal read, search, and wait; control additionally permits text, commands, and key signals such as Ctrl-C. Keep the returned connector session open and reuse its task IDs for follow-ups; status, partial output, and collected answers survive panel changes and reconnects. The browser saves a reload snapshot only inside the current tab for at most four hours. Recovery still requires the local shell process to be running, and the relay stores no terminal output. File access remains a separate host opt-in. Refstream is currently v0.1.0-alpha.5. It owns only the browser terminal model and renderer; shell.online continues to own the PTY, E2EE transport, read-only policy, input lease, shared grid, and process lifecycle. Reuse the connector's session ID and stable task IDs for follow-ups. A task is complete only with a shell marker, a trusted host callback, or an explicitly labelled agent observation; output, silence, and redraws are not completion. Remote writes use a recent sequence and never override a protected local draft. See https://shell.online/refstream/ and the pinned upstream protocol at https://github.com/TeoSlayer/refstream.js/blob/v0.1.0-alpha.5/docs/agents.md. The optional account app is documented at https://shell.online/app/. A vault is personal rather than team-wide, and machine remote-start permission is explicit. The hosted app uses Firebase Authentication. Manage local sessions: shell help shell list shell list --json shell attach shell kill shell kill --all `shell help` prints a guided lifecycle; `shell help attach` explains local takeover and detaching. `shell attach` opens the existing PTY locally. Its terminal title keeps a Ctrl-X D to detach reminder visible even when a full-screen TUI redraws the terminal. Press Ctrl-X, release it, then press D to detach without stopping it (Ctrl-] remains a legacy alternative); the wrapper intercepts the sequence before the child process receives it. Input and output remain mirrored to browser viewers. Anonymous presence and a brief per-typist input lease prevent remote keystrokes from interleaving. Full-screen and nested terminals are supported. Snapshot restoration suppresses replies to historical terminal queries, so a joining or reconnecting browser cannot inject old capability responses into tmux, Herdr, mosh, or another live TUI. Sessions close immediately when their task exits. `--auto-close 5m` or an absolute/local date adds an earlier deadline; supported duration units are ms, s, m, h, d, w, mo, and y. ROS 1 and ROS 2 processes need no plugin: source the ROS environment, then run `shell roscore`, `shell roslaunch `, `shell ros2 run `, or `shell ros2 launch `. shell.online platform support does not expand the supported platforms of the installed ROS distribution. Native shares run in the background by default. Re-run `shell --persistent ` with the same private state file to recover the same URL and password after a process or machine restart. Docker combines the same identity with `restart: unless-stopped` for automatic recovery. The repository includes a persistent Docker client. Run `docker compose up --build -d`, then `docker compose logs shell-online` for its stable E2EE URL and generated ten-character browser password. Its state and workspace live in separate named volumes; the state volume contains the browser password, host credential, and decryption key. The saved password is reused across restarts, and a conflicting configured password is refused. Create new state to rotate the password and URL. This is a client for the hosted shell.online relay, not self-hosting documentation. ## Accounts, machines, and organizations Accounts are optional. Every command above works without one, and an unlinked machine behaves exactly as described. `shell login` links a machine to an account. The account and the web app live at https://app.shell.online; shell.online itself serves this site and the session links. It opens a browser to approve the request, then returns to the sessions page; a browser with no account yet is sent to the sign-up page first, which asks for a name for the organization being created. Signing in again from the same machine updates that machine's entry rather than adding a second one. `shell whoami` shows which account a machine is linked to; `shell logout` unlinks it and revokes its token. Once linked, sessions started with `shell` appear in the account automatically. What is published is the share URL, the command line, the host name, the session name, the timings, and the read-only/encrypted/persistent flags. Terminal output is never published, and neither is the encryption key. Signing up creates an organization; an invite link joins an existing one. Everyone in an organization can see every member's sessions. A session has an owner and an assignee, and the owner can hand it off. ## Sessions started from the browser `shell login` asks once whether the signed-in browser may start sessions on that machine. Only an explicit yes is recorded; declining is asked again next time, and a non-interactive login defaults to no. After a yes, a background daemon polls for work and can start and stop sessions on that machine. The browser chooses the session password and seals it to an ephemeral key the daemon publishes, so the accounts service relays an envelope it cannot open. The daemon also reports which agent harnesses this machine can run, so the web app offers the ones that are actually there. It looks up four command names on PATH -- claude, codex, hermes, openclaw -- once per daemon run. It does not execute them, read their configuration, or read anything in your projects. The list of which of those four exist is what is sent. shell daemon status is this machine reachable from a browser shell daemon stop stop until the next shell command shell login --no-remote-start withdraw it on this machine shell service install keep the daemon running across restarts An agent should not enable this on a machine it does not own, and should tell the operator plainly if it does: while it is allowed, anyone signed in to that account can start processes on that machine. ## Collaboration records The accounts service records collaboration metadata such as session ownership, handoffs, comments, mentions, and notifications, and session records: the share URL, the command line as written, the machine's host name, the session name, timings, and exit code. Every member of the team sees those. What anyone types into a session from the browser (commands, agent prompts, Ctrl-C) is recorded in the team's audit log. It is end-to-end encrypted in the browser to the team's audit key: every member of the organization can read and export it, and the accounts service stores only ciphertext it cannot read. The service still sees who acted, in which session, what kind of entry it was, and when. Anything typed by mistake, such as a pasted password, is recorded and readable by the whole team. Typing in the terminal a session was started from never reaches the browser or the service, and a --read-only share accepts no browser input at all. Session passwords are sealed to each person's session vault; the service stores them sealed and cannot open them. Terminal output stays inside the end-to-end encrypted stream. ## Release integrity Run `shell --version` to print the installed CLI version. The installer validates the platform binary against the canonical SHA-256 manifest and prints the verified digest. The website and corresponding GitHub release expose the same version, binaries, and SHA256SUMS file. ## Security model The share URL and browser password together are a bearer capability. Interactive shares grant terminal input; --read-only shares grant viewing only and reject browser input server-side. Only send access to an intended operator. An account is optional and changes none of this: the link and password remain the capability, and the relay still sees only ciphertext. Every current-CLI share encrypts terminal payloads end to end. Cloudflare relays ciphertext while active and deletes ordinary session state when the task closes; an old link reports that the session no longer exists.