Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Base-branch picker

How the Base branch picker in the Start session dialog works: choosing which git branch a new session's worktree forks from and merges back into, where the dropdown appears, how the choice is remembered on the session, and the one boundary worth knowing about the auto-lander.

What it is

One line: When you start a new session, you can choose which git branch its worktree forks from — and that same branch is where the session's work merges back when it's done — instead of always branching off (and merging into) master.

What it does (user-visible)

Omniscio isolates most sessions in their own git worktree (a separate working copy on its own branch) so agents don't step on each other. Until now that worktree always started from the repo's current HEAD (normally master), and the session's work merged back into master when the session ended.

The base-branch picker adds one control to the Start session dialog: a Base branch dropdown. Pick a branch (say develop or a feature branch) and:

  • the new session's worktree is forked from that branch (it starts with that branch's code), and
  • when the session finishes and its work merges back, it merges into that same branch, not master.

Pick nothing and everything behaves exactly as before (fork from master, merge to master) — the default is byte-for-byte the old behavior.

Where to find it

Where it is

  • The Start session dialog (the one you get from the inbox "Start session" action). A Base branch dropdown appears below the Repo picker, but only once you've picked a project and that project has branches. It's a searchable dropdown that defaults to the project's current branch; a tooltip reads "The session forks from — and merges back into — this branch."
  • The branch list is fetched live from the chosen project's git repo (its local branches, current branch first). If the folder isn't a git repo, the dropdown simply doesn't appear — it never errors.

How it behaves

The one boundary to know

This is delivered entirely through Omniscio's in-app merge — the path interactive sessions already use when they end. The background auto-lander (which merges ready-to-merge-tagged branches) is deliberately left untouched.

So do NOT tag a base-branch session ready-to-merge. If you do, the auto-lander lands the branch to master (its normal, unchanged behavior) — and, critically, your chosen target then never receives the work at all. This is stronger than "the lander used the wrong target": once the lander has landed the branch, the later in-app merge is SKIPPED. executeMerge (worktree-merge-queue.ts) computes alreadyLanded = await isBranchDeliveredToBase(projectPath, branchName) — true when the branch has reached the base by ANY route — and short-circuits to a synthesized { success: true } without ever calling mergeWorktree, so the landTarget it just read is never used. The worktree is retired down the shared success path and the session is pushed as status: 'merged'.

Note which function that is, if you are debugging a skipped merge: isBranchDeliveredToBase is the cold-path delivery check. It trusts the branch's status: landed tombstone first and only then falls through to the auto-lander event ledger — deliberately, so a land by land:catch-up, merge-all-ready or safe-merge, none of which write an auto_lander_events row, still counts as delivered. The inner, ledger-only isBranchAlreadyLanded also still exists, so an empty auto_lander_events does not prove the skip could not have fired — read the tombstone too.

Net effect for exactly that combination: the UI reports success, and the branch you picked is never touched. The work is not lost — it is on master — but it is not where you asked for it. (The skip itself is correct in isolation: the lander replays commits with FRESH SHAs, so a plain git merge would FALSE-conflict on already-landed changes. What is missing is any handling of a landTarget that the land bypassed.)

An earlier version of this page — and invariant 5 of the contract — described this as "safe, just not the chosen target", which understated it. Landing into your branch happens via the normal session-end / Merge / CLI merge only when the auto-lander has not already landed the branch. Closing the gap properly is a lander/merge-queue behaviour change and is deliberately not taken here (contract invariant 5: "Do not re-solve this in the lander without an explicit decision").

Status & limits

  • Shipped for the Start session dialog. The Quick Launch composer picker and the CLI/API (baseBranch on POST /project/:name/new) are planned follow-ups.
  • Desktop + mobile (the picker reuses the standard searchable <Select>; the branch-list read is mobile-reachable).

For agents

How it works (for agents)

  • Fork point. createWorktree(projectPath, sessionId, sessionName, options) (src/main/services/worktree/worktree-service.ts), where the fork point is options.baseBranch — a field of CreateWorktreeOptions, alongside explicitTarget and provenance. It is NOT a 4th positional string. Pass a bare branch name in that slot and options.baseBranch is undefined, so the worktree silently forks from the repo's resolved head and the user's chosen base is ignored. (The options object replaced a positional list that had reached three, four and six arguments across three subsystems, precisely because a future insertion would mis-bind silently.) It validates the chosen ref (git rev-parse --verify) and passes it as the start point of git worktree add -b <branch> --no-checkout <path> <baseRef>. A bad/typo'd branch fails with a clear "Base branch not found" error, never a raw git dump. With no pick and no default branch resolving, it forks from HEAD, always passed as an explicit start point — with none, git guesses --orphan in an empty repository and dies against --no-checkout. A repository whose HEAD names no commit (brand new, or its .git damaged) is refused before any worktree exists with a clear "Nothing to branch from" error — base-branch-invalid (400) on POST /worktrees/create, never git's raw message — while any other failure of that check surfaces unchanged. And a create that succeeds is not a folder you can work in yet: on a busy box the route routinely answers 202 status: 'creating', and even its 200 carries a readinessWarning while node_modules keeps filling in behind the reply. Read it before you commit anything in the new folder.
  • Persistence. The chosen branch is saved on the session as land_target_branch (a nullable column; NULL = master/today) so the merge step later knows where to land.
  • Merge back. When the session's worktree merges (on session-end, the Merge action, or the CLI), the in-app merge queue reads that land target and merges into it via a ref-only advance — it updates refs/heads/<target> in git's object store and never touches a live working tree. If the target branch happens to be checked out in another worktree, it refuses (rather than corrupt that checkout) and reports it; a target branch that's gone is a harmless no-op.
  • Branch list IPC. PROJECT_BRANCHES_GET (project:branches-get) returns { branches, currentBranch } for a project; it's a read, safe to call from mobile.

The full invariants live in the repo's own base-branch-picker-contract.md (contributors only). The behavior that matters to a reader here: a base-branch session must not be tagged ready-to-merge, because the auto-lander would land it to base and the in-app merge into your chosen branch is then skipped.

Related

Base branches are one part of a session's git story: start-a-new-session.md covers the Start session dialog this picker lives in, session-land-status-strip.md shows where a finished session's branch sits in the auto-lander's queue, and auto-lander-dashboard.md is where the lander itself is watched, paused and resumed.

Last verified 2026-09-28