Skein

CLI & Claude Code plugin

Install the skein command, create and inspect workspaces from a shell, and let Claude Code do it for you with the Skein plugin.

Skein ships a small skein command-line tool so scripts, hooks, and agents can list projects and open new workspaces without going through the UI. A Claude Code plugin wraps it, so you can ask Claude to "start a Skein workspace for ENG-42" from any session.

The CLI talks to the running desktop app — it doesn't work on its own. Every workspace it creates opens live in the app window.

Install the CLI

Open Settings → Companion CLI and click Install next to Install to PATH. Skein symlinks skein into /usr/local/bin, falling back to ~/.local/bin if that isn't writable, and a toast shows where it landed. Check it from a new terminal:

skein --version

If you fall back to ~/.local/bin, make sure that directory is on your PATH. Install refuses to overwrite a different skein binary that's already in the target directory — remove it first, then click Install again. The CLI is only bundled in release builds of Skein.

The symlink points into the app bundle, so it stays current as Skein updates itself.

Find a project

Every create command needs a project. List them with:

skein projects

Each line shows a project id and its domain/name. Add --json for [{ "id", "name", "domain" }, …]. Wherever a command takes --project, you can pass either the id or the project's name; a name that exists in more than one domain is rejected with the matching domain/name pairs, so use the id instead.

Create a workspace

skein new --project <id-or-name> --prompt "Where does this milestone stand?"

The workspace opens in the app with its terminal running claude and your prompt typed in but not sent — review it and press Enter. skein new prints the new workspace's id.

Options:

  • --issue <ref> — link an issue. Skein fetches it and derives the branch and workspace name exactly as the in-app issue picker would. Accepted refs:
    • GitHub: #123 (the project's GitHub issues repo), owner/repo#123, or a GitHub issue or PR URL
    • Linear: ENG-42 or a linear.app issue URL (the project needs a Linear team connected)
    • Airtable: an issue id like O2178 or an airtable.com record URL (the project needs an Airtable binding)
  • --issue is repeatable: skein new --project skein --issue '#1309' --issue ENG-42. The first issue is the primary and names the branch; later ones become linked issues. If one of those can't be linked, skein new prints a warning: to stderr and still creates the workspace (--json includes warnings).
  • --name <name> — the workspace's display name. Without --issue, the branch is derived from it: --name "Payment Retry Spike" gives skein/payment-retry-spike.
  • --branch <branch> — use this branch name instead of a derived one.
  • --tag <name> — tag the new workspace; repeat for more. A name that matches no tag (case-insensitively) is created as a project tag. If a tag can't be applied, skein new prints a warning: and still creates the workspace.
  • --force — recover from a collision (below).
  • --submit — send the prompt as soon as claude is ready instead of leaving it for you to review. If Skein can't tell that claude is ready within 10 seconds of the terminal opening, the prompt stays typed in but unsent. Requires --prompt.
  • --json — print { "workspace_id": … } instead of a sentence.

New branches are always cut from the project's default branch.

Recover from a collision

skein new fails when something already occupies the branch or worktree, and the error says which case you hit:

Message starts withWhat to do
"a workspace for … was archived at …"Re-run with --force to reopen it. Its setup scripts run again.
"a branch named … already exists"Re-run with --force to attach a workspace to that branch.
"workspace … is already live on this branch"Nothing — the workspace exists; its id is in the message.
"a worktree or directory Skein doesn't manage …"Move it aside, or pass --branch.
"branch … is already checked out by a worktree Skein doesn't manage …"Adopt that worktree in the app, or pass --branch.

--force never deletes a branch or a commit, and never touches a live workspace.

Work with a workspace's issues and PR

These commands take a workspace id or name. Inside a workspace's worktree you can leave it out and Skein uses the workspace containing the current directory. All of them accept --json.

skein issues [<workspace>]
skein issues add [-w <workspace>] <ref>...
skein issues rm [-w <workspace>] <ref>...
skein issues primary [-w <workspace>] <ref>
skein pr [<workspace>] [--refresh]
  • skein issues lists the primary issue (marked ★ primary) and then the linked ones. Issues that come from the PR body end in (from PR).
  • add links more issues. rm unlinks them; removing the primary leaves the workspace with none (nothing is promoted). A PR-body issue is refused with "referenced by the PR body — edit the PR to drop it". primary promotes a ref, and the old primary stays linked. These exit 1 only if every ref failed.
  • Refs can be #123, owner/repo#123, ENG-42, O2178, or an issue URL (GitHub, linear.app, airtable.com). GitHub issues must belong to the project's bound issues repo.
  • skein pr prints the branch's PR from the app's cache, for example #42 Add retries open · checks passing <url>. --refresh fetches from GitHub first. With no PR it prints No PR for branch <branch>.

