Add your description here
Project description
workstack
Effortless git worktree management for parallel development.
Create, switch, and manage multiple worktrees from a centralized location with automatic environment setup.
Installation
# With uv (recommended)
uv tool install workstack
# From source
uv tool install git+https://github.com/dagster-io/workstack.git
Quick Start
# Initialize in your repo
cd /path/to/your/repo
workstack init
source ~/.zshrc # or ~/.bashrc
# Create and switch to a worktree
workstack create user-auth
workstack switch user-auth
# Switch back and clean up
workstack switch root
workstack rm user-auth
Overview
workstack solves the pain of managing multiple git worktrees for parallel agenetic coding sessions.
Key features:
- Centralized worktrees in
~/worktrees/<repo>/<feature>/ - Automatic environment setup (
.env, virtual environments, activation scripts) - Simple CLI:
create,switch,rm,ls - Plan-based development workflow
- Optional Graphite integration for stacked diffs
Core Commands
Creating Worktrees
# New feature branch
workstack create feature-x # Creates worktree 'feature-x' with branch 'feature-x'
workstack create fix --branch hotfix/bug # Creates worktree 'fix' with branch 'hotfix/bug'
# From existing branch
workstack create --from-branch feature/login # Creates worktree from existing branch 'feature/login'
workstack create login --from-branch feature/login # Creates worktree 'login' from branch 'feature/login'
# Move current work
workstack create --from-current-branch # Move current branch to new worktree
# From a plan file
workstack create --plan Add_Auth.md # Creates worktree with .plan/ folder
Managing Worktrees
workstack switch NAME # Switch between worktrees (or 'root' for repo root)
workstack switch --up # Navigate to child branch in Graphite stack
workstack switch --down # Navigate to parent branch in Graphite stack
workstack jump BRANCH # Jump to branch (finds worktree automatically)
workstack status # Show status of current worktree
workstack list # List all worktrees (alias: ls)
workstack list --stacks # List with graphite stacks and PR status
workstack tree # Show tree of worktrees with dependencies
workstack rename OLD NEW # Rename a worktree
workstack rm NAME # Remove worktree
workstack sync # Sync with Graphite, show cleanup candidates
workstack sync --dry-run # Show safe-to-delete worktrees (merged PRs)
workstack sync -f # Sync and auto-remove merged workstacks
Stack Navigation
With Graphite enabled, navigate your stacks directly:
workstack switch --up # Move to child branch in stack
workstack switch --down # Move to parent branch in stack
workstack jump BRANCH # Jump to any branch in a stack (finds worktree automatically)
Jump to Branch
Find and switch to a worktree by branch name:
workstack jump feature/user-auth # Finds worktree containing this branch
workstack jump hotfix/critical-bug # Works with any branch in your stacks
workstack jump origin-branch # Auto-creates from remote if not local
How it works:
- Searches all worktrees to find which one contains the target branch in its Graphite stack
- If not found in any worktree, checks if branch exists locally
- If not local, checks if
origin/branchexists remotely - Automatically creates tracking branch and worktree if needed
- No need to remember which worktree has which branch
Requirements:
- Graphite must be enabled for stack-based search (
workstack config set use_graphite true) - Branch auto-creation works without Graphite
Behavior:
- Branch checked out in one worktree: Switches to that worktree and checks out the branch
- Branch checked out in multiple worktrees: Shows all worktrees (choose manually with
workstack switch) - Branch exists locally but not checked out: Auto-creates worktree for the branch
- Branch exists on origin but not locally: Auto-creates tracking branch and worktree
- Branch doesn't exist anywhere: Shows error with suggestion to create new branch
Example workflow:
# You have multiple worktrees with different stacks:
# - worktree "feature-work": main -> feature-1 -> feature-2 -> feature-3
# - worktree "bugfix-work": main -> bugfix-1 -> bugfix-2
# Jump to existing branch in worktree
workstack jump feature-2 # → Switches to "feature-work" and checks out feature-2
workstack jump bugfix-1 # → Switches to "bugfix-work" and checks out bugfix-1
# Jump to unchecked local branch
workstack jump feature-4 # → Auto-creates worktree for feature-4
# Jump to remote-only branch (like git checkout origin/branch)
workstack jump hotfix-123 # → Creates tracking branch + worktree from origin/hotfix-123
Stack Navigation with Switch
Example workflow:
# Current stack: main -> feature-1 -> feature-2 -> feature-3
# You are in: feature-2
workstack switch --up # → feature-3
workstack switch --down # → feature-2
workstack switch --down # → feature-1
workstack switch --down # → root (main)
Requirements:
- Graphite must be enabled (
workstack config set use_graphite true) - Target branch must have an existing worktree
- If no worktree exists, shows helpful message:
workstack create <branch>
Behavior:
--up: Navigates to child branch (up the stack)--down: Navigates to parent branch (down toward trunk)- At stack boundaries, shows clear error messages
- Cannot be combined with NAME argument
Moving Branches
Move or swap branches between worktrees:
workstack move target-wt # Move from current to new worktree
workstack move --worktree old-wt new-wt # Move from specific source to target
workstack move --current existing-wt # Swap branches between worktrees
workstack move --branch feature-x new-wt # Auto-detect source from branch name
Example output:
$ workstack list
root [master]
feature-a [feature-a]
feature-b [work/feature-b]
$ workstack list --stacks
root [master]
◉ master
feature-a [feature-a]
◯ master
◉ feature-a ✅ #123
feature-b [work/feature-b]
◯ master
◉ work/feature-b 🚧 #456
PR Status Indicators:
- ✅ Checks passing
- ❌ Checks failing
- 🟣 Merged
- 🚧 Draft
- ⭕ Closed
- ◯ Open (no checks)
Note: The repository root is displayed as root and can be accessed with workstack switch root.
Visualizing Worktrees
workstack tree # Show tree of worktrees with dependencies
Example output:
$ workstack tree
main [@root]
├─ feature-a [@feature-a]
│ └─ feature-a-2 [@feature-a-2]
└─ feature-b [@feature-b]
The tree command shows:
- Only branches with active worktrees (not all branches)
- Dependency relationships from Graphite stacks
- Current worktree highlighted in bright green
- Worktree names in brackets
[@name]
Note: Requires Graphite to be enabled.
Configuration
workstack init # Initialize in repository
workstack init --shell # Show shell integration setup instructions
workstack init --list-presets # List available config presets
workstack init --repo # Initialize repo config only (skip global)
workstack config list # Show all configuration
workstack config get KEY # Get config value
workstack config set KEY VALUE # Set config value
workstack completion bash/zsh/fish # Generate shell completion script
Configuration Files
Global (~/.workstack/config.toml):
workstacks_root = "/Users/you/worktrees"
use_graphite = true # Auto-detected if gt CLI installed
show_pr_info = true # Display PR status in list --stacks (requires gh CLI)
Per-Repository (~/worktrees/<repo>/config.toml):
[env]
# Template variables: {worktree_path}, {repo_root}, {name}
DATABASE_URL = "postgresql://localhost/{name}_db"
[post_create]
shell = "bash"
commands = [
"uv venv",
"uv pip install -e .",
]
Common Workflows
Parallel Feature Development
workstack create feature-a
workstack switch feature-a
# ... work on feature A ...
workstack create feature-b
workstack switch feature-b
# ... work on feature B ...
workstack switch feature-a # Instantly back to feature A
Plan-Based Development
workstack promotes an opinionated workflow that separates planning from implementation:
Core principles:
- Plan in main/master - Keep your main branch "read-only" for planning. Since planning doesn't modify code, you can create multiple plans in parallel without worktrees.
- Execute in worktrees - All code changes happen in dedicated worktrees, keeping work isolated and switchable.
- Plans as artifacts - Each plan is a markdown file that travels with its worktree.
Workflow:
# 1. Stay in root repo for planning
workstack switch root
# 2. Create your plan and save it to disk (e.g. Add_User_Auth.md)
# 3. Create worktree from plan
workstack create --plan Add_User_Auth.md
# This automatically:
# - Creates worktree named 'add-user-auth'
# - Creates .plan/ folder with plan.md (immutable) and progress.md (mutable)
# - .plan/ is already in .gitignore (added by workstack init)
# 4. Switch and execute
workstack switch add-user-auth
# Your plan is now at .plan/plan.md for reference during implementation
# Progress tracking in .plan/progress.md shows step completion
Why this works:
- Plans don't clutter PR reviews (
.plan/in.gitignore) - Each worktree has its own plan context
- Clean separation between thinking and doing
- Progress tracking separates plan content from completion status
- Workflow guides user to start implementation with clean context and progress visibility
This workflow emerged from experience - checking in planning documents created noise in reviews and maintenance overhead without clear benefits.
Moving Current Work
# Started work on main by accident?
workstack create --from-current-branch
# Creates worktree with current branch, switches you back to root
Syncing and Cleanup
After merging PRs, sync your local branches and clean up:
workstack sync
# This will:
# 1. Switch to root (avoiding git conflicts)
# 2. Run gt sync to update branch tracking
# 3. Identify merged/closed PR workstacks
# 4. Prompt for confirmation before removing them
# 5. Switch back to your original worktree
# Or use -f to skip confirmation:
workstack sync -f
Options:
workstack sync # Sync and show cleanup candidates
workstack sync -f # Force gt sync and auto-remove merged workstacks
workstack sync --dry-run # Preview without executing
Requires Graphite CLI (gt) and GitHub CLI (gh) installed.
Command Reference
create Options
| Option | Description |
|---|---|
--branch BRANCH |
Specify branch name (default: NAME) |
--ref REF |
Base ref (default: current HEAD) |
--plan FILE |
Create from plan file |
--from-current-branch |
Move current branch to worktree |
--from-branch BRANCH |
Create from existing branch |
--no-post |
Skip post-create commands |
list / ls Options
| Option | Description |
|---|---|
-s, --stacks |
Show graphite stacks and PR status |
-c, --checks |
Show CI check status (requires GitHub API call) |
move Options
| Option | Description |
|---|---|
--current |
Use current worktree as source |
--branch BRANCH |
Auto-detect worktree containing this branch |
--worktree NAME |
Use specific worktree as source |
--ref REF |
Fallback branch for source (default: main) |
-f, --force |
Skip confirmation prompts |
remove / rm Options
| Option | Description |
|---|---|
-f, --force |
Do not prompt for confirmation |
-s, --delete-stack |
Delete all branches in Graphite stack |
--dry-run |
Show what would be done without executing |
rename Options
| Option | Description |
|---|---|
--dry-run |
Show what would be done without executing |
sync Options
| Option | Description |
|---|---|
-f, --force |
Force gt sync and auto-remove merged workstacks |
--dry-run |
Show what would be done without executing |
init Options
| Option | Description |
|---|---|
--force |
Overwrite existing repo config |
--preset NAME |
Config template (auto/generic/dagster/etc) |
--list-presets |
List available presets and exit |
--repo |
Initialize repo config only (skip global) |
--shell |
Show shell integration setup instructions |
Environment Variables
Always exported when switching:
WORKTREE_PATH- Absolute path to current worktreeREPO_ROOT- Absolute path to repository rootWORKTREE_NAME- Name of current worktree
Advanced Features
Graphite Integration
If Graphite CLI is installed, workstack automatically uses gt create for proper stack tracking.
brew install withgraphite/tap/graphite
workstack init # Auto-detects gt
Disable in ~/.workstack/config.toml: use_graphite = false
Repository Presets
Dagster:
[env]
DAGSTER_GIT_REPO_DIR = "{worktree_path}"
[post_create]
commands = ["uv venv", "uv run make dev_install"]
Cleanup
Find and clean up merged/closed PR branches:
workstack sync --dry-run
# Output:
# feature-x [work/feature-x] - merged (PR #123)
# feature-y [work/feature-y] - closed (PR #456)
workstack sync -f # Clean up automatically
Requires GitHub CLI (gh) installed and authenticated.
FAQ
Q: How is this different from git worktree?
A: Adds centralized management, automatic environment setup, and seamless switching.
Q: Does it work with non-Python projects?
A: Yes! Configure post_create commands for any stack.
Q: What if I don't use Graphite?
A: Works perfectly with standard git commands.
Documentation
For Developers
Core documentation for contributors:
- AGENTS.md - Coding standards and conventions (required reading)
- tests/AGENTS.md - Testing patterns and practices
- docs/PUBLISHING.md - Publishing to PyPI guide
Shell Integration Output Pattern
Commands that generate activation scripts should use the self-documenting ScriptResult API:
# Generate activation script
result = ctx.script_writer.write_activation_script(
script_content,
command_name="mycommand",
comment="description",
)
# Output for shell integration (--script flag)
result.output_for_shell_integration() # ✓ Routes to stdout
# OR output for user visibility (rarely needed)
if verbose:
result.output_path_for_user() # Routes to stderr
# OR defer output (advanced pattern)
script_result = result # Save for later
# ... more logic ...
if should_output:
script_result.output_for_shell_integration()
This prevents bugs where script paths are written to the wrong stream (stderr instead of stdout), causing shell integration to fail. See src/workstack/core/script_writer.py for detailed documentation.
Workspace Structure
This project uses a uv workspace to organize the codebase:
workstack/ # Root workspace
├── src/workstack/ # Main workstack package
├── packages/
│ └── workstack-dev/ # Development tools package
│ ├── src/workstack_dev/ # Development CLI commands
│ ├── tests/ # Dev CLI tests
│ └── pyproject.toml # Package metadata
└── pyproject.toml # Workspace configuration
workstack-dev is an independent package containing development tools for workstack. It provides commands for publishing to PyPI, code review, cache management, and more. It is installed as a dev dependency.
For AI Assistants
Comprehensive, agent-optimized documentation is available in the .agent/ directory:
- Architecture - System design, patterns, and component relationships
- Feature Index - Complete feature catalog with implementation locations
- Glossary - Terminology and concept definitions
- Module Map - Module structure and exports
- Coding Patterns - Detailed implementation patterns with examples
- Exception Handling - Complete exception handling guide
- workstack-dev CLI - Development CLI architecture and design
See .agent/README.md for more details.
Links
- GitHub: https://github.com/dagster-io/workstack
- Issues: https://github.com/dagster-io/workstack/issues
License
MIT - Nick Schrock (@schrockn)
Originally developed by @schrockn, now maintained by Dagster Labs.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file workstack-0.1.26.tar.gz.
File metadata
- Download URL: workstack-0.1.26.tar.gz
- Upload date:
- Size: 963.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2f671f602b0191e14a109360179ba9b42effece4cb2fee97f74b8841e135490
|
|
| MD5 |
64ece4ed44db2c0fa053d1330b6b877e
|
|
| BLAKE2b-256 |
edc56dc69d2ad80780d921309db8097db71cfecfc32e3e4ecb68ebef87545e49
|
File details
Details for the file workstack-0.1.26-py3-none-any.whl.
File metadata
- Download URL: workstack-0.1.26-py3-none-any.whl
- Upload date:
- Size: 149.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd523a7d12030d93f4db755220421bac34ba8815eef156560953d76bfb895cd7
|
|
| MD5 |
31b1031ef49bdac3b8e12917746e4419
|
|
| BLAKE2b-256 |
a076566344917597c9f578a6d539f90a7dff2a04b1b54661e9c9b9580a8dbe97
|