The kwt guide

How to use kwt, from registering a project to embedding it in your own tools. Each section links to the documentation for exact commands, JSON fields, and configuration.

  1. Register a project
  2. Create a worktree
  3. Configure a layout
  4. Run commands
  5. Inspect changes
  6. Import a pull request
  7. Remove and prune
  8. Sync across machines
  9. Embed kwt
  1. Register a project

    There is no init step. Run kwt inside a repository and it becomes a registered project. The dashboard opens with its primary checkout and any linked worktrees, next to the other registered projects. A directory that is not a repository becomes a directory workspace: a tmux session with no Git behavior.

    Registration is stored in registry.json under KWT_HOME, next to config.toml and pull-request records. kwt writes nothing into the repository.

    Quickstart · Install · Directory workspaces

    $ cd ~/code/widget
    $ kwt
    # widget is now a registered project; the dashboard opens
    # with main [primary] selected and every other project listed
    
    $ kwt projects
    github.com/acme/widget    ~/code/widget
    github.com/acme/gadget    ~/code/gadget
  2. Create a worktree

    Press n in the dashboard, or run kwt add -b, to create a branch, its worktree, and its tmux workspace. Worktrees go under a configured base directory with a configured naming rule, so you do not choose a path.

    Press b, or run kwt add --from, to check out a branch that already exists locally or on a remote. Those worktrees start inert. kwt runs no hooks, setup commands, or file copies and starts no workspace until you open the worktree yourself.

    Create or import a worktree · Configuration

    $ kwt add -b feature/new-ui
    # branch created, checkout at ~/worktrees/widget-feature-new-ui,
    # workspace started with the current layout
    
    $ kwt add --from origin/contrib-fix contrib-fix
    # worktree created; nothing run, nothing launched
    # review it, then open it
    $ kwt changes "$(kwt get contrib-fix)"
    $ kwt open "$(kwt get contrib-fix)"
  3. Configure a layout

    Name agent commands under [agents] and combine them into a preset under [[layouts.presets]]. Every workspace that uses the preset opens with those panes running. An empty pane string is a plain shell.

    Layouts are opt-in. Select one with --layout, the L key, or layouts.default. The reserved name none gives a single blank pane. A repository's .kwt.toml can set a local default once you have trusted the file.

    Configure a layout · Configuration

    ~/.config/kwt/config.toml
    [agents]
    codex   = "codex"
    roborev = "roborev tui"
    
    [[layouts.presets]]
    name    = "review"
    arrange = "even-horizontal"
    panes   = ["agent:codex", "agent:roborev", ""]
    
    # then:
    $ kwt add -b fix/flaky-status --layout review
    $ kwt config set layouts.default review
  4. Run commands in a worktree

    Press enter or run kwt open to attach. Agents do not need tmux: kwt exec runs a command with the worktree as its working directory, and kwt get prints the path.

    Workspaces run on kwt's own tmux server, tmux -L kwt, separate from your other sessions. A terminal client that manages its own attachment runs kwt open with --start-session --json and attaches to the endpoint kwt reports.

    Run and inspect work · kwt open

    $ kwt open fix/flaky-status
    # attaches; creates the session with the layout if needed
    
    $ kwt exec fix/flaky-status -- go test ./internal/status
    ok      go.kenn.io/kwt/internal/status  1.204s
    
    $ kwt open "$(kwt get fix/flaky-status)" --start-session --json
    { "session_name": "kwt-wt-widget-fix-flaky-status-…",
      "tmux_socket_name": "kwt", "tmux_attach_mode": "direct" }
  5. Inspect changes

    kwt status summarizes every worktree across projects: branch, dirty files, ahead, behind, and last activity. kwt changes lists the changed files in one worktree, staged and working-tree sides separately, including untracked files, renames, deletions, and conflicts.

    Both are read-only. With --json the result carries the worktree's generation. Pass --expected-generation to make kwt fail if the checkout you reviewed has been replaced. kwt list --json is the inventory for the rest of your tooling.

    Inspect current state · kwt changes · kwt list

    $ kwt changes "$(kwt get fix/flaky-status)" \
        --expected-repository github.com/acme/widget \
        --expected-generation 0123456789abcdef… --json
    {
      "worktree": { "repository": "github.com/acme/widget", "path": "…", "generation": "0123456789abcdef…" },
      "changes": {
        "state": "modified",
        "summary": { "modified": 1, "added": 0, "deleted": 0, "untracked": 1, "staged": 0, "conflicts": 0 },
        "files": [
          { "path": "internal/status/poll.go", "worktree": "modified" },
          { "path": "internal/status/poll_test.go", "worktree": "untracked" }
        ]
      },
      "observed_at": "2026-09-04T14:02:11Z"
    }
  6. Import a pull request

    kwt pr list shows a project's pull requests. kwt pr import creates an inert worktree for one of them and keeps the contributor branch's push destination, so a fix you push goes where the pull request expects. Repository setup and agent commands do not run until you choose to run them.

    Attach only with kwt pr attach. kwt open and the dashboard refuse imported pull-request worktrees. kwt pr attach rechecks the worktree and its recorded project, then creates or repairs the session on a workspace-specific tmux socket.

    Pull-request automation · kwt pr

    $ kwt pr list --project github.com/acme/widget --state open --json
    $ kwt pr import github:github.com/acme/widget#17 \
        --project github.com/acme/widget --json
    { "workspace": { "path": "~/worktrees/widget-pr-17", … }, … }
    $ kwt changes ~/worktrees/widget-pr-17
    $ kwt pr attach ~/worktrees/widget-pr-17
    # kwt open refuses this path; use kwt pr attach
  7. Remove and prune worktrees

    kwt remove -b removes a worktree and its branch. It refuses when the checkout is dirty or a running process is inside it, and lists the process IDs. kwt prune needs a policy, --expired or --merged, and --dry-run prints every decision first. Merged pruning requires a merged pull request and keeps the local branch.

    kwt doctor finds broken backlinks, stale metadata, and registry drift without changing anything. kwt doctor --fix repairs only findings with one correct repair, rescans, and reports what remains.

    Worktree lifecycle and maintenance · kwt doctor · kwt prune

    $ kwt remove --dry-run feature/new-ui
    $ kwt remove -b feature/new-ui
    
    $ kwt prune --merged --dry-run
    [would_remove] pull request #23 is merged; the local branch is preserved
      ~/worktrees/widget-feature-search
    Candidates: 1, removed: 0, would remove: 1, skipped: 0
    $ kwt prune --merged
    
    $ kwt doctor
    $ kwt doctor --fix
  8. Sync across machines

    Enable [fleet], point each machine at a hub you run, and each machine publishes its worktree manifest. The dashboard marks rows that exist only on another machine, heads that differ between machines, and where dirty files were last seen. Select a remote-only row and press s to create the same branch locally.

    Sync is advisory. kwt never transfers files or commits, clones repositories, deletes remote worktrees, or locks a branch on another machine. The hub listens on loopback only. Put a private TLS endpoint in front of it and keep the bearer token in a file, not in config.toml.

    Multi-machine sync · Sync architecture

    [fleet]
    enabled    = true
    host_id    = "laptop"
    hub_url    = "https://desk.tail.example"
    token_file = "~/.config/kwt/fleet.token"
    
    # on the hub machine:
    $ kwt sync serve
    # on each client:
    $ kwt sync publish
    $ kwt sync status
  9. Embed kwt

    Start with the CLI and its JSON output. It keeps kwt's behavior and exit codes, and your client does not need to discover the daemon. A Go application can build the inventory, removal, inspection, and SSH services in process from go.kenn.io/kwt. A terminal client that manages its own attachment uses the tmux session endpoint.

    Ghosthub embeds these services to manage projects, worktrees, pull-request imports, and tmux workspaces on local and SSH-hosted machines. Any client can use the same interfaces.

    Embed and connect kwt · Design notes · Go package docs

    The dashboard, CLI, Go package, tmux session endpoint, SSH routes, and embedding applications such as Ghosthub all share one kwt daemon and its registry under KWT_HOME

Documentation

The documentation has the commands, JSON fields, exit statuses, configuration keys, the threat model, and the design notes. Every page has a Markdown version at the same path with a .md suffix, and llms.txt indexes them.

Expanded documentation capture