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

Unfinished work card (branches nobody is coming back for)

When a session goes away and leaves commits that never merged, this inbox card is where you find them and decide: pick the work back up, or let the folder go and keep just the branch. **It is retired — the daily maintenance report does this now.**

RETIRED 2026-09-30 — this card is no longer raised. Its job moved to the daily maintenance report, which judges the branches nothing can classify and names the ones worth a decision. The reason it went is measurable rather than a change of mind: 134 of the ~144 rows it listed offered only the paid-spawn button and no way to dismiss one, so it asked the owner about a pile he had no answer for — 26 times.

Everything below still describes the card, because the card, its readout and its ADOPT/DROP routes all remain in the product, and restoring one call brings it back. It is simply not raised. See leftover-branch-disposition-contract.md.

What it is

Every agent session works on its own branch in its own folder. When a session ends, closes or is archived before its work lands, that work is not lost — the branch still holds it — but nobody is coming back for it. This card lists every such branch, with how many commits it holds that the main branch does not.

The card covers every project you work in, not only the one you are looking at, so its branches are grouped into one fold per project. The heading names the project and says how many branches are inside it, and a project holding enough branches to fill more than a screen arrives folded shut — so one project's long list never buries another project's work behind it. Opening a fold shows the same rows and the same two buttons described below; nothing is hidden or left out, only folded.

A row comes in one of two kinds:

  • The folder is still on disk. The row shows where the folder lives.
  • "Folder reclaimed — branch kept". The folder was freed so the disk could be reused (freed folders are routine), but the branch was kept, and it still holds work that never merged. The old location is not shown, because another task may already be using that folder.

Saved Work lists work that was already rescued; this card lists work that has not been.

Where to find it

It appears in the inbox as "Unfinished work nobody is coming back for" whenever at least one such branch exists. Open it to see one fold per project; open a fold to see its rows, and each row has its own buttons.

On your phone the alert arrives as usual but the card itself does not: this list and both of its buttons live only in the desktop app, and the phone says so in one line instead of showing you a list it cannot read. Open Omniscio on your computer to see the folders and act on them.

How it behaves

  • Pick it back up starts one new agent session on that branch to finish the work. That costs money like any session, so it only ever happens when you click — and two clicks on the same row still start just one agent. On a "Folder reclaimed" row it first makes a fresh folder for the branch, then starts the agent there.
  • Let the folder go frees the folder's disk space. Any unsaved changes are saved to a recovery copy first, the save is checked, and the branch itself is always kept. This button is not offered on a "Folder reclaimed" row — that folder is already gone.
  • A row leaves the card by itself once its branch is picked back up (by you or anyone else), lands on the main branch, or is deleted. Opening the card never scans or changes anything.
  • Known limit. Right after a folder is freed, the folder pool can still hold the branch checked out for a while. Until the pool reuses that folder, "Pick it back up" says so and starts nothing; it works once the folder is reused.
  • How rows get here. A background check runs every 10 minutes and looks at recently freed folders (newest first, a limited batch each pass), so a freed branch appears within minutes, and older ones fill in over time.
  • Branches nobody ever asked to finish also appear here. When a session walks away without asking its work to be finished, that branch is held — nothing adopts, gates or lands it — and it is yours to complete or drop. It is named in your daily summary every day until you answer, and the same two buttons decide it here. Answering is permanent: the branch leaves both this card and the daily summary for good, and the answer is written onto the branch itself so nothing re-asks you. A branch whose folder was already freed shows no path, exactly like the reclaimed rows above, and "Let the folder go" is not offered because there is no folder left to free.
  • If a branch known to hold unlanded work disappears, you get a separate card — "A branch holding unlanded work is gone" — naming the branch, the last commit it was seen at, how many commits had not merged, where its folder used to be, which session owned it, and which repository it was in. A deleted branch is not necessarily gone for good: the Dev Pipeline panel — the same one that card's own button opens — carries a Restore a reaped worktree list, and where this branch is on it, one click there puts the branch back at the commit the card names. Only where it is not on that list is that commit id what you would search for, in that repository, before the objects are cleaned up for good. It only fires when the app had actually checked that the branch still held unlanded commits, so a branch that had already merged, been picked back up, or been deliberately released stays quiet.

For agents

  • Readout: listStrandedWork in src/main/services/worktree/stranded-work-readout.ts. Three arms: open rows with a stranded event; closed rows whose newest watch event is stranded-reclaimed; and the branches held for the owner's complete-or-drop decision. The badge count is backend-computed from the same rows.
  • Arm 3 (the held branches), and why it is a third source. They are not ledger rows — measured 2026-09-28, of 22 held branches only 2 had a live ledger row and 11 had no ledger row at all — so they cannot arrive as the events arms 1 and 2 are built from. The same hourly inventory that feeds the daily summary writes ~/.amc/held-branches.json (writeHeldBranchQueue, called from refreshHeldBranchDigest) and this arm reads it, so opening the card still spawns no git (I90 holds unchanged). A branch already carried by arm 1 or 2 is skipped: one row per branch. A row with no live folder is emitted as the existing reclaimed kind, which is what gives it the right reach with no new row kind and no new button.
  • Who is held, and the answer that ends it. ONE predicate decides it: isHeldForOwnerDecision in src/shared/land-core/rescue-hold.mjs, shared with the ops rescue that refuses to touch those branches. Both actions write owner-decided:<complete|drop> | <ISO> into the branch DESCRIPTION on success (after the spawn is confirmed / after the preserve is proven), and the predicate excludes it — neither action removes the branch, so without a durable mark on the branch the next pass would re-ask. isAnsweredByOwner is asked SEPARATELY by the ops rescue's partitionStranded, so an answered branch lands in neither its held nor its recoverable list.
  • worktreeId may be empty, and two writers respect that. writeReclaimedClearedMark writes no ledger event when the id is empty, and ADOPT's single-flight creatorFingerprint falls back to repo+branch — keyed on the id alone, every no-row branch would share one fingerprint and a second row's "Pick it back up" would silently do nothing.
  • Background watch: src/main/services/worktree/kept-branch-watch.ts, startup task 1521, pausable from the Resources diagnostics panel; off switch AMC_DISABLE_KEPT_BRANCH_WATCH=1 (default ON).
  • The watch never turns a git fault into an answer: a repo whose branch list cannot be read (the read failed, or came back empty) is skipped for that pass and counted as repos-unreadable; a landed proof that fails counts toward the three-strike repo-unreadable record. Branch names match regardless of case.
  • A record is about the branch it names. If the row's branch label later changes, the watch keeps checking the recorded branch. Known limit: an ops adopt that hands the row to a live session hides it from the card (never seen on the owner's box).
  • Actions: src/main/services/worktree/stranded-work-actions.ts (adoptStrandedBranch, dropStrandedFolder); a reclaimed row's DROP is refused as no-folder before any path is touched.
  • The loss alarm: src/main/services/worktree/lost-unlanded-branch.ts is the ONLY writer of a stranded-reclaimed-cleared event. It carries the record's tip into the clear instead of nulling it, asks git whether that tip is already on the integration branch before believing a branch-gone clear means loss, and raises the card. A structural guard fails the build if a new writer appears outside it.
  • Desktop-only, and the phone is told so (I99). STRANDED_WORK_LIST and both actions are in BLOCKED_CHANNELS (web-access-ws-channels.ts), so a paired phone's read returns the bridge's blockedChannelResult — success: false, code: FORBIDDEN. That refusal is NOT an empty population: until 2026-09-28 the card drew its empty state on it and told a phone "Nothing is stranded right now." on a box holding 115 stranded folders. AlertInboxViewer now mounts StrandedWorkDesktopOnlyNotice on a non-Electron client instead of the card — the same answer the mobile-device card gives. The gate is isElectron (the thing that actually decides), never a viewport width.
  • Contract: .claude/memory/contracts/stranded-work-triage-contract.md (I90–I99).

Related

Last verified 2026-10-01