npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nano-step/opencode-worktree-plugin

v4.0.8

Published

Manage git worktrees across parallel OpenCode sessions — plugin + CLI

Readme

owt — OpenCode Worktree Manager

Manage git worktrees across parallel OpenCode sessions. Create named worktrees, open them in new terminals, view their status, and commit — all without switching branches or losing uncommitted work.


What it does

  • Named worktrees — attach human-readable names to branches (e.g. "Fix login bug" instead of feature/WIN-123)
  • Parallel sessions — unlimited features in progress simultaneously, zero conflicts
  • Dirty status — see which worktrees have uncommitted changes at a glance
  • Quick accessowt <name> opens a worktree in a new terminal window
  • In-place git opsowt diff, owt status, owt log, owt merge, owt commit without cd
  • Co-author stripowt hook removes AI-injected Co-authored-by: from every commit
  • Shared node_modules — symlinked from main repo; no duplicate installs
  • Feature-first grouping/init-feature WIN-123 creates worktrees for multiple repos under one ticket folder; AI gets full feature context injected automatically
  • Local or global state — worktrees can live inside your project (.opencode/worktrees/) or globally (~/.config/opencode/worktrees/) — configured per project

Release channels

  • @latest (v4.x) — current stable. Includes feature-first cross-repo workflows, local state mode, and all slash commands.

Previous stable: v3.2.0 (zero-project-footprint state). v4 is backward compatible — existing worktrees keep working.


How OWT works

OWT has three layers that work together. Each layer can be used independently.

