Command line

Every verb, as wsp --help prints it. This page is generated from the binary at wsp 0.1.4; do not edit it by hand, run pnpm --filter @wsp/docs cli after the host changes.

Every verb takes --json for one JSON object per line, frames first and the result last, and --state <path> to name the state file the host serves. A refusal is one line on stderr and an exit code of its class: 0 ok, 1 provider, 2 auth, 3 usage. wsp exec exits with the command's own code.

wsp - your setup, on cloud machines, for coding agents

usage:
  wsp up             start the app and the runtime over the golden you sealed
                     (plain wsp does the same). It serves until you stop it, so
                     closing that terminal takes the app down with it; --service
                     hands the same line to this computer's own service manager
                     instead, which starts it now and again at every login
  wsp down           stop the service and take it away, so nothing brings the
                     host back at the next login
  wsp status         whether a host is serving this state file, on which ports,
                     and what keeps it there, with a non-zero exit code when
                     none does
  wsp init           set up your first golden image in six screens: Agents,
                     Tools, Also on this Mac, Sign-ins, wsp for your agents
                     on this Mac, and Build, then the browser. With no provider
                     key it seals nothing and makes this computer your
                     workspace instead
  wsp doctor         run the reach loop end to end against one live machine
                     (--yes also deletes the snapshots this host left behind);
                     --local proves the other half instead, a thread on this
                     computer and its reply, with no machine and no key
  wsp mcp            serve the verbs as MCP tools over stdio to an agent on this
                     computer; wsp mcp install --agent <id> puts the server in
                     that agent's own MCP config (claude, codex, gemini, opencode),
                     the wsp skill in its skills folder, and wsp's own section
                     in this folder's AGENTS.md, which --remove takes back out.
                     --agent repeats and off a terminal every agent on your PATH
                     takes it; --json prints one line holding what each agent
                     took and a failures array for the ones that took nothing;
                     all three are read by mcp install alone
  wsp --version      print the version

