All documentation

Git and review

How OpenOrc runs Git, creates worktrees, shows changes, applies work to your checkout, and publishes commits and pull requests.

Checked against the source on September 27, 2026.

How OpenOrc runs Git

The core runs your installed git and gh, found through the PATH from your login shell. Commands run with execFile, never through a shell, with these environment additions:

GIT_TERMINAL_PROMPT=0   # fail instead of waiting for a password prompt
LC_ALL=C                # stable, parseable output

Most commands have a 60-second timeout and a 64 MiB output limit. Some have their own:

CommandTimeout
git fetch20 seconds
git push120 seconds
git submodule update300 seconds
gh pr create60 seconds
gh pr view20 seconds
Per-turn diffs15 seconds, 8 MiB

OpenOrc never runs git stash, rebase, cherry-pick, gc, tag, or config, and never force-pushes.

Source: packages/git/src/exec.ts

Checkout or worktree

Each project conversation works in one of two places:

  • The checkout: your repository folder, on whatever branch you have checked out. This is the default. Agents edit the same files you do.
  • A worktree: a separate folder linked to the same repository, with its own branch. Its edits do not touch your checkout until you bring them over.

Workspace conversations work in any folder you choose, which does not need to be a Git repository. They have no worktree, commit, push, or pull request controls.

Worktrees

A worktree is created the first time a worktree conversation needs it. A task works in its execution conversation, so a task set to Worktree uses that conversation's worktree. Team assignments have worktrees of their own; see Agent teams.

Folder<profile>/worktrees/<project>-<id>/thread-<title>-<id>
Branchopenorc/<title>-<id>; the prefix is a project setting
Starting pointThe project's default branch, or the base branch a task names, after git fetch origin <branch>. OpenOrc uses origin/<branch> when the fetch works, and the local branch otherwise.
  1. git worktree add creates the folder and the branch. If the branch already exists, it is checked out instead.
  2. Files matching the project's include list are copied from your checkout: .env and .env.* by default, or the patterns in the repository's .worktreeinclude file when the project was imported. You can edit the list in the project's settings. OpenOrc does not check that a pattern stays inside the repository, so keep every pattern inside it: a pattern such as ../secrets copies files from outside.
  3. If the repository has submodules, git submodule update --init --recursive runs.
  4. If the project has a setup script, it runs with /bin/bash -lc, with OPENORC_WORKSPACE_PATH, OPENORC_ROOT_PATH, OPENORC_WORKSPACE_NAME, and OPENORC_PORT set. If it exits with anything but 0, that start fails. The worktree and branch are kept, and the next start uses them without running the script again.

A conversation's worktree stays, even when the conversation is archived, until you move the conversation to the checkout or delete it. Archiving a task never removes a worktree that a conversation uses.

Source: packages/core/src/services/workspace.ts, packages/git/src/worktree.ts, packages/core/src/services/projects.ts

Moving a conversation

A conversation's menu moves it between the checkout and a worktree of its own. A dialog first lists every file that will move. Moving does not start an agent.

From the checkout to a worktree

  1. OpenOrc reads the checkout's files as a Git tree through a temporary index: every uncommitted change, staged or not, and every new file that is not ignored. Every change in the checkout moves, whoever made it. What moves is each file as it is on disk: if you staged a different version of a file, that staged version does not move and is lost when the file is unstaged in the last step.
  2. A new worktree starts at the checkout's current commit, on a branch of its own. If a branch with the conversation's name already exists, OpenOrc adds a number to the new name instead of using that branch.
  3. Git writes the changed files into the worktree through a temporary index, so filters such as Git LFS and line endings apply. OpenOrc then checks that the worktree holds exactly those files.
  4. Only then do those files in the checkout go back to its last commit, and any staged versions of them are unstaged.

If anything fails before the last step, OpenOrc removes the worktree it created, and its branch while nothing was committed on it, and the checkout stays as it was. If a file in the checkout changed during the move, Git refuses to change the checkout, and both places keep a copy.

From a worktree to the checkout

The worktree's work since its starting commit, committed or not, merges into the checkout's current files. A file changed on only one side takes that side's version; a file changed on both sides goes through Git's builtin text merge. If Git cannot combine a file, nothing moves, and OpenOrc names the files. The result is written into the checkout through a temporary index, so your staged changes stay as they are and the moved changes arrive unstaged. The worktree is removed only if it still holds exactly what moved. Its branch stays, with any commits made on it.

A move is refused when it would carry a change to a submodule or a nested repository. Both directions read and write files through Git, so any file arrives whatever its size or name, with Git's filters, such as Git LFS and line endings, applied as in a checkout.

Source: packages/core/src/services/thread-moves.ts, packages/git/src/snapshot.ts (switchFiles), team-transfer.ts (mergeTrees)

Removing worktrees

Every way a conversation's worktree goes away keeps its uncommitted work:

  • Deleting a conversation commits any uncommitted changes to the worktree's branch first, with the pre-commit and commit-msg hooks skipped, then removes the folder. The branch stays. Ignored files, such as a copied .env, are not committed and are deleted with the folder. If that commit fails, for example because Git has no user name set, nothing is removed.
  • Moving a conversation to the checkout removes its worktree without a commit, because its changes are in the checkout by then. The branch stays.
  • Deleting a team conversation removes its team workspaces and deletes a branch only when its commits are merged or pushed. See Agent teams.

Source: packages/core/src/services/workspace.ts (cleanupThread, cleanup), packages/git/src/worktree.ts

Showing changes

