Skip to content

Commit 584d35f

Browse files
committed
refactor(settings): remove Orbit hosted mode and deployment flag
1 parent 142b164 commit 584d35f

10 files changed

Lines changed: 32 additions & 117 deletions

File tree

docs/mobile-ios-cloudflare-blueprint.md

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ This document is the canonical implementation plan for shipping CodexMonitor on
3333
- Remote provider settings baseline is implemented:
3434
- `remoteBackendProvider`: `"tcp" | "orbit"`
3535
- `remoteBackendHost`, `remoteBackendToken`
36-
- `orbitDeploymentMode`, `orbitWsUrl`, `orbitAuthUrl`
36+
- `orbitWsUrl`, `orbitAuthUrl`
3737
- `orbitRunnerName`, `orbitAutoStartRunner`
3838
- `orbitUseAccess`, `orbitAccessClientId`, `orbitAccessClientSecretRef`
3939
- Orbit remote operations are implemented in app and daemon wiring via shared core:
@@ -45,7 +45,7 @@ This document is the canonical implementation plan for shipping CodexMonitor on
4545
- `orbit_runner_stop`
4646
- `orbit_runner_status`
4747
- Settings UI now includes Orbit provider setup/actions in `SettingsView`:
48-
- deployment mode, URLs, runner name, access fields, connect/sign-in/sign-out, runner start/stop/status
48+
- URLs, runner name, access fields, connect/sign-in/sign-out, runner start/stop/status
4949
- inline device-code polling flow wired to `orbit_sign_in_poll`
5050
- Remote notification forwarding currently handles only:
5151
- `app-server-event`
@@ -73,7 +73,7 @@ This document is the canonical implementation plan for shipping CodexMonitor on
7373
3. Orbit Cloud Services
7474
- Auth service (passkey + JWT/session).
7575
- Orbit relay (Worker + Durable Object routing + event persistence endpoint).
76-
- Optional hosted deployment path or self-host deployment path.
76+
- User-owned self-host deployment path only.
7777

7878
## Canonical Protocol Choice
7979

@@ -92,19 +92,9 @@ This document is the canonical implementation plan for shipping CodexMonitor on
9292
7. Orbit relays results and notifications back to subscribed iOS clients.
9393
8. On reconnect, iOS reloads state from thread resume + stored events endpoint.
9494

95-
## Orbit Deployment Modes
95+
## Orbit Deployment Model
9696

97-
## Mode A (Recommended): Hosted Orbit
98-
99-
Best setup UX for most users.
100-
101-
- User does not deploy Cloudflare services manually.
102-
- User authenticates in app, pairs device, and connects.
103-
- CodexMonitor stores only required client credentials/tokens in secure storage.
104-
105-
## Mode B: Self-Hosted Orbit
106-
107-
Advanced setup for users who want full control.
97+
## Self-Hosted Orbit Only
10898

10999
- User deploys Orbit/Auth workers and D1 with Wrangler.
110100
- User provides Orbit/Auth endpoints in Settings.
@@ -147,7 +137,6 @@ Implemented baseline fields:
147137
- `remoteBackendProvider`: `"tcp" | "orbit"`
148138
- `remoteBackendHost`
149139
- `remoteBackendToken`
150-
- `orbitDeploymentMode`
151140
- `orbitWsUrl`
152141
- `orbitAuthUrl`
153142
- `orbitRunnerName`
@@ -158,7 +147,7 @@ Implemented baseline fields:
158147

159148
Planned next (not yet implemented in settings model):
160149

161-
- deployment/auth/pairing metadata required for full hosted/self-host Orbit UX
150+
- deployment/auth/pairing metadata required for full self-host Orbit UX
162151
- secure-storage integration for secret material lifecycle (set/reset/rotation)
163152

164153
Keep secrets out of plain `settings.json` where possible.
@@ -260,11 +249,10 @@ Update `src/features/settings/components/SettingsView.tsx` to add an Orbit secti
260249
Required controls:
261250

