---
url: https://ws.kloudkit.com/tools/ws-cli.md
description: >-
  ws-cli is the CLI companion for Kloud Workspace — a suite of helper commands
  to navigate, manage, and automate your workspace.
---

# `ws-cli` *(alias: `ws`)*

> ⚡ CLI companion to charge the workspace batteries

## Overview

`ws-cli` is a CLI tool designed to supercharge your development by providing a suite of
helper commands.
With `ws-cli`, you can navigate and manage your workspace efficiently, automate repetitive
tasks, and access a variety of functionalities directly from your terminal.

::: tip
The `ws-cli` command can be conveniently used with its alias `ws`.
When executing `ws` without any sub-commands, it automatically navigates to the
`/workspace`.

This feature allows for quick access to your workspace root with a minimal command.
:::

## Commands

### `ws-cli clip`&#x20;

> Reach the browser clipboard from the terminal over the workspace IPC socket.

```sh
# Save the browser clipboard to a file
ws clip paste > out.txt

# Search within it
ws clip paste | grep "pattern"

# Send command output to the browser clipboard
ls | ws clip copy
```

***

### `ws-cli clip copy`&#x20;

> Read stdin and write it to the browser clipboard over the workspace IPC socket. Pairs with the pbcopy/xclip/xsel shims for terminal clipboard access.

`ws-cli clip copy`

***

### `ws-cli clip paste`&#x20;

> Read the browser clipboard over the workspace IPC socket and write it to stdout — redirect it to a file or pipe it onward. Pairs with the pbcopy/xclip/xsel shims for terminal clipboard access.

`ws-cli clip paste`

***

### `ws-cli editor`&#x20;

> Query and control the running VS Code / code-server window over the workspace IPC socket — list open tabs, read diagnostics and the current selection, or open a file. Blocked over SSH, where there is no browser editor to reach.

| Flag | Description | Default |
| --- | --- | --- |
| `--raw` | Output the raw JSON response without styling | `false` |

```sh
# List the open editor tabs
ws editor list

# Open a file at a specific line and column
ws editor open src/main.go --selection 12:1
```

***

### `ws-cli editor diagnostics`&#x20;

> Pull language-server diagnostics (errors, warnings) from the editor over the IPC socket, across the whole workspace or a single file with --uri. Styled table by default, --raw for the JSON.

`ws-cli editor diagnostics [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--uri` | Filter to a single file (URI or absolute path) |  |

***

### `ws-cli editor list`&#x20;

> List the editor's open tabs over the IPC socket, with each tab's path, language, and active or dirty state.

`ws-cli editor list`

***

### `ws-cli editor notify`&#x20;

> Read a JSON payload from stdin and raise it as a notification in the running editor window over the workspace IPC socket. Requires a "message"; optional "detail", "actions", "modal", "timeout", and "severity" tune it. Prints the chosen action (or timeout) as JSON. Blocked over SSH.

`ws-cli editor notify`

```sh
# A simple toast
echo '{"message": "Build finished"}' | ws editor notify

# Ask a question and read the chosen action
echo '{"message": "Deploy now?", "actions": ["Yes", "No"]}' | ws editor notify
```

***

### `ws-cli editor open`&#x20;

> Open a file in the running editor window over the workspace IPC socket — a tab in the current window by default, a separate one with --new-window, jumping to a range with --selection. Fails fast over SSH, where there is no browser editor to open into.

`ws-cli editor open <file> [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--new-window` | Open in a new window | `false` |
| `--preview` | Open as a preview tab (reuse-window only) | `false` |
| `--reuse-window` | Open in the current window as a tab (default) | `false` |
| `--selection` | Select a range: LINE:COL\[-LINE:COL] (1-based) |  |

***

### `ws-cli editor selection`&#x20;

> Report the active editor's current selection — file, range, and selected text — over the IPC socket. Empty when nothing is selected.

`ws-cli editor selection`

***

### `ws-cli feature`&#x20;

> Install and inspect optional workspace features — Ansible playbooks that add tools on top of the base image. Ships a curated set; --root points at your own under ~/.ws/features.d.

| Flag | Description | Default |
| --- | --- | --- |
| `--root` | Root directory of additional features |  |

```sh
# List the features you can install
ws feature list

# Install one, skipping its VSCode extensions
ws feature install redis --skip-extensions
```