skein status also shows an issues: block and a pr: line, and skein list shows +N for extra issues. If the running app is older, these commands ask you to update Skein.

Tag a workspace

skein tags [<workspace>]
skein tags add [-w <workspace>] <name>...
skein tags rm [-w <workspace>] <name>...

The workspace defaults to the one containing the current directory, and every command accepts --json. The desktop sidebar updates as soon as a command runs.

  • skein tags lists the workspace's user tags; global tags are marked (global).
  • add assigns tags by name, case-insensitively. A project tag wins over a global tag with the same name. A name that matches no tag is created as a project tag (prints created tag <name>).
  • rm removes tags from the workspace. The tag itself is kept — delete it from the Manage tags sheet.
  • System tags (Running, Linked, the project and domain name tags, …) are computed by Skein and can't be added or removed.

add and rm exit 1 only if every name failed. See Tags for how tags work in the app.

Rename a workspace

skein rename "<new name>" [-w <workspace>] [--json]

Changes the workspace's display name, like renaming it in the sidebar. The branch keeps its name. The workspace defaults to the one containing the current directory; pass -w with an id or a name that is unique across all projects to pick another. A blank name is refused. --json prints the renamed workspace.

Check on workspaces

skein list [--project <id-or-name>]
skein status <workspace-id-or-name>

skein list shows every active and pending workspace (archived ones are left out) with its status, project, branch, linked issue, and last activity. Within each project the stalest workspace comes first. skein status shows one workspace in detail: branch and base, status, origin, worktree path, linked issue, and any setup error. A name passed to status must be unique across all projects; otherwise it lists the matching ids. Both commands take --json.

Archive workspaces

skein archive <id-or-name>... [--force] [--json]

Archives one or more workspaces, like Archive… in the app: the working directory goes away, the branch stays. Each argument is a workspace id or a name that is unique across all projects. Every argument is resolved before anything is archived, so a typo or an ambiguous name fails the whole command and archives nothing. Archived workspaces can't be named: a ref to one fails with "no workspace matches".

Each workspace gets its own result line: archived, not found, failed: …, or refused: uncommitted changes (re-run with --force). already archived appears only when the same workspace is named twice, or something else archived it while the command ran. A dirty worktree is never discarded unless you pass --force, which discards uncommitted changes in every workspace named. The command exits 1 if any workspace was refused, not found, or failed, and 0 otherwise. --json prints the per-workspace results as JSON.

skein archive refuses to archive the workspace you run it from (its worktree is your current directory or one of its parents), since that would end your own shell. Run it from somewhere else.

For a guided version, run:

skein archive -i [--project <id-or-name>] [--force]

Without --project it first asks which project to clean up. It then shows that project's workspaces stalest first, lets you select several, and asks you to confirm. Any that were refused for uncommitted changes are offered again with force. It needs an interactive terminal and exits with an error otherwise. The same flow is in the app as Clean up workspaces…; see Workspaces & panes.

Add the Claude Code plugin

The plugin teaches Claude Code when and how to call skein. Install the CLI first, then run these in Claude Code:

/plugin marketplace add BuildQube/skein-releases
/plugin install skein@skein-marketplace

It adds two skills:

  • skein-workspace — for open-ended requests: "start a Skein workspace for BuildQube/Skein#123 and ask it to write a plan", "what are my Skein workspaces doing?", "what's the status of workspace X?". Claude looks up the project, checks existing workspaces, then creates one or reports what it found.
  • skein-new — a shorthand for when the target is already explicit: /skein-new ENG-42: fix the retry loop, or "new skein workspace named Payment Spike prompted with …". It skips the survey and creates the workspace straight away.

Either way, Claude only stages the prompt — it opens in the new workspace unsent, for you to review — unless you ask Claude to start it running, in which case it passes --submit.

The plugin is versioned with Skein releases. Run /plugin marketplace update skein-marketplace in Claude Code to pick up a newer version.

Troubleshooting

  • "Skein isn't running" — open the Skein app and try again. The CLI finds the app through a file the app writes on launch.
  • "CLI token rejected" — restart Skein.
  • Targeting a dev or pre-release build — pass --flavor dev or --flavor pre (or set SKEIN_FLAVOR) to talk to that build instead of the release app.

On this page