Files
max-sixty__worktrunk/docs/content/worktrunk.md
Maximilian Roos 60661a0d7e docs(signing): carry the SignPath attribution on the install section (#3709)
SignPath Foundation's OSS program requires the attribution notice, and a
route to the code signing policy, on a project's home page and
download/release pages. Worktrunk had both only on the policy page
itself — nothing on the README or the docs landing page. This puts the
notice in the install section's Windows block, beside the artifacts it
actually describes:

> Free code signing provided by [SignPath.io](https://signpath.io/),
certificate by [SignPath Foundation](https://signpath.org/) —
[policy](https://worktrunk.dev/code-signing/).

The edit is one line in `docs/content/worktrunk.md`; the README's
Install→Further reading block is generated from it, so it propagates
there and to both skill mirrors.

The policy page leaves the docs navigation in the same change, so this
is the single place it's linked from. `hide_from_nav = true` in a page's
`[extra]` skips it in all three loops over `docs_section.pages`: the
desktop TOC (`macros.html`), the mobile menu (`base.html`), and the
prev/next flow nav (`page.html`). The page stays published and reachable
at `/code-signing/` — unlisted, not removed.

In the nav loops the skip wraps the whole per-page body, so a hidden
page can't emit a stray group heading. In the prev/next loop it guards
only the *candidate* assignments — the current-page test stays
unguarded, because viewing a hidden page directly must still flip
`found_current` or its own neighbours compute against the wrong page.
Verified both directions: FAQ ends at `← Tips & Patterns` with no
forward link, and the policy page keeps `← FAQ` back out into the docs.

<details><summary>Why this came up, and the placement tradeoff</summary>

Found while debugging why the `release-signing` signing policy shows
INVALID in the SignPath console. That turned out to be unrelated and not
fixable here — its certificate ("Release certificate 2026", subject
`CN=SignPath Foundation`, on SignPath's HSM) is in `CSR PENDING` with no
validity dates, awaiting CA issuance. The policy's own configuration is
complete and correct. Worktrunk currently signs with the test
certificate, which is VALID.

The attribution gap was the one thing found on our side. Whether it
bears on the pending review is unknown — the console exposes no
application status.

On placement: the notice sits inside the collapsed `<details>`, so it
isn't visible until a reader expands "Windows & other". That's
deliberate — the signing is Windows-specific and the notice reads better
next to it than in the page chrome — but it is the least prominent
placement that still counts as a link, and the terms ask for the notice
*on* the home and download pages. Worth knowing if placement is ever
queried during review.

</details>

> _This was written by Claude Code on behalf of max-sixty_

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 10:53:46 -07:00

11 KiB

+++ title = "Worktrunk" description = "CLI for Git worktree management, designed for parallel AI agent workflows." weight = 1

[extra] canonical = "/" +++

Worktrunk is a CLI for git worktree management, designed for running AI agents in parallel.

Worktrunk's three core commands make worktrees as easy as branches. Plus, Worktrunk has a bunch of quality-of-life features to simplify working with many parallel changes, including hooks to automate local workflows.

A quick demo:

Worktrunk demo showing wt list, wt switch, and hooks
Listing worktrees, switching, cleaning up

Context: git worktrees

AI agents like Claude Code and Codex can handle longer tasks without supervision, such that it's possible to manage 5-10+ in parallel. Git's native worktree feature give each agent its own working directory, so they don't step on each other's changes.

But the git worktree UX is clunky. Even a task as small as starting a new worktree requires typing the branch name three times: git worktree add -b feat ../repo.feat, then cd ../repo.feat.

Worktrunk makes git worktrees as easy as branches

Worktrees are addressed by branch name; paths are computed from a configurable template. Commands that take a branch also accept the path of the worktree it is checked out in.

Start with the core commands

Core commands:

Task Worktrunk Plain git
Switch worktrees {% rawcode() %}wt switch feat{% end %} {% rawcode() %}cd ../repo.feat{% end %}
Create + start Claude {% rawcode() %}wt switch -c -x claude feat{% end %} {% rawcode() %}git worktree add -b feat ../repo.feat && \ cd ../repo.feat && \ claude{% end %}
Clean up {% rawcode() %}wt remove{% end %} {% rawcode() %}cd ../repo && \ git worktree remove ../repo.feat && \ git branch -d feat{% end %}
List with status {% rawcode() %}wt list{% end %} {% rawcode() %}git worktree list{% end %} (paths only)

Expand into the more advanced commands as needed

Workflow automation:

Multiple parallel agents, same simple commands:

Worktrunk omnibus demo: multiple Claude agents in Zellij tabs with hooks, LLM commits, and merge workflow
Multiple Claude agents in parallel with interactive picker, hooks, LLM commits, and merge

Install

Homebrew (macOS & Linux):

{{ terminal(cmd="brew install worktrunk && wt config shell install") }}

Shell integration allows commands to change directories.

Cargo:

{{ terminal(cmd="cargo install worktrunk && wt config shell install") }}

Windows & other

Windows. wt defaults to Windows Terminal's command, so Winget additionally installs Worktrunk as git-wt to avoid the conflict:

{{ terminal(cmd="winget install max-sixty.worktrunk|||git-wt config shell install") }}

Alternatively, disable Windows Terminal's alias (Settings → Apps → Advanced app settings → App execution aliases → "Terminal"/"Terminal Preview") to use wt directly.

Free code signing provided by SignPath.io, certificate by SignPath Foundation — policy.

Arch Linux:

{{ terminal(cmd="sudo pacman -S worktrunk && wt config shell install") }}

Conda / Pixi (community-maintained feedstock):

{{ terminal(cmd="conda install -c conda-forge worktrunk && wt config shell install") }}

Or with Pixi: pixi global install worktrunk && wt config shell install.

Quick start

Create a worktree for a new feature:

{% terminal(cmd="wt switch --create feature-auth") %} wt switch --create feature-auth ✓ Created branch feature-auth from main and worktree @ ~/repo.feature-auth {% end %}

This creates a new branch and worktree, then switches to it. Do your work, then check all worktrees with wt list:

{% terminal(cmd="wt list") %} wt list Branch Status HEAD± main↕ main…± Remote⇅ Commit Age Message @ feature-auth + ↑ +27 -8 ↑1 +31 4bc72dc 2h Add authenticati… ^ main ^⇡ ⇡1 0e631ad 1d Initial commit

○ Showing 2 worktrees, 1 with changes, 1 ahead, 1 column hidden {% end %}

The @ marks the current worktree. + means staged changes, ↑1 means 1 commit ahead of main, ⇡ means unpushed commits.

When done, either:

PR workflow — commit, push, open a PR, merge via GitHub/GitLab, then clean up:

{{ terminal(cmd="wt step commit # commit staged changes|||gh pr create # or glab mr create|||wt remove # after PR is merged") }}

Local merge — squash, rebase onto main, fast-forward merge, clean up:

{% terminal(cmd="wt merge main") %} wt merge main ◎ Generating commit message and committing changes... (2 files, +53, no squashing needed) Add authentication module ✓ Committed changes @ a1b2c3d ◎ Merging 1 commit to main @ a1b2c3d (no rebase needed) * a1b2c3d Add authentication module auth.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib.rs | 2 ++ 2 files changed, 53 insertions(+) ✓ Merged to main (1 commit, 2 files, +53) ◎ Removing feature-auth worktree & branch in background (same commit as main, _) ○ Switched to worktree for main @ ~/repo {% end %}

For parallel agents, create multiple worktrees and launch an agent in each:

{{ terminal(cmd="wt switch -x claude -c feature-a -- 'Add user authentication'|||wt switch -x claude -c feature-b -- 'Fix the pagination bug'|||wt switch -x claude -c feature-c -- 'Write tests for the API'") }}

The -x flag runs a command after switching; arguments after -- are passed to it. Configure post-start hooks to automate setup (install deps, start dev servers).

Next steps

Further reading