┌─────────────────────────────────────────────────────────────┐
│                      You (human)                            │
├──────────────┬──────────────────────┬───────────────────────┤
│  OpenCode    │   OpenCode session   │   Terminal            │
│  main session│   (worktree)         │                       │
│              │                      │                       │
│ /init-worktree ──→ createworktree ──┼──→ owt <name>         │
│ /list-worktrees ─→ listworktrees    │    owt status/diff/   │
│ /open-worktree                      │    log/merge/commit   │
├──────────────┴──────────────────────┴───────────────────────┤
│              Slash Commands (command/*.md)                   │
│              Parse arguments, call plugin tools              │
├─────────────────────────────────────────────────────────────┤
│              Plugin (worktree-plugin.js)                     │
│              3 tools: createworktree / deleteworktree /      │
│              listworktrees                                   │
│              + system prompt injection                       │
│              + state management (worktree-sessions.json)     │
├─────────────────────────────────────────────────────────────┤
│              Shell Script (owt.sh)                           │
│              Terminal manager: list, open, status, diff,     │
│              log, merge, commit, hook                        │
├─────────────────────────────────────────────────────────────┤
│              git worktree (built-in git)                     │
│              The actual isolation mechanism                  │
└─────────────────────────────────────────────────────────────┘

Layer 1 — Plugin (worktree-plugin.js)

The plugin registers three tools that OpenCode's AI agent can call:

| Tool | What it does | |------|-------------| | createworktree | Runs git worktree add, symlinks node_modules, saves session state | | deleteworktree | Checks for uncommitted changes, runs git worktree remove, cleans up state | | listworktrees | Combines git worktree list with saved display names and dirty status | | createfeature | Creates a feature folder with worktrees for multiple repos in one command | | listfeatures | Lists all features with per-repo clean/dirty/missing status | | deletefeature | Aggregate dirty check across all repos, then removes all worktrees atomically |

System prompt injection: When OpenCode starts a session, the plugin injects context into the AI's system prompt:

  • Feature worktree → injects full feature context (ticket, name, repo count, sibling repo paths) + cleanup rules
  • Regular worktree → injects cleanup rules: tell user to run deleteworktree when done, stop after cleanup
  • Main repo (single-repo) → injects availability hint: createworktree is available for parallel tasks
  • Main repo (workspace) → injects workspace hint: lists available repos, suggests listworktrees

This is how the AI "knows" it's inside a worktree without being told.

State management: Display names, session IDs, and creation timestamps are stored in .opencode/worktree-sessions.json. This file is read by both the plugin and the shell script. It is not committed to git.

Layer 2 — Slash commands (command/*.md)

Markdown files that define /init-worktree, /list-worktrees, and /open-worktree. These are prompt templates that:

  1. Parse user arguments (branch name, display name, base branch)
  2. Call the plugin tools with the correct parameters
  3. Format the output for the user

They are the user-facing interface inside OpenCode sessions. The AI reads the markdown instructions and executes them.

Layer 3 — Shell script (owt.sh)

A standalone bash script for use outside OpenCode — in any terminal. It reads the same worktree-sessions.json state file to resolve display names, and calls git directly for all operations.

Key capabilities not available through the plugin:

  • Terminal detection: Auto-detects Ghostty, iTerm, Terminal.app, WezTerm, Kitty, Alacritty, tmux — opens a new window with opencode --cwd
  • Fuzzy matching: owt fix matches "Fix login bug" by partial name or branch
  • In-place git ops: owt diff, owt log, owt status without cd-ing into the worktree
  • Co-author hook: Strips AI-injected Co-authored-by: lines from commit messages

Data flow: creating a worktree

/init-worktree feature/WIN-123 name:"Fix login bug"
                │
                ▼
    Slash command parses args
                │
                ▼
    createworktree(branch="feature/WIN-123", name="Fix login bug")
                │
                ├─ Branch exists locally?  → git worktree add <path> <branch>
                ├─ Branch exists remote?   → git fetch + git worktree add
                └─ New branch?             → git worktree add <path> -b <branch> <base>
                │
                ▼
    Symlink node_modules from main repo → worktree
                │
                ▼
    Save to .opencode/worktree-sessions.json:
    { "sessions": { "<sessionId>": { "branch": "...", "name": "...", "worktreePath": "..." } } }
                │
                ▼
    User opens: opencode --cwd "~/.config/opencode/worktrees/repos/<repo-id>/worktrees/fix-login/"
               (or .opencode/worktrees/fix-login/ in local state mode)
                │
                ▼
    Plugin detects worktree directory → injects WORKTREE_RULES into system prompt
                │
                ▼
    AI agent operates in isolated branch, full source checkout

Data flow: listing and opening

owt                         owt fix-login
 │                           │
 ▼                           ▼
git worktree list           Fuzzy-match "fix-login" against
 +                          display names and branch names
worktree-sessions.json       │
 │                           ▼
 ▼                          Resolve to single worktree path
Display all with             │
✓/⚠ dirty status            ▼
                            Detect terminal emulator
                             │
                             ▼
                            Open new window:
                            opencode --cwd <worktree-path>

Quick start

Two paths depending on whether you want the owt CLI permanently.

Path A — npx (zero-install)

One command copies everything into ~/.config/opencode/:

# stable (v2.x)
npx @nano-step/opencode-worktree-plugin install

# beta — workspace mode (v3.0.0+)
npx @nano-step/opencode-worktree-plugin@beta install

This copies the slash commands into ~/.config/opencode/command/ and the plugin into ~/.config/opencode/plugins/. No package is left installed on your machine.

Then restart OpenCode. Plugins and commands are loaded at startup — nothing takes effect until you do.

Note: npx runs the installer temporarily. The owt CLI is not added to your PATH. To test the install worked, open OpenCode and run /init-worktree. If you want owt on your PATH permanently, use Path B instead.

Path B — Global install (gives you owt CLI)

# stable (v2.x)
npm install -g @nano-step/opencode-worktree-plugin

# beta — workspace mode (v3.0.0+)
npm install -g @nano-step/opencode-worktree-plugin@beta

owt-setup install

npm install -g puts owt and owt-setup on your PATH. owt-setup install copies the slash commands and plugin into ~/.config/opencode/ (same files as npx).

Then restart OpenCode.

Optionally, strip the AI co-author line from commits:

owt hook --global

Verify everything is working:

owt help

Troubleshooting: If owt help works but OpenCode doesn't recognize /init-worktree, you haven't restarted OpenCode yet.


Workspace mode (multiple repos)

Available in @beta (v3.0.0+). Install with npx @nano-step/opencode-worktree-plugin@beta install.

If you open OpenCode at a folder containing multiple git repos (not itself a git repo), the plugin automatically detects and works with all of them.

~/projects/
├── frontend/     ← .git
├── backend/      ← .git
└── shared-lib/   ← .git
opencode --cwd ~/projects    # opens at workspace level — plugin finds all 3 repos

Create a worktree in a specific repo

/init-worktree feature/new-dashboard repo:"frontend" name:"Dashboard redesign"

List all repos and worktrees

/list-worktrees

Shows all repos, even those with no active worktrees.

How it works

  • The plugin scans immediate children of the workspace directory for .git folders
  • Symlinks, hidden directories, and node_modules are skipped
  • Discovery caps at 50 repos
  • Each repo's worktrees are stored at ~/.config/opencode/worktrees/repos/<repo-id>/worktrees/ by default (global state). Set stateLocation: "local" in .opencode/worktree-config.json to keep them inside the project instead.
  • The system prompt tells the AI which repos are available

Single-repo backward compatibility

If you open OpenCode inside a git repo (the existing workflow), everything works exactly as before. The repo parameter is optional and ignored in single-repo mode.


Feature-first workflow (v4+)

Requires v4.0.0+. Works in workspace mode (ecosystem folder with multiple repos).

The standard /init-worktree creates one worktree per repo independently. Feature-first groups them: one ticket ID creates a folder containing worktrees for all involved repos, and the AI automatically knows which feature it's working on.

Layout

~/.config/opencode/worktrees/features/
└── win-123-dashboard-redesign/
    ├── feature.json          ← feature metadata
    ├── frontend/             ← git worktree (branch: feature/WIN-123)
    └── backend/              ← git worktree (branch: feature/WIN-123)

feature.json

Each feature folder contains a feature.json file created by /init-feature. It stores the feature metadata and is used by the plugin to detect feature mode when you open a worktree session.

{
  "version": 1,
  "id": "WIN-123",
  "slug": "win-123-dashboard-redesign",
  "name": "Dashboard redesign",
  "branch": "feature/WIN-123",
  "ecosystemDir": "/Users/you/projects",
  "createdAt": 1713820800000,
  "repos": {
    "frontend": {
      "source": "/Users/you/projects/frontend",
      "worktreePath": "frontend"
    },
    "backend": {
      "source": "/Users/you/projects/backend",
      "worktreePath": "backend"
    }
  }
}

Do not edit this file manually. It is managed by the plugin.

Create a feature

Open OpenCode at your ecosystem folder:

opencode --cwd ~/projects    # must be a workspace (folder containing repos, not itself a git repo)

Then:

/init-feature ticket:WIN-123 name:"Dashboard redesign" branch:feature/WIN-123 repos:frontend,backend

Output:

✓ Feature "win-123-dashboard-redesign" created.
  Branch: feature/WIN-123
  Path  : ~/.config/opencode/worktrees/features/win-123-dashboard-redesign

  frontend: opencode --cwd "~/.config/opencode/worktrees/features/win-123-dashboard-redesign/frontend"
  backend:  opencode --cwd "~/.config/opencode/worktrees/features/win-123-dashboard-redesign/backend"

Open each repo in a separate terminal — each session is fully isolated on feature/WIN-123.

AI context injection

When you open a feature worktree session, the AI automatically receives:

FEATURE CONTEXT: WIN-123 — Dashboard redesign
You are working on the FRONTEND repo (1 of 2 in this feature).
Other repos in this feature:
  - backend: opencode --cwd "..."
Branch: feature/WIN-123 (all repos)

No manual prompting needed — the AI knows which feature, which repo, which branch, and how to switch to sibling repos.

List and delete features

/list-features
⚠ WIN-123 — Dashboard redesign
  Branch: feature/WIN-123
  Repos : frontend [dirty], backend [clean]
  Open  : opencode --cwd "..."
/delete-feature ticket:WIN-123

Refuses if any repo has uncommitted changes. Removes all worktrees atomically. Never deletes branches.


Install (step by step)

Step 1 — Install

Option A (npx, no permanent install):

npx @nano-step/opencode-worktree-plugin install

Downloads the package, copies config files into ~/.config/opencode/, then exits. Nothing stays on your PATH.

Option B (global, gives you owt CLI):

npm install -g @nano-step/opencode-worktree-plugin
owt-setup install

npm install -g puts owt and owt-setup on your PATH permanently. owt-setup install copies the slash commands into ~/.config/opencode/command/ and the plugin into ~/.config/opencode/plugins/. Requires Node.js >= 18.

Troubleshooting: If owt is not found after global install, your npm global bin directory may not be in your PATH. Run npm bin -g to find it.

Step 2 — Configure OpenCode

Restart OpenCode. This is the most common setup gotcha. Plugins and slash commands are loaded once at startup, so changes don't take effect until you restart.

After restarting:

  • Test with /init-worktree in OpenCode (works for both paths)
  • Or run owt help in your terminal (global install only)

Per-project plugin loading (alternative to global config): Instead of copying to ~/.config/opencode/, you can load the plugin per project via opencode.json:

{
  "plugin": ["@nano-step/opencode-worktree-plugin"]
}

OpenCode resolves the package from your project's node_modules. Useful when different projects need different plugin versions.

Step 3 — Strip AI co-author from commits (optional)

If you use OpenCode to commit, it injects Co-authored-by: Sisyphus into every commit message. To strip it globally:

owt hook --global

This installs a commit-msg git hook at ~/.config/git/hooks/commit-msg and sets git config --global core.hooksPath. One-time setup, applies to all repos on your machine.

Note: git commit --no-verify bypasses hooks including this one.


Migrating from v1.x or unscoped package

If you previously installed the plugin by cloning the repo and copying files manually, remove the old copy before switching to the npm-based install:

rm ~/.config/opencode/plugins/worktree-plugin.js

If you also switch to opencode.json plugin loading (the "plugin": [...] key), make sure the file-based copy above is gone first. Otherwise the plugin loads twice, which causes duplicate tools and confusing behavior.

If you were using the unscoped opencode-worktree-plugin package, update your opencode.json to reference the scoped package:

{
  "plugin": ["@nano-step/opencode-worktree-plugin"]
}

Then follow the Quick start steps above.


Migrating from v3.x to v4

v4 is backward compatible. Existing worktrees continue to work without any manual steps.

On first load after upgrading, the plugin automatically reorganizes the global state directory:

Before (v3):

~/.config/opencode/worktrees/
├── <repo-id>/
│   ├── worktrees/
│   └── worktree-sessions.json

After (v4):

~/.config/opencode/worktrees/
├── repos/
│   └── <repo-id>/
│       ├── worktrees/
│       └── worktree-sessions.json
└── features/        ← new in v4

The migration runs once and creates a .migrated-v4 sentinel file to skip on subsequent loads. If migration fails (non-fatal), the plugin logs a warning and continues — your worktrees are not deleted.


Usage

List all worktrees

owt

Output:

Active worktrees:

  ⚠ Fix login bug  [dirty (uncommitted changes)]
    Branch : feature/WIN-123
    Path   : /project/.opencode/worktrees/fix-login-bug
    Open   : opencode --cwd "/project/.opencode/worktrees/fix-login-bug"

  ✓ pod-3 hotfix  [clean]
    Branch : release/pod-3
    Path   : /project/.opencode/worktrees/pod-3-hotfix
    Open   : opencode --cwd "/project/.opencode/worktrees/pod-3-hotfix"

Open a worktree in a new terminal

owt fix-login        # partial match on name or branch
owt WIN-123          # matches "feature/WIN-123"
owt pod              # matches "pod-3 hotfix"

Spawns a new terminal window running opencode --cwd <worktree-path>. Supports: Ghostty, iTerm, Terminal.app, WezTerm, Kitty, Alacritty, tmux.

View git status

owt status              # all worktrees at once
owt status fix-login    # specific worktree

View changes (diff)

owt diff fix-login               # full diff vs base branch
owt diff fix-login -- src/auth.ts  # specific file

View recent commits

owt log fix-login    # commits since branched off base

Merge into another branch

owt merge fix-login                   # merge into current branch
owt merge fix-login --into main       # merge into specific branch
owt merge fix-login --into release/qa3

Guards against dirty state — will error if uncommitted changes exist.

Commit from main session (without cd)

owt commit fix-login -m "feat: fix login redirect"

Runs git add -A + git commit inside the worktree. Useful when you want to commit without opening a new terminal.

Guideline: If you are on main and need to commit changes that belong to another worktree, always use owt commit <name> -m "..." instead of switching branches. This keeps each branch's history clean and avoids accidentally committing feature work onto main.

Examples:

owt commit implement-a -m "feat: implement A"   # commits into feature/implement-A
owt commit fix-login   -m "fix: login redirect"  # commits into feature/fix-login
owt commit pod-3       -m "chore: bump version"  # commits into release/pod-3

owt matches by partial name or branch — implement-a matches feature/implement-A.

Install co-author strip hook

owt hook --global           # all repos on this machine (recommended)
owt hook --local            # current repo only
owt hook --worktree WIN-123 # specific worktree (note: shares .git/hooks with main)

Inside OpenCode (slash commands)

Single-repo worktrees:

| Command | Description | | -------------------------------------- | ---------------------------------------- | | /init-worktree <branch> [name:"..."] | Create a named worktree | | /list-worktrees | List all worktrees with status | | /open-worktree [name-or-branch] | Print opencode --cwd command | | /owt-current | Show current worktree name/branch/status |

Feature-first (cross-repo):

| Command | Description | | ---------------------------------------------------------------- | ---------------------------------------------- | | /init-feature ticket:<id> name:"..." branch:<b> repos:<r1,r2> | Create feature folder with worktrees per repo | | /list-features | List all features with per-repo status | | /delete-feature ticket:<id> | Delete all worktrees for a feature |

Examples:

/init-worktree feature/WIN-123 name:"Fix login bug"
/init-worktree hotfix/crash name:"Critical crash" from:main
/list-worktrees
/open-worktree fix-login
/owt-current

/init-feature ticket:WIN-123 name:"Dashboard redesign" branch:feature/WIN-123 repos:frontend,backend
/list-features
/delete-feature ticket:WIN-123

Check current worktree (/owt-current)

Run /owt-current from any OpenCode session to see what worktree you are in.

Inside a worktree:

Current worktree:

  Name   : Fix login bug
  Branch : feature/WIN-123
  Path   : ~/.config/opencode/worktrees/repos/.../worktrees/feature/WIN-123
  Status : clean

Main repo: /Users/you/projects/myapp

Inside a feature worktree:

FEATURE CONTEXT: WIN-123 — Dashboard redesign
You are working on the FRONTEND repo (1 of 2 in this feature).
Other repos in this feature:
  - backend: opencode --cwd "..."
Branch: feature/WIN-123 (all repos)
Path   : ~/.config/opencode/worktrees/features/win-123-dashboard-redesign/frontend
Status : clean

In the main repo:

You are in the main repository.

  Branch : main
  Path   : /Users/you/projects/myapp

Use /init-worktree to create a parallel worktree session.

How git worktrees work — FAQ

These are the most common questions when using worktrees for the first time.

Does each worktree have the full source code?

Yes. A worktree is not a symlink or a partial copy. It is a complete checkout of the branch. Every file in the project exists inside the worktree directory.

project/                                          ← full source, branch: main
~/.config/opencode/worktrees/repos/<repo-id>/
  worktrees/fix-login/                            ← full source, branch: feature/WIN-123, name: "Fix login"
  worktrees/pod-3-hotfix/                         ← full source, branch: release/pod-3, name: "pod-3 hotfix"

# Or with stateLocation: "local":
project/.opencode/worktrees/
  fix-login/                      ← full source, branch: feature/WIN-123
  pod-3-hotfix/                   ← full source, branch: release/pod-3

The only thing that is symlinked is node_modules (to avoid duplicate installs).

Do 4 parallel sessions write to the same files?

No. Each session operates in its own directory. Session A edits worktrees/fix-login/src/Button.tsx. Session B edits worktrees/pod-3-hotfix/src/Button.tsx. These are different files on disk.

Git also enforces branch locking — the same branch cannot be checked out in two worktrees simultaneously. If you try, git returns an error.

If I commit in worktree A, does the main repo see it?

Yes, immediately. All worktrees share a single .git repository. A commit in worktree A goes into the branch of worktree A. From the main session you can run:

git log feature/WIN-123 --oneline   # see the commit immediately
git diff main...feature/WIN-123      # diff without switching branches

You do not need to cd into the worktree to inspect its commits.

Do uncommitted changes get lost when I switch to another worktree?

No. Uncommitted changes stay in their worktree directory indefinitely. There is nothing to stash. To "switch" to another worktree, just cd to it or open a new terminal. The changes in the previous worktree are untouched.

This is the main advantage over git checkout — you never need to stash.

Why can't I commit feature A from the main repo directory?

The main repo directory is on a different branch (e.g. main or release/qa3). Committing there puts the commit on that branch, not on feature/implement-A.

To commit feature A, you must be in worktrees/feature/implement-A/ — or use owt commit implement-A -m "...".

Can I run npm test inside a worktree?

Yes. Each worktree has the full project structure and node_modules symlinked from the main repo. Run npm test, npm run build, or npm run start directly inside the worktree directory.

To run multiple features simultaneously on different ports:

# Each worktree gets its own port — as many as you need
PORT=3001 npm run start   # in worktrees/feature/implement-A
PORT=3002 npm run start   # in worktrees/feature/implement-B
PORT=3003 npm run start   # in worktrees/feature/implement-C
# ... and so on

How do I check out a worktree branch in the main repo?

You do not need to. From the main repo, use git -C to run git commands in any worktree without cd:

git -C .opencode/worktrees/fix-login diff
git -C .opencode/worktrees/fix-login log --oneline -5
git -C .opencode/worktrees/fix-login status

Or use owt diff WIN-123, owt log WIN-123, owt status WIN-123.


End-to-end workflow

1. Create worktrees for each task

In OpenCode (main session):

/init-worktree feature/implement-A name:"Feature A"
/init-worktree feature/implement-B name:"Feature B"
/init-worktree feature/implement-C name:"Feature C"
/init-worktree feature/implement-D name:"Feature D"

2. Open each in a new session

owt feature-a    # opens terminal with opencode --cwd <path>
owt feature-b
owt feature-c
owt feature-d

Now you have 4 OpenCode sessions, each on their own branch, working in parallel.

3. Check progress from main session

owt              # see which are dirty/clean
owt status       # git status of all worktrees
owt log A        # commits in feature A

4. Review and commit

Option A — commit inside the worktree session:

# Inside the feature-A session
git add .
git commit -m "feat: implement A"

Option B — commit from main session without cd:

owt commit feature-a -m "feat: implement A"

5. Merge when done

owt merge feature-a --into release/qa3
npm test                                # verify after merge A
owt merge feature-b --into release/qa3
npm test                                # verify after merge A+B
# ... repeat for C, D

6. Cleanup

In OpenCode, call deleteworktree for each worktree, or:

git worktree remove .opencode/worktrees/implement-a

Configuration (worktree-config.json)

Per-project worktree behavior is controlled by .opencode/worktree-config.json in your project root. This file is optional — all settings have defaults.

First-run setup

The first time you run /init-worktree or /init-feature in a project, the plugin checks for .opencode/worktree-config.json. If the file does not exist, you will be prompted once:

No worktree config found. Where should worktrees be stored?

  [1] Global — ~/.config/opencode/worktrees/  (default, shared across all projects)
  [2] Local  — .opencode/worktrees/ inside this project

Reply with 1 or 2.

The plugin creates .opencode/worktree-config.json with your choice and proceeds. You can change the setting at any time by editing the file directly.

// .opencode/worktree-config.json
{
  "stateLocation": "global",
  "worktreesRoot": null,
  "repos": null
}

stateLocation

Controls where worktree state (sessions, worktree directories) is stored.

| Value | State file | Worktrees created at | |---|---|---| | "global" (default) | ~/.config/opencode/worktrees/repos/<repo-id>/ | ~/.config/opencode/worktrees/repos/<repo-id>/worktrees/<name-slug>/ | | "local" | <project>/.opencode/ | <project>/.opencode/worktrees/<name-slug>/ |

Use "local" if you want worktrees to live inside your project directory (e.g., visible in the same filesystem tree, or when you don't want global state):

{ "stateLocation": "local" }

Worktrees then appear at <project>/.opencode/worktrees/<branch>. Add .opencode/worktrees/ to your .gitignore.

worktreesRoot

Override where worktrees are physically created (relative to project root). Only applies when stateLocation is "local" or when you want a custom path.

{
  "stateLocation": "local",
  "worktreesRoot": ".worktrees"
}

Worktrees appear at <project>/.worktrees/<branch>.

repos (workspace mode only)

Explicitly list which repos to include instead of auto-discovering all git repos in the folder:

{
  "repos": {
    "frontend": "./frontend",
    "backend":  "./backend"
  }
}

Note: stateLocation: "local" is ignored in feature mode (/init-feature). Feature worktrees always use global state under ~/.config/opencode/worktrees/features/.


Important notes

node_modules is symlinked

When a worktree is created, node_modules is symlinked from the main repo root. This means:

  • No npm install needed per worktree — saves disk and time
  • If you install a new package in a worktree session, it installs into the main node_modules and is immediately available in all other worktrees
  • If the main node_modules does not exist yet, the symlink is skipped silently; run npm install in the main repo first

git hooks are shared between worktrees

All worktrees of a repo share the same .git/hooks directory. Installing owt hook --local or owt hook --worktree affects all worktrees of that repo, not just one. This is a git design decision, not a limitation of owt.

For per-repo isolation, use --local. For machine-wide isolation, use --global.

--no-verify bypasses all hooks

Running git commit --no-verify skips the commit-msg hook entirely. Co-authored-by will not be stripped. Avoid --no-verify unless intentional.

Branch locking

Git will refuse to checkout the same branch in two worktrees at the same time:

fatal: 'feature/WIN-123' is already checked out at '/path/to/worktree'

This is intentional and protects you from editing the same branch in two places.

State file

Display names and session metadata are stored in worktree-sessions.json. Its location depends on stateLocation:

  • global (default): ~/.config/opencode/worktrees/repos/<repo-id>/worktree-sessions.json
  • local: <project>/.opencode/worktree-sessions.json

If display names stop showing, check that this file exists and is valid JSON. See Configuration to change the location.


File structure

plugins/
└── worktree-plugin.js      OpenCode plugin — all tools + system prompt injection

command/
├── init-worktree.md        /init-worktree slash command
├── list-worktrees.md       /list-worktrees slash command
├── open-worktree.md        /open-worktree slash command
├── owt-current.md          /owt-current slash command
├── init-feature.md         /init-feature slash command (v4)
├── list-features.md        /list-features slash command (v4)
└── delete-feature.md       /delete-feature slash command (v4)

scripts/
└── owt.sh                  Terminal manager script (v2)

Requirements

  • OpenCode with plugin support (@opencode-ai/plugin >= 1.4.6)
  • git >= 2.5 (worktree support)
  • Node.js or Bun (for plugin runtime)
  • Python 3 (used by owt.sh for JSON parsing — pre-installed on macOS/Linux)
  • macOS or Linux