Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Target server settings by environment - #4559

Open
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings
Open

Target server settings by environment#4559
colonelpanic8 wants to merge 13 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/client-only-environment-settings

Conversation

@colonelpanic8

@colonelpanic8colonelpanic8 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Add one shared environment selector across General, Providers, Keybindings, Source Control, and Diagnostics settings.
  • Route server-backed settings to the selected environment while keeping client-only preferences in local client storage.
  • Use the active saved environment for global keybindings, provider updates, and server presentation when no primary environment exists.
  • Resolve new-thread defaults, worktree behavior, editors, and keybindings from the project or thread environment.
  • Incorporate per-environment provider configuration and environment-scoped diagnostics behavior.
  • Disable server-backed controls while the selected environment is disconnected.

Why

Client-only desktop mode deliberately has no PrimaryConnectionTarget, but several settings surfaces still read and wrote exclusively through primary-server atoms and hooks. Those controls therefore displayed defaults and silently failed to persist.

Settings now resolve an explicit selection first, then the managed primary environment, the active saved environment, and finally the first available environment. This preserves existing managed-client behavior while making client-only and multi-environment operation explicit.

UI Changes

  • General Settings now starts with a Server Settings environment row showing connection state and the selected environment.
  • Providers, Keybindings, Source Control, and Diagnostics use the same shared selection.
  • Client-local settings remain available when an environment is disconnected; server-backed controls are disabled until it reconnects.
  • Provider accounts and authorization state are shown only for the selected environment.

This PR is stacked on desktop-client-only-discovery, the branch behind #4444. It also carries the environment-scoped provider and diagnostics work needed by the complete settings flow.

Checklist

  • vp test run apps/web/src/components/settings/SettingsPanels.logic.test.ts apps/web/src/components/settings/DiagnosticsSettings.logic.test.ts apps/web/src/hooks/useSettings.test.ts — 31 tests passed
  • Targeted vp lint --report-unused-disable-directives for all changed files
  • vp run --filter @t3tools/web build
  • Integrated authenticated browser verification across General, Providers, Keybindings, Source Control, and Diagnostics
  • Confirmed assistant output, provider update checks, and the add-project base path persist through reload
  • vp run --filter @t3tools/web typecheck remains blocked by pre-existing unrelated errors in BranchToolbarBranchSelector, ModelPickerContent, PreviewAutomationHosts, and the atom command/query helpers

Note

High Risk
Touches desktop startup/shutdown, custom protocol static serving, and relaunch; web surfaces now depend on per-environment connection state instead of always-available primary server atoms.

Overview
Introduces a managed vs client-only desktop backend mode (--backend-mode, persisted backendMode, IPC + Connections UI). In client-only, startup skips the backend pool, registers the custom protocol as static (packaged renderer) or dev proxy, opens the window via handleRendererReady, and omits local bootstraps; shutdown skips pool teardown. Managed mode keeps proxying to the backend but drops the separate backendOrigin on protocol registration.

Electron protocol gains source: "proxy" | "static" with path-normalized static serving (SPA fallback, HEAD, traversal guards). Relaunch schedules the replacement process earlier, surfaces DesktopLifecycleRelaunchError, and setBackendMode rolls back settings if relaunch fails.

On the web side, server-backed settings (General, Providers, Keybindings, Source Control, Diagnostics) use a shared environment selector and useSettingsEnvironment / per-environment settings hooks instead of primary-only reads. Diagnostics is scoped to the selected environment with connection notices, disabled refresh when offline, and per-environment pending process signals. Chat, sidebar, and command palette stop using primaryServer* atoms for keybindings, providers, and config—useDefaultServerConfig and thread/project environment config drive defaults; remote thread labeling uses EnvironmentPresenceScope / ownsLocalEnvironment rather than comparing only to the primary id.

Reviewed by Cursor Bugbot for commit 13a79c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Scope settings panels and server config reads to target environment with desktop client-only mode support

  • Settings panels (General, Providers, Source Control, Keybindings, Diagnostics) now include an environment selector and scope server-side reads and writes to the chosen environment; controls are disabled when the selected environment is not connected.
  • Adds a client-only desktop backend mode that skips local backend startup, serves the renderer from either a dev proxy or packaged static assets, and hides local backend management UI.
  • New useDefaultServerConfig and useDefaultEnvironmentId hooks replace direct reads from primaryServer* atoms across sidebar, command palette, and chat components.
  • buildSidebarProjectSnapshots and remote-thread indicators now use isRemoteEnvironmentId with an EnvironmentPresenceScope instead of direct primary environment ID comparisons.
  • DesktopLifecycle.relaunch now propagates typed DesktopLifecycleRelaunchError failures to callers; setBackendMode rolls back settings when a triggered relaunch fails.
  • Risk: Components that previously read from global primary-server atoms now depend on per-environment config availability; surfaces will show defaults or be disabled when no environment is connected.