***

### `ws-cli feature info`&#x20;

> Show a feature's description and the variables it accepts, so you know what --opt values install will take.

`ws-cli feature info <name>`

***

### `ws-cli feature install`&#x20;

> Run a feature's playbook to install it. Pass variables with --opt KEY=VAL, and skip parts you do not want with --skip-extensions, --skip-completion, or --skip-repository.

`ws-cli feature install [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--opt` | Optional variables to use during installation | `[]` |
| `--skip-completion` | Skip configuring shell completion | `false` |
| `--skip-extensions` | Skip installing VSCode extensions | `false` |
| `--skip-repository` | Skip enabling the vendor APT repository | `false` |

***

### `ws-cli feature list` &#x20;

> List the features you can install, marking where each comes from — the shipped set, a workspace override, or your own ~/.ws/features.d.

`ws-cli feature list`

***

### `ws-cli feature new`&#x20;

> Print a starter feature playbook to stdout.
>
> Redirect it into ~/.ws/features.d/\<name>.yaml, then extend it and install
> with "ws-cli feature install \<name>":
>
> ws-cli feature new redis > ~/.ws/features.d/redis.yaml

`ws-cli feature new [name]`

***

### `ws-cli feature store`&#x20;

> List the artifacts published to the feature store (WS\_FEATURES\_STORE\_URL) — the offline mirror features install from when the network is locked down.

`ws-cli feature store`

***

### `ws-cli info`&#x20;

> Report facts about the running workspace — version, effective environment, installed extensions, live resource metrics, and uptime.

```sh
# Show the full version table
ws info version --all

# Watch live resource usage
ws info metrics
```

***

### `ws-cli info env`&#x20;

> Print every WS\_\* variable in effect, sorted — the resolved environment the workspace booted with.

`ws-cli info env`

***

### `ws-cli info extensions`&#x20;

> List the installed VS Code extensions with their versions.

`ws-cli info extensions`

***

### `ws-cli info metrics`&#x20;

> Show live resource usage — CPU, memory, disk, and file descriptors, plus GPU with --gpu.

`ws-cli info metrics [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--gpu` | Include GPU metrics | `false` |

***

### `ws-cli info uptime`&#x20;

> Show when the workspace session started and how long it has been running.

`ws-cli info uptime`

***

### `ws-cli info version`&#x20;

> Print the workspace version. --all expands to the full table — workspace, ws-cli, and VS Code.

`ws-cli info version [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--all` | Show all version information | `false` |

***

### `ws-cli log`&#x20;

> Emit styled, level-tagged log lines — the same formatting the startup scripts use. --pipe runs each line of piped input through the logger.

| Flag | Description | Default |
| --- | --- | --- |
| `--pipe, -p` | Loop through piped output | `false` |

```sh
# Emit an info-level line
ws log info "starting up"

# Nest a warning under it with a timestamp
ws log warn "slow response" --indent 1 --stamp
```

***

### `ws-cli log debug`&#x20;

> Emit a log line at debug level in the workspace style — the same formatting the startup scripts use. --indent nests it under a preceding line, --stamp prefixes a timestamp.

`ws-cli log debug message [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--indent, -i` | Desired prefixed indentation | `0` |
| `--stamp, -s` | Prefix message with current timestamp | `false` |

***

### `ws-cli log error`&#x20;

> Emit a log line at error level in the workspace style — the same formatting the startup scripts use. --indent nests it under a preceding line, --stamp prefixes a timestamp.

`ws-cli log error message [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--indent, -i` | Desired prefixed indentation | `0` |
| `--stamp, -s` | Prefix message with current timestamp | `false` |

***

### `ws-cli log info`&#x20;

> Emit a log line at info level in the workspace style — the same formatting the startup scripts use. --indent nests it under a preceding line, --stamp prefixes a timestamp.

`ws-cli log info message [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--indent, -i` | Desired prefixed indentation | `0` |
| `--stamp, -s` | Prefix message with current timestamp | `false` |

***

### `ws-cli log stamp`&#x20;

> Print just the current timestamp in the workspace log style — handy for marking phases in a startup log.

`ws-cli log stamp`

***

### `ws-cli log warn`&#x20;

> Emit a log line at warn level in the workspace style — the same formatting the startup scripts use. --indent nests it under a preceding line, --stamp prefixes a timestamp.

