https://github.com/block/wt
A set of command line tools to help working with Bazel + IntelliJ-based AI worktrees in large codebases
https://github.com/block/wt
Last synced: 2 months ago
JSON representation
A set of command line tools to help working with Bazel + IntelliJ-based AI worktrees in large codebases
- Host: GitHub
- URL: https://github.com/block/wt
- Owner: block
- License: apache-2.0
- Created: 2026-01-16T18:31:02.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-03-22T07:00:36.000Z (2 months ago)
- Last Synced: 2026-03-22T18:14:12.562Z (2 months ago)
- Language: Kotlin
- Homepage:
- Size: 742 KB
- Stars: 5
- Watchers: 0
- Forks: 3
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: CODEOWNERS
- Governance: GOVERNANCE.md
Awesome Lists containing this project
README
# Worktree Toolkit
[](https://github.com/block/wt/actions/workflows/test.yml)
[](https://github.com/block/wt/actions/workflows/lint.yml)
[](https://github.com/block/wt/actions/workflows/plugin-build.yml)
A streamlined workflow for developing in large Bazel + IntelliJ monorepos using Git worktrees.
Enables instant IntelliJ context switching between worktreesβno re-imports, no re-indexingβand scales to support parallel development by humans and AI agents alike.
## Overview
Git worktrees let you work on multiple branches in parallel, but IntelliJ treats each worktree as a separate project, requiring expensive Bazel syncs and index rebuilds every time you switch to a new worktree.
This toolkit makes IntelliJ context switching **instant** by:
- **Symlink trick**: IntelliJ always opens the same path; switching worktrees looks like a branch checkout β incremental refresh in seconds, not minutes
- **Metadata vault**: IDE project metadata (`.ijwb`, `.idea`, `.vscode`, etc.) is stored externally and automatically installed into every new worktreeβno manual IDE setup needed
- **Safe worktree management**: Automatic stash/restore, branch creation, and cleanup of merged branches
- **Parallel development at scale**: Works for humans and AI agents alike
π See the [presentation slides](presentation/slides.pdf) for a visual walkthrough.
## Quick Start
```bash
# Install (interactive prompts for configuration)
./install.sh
# Reload shell
source ~/.zshrc
# Use
wt help
```
The installer will:
1. Copy the toolkit to `~/.wt/`
2. Add sourcing to your shell rc file
3. Prompt for workspace paths (main repo, worktrees, metadata vault)
4. Create required directories
5. Optionally migrate existing repo to worktree structure
6. Optionally export project metadata to the vault
7. Optionally set up a nightly cron job to refresh Bazel IDE metadata
## Workflow
### Initial Setup
The directory structure expected (controlled by environment variables, can be overwritten):
```
~/Development/
βββ java -> java-master # Symlink (IntelliJ opens this)
βββ java-master/ # Main repository
βββ java-worktrees/ # Worktrees go here
βββ idea-project-files/ # Project metadata vault
```
### Full Workflow Diagram
```
βββββββββββββββββββββββββββββββββββββββββββββββ
β External Project Metadata Vault β
β ~/Development/idea-project-files β
β (IDE configs: .ijwb, .idea, etc.) β
ββββββββββββ²ββββββββββββββββ¬βββββββββββββββββββ
β β
β β
βββwt metadata-exportββ βββwt metadata-importββ
β β
ββββββββββββ΄ββββββββββββββββββββββββ βββββββββββββββΌβββββββββββββββββββββββ
β Main Repository β β Worktrees β
β ~/Development/java-master β wt add β ~/Development/java-worktrees/... β
β β’ master branch β βββββββββββββββββββΊ β β’ feature/foo β
β β’ safe stash/pull/restore β(calls metadata-imp) β β’ bugfix/bar β
β β’ never removed β β β’ agent-task-123 β
βββββββββββββββββ¬βββββββββββββββββββ βββββββββββ¬βββββββββββββββββββββββββββ
β β
wt switch wt remove
β β
βββββββββββββΌβββββββββββββββββββ βββββββββββΌβββββββββββββ
β Stable IntelliJ Project Dir β β Safe cleanup with β
β ~/Development/java β β confirmation prompt β
β (symlink updated per switch) β ββββββββββββββββββββββββ
βββββββββββββ²βββββββββββββββββββ
β
IntelliJ auto-refresh
β
ββββββββββββΌββββββββββββββββββββ
β IntelliJ loads worktree β
β instantly (no import needed) β
ββββββββββββββββββββββββββββββββ
```
### Creating Worktrees
```bash
# Existing branch
wt add feature/foo
# New branch (from latest master)
wt add -b feature/foo
```
When creating with `-b`, the script:
1. Stashes uncommitted changes
2. Switches to master, pulls latest
3. Creates branch + worktree
4. Imports project metadata from vault
5. Restores original state
### Switching Worktrees
```bash
# Interactive
wt switch
# Direct
wt switch ~/Development/java-worktrees/feature/foo
```
Updates the symlink so IntelliJ instantly loads the new worktree.
### Navigation
```bash
# Interactive cd
wt cd
# Direct cd
wt cd ~/Development/java-worktrees/feature/foo
```
### Listing Worktrees
```bash
wt list
```
Shows all worktrees with status indicators:
- `*` = Currently linked worktree
- `[main]` = Main repository root
- `[linked]` = Active symlink target
- `[dirty]` = Has uncommitted changes
- `[βN]` / `[βN]` = Commits ahead/behind upstream
### Removing Worktrees
```bash
# Interactive
wt remove
# Direct (with confirmation)
wt remove ~/Development/java-worktrees/feature/foo
# Skip confirmation (unless uncommitted changes exist)
wt remove -y ~/Development/java-worktrees/feature/foo
# Remove all worktrees with branches merged into base branch
wt remove --merged
# Auto-remove merged without prompts (skips worktrees with uncommitted changes)
wt remove --merged -y
```
Safety features:
- Warns if the worktree is currently linked (symlink will be switched to main repo)
- Warns if there are uncommitted changes (shows summary)
- Always prompts for confirmation if uncommitted changes exist, even with `-y`
- `--merged` mode: automatically finds and removes all worktrees whose branches are merged
### Managing Project Metadata
```bash
# Export metadata from main repo to vault (run after setting up new IDE projects)
wt metadata-export
# Import metadata into a worktree (interactive selection if target omitted)
wt metadata-import
wt metadata-import ~/Development/java-worktrees/feature/foo
# Skip confirmation prompts (useful in scripts)
wt metadata-export -y
wt metadata-import -y ~/Development/java-worktrees/feature/foo
```
### Refreshing Stale Bazel IDE Metadata (Cron Job)
When most development work is done in worktrees, the Bazel IDE directories (`.ijwb`, `.aswb`, `.clwb`) in the main repository can become stale (targets files don't reflect new Bazel targets).
The `lib/wt-metadata-refresh` script is designed to run as a cron job to keep metadata current.
**Note:** When IntelliJ has `derive_targets_from_directories: true` in `.bazelproject` (the default), it queries Bazel fresh on every sync. The `targets-*` file serves as a cache for initial project imports and may improve import speed.
**Note:** The installer (`install.sh`) offers to set up this cron job automatically (default: yes).
To set it up manually:
```bash
# Create log directory
mkdir -p ~/.wt/logs
# Edit crontab
crontab -e
# Add this line to run nightly at 2am (uses login shell for full PATH):
0 2 * * * /bin/zsh -lc '~/.wt/lib/wt-metadata-refresh' >> ~/.wt/logs/metadata-refresh.log 2>&1
```
You can also run the script manually:
```bash
# Refresh all Bazel IDE directories and re-export to vault
~/.wt/lib/wt-metadata-refresh
# Preview what would be refreshed (dry run)
~/.wt/lib/wt-metadata-refresh --dry-run
# Refresh targets files only (skip re-export step)
~/.wt/lib/wt-metadata-refresh --no-export
```
The refresh script:
- Uses `bazel query` to regenerate `targets/targets-*` files in each Bazel IDE directory
- Supports all Bazel patterns configured in WT_METADATA_PATTERNS (`.ijwb`, `.aswb`, `.clwb`)
- Parses `.bazelproject` to determine which directories to include in the query
- Preserves existing targets file hashes (IntelliJ may reference them)
- Re-exports all metadata to the vault (including non-Bazel patterns)
- Logs timestamped output for monitoring
- Returns exit codes: 0=success, 1=error, 2=partial success
## Configuration: Environment Variables
The scripts rely on a few environment variables to know where your
main repository, worktrees, and IntelliJ metadata live.
These environment variables are set in `wt-common` with built-in defaults.
If set in your shell configuration, they take precedence over the built-in defaults.
| Variable | Default | Purpose |
|----------|---------|---------|
| `WT_MAIN_REPO_ROOT` | `~/Development/java-master` | Main repository root |
| `WT_WORKTREES_BASE` | `~/Development/java-worktrees` | Where worktrees are created |
| `WT_IDEA_FILES_BASE` | `~/Development/idea-project-files` | IntelliJ metadata vault |
| `WT_ACTIVE_WORKTREE` | `~/Development/java` | Symlink to active worktree |
| `WT_BASE_BRANCH` | `master` | Default branch for new worktrees |
### WT_MAIN_REPO_ROOT
Path to your primary git repository clone.
**Default:** `~/Development/java-master`
```bash
export WT_MAIN_REPO_ROOT="$HOME/Development/java-master"
```
Used by:
- wt-add (for stash/restore & base branch operations)
- wt-choose (listing worktrees)
- wt-switch (default symlink target)
- wt-remove (safety check to prevent removing main repo)
### WT_WORKTREES_BASE
Directory where new worktrees are created by default.
**Default:** `~/Development/java-worktrees`
```bash
export WT_WORKTREES_BASE="$HOME/Development/java-worktrees"
```
### WT_IDEA_FILES_BASE
Canonical metadata vault storing project metadata (IDE configs, etc.).
**Default:** `~/Development/idea-project-files`
```bash
export WT_IDEA_FILES_BASE="$HOME/Development/idea-project-files"
```
Used by:
- wt-metadata-import
- wt-metadata-export
- wt-metadata-refresh
- wt-add (when installing metadata)
### WT_ACTIVE_WORKTREE
Symlink path that points to the currently active worktree. This is where IntelliJ should open the project.
**Default:** `~/Development/java`
```bash
export WT_ACTIVE_WORKTREE="$HOME/Development/java"
```
Used by:
- wt-switch (updates this symlink)
- wt-remove (warns if removing the linked worktree)
### WT_BASE_BRANCH
Name of the mainline branch to branch from.
**Default:** `master`
```bash
export WT_BASE_BRANCH="master"
```
## Presentation
A 10-minute overview presentation is available in the `presentation/` directory:
- `slides.md` β Marp markdown source
- `slides.pdf` β Generated PDF
To regenerate the PDF from the markdown:
```bash
npx @marp-team/marp-cli presentation/slides.md -o presentation/slides.pdf
```
## Directory Structure
```
wt/
βββ wt.sh # Entry point (source this)
βββ presentation/ # Overview slides
βββ bin/ # Executable commands
β βββ wt-add
β βββ wt-cd
β βββ wt-list
β βββ wt-remove
β βββ wt-switch
β βββ wt-metadata-import
β βββ wt-metadata-export
βββ lib/ # Shared libraries
β βββ wt-common # Configuration and helpers
β βββ wt-choose # Interactive worktree selection
β βββ wt-help # Help text for wt command
β βββ wt-completion # Shell completion for wt command
β βββ wt-metadata-refresh # Cron script to refresh Bazel IDE metadata
βββ completion/ # Shell completions for wt-* scripts
β βββ wt.zsh
β βββ wt.bash
βββ install.sh
βββ README.md
```
## Individual Scripts
You can also run the underlying scripts directly:
```bash
wt-add, wt-switch, wt-remove, wt-list, wt-cd, wt-metadata-export, wt-metadata-import
```
These are located in `bin/` and work identically to the `wt` subcommands.
The `lib/wt-metadata-refresh` script is designed for cron jobs and can be run directly from its location.
## Project Resources
| Resource | Description |
| ------------------------------ | -------------------------- |
| [CODEOWNERS](./CODEOWNERS) | Project lead(s) |
| [GOVERNANCE.md](./GOVERNANCE.md) | Project governance |
| [LICENSE](./LICENSE) | Apache License, Version 2.0 |