Skip to content

feat(native): add OMP settings integration - #89

Merged
wolfiesch merged 9 commits into
mainfrom
codex/native-settings-integration
Jul 28, 2026
Merged

feat(native): add OMP settings integration#89
wolfiesch merged 9 commits into
mainfrom
codex/native-settings-integration

Conversation

@wolfiesch

Copy link
Copy Markdown
Owner

What changed

  • Add an official OMP settings authority backed by the selected profile's config and agent database, including revision checks and masked provider secrets.
  • Grant paired native clients the config.write capability and expose a complete iOS/macOS settings surface for model roles, thinking level, approval mode, provider keys, connection details, and appearance.
  • Keep command-line dogfood credentials ephemeral so test launches never read, overwrite, migrate, or delete the developer's saved Keychain connection.
  • Preserve ordered live assistant, thinking, and tool-call streaming while the settings changes are integrated.
  • Clear stale endpoint failures after a later connection succeeds, preventing an obsolete transport error from remaining above a live inventory.

Why

The native settings pane previously exposed only a partial host-wire surface, while official OMP settings live across config.yml and agent.db. The client also treated settings metadata as bare values, could round-trip masked provider keys incorrectly, and kept connection failures in a global error slot indefinitely. This change makes the selected official OMP profile authoritative end to end and reconciles native connection state after recovery.

Impact

  • Settings reads and writes now target the explicitly selected official OMP profile, never ambient user configuration.
  • Provider secrets remain masked on reads and are merged per provider on writes.
  • Existing OMP CLI sessions remain runtime-authoritative; the native client observes them without taking control.
  • Successful reconnects remove superseded endpoint errors from the session rail.

Verification

  • pnpm check
  • pnpm --filter @t4-code/host-daemon test (17 passed)
  • pnpm --filter @t4-code/host-service test (473 passed, 1 skipped)
  • pnpm test:tooling (143 passed, 1 skipped)
  • pnpm test:maintainer (211 passed, 1 skipped)
  • pnpm test:cluster:ci (29 passed)
  • pnpm verify:official-omp-lifecycle
  • pnpm verify:official-omp-packaged
  • pnpm test:legacy-bridge-continuity against a clean OMP source checkout
  • node scripts/verify-ios.mjs (9 unit tests and 5 UI tests passed)
  • pnpm --filter @t4-code/mobile check:android:debug
  • Exact-head macOS dogfood against the existing live host, including a separate patched client reconnect with no CLI-session interruption

epsilver and others added 9 commits July 27, 2026 16:56
…yml + agent.db)

Reads modelRoles/defaultThinkingLevel/approvalMode/enabledModels and provider
keys (masked sk-…last4) from the real OMP stores; writes round-trip unknown
config.yml keys, upsert auth_credentials, and conflict on stale revisions.
config.read/config.write now implemented on official hosts.
…ance)

T4SessionStore: replace settingsWrite(key:value:) with settingsWrite(patch:)
— sends a partial settings object with expectedRevision, gates on
config.write, captures the new revision from the {written, revision}
result, and re-reads so masked providerKeys stay authoritative. Request
config.write at pair time so the pane's writes are authorized.

T4SettingsPane: rewrite into five sections against the live contract.
MODELS: per-role (default/smol/slow/vision/plan/designer/commit/tiny/
task/advisor) model selector dropdown from the catalog; current value
from modelRoles or 'default'. BEHAVIOR: defaultThinkingLevel picker
(off/minimal/low/medium/high/xhigh/max/auto) + tools.approvalMode picker
(always-ask/write/yolo). PROVIDERS & KEYS: masked rows per providerKeys
entry + an add-key sheet (provider + write-only SecureField) saved as a
single-key providerKeys patch (never echoes masked values back).
CONNECTION: endpoint, host info, wss leaf-cert fingerprint row with
Forget (T4CertPinner), disconnect. APPEARANCE: theme picker.

All writes go through settingsWrite(patch:) with revision; the pane
keeps a local optimistic snapshot mirror, applies mutations in place,
and reverts from the store on failure (lastError surfaced).
… effective

boundedSettings rejects bare scalar settings values (they hit the JSON
literal parser), so the authority now emits {type, effective} leaves and the
app store unwraps them back to raw values for the panes.
…nt on controls

The pane's insetGrouped List traded row hairlines for labeled cards (bg2,
12pt radius, faint border, padded rows). All pickers/buttons use
t.interactiveAccent — the user's system accent on macOS — leaving brand
color for meaning (status, roles, attention).
@wolfiesch
wolfiesch marked this pull request as ready for review July 28, 2026 00:49
@wolfiesch
wolfiesch merged commit c41e740 into main Jul 28, 2026
15 checks passed
@wolfiesch
wolfiesch deleted the codex/native-settings-integration branch July 28, 2026 00:49

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab909d864c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +39 to +40
const parent = dirname(sessionsRoot);
return basename(parent) === "agent" ? dirname(parent) : parent;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Derive settings paths from the selected OMP profile

In the checked official desktop launch, apps/desktop/src/lifecycle.ts:131 passes a T4-owned session path such as ~/.t4-code/host/official-sessions/default, while apps/desktop/src/local-profiles.ts:157-159 locates OMP profiles under ~/.omp/agent or ~/.omp/profiles/<id>/agent. Deriving the settings root from the unrelated session path therefore reads or creates config.yml and agent/agent.db under T4 host state instead of the selected OMP profile; settings appear empty, provider writes fail against a database without the OMP schema, and config edits never affect OMP. Pass the actual profile directory derived from profileId and the service's home instead.

AGENTS.md reference: AGENTS.md:L5-L5

Useful? React with 👍 / 👎.

Comment on lines +161 to +163
effective: Object.fromEntries(
Object.entries(keys).map(([provider, masked]) => [provider, { type: "string", effective: masked }]),
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return provider-key leaves in the shape the client consumes

When an official host has provider credentials, this wraps each provider value as {type, effective} inside the outer providerKeys metadata object. The new client unwrapping in T4SessionStore.unwrapSettingsMetadata strips only the outer layer, while T4SettingsPane.providerKeys() accepts only direct string values, so every existing key—and a newly added key after the authoritative re-read—is omitted from the Providers & Keys section. Make the nested effective map contain masked strings directly or recursively unwrap these leaves on the client.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants