# Projects and tabs Closing project tabs, temporary workspaces, the new-instance launcher and the Git-unavailable degraded mode. ## Agent conventions - Closing a project tab detaches it immediately and requests deletion of that occurrence's logical backend workspace record; failures notify and never retry automatically. Separate occurrences of the same folder are independent. A `workspace.stopped` deletion closes the same record in other windows and notifies only windows displaying it that did not initiate the close. CodeNomad never evicts native Locations; OpenCode sessions keep running and reopening finds them. Whole-window close, app quit, renderer reload and backend shutdown keep existing restoration behavior. Temporary discard and server stop events use local-only tab detachment, not another DELETE; Keep closes the retained project normally. - Git is a full-functionality prerequisite, with directory-only degraded conversations when the backend cannot find Git. Only the explicitly opened physical folder is session authority in that mode; never infer sibling worktrees from native project IDs. Keep ancestor/descendant mutation identities covered by the deletion fence across Git availability changes. Inform agents through the owned native `codenomad.git-availability` instruction before prompts/custom commands, remove stale context after recovery, and keep this advisory separate from fail-closed environment synchronization. Do not add a blocking Git setup UI. Validate with `scripts/test-git-degraded-native.mjs` using an isolated CLI/database and provider. - Temporary instances (`workspaces/temporary-workspaces.ts`, UI `stores/temporary-instances.ts`) are ordinary non-Git workspaces on CodeNomad-created direct children of `/temporary-workspaces`. Registry membership (`temporary-workspaces.json`), not location, makes a folder temporary; keeping only unregisters it and adds a named recent project. Discard deletes only registered children of that root, refuses running conversations and other open tabs of the folder, removes conversations deepest-first, closes the workspace before deleting the folder and keeps failed removals registered; such a folder is reachable only by browsing to it. Closing a temporary tab from the UI asks Keep/Discard/Cancel, except that an untouched one (no conversation, file or unsent draft) closes and is discarded silently (`onlyIfEmpty`: the server refuses with `temporary_has_conversations`/`temporary_not_empty`, and any failure of that quiet discard returns the choice without an error). Before the server stops it, a visible temporary tab yields to its neighbour (or closes if alone) and a refusal restores it in place; `workspace.stopped` likewise closes the tab first and clears the instance in a microtask, because clearing a visible shell's state in the same update as its tab freezes the window. Same-minute names get a `(n)` suffix. Registry changes broadcast `workspace.temporaryChanged`, which clears kept marks in every window. Open temporary tabs are saved and restored with the app state like any project tab (still marked temporary). Only the choice dialog overrides initial focus (to its last, non-destructive choice); confirms keep focus on Cancel. Refusals use stable `temporary_*` codes localized by the client. Validate with `scripts/test-temporary-workspaces-native.mjs` against an isolated CLI. - The tab-bar new-instance button follows the last tab like a browser: the instance `TabScroll` frame only spans its tabs and the button sits after it, outside the scroller (so focusing it never scrolls the strip), ending up at the strip's end once tabs overflow. Dragged tabs stay visually within the tab list like a browser's (`KeepDraggedTabInStrip`), while the drop slot follows the pointer's unbounded position (`closestUnboundedCenter`). The button keeps its click (full home page, Cmd/Ctrl+N) while a long press, right-click, Alt+Down, Shift+F10 or Menu opens the anchored `NewInstanceLauncher` (`lib/long-press.ts`; only Escape returns focus to the button, never over another surface or the home page): search-first recent projects (an open project switches to its tab) and Browse/Temporary/Clone only. Remote servers, SideCar and management (rename/remove recents, servers, settings) stay on the home page. Browse/clone flows live once in `components/new-instance-dialogs.tsx` (with optional home-only add-server setup) and recent-folder display helpers in `lib/recent-folder-display.ts`, shared with `FolderSelectionView`; styles in `styles/components/new-instance-launcher.css`.