# Terminalwire Client

Install and run Terminalwire apps on your workstation

The Terminalwire Client is a small, cross-platform binary that runs on your workstation. It connects to a Terminalwire Server and streams Terminal I/O, and other commands, over a WebSocket to your terminal. It's a single self-contained executable (`terminalwire-exec`) with no runtime to install, and it keeps itself up to date automatically.

This guide covers everything you need to know to install and run Terminalwire apps on your workstation.


## Installation

Most people install Terminalwire by installing an app: the app's one-liner installs the Terminalwire client for you, then drops the app's launcher on your `$PATH`. For example, to install the `ogplus` app:

```sh
# Installs the Terminalwire client and the ogplus app on Linux or macOS
$ curl -sSL https://ogplus.terminalwire.sh | bash
# Restart your terminal to complete the installation
```

If you just want the client itself, without any app, install it from the bare domain:

```sh
# Installs only the Terminalwire client
$ curl -sSL https://terminalwire.sh | bash
```

The installer does the following on your workstation:

1. Downloads the Terminalwire client (a single self-contained binary, `terminalwire-exec`) to `~/.terminalwire/bin`. No Ruby, Node, or other runtime is required.
2. Detects and configures your shell initialization file to include `~/.terminalwire/bin` in your `$PATH` variable.
3. Creates a `~/.terminalwire` directory to store configuration, per-app permissions, and installed app launchers.
4. Installs any app launcher bundled with the one-liner (e.g. `ogplus`) into `~/.terminalwire/usr/bin`.

Verify the client is installed by printing its version:

```sh
$ terminalwire-exec --version
2.0.8
```

That's it! You have successfully installed Terminalwire on your workstation. If you installed an app, restart your terminal and run it by name (e.g. `ogplus`).

# Staying up to date

The client keeps itself current. It checks for new versions in the background and applies signed updates automatically, so you never reinstall. To check and update on demand:

```sh
# Force an update check now
$ terminalwire-exec update
already up to date (2.0.8)
```

Updates are served over a signed release channel; `stable` is the default. Advanced users can track a faster train (`alpha`, `beta`) when switching channels is supported by their client version.

# Manual configuration

The installer edits your shell rc file for you. If you prefer to configure your shell manually, add the Terminalwire binary directory to your `$PATH`.

## Linux or Bash

```sh
# Linux or bash
$ echo 'export PATH=$HOME/.terminalwire/bin:$PATH' >> ~/.bashrc
# Reload your shell or run...
$ source ~/.bashrc
```

## macOS or zsh

```sh
# macOS or zsh
$ echo 'export PATH=$HOME/.terminalwire/bin:$PATH' >> ~/.zshrc
# Reload your shell or run...
$ source ~/.zshrc
```

# Test the installation

To verify the client can reach a server and negotiate the protocol, run `terminalwire-exec inspect` against a server URL. You'll see the negotiated protocol and the capabilities the server offers:

```sh
$ terminalwire-exec inspect wss://opengraphplus.com/terminal
Server inspection
  endpoint:     wss://opengraphplus.com/terminal
  protocol:     v2
  version:      2
  capabilities: stdio, file, directory, browser, env, signal, flow, raw-input, terminal-query
```

Once verified, you're ready to start installing apps and using Terminalwire on your workstation.


## Apps

Terminalwire apps are command-line applications that run on your workstation and connect to a Terminalwire server. They can be installed, run, and removed just like any other command-line application.

# Installing a Terminalwire app

