workspaces
Skill9 starsChanged 4 days agoMITView on GitHub
Window and workspace patterns: BaseWindow + one WebContentsView per workspace (src/main/window), the folder owned by main per view, sessions and windows.json, the close/quit guard, dormant and hibernated views, viewActive gating and the welcome screen (recent folders, open many, open with prompt). Use when creating or reviewing code in src/main/window, ipc/workspaces.ts, ipc/window.ts, ipc/session.ts, workspaceLifecycle.ts or anything owned per view.
7 other projects use a version of this.
Adopted by
Most recently taken up by
- MosoFin/mosofin-llm-plugintheir own version, first seen Nov 15, 2026
- langchain-ai/open-swetheir own version, first seen Nov 8, 2026
- MosoFin/mosofin-mcp-plugintheir own version, first seen Oct 21, 2026
- MosoFin/mosofin-pluginstheir own version, first seen Oct 21, 2026
- stacksyncdata/skillstheir own version, first seen Oct 20, 2026
- wyattjoh/skillstheir own version, first seen Sep 27, 2026
Used with
Projects with it also use connections.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
stacksyncdataSkillconnections
Lists, creates, reads, renames, shares, reauthorizes and deletes Stacksync connections, reads the live tables and columns of a connected app, and explains network options and app rate limits. Use when someone wants to connect an app or database, a connection expired or needs reauthorization, a teammate cannot see a connection, a connection must be deleted, someone asks which tables or fields an app has, or a database sits behind a firewall or in a private network.
Also in 3 projects that use this
Other versions7 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 7
- langchain-ai/open-swe★ 11ksame name
- coder/skills★ 14same name
- MosoFin/mosofin-llm-plugin★ 3same name
- MosoFin/mosofin-mcp-plugin★ 3same name
- MosoFin/mosofin-plugins★ 3same name
- wyattjoh/skills★ 3same name
- stacksyncdata/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository17 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- app-testingSkill
- claude-panelSkill
- commands-settingsSkill
- containersSkill
- debuggerSkill
- files-git-searchSkill
- i18nSkill
- lspSkill
- main-ipcSkill
- main-processesSkill
- packaging-releaseSkill
- renderer-componentsSkill
- renderer-editorSkill
- renderer-storeSkill
- renderer-stylesSkill
- renderer-terminalSkill
The file
We split this skill into the rules it gives an agent
1 rule. 0 are common, 0 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 7 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 70
Never use BrowserWindow.fromWebContents/getAllWindows.
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Windows and workspaces (src/main/window)
The VIEW webContents is the unit of ownership: every per-view resource (watcher, ptys, LSP, Claude, docker, settings,
session) dies with it. Disposable resources (processes, ptys, managers, conversations) live in a
createViewRegistry from window/viewResources.ts (owner-checked get, automatic reset, has(wc) for eviction guards,
guardEpoch after an await); see main-processes.
The folder lives in main
- Each window's (= each workspace view's) folder lives in main (
window/windows.ts): assigned at creation (argv,windows.jsonrestore, Abrir Recente) or byworkspace.open;workspace.current()returns it on every call (a reload keeps the folder). - The same folder is never in two windows (
samePathfromshared/pathCompare.ts; the single path comparison of the repo, string-only (nonode:path):pathKey/samePath/isInside(root, path, { strict, caseSensitive, nfc… }), case-insensitive on macOS/Windows and NFC on macOS by default; the renderer'slib/path.tswraps it with a required platform, and itsisInsideis exact in case/Unicode because callers slice byroot.length); opening it focuses the owner. - Watchers, terminals and
files:listare scoped to the senderwebContents; ptys die on reload/close of their window. - The renderer serializes
workspace.opencalls (openChain) so main and renderer agree on the folder.
Sessions
- Sessions (
<userData>/sessions/<sha256>.json) are written by main (atomic; async normally, sync on destroy/quit); the renderer sends the last one frombeforeunload. - Pruning: the file name is a hash, so the folder cannot be recovered from it.
session/pruneRun.tsschedulePruneSessions()runspruneSessions()~30 s after startup (unref'd timer, sowalph <dir>and second-instance forwards are bound first; errors logged, never fatal). It lists the directory and deletes, through the puresession/prune.tsplanSessionPrune(files, recent, windows, live, now), the<sha256>.jsonfiles older than 90 days (SESSION_MAX_AGE_MS) whosesessionFileName(root)is not produced by anyrecent.jsonfolder, savedwindows.jsonworkspace or live workspace (allHosts()workspaces, dormant ones included). Each file isstated again right before thermand skipped if asession:savemade it young meanwhile. Other names in the directory are never touched. These are app state files, not user files, so a plainrmis used (the trash rule is for user content). - Scroll is stored as
topLine, never px (CodeMirror estimates unmeasured heights). - "Reopen Closed Tab" (
closedTabsin the store, pure stack inlib/closedTabs.ts, actionclosedTabActions.ts) is part of the session (closedTabs, at most 20, group as an index intoeditorGroups). Only user closes push to it (closeTabs,closeEditorGroupviarememberClosed, read before the commit so cursor/scroll are still live); tabs the session never keeps (commit diffs, Claude proposals) are skipped. A session tab is rebuilt withtabFromSession(tabActions.ts), shared with the session restore. windows.jsonkeeps the last window when it closes alone; it is frozen during a quit.
Closing and quitting
- Closing/quitting is guarded in main:
window/closeCoordinator.tsis the pure state machine (createCloseCoordinator(deps)),window/closeController.tsits Electron-bound instance (requestCloseWorkspace,onQuitCancelled,isViewResponsive,setDirty,confirmClose,cancelClose,installCloseCoordinator) andwindow/closeGuard.tsthe per-view guard;ipc/window.tsonly wires channels. While the renderer reportswindow.setDirty(true),closeis prevented and becomeswindow:closeRequested; the renderer answersconfirmClose()orcancelClose(). - A quit is vetoed in
before-quit(before any window closes), asking one dirty window at a time; cancelling reverts the windows already confirmed in that chain (window:closeAborted). - Process cleanup lives in
will-quit(notbefore-quit, which fires even when the quit is then cancelled). - Main frame navigation is blocked (
will-navigate), except same-URL reloads in dev.
Workspaces
- The host window is a
BaseWindow(no own webContents) and each workspace is aWebContentsViewrunning the whole renderer (window/windows.tsis the entry point; state inwindowState.ts, ready queues inviewDelivery.ts, close/hibernate inviewClose.ts,windowsPersistence.ts,openFolder.ts,restoreWindows.ts; pluswindow/workspaceViews.ts,ipc/workspaces.tswiring,window/openMany.tsfor "open many"). - The VIEW webContents is today's "window": every per-
webContentsowner (watcher, ptys, LSP, Claude, settings, session,setDirty,whencontexts, chords) is per view. - Anything sent to a view that may still be loading (
app:command,workspace:openRequested) goes throughdeliverCommand/deliverOpenRequest(window/viewDelivery.ts): sent when the renderer is ready (workspace:current), otherwise queued and flushed then. Neversend(wc, 'app:command', …)directly. - Never use
BrowserWindow.fromWebContents/getAllWindows; usewindowOf(wc)(dialog parents, menus). - Menu
app:commandgoes to the active view of the focused window; when that view is crashed/unresponsive,workspace.*commands run in main (window/workspaceCommands.ts:runWorkspaceCommandInMain,runWorkspaceCommandWhenUnresponsive). - Automatic reloads of a crashed renderer are capped by
window/reloadPolicy.ts(createReloadLimiter: 3 per 30 s per view, then it stays dead). Chord shortcuts are installed per view byindex.tson theviewCreatedworkspace event (installChordShortcuts(wc));windows.tsknows nothing about menus or keybindings. - Restored workspaces are dormant (no view) until activated.
- View webContents aren't destroyed with the window: they're closed with
close({ waitForBeforeUnload: true })(the renderer's finalsession:save) and force-closed after 3 s. - The close guard is per view with target
workspace | window | quit(chains ask one dirty view at a time, activating it silently; silent activation doesn'tmarkAllRead). - Activating a workspace marks all its Claude sessions read; main ignores
claude:markReadfrom inactive views and sendsnotifications:show(keyws:<id>:<session>) to the active view for sessions of inactive workspaces. windows.jsonv2 = per window{ workspaces: [{root, branch}], active }(v1 migrated).- The
WorkspaceBaris the title bar on macOS (titleBarStyle: 'hidden',--titlebar-inset); Windows/Linux keep the native frame. - A folder is unique across all workspaces of all windows (dormant included).
Many workspaces (performance pass)
- A hidden
WebContentsViewstill reportsvisibilityState === 'visible'(no Chromium background throttling); the renderer gates work onviewActive(store, fromisViewActive), never onvisibilitychange: inactive views accumulate watcher changes inlib/staleWork.tsand flush on activation (dirty-tab disk sync and a slow 3 s git refresh still run). - Inactive views hibernate back to dormant (
window/hibernation*.ts,workspaces.maxLiveViews/workspaces.hibernateAfterMinutes) unless an eviction guard (window/evictionGuards.ts: dirty, Claude running/attention/unread, terminal foreground process; any pty on Windows, clone/network git, pending start) keeps them; guards are rechecked right before closing. A guard returns a code ('unsaved' | 'closing' | 'unresponsive' | 'pendingRequest' | …, type inevictionGuards.ts) ornull; the code is for diagnostics and tests, never shown to the user. - Claude tabs + drafts persist in the workspace session and come back as
dormant:conversations woken withresume(never send adormant:id toapi.claude.*; React keys use the stabletabKey). - Main also idles out LSP servers (
lsp/idlePolicy.ts) and the Claude CLI (claude/conversation/idlePolicy.ts+run.tssleep/ensureRun, user-onlyclaude.idleSleepMinutes, default 0 = never: a relaunch drops the session's MCP servers;sendkeeps its ack ahead of CLI events). - The first
sendof every CLI process waits (≤ 15 s) until no MCP server ispending(waitMcpConnected,noticefor the ones still connecting). - The workspace tree watcher (
workspace/treeWatcher.ts, injectablesubscribe; real wiring inworkspace/viewWatchers.ts; opening a folder goes throughworkspace/openRoot.ts) is@parcel/watcher(chokidar 5 opens one fd per file on macOS). A second consecutive failure setsWorkspaceChange.watchError(translatedapp.errors.watchFailed, the renderer notifies) and the next activation retries. It honors onlyfiles.watcherExclude+ a fixed floor, neverfiles.exclude; events come back in the window folder's spelling andWorkspaceChange.fullasks the renderer to reload everything. - Terminal output is batched with ack flow control (
terminal.ack, pause only for the active view + 2 s watchdog). - Production renderer loads from
app://walph/(window/appProtocol.ts, V8 code cache) and is minified; heavy screens/libs areReact.lazy/dynamicimport(). - Session writes are async (
session/asyncWriter.ts, sync flush on destroy/quit).
Welcome screen
- The recent list lives in
recent/store.ts(getRecent,addRecent,removeRecentFolder,assertFolderOrForget,onRecentChange);ipc/recent.tsonly forwards changes asrecent:changed.recent.jsonv2 ={ folders: [{ path, lastOpened, branch }] }(v1 strings still read);workspaces.reportBranchalso updates the recent entry. workspaces.openManyreuses the empty active view for the first root (guarded per host); the window's "Abrir todos" memory (window/folderMemory.ts) only changes when the window gains a folder.workspaces.openWithPromptqueuesclaude:startRequestedper view and delivers it only after that view'sworkspace:openofrootfinished (dropped on folder change/failure); the renderer still waits forroot+ end of session restore beforeaskClaude(prompt, { reuseStart: true }).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

