Electron desktop shell for a single-window dual-partner coding/review loop with an explicit Windows-host / WSL-workspace backend split.
- Left plane: Codex work companion chat surface.
- Middle plane: workflow control plane, not a chat.
- Right plane: ChatGPT review/world-model thread surface.
The shell remains the source of truth for project bindings. Each project stores:
- project name
- typed workspace binding
- Codex target/binding
- project-bound ChatGPT thread deck
- FlowProfile metadata: prompt templates, watched file patterns, return header
Current implementation baseline:
- Explicit
workspace.kindin project config:local,windows, orwsl. - WSL-native workspace config fields: distro + canonical Linux path.
- Resident backend session manager in the Electron host.
- WSL backend agent at
src/backend/wsl-agent.js. - Newline-delimited JSON protocol over stdio.
- Work tree and file preview now route through the workspace backend.
- Command execution scaffold, watched artifact scanning, and watcher scaffolding are present in the backend protocol.
- Existing three-plane geometry and maximize/restore reflow fix are preserved.
- Existing ChatGPT embedding/chrome reduction behavior is preserved.
Current workflow surfaces:
- Direct Workbench project directory plus revision-bound create/edit binding dock for project identity, substrate, and default runtime.
- Project-bound ChatGPT thread deck instead of one hard-coded review URL.
- Thread roles: review, brainstorming, architecture, research, debugging, planning, custom.
- Add/edit/remove/archive thread bindings per project.
- Primary review thread and last-active thread tracking.
- Role-aware prompt templates with placeholder interpolation.
- Manual/copy-assisted handoff queue.
- Watched artifact scan through the workspace backend with preview/stage/ignore actions.
For WSL projects on Windows:
Native Windows Electron host
⇄ stdio JSON protocol
wsl.exe-launched resident backend agent
⇄ Linux filesystem
Canonical WSL workspace path
The app does not use \\wsl$ browsing as the primary architecture. UNC paths may be recognized during migration or used as fallback display values, but WSL workspace truth lives on the Linux side.
Example WSL project:
{
"name": "Example Project",
"repoPath": "wsl:Ubuntu:/home/me/example-project",
"workspace": {
"kind": "wsl",
"distro": "Ubuntu",
"linuxPath": "/home/me/example-project",
"label": "Example Project in WSL"
},
"surfaceBinding": {
"codex": {
"mode": "local",
"target": "codex://local-workspace",
"label": "Local Codex lane"
},
"chatgpt": {
"reviewThreadUrl": "https://chatgpt.com/",
"reduceChrome": true
}
},
"chatThreads": [
{
"id": "thread_review_primary",
"role": "review",
"title": "Primary review",
"url": "https://chatgpt.com/c/...",
"isPrimary": true,
"pinned": true,
"archived": false
}
],
"activeChatThreadId": "thread_review_primary"
}Example local/dev project:
{
"workspace": {
"kind": "local",
"localPath": "C:\\path\\to\\repo",
"label": "Local workspace"
}
}From PowerShell or Windows Terminal:
cd codex-review-shell
npm install
npm run startThe two primary experiences now have explicit launch and control-plane identities. Direct Workbench preserves the conventional thread-first Codex workflow using the T3-informed project/thread geometry:
npm run dev:direct-workbenchWorldManager Studio retains the semantic settlement, admission, and worldstate path:
npm run dev:world-manager-studioThe normal legacy shell remains the default npm run dev compatibility path.
Direct Workbench currently connects a main-owned project directory, a
runtime-neutral project-scoped thread directory, thread intake, Runtime, and
Analytics surfaces. The thread directory normalizes Direct and App Server
inventories without exposing raw workspace paths or provider cursors. Project
switching shows the configured WSL/Windows/local substrate and runtime before
activation. Files, Diff, Terminal, and Browser remain visibly unavailable until
bounded Direct tenant adapters exist. See the
experience split spec
project directory spec, and
thread directory spec.
Direct implementation threads have one access setting, chosen from the composer's Access menu. It applies to the current thread and becomes the default for new threads in that project:
- Read only: reads files and runs commands in a sandbox with no network. It can't change files.
- Workspace: changes files and runs commands inside the project folder
(plus
/tmp), with the network off. - Full access (default): no sandbox.
None of the modes ask for approval on each tool call. Actions outside the
selected mode are refused with a message telling the user to switch Access.
Workspace and Read only run commands under bubblewrap (bwrap), so they need
Linux with unprivileged user namespaces. Where no sandbox is available, those
modes refuse to run commands rather than running them unsandboxed. Access
can't change while a turn is running. npm run direct:access-profiles covers
this behavior.
For everyday use, run a tagged release instead of the mirror. Versions are
installed side by side under C:\LexLattice\direct-workbench
(CODEX_REVIEW_SHELL_RELEASE_ROOT); starting the app never changes them.
First install (the newest v* tag of the WSL checkout):
node \\wsl.localhost\Ubuntu\home\rose\work\LexLattice\codex-review-shell-direct\scripts\release-install.mjsThen, from C:\LexLattice\direct-workbench:
start-direct-workbench.vbs(or.cmd): starts the current version, or brings it to the front. Point the desktop shortcut here.update-direct-workbench.cmd [TAG]: installs the newest tag (or TAG), switches to it, and restarts the app on it.rollback-direct-workbench.cmd: switches back to the version before.update-direct-workbench.cmd --list: installed versions and tags.
To release, tag a commit on main (git tag v0.5.1 && git push origin v0.5.1) and run the update. The installed app and the mirror share the default profile, so each launcher first asks the other's running app to quit. Three versions are kept: the current one, the previous one, and the most recently used other.
Only one installer may update a release root at a time; a second update or rollback refuses while it is busy. Locks from an exited installer are recovered on retry, including when its PID has been reused: ownership also records the process start identity (and boot identity on Linux). Unavailable identity metadata preserves existing ownership. A release launch whose profile channel does not answer uses that profile's single-instance lock; it does not stop other profiles' Electron processes.
While building, use the tracked Windows launcher scripts in this repo so the Windows checkout mirrors the WSL worktree before each run:
cd C:\LexLattice\codex-review-shell-direct
.\start-codex-review-shell.cmdWhat it does:
- checks whether the WSL worktree differs from the mirror (
sync-from-wsl.cmd /check, which copies nothing) - asks the app already running from this folder what it runs (
scripts/app-control.mjs, over a local named pipe): when nothing changed and it runs the same experience and synced code, the launcher brings it to the front and stops there, with no restart; otherwise the running app quits the ordinary way (ordered shutdown), and is force-stopped if it doesn't within 20 s - first asks the installed daily app (see above) to quit when it runs on the same profile
- mirrors
\\wsl.localhost\<distro>\<path>to the Windows repo root viasync-from-wsl.cmd - runs
npm installonly whenpackage.jsonorpackage-lock.jsonchanged, or when the Windows dependency installation is incomplete - writes
.wsl-sync-head.txtin the Windows repo with the mirrored WSL commit hash, and.sync-generation.txt, which changes whenever a sync changes files or dependencies - writes a timestamped log pair under
%LOCALAPPDATA%\codex-review-shell-direct\launcher-logsand records the newest pair inlauncher-latest.txt - prints the active preflight stage in the launcher console
- starts
node_modules\electron\dist\electron.exedirectly (scripts/run-electron.mjsonly when it is missing)
Default source path is /home/rose/work/LexLattice/codex-review-shell-direct in Ubuntu.
Override source by setting:
CODEX_REVIEW_SHELL_DEFAULT_WSL_DISTROCODEX_REVIEW_SHELL_DEFAULT_WSL_PATH
If your Windows checkout predates these scripts, copy these tracked files from WSL once into C:\LexLattice\codex-review-shell-direct:
start-codex-review-shell.cmdstart-direct-workbench.cmdstart-world-manager-studio.cmdstart-world-manager-studio-mock.cmdstart-codex-review-shell-t3.cmdsync-from-wsl.cmd
To attach to a WSL workspace, edit the project binding:
- Workspace kind:
WSL workspace - WSL distro:
Ubuntuor your distro name; blank means WSL default - Canonical Linux path:
/home/<you>/<repo>
Node.js must be available as node inside that WSL distro.
Ordinary Direct implementation turns can use an asynchronous native reasoning pool independently of the WorldManager path. It defaults to eight active child leases and 64 queued jobs, and permits full, recent-N, or empty parent-context handoff independently from child model and reasoning effort.
Optional process-level overrides:
CODEX_DIRECT_SUB_AGENT_MAX_ACTIVE
CODEX_DIRECT_SUB_AGENT_MAX_QUEUED
CODEX_DIRECT_SUB_AGENT_DEFAULT_MODEL
CODEX_DIRECT_SUB_AGENT_DEFAULT_REASONING_EFFORT
See the Direct native multi-agent pool spec for the current reasoning-only authority boundary and test commands.
Syntax check:
npm run check:syntaxThe files each check:*-syntax script covers are listed in
scripts/syntax-check-groups.json (check:syntax is group all); add a new
file there, not to package.json.
Full bounded validation path:
npm run validateHeadless Electron smoke remains available on Linux environments that have xvfb-run:
npm run smokeChatGPT is embedded as the real web thread surface. There is no assumed official consumer ChatGPT API for sending messages to an existing thread or uploading files. Chrome reduction, dark-mode forcing, and settings access are best-effort browser-surface behavior.
For the WSL architecture note, see WSL_HOST_ARCHITECTURE.md. For the v1.2 product-boundary/workflow pass, see DUAL_PARTNER_WORKFLOW_SHELL_v1.2.md.