The easiest way to install an app is its one-liner. Each app publishes an installer at its own subdomain that installs the Terminalwire client (if it isn't already installed) and drops the app's launcher on your `$PATH`:

```sh
# Installs the client (if needed) and the ogplus app
$ curl -sSL https://ogplus.terminalwire.sh | bash
```

Restart your terminal (or `source` your shell rc file) and the app is ready to run by name.

## Direct installation

If you already have the client and just want to add a launcher for a server URL (handy for testing an app before it's published), use `terminalwire-exec install`:

```sh
# Writes a launcher to ~/.terminalwire/usr/bin/ogplus
$ terminalwire-exec install ogplus https://opengraphplus.com/terminal
```

# Running an app

Once an app is installed, run it from the command line just like any other command-line app:

```sh
$ ogplus
Commands:
  ogplus help [COMMAND]  # Describe available commands or one specific command
  ogplus link            # Manage links
  ogplus login           # Login to ogplus
  ogplus logout          # Logout of your account
  ogplus open            # Open in your browser
  ogplus site            # Manage sites
  ogplus version         # Prints the version of the CLI
  ogplus whoami          # Prints your current login information
```

If the app doesn't run, the Terminalwire binary directory is likely not on your `$PATH`. Re-run the app's installer, or add `~/.terminalwire/bin` to your `$PATH` (see [Installation](./installation)).

# Where apps live

Terminalwire keeps the engine and your apps in separate directories under `~/.terminalwire`:

- `~/.terminalwire/bin` holds the Terminalwire client itself (`terminalwire-exec` and the `terminalwire` stub). A server can never write here.
- `~/.terminalwire/usr/bin` holds your installed app launchers (e.g. `ogplus`). This is the only directory an app install touches.

Both are added to your `$PATH`, with the engine directory taking precedence so an app can never shadow the client.

# Uninstalling an app

An app is just a launcher file, so removing it uninstalls the app:

```sh
# Removes the ogplus launcher
$ rm ~/.terminalwire/usr/bin/ogplus
```

# Terminalwire executables

An app launcher is a small executable file in `~/.terminalwire/usr/bin` that points at a Terminalwire server URL. Here's what `ogplus` looks like:

```sh
#!/usr/bin/env terminalwire-exec
url: "https://opengraphplus.com/terminal"
```

When executed, `terminalwire-exec` reads the `url` key from the file, connects to the server, streams the command to the server for interpretation, and returns the output to you. For example, `ogplus link ls` connects to `https://opengraphplus.com/terminal`, streams `["ogplus", "link", "ls"]` to the server, which processes the command and streams the output back to your terminal.


## Security

Terminalwire makes it easier for web developers to build commmand-line applications for their web apps. It accomplishes this by streaming command-line I/O between a web server and client over WebSockets.

# Terminalwire Client

The Terminalwire client is a thin-client that users install on their workstation. It sends and recieves commands to and from the server to accomplish various command-line tasks like printing text to screen, launching a URL in the browser, or reading and writing files.

# Terminalwire Server

The Terminalwire Client connects to a Terminalwire Server over WebSockets. Once connected, the server is capable of issueing commands to the client to perform various tasks including reading and writing files, launching URLs in the browser, and printing text to the screen.

# Authority

Terminalwire uses URL authorities to secure client workstations between different domains. This is similar to the way browsers secure cookies between different domains.

URL authorities are the domain name and non-standard port. For example, the URL `https://example.com` would resolve the authority `example.com`. The URL `https://example.com:3000` would resolve the authority `example.com:3000`.

# Initialization

When the client connects to the server, it sends `initialization` message to establish and negotiate a connection. The client includes information about the opearating system version, Terminalwire client version, and protocol version to help the server determine how to best communicate with the client.

The server responds with a `ready` message to indicate that the client is ready to receive commands.

# Entitlements

By default the server can reach almost nothing on your workstation. It gets `stdin`, `stdout`, and `stderr`, and it gets the per-origin storage path (`~/.terminalwire/authorities/$ORIGIN/storage`), where it keeps your session cookie and other config for that server. Everything else (reading an environment variable, opening a browser URL to another host, reading or writing a file outside its storage) is denied until you grant it.

Grants are scoped to the **origin** (`scheme://host:port`), the same way a browser scopes cookies and permissions. A grant you give `wss://example.com` never applies to `wss://other.com`, and `ws://` (plaintext, for local development) is a separate origin from `wss://`, so you can't grant a plaintext server by accident.

When the server asks for something it isn't allowed, the client denies it and prints exactly how to allow it:

```
terminalwire: denied read of env SECRET
  allow it with: terminalwire-exec policy example.com env SECRET --approve
```

## Granting access

Grants live in a per-origin YAML policy file that you own. Edit it with `terminalwire-exec policy` (which runs out of band from any session, so a server can never grant itself access), by hand in `$EDITOR`, or with a tool like `yq`.

```sh
# List the origins that have a policy
$ terminalwire-exec policy

# Show one origin's policy
$ terminalwire-exec policy example.com

# Print the policy file path, e.g. to edit it directly
$ terminalwire-exec policy example.com --path
```

Approve, deny, or revoke a specific resource. `--approve` allows it, `--deny` blocks it even where a default would have allowed it, and `--revoke` removes the rule:

```sh
# Let the server read the SECRET environment variable
$ terminalwire-exec policy example.com env SECRET --approve

# Let it open another scheme, or a browser URL to another host
$ terminalwire-exec policy example.com scheme ftp --approve
$ terminalwire-exec policy example.com host docs.example.com --approve

# Let it read and write files matching a glob (mode: ro, rw, or an octal like 0644)
$ terminalwire-exec policy example.com path '~/projects/**' rw --approve

# Block or remove a rule
$ terminalwire-exec policy example.com env SECRET --deny
$ terminalwire-exec policy example.com env SECRET --revoke
```

A bare hostname defaults to the `wss://` origin; pass a full `scheme://host:port` to target another, such as `ws://127.0.0.1:8744` for a local development server.


## Terminalwire.com entitlements

The `terminalwire.com` is granted elevated entitlements by the client so it can perform installation, troubleshooting, and other administrative tasks on the client workstation. These entitlements are detailed in the [Resources](#resources) section below.

# Resources

After the client sends the `initialization` message, the server then requests the following resources from the client:

* **stdin**: The standard input stream for the client.
* **stdout**: The standard output stream for the client.
* **stderr**: The standard error stream for the client.
* **exit**: The exit status of the client.
* **browser**: Launch a URL on the users workstation.
* **file**: The configuration file on the client used to store API credentails, session cookies, and other local configuration data for the endpoint.
* **directory**: Create, read, update, and check for existence of directories on client.

The client responds with messages on whether or not the resources are available. When all the devices are ready, the client & server can begin streaming commands between the resources.

## Standard I/O

The `stdin`, `stdout`, and `stdin` resources are part of the standard I/O streams. The client grants the server permission to read and write to these streams by default.

## Files

Terminalwire uses the `files` device to store API credentials, session cookies, and other local configuration data for the endpoint. These entitlements are implicitly granted by the client.

Files requires an entitlement to read and/or write files to a path on the client. The client must grant the server permission to read and/or write files to a path on the client with the exception of the `~/.terminalwire/authorities/$AUTHORITY/storage` path, which is used to store API credentials, session cookies, and other local configuration data for the endpoint.

The `terminalwire.com` authority has an entitlement to the `~/.terminalwire/bin/**` path by default to manage the installation, listing, and removal of Terminalwire apps.

## Directories

API credentials, session cookies, and other local configuration data for the endpoint are stored in the `files` device on the client.

The `terminalwire.com` authority has an entitlement to the `~/.terminalwire/bin/**` path by default to manage the installation, listing, and removal of Terminalwire apps. It also has an entitlement to shell initialization files in the `~` directory to aid users in appending the `$PATH` variable to their shell initialization file.

## Environment Variables

The client's environment variables are not shared with the server by default, with the exception of the `TERMINALWIRE_HOME` path. This path is necessary to store API credentials, session cookies, and other local configuration data for the endpoint.

The client must grant the server permission to read and/or write environment variables.

The `terminalwire.com` authority has an entitlement to the `PATH` variable to manage the installation, listing, and removal of Terminalwire apps.

## Browser

The Terminalwire server can launch URLs in your browser. By default the client only allows `http` and `https` URLs to the **same host** as the server, so a server at `example.com` can open `https://example.com/...` but not another site. To allow another host or scheme, grant it:

```sh
$ terminalwire-exec policy example.com host docs.example.com --approve
$ terminalwire-exec policy example.com scheme ftp --approve
```