262251
- Provider selector (`TCP daemon` / `Orbit`)
263-
- Deployment mode selector (`Hosted` / `Self-Hosted`)
264-
- Orbit WS URL input (self-host only)
265-
- Orbit Auth URL input (self-host only)
252+
- Orbit WS URL input
253+
- Orbit Auth URL input
266254
- Runner name input
267-
- Access auth toggle + client id input + secret set/reset (self-host optional)
255+
- Access auth toggle + client id input + secret set/reset (optional)
268256
- `Connect test` button
269257
- `Sign In` / `Sign Out` actions
270258
- `Start Runner` / `Stop Runner` buttons
@@ -276,7 +264,7 @@ Required controls:
276264
Current implementation status:
277265

278266
- Implemented now:
279-
- Provider selector, deployment mode selector
267+
- Provider selector
280268
- Orbit WS/Auth URL inputs
281269
- Runner name input
282270
- Access toggle + client id/secret ref fields
@@ -290,7 +278,6 @@ Current implementation status:
290278

291279
UX behavior:
292280

293-
- Hide manual endpoint fields in hosted mode.
294281
- Disable invalid combinations.
295282
- Show clear actionable errors (auth failed, runner offline, endpoint invalid, token expired).
296283
- Persist non-secret fields immediately.
@@ -299,7 +286,7 @@ UX behavior:
299286
## iOS client UX
300287

301288
- First launch setup:
302-
- `Sign In` (hosted) or endpoint-aware sign-in (self-host)
289+
- endpoint-aware sign-in (self-host)
303290
- `Scan QR` / `Enter pair code`
304291
- Recent sessions
305292
- Runtime status:
@@ -312,35 +299,13 @@ UX behavior:
312299

313300
## User Setup Flows
314301

315-
## Hosted Orbit (default)
316-
317-
Desktop setup:
318-
319-
1. Open CodexMonitor Settings.
320-
2. Set `Backend Mode = Remote`, `Provider = Orbit`, `Mode = Hosted`.
321-
3. Click `Sign In` and complete auth.
322-
4. Click `Start Runner`.
323-
5. Click `Show QR` (or `Copy Pair Code`).
324-
325-
Mobile setup:
326-
327-
1. Launch iOS app.
328-
2. Sign in.
329-
3. Scan QR (or enter pair code).
330-
4. App stores credentials in Keychain and auto-connects.
331-
332-
User-provided information:
333-
334-
- No manual URL/session entry required.
335-
- Only account login + pair action.
336-
337302
## Self-Hosted Orbit
338303

339304
Desktop setup:
340305

341306
1. Deploy Orbit/Auth services to Cloudflare.
342307
2. Open CodexMonitor Settings.
343-
3. Set `Backend Mode = Remote`, `Provider = Orbit`, `Mode = Self-Hosted`.
308+
3. Set `Backend Mode = Remote`, `Provider = Orbit`.
344309
4. Enter `Orbit WS URL` and `Orbit Auth URL`.
345310
5. Configure optional Access credentials.
346311
6. Sign in and start runner.
@@ -511,7 +476,7 @@ cargo test
511476
## Implementation Milestones
512477

513478
1. Milestone A: iOS compile baseline + mobile-safe stubs.
514-
2. Milestone B: Orbit integration baseline (hosted + self-host config paths).
479+
2. Milestone B: Orbit integration baseline (self-host config path).
515480
3. Milestone C: `remote_backend` transport refactor + Orbit WS transport + runner Orbit mode.
516481
4. Milestone D: daemon parity closure for mobile scope (excluding terminal/dictation).
517482
5. Milestone E: Settings UX/service manager + pairing UX.
@@ -521,7 +486,7 @@ cargo test
521486

522487
- iOS app can fully control a macOS runner via Orbit bridge.
523488
- Remote feature parity with desktop local mode for supported workflows.
524-
- macOS users can configure Orbit from Settings without terminal steps in hosted mode.
489+
- macOS users can configure Orbit from Settings using self-hosted Orbit endpoints.
525490
- Runner can be started/stopped/auto-started from app.
526491
- Reconnect/resync is robust and observable.
527492
- Build/install flow is documented and reproducible.

memory/decisions.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,10 @@ Type: decision
260260
Event: Split `SettingsView` into section-focused components plus a dedicated sidebar nav while keeping orchestration/state in the container.
261261
Action: Added `SettingsNav`, extracted section components under `src/features/settings/components/sections/*`, introduced shared settings types in `settingsTypes.ts`, and rewired `SettingsView.tsx` to modal shell + section routing.
262262
Rule: For large settings surfaces, keep `SettingsView` as layout/orchestration and move section UI into dedicated components with typed props.
263+
264+
## 2026-02-07 20:23
265+
Context: Orbit product scope canonicalization
266+
Type: decision
267+
Event: Product direction is now self-hosted Orbit only; app should not present hosted Orbit mode or imply CodexMonitor-hosted relay/auth services.
268+
Action: Removed `orbitDeploymentMode` from frontend/backend settings models and defaults, removed deployment mode selector from Settings UI, and updated mobile Orbit blueprint/setup language to self-host-only.
269+
Rule: Keep Orbit setup/docs/UI self-host-only unless user explicitly requests reintroducing hosted mode.

memory/todo.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# TODO
22

33
## Open
4-
- [ ] 2026-02-07: Implement Orbit-only mobile remote foundation: Orbit transport in `remote_backend`, runner Orbit mode, hosted/self-host settings + pairing UX, and iOS keychain-backed auth storage.
4+
- [ ] 2026-02-07: Implement Orbit-only mobile remote foundation: Orbit transport in `remote_backend`, runner Orbit mode, self-host settings + pairing UX, and iOS keychain-backed auth storage.
55
- [ ] 2026-02-07: Harden Orbit WS transport with explicit reconnect/backoff + replay/resync handling for mobile reconnect flows.
66
- [ ] 2026-02-07: Complete Orbit production readiness gaps after baseline wiring: secure secret storage (Keychain/keyring), LaunchAgent/background runner management, pairing QR/code UX, and app-side Orbit reconnect/resync handling.
77

src-tauri/src/settings/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,13 @@ pub(crate) async fn get_codex_config_path() -> Result<String, String> {
4141
fn should_reset_remote_backend(previous: &AppSettings, updated: &AppSettings) -> bool {
4242
let backend_mode_changed = !matches!(
4343
(&previous.backend_mode, &updated.backend_mode),
44-
(crate::types::BackendMode::Local, crate::types::BackendMode::Local)
45-
| (crate::types::BackendMode::Remote, crate::types::BackendMode::Remote)
44+
(
45+
crate::types::BackendMode::Local,
46+
crate::types::BackendMode::Local
47+
) | (
48+
crate::types::BackendMode::Remote,
49+
crate::types::BackendMode::Remote
50+
)
4651
);
4752
backend_mode_changed
4853
|| previous.remote_backend_provider != updated.remote_backend_provider

src-tauri/src/types.rs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,6 @@ pub(crate) struct AppSettings {
400400
pub(crate) remote_backend_host: String,
401401
#[serde(default, rename = "remoteBackendToken")]
402402
pub(crate) remote_backend_token: Option<String>,
403-
#[serde(default, rename = "orbitDeploymentMode")]
404-
pub(crate) orbit_deployment_mode: OrbitDeploymentMode,
405403
#[serde(default, rename = "orbitWsUrl")]
406404
pub(crate) orbit_ws_url: Option<String>,
407405
#[serde(default, rename = "orbitAuthUrl")]
@@ -654,19 +652,6 @@ impl Default for RemoteBackendProvider {
654652
}
655653
}
656654

657-
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
658-
#[serde(rename_all = "snake_case")]
659-
pub(crate) enum OrbitDeploymentMode {
660-
Hosted,
661-
SelfHosted,
662-
}
663-
664-
impl Default for OrbitDeploymentMode {
665-
fn default() -> Self {
666-
OrbitDeploymentMode::Hosted
667-
}
668-
}
669-
670655
fn default_access_mode() -> String {
671656
"current".to_string()
672657
}
@@ -1072,7 +1057,6 @@ impl Default for AppSettings {
10721057
remote_backend_provider: RemoteBackendProvider::Tcp,
10731058
remote_backend_host: default_remote_backend_host(),
10741059
remote_backend_token: None,
1075-
orbit_deployment_mode: OrbitDeploymentMode::Hosted,
10761060
orbit_ws_url: None,
10771061
orbit_auth_url: None,
10781062
orbit_runner_name: None,
@@ -1142,8 +1126,8 @@ impl Default for AppSettings {
11421126
#[cfg(test)]
11431127
mod tests {
11441128
use super::{
1145-
AppSettings, BackendMode, OrbitDeploymentMode, RemoteBackendProvider, WorkspaceEntry,
1146-
WorkspaceGroup, WorkspaceKind, WorkspaceSettings,
1129+
AppSettings, BackendMode, RemoteBackendProvider, WorkspaceEntry, WorkspaceGroup,
1130+
WorkspaceKind, WorkspaceSettings,
11471131
};
11481132

11491133
#[test]
@@ -1157,10 +1141,6 @@ mod tests {
11571141
));
11581142
assert_eq!(settings.remote_backend_host, "127.0.0.1:4732");
11591143
assert!(settings.remote_backend_token.is_none());
1160-
assert!(matches!(
1161-
settings.orbit_deployment_mode,
1162-
OrbitDeploymentMode::Hosted
1163-
));
11641144
assert!(settings.orbit_ws_url.is_none());
11651145
assert!(settings.orbit_auth_url.is_none());
11661146
assert!(settings.orbit_runner_name.is_none());

src/features/settings/components/SettingsView.test.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ const baseSettings: AppSettings = {
2525
remoteBackendProvider: "tcp",
2626
remoteBackendHost: "127.0.0.1:4732",
2727
remoteBackendToken: null,
28-
orbitDeploymentMode: "hosted",
2928
orbitWsUrl: null,
3029
orbitAuthUrl: null,
3130
orbitRunnerName: null,
@@ -679,7 +678,6 @@ describe("SettingsView Codex overrides", () => {
679678
);
680679

681680
await waitFor(() => {
682-
expect(screen.getByLabelText("Orbit deployment mode")).toBeTruthy();
683681
expect(screen.getByLabelText("Orbit websocket URL")).toBeTruthy();
684682
expect(screen.getByLabelText("Orbit auth URL")).toBeTruthy();
685683
expect(screen.getByLabelText("Orbit runner name")).toBeTruthy();

src/features/settings/components/SettingsView.tsx

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -831,18 +831,6 @@ export function SettingsView({
831831
});
832832
};
833833

834-
const handleChangeOrbitDeploymentMode = async (
835-
deploymentMode: AppSettings["orbitDeploymentMode"],
836-
) => {
837-
if (deploymentMode === appSettings.orbitDeploymentMode) {
838-
return;
839-
}
840-
await onUpdateAppSettings({
841-
...appSettings,
842-
orbitDeploymentMode: deploymentMode,
843-
});
844-
};
845-
846834
const handleCommitOrbitWsUrl = async () => {
847835
const nextValue = normalizeOverrideValue(orbitWsUrlDraft);
848836
setOrbitWsUrlDraft(nextValue ?? "");
@@ -1644,7 +1632,6 @@ export function SettingsView({
16441632
onCommitRemoteHost={handleCommitRemoteHost}
16451633
onCommitRemoteToken={handleCommitRemoteToken}
16461634
onChangeRemoteProvider={handleChangeRemoteProvider}
1647-
onChangeOrbitDeploymentMode={handleChangeOrbitDeploymentMode}
16481635
onCommitOrbitWsUrl={handleCommitOrbitWsUrl}
16491636
onCommitOrbitAuthUrl={handleCommitOrbitAuthUrl}
16501637
onCommitOrbitRunnerName={handleCommitOrbitRunnerName}

src/features/settings/components/sections/SettingsCodexSection.tsx

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,6 @@ type SettingsCodexSectionProps = {
6363
onCommitRemoteHost: () => Promise<void>;
6464
onCommitRemoteToken: () => Promise<void>;
6565
onChangeRemoteProvider: (provider: AppSettings["remoteBackendProvider"]) => Promise<void>;
66-
onChangeOrbitDeploymentMode: (
67-
deploymentMode: AppSettings["orbitDeploymentMode"],
68-
) => Promise<void>;
6966
onCommitOrbitWsUrl: () => Promise<void>;
7067
onCommitOrbitAuthUrl: () => Promise<void>;
7168
onCommitOrbitRunnerName: () => Promise<void>;
@@ -150,7 +147,6 @@ export function SettingsCodexSection({
150147
onCommitRemoteHost,
151148
onCommitRemoteToken,
152149
onChangeRemoteProvider,
153-
onChangeOrbitDeploymentMode,
154150
onCommitOrbitWsUrl,
155151
onCommitOrbitAuthUrl,
156152
onCommitOrbitRunnerName,
@@ -366,7 +362,7 @@ export function SettingsCodexSection({
366362
<option value="orbit">Orbit</option>
367363
</select>
368364
<div className="settings-help">
369-
Use TCP for host:port daemon access, or Orbit for managed/authenticated remote
365+
Use TCP for host:port daemon access, or Orbit for self-hosted Cloudflare relay
370366
sessions.
371367
</div>
372368
</div>
@@ -417,26 +413,6 @@ export function SettingsCodexSection({
417413

418414
{appSettings.remoteBackendProvider === "orbit" && (
419415
<>
420-
<div className="settings-field">
421-
<label className="settings-field-label" htmlFor="orbit-deployment-mode">
422-
Orbit deployment mode
423-
</label>
424-
<select
425-
id="orbit-deployment-mode"
426-
className="settings-select"
427-
value={appSettings.orbitDeploymentMode}
428-
onChange={(event) => {
429-
void onChangeOrbitDeploymentMode(
430-
event.target.value as AppSettings["orbitDeploymentMode"],
431-
);
432-
}}
433-
aria-label="Orbit deployment mode"
434-
>
435-
<option value="hosted">Hosted</option>
436-
<option value="self_hosted">Self-hosted</option>
437-
</select>
438-
</div>
439-
440416
<div className="settings-field">
441417
<label className="settings-field-label" htmlFor="orbit-ws-url">
442418
Orbit websocket URL

src/features/settings/hooks/useAppSettings.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ function buildDefaultSettings(): AppSettings {
2929
remoteBackendProvider: "tcp",
3030
remoteBackendHost: "127.0.0.1:4732",
3131
remoteBackendToken: null,
32-
orbitDeploymentMode: "hosted",
3332
orbitWsUrl: null,
3433
orbitAuthUrl: null,
3534
orbitRunnerName: null,

src/types.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ export type ReviewTarget =
116116
export type AccessMode = "read-only" | "current" | "full-access";
117117
export type BackendMode = "local" | "remote";
118118
export type RemoteBackendProvider = "tcp" | "orbit";
119-
export type OrbitDeploymentMode = "hosted" | "self_hosted";
120119
export type ThemePreference = "system" | "light" | "dark" | "dim";
121120
export type PersonalityPreference = "friendly" | "pragmatic";
122121

@@ -150,7 +149,6 @@ export type AppSettings = {
150149
remoteBackendProvider: RemoteBackendProvider;
151150
remoteBackendHost: string;
152151
remoteBackendToken: string | null;
153-
orbitDeploymentMode: OrbitDeploymentMode;
154152
orbitWsUrl: string | null;
155153
orbitAuthUrl: string | null;
156154
orbitRunnerName: string | null;

0 commit comments

Comments
 (0)