`ws-cli log warn message [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--indent, -i` | Desired prefixed indentation | `0` |
| `--stamp, -s` | Prefix message with current timestamp | `false` |

***

### `ws-cli logs`&#x20;

> Read a workspace daemon's log — the main log by default, or --target metrics|docker|auth\_proxy|cloudflared. Filter by --level, limit with --tail, or stream live with --follow.

`ws-cli logs [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--follow, -f` | Follow log output in real-time | `false` |
| `--level, -l` | Filter by log level (debug|info|warn|error) |  |
| `--tail, -t` | Number of lines to show from the end (0 for all) | `0` |
| `--target` | Log target to read (main|metrics|docker|auth\_proxy|cloudflared) | `main` |

```sh
# Stream errors live, starting from the last 100 lines
ws logs --level=error --tail=100 --follow

# Read a specific target instead of the main log
ws logs --target metrics
```

***

### `ws-cli secrets`&#x20;

> Encrypt and decrypt values under a master key, and generate the keys themselves. Encrypted values are what the seed engine's secrets: map stores and decrypts at boot.

| Flag | Description | Default |
| --- | --- | --- |
| `--force` | Overwrite existing files | `false` |
| `--master` | Master key or path to key file |  |
| `--mode` | File permissions (e.g., 0o600, 384), only when --output is used |  |
| `--output` | Write output to file instead of stdout |  |
| `--raw` | Output without styling | `false` |

```sh
# Generate a master key
ws secrets generate master

# Encrypt a value under it
ws secrets encrypt "s3cr3t" --master ~/.ws/master.key
```

***

### `ws-cli secrets decrypt`&#x20;

> Decrypt a value produced by encrypt, under the master key. Reads from the argument or stdin (-); writes the plaintext to stdout, or a file with --output.

`ws-cli secrets decrypt <encrypted|->`

***

### `ws-cli secrets encrypt`&#x20;

> Encrypt a value under the master key. Reads the plaintext from the argument or stdin (-); writes the ciphertext to stdout, or a file with --output.

`ws-cli secrets encrypt <plaintext|->`

***

### `ws-cli secrets generate`&#x20;

> Generate the credentials the workspace needs — a master key for secrets, or a login password hash for the server.

***

### `ws-cli secrets generate login`&#x20;

> Prompt for a password and print its hash for the workspace server login (WS\_AUTH\_PASSWORD\_HASHED). Store the hash, never the password.

`ws-cli secrets generate login`

***

### `ws-cli secrets generate master`&#x20;

> Generate a random master key, printed base64-encoded — the key encrypt, decrypt, and the seed engine use. --length sets the byte size (default 32).

`ws-cli secrets generate master [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--length` | Key length in bytes | `32` |

***

### `ws-cli secrets materialize`&#x20;

> Persist WS\_SECRETS\_MASTER\_KEY to /run/secrets/workspace/secrets/master\_key so the key outlives the editor's environment scrub. A no-op when the key is unset or the path already holds one.

`ws-cli secrets materialize`

***

### `ws-cli seed`&#x20;

> Copy files and apply small edits from a seed source onto the filesystem at boot. Bare files mirror verbatim; a .seed.yaml manifest overlays behavior — copy, merge, append — and decrypts secrets under the master key. Point --source at a mounted volume to seed a container from durable storage.

| Flag | Description | Default |
| --- | --- | --- |
| `--source` | Seed source directory |  |

```sh
# Preview what apply would write
ws seed ls --source /mnt/seed

# Apply it, overwriting existing destinations
ws seed apply --source /mnt/seed --force
```

***

### `ws-cli seed apply`&#x20;

> Apply the seed source to the filesystem — mirror bare files and run the .seed.yaml operations. Writes only where the destination is missing unless --force; pass destinations to limit the run to those paths.

`ws-cli seed apply [dest...] [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--force` | Overwrite existing destinations | `false` |
| `--master` | Master key or path to key file |  |

***

### `ws-cli seed ls`&#x20;

> List what apply would write — each destination with its operation and whether it carries a secret or a template — without touching the filesystem.

`ws-cli seed ls`

***

### `ws-cli seed rotate`&#x20;

> Re-encrypt every managed secret from the old master key (--master) to a new one (--new-master), in place. All-or-nothing: it verifies every secret decrypts before writing anything.