Macroscope summarized 13a79c6.

@coderabbitai

coderabbitaiBot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aad25f0c-63bf-47b6-98ec-13cf5784b5c5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 26, 2026
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/components/settings/KeybindingsSettings.tsx
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts
Comment threadapps/web/src/components/settings/DiagnosticsSettings.tsx
@macroscopeapp

macroscopeappBot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new "client-only" desktop mode that fundamentally changes how the app can operate - allowing it to run without managing a local backend. The changes span startup behavior, settings scoping, IPC contracts, and environment handling. Given this is a significant new feature affecting core app behavior, human review is warranted.

You can customize Macroscope's approvability policy. Learn more.

colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 26, 2026
# Conflicts:
#	apps/desktop/src/ipc/methods/backendMode.test.ts
#	apps/desktop/src/ipc/methods/backendMode.ts
#	apps/web/src/components/CommandPalette.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/SidebarV2.tsx
#	apps/web/src/components/settings/DiagnosticsSettings.tsx
#	apps/web/src/hooks/useSettings.ts
#	apps/web/src/routes/_chat.tsx
#	apps/web/src/state/environments.ts
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from bf1d0ee to d17eb8aCompareJuly 28, 2026 02:08
Comment threadapps/web/src/components/settings/SettingsPanels.tsx
Comment threadapps/web/src/hooks/useHandleNewThread.ts Outdated
Comment threadapps/web/src/components/AppSidebarLayout.tsx
Comment threadapps/desktop/src/ipc/methods/backendMode.ts Outdated
Comment threadapps/web/src/components/settings/SettingsPanels.tsx Outdated
Comment threadapps/web/src/state/entities.ts

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb4f20. Configure here.

Comment threadapps/web/src/state/entities.ts
colonelpanic8and others added 13 commits July 27, 2026 19:47
Let the desktop app run as a pure client for remote or independently
managed backends, instead of always owning a local backend process.
- Add a persisted `managed` / `client-only` backend mode with a
launch-only `--backend-mode` override, exposed over IPC.
- In client-only mode, bootstrap skips the backend pool entirely and
serves the renderer from packaged static assets (or the dev proxy),
opening the window on renderer readiness rather than backend
readiness, and skipping backend shutdown on quit.
- `ElectronProtocol` takes an explicit `source: "proxy" | "static"`.
Static serving adds path-safe file resolution, SPA fallback, MIME
types, CSP and HEAD support.
- Web routing treats client-only like hosted static, and local
environment bootstraps are empty, so a client-only desktop is never
stranded on a dead primary-backend state.
Co-Authored-By: Claude <noreply@anthropic.com>
The sidebar decided a thread or project was remote by comparing its
environment against the primary environment id. A client-only desktop
(and the hosted static web app) never registers a primary, so that id is
always null and every row read as local: no cloud/server icon, and no
environment name on the project header.
Make the comparison explicit about the two different meanings of a null
primary id. `isRemoteEnvironmentId` now takes an `ownsLocalEnvironment`
flag: when the app can never serve an environment from its own backend,
every environment is remote; when it can, a null primary id still means
"the local backend has not registered yet" and nothing is flagged remote.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The diagnostics environment picker made three pieces of panel-local state
lie about which machine they belong to:
- `openLogsDirectoryError` / `isOpeningLogsDirectory` kept showing an
environment A failure (or spinner) after switching to environment B.
They are now stored together with the environment they belong to, so
they only render for that environment and a late completion can only
update its own request.
- `signalingPid` was a single shared value, so completing a signal on
environment A re-enabled the signal controls for an in-flight signal on
environment B and allowed a duplicate SIGKILL. Pending signals are now
identified by environment id plus pid.
- Diagnostics queries only run while the selected environment's
supervisor is connected, so a disconnected machine showed permanent
"Loading..." placeholders with the refresh buttons disabled. The panel
now derives a connection notice and renders it instead of the loading
state.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follow-up to the review feedback on the previous commit:
- `DiagnosticsRefreshButton` used a single `isPending` prop for both the
spinner and `disabled`, so suppressing the spinner while the selected
environment is disconnected also made the button clickable even though
the query cannot run. It now takes an explicit `isDisabled` prop.
- The open-logs completion matched on environment id alone, so returning
to an environment and starting a second open while the first was still
in flight let the older completion clear the newer pending state. The
completion now matches the request by identity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@colonelpanic8
colonelpanic8force-pushed the t3code/client-only-environment-settings branch from 0f957cc to 13a79c6CompareJuly 28, 2026 02:51
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@colonelpanic8