The Changes panel shows a unified diff:

  • For a worktree conversation, against the commit the worktree started from, so it includes the agent's commits, staged and unstaged edits, and new files. "Show uncommitted" compares with HEAD instead.
  • For a conversation in the checkout, against HEAD. This shows every uncommitted change in the checkout, whoever made it.
  • For a task, the Changes tab shows its execution conversation's changes, compared as above.

Tracked files come from git diff -M. New files are added to a temporary index as intent-to-add and diffed from there, so your real index is untouched. New files over 1 MiB, and things that are not regular files, appear as a one-line placeholder in the diff instead of their content.

Each turn's changes are shown separately by comparing the checkpoints saved when turns end. A checkpoint is a Git tree object written through a temporary index, so it never touches your staging area.

Keeping it current

OpenOrc does not watch the file system. The Changes panel refreshes when an agent finishes a tool that can change files (at most once a second, and every 8 seconds while a turn runs), when a turn or background task ends, when a terminal command finishes, and when the window regains focus. Edits made in another app appear on the next refresh.

Source: packages/core/src/services/review.ts, packages/git/src/repo.ts, snapshot.ts

Checkpoints and restore

When a turn ends in a project conversation, OpenOrc saves its files as a Git tree, untracked files included, through a temporary index. A ref under refs/openorc/checkpoints/<conversation>/ pins each saved tree, so git gc never removes them. The refs last as long as their conversation; deleting it deletes them. A checkpoint also records the folder it was read from.

A restore, from the Checkpoints panel or a turn's Undo, works like this:

  1. In the Checkpoints panel, a dialog first lists the files that will change. Undo asks for a second click instead.
  2. The files as they are now become a checkpoint named "Before restoring", so the restore can itself be undone.
  3. Git changes the files through a temporary index: changes made since are undone, files created since are deleted, and ignored files are left alone. Staged changes stay staged. If a file changed after OpenOrc read it, Git refuses and nothing changes.
  4. The restored files become a checkpoint named "Restored", so the next turn's changes are shown against them.

A checkpoint restores only into the folder it was saved from, so after a move, move the conversation back to use it. Checkpoints saved before OpenOrc pinned them may already be gone if Git cleaned them up; a restore then says so.

Source: packages/core/src/services/threads.ts (restore), run-settlement.ts (checkpoint), checkpoint-refs.ts

Review comments

In a conversation's Changes panel you can comment on the diff. Click a line number to comment on one line, or drag or shift-click across line numbers in the same hunk to comment on a range. Comments are stored in review_comments with the file, the lines, the side of the diff, and the text of those lines. When those lines change later, the comment is shown as outdated. Comments written from a task's Changes tab also carry that task. Team conversations have no line comments.

Send, shown as "Send N to the conversation", queues one message in the conversation. It is delivered like any queued message, with the conversation's own agent, mode, and permission level. Sending also moves the tasks the comments carry back to in progress. Removing the message from the queue returns its comments to the review. The message lists every unsent comment:

Review comments on the current changes:

1. src/app.ts:42
   > const total = items.reduce((sum, item) => sum + item.price, 0);
   Use the shared helper here.

Address each comment. When a comment is wrong, say why instead of changing the code. Finish with a short list of what changed.

A range reads 10-12. A removed line has a minus sign, -12, and a range that includes one marks both ends, -10 to +12; the message then adds a line under its heading explaining the minus sign. Each comment quotes up to 20 of its lines.

Source: packages/core/src/services/review.ts (sendComments), packages/protocol/src/review-comments.ts, apps/desktop/src/renderer/src/panels/ConversationReview.tsx

Commit, push, pull request

No model writes commit messages or pull request descriptions for you. The commit message and the pull request description start empty. The pull request title starts as the conversation's title, which a model may have written (see Conversation titles), so read it before you confirm.

  • Commit runs git add -A, then git commit -m <your message>. Everything in the working folder is included, and your Git hooks run.
  • Push runs git push -u origin <branch>. When the remote has newer commits, OpenOrc says "origin has newer commits on <branch>. Pull them in first, then push again."; other failures show Git's own message. OpenOrc never retries with force.
  • Pull request runs gh pr create --title --body --base --head, if the GitHub CLI is installed. A conversation's branch must be pushed first. Without gh, a GitHub remote gets a button that opens GitHub's compare page in your browser, except for conversations that work in the checkout.

For conversations with an open pull request, OpenOrc checks its state with gh pr view <url> --json state about every 5 minutes, to show whether it was merged or closed.

Source: packages/git/src/publish.ts, packages/core/src/services/review.ts, lifecycle.ts

What OpenOrc writes to your repository

  • Branches for worktrees (openorc/…) and for the team preview (openorc/team-…).
  • Worktree registrations under .git/worktrees/, including a lock while a team assignment's agent runs in its own worktree.
  • Objects: trees and blobs for checkpoints and captures.
  • Refs under refs/openorc/ that keep them alive: checkpoints/ for as long as their conversation exists, thread-moves/ for the length of a move, exports/ (deleted right after an export), and, for the team preview, teams/, forks/, restores/, and moves/. Most of these refs point at trees, not commits, so git log --all does not show them. A capture also keeps a ref ending in /head on the commit its folder was on.
  • Config: git push -u sets the branch's upstream, and submodule setup records submodule URLs.
  • Remote-tracking refs from git fetch when a worktree is created.
  • Commits you make from the Changes panel, and the commit that saves a worktree's uncommitted work before OpenOrc removes it.

Moving a conversation, restoring a checkpoint, and deleting a conversation also change your files, commits, or branches, as the sections above describe. None of them changes your staging area except a move out of the checkout, which unstages the files it took.

OpenOrc installs no hooks and does not edit .git/info/exclude or .gitignore.