Skip to content

Worktrees

A worktree is a second checkout of your repository: its own branch, its own folder under ~/.offsite-worktrees, its own agent. Your repository stays untouched while the agent works, and you can run three worktrees on three tasks side by side.

Two words come up everywhere: the base is the branch a worktree starts from (origin/main by default), the repository is your own checkout, the workspace the worktree was created from.

Every repository workspace gets a Worktrees column right of the board. Click a card to open the worktree as a board over the repository; click it again, the repository or any other card to get back.

Press + in the Worktrees column.

  • Task — explain what you want to fix or build. It becomes the agent’s first prompt. Without a task the agent waits for your first message.
  • Name — derived from the task, editable. The branch is offsite/<name>.
  • Base — the branch the worktree starts from, fetched first. Default: origin/HEAD.
  • Agent — Claude, Codex or Grok, with model and effort if you want them. YOLO lets the agent run without permission prompts.

The agent starts with a preamble that says where it is and what it may do: work only in its worktree, never touch your repository, never commit, push or merge unless the task says so. You review and commit through the Git card, and you finish from Offsite.

A worktree starts as a plain checkout. Everything git ignores is missing: node_modules, .env, build caches. Set up once what every worktree of this repository gets, in three stages: Prepare (copy and install before the agent starts), Run (what starts the app or tool of a worktree) and Clean up (free what a worktree created before it is deleted). The first time you press + in a repository without a setup, Offsite asks whether to set it up now; Not now keeps worktrees as plain checkouts, and the dialog keeps offering Set it up now… until you do. Later, Edit setup… in the dialog or Repository setup… in a worktree card’s menu opens the same editor.

The setup lives in two places. The host keeps a copy per repository: that is what runs, on every device connected to this host, and it works before anything is committed. The repository file .offsite/worktree.json is the shared copy: write it from the editor so teammates and a new machine start with the same setup. When both exist and differ, the host’s copy runs and the editor shows Compare… to take either side.

Every repository’s host copy at one place: Host Settings › Worktrees lists the repositories with a setup, a branch prefix or a “Not now”, with what each one copies and runs, how many worktrees it has and how much disk they take. Edit… opens the same editor, Forget drops the host copy, the prefix and the “Not now” answer. The card at the top shows the worktrees folder and its size; Leftovers lists folders in it that no workspace uses any more, each with Remove….

Paths git ignores that a fresh worktree needs. Each one is copied from your repository into the new worktree (a reflink clone on APFS, so it takes no time and no space). Click the tag on a row to switch between copy and link: a link points at the repository’s file, the right choice for .env and other secrets you never want duplicated.

Commands that run in order in a visible Setup card before the agent starts, for example npm ci. The card shows every step; if one fails, press Enter in the card to run the setup again. The agent starts only after the setup succeeded, and Offsite notifies you when a long setup finishes while you work elsewhere.

The steps that start what you work on in a worktree, in order; the last one keeps running: nvm use 22 then npm run dev -- --port $OFFSITE_PORT_BASE, a mobile app (flutter run, a build plus xcrun simctl launch), a CLI or TUI (cargo run), a watcher (npm test -- --watch). Run in the worktree header runs them on a Run card on the worktree’s board, in your login shell with the worktree’s environment, so shell functions like nvm work; a server takes its port from the worktree’s own window, so three worktrees serve side by side. Stop ends it, Enter in the card starts it again after it exits. The column card says Running while it goes. The worktree’s agent uses the same card: when it wants to try its work it starts the app through its worktree_run tool, on the worktree’s port, visible to you, and stops it when done.

Commands that run before a worktree is deleted: drop the database it created, stop its container, remove its build output or emulator snapshot. Delete worktree ends the Run card, runs the steps in the worktree with the same environment, then removes the folder. A step that fails keeps the worktree; the sheet shows the step, its exit code and the last lines of its output, and offers Delete anyway.

Not sure what the project needs? Press Set it up with an agent… in the editor, pick the agent, model and effort, and press Start. The agent gets a scratch worktree of the repository, works out how the project installs, runs the setup there and proposes all three stages: the paths and commands appear in the form under the terminal as it declares them. Ask for changes in the terminal, edit the lists yourself, then Save. The scratch worktree is removed, the setup is saved on this host, and the next page offers to write it to the repository. The agent has one job: it answers anything else with a pointer to the setup and never touches your repository.

Write to repository… shows what goes into .offsite/worktree.json and marks lines that probably work only on this machine: absolute paths, home paths, version-manager commands like nvm use, sudo. Keep those on the host or change them, then write. The file lands uncommitted in your repository; the Git card shows it, commit it with your next change.

The agent in a worktree has its own tools for all of this: it can read where the worktree stands, update from the base, publish, open a pull request, merge when you asked for it, and declare the setup it worked out. Say “publish and open a pull request” or “finish this” in the task or the chat and it uses those tools instead of raw git commands. Deleting a worktree stays with you.

Agent branches carry a prefix, offsite by default, so they stay recognizable on the remote and apart from yours. Change it in the setup; it is remembered per repository.

Setup commands and the agent get these variables: OFFSITE_WORKTREE_PATH, OFFSITE_WORKTREE_BRANCH, OFFSITE_SOURCE_CHECKOUT and a private port window OFFSITE_PORT_BASEOFFSITE_PORT_BASE_END, so parallel dev servers never collide.

The overlay board has its own +: add terminals, browsers, a simulator, Git and Files cards; they land on the worktree’s board. Notifications from a worktree’s agent open the worktree directly. The column card shows the agent’s state, the branch’s state and what happens next: Working, Needs you, Setup done, Ready to clean up.

Finish worktree opens the checklist: uncommitted changes, commits ahead of the base, whether the base moved, conflicts, the pull request and its checks. Every row that has a remedy carries it, and one button does the finishing:

  • Pull request — publishes the branch, opens the request on GitHub and merges it from Offsite once checks pass (squash, merge commit or rebase, as the repository allows).
  • Merge directly — fast-forwards the base branch to the worktree and pushes, when nothing diverged and your repository is clean.

If the base moved, Update from base merges it into the worktree. Conflicts go to the worktree’s agent with one click: it resolves them in place and commits the merge. A running agent is a warning to confirm, never a block. When the work is in the base, the checklist says Merged and offers Delete worktree.

Delete worktree in the overlay header or the card’s menu shows what would go: uncommitted changes, unpushed commits, whether the branch’s work is in the base, running sessions. The folder and the workspace are removed. The local branch is deleted when its work is proven to be in the base (a squash merge counts). Also delete it on origin removes the remote copy in the same step; it is pre-ticked only when the work is in the base and never touches a branch with commits the base lacks.