verbs; every one takes --json for its raw values. The recipe verbs read this
computer and write beside the state file; the rest speak to the host wsp up
started:
  wsp workspaces
      every workspace this host runs: what its machine is, its state as the
      sidebar shows it (running, paused, waking or unreachable, off the phase
      with the provider's word for the machine and the daemon reach beside it)
      where the kind has one, and how many projects it holds
  wsp projects <workspace>
      the projects on the workspace, oldest import first: name, folder on the
      machine, size and when it landed; the name is what thread new --project
      takes
  wsp threads [--in <workspace>]
      every thread as the sidebar lists it: agent, state, who opened it, the
      folder it works in
  wsp threads wait <thread>... [--timeout <s>]
      blocks until one of the threads leaves running and prints its finished
      line, the one a notify sends; --timeout gives up after so many seconds and
      says so on stderr
  wsp recipe scan [--project <folder>]
      read this computer and print every option, writing nothing: the agents,
      the tools with why and size, what else a package manager here has that the
      image could take, the commands your agents ran, and the sign-ins, each
      with what to do about it and one line of why; --project weighs the
      histories by a folder and --json prints it as one object
  wsp recipe [--tick used|installed|default] [--set <id>=on|off]
    [--signin <id>=copy|machine|key|skip] [--add <id>=<command>]
    [--add-check <id>=<command>] [--project <folder>] [--out <path>]
      write the recipe and print it as a table: every catalog agent and tool
      with its tick, why it has it and what it costs on the machine, then the
      commands your agents ran that no catalog row carries. --tick
      used|installed|default names the rule that decides every tick (used, the
      default, ticks what your agents actually ran here); --set <id>=on|off
      flips a row by its catalog id, or a package this Mac's own package
      managers have by the id wsp recipe scan gives it, which the build installs
      by that package's own road; --signin <id>=copy|machine|key|skip answers a
      sign-in by catalog id, key bringing the key files beside a login and
      nothing else of it; --add <id>=<command> carries a tool neither the
      catalog nor this Mac has, installed by that command on the machine, with
      --add-check <id>=<command> saying it is there; --project reads a folder's
      own manifests for what it takes to build and weighs the histories by it,
      --out says where the file goes and --json prints the table as one object.
      Naming --tick or --project decides every tick again; without either, what
      the file says stands and the flags flip rows on top of it. A sign-in
      answer stands either way: no rule decides one. All of them repeat. Review
      it, then wsp init --recipe
  wsp new <name> [--from <project golden>] [--size <cpu>x<memGb>] | wsp new
    --local [name] | wsp new --ssh <user@host> [name] [--ssh-port <port>]
    [--ssh-key <path>]
      a workspace from the golden's head or, with --from, a project golden;
      --local is this computer, --ssh a machine of your own
  wsp rename <workspace> "<name>"
      names the workspace on this computer; the name is unique here, so one
      another workspace holds is refused
  wsp snapshot <workspace>
      a project golden of the workspace: its golden plus the project as it is
      now, ready to fork
  wsp fork <workspace> [--name <n>] [--size <cpu>x<memGb>]
    [--send "<task>" [thread new's flags]]
      a new machine from the source's golden version, not a copy of its live
      disk; --size as new's
  wsp pause <workspace>
      naps the workspace's machine
  wsp wake <workspace>
      wakes the workspace's machine and prints its state once the runtime has
      answered
  wsp rebuild <workspace>
      replaces a gone workspace's machine from its image and prints the state of
      the new one
  wsp forget <workspace> [--yes]
      drops a gone workspace and its threads from this computer; refused while
      its machine exists
  wsp delete <workspace> [--yes]
      deletes the machine at the provider, then drops the record and threads
      from this computer
  wsp thread new --in <workspace>
    [--agent, --model, --effort, --access, --project <name>, --cwd, --notify, -…
    "<task>"
      opens a thread with the agent, model, effort and access the app offers, in
      the project named or the one the app's pick would take; follows its first
      turn, or with --detach prints the id and returns
  wsp thread read <thread> [--last]
      the thread's messages as the app lists them, oldest first: who each one
      is, when the runtime recorded it and the text, with every tool call folded
      to the one line the app's row reads; --last prints the final reply alone,
      the whole message its finished line carries. A tool's output and the
      agent's reasoning are no rows of it
  wsp thread rename <thread> "<title>"
      names the thread inside the agent's own store, so the agent shows the same
      name
  wsp send <thread> [--model, --effort, --access <value>] [--image <path>]
    [--detach] "<message>"
      a message to the thread, on a named model, effort or access, with images;
      a running turn keeps its own; --detach prints the id and returns
  wsp stop <thread>
      stops the thread's running turn, as the app's stop does; the machine stays
      up
  wsp exec <workspace> [--cwd <dir>] -- <command...>
      runs the command on the machine, each word as given, in --cwd or the
      folder a thread would start in
  wsp folders [<folder>] [--hidden]
      the folders inside one folder on this computer, for naming one to import;
      the home folder and every imported project are the roots and nothing
      outside them is listed
  wsp import <folder> --to <workspace> [--yes] [--keep, --cut <path>]
    [--agents <ids>] [--replace]
      lands a folder on the machine at its path here; the plan first, then --yes
      or one question
  wsp terminal config [--scheme light|dark]
      the Ghostty config on this computer as the app's terminal pane applies it,
      read from ~/.config/ghostty and Application Support with its includes and
      theme resolved: the font and its fallbacks, the size, the colors, the
      cursor, the padding, the background opacity, and the blur, which is read
      but not applied; --scheme picks the side of a light:...,dark:... theme
  wsp export <workspace> <folder> [--from <path on the machine>] [--replace]
    [--agents <ids>]
      brings a project folder and the agent sessions keyed to it home from the
      machine

  wsp send streams the reply to stderr as it arrives and prints the last message
  on stdout when the reply is complete.
  A turn ends when the agent process exits, not at its reply, and the thread
  reads running until then.
  wsp exec streams the command's output and exits with its code. thread new,
  send and exec wake a paused workspace first, with one line on stderr saying so.

exit codes; every failure is one line on stderr, the failure object with --json:
  0 ok        it did what its line says; with --json stdout holds the answer
  1 provider  the host, the runtime, Solari or the machine refused or failed
  2 auth      no key, no sign-in, or the host refused the token
  3 usage     the line was refused before anything ran: a missing argument, an
              unknown flag or a value nothing takes

options:
  --port N           app port (default 4400); the runtime websocket
                     port follows 10 above it
  --ws-port N        runtime websocket port on its own (default
                     4410); --port alone moves both
  --state PATH       state file (default ~/.wsp/state.json, or ./.wsp/state.json
                     when the current directory has a .env)
  --yes              init: take every default and ask nothing (required off a
                     terminal); a login with a browser or device sign-in, or one
                     held in the Keychain, defaults to sign in on the machine
                     unless a saved recipe answered copy, so macOS has nothing
                     to ask either and the sign-ins wait for the app's terminal.
                     doctor: also delete the snapshots and templates this host
                     left behind, which is not reversible
  --recipe PATH      init: tick the agents and tools from this recipe (wsp recipe
                     writes it; init writes <state dir>/recipe.json too) and go
                     straight to the sign-ins; this machine is still read for
                     what travels
  --project PATH     init: the project folder you are bringing first. Its own
                     files (package.json, the lockfiles, pyproject, go.mod,
                     Cargo.toml, the compose files, .tool-versions, the CI
                     workflows) say what it needs, and those rows are ticked
                     first, each saying which file asked. Without it, init asks
                     for one before the first screen
  --first-workspace NAME
                     init: fork the first workspace under this name once the
                     golden seals, without asking (default first). A run with
                     nobody at a terminal forks nothing unless this or --import
                     asks for it
  --import FOLDER    init: import this folder's project onto that first
                     workspace, with the consent the app's import starts from:
                     caches left behind, secret-shaped files cut unless a
                     rewrite drops their credentials, and the sessions your
                     agents have for the folder travelling with it
  --no-local         init: leave this computer alone. The workspace step ticks
                     it by default, since a workspace here forks nothing and
                     bills nothing; this is the one way to end an init without
                     one. Refused on a run with no provider key, where it is
                     the only workspace there is
  --local            doctor: prove a thread on this computer and its reply
                     instead of the reach loop, which needs no provider key,
                     forks nothing and bills nothing
  --non-interactive  init: ask nothing, but still run the sign-ins on the
                     machine: each one prints the page to open on this computer,
                     the code when the flow shows one, and the command that
                     opens it, then waits for you (this is what a run off a
                     terminal does anyway). The run ends with the golden
                     recorded and never serves the app; wsp up does that
  --service          up: install the host as a launchd agent on a Mac, or a
                     systemd user unit on Linux, and wait for it to answer on
                     its port. The keys are not written into it: the service
                     reads the same .env a terminal run reads, so they have to
                     be in a file rather than exported in the shell that
                     installs it. It does pin the node and the wsp it was run
                     from by path, so a node that goes away later (an nvm
                     switch, a brew upgrade) stops the service at the next
                     login, with its log the only place that says why
  --json             init: print each build stage frame (with the install step
                     it belongs to, the command that step runs and its seconds
                     so far), each sign-in hand-off and its outcome as one JSON
                     object on stdout, then one last object naming the golden,
                     the recipe, the wsp up to run next and, unless
                     --first-workspace or --import asked for one, the wsp new
                     that forks a workspace; everything else on stderr. Implies
                     --non-interactive, and is refused beside --yes, which skips
                     the sign-ins

keys are read from the environment, then ./.env, then ~/.wsp/.env (WSP_HOME
overrides ~/.wsp). The prompt runs only when no Solari key is found; it asks
for the optional Anthropic key at the same time and can save both to that file.
With a Solari key present, a missing Anthropic key is only noted at start.
Without one, init and up take the local road: this computer is the workspace,
nothing is forked and nothing is sealed.

wsp up

wsp - your setup, on cloud machines, for coding agents

usage:
  wsp up             start the app and the runtime over the golden you sealed
                     (plain wsp does the same). It serves until you stop it, so
                     closing that terminal takes the app down with it; --service
                     hands the same line to this computer's own service manager
                     instead, which starts it now and again at every login
  wsp down           stop the service and take it away, so nothing brings the
                     host back at the next login
  wsp status         whether a host is serving this state file, on which ports,
                     and what keeps it there, with a non-zero exit code when
                     none does
  wsp init           set up your first golden image in six screens: Agents,
                     Tools, Also on this Mac, Sign-ins, wsp for your agents
                     on this Mac, and Build, then the browser. With no provider
                     key it seals nothing and makes this computer your
                     workspace instead
  wsp doctor         run the reach loop end to end against one live machine
                     (--yes also deletes the snapshots this host left behind);
                     --local proves the other half instead, a thread on this
                     computer and its reply, with no machine and no key
  wsp mcp            serve the verbs as MCP tools over stdio to an agent on this
                     computer; wsp mcp install --agent <id> puts the server in
                     that agent's own MCP config (claude, codex, gemini, opencode),
                     the wsp skill in its skills folder, and wsp's own section
                     in this folder's AGENTS.md, which --remove takes back out.
                     --agent repeats and off a terminal every agent on your PATH
                     takes it; --json prints one line holding what each agent
                     took and a failures array for the ones that took nothing;
                     all three are read by mcp install alone
  wsp --version      print the version

verbs; every one takes --json for its raw values. The recipe verbs read this
computer and write beside the state file; the rest speak to the host wsp up
started:
  wsp workspaces
      every workspace this host runs: what its machine is, its state as the
      sidebar shows it (running, paused, waking or unreachable, off the phase
      with the provider's word for the machine and the daemon reach beside it)
      where the kind has one, and how many projects it holds
  wsp projects <workspace>
      the projects on the workspace, oldest import first: name, folder on the
      machine, size and when it landed; the name is what thread new --project
      takes
  wsp threads [--in <workspace>]
      every thread as the sidebar lists it: agent, state, who opened it, the
      folder it works in
  wsp threads wait <thread>... [--timeout <s>]
      blocks until one of the threads leaves running and prints its finished
      line, the one a notify sends; --timeout gives up after so many seconds and
      says so on stderr
  wsp recipe scan [--project <folder>]
      read this computer and print every option, writing nothing: the agents,
      the tools with why and size, what else a package manager here has that the
      image could take, the commands your agents ran, and the sign-ins, each
      with what to do about it and one line of why; --project weighs the
      histories by a folder and --json prints it as one object
  wsp recipe [--tick used|installed|default] [--set <id>=on|off]
    [--signin <id>=copy|machine|key|skip] [--add <id>=<command>]
    [--add-check <id>=<command>] [--project <folder>] [--out <path>]
      write the recipe and print it as a table: every catalog agent and tool
      with its tick, why it has it and what it costs on the machine, then the
      commands your agents ran that no catalog row carries. --tick
      used|installed|default names the rule that decides every tick (used, the
      default, ticks what your agents actually ran here); --set <id>=on|off
      flips a row by its catalog id, or a package this Mac's own package
      managers have by the id wsp recipe scan gives it, which the build installs
      by that package's own road; --signin <id>=copy|machine|key|skip answers a
      sign-in by catalog id, key bringing the key files beside a login and
      nothing else of it; --add <id>=<command> carries a tool neither the
      catalog nor this Mac has, installed by that command on the machine, with
      --add-check <id>=<command> saying it is there; --project reads a folder's
      own manifests for what it takes to build and weighs the histories by it,
      --out says where the file goes and --json prints the table as one object.
      Naming --tick or --project decides every tick again; without either, what
      the file says stands and the flags flip rows on top of it. A sign-in
      answer stands either way: no rule decides one. All of them repeat. Review
      it, then wsp init --recipe
  wsp new <name> [--from <project golden>] [--size <cpu>x<memGb>] | wsp new
    --local [name] | wsp new --ssh <user@host> [name] [--ssh-port <port>]
    [--ssh-key <path>]
      a workspace from the golden's head or, with --from, a project golden;
      --local is this computer, --ssh a machine of your own
  wsp rename <workspace> "<name>"
      names the workspace on this computer; the name is unique here, so one
      another workspace holds is refused
  wsp snapshot <workspace>
      a project golden of the workspace: its golden plus the project as it is
      now, ready to fork
  wsp fork <workspace> [--name <n>] [--size <cpu>x<memGb>]
    [--send "<task>" [thread new's flags]]
      a new machine from the source's golden version, not a copy of its live
      disk; --size as new's
  wsp pause <workspace>
      naps the workspace's machine
  wsp wake <workspace>
      wakes the workspace's machine and prints its state once the runtime has
      answered
  wsp rebuild <workspace>
      replaces a gone workspace's machine from its image and prints the state of
      the new one
  wsp forget <workspace> [--yes]
      drops a gone workspace and its threads from this computer; refused while
      its machine exists
  wsp delete <workspace> [--yes]
      deletes the machine at the provider, then drops the record and threads
      from this computer
  wsp thread new --in <workspace>
    [--agent, --model, --effort, --access, --project <name>, --cwd, --notify, -…
    "<task>"
      opens a thread with the agent, model, effort and access the app offers, in
      the project named or the one the app's pick would take; follows its first
      turn, or with --detach prints the id and returns
  wsp thread read <thread> [--last]
      the thread's messages as the app lists them, oldest first: who each one
      is, when the runtime recorded it and the text, with every tool call folded
      to the one line the app's row reads; --last prints the final reply alone,
      the whole message its finished line carries. A tool's output and the
      agent's reasoning are no rows of it
  wsp thread rename <thread> "<title>"
      names the thread inside the agent's own store, so the agent shows the same
      name
  wsp send <thread> [--model, --effort, --access <value>] [--image <path>]
    [--detach] "<message>"
      a message to the thread, on a named model, effort or access, with images;
      a running turn keeps its own; --detach prints the id and returns
  wsp stop <thread>
      stops the thread's running turn, as the app's stop does; the machine stays
      up
  wsp exec <workspace> [--cwd <dir>] -- <command...>
      runs the command on the machine, each word as given, in --cwd or the
      folder a thread would start in
  wsp folders [<folder>] [--hidden]
      the folders inside one folder on this computer, for naming one to import;
      the home folder and every imported project are the roots and nothing
      outside them is listed
  wsp import <folder> --to <workspace> [--yes] [--keep, --cut <path>]
    [--agents <ids>] [--replace]
      lands a folder on the machine at its path here; the plan first, then --yes
      or one question
  wsp terminal config [--scheme light|dark]
      the Ghostty config on this computer as the app's terminal pane applies it,
      read from ~/.config/ghostty and Application Support with its includes and
      theme resolved: the font and its fallbacks, the size, the colors, the
      cursor, the padding, the background opacity, and the blur, which is read
      but not applied; --scheme picks the side of a light:...,dark:... theme
  wsp export <workspace> <folder> [--from <path on the machine>] [--replace]
    [--agents <ids>]
      brings a project folder and the agent sessions keyed to it home from the
      machine

  wsp send streams the reply to stderr as it arrives and prints the last message
  on stdout when the reply is complete.
  A turn ends when the agent process exits, not at its reply, and the thread
  reads running until then.
  wsp exec streams the command's output and exits with its code. thread new,
  send and exec wake a paused workspace first, with one line on stderr saying so.

exit codes; every failure is one line on stderr, the failure object with --json:
  0 ok        it did what its line says; with --json stdout holds the answer
  1 provider  the host, the runtime, Solari or the machine refused or failed
  2 auth      no key, no sign-in, or the host refused the token
  3 usage     the line was refused before anything ran: a missing argument, an
              unknown flag or a value nothing takes

options:
  --port N           app port (default 4400); the runtime websocket
                     port follows 10 above it
  --ws-port N        runtime websocket port on its own (default
                     4410); --port alone moves both
  --state PATH       state file (default ~/.wsp/state.json, or ./.wsp/state.json
                     when the current directory has a .env)
  --yes              init: take every default and ask nothing (required off a
                     terminal); a login with a browser or device sign-in, or one
                     held in the Keychain, defaults to sign in on the machine
                     unless a saved recipe answered copy, so macOS has nothing
                     to ask either and the sign-ins wait for the app's terminal.
                     doctor: also delete the snapshots and templates this host
                     left behind, which is not reversible
  --recipe PATH      init: tick the agents and tools from this recipe (wsp recipe
                     writes it; init writes <state dir>/recipe.json too) and go
                     straight to the sign-ins; this machine is still read for
                     what travels
  --project PATH     init: the project folder you are bringing first. Its own
                     files (package.json, the lockfiles, pyproject, go.mod,
                     Cargo.toml, the compose files, .tool-versions, the CI
                     workflows) say what it needs, and those rows are ticked
                     first, each saying which file asked. Without it, init asks
                     for one before the first screen
  --first-workspace NAME
                     init: fork the first workspace under this name once the
                     golden seals, without asking (default first). A run with
                     nobody at a terminal forks nothing unless this or --import
                     asks for it
  --import FOLDER    init: import this folder's project onto that first
                     workspace, with the consent the app's import starts from:
                     caches left behind, secret-shaped files cut unless a
                     rewrite drops their credentials, and the sessions your
                     agents have for the folder travelling with it
  --no-local         init: leave this computer alone. The workspace step ticks
                     it by default, since a workspace here forks nothing and
                     bills nothing; this is the one way to end an init without
                     one. Refused on a run with no provider key, where it is
                     the only workspace there is
  --local            doctor: prove a thread on this computer and its reply
                     instead of the reach loop, which needs no provider key,
                     forks nothing and bills nothing
  --non-interactive  init: ask nothing, but still run the sign-ins on the
                     machine: each one prints the page to open on this computer,
                     the code when the flow shows one, and the command that
                     opens it, then waits for you (this is what a run off a
                     terminal does anyway). The run ends with the golden
                     recorded and never serves the app; wsp up does that
  --service          up: install the host as a launchd agent on a Mac, or a
                     systemd user unit on Linux, and wait for it to answer on
                     its port. The keys are not written into it: the service
                     reads the same .env a terminal run reads, so they have to
                     be in a file rather than exported in the shell that
                     installs it. It does pin the node and the wsp it was run
                     from by path, so a node that goes away later (an nvm
                     switch, a brew upgrade) stops the service at the next
                     login, with its log the only place that says why
  --json             init: print each build stage frame (with the install step
                     it belongs to, the command that step runs and its seconds
                     so far), each sign-in hand-off and its outcome as one JSON
                     object on stdout, then one last object naming the golden,
                     the recipe, the wsp up to run next and, unless
                     --first-workspace or --import asked for one, the wsp new
                     that forks a workspace; everything else on stderr. Implies
                     --non-interactive, and is refused beside --yes, which skips
                     the sign-ins

keys are read from the environment, then ./.env, then ~/.wsp/.env (WSP_HOME
overrides ~/.wsp). The prompt runs only when no Solari key is found; it asks
for the optional Anthropic key at the same time and can save both to that file.
With a Solari key present, a missing Anthropic key is only noted at start.
Without one, init and up take the local road: this computer is the workspace,
nothing is forked and nothing is sealed.

wsp init

wsp - your setup, on cloud machines, for coding agents

usage:
  wsp up             start the app and the runtime over the golden you sealed
                     (plain wsp does the same). It serves until you stop it, so
                     closing that terminal takes the app down with it; --service
                     hands the same line to this computer's own service manager
                     instead, which starts it now and again at every login
  wsp down           stop the service and take it away, so nothing brings the
                     host back at the next login
  wsp status         whether a host is serving this state file, on which ports,
                     and what keeps it there, with a non-zero exit code when
                     none does
  wsp init           set up your first golden image in six screens: Agents,
                     Tools, Also on this Mac, Sign-ins, wsp for your agents
                     on this Mac, and Build, then the browser. With no provider
                     key it seals nothing and makes this computer your
                     workspace instead
  wsp doctor         run the reach loop end to end against one live machine
                     (--yes also deletes the snapshots this host left behind);
                     --local proves the other half instead, a thread on this
                     computer and its reply, with no machine and no key
  wsp mcp            serve the verbs as MCP tools over stdio to an agent on this
                     computer; wsp mcp install --agent <id> puts the server in
                     that agent's own MCP config (claude, codex, gemini, opencode),
                     the wsp skill in its skills folder, and wsp's own section
                     in this folder's AGENTS.md, which --remove takes back out.
                     --agent repeats and off a terminal every agent on your PATH
                     takes it; --json prints one line holding what each agent
                     took and a failures array for the ones that took nothing;
                     all three are read by mcp install alone
  wsp --version      print the version

verbs; every one takes --json for its raw values. The recipe verbs read this
computer and write beside the state file; the rest speak to the host wsp up
started:
  wsp workspaces
      every workspace this host runs: what its machine is, its state as the
      sidebar shows it (running, paused, waking or unreachable, off the phase
      with the provider's word for the machine and the daemon reach beside it)
      where the kind has one, and how many projects it holds
  wsp projects <workspace>
      the projects on the workspace, oldest import first: name, folder on the
      machine, size and when it landed; the name is what thread new --project
      takes
  wsp threads [--in <workspace>]
      every thread as the sidebar lists it: agent, state, who opened it, the
      folder it works in
  wsp threads wait <thread>... [--timeout <s>]
      blocks until one of the threads leaves running and prints its finished
      line, the one a notify sends; --timeout gives up after so many seconds and
      says so on stderr
  wsp recipe scan [--project <folder>]
      read this computer and print every option, writing nothing: the agents,
      the tools with why and size, what else a package manager here has that the
      image could take, the commands your agents ran, and the sign-ins, each
      with what to do about it and one line of why; --project weighs the
      histories by a folder and --json prints it as one object
  wsp recipe [--tick used|installed|default] [--set <id>=on|off]
    [--signin <id>=copy|machine|key|skip] [--add <id>=<command>]
    [--add-check <id>=<command>] [--project <folder>] [--out <path>]
      write the recipe and print it as a table: every catalog agent and tool
      with its tick, why it has it and what it costs on the machine, then the
      commands your agents ran that no catalog row carries. --tick
      used|installed|default names the rule that decides every tick (used, the
      default, ticks what your agents actually ran here); --set <id>=on|off
      flips a row by its catalog id, or a package this Mac's own package
      managers have by the id wsp recipe scan gives it, which the build installs
      by that package's own road; --signin <id>=copy|machine|key|skip answers a
      sign-in by catalog id, key bringing the key files beside a login and
      nothing else of it; --add <id>=<command> carries a tool neither the
      catalog nor this Mac has, installed by that command on the machine, with
      --add-check <id>=<command> saying it is there; --project reads a folder's
      own manifests for what it takes to build and weighs the histories by it,
      --out says where the file goes and --json prints the table as one object.
      Naming --tick or --project decides every tick again; without either, what
      the file says stands and the flags flip rows on top of it. A sign-in
      answer stands either way: no rule decides one. All of them repeat. Review
      it, then wsp init --recipe
  wsp new <name> [--from <project golden>] [--size <cpu>x<memGb>] | wsp new
    --local [name] | wsp new --ssh <user@host> [name] [--ssh-port <port>]
    [--ssh-key <path>]
      a workspace from the golden's head or, with --from, a project golden;
      --local is this computer, --ssh a machine of your own
  wsp rename <workspace> "<name>"
      names the workspace on this computer; the name is unique here, so one
      another workspace holds is refused
  wsp snapshot <workspace>
      a project golden of the workspace: its golden plus the project as it is
      now, ready to fork
  wsp fork <workspace> [--name <n>] [--size <cpu>x<memGb>]
    [--send "<task>" [thread new's flags]]
      a new machine from the source's golden version, not a copy of its live
      disk; --size as new's
  wsp pause <workspace>
      naps the workspace's machine
  wsp wake <workspace>
      wakes the workspace's machine and prints its state once the runtime has
      answered
  wsp rebuild <workspace>
      replaces a gone workspace's machine from its image and prints the state of
      the new one
  wsp forget <workspace> [--yes]
      drops a gone workspace and its threads from this computer; refused while
      its machine exists
  wsp delete <workspace> [--yes]
      deletes the machine at the provider, then drops the record and threads
      from this computer
  wsp thread new --in <workspace>
    [--agent, --model, --effort, --access, --project <name>, --cwd, --notify, -…
    "<task>"
      opens a thread with the agent, model, effort and access the app offers, in
      the project named or the one the app's pick would take; follows its first
      turn, or with --detach prints the id and returns
  wsp thread read <thread> [--last]
      the thread's messages as the app lists them, oldest first: who each one
      is, when the runtime recorded it and the text, with every tool call folded
      to the one line the app's row reads; --last prints the final reply alone,
      the whole message its finished line carries. A tool's output and the
      agent's reasoning are no rows of it
  wsp thread rename <thread> "<title>"
      names the thread inside the agent's own store, so the agent shows the same
      name
  wsp send <thread> [--model, --effort, --access <value>] [--image <path>]
    [--detach] "<message>"
      a message to the thread, on a named model, effort or access, with images;
      a running turn keeps its own; --detach prints the id and returns
  wsp stop <thread>
      stops the thread's running turn, as the app's stop does; the machine stays
      up
  wsp exec <workspace> [--cwd <dir>] -- <command...>
      runs the command on the machine, each word as given, in --cwd or the
      folder a thread would start in
  wsp folders [<folder>] [--hidden]
      the folders inside one folder on this computer, for naming one to import;
      the home folder and every imported project are the roots and nothing
      outside them is listed
  wsp import <folder> --to <workspace> [--yes] [--keep, --cut <path>]
    [--agents <ids>] [--replace]
      lands a folder on the machine at its path here; the plan first, then --yes
      or one question
  wsp terminal config [--scheme light|dark]
      the Ghostty config on this computer as the app's terminal pane applies it,
      read from ~/.config/ghostty and Application Support with its includes and
      theme resolved: the font and its fallbacks, the size, the colors, the
      cursor, the padding, the background opacity, and the blur, which is read
      but not applied; --scheme picks the side of a light:...,dark:... theme
  wsp export <workspace> <folder> [--from <path on the machine>] [--replace]
    [--agents <ids>]
      brings a project folder and the agent sessions keyed to it home from the
      machine

  wsp send streams the reply to stderr as it arrives and prints the last message
  on stdout when the reply is complete.
  A turn ends when the agent process exits, not at its reply, and the thread
  reads running until then.
  wsp exec streams the command's output and exits with its code. thread new,
  send and exec wake a paused workspace first, with one line on stderr saying so.

exit codes; every failure is one line on stderr, the failure object with --json:
  0 ok        it did what its line says; with --json stdout holds the answer
  1 provider  the host, the runtime, Solari or the machine refused or failed
  2 auth      no key, no sign-in, or the host refused the token
  3 usage     the line was refused before anything ran: a missing argument, an
              unknown flag or a value nothing takes

options:
  --port N           app port (default 4400); the runtime websocket
                     port follows 10 above it
  --ws-port N        runtime websocket port on its own (default
                     4410); --port alone moves both
  --state PATH       state file (default ~/.wsp/state.json, or ./.wsp/state.json
                     when the current directory has a .env)
  --yes              init: take every default and ask nothing (required off a
                     terminal); a login with a browser or device sign-in, or one
                     held in the Keychain, defaults to sign in on the machine
                     unless a saved recipe answered copy, so macOS has nothing
                     to ask either and the sign-ins wait for the app's terminal.
                     doctor: also delete the snapshots and templates this host
                     left behind, which is not reversible
  --recipe PATH      init: tick the agents and tools from this recipe (wsp recipe
                     writes it; init writes <state dir>/recipe.json too) and go
                     straight to the sign-ins; this machine is still read for
                     what travels
  --project PATH     init: the project folder you are bringing first. Its own
                     files (package.json, the lockfiles, pyproject, go.mod,
                     Cargo.toml, the compose files, .tool-versions, the CI
                     workflows) say what it needs, and those rows are ticked
                     first, each saying which file asked. Without it, init asks
                     for one before the first screen
  --first-workspace NAME
                     init: fork the first workspace under this name once the
                     golden seals, without asking (default first). A run with
                     nobody at a terminal forks nothing unless this or --import
                     asks for it
  --import FOLDER    init: import this folder's project onto that first
                     workspace, with the consent the app's import starts from:
                     caches left behind, secret-shaped files cut unless a
                     rewrite drops their credentials, and the sessions your
                     agents have for the folder travelling with it
  --no-local         init: leave this computer alone. The workspace step ticks
                     it by default, since a workspace here forks nothing and
                     bills nothing; this is the one way to end an init without
                     one. Refused on a run with no provider key, where it is
                     the only workspace there is
  --local            doctor: prove a thread on this computer and its reply
                     instead of the reach loop, which needs no provider key,
                     forks nothing and bills nothing
  --non-interactive  init: ask nothing, but still run the sign-ins on the
                     machine: each one prints the page to open on this computer,
                     the code when the flow shows one, and the command that
                     opens it, then waits for you (this is what a run off a
                     terminal does anyway). The run ends with the golden
                     recorded and never serves the app; wsp up does that
  --service          up: install the host as a launchd agent on a Mac, or a
                     systemd user unit on Linux, and wait for it to answer on
                     its port. The keys are not written into it: the service
                     reads the same .env a terminal run reads, so they have to
                     be in a file rather than exported in the shell that
                     installs it. It does pin the node and the wsp it was run
                     from by path, so a node that goes away later (an nvm
                     switch, a brew upgrade) stops the service at the next
                     login, with its log the only place that says why
  --json             init: print each build stage frame (with the install step
                     it belongs to, the command that step runs and its seconds
                     so far), each sign-in hand-off and its outcome as one JSON
                     object on stdout, then one last object naming the golden,
                     the recipe, the wsp up to run next and, unless
                     --first-workspace or --import asked for one, the wsp new
                     that forks a workspace; everything else on stderr. Implies
                     --non-interactive, and is refused beside --yes, which skips
                     the sign-ins

keys are read from the environment, then ./.env, then ~/.wsp/.env (WSP_HOME
overrides ~/.wsp). The prompt runs only when no Solari key is found; it asks
for the optional Anthropic key at the same time and can save both to that file.
With a Solari key present, a missing Anthropic key is only noted at start.
Without one, init and up take the local road: this computer is the workspace,
nothing is forked and nothing is sealed.

wsp recipe

usage: wsp recipe [--tick used|installed|default] [--set <id>=on|off] [--signin <id>=copy|machine|key|skip] [--add <id>=<command>] [--add-check <id>=<command>] [--project <folder>] [--out <path>]
  write the recipe and print it as a table: every catalog agent and tool with
  its tick, why it has it and what it costs on the machine, then the commands
  your agents ran that no catalog row carries. --tick used|installed|default
  names the rule that decides every tick (used, the default, ticks what your
  agents actually ran here); --set <id>=on|off flips a row by its catalog id, or
  a package this Mac's own package managers have by the id wsp recipe scan gives
  it, which the build installs by that package's own road; --signin
  <id>=copy|machine|key|skip answers a sign-in by catalog id, key bringing the
  key files beside a login and nothing else of it; --add <id>=<command> carries
  a tool neither the catalog nor this Mac has, installed by that command on the
  machine, with --add-check <id>=<command> saying it is there; --project reads a
  folder's own manifests for what it takes to build and weighs the histories by
  it, --out says where the file goes and --json prints the table as one object.
  Naming --tick or --project decides every tick again; without either, what the
  file says stands and the flags flip rows on top of it. A sign-in answer stands
  either way: no rule decides one. All of them repeat. Review it, then wsp init
  --recipe

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp workspaces

usage: wsp workspaces
  every workspace this host runs: what its machine is, its state as the sidebar
  shows it (running, paused, waking or unreachable, off the phase with the
  provider's word for the machine and the daemon reach beside it) where the kind
  has one, and how many projects it holds

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp threads

usage: wsp threads [--in <workspace>]
  every thread as the sidebar lists it: agent, state, who opened it, the folder
  it works in

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp new

usage: wsp new <name> [--from <project golden>] [--size <cpu>x<memGb>] | wsp new --local [name] | wsp new --ssh <user@host> [name] [--ssh-port <port>] [--ssh-key <path>]
  a workspace from the golden's head or, with --from, a project golden; --local
  is this computer, --ssh a machine of your own

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp fork

usage: wsp fork <workspace> [--name <n>] [--size <cpu>x<memGb>] [--send "<task>" [thread new's flags]]
  a new machine from the source's golden version, not a copy of its live disk;
  --size as new's

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp snapshot

usage: wsp snapshot <workspace>
  a project golden of the workspace: its golden plus the project as it is now,
  ready to fork

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp pause

usage: wsp pause <workspace>
  naps the workspace's machine

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp wake

usage: wsp wake <workspace>
  wakes the workspace's machine and prints its state once the runtime has
  answered

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp rename

usage: wsp rename <workspace> "<name>"
  names the workspace on this computer; the name is unique here, so one another
  workspace holds is refused

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp forget

usage: wsp forget <workspace> [--yes]
  drops a gone workspace and its threads from this computer; refused while its
  machine exists

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp delete

usage: wsp delete <workspace> [--yes]
  deletes the machine at the provider, then drops the record and threads from
  this computer

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp thread

wsp - your setup, on cloud machines, for coding agents

usage:
  wsp up             start the app and the runtime over the golden you sealed
                     (plain wsp does the same). It serves until you stop it, so
                     closing that terminal takes the app down with it; --service
                     hands the same line to this computer's own service manager
                     instead, which starts it now and again at every login
  wsp down           stop the service and take it away, so nothing brings the
                     host back at the next login
  wsp status         whether a host is serving this state file, on which ports,
                     and what keeps it there, with a non-zero exit code when
                     none does
  wsp init           set up your first golden image in six screens: Agents,
                     Tools, Also on this Mac, Sign-ins, wsp for your agents
                     on this Mac, and Build, then the browser. With no provider
                     key it seals nothing and makes this computer your
                     workspace instead
  wsp doctor         run the reach loop end to end against one live machine
                     (--yes also deletes the snapshots this host left behind);
                     --local proves the other half instead, a thread on this
                     computer and its reply, with no machine and no key
  wsp mcp            serve the verbs as MCP tools over stdio to an agent on this
                     computer; wsp mcp install --agent <id> puts the server in
                     that agent's own MCP config (claude, codex, gemini, opencode),
                     the wsp skill in its skills folder, and wsp's own section
                     in this folder's AGENTS.md, which --remove takes back out.
                     --agent repeats and off a terminal every agent on your PATH
                     takes it; --json prints one line holding what each agent
                     took and a failures array for the ones that took nothing;
                     all three are read by mcp install alone
  wsp --version      print the version

verbs; every one takes --json for its raw values. The recipe verbs read this
computer and write beside the state file; the rest speak to the host wsp up
started:
  wsp workspaces
      every workspace this host runs: what its machine is, its state as the
      sidebar shows it (running, paused, waking or unreachable, off the phase
      with the provider's word for the machine and the daemon reach beside it)
      where the kind has one, and how many projects it holds
  wsp projects <workspace>
      the projects on the workspace, oldest import first: name, folder on the
      machine, size and when it landed; the name is what thread new --project
      takes
  wsp threads [--in <workspace>]
      every thread as the sidebar lists it: agent, state, who opened it, the
      folder it works in
  wsp threads wait <thread>... [--timeout <s>]
      blocks until one of the threads leaves running and prints its finished
      line, the one a notify sends; --timeout gives up after so many seconds and
      says so on stderr
  wsp recipe scan [--project <folder>]
      read this computer and print every option, writing nothing: the agents,
      the tools with why and size, what else a package manager here has that the
      image could take, the commands your agents ran, and the sign-ins, each
      with what to do about it and one line of why; --project weighs the
      histories by a folder and --json prints it as one object
  wsp recipe [--tick used|installed|default] [--set <id>=on|off]
    [--signin <id>=copy|machine|key|skip] [--add <id>=<command>]
    [--add-check <id>=<command>] [--project <folder>] [--out <path>]
      write the recipe and print it as a table: every catalog agent and tool
      with its tick, why it has it and what it costs on the machine, then the
      commands your agents ran that no catalog row carries. --tick
      used|installed|default names the rule that decides every tick (used, the
      default, ticks what your agents actually ran here); --set <id>=on|off
      flips a row by its catalog id, or a package this Mac's own package
      managers have by the id wsp recipe scan gives it, which the build installs
      by that package's own road; --signin <id>=copy|machine|key|skip answers a
      sign-in by catalog id, key bringing the key files beside a login and
      nothing else of it; --add <id>=<command> carries a tool neither the
      catalog nor this Mac has, installed by that command on the machine, with
      --add-check <id>=<command> saying it is there; --project reads a folder's
      own manifests for what it takes to build and weighs the histories by it,
      --out says where the file goes and --json prints the table as one object.
      Naming --tick or --project decides every tick again; without either, what
      the file says stands and the flags flip rows on top of it. A sign-in
      answer stands either way: no rule decides one. All of them repeat. Review
      it, then wsp init --recipe
  wsp new <name> [--from <project golden>] [--size <cpu>x<memGb>] | wsp new
    --local [name] | wsp new --ssh <user@host> [name] [--ssh-port <port>]
    [--ssh-key <path>]
      a workspace from the golden's head or, with --from, a project golden;
      --local is this computer, --ssh a machine of your own
  wsp rename <workspace> "<name>"
      names the workspace on this computer; the name is unique here, so one
      another workspace holds is refused
  wsp snapshot <workspace>
      a project golden of the workspace: its golden plus the project as it is
      now, ready to fork
  wsp fork <workspace> [--name <n>] [--size <cpu>x<memGb>]
    [--send "<task>" [thread new's flags]]
      a new machine from the source's golden version, not a copy of its live
      disk; --size as new's
  wsp pause <workspace>
      naps the workspace's machine
  wsp wake <workspace>
      wakes the workspace's machine and prints its state once the runtime has
      answered
  wsp rebuild <workspace>
      replaces a gone workspace's machine from its image and prints the state of
      the new one
  wsp forget <workspace> [--yes]
      drops a gone workspace and its threads from this computer; refused while
      its machine exists
  wsp delete <workspace> [--yes]
      deletes the machine at the provider, then drops the record and threads
      from this computer
  wsp thread new --in <workspace>
    [--agent, --model, --effort, --access, --project <name>, --cwd, --notify, -…
    "<task>"
      opens a thread with the agent, model, effort and access the app offers, in
      the project named or the one the app's pick would take; follows its first
      turn, or with --detach prints the id and returns
  wsp thread read <thread> [--last]
      the thread's messages as the app lists them, oldest first: who each one
      is, when the runtime recorded it and the text, with every tool call folded
      to the one line the app's row reads; --last prints the final reply alone,
      the whole message its finished line carries. A tool's output and the
      agent's reasoning are no rows of it
  wsp thread rename <thread> "<title>"
      names the thread inside the agent's own store, so the agent shows the same
      name
  wsp send <thread> [--model, --effort, --access <value>] [--image <path>]
    [--detach] "<message>"
      a message to the thread, on a named model, effort or access, with images;
      a running turn keeps its own; --detach prints the id and returns
  wsp stop <thread>
      stops the thread's running turn, as the app's stop does; the machine stays
      up
  wsp exec <workspace> [--cwd <dir>] -- <command...>
      runs the command on the machine, each word as given, in --cwd or the
      folder a thread would start in
  wsp folders [<folder>] [--hidden]
      the folders inside one folder on this computer, for naming one to import;
      the home folder and every imported project are the roots and nothing
      outside them is listed
  wsp import <folder> --to <workspace> [--yes] [--keep, --cut <path>]
    [--agents <ids>] [--replace]
      lands a folder on the machine at its path here; the plan first, then --yes
      or one question
  wsp terminal config [--scheme light|dark]
      the Ghostty config on this computer as the app's terminal pane applies it,
      read from ~/.config/ghostty and Application Support with its includes and
      theme resolved: the font and its fallbacks, the size, the colors, the
      cursor, the padding, the background opacity, and the blur, which is read
      but not applied; --scheme picks the side of a light:...,dark:... theme
  wsp export <workspace> <folder> [--from <path on the machine>] [--replace]
    [--agents <ids>]
      brings a project folder and the agent sessions keyed to it home from the
      machine

  wsp send streams the reply to stderr as it arrives and prints the last message
  on stdout when the reply is complete.
  A turn ends when the agent process exits, not at its reply, and the thread
  reads running until then.
  wsp exec streams the command's output and exits with its code. thread new,
  send and exec wake a paused workspace first, with one line on stderr saying so.

exit codes; every failure is one line on stderr, the failure object with --json:
  0 ok        it did what its line says; with --json stdout holds the answer
  1 provider  the host, the runtime, Solari or the machine refused or failed
  2 auth      no key, no sign-in, or the host refused the token
  3 usage     the line was refused before anything ran: a missing argument, an
              unknown flag or a value nothing takes

options:
  --port N           app port (default 4400); the runtime websocket
                     port follows 10 above it
  --ws-port N        runtime websocket port on its own (default
                     4410); --port alone moves both
  --state PATH       state file (default ~/.wsp/state.json, or ./.wsp/state.json
                     when the current directory has a .env)
  --yes              init: take every default and ask nothing (required off a
                     terminal); a login with a browser or device sign-in, or one
                     held in the Keychain, defaults to sign in on the machine
                     unless a saved recipe answered copy, so macOS has nothing
                     to ask either and the sign-ins wait for the app's terminal.
                     doctor: also delete the snapshots and templates this host
                     left behind, which is not reversible
  --recipe PATH      init: tick the agents and tools from this recipe (wsp recipe
                     writes it; init writes <state dir>/recipe.json too) and go
                     straight to the sign-ins; this machine is still read for
                     what travels
  --project PATH     init: the project folder you are bringing first. Its own
                     files (package.json, the lockfiles, pyproject, go.mod,
                     Cargo.toml, the compose files, .tool-versions, the CI
                     workflows) say what it needs, and those rows are ticked
                     first, each saying which file asked. Without it, init asks
                     for one before the first screen
  --first-workspace NAME
                     init: fork the first workspace under this name once the
                     golden seals, without asking (default first). A run with
                     nobody at a terminal forks nothing unless this or --import
                     asks for it
  --import FOLDER    init: import this folder's project onto that first
                     workspace, with the consent the app's import starts from:
                     caches left behind, secret-shaped files cut unless a
                     rewrite drops their credentials, and the sessions your
                     agents have for the folder travelling with it
  --no-local         init: leave this computer alone. The workspace step ticks
                     it by default, since a workspace here forks nothing and
                     bills nothing; this is the one way to end an init without
                     one. Refused on a run with no provider key, where it is
                     the only workspace there is
  --local            doctor: prove a thread on this computer and its reply
                     instead of the reach loop, which needs no provider key,
                     forks nothing and bills nothing
  --non-interactive  init: ask nothing, but still run the sign-ins on the
                     machine: each one prints the page to open on this computer,
                     the code when the flow shows one, and the command that
                     opens it, then waits for you (this is what a run off a
                     terminal does anyway). The run ends with the golden
                     recorded and never serves the app; wsp up does that
  --service          up: install the host as a launchd agent on a Mac, or a
                     systemd user unit on Linux, and wait for it to answer on
                     its port. The keys are not written into it: the service
                     reads the same .env a terminal run reads, so they have to
                     be in a file rather than exported in the shell that
                     installs it. It does pin the node and the wsp it was run
                     from by path, so a node that goes away later (an nvm
                     switch, a brew upgrade) stops the service at the next
                     login, with its log the only place that says why
  --json             init: print each build stage frame (with the install step
                     it belongs to, the command that step runs and its seconds
                     so far), each sign-in hand-off and its outcome as one JSON
                     object on stdout, then one last object naming the golden,
                     the recipe, the wsp up to run next and, unless
                     --first-workspace or --import asked for one, the wsp new
                     that forks a workspace; everything else on stderr. Implies
                     --non-interactive, and is refused beside --yes, which skips
                     the sign-ins

keys are read from the environment, then ./.env, then ~/.wsp/.env (WSP_HOME
overrides ~/.wsp). The prompt runs only when no Solari key is found; it asks
for the optional Anthropic key at the same time and can save both to that file.
With a Solari key present, a missing Anthropic key is only noted at start.
Without one, init and up take the local road: this computer is the workspace,
nothing is forked and nothing is sealed.

wsp send

usage: wsp send <thread> [--model, --effort, --access <value>] [--image <path>] [--detach] "<message>"
  a message to the thread, on a named model, effort or access, with images; a
  running turn keeps its own; --detach prints the id and returns

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp stop

usage: wsp stop <thread>
  stops the thread's running turn, as the app's stop does; the machine stays up

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp exec

usage: wsp exec <workspace> [--cwd <dir>] -- <command...>
  runs the command on the machine, each word as given, in --cwd or the folder a
  thread would start in

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp folders

usage: wsp folders [<folder>] [--hidden]
  the folders inside one folder on this computer, for naming one to import; the
  home folder and every imported project are the roots and nothing outside them
  is listed

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp import

usage: wsp import <folder> --to <workspace> [--yes] [--keep, --cut <path>] [--agents <ids>] [--replace]
  lands a folder on the machine at its path here; the plan first, then --yes or
  one question

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp export

usage: wsp export <workspace> <folder> [--from <path on the machine>] [--replace] [--agents <ids>]
  brings a project folder and the agent sessions keyed to it home from the
  machine

  --json         print the raw protocol values, one JSON line each
  --state PATH   the state file the host serves

wsp terminal

wsp - your setup, on cloud machines, for coding agents

usage:
  wsp up             start the app and the runtime over the golden you sealed
                     (plain wsp does the same). It serves until you stop it, so
                     closing that terminal takes the app down with it; --service
                     hands the same line to this computer's own service manager
                     instead, which starts it now and again at every login
  wsp down           stop the service and take it away, so nothing brings the
                     host back at the next login
  wsp status         whether a host is serving this state file, on which ports,
                     and what keeps it there, with a non-zero exit code when
                     none does
  wsp init           set up your first golden image in six screens: Agents,
                     Tools, Also on this Mac, Sign-ins, wsp for your agents
                     on this Mac, and Build, then the browser. With no provider
                     key it seals nothing and makes this computer your
                     workspace instead
  wsp doctor         run the reach loop end to end against one live machine
                     (--yes also deletes the snapshots this host left behind);
                     --local proves the other half instead, a thread on this
                     computer and its reply, with no machine and no key
  wsp mcp            serve the verbs as MCP tools over stdio to an agent on this
                     computer; wsp mcp install --agent <id> puts the server in
                     that agent's own MCP config (claude, codex, gemini, opencode),
                     the wsp skill in its skills folder, and wsp's own section
                     in this folder's AGENTS.md, which --remove takes back out.
                     --agent repeats and off a terminal every agent on your PATH
                     takes it; --json prints one line holding what each agent
                     took and a failures array for the ones that took nothing;
                     all three are read by mcp install alone
  wsp --version      print the version

verbs; every one takes --json for its raw values. The recipe verbs read this
computer and write beside the state file; the rest speak to the host wsp up
started:
  wsp workspaces
      every workspace this host runs: what its machine is, its state as the
      sidebar shows it (running, paused, waking or unreachable, off the phase
      with the provider's word for the machine and the daemon reach beside it)
      where the kind has one, and how many projects it holds
  wsp projects <workspace>
      the projects on the workspace, oldest import first: name, folder on the
      machine, size and when it landed; the name is what thread new --project
      takes
  wsp threads [--in <workspace>]
      every thread as the sidebar lists it: agent, state, who opened it, the
      folder it works in
  wsp threads wait <thread>... [--timeout <s>]
      blocks until one of the threads leaves running and prints its finished
      line, the one a notify sends; --timeout gives up after so many seconds and
      says so on stderr
  wsp recipe scan [--project <folder>]
      read this computer and print every option, writing nothing: the agents,
      the tools with why and size, what else a package manager here has that the
      image could take, the commands your agents ran, and the sign-ins, each
      with what to do about it and one line of why; --project weighs the
      histories by a folder and --json prints it as one object
  wsp recipe [--tick used|installed|default] [--set <id>=on|off]
    [--signin <id>=copy|machine|key|skip] [--add <id>=<command>]
    [--add-check <id>=<command>] [--project <folder>] [--out <path>]
      write the recipe and print it as a table: every catalog agent and tool
      with its tick, why it has it and what it costs on the machine, then the
      commands your agents ran that no catalog row carries. --tick
      used|installed|default names the rule that decides every tick (used, the
      default, ticks what your agents actually ran here); --set <id>=on|off
      flips a row by its catalog id, or a package this Mac's own package
      managers have by the id wsp recipe scan gives it, which the build installs
      by that package's own road; --signin <id>=copy|machine|key|skip answers a
      sign-in by catalog id, key bringing the key files beside a login and
      nothing else of it; --add <id>=<command> carries a tool neither the
      catalog nor this Mac has, installed by that command on the machine, with
      --add-check <id>=<command> saying it is there; --project reads a folder's
      own manifests for what it takes to build and weighs the histories by it,
      --out says where the file goes and --json prints the table as one object.
      Naming --tick or --project decides every tick again; without either, what
      the file says stands and the flags flip rows on top of it. A sign-in
      answer stands either way: no rule decides one. All of them repeat. Review
      it, then wsp init --recipe
  wsp new <name> [--from <project golden>] [--size <cpu>x<memGb>] | wsp new
    --local [name] | wsp new --ssh <user@host> [name] [--ssh-port <port>]
    [--ssh-key <path>]
      a workspace from the golden's head or, with --from, a project golden;
      --local is this computer, --ssh a machine of your own
  wsp rename <workspace> "<name>"
      names the workspace on this computer; the name is unique here, so one
      another workspace holds is refused
  wsp snapshot <workspace>
      a project golden of the workspace: its golden plus the project as it is
      now, ready to fork
  wsp fork <workspace> [--name <n>] [--size <cpu>x<memGb>]
    [--send "<task>" [thread new's flags]]
      a new machine from the source's golden version, not a copy of its live
      disk; --size as new's
  wsp pause <workspace>
      naps the workspace's machine
  wsp wake <workspace>
      wakes the workspace's machine and prints its state once the runtime has
      answered
  wsp rebuild <workspace>
      replaces a gone workspace's machine from its image and prints the state of
      the new one
  wsp forget <workspace> [--yes]
      drops a gone workspace and its threads from this computer; refused while
      its machine exists
  wsp delete <workspace> [--yes]
      deletes the machine at the provider, then drops the record and threads
      from this computer
  wsp thread new --in <workspace>
    [--agent, --model, --effort, --access, --project <name>, --cwd, --notify, -…
    "<task>"
      opens a thread with the agent, model, effort and access the app offers, in
      the project named or the one the app's pick would take; follows its first
      turn, or with --detach prints the id and returns
  wsp thread read <thread> [--last]
      the thread's messages as the app lists them, oldest first: who each one
      is, when the runtime recorded it and the text, with every tool call folded
      to the one line the app's row reads; --last prints the final reply alone,
      the whole message its finished line carries. A tool's output and the
      agent's reasoning are no rows of it
  wsp thread rename <thread> "<title>"
      names the thread inside the agent's own store, so the agent shows the same
      name
  wsp send <thread> [--model, --effort, --access <value>] [--image <path>]
    [--detach] "<message>"
      a message to the thread, on a named model, effort or access, with images;
      a running turn keeps its own; --detach prints the id and returns
  wsp stop <thread>
      stops the thread's running turn, as the app's stop does; the machine stays
      up
  wsp exec <workspace> [--cwd <dir>] -- <command...>
      runs the command on the machine, each word as given, in --cwd or the
      folder a thread would start in
  wsp folders [<folder>] [--hidden]
      the folders inside one folder on this computer, for naming one to import;
      the home folder and every imported project are the roots and nothing
      outside them is listed
  wsp import <folder> --to <workspace> [--yes] [--keep, --cut <path>]
    [--agents <ids>] [--replace]
      lands a folder on the machine at its path here; the plan first, then --yes
      or one question
  wsp terminal config [--scheme light|dark]
      the Ghostty config on this computer as the app's terminal pane applies it,
      read from ~/.config/ghostty and Application Support with its includes and
      theme resolved: the font and its fallbacks, the size, the colors, the
      cursor, the padding, the background opacity, and the blur, which is read
      but not applied; --scheme picks the side of a light:...,dark:... theme
  wsp export <workspace> <folder> [--from <path on the machine>] [--replace]
    [--agents <ids>]
      brings a project folder and the agent sessions keyed to it home from the
      machine

  wsp send streams the reply to stderr as it arrives and prints the last message
  on stdout when the reply is complete.
  A turn ends when the agent process exits, not at its reply, and the thread
  reads running until then.
  wsp exec streams the command's output and exits with its code. thread new,
  send and exec wake a paused workspace first, with one line on stderr saying so.

exit codes; every failure is one line on stderr, the failure object with --json:
  0 ok        it did what its line says; with --json stdout holds the answer
  1 provider  the host, the runtime, Solari or the machine refused or failed
  2 auth      no key, no sign-in, or the host refused the token
  3 usage     the line was refused before anything ran: a missing argument, an
              unknown flag or a value nothing takes

options:
  --port N           app port (default 4400); the runtime websocket
                     port follows 10 above it
  --ws-port N        runtime websocket port on its own (default
                     4410); --port alone moves both
  --state PATH       state file (default ~/.wsp/state.json, or ./.wsp/state.json
                     when the current directory has a .env)
  --yes              init: take every default and ask nothing (required off a
                     terminal); a login with a browser or device sign-in, or one
                     held in the Keychain, defaults to sign in on the machine
                     unless a saved recipe answered copy, so macOS has nothing
                     to ask either and the sign-ins wait for the app's terminal.
                     doctor: also delete the snapshots and templates this host
                     left behind, which is not reversible
  --recipe PATH      init: tick the agents and tools from this recipe (wsp recipe
                     writes it; init writes <state dir>/recipe.json too) and go
                     straight to the sign-ins; this machine is still read for
                     what travels
  --project PATH     init: the project folder you are bringing first. Its own
                     files (package.json, the lockfiles, pyproject, go.mod,
                     Cargo.toml, the compose files, .tool-versions, the CI
                     workflows) say what it needs, and those rows are ticked
                     first, each saying which file asked. Without it, init asks
                     for one before the first screen
  --first-workspace NAME
                     init: fork the first workspace under this name once the
                     golden seals, without asking (default first). A run with
                     nobody at a terminal forks nothing unless this or --import
                     asks for it
  --import FOLDER    init: import this folder's project onto that first
                     workspace, with the consent the app's import starts from:
                     caches left behind, secret-shaped files cut unless a
                     rewrite drops their credentials, and the sessions your
                     agents have for the folder travelling with it
  --no-local         init: leave this computer alone. The workspace step ticks
                     it by default, since a workspace here forks nothing and
                     bills nothing; this is the one way to end an init without
                     one. Refused on a run with no provider key, where it is
                     the only workspace there is
  --local            doctor: prove a thread on this computer and its reply
                     instead of the reach loop, which needs no provider key,
                     forks nothing and bills nothing
  --non-interactive  init: ask nothing, but still run the sign-ins on the
                     machine: each one prints the page to open on this computer,
                     the code when the flow shows one, and the command that
                     opens it, then waits for you (this is what a run off a
                     terminal does anyway). The run ends with the golden
                     recorded and never serves the app; wsp up does that
  --service          up: install the host as a launchd agent on a Mac, or a
                     systemd user unit on Linux, and wait for it to answer on
                     its port. The keys are not written into it: the service
                     reads the same .env a terminal run reads, so they have to
                     be in a file rather than exported in the shell that
                     installs it. It does pin the node and the wsp it was run
                     from by path, so a node that goes away later (an nvm
                     switch, a brew upgrade) stops the service at the next
                     login, with its log the only place that says why
  --json             init: print each build stage frame (with the install step
                     it belongs to, the command that step runs and its seconds
                     so far), each sign-in hand-off and its outcome as one JSON
                     object on stdout, then one last object naming the golden,
                     the recipe, the wsp up to run next and, unless
                     --first-workspace or --import asked for one, the wsp new
                     that forks a workspace; everything else on stderr. Implies
                     --non-interactive, and is refused beside --yes, which skips
                     the sign-ins

keys are read from the environment, then ./.env, then ~/.wsp/.env (WSP_HOME
overrides ~/.wsp). The prompt runs only when no Solari key is found; it asks
for the optional Anthropic key at the same time and can save both to that file.
With a Solari key present, a missing Anthropic key is only noted at start.
Without one, init and up take the local road: this computer is the workspace,
nothing is forked and nothing is sealed.

wsp mcp

usage: wsp mcp
       wsp mcp install --agent <id> [--agent <id>] [--json] [--remove]   (claude, codex, gemini, opencode)