Shadow EditA VS Code extension for private, per-file editing while agents continue to use the real working directory. Shadow Edit is opt-in. It never changes Git branches, the index, hooks, or agent workflows. Install and launchRequires desktop VS Code 1.95 or newer. For development, use Node.js 22 or newer.
Open this project in VS Code and press F5 ( To produce an installable package:
In VS Code, run Extensions: Install from VSIX… and select Use
The status bar opens all session actions. Multiple files can have separate sessions. Start always creates a fresh session from the ordinary editor’s current text (including unsaved edits) and captures a new disk baseline. If a saved session already exists, confirm Start Fresh to archive the previous draft and replace it, or cancel to leave it untouched. Resume explicitly continues the saved private draft with its existing baseline. Starting again while already in that file’s shadow keeps the active session. Fresh sessions use distinct document URIs so VS Code cannot reuse an earlier buffer. Closing a private tab preserves its session; use Resume to reopen it. Starting with unsaved edits: these are copied to private storage before opening the shadow. The original dirty tab remains open because the public API cannot silently retarget or discard that buffer. Close the original tab and choose Don’t Save. Do not save that original buffer unless you intend to change the real file. Merging is blocked while an ordinary buffer for the target is dirty. AppearanceThe tint applies only to private Shadow document lines, including in split editors. The empty space below the document keeps the normal editor background. Diff and conflict-resolution editors keep their normal colors. Disable the tint with Shadow Edit: Editor Tint in Settings. High-contrast themes default to no tint. Customize If the tab badge is missing, check Keyboard shortcutsPress Cmd+K on macOS or Ctrl+K on Windows/Linux, release it, then press Shift + the letter. With Remote–SSH, use the shortcuts for your local VS Code client’s operating system.
Start and Resume are active in ordinary editable file editors, including remote files. Merge and Review shortcuts are active only in private Shadow editors. They do not apply in terminals, read-only views, or resolution documents. Save keeps its usual shortcut and saves privately; Apply Resolution and Discard have no default shortcuts. Customize these bindings in VS Code’s Keyboard Shortcuts editor by searching for “Shadow Edit”. ConflictsThe merge compares the start/last-merge baseline, your private text, and current disk contents, independently of Git HEAD. Nonoverlapping line edits merge automatically, including a replacement next to an insertion. Overlapping edits produce a private Resolution document with MINE / BASE / THEIRS markers. Edit that document into the complete desired result, remove the marker lines, and run Apply Resolution. Saving the resolution remains private. The native text editor and diff views are used; no undocumented Merge Editor API is required. Marker-like lines also block publishing if they were already in the source; remove them or use an ordinary manual workflow for such files. Cancel Merge returns to your shadow and retains the draft. Resume Resolution reopens it. A subsequent merge asks before replacing a prior draft and archives it first. If the original or your shadow changes during resolution, applying is blocked; run Merge & Stop or Merge & Continue again against current contents. No unresolved markers are written to the real file. Stop, suspend, and recover
Saved state survives restarts and extension-host crashes. Changes are also checkpointed on every document edit; a crash can still lose the last edits whose asynchronous checkpoint has not completed. Use Save to wait for persistence. VS Code's own dirty-editor recovery is an additional safeguard. Private session JSON files live in VS Code's workspace storage (global storage for an empty window), outside the repository. Each contains the baseline, private contents, original URI, language, timestamps, and any resolution draft with its disk snapshot. Writes are serialized, flushed, and atomically replaced. An active-host lock prevents ordinary simultaneous use of the same storage by two hosts. Open Recovery Storage opens the directory. If a file is renamed or deleted, the session remains recoverable; Shadow Edit does not guess its new location or recreate it. Restore the original path, or copy your private text to a file you choose. Workspace moves and storage/profile changes do not automatically migrate sessions. A malformed session stops loading and reports an error; files are retained for manual recovery. Concurrency guaranteesBefore publication the extension saves a recovery snapshot containing BASE, MINE, THEIRS, and RESULT. It writes a temporary result outside the repository, flushes it, rereads the target, and compares its contents and filesystem identity/timestamps. A mismatch aborts. It then atomically renames the temporary file over the target and checks the result. It does not truncate the real file or fall back to a non-atomic copy. This is optimistic concurrency, not atomic compare-and-swap. A noncooperating writer can change or replace the target between the final check and rename, or immediately afterward. An agent holding an old file descriptor can continue writing to the replaced inode. No standalone extension can eliminate those races. Recovery snapshots retain the versions observed by the extension, but cannot retain an unseen intervening write. If VS Code storage is on a different filesystem ( After merging, changes are ordinary working-directory edits. An agent's next Architecture and limits
API references used for the implementation:
The public API cannot change a TextDocument's URI in place. This extension opens a separate native text document. No documented public API accepts arbitrary BASE/MINE/THEIRS inputs for the native Merge Editor, so it uses supported diff commands and a private editable resolution instead. Tests
Core tests exercise merge boundaries and conflicts, newline handling, persistence/recovery, failed writes, cancellation state, raced publication, cross-filesystem fallback and cleanup, permissions, and real Git commits. Integration tests launch an isolated VS Code instance and exercise native documents, saves, languages, multiple files, duplicate start, agent commits, undo/redo, merge/continue, conflicts, cancellation, stale resolutions, suspend/resume, merge/stop, unsaved initial buffers, and baseline recovery across a full VS Code restart. By default the runner downloads VS Code; set |