Command reference
This page lists every ws command, subcommand, argument and flag, in the order ws --help shows them. Each entry has a one-line description, its options with defaults, and a short example. For task-oriented help with the scripting commands, see Scripting ws. For the socket messages behind them, see the protocol.
The prefix key is Ctrl-Space: prefix t means press Ctrl-Space, let go, then press t. Every key is in Keys and mouse.
Synopsis
Section titled “Synopsis”ws [OPTIONS] [COMMAND]...ws <SUBCOMMAND> [OPTIONS] ...ws with no subcommand starts or attaches to the background server. Any words that are not a subcommand are a command to run in a pane.
Global options
Section titled “Global options”These work with every subcommand, before or after it. ws -L dev attach and ws attach -L dev are the same.
| Option | Default | Description |
|---|---|---|
--local |
off | Run in this terminal instead of the background server. Nothing survives closing the terminal |
-L, --socket-name <name> |
default |
Use a separate server with this name, like tmux -L. Also read from WS_SOCKET_NAME |
-h, --help |
Print help for ws or any subcommand |
|
-V, --version |
Print the version (top level only) |
A server name may contain ASCII letters, digits, - and _. Any other character becomes _ in the socket file name. Each name has its own socket, its own saved session (~/.local/state/ws/state-<name>.db) and its own panes.
ws [COMMAND]...
Section titled “ws [COMMAND]...”Start the background server if needed, then attach this terminal to it.
| Argument | Default | Description |
|---|---|---|
[COMMAND]... |
$SHELL |
Command to run in the pane. Everything after the program name goes to it |
- No server running:
wsstarts one with the command in its first pane. If a saved session is waiting (after a crash orws kill-server --keep), it first asks whether to restore it. Without a terminal to ask, it restores. - Server running:
wsattaches. A command opens in a new tab, in the directory you ranwsfrom. - With
--local: ws runs inside this terminal with no server. - Inside a pane of the same server:
wsrefuses, because ws would show itself inside itself. Useprefix tfor a new tab, orws -L <name>to reach a different server.
ws # your shell, or reattachws claude --model opus # "--model opus" goes to claudews -L dev # a separate server named "dev"ws --local htop # no server; ends when this terminal closesTo run a program whose name matches a ws subcommand, give its path, for example ws ./new.
Caution: because any word that isn’t a subcommand is a command to run, a mistyped or quoted subcommand doesn’t give a usage error.
ws "tab new"orws tabs liststarts a server (or attaches to the running one) and tries to runtab newortabsin a pane. Type subcommands as separate words, spelled as in this page:ws tab new. See Troubleshooting.
ws attach
Section titled “ws attach”Attach to the running server. Plain ws does too, and starts one if needed.
ws attach fails with no ws server is running; `ws` starts one when nothing is running. Only one terminal is attached at a time; attaching from a second terminal detaches the first, which prints [detached: attached from another terminal].
ws attachws attach -L devws kill-server
Section titled “ws kill-server”Stop the background server and every pane in it. This also clears the saved session, so the next ws starts fresh. It returns once the server has exited (up to five seconds), so when it says stopped, the panes’ programs are gone.
ws kill-serverws -L dev kill-server| Option | Default | Description |
|---|---|---|
--keep |
off | Save the session first and leave it on disk, so the next ws offers to restore it (agents resume their conversations). |
Prints Stopped the ws server; its panes were closed., or with --keep, Stopped the ws server and saved the session; `ws` restores it. Fails if no server is running.
ws restart
Section titled “ws restart”Stop the server keeping the session, start a new one that restores it without asking, and attach. Use it to switch to a newly installed build. Refuses to run inside a pane of the server it would restart.
ws restartws -L dev restartA server from before ws restart existed answers that it’s too old; use ws kill-server and ws then. See Restart, keeping the session.
ws debug
Section titled “ws debug”Look at what the server recorded about agent status. These commands read the server’s state file directly, so they work whether or not the server is running.
ws debug events
Section titled “ws debug events”Hook events, status changes and detections, oldest first.
| Option | Default | Description |
|---|---|---|
--since <duration> |
10m |
How far back: a number with s, m, h or d, such as 90s, 10m, 2h, 1d |
--pane <id> |
all panes | Only this pane. Its number is in the inspector title |
ws debug events --since 2h --pane 3ws debug status
Section titled “ws debug status”A pane’s saved agent identity and its last 20 events.
| Argument | Description |
|---|---|
<PANE> |
The pane id |
ws debug status 3ws record
Section titled “ws record”Run a command in ws and record its raw terminal output to a file, for golden-test fixtures. It always runs in this terminal, never in the server. Avoid resizing the window while recording.
| Argument | Default | Description |
|---|---|---|
<FILE> |
Where to write the recording | |
[COMMAND]... |
$SHELL |
Command to record |
ws record crates/ws-term/tests/fixtures/htop.wsrec htopThis is a development tool for ws itself.
ws capture
Section titled “ws capture”Run a command in an off-screen terminal and save its screen, for documentation. It writes OUT.json, the screen as frame data (rows of styled text runs) that the website draws as a sharp, theme-aware picture, and OUT.svg, the same screen as an image. A setup script can stage what should be on screen first. The screenshots in this guide are made this way, from the real interface.
| Argument or option | Default | Description |
|---|---|---|
<OUT> |
Where to write, without extension | |
--size <COLSxROWS> |
160x48 |
The terminal’s size |
--setup <command> |
none | A shell command to run once the program has drawn something |
--wait-for <text> |
none | Wait until this text is on screen. Repeatable, checked in order |
--keys <keys> |
none | Keys to send before capturing, such as "C-Space f", Enter, Esc. A word that isn’t a key name is typed; Click@X,Y and RClick@X,Y click a cell. Repeatable |
--crop <NAME=X,Y,WxH> |
none | Also save this part of the screen, as OUT-NAME.json and .svg. Repeatable |
--settle <ms> |
800 |
How long to let the screen settle before capturing |
--timeout <s> |
20 |
The longest wait for any one step |
[COMMAND]... |
$SHELL |
What to run |
ws capture /tmp/htop --size 120x30 --wait-for "Load average" -- htopThis is a development tool for ws itself.
ws report
Section titled “ws report”Report an agent hook event to the ws that owns this pane. It reads the hook’s JSON from stdin.
| Argument or option | Default | Description |
|---|---|---|
<EVENT> |
Hook event name, such as Stop or UserPromptSubmit |
|
--agent <name> |
none | Agent CLI sending the event, such as claude or codex |
Agent hooks call this; you don’t normally run it yourself. ws integrate installs the hooks. Outside ws (no WS_SOCKET or WS_PANE_ID), it does nothing. It always exits 0 and gives up after about a second, so it can never break or stall the agent.
echo '{"session_id":"abc"}' | ws report --agent claude Stopws new
Section titled “ws new”Open a workstream from a template: a worktree and branch, the template’s panes, and its setup. See Workstreams.
| Argument or option | Default | Description |
|---|---|---|
<TEMPLATE> |
Template name (see ws templates) |
|
[NAME] |
pr-<number> with --pr |
Workstream name, and the new branch’s name. Required unless --pr is given |
--branch <branch> |
a new branch named NAME |
Check out this existing branch instead. Can’t be combined with --pr |
--pr <number> |
none | Check out this pull request (forks too) with gh pr checkout |
--project <slug> |
none | Link the workstream to this project |
Inside ws, it opens in that ws and prints Opening <name> in ws. With -L <name> it goes to that server instead, even from inside another one (Opening <name> in ws -L <name>), starting it if it isn’t running. Outside, it starts or attaches to the server with the workstream, or runs it in this terminal with --local.
ws new design-system-pr button-focusws new design-system-pr --pr 101 --project button-a11yws workspace
Section titled “ws workspace”Workspaces, for scripts. See Scripting ws.
ws workspace new
Section titled “ws workspace new”Create a workspace with one shell tab, in the background. Prints nothing.
| Argument or option | Default | Description |
|---|---|---|
<NAME> |
The workspace’s name | |
--exists-ok |
off | Succeed if a workspace with this name already exists. Names that differ only in case count as the same |
ws workspace new Games --exists-okws workspace list
Section titled “ws workspace list”Workspaces and how many tabs each has: one line each, name[ (current)]<TAB>N tabs.
| Option | Default | Description |
|---|---|---|
--json |
off | Print JSON: workspaces with their tabs, projects and panes |
ws workspace list --jsonws workspace close
Section titled “ws workspace close”Close a workspace and stop everything in it. The only workspace can’t be closed this way; use ws kill-server.
| Argument | Description |
|---|---|
<NAME> |
The workspace’s name (exact, then ignoring case) |
ws workspace close Gamesws pane
Section titled “ws pane”Panes, for scripts. See Scripting ws.
ws pane send
Section titled “ws pane send”Type text into a pane as a paste, then press Enter with --enter.
| Argument or option | Default | Description |
|---|---|---|
<PANE> |
The pane id | |
[TEXT]... |
empty | The text. Words are joined with spaces. Omit it with --enter to just press Enter |
--enter |
off | Press Enter after the text |
ws pane send 12 --enter cargo testws pane close
Section titled “ws pane close”Close a pane and stop what runs in it. An emptied tab or workspace closes too. The last pane in ws can’t be closed this way.
| Argument | Description |
|---|---|
<PANE> |
The pane id |
ws pane close 12ws tab
Section titled “ws tab”Tabs, for scripts. See Scripting ws.
ws tab new
Section titled “ws tab new”Open a tab running a command (default: your shell). Prints the new pane’s id.
| Argument or option | Default | Description |
|---|---|---|
--workspace <name> |
the workspace on screen | Where to open the tab |
--name <name> |
the focused pane’s label | The tab’s name |
--cwd <dir> |
the current directory | Where the command starts |
--project <slug> |
none | Link the tab to this project |
--focus |
off | Move the view to the new tab |
[COMMAND]... |
$SHELL |
What to run. Put it after -- |
ws tab new --workspace Games --name Snake --cwd ~/code/snake -- nvim plan.mdws tab close
Section titled “ws tab close”Close a tab and stop its panes. The last tab in ws can’t be closed this way.
| Argument or option | Default | Description |
|---|---|---|
<TAB> |
The tab’s name, or its number counting from 1 | |
--workspace <name> |
the workspace on screen | The workspace the tab is in |
ws tab close --workspace Games Snakews tab list
Section titled “ws tab list”Tabs as workspace<TAB>tab<TAB>project<TAB>panes<TAB>ports lines. project is - when the tab has none, panes is a comma-separated list, and ports is the tab’s listening TCP ports, comma-separated, or - (dev servers).
| Option | Default | Description |
|---|---|---|
--workspace <name> |
all workspaces | Only this workspace (ignoring case) |
--json |
off | Print JSON instead |
ws tab list --workspace Games | awk -F'\t' '{ print $2, $4 }'ws split
Section titled “ws split”Split a pane to the right, or below with --down, and run a command there. Prints the new pane’s id.
| Argument or option | Default | Description |
|---|---|---|
--pane <id> |
$WS_PANE_ID |
The pane to split. Required outside ws |
--down |
off | Split below instead of to the right |
--cwd <dir> |
the current directory | Where the new pane starts |
--focus |
off | Move the view to the new pane |
--size <cells> |
half | The new pane’s rows (with --down) or columns, as its program sees them |
[COMMAND]... |
$SHELL |
What to run. Put it after -- |
agent=$(ws split --pane 4 -- claude)ws split --pane "$agent" --down --size 24 -- cargo runws project
Section titled “ws project”Projects: a goal plus the files that carry it across agent sessions. See Projects. Project folders live in ~/.local/share/ws/projects/ (or $XDG_DATA_HOME/ws/projects/).
ws project new
Section titled “ws project new”Create a project folder (brief, plan, decisions, log) and open the brief in your editor.
| Argument or option | Default | Description |
|---|---|---|
<NAME> |
The project’s name. Its slug is made from it | |
--goal <text> |
"" |
The project’s goal |
--workspace <name> |
none | The workspace the project belongs to |
--no-edit |
off | Don’t open the brief |
The editor is WS_EDITOR if set, else nvim if it’s installed, else $VISUAL or $EDITOR, else vi. The brief only opens when stdin is a terminal.
ws project new "Button a11y" --goal "Every button passes WCAG 2.1 AA" --no-editws project list
Section titled “ws project list”Projects, their status, next task and last handoff.
ws project listws project show
Section titled “ws project show”One project’s details, open tasks and recent handoffs.
| Argument | Description |
|---|---|
<SLUG> |
The project’s slug |
ws project show button-a11yws project attach
Section titled “ws project attach”Link the tab you run this in to a project. It only works inside a ws pane.
| Argument | Description |
|---|---|
<SLUG> |
The project’s slug |
ws project attach button-a11yws project archive
Section titled “ws project archive”Mark a project done. It’s hidden from the sidebar, and its files are kept.
| Argument | Description |
|---|---|
<SLUG> |
The project’s slug |
ws project archive button-a11yws project rename
Section titled “ws project rename”Rename a project. Its slug (folder and id) stays the same unless you pass --slug.
| Argument or option | Default | Description |
|---|---|---|
<SLUG> |
The project’s current slug | |
<NAME> |
The new name | |
--slug |
off | Also move its folder to the new name’s slug. Linked tabs in the running ws follow |
ws project rename button-a11y "Accessible buttons" --slugws project delete
Section titled “ws project delete”Delete a project and its folder. It asks first.
| Argument or option | Default | Description |
|---|---|---|
<SLUG> |
The project’s slug | |
--yes |
off | Don’t ask. Required when there is no terminal to ask on |
ws project delete old-spike --yesws project continue
Section titled “ws project continue”Open a tab with an agent continuing the project from its files.
| Argument or option | Default | Description |
|---|---|---|
<SLUG> |
The project’s slug | |
--workspace <name> |
the workspace on screen | Put the tab in this workspace |
--split |
off | A shell on the left and the agent on the right. Same as --layout split |
--layout <layout> |
agent |
agent (one pane), split (shell, then agent), or workbench (brief, plan and log in the editor, then the agent above a run pane) |
--focus |
on without --workspace, off with it |
Move the view to the new tab |
--agent <name> |
claude |
claude or codex |
--model <model> |
the agent’s default | Model to pass to the agent as --model |
--task <n> |
the next open task | The task number in plan.md |
--dir <dir> |
the project’s remembered directory, else the current one | Where the agent works. Remembered |
--run <command> |
none (a shell) | With --layout workbench: what the run pane runs, again on Enter after it exits. Remembered |
--run-rows <n> |
half | With --layout workbench: rows the run pane starts with. Remembered |
With --workspace, --layout or --split, it builds the tab through the scripting requests and prints <name> in <workspace>: panes <ids>. Without them, it opens one agent tab in the ws you’re in (or starts and attaches ws) and prints Opened a tab continuing <slug>. That form also uses and remembers --dir, but it has no run pane: it ignores --run and --run-rows and prints ws: --run and --run-rows apply to --layout workbench; ignoring them.
ws project continue tetris --workspace Games --layout workbench --dir ~/code/tetris --run "cargo run" --run-rows 24ws project continue button-a11y --agent codex --task 3ws project handoff
Section titled “ws project handoff”Ask the project’s idle agents to write their handoff entries in the project log.
| Argument | Description |
|---|---|
<SLUG> |
The project’s slug |
ws project handoff button-a11yws settings
Section titled “ws settings”Settings. See that page for what’s in each tab.
| Command | Does |
|---|---|
ws settings |
Open the Settings workspace in the running ws (as prefix S). With no ws running, runs the Keyboard shortcuts page here |
ws settings keys |
The Keyboard shortcuts page, in this terminal (what each Settings tab runs) |
ws keys
Section titled “ws keys”Your keys, from ~/.config/ws/keys.toml over the defaults. See Changing keys.
| Command | Does |
|---|---|
ws keys |
In a terminal: the shortcut editor (see Changing keys). Piped: the same as --list |
ws keys --list |
Every command’s name, description and keys, and the leader |
ws keys --check |
Load keys.toml and report errors and notes |
ws keys --print-defaults |
A complete keys.toml with every default |
ws usage
Section titled “ws usage”AI usage recorded from agents’ transcripts: tokens by agent and model, Codex’s rate limit, and the commands, skills and tools agents used. See AI usage.
| Command | Does |
|---|---|
ws usage |
Today (--week from Monday, --all everything; --json for scripts) |
ws usage backfill |
Read the transcripts of sessions recorded before usage was, once |
ws usage clear --all / --since YYYY-MM-DD / --session ID |
Forget recorded usage (asks first; --yes doesn’t). The transcripts aren’t touched |
ws mem
Section titled “ws mem”The agent memory store: facts, decisions, preferences, tasks and handoffs that every agent can share. See Memory. Ids can be given as any unique start or end of 4+ characters; lists show the last 6.
| Command | Does |
|---|---|
ws mem add [TEXT]... |
Store an item; first line is the title. Reads stdin with no text. Options: --kind (note), --scope (repo here, else global), --title, --tag, --link kind:target (file, pr, commit, url, workstream, project, memory), --pin, --propose |
ws mem search <QUERY>... |
Full-text search, best first. --scope, --kind, --all (any status), --limit (20), --json |
ws mem list |
Newest first, pinned on top. --scope, --kind, --status, --all, --json |
ws mem show <ID> |
Text, provenance, links and history. --json |
ws mem edit <ID> |
Edit in your editor; saving makes a new version. --in-place fixes the text without one |
ws mem approve / reject / archive <ID>... |
Change status |
ws mem pin / unpin <ID> |
Always (or no longer always) include it in agents’ context |
ws mem forget [ID]... |
Delete for good; also --scope, --since YYYY-MM-DD, --session <id>. Asks first unless --yes |
ws mem export |
JSON lines with provenance. --scope, --kind, --all |
ws mem import <FILE> |
Items from an export, as proposed; - reads stdin |
ws mem lint |
Links to missing files, expired tasks, items unused for --days (90) |
ws mem summarize [SESSION] |
Summarize a session now with memory.summarize.command: a summary item and up to five proposed items. Default: the latest session in this pane |
ws mem sessions |
Agent sessions ws recorded, newest first: this repo’s, or --all, --project <slug>, --workstream <name>. --limit (20), --json |
ws mem path |
The database’s path |
Scopes are written global, repo, workspace, workstream, project (worked out from the current directory and pane) or kind:key (repo:github.com/org/name, project:button-a11y). With -L <name> (or inside a named server’s pane), ws mem uses that server’s store, memory-<name>.db.
ws mem add "Run bin/setup_db before specs" --kind fact --link file:bin/setup_dbws mem search setup db --json | jq -r '.[].title'ws mem export --all > memory-backup.jsonlws context pack
Section titled “ws context pack”Print the context pack for an agent starting here: what memory holds for this directory’s workstream, project, workspace, repo and global scopes, within the token budget.
| Option | Default | Description |
|---|---|---|
--for <AGENT> |
none | The agent it’s for (claude, codex). Prints nothing unless memory.deliver_to includes it, and never fails, since it runs inside agents’ launch commands |
--budget <TOKENS> |
memory.budget (1500) |
Size cap, about 4 characters per token |
--from <SESSION> |
none | Start with what that session (an id from ws mem sessions --json) did and left: the handoff pack |
--then <TEXT> |
none | Text to put after the pack, such as a first prompt |
--delta <SESSION> |
none | Instead of the pack: only what happened since that session’s turn, for an agent resuming it (with --from, the session being left). What ws handoff uses when it goes back to an agent |
--toml |
off | Print it as a TOML string, for codex -c developer_instructions=…; with --for codex, your own developer_instructions come first |
--json |
off | The text, the ids used, and how many didn’t fit |
ws handoff
Section titled “ws handoff”Continue a pane’s work in another agent: a new pane beside it runs the agent with a handoff pack (what the pane’s last agent session did and left, plus memory) and a prompt to carry on. See Memory.
| Option | Default | Description |
|---|---|---|
--to <AGENT> |
required | claude, codex, or any [agents.<kind>] in config.toml |
--model <MODEL> |
none | Passed with the agent’s model flag |
--pane <ID> |
this pane | The pane to take over from |
--prompt <TEXT> |
carry on from the handoff | The new agent’s first prompt |
--no-ask |
off | Skip asking the old agent for a handoff before switching |
--fresh |
off | Start a new session even when an earlier session of that agent could be gone back to |
--replace |
off | Close the old pane once the new one is up |
--no-focus |
off | Don’t focus the new pane |
Prints <new pane><TAB><old agent> → <new agent>, followed by the handoff
request’s outcome when ws asked for one. Going back to an earlier session, it
says → back to <agent> (resumed), or → back to <agent> in pane <N> when
that session is still running there.
ws review
Section titled “ws review”Open a review tab for each pull request: a worktree with the PR checked out, .ws/pr.md with its description, comments, reviews and inline threads, and your review agent started as a new session. See Reviewing PRs.
ws review https://github.com/org/repo/pull/12ws review billing/12 billing/14 org/repo#88ws review --update billing/12| Argument or option | Default | Description |
|---|---|---|
<PRS>... |
required (except with --post or --send) |
URLs, alias/N or alias#N, org/repo#N, or numbers in the current directory’s repo; separate arguments or comma-separated |
--post |
off | Post the review in .ws/review.md: shows it and asks approve, comment, request changes, edit or quit (needs a terminal). PR: the one given, else the review worktree you’re in |
--send |
off | Send your comments on this branch’s changes (.ws/review.md at the top of the repo, from :WsComment) to the agent in this tab as one prompt, then move the file to .ws/review-sent-<time>.md. See Reviewing your own agents’ work |
--print |
off | With --send: print the prompt and send nothing |
--update |
off | Pull new commits, rewrite .ws/pr.md and start the review over in a new tab, replacing an open one |
--no-focus |
off | Don’t switch to the first review’s tab |
Prints label<TAB>opened|updated|already open<TAB>pane for each PR. Errors are printed per PR on stderr, and the exit status is 1 if any PR didn’t open. Settings are in ~/.config/ws/config.toml under [review].
ws pr comments
Section titled “ws pr comments”Send a PR’s unresolved review threads to the agent in this tab, as one “address these” prompt. It shows exactly what it will send and asks first. See Reviewing PRs.
ws pr comments # the PR for the branch checked out herews pr comments billing/12ws pr comments 61 --print # just print the prompt| Argument or option | Default | Description |
|---|---|---|
[PR] |
the branch’s PR | A URL, alias/N, org/repo#N, or a number in this repo |
--yes |
off | Send without asking (otherwise it needs a terminal to ask) |
--print |
off | Print the prompt and send nothing; works outside ws |
It prints label: sent N unresolved threads to the agent in pane P, or label: no unresolved review comments. Sending must run in a ws pane whose tab has an agent. It never resolves threads or replies on GitHub. The prompt’s first line is [pr_comments] prompt in ~/.config/ws/config.toml.
ws done
Section titled “ws done”Finish a workstream: close its tab (stopping its processes) and remove its git worktree. The branch stays, and so does any project linked to the tab.
ws done # the workstream this pane is inws done pr-101 # by namews done pr-101 --force| Argument or option | Default | Description |
|---|---|---|
[NAME] |
this pane’s workstream | The workstream’s name. Default: the one whose tab this pane is in. Outside ws, the name is required. |
--force |
off | Remove it even with uncommitted changes or commits that aren’t on any remote branch. |
Without --force, ws done refuses and says why when the worktree has uncommitted changes, or when its current commit isn’t on any remote branch (neither pushed nor merged):
pr-101 isn't done: 2 uncommitted changes; feat/login has commits that aren't pushed or merged (--force removes it anyway)On success it prints Done: the tab is closed; the worktree is removed in a moment (the branch stays). Run from inside the workstream, the pane may close before that line appears; that’s still success. It can’t close the last tab in ws. See Finishing a workstream.
ws open
Section titled “ws open”Open a file in this workstream’s Neovim and focus it. Outside ws, it runs nvim directly.
| Argument | Description |
|---|---|
<LOCATION> |
path[:line[:col]]. Relative paths are resolved from the current directory |
ws open app/models/user.rb:42ws view
Section titled “ws view”Read a Markdown file, rendered, updating as it changes. See the Markdown viewer.
| Argument or option | Default | Description |
|---|---|---|
<FILE> |
The Markdown file | |
-s, --split |
off | Inside ws, open it in a new pane beside this one, on the right, and focus it |
--below |
off | With --split: below instead of on the right |
Outside ws, --split is ignored and the file opens in this terminal.
ws view README.mdws view --split --below log.mdws dashboard
Section titled “ws dashboard”The Dashboard page, in this pane: what needs you now (agents, workstreams, review requests), how to get going with your own keys, agent hooks, what ws doctor found, and buttons to start things and go to your workspaces and projects. ws keeps one as the first tab of the Dashboard workspace; see Getting started.
| Key or mouse | Action |
|---|---|
Tab / Shift-Tab, arrows, h / l |
Move between buttons |
Enter, space, a click |
Run the button: go to the agent’s or workstream’s pane, run the command as if you pressed its key, go to the workspace, or continue the project (ws project continue) |
j / k, the wheel |
Scroll |
r |
Read everything again, ws doctor and review requests included |
q |
Close the page |
It asks the server what’s happening every 2 seconds (dashboard), ws doctor once when it opens, and GitHub for review requests every 2 minutes. Outside ws there’s no “Now” section, and buttons say there’s no server.
ws templates
Section titled “ws templates”List workstream templates from ~/.config/ws/templates, with each template’s repo and panes.
ws templatesws doctor
Section titled “ws doctor”Check the tools, hooks, config and terminal ws depends on, and say what to fix. Exits 1 if something is broken. See Troubleshooting.
| Option | Default | Description |
|---|---|---|
--fix |
off | Apply the safe fixes first (remove stale sockets, create directories), after asking |
--json |
off | Print the checks as a JSON array of {area, name, level, detail, fix} objects, for tools. level is ok, warn or fail; fix is left out when there’s nothing to fix. The exit code is the same |
The running server uses ws doctor --json for the ✗ doctor: N badge in its top bar; see the interface.
ws doctor --fixws doctor --json | jq -r '.[] | select(.level == "fail") | .name'ws integrate
Section titled “ws integrate”Install the hooks that let ws see an agent’s status. See Agents.
| Argument or option | Default | Description |
|---|---|---|
<TARGET> |
claude: user-level hooks in ~/.claude/settings.json. codex: user-level hooks in ~/.codex/hooks.json (or $CODEX_HOME/hooks.json) |
|
--remove |
off | Remove the hooks instead |
--print |
off | Print the resulting settings without writing them |
--bin <path> |
this ws binary |
The ws binary the hooks should run |
--mcp |
off | Register ws mcp (agent memory) as a user-level MCP server named ws, through the agent’s own CLI (claude mcp add --scope user, codex mcp add), instead of installing hooks. With --remove, unregister it; with --print, show the commands |
It keeps a backup of the previous file next to it. For Codex, it also makes sure Codex’s hooks feature is on and its daemon_auto_start feature is off, setting features.hooks = true and features.daemon_auto_start = false in Codex’s config.toml if needed. If Codex’s shared daemon is running, it says how to stop it.
ws integrate claudews integrate codex --printws integrate claude --removews integrate claude --mcpws integrate codex --mcp --printws mcp
Section titled “ws mcp”Agent memory as an MCP server on stdin/stdout, for Claude Code, Codex and other MCP clients. Agents start it themselves once it’s registered (ws integrate <agent> --mcp). Its tools: memory_context, memory_search, memory_get, memory_propose, memory_handoff, session_history. See Memory.
ws help
Section titled “ws help”Print help for ws or a subcommand. ws help tab new is the same as ws tab new --help.
Internal: ws __serve
Section titled “Internal: ws __serve”ws __serve is the background server itself. ws starts it in its own session so closing the terminal doesn’t stop it. It is hidden from help and not meant to be run by hand. Its flags (--cols, --rows, --workstream, --restore) are internal and may change.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 |
Success. ws report always exits 0 |
1 |
The command failed. The reason is printed as Error: … on stderr. ws doctor exits 1 when a check fails |
2 |
A usage error, such as an unknown flag or a missing argument |
Environment variables
Section titled “Environment variables”| Variable | Read by | Meaning |
|---|---|---|
WS_SOCKET_NAME |
every command | Same as -L: the server name to use |
WS_SOCKET |
scripting commands, ws open, ws report, ws new, ws project … |
Set in every pane: the socket of the ws that owns it |
WS_PANE_ID |
ws split, ws view --split, ws open, ws report, ws project attach |
Set in every pane: its id |
WS_WORKSPACE |
your scripts | Set in every pane: its workspace’s name |
WS_WORKSTREAM |
your scripts | Set in workstream template panes: the workstream’s name |
WS_EDITOR |
ws project new, workbench layout |
The editor to use |
See Configuration for files ws reads, and the protocol for how panes use these variables.