`ws-cli seed rotate [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--master` | Current master key or path to key file |  |
| `--new-master` | New master key or path to key file |  |

***

### `ws-cli serve`&#x20;

> Run a small HTTP server for the current directory on --port (default 38080).

| Flag | Description | Default |
| --- | --- | --- |
| `--bind` | Bind address | `0.0.0.0` |
| `--port, -p` | Port to serve assets on | `38080` |

```sh
# Serve the current directory
ws serve current

# Serve on a custom port
ws serve current --port 38081
```

***

### `ws-cli serve current`&#x20;

> Serve the current directory over HTTP as a static site — a quick way to preview built files.

`ws-cli serve current`

***

### `ws-cli serve current`&#x20;

> Serve the current directory over HTTP as a static site — a quick way to preview built files.

`ws-cli serve current [flags]`

***

### `ws-cli serve metrics`&#x20;

`ws-cli serve metrics [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--collectors` | Comma-separated list of collectors to enable (e.g., workspace,container.cpu,gpu) | `[*]` |
| `--port, -p` | Port to serve metrics on | `9100` |

***

### `ws-cli show`&#x20;

> Resolve and print facts about this workspace instance — settings, IP addresses, and paths. --raw drops the styling for use in scripts.

| Flag | Description | Default |
| --- | --- | --- |
| `--raw` | Output raw value without styling | `false` |

```sh
# Resolve a setting by its dotted key
ws show env server.port

# Reverse-tunnel a local port to the workspace node
ws_node_ip=$(ws show ip node); ssh -N -R "3001:${ws_node_ip}:3001" "${ws_node_ip}"
```

***

### `ws-cli show env`&#x20;

> Resolve a setting by its dotted key (server.port) and print it with its source and description. --value emits just the value for scripts, --as bool|int|list validates the shape, --check tests whether it is set so a startup script can guard on it.

`ws-cli show env <KEY> [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--as` | Validate and emit as one of: bool, int, list (mutex with --value) |  |
| `--check` | Check whether the variable (or its --deprecated alias) is set | `false` |
| `--delimiter` | Override delimiter for --as=list (defaults to YAML delimiter or space) |  |
| `--deprecated` | Deprecated alias paired with --check |  |
| `--or-skip` | Exit 1 (not error) on the natural absence of the chosen projection | `false` |
| `--validate` | Anchored regex each --as=list token must full-match; rejects fail-closed |  |
| `--value` | Emit the raw resolved value as a single line | `false` |

***

### `ws-cli show ip`&#x20;

> Print the workspace's IP addresses — the internal container address or the node it runs on.

***

### `ws-cli show ip internal`&#x20;

> Print the workspace container's internal IP address.

`ws-cli show ip internal`

***

### `ws-cli show ip node`&#x20;

> Print the IP address of the node hosting the workspace.

`ws-cli show ip node`

***

### `ws-cli show path`&#x20;

> Print well-known workspace paths — the home root or the VS Code settings file.

***

### `ws-cli show path home`&#x20;

> Print the workspace home (server root) path.

`ws-cli show path home`

***

### `ws-cli show path vscode-settings`&#x20;

> Print the path to the VS Code settings file — the user file by default, or the folder's with --workspace.

`ws-cli show path vscode-settings [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--workspace` | Get the workspace settings | `false` |

***

### `ws-cli template`&#x20;

> Copy shared configuration files (linters, formatters) from their global locations into a project, and inspect what they hold.

```sh
# List available templates
ws template list

# Apply the ruff config to the current project
ws template apply ruff
```

***

### `ws-cli template apply`&#x20;

> Copy a template into the project — a shared config like ruff or markdownlint — to --path (the current directory by default). --force overwrites an existing file.

`ws-cli template apply <template> [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--force, -f` | Overwrite existing files | `false` |
| `--path` | Target directory path | `.` |

***

### `ws-cli template list` &#x20;

> List the templates you can apply, with their source paths and whether one is already applied here.

`ws-cli template list`

***

### `ws-cli template show`&#x20;

> Display the contents of a configuration template.
>
> Available templates: ansible, markdownlint, ruff, yamllint

`ws-cli template show <template> [flags]`

| Flag | Description | Default |
| --- | --- | --- |
| `--local` | Show the local version of the template (if applied) | `false` |
