Configuration
ws has no settings file of its own yet. You configure it through
environment variables, and you define workstreams in template files. This
page lists every environment variable ws reads or sets, every file and
directory it uses, and the full workstream template format.
The prefix key is Ctrl-Space: prefix e means press Ctrl-Space, let go, then press e. Every key is in Keys and mouse.
Environment variables
Section titled “Environment variables”Variables you can set
Section titled “Variables you can set”| Variable | Effect |
|---|---|
WS_SOCKET_NAME |
The server name, the same as -L <name>. Picks a separate server with its own socket and saved session. Default: default. See Sessions. |
WS_EDITOR |
The editor for project files (ws project new, the project tab, the workbench layout) and ws mem edit. Wins over everything else. |
WS_MEMORY_DB |
The memory database to use instead of memory.db / memory-<name>.db. See Memory. |
VISUAL, EDITOR |
Used for project files when WS_EDITOR isn’t set and nvim isn’t on your PATH. VISUAL wins over EDITOR. |
WS_NO_NOTIFY |
Set to any value to turn off desktop notifications. |
SHELL |
The program a new pane runs when you don’t give one, and the shell used to resume agents after a restore. |
CODEX_HOME |
Where Codex keeps its files. ws integrate codex writes $CODEX_HOME/hooks.json and $CODEX_HOME/config.toml. Default: ~/.codex. |
XDG_CONFIG_HOME |
Base for templates: $XDG_CONFIG_HOME/ws/templates. Default: ~/.config. |
XDG_DATA_HOME |
Base for worktrees and projects: $XDG_DATA_HOME/ws/. Default: ~/.local/share. |
XDG_STATE_HOME |
Base for the log, saved sessions and crash logs: $XDG_STATE_HOME/ws/. Default: ~/.local/state. |
XDG_RUNTIME_DIR |
When set, sockets go in $XDG_RUNTIME_DIR/ws/. |
TMPDIR |
When XDG_RUNTIME_DIR isn’t set (the usual case on macOS), sockets go in $TMPDIR/ws-<uid>/. |
HOME |
Used to find ~/.claude, ~/.codex, and the defaults above. |
The editor for project files is chosen in this order:
$WS_EDITORnvim, if it’s on yourPATH, even when$EDITORnames something else. (wsis built around Neovim, and an alias such asvim=nvimonly exists in an interactive shell.)$VISUAL, then$EDITORvi
Some variables are read by the server, not by the command you type:
WS_NO_NOTIFY, SHELL, and the editor variables when you open project files
from inside ws. The server has the environment of the terminal where it
started. To change one of these, set it and run ws restart from that
terminal. The new server gets that terminal’s environment and restores the
session; processes in the panes are restarted.
Variables ws sets in panes
Section titled “Variables ws sets in panes”Every program in a pane gets these:
| Variable | Value |
|---|---|
TERM |
xterm-256color |
COLORTERM |
truecolor |
WS_SOCKET |
The socket of the ws server that owns the pane. Hooks and ws commands run in the pane use it to reach that server. |
WS_PANE_ID |
The pane’s number, for example 12. ws report tags hook events with it, and ws split splits this pane when you don’t pass --pane. |
WS_WORKSPACE |
The name of the workspace the pane was started in. |
WS_WORKSTREAM |
The workstream’s name, in panes opened from a template. |
Commands that act on a server use WS_SOCKET when they run inside a pane,
unless you pass -L <name>. Outside a pane, they use the default server (or
WS_SOCKET_NAME). ws report does nothing unless both WS_SOCKET and
WS_PANE_ID are set, which is why agent hooks are harmless in other
terminals.
Files and directories
Section titled “Files and directories”The paths below use the defaults. The XDG variables above move them.
Configuration
Section titled “Configuration”| Path | What |
|---|---|
~/.config/ws/config.toml |
Settings. Optional; today it holds [review] and [pr_comments] (see Reviewing PRs), [dashboard] (see Getting started) [memory] (see Memory) and [agents.<kind>] (see Memory). A typo in a known section is an error; unknown sections are ignored. The General, Agents & memory and Reviews tabs of Settings (prefix S) edit it for you. |
~/.config/ws/keys.toml |
Your keys: the leader, keys after it, sequences and direct keys. Optional; reloaded while ws runs. See Changing keys, or edit it in Settings › Keyboard shortcuts. |
~/.config/ws/templates/*.toml |
Workstream templates. See Workstream templates. |
| Path | What |
|---|---|
~/.local/share/ws/worktrees/<repo>/<name>/ |
Git worktrees for workstreams. <repo> is the repo directory’s name; a / in the workstream name becomes -. |
~/.local/share/ws/memory.db |
Agent memory; a named server uses memory-<name>.db. See Memory. |
~/.local/share/ws/projects/<slug>/ |
One folder per project: project.toml, brief.md, plan.md, decisions.md, log.md, context/. See Projects. |
| Path | What |
|---|---|
~/.local/state/ws/state-<name>.db |
The saved session and agent event history for the server named <name> (SQLite). SQLite may keep -wal and -shm files next to it. |
~/.local/state/ws/ws.log |
The log for every server and --local run. Past 10 MB it’s moved to ws.log.1 when the next one starts. |
~/.local/state/ws/crash-<time>.log |
A panic message and backtrace, written when the server crashes. <time> is Unix seconds. |
~/.local/state/ws/status-report-<pane>-<time>.txt |
A status report saved by c in the agent status inspector. |
The event history keeps the most recent 5,000 events.
Sockets
Section titled “Sockets”The socket directory is $XDG_RUNTIME_DIR/ws/ when XDG_RUNTIME_DIR is set,
and $TMPDIR/ws-<uid>/ otherwise. ws creates it readable only by you,
since anyone who can reach a socket can drive your agents.
| Path | What |
|---|---|
<socket dir>/<name>.sock |
The server named <name>; default.sock without -L. |
<socket dir>/ws-<pid>.sock |
A ws --local run. |
<socket dir>/nvim-<workstream>.sock |
The Neovim socket of a workstream’s tab. |
<socket dir>/nvim-<pid>-<pane>.sock |
The Neovim socket of another tab. |
A socket that nothing answers on was left by a run that crashed. ws doctor --fix removes them.
Agent CLI files ws edits
Section titled “Agent CLI files ws edits”ws integrate edits these files. Before it changes a file, it writes a
backup next to it, named with the time in Unix seconds. It writes the new
file to a temporary name first and renames it into place, so a crash never
leaves a half-written file.
| Path | Changed by | Backup |
|---|---|---|
~/.claude/settings.json |
ws integrate claude |
settings.json.ws-backup-<time> |
~/.codex/hooks.json |
ws integrate codex |
hooks.json.ws-backup-<time> |
~/.codex/config.toml |
ws integrate codex, only when the hooks feature is off or unknown, or daemon_auto_start is on or unknown |
config.toml.ws-backup-<time> |
ws won’t edit a hooks file that isn’t valid JSON, or a config.toml that
isn’t valid TOML. It stops and tells you to fix the file first.
Workstream templates
Section titled “Workstream templates”A template describes how to open a workstream: the repo to make a worktree
from, the panes to start, their layout, and setup commands. Put templates in
~/.config/ws/templates/, in files ending in .toml. List the ones ws
found with:
ws templatesA file can hold several templates. ws reads the files in name order, and a
later template with the same name replaces an earlier one. ws doctor checks
every template and warns when a template’s repo isn’t a git checkout.
A full example
Section titled “A full example”# Open with: ws new design-system-pr pr-101
[template.design-system-pr]# The checkout worktrees are made from. A leading ~/ is expanded.# Leave `repo` out for a scratch workstream (see below).repo = "~/code/design-system"
# The branch new branches start from. Default: "main".base = "main"
# The workspace the tab goes in; created if it doesn't exist.# Default: the template's name.workspace = "Design System"
# Commands run when the tab opens, joined with &&, in the worktree.# They run in the first plain shell pane below (cmd = "$SHELL"),# or in a pane of their own if there is none. Default: none.setup = ["pnpm install", "pnpm build:tokens"]
# Panes, in order. The first pane gets focus. At least one is required.[[template.design-system-pr.pane]]name = "claude" # the pane's labelcmd = "claude" # a shell command, run in the worktreeagent = "claude" # this pane runs an agent CLImodel = "opus" # added as `--model opus`
[[template.design-system-pr.pane]]name = "nvim"# A pane whose cmd uses {nvim_socket} becomes the tab's Neovim:# `ws open` and `prefix e` send files to it.cmd = "nvim --listen {nvim_socket}"
[[template.design-system-pr.pane]]name = "shell"cmd = "$SHELL" # a plain shell pane: runs the setup
[template.design-system-pr.layout]# main-left: first pane on the left, the rest stacked on the right.# columns: side by side. rows: stacked. Default: main-left.preset = "main-left"
# A workstream with no repo: one Codex pane, no worktree or branch.[template.scratch]workspace = "Scratch"
[[template.scratch.pane]]name = "codex"cmd = "codex"agent = "codex"model = "gpt-5" # added as `-m gpt-5`To start your own, copy the example above into a file in
~/.config/ws/templates/ and edit it.
Template keys
Section titled “Template keys”Each template is a table named [template.<name>]. The name is what you pass
to ws new.
| Key | Type | Default | Meaning |
|---|---|---|---|
repo |
string | none | The git checkout to make worktrees from. A leading ~/ is expanded. Without it, the workstream is a scratch workstream: no worktree, no branch, and its panes start in the directory the server started in. |
base |
string | "main" |
The branch a new branch is created from. |
workspace |
string | the template name | The workspace the tab opens in. |
setup |
list of strings | [] |
Commands to run when the tab opens. |
pane |
array of tables | required | The panes, in order. At least one. |
layout.preset |
string | "main-left" |
main-left, columns or rows. |
Layout presets:
| Preset | Arrangement |
|---|---|
main-left |
The first pane on the left, the rest stacked on the right |
columns |
All panes side by side |
rows |
All panes stacked |
Pane keys, in each [[template.<name>.pane]]:
| Key | Type | Required | Meaning |
|---|---|---|---|
name |
string | yes | The pane’s label. |
cmd |
string | yes | A shell command. It runs with /bin/sh -c, with exec in front, in the workstream’s directory. |
agent |
string | no | The agent CLI this pane runs, such as claude or codex. |
model |
string | no | The model to start the agent with. For claude it adds --model <model>; for codex, -m <model>. Other agents ignore it. |
Unknown keys are an error, so a typo shows up in ws doctor and ws templates instead of being ignored.
Placeholders
Section titled “Placeholders”cmd can use these placeholders. ws fills them in before it runs the
command.
| Placeholder | Becomes |
|---|---|
{worktree} |
The workstream’s directory: its worktree, or, for a scratch workstream, the directory the server started in. |
{branch} |
The workstream’s branch (empty for a scratch workstream). |
{name} |
The workstream’s name. |
{nvim_socket} |
The tab’s Neovim socket, <socket dir>/nvim-<name>.sock. |
How a template opens
Section titled “How a template opens”When you run ws new <template> <name>:
- The name is checked. It may use letters, digits,
.,_,-and/, can’t start with.or-, and can’t contain... - For a template with a
repo,wsmakes a worktree at~/.local/share/ws/worktrees/<repo>/<name>:- With no options, the branch is
<name>. If that branch exists, it is checked out; otherwise it is created frombase. - With
--branch <branch>, that existing branch is checked out. - With
--pr <number>,wschecks the pull request out withgh pr checkout, forks included. The name defaults topr-<number>. - If the worktree already exists, it is reused.
- With no options, the branch is
- The panes start in the worktree, each with
WS_WORKSTREAMset. - The setup commands run in the first pane whose
cmdis exactly$SHELLand that has noagent. If there is no such pane,wsadds a pane namedsetupfor them. The pane prints▶ ws setup, runs the commands, prints✓ setup doneor✗ setup failed, and then leaves a shell open so you can read the output. - The panes are arranged by the layout preset. Panes that don’t fit in the window are left out, and the top bar says how many.
If the workstream is already open, ws new jumps to its tab instead. See
Workstreams for day-to-day use.