Skip to content

[FEATURE]: Configurable worktree creation — base ref, branch naming, repo-relative path #33332

Description

@StephanMeijer

Feature hasn't been suggested before.

  • I have verified this feature I'm about to request hasn't been suggested before.

Describe the enhancement you want to request

Worktree.create() in packages/opencode/src/worktree/index.ts hardcodes three behaviors that, taken together, prevent a common workflow:

  1. Storage location (line 339): Global.Path.data/worktree/<projectId>/<random>/ — worktrees always land under ~/.local/share/opencode/..., separate from the source repo. (Related: [FEATURE]: configurable path for worktrees #14032 — same concern, location only.)
  2. Base ref (line 345): git worktree add --no-checkout -b ${info.branch} ${info.directory} — new branches are created off HEAD of the primary worktree, with no git fetch first. There is no way to base a worktree on, say, origin/main.
  3. Branch naming (line 271): branch = opencode/<adjective>-<noun> — always auto-generated, always prefixed opencode/. No way to pass an explicit branch name like feat/login.

None of these can be customized via plugin today: the Hooks interface in packages/plugin/src/index.ts has no worktree.create.* hook. The only worktree-related signal a plugin can receive is the worktree.ready / worktree.failed events via the event catch-all — and by that point the worktree has been created at the wrong path, off the wrong ref, with the wrong branch name, and an Instance is already bound to the directory (line 375), making post-hoc relocation racy.

Motivation — concrete workflow

I want every new worktree to be:

  • created at <repoRoot>/.worktrees/<branch-as-slug>/ (consistent with .gitignore conventions; co-located with the repo for ephemeral containers, codespaces, IDE project trees)
  • based on a freshly-fetched origin/main, not local HEAD
  • on a user-supplied branch like feat/login, not opencode/cosmic-rocket

Clicking "Create new worktree" in opencode desktop should be all it takes.

Proposed design

Config schema additions (all defaults preserve current behavior):

{
  "worktree": {
    "storage": "data",     // "data" (default, current) | "repo" → "<repoRoot>/.worktrees/"
    "baseRef": "HEAD",     // default "HEAD" (current). e.g. "origin/main"
    "fetch": false,        // default false. true → `git fetch <remote>` before branching
    "naming": "random"     // "random" (default, current) | "explicit" — require `branch` on CreateInput, error if absent
  }
}

CreateInput extension (packages/opencode/src/worktree/index.ts):

export const CreateInput = z.object({
  name: z.string().optional(),
  branch: z.string().optional(),   // NEW — explicit branch name; takes precedence over auto-generation
  baseRef: z.string().optional(),  // NEW — per-call override of config.worktree.baseRef
  startCommand: z.string().optional(),
})

Plugin hook (extends #15680 — they propose worktree.created/removed/reset after-the-fact events; this adds a before hook for full extensibility):

"worktree.create.before"?: (
  input: { name?: string; branch?: string; baseRef?: string },
  output: { name: string; branch: string; baseRef: string; directory: string; fetch: boolean },
) => Promise<void>

Example — what becomes possible

// ~/.config/opencode/opencode.json
{
  "worktree": {
    "storage": "repo",
    "baseRef": "origin/main",
    "fetch": true,
    "naming": "explicit"
  }
}

User clicks "Create new worktree" in opencode desktop, supplies feat/login. Backend runs:

git fetch origin
git worktree add -b feat/login <repoRoot>/.worktrees/feat-login origin/main

The new branch tracks origin/main at fetch time, independent of local main state. .worktrees/ is added once to .gitignore (or ~/.config/git/ignore) and the convention is global.

Files that would change

  • packages/opencode/src/worktree/index.ts — creation logic, CreateInput shape
  • packages/opencode/src/config/... — schema (wherever worktree config lands)
  • packages/plugin/src/index.ts — Hooks interface
  • packages/app/src/components/session/session-new-view.tsx — UI input for branch name when naming: "explicit"

Related issues

Happy to implement

If the design is approved, I'll send the PR. Open to alternative shapes — e.g. a single worktree.create.before hook may be enough if maintainers prefer plugin-driven customization over new config knobs.

Activity

trin4ik commented on Jun 26, 2026

@trin4ik

I never stop being amazed by how developers from different parts of the world end up thinking along the same lines.

I was considering almost exactly the same architecture: something like ~/<project-path>/.worktrees/<branch-slug>, for roughly the same reasons:

  • .gitignore solves the Git-related issues, and IDE excludes solve the indexing problem.
  • It becomes easy to switch between worktrees in the IDE, while still seeing the whole project root with all worktrees.
  • With hacks like subvolumes in modern filesystems such as btrfs, worktrees can be created in a fraction of a second.

But for me, simply creating a worktree from opencode is not enough. I also need to create Docker networks, start containers for each worktree, create copies of databases/caches for those worktrees, and handle other infrastructure plumbing.

So overall I do not really have this problem myself, because I already do it through my own tooling — scripts in skills. But it would definitely be more convenient if there were hooks, especially with the ability to control the target directory. I would gladly shrink my skill quite a bit and move most of that logic into hooks.

devcxl commented on Jul 18, 2026

@devcxl

Looking forward to this being merged — it will solve a lot of the pain points I encounter when working on multiple features in parallel. It would be great to manage branches natively instead of relying on skills/plugins to orchestrate the workflow.


很期待这个功能被合并,能解决我在并行开发时遇到的很多问题。希望能原生管理分支,而不是每次都靠 skill 去控制分支工作流。

github-actions commented on Sep 18, 2026

@github-actions
Contributor

To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions