Skip to content

[codex] add configurable automatic git fetch interval#2605

Merged
juliusmarminge merged 11 commits intomainfrom
t3code/bf29617b
May 8, 2026
Merged

[codex] add configurable automatic git fetch interval#2605
juliusmarminge merged 11 commits intomainfrom
t3code/bf29617b

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented May 8, 2026

Summary

Adds a Source Control setting for configuring the background Git fetch interval. The default remains 30 seconds, and setting the interval to 0 disables automatic fetches while preserving explicit Git actions.

What changed

  • Replaced the unshipped automaticGitFetches boolean with automaticGitFetchInterval, stored as an Effect duration setting with millisecond JSON encoding.
  • Added a Fetch interval number field to the Source Control settings page, with 0 seconds shown as disabled.
  • Routed VCS status subscriptions through the configured interval so passive remote refresh polling can be slowed down or disabled before it reaches git fetch.
  • Set SSH_ASKPASS_REQUIRE=never on background upstream status fetches so OpenSSH askpass dialogs are not triggered by passive refreshes.
  • Kept explicit user-triggered Git operations such as pull, push, and PR branch fetches unchanged.
  • Updated settings merge/persistence handling so duration settings are merged atomically and persisted in encoded form.
  • Included the setting in restore-defaults behavior and added status broadcaster coverage for the disabled path.

Why

Background git fetch can trigger SSH agent, passphrase, Touch ID, security-key, or Windows GCM prompts for users with secure Git setups. Making the interval configurable lets users reduce that background activity, and 0 lets those prompts happen only on explicit Git actions. The OpenSSH SSH_ASKPASS_REQUIRE=never guard also prevents passive refreshes from opening askpass UI when a fetch still runs.

Closes #356
Closes #1190
Closes #1418
Closes #1467
Closes #1965
Closes #2285

Refs #1921

Validation

  • bun fmt
  • bun lint (passes with existing warnings)
  • bun typecheck
  • bun run test --filter=t3 -- src/vcs/VcsStatusBroadcaster.test.ts
  • bun run test --filter=t3 -- src/vcs/GitVcsDriverCore.test.ts
  • bun run test --filter=t3 -- src/serverSettings.test.ts
  • bun run test --filter=@t3tools/web -- src/rpc/wsTransport.test.ts
  • bun run test:browser src/components/settings/SettingsPanels.browser.tsx
  • bun run test:browser src/components/ChatView.browser.tsx
  • bun run test:browser src/components/KeybindingsToast.browser.tsx
  • bun run test:browser

Note

Medium Risk
Touches server settings normalization/persistence and VCS background polling behavior; misconfiguration could change remote status refresh cadence or settings serialization, but the change is scoped and covered by tests.

Overview
Adds a new ServerSettings.automaticGitFetchInterval (default 30s, 0 disables) and threads it through the subscribeVcsStatus WebSocket flow so background remote status refresh/polling respects the configured interval.

Updates Git background upstream fetches to run with SSH_ASKPASS_REQUIRE=never to avoid triggering askpass prompts during passive refreshes, and extends the Source Control settings UI with a per-Git collapsible “Fetch interval” control (including reset-to-default behavior).

Refactors settings patching/serialization to round-trip normalize settings via schema encode/decode, persist sparse settings via schema JSON encoding, treat automaticGitFetchInterval as an atomic key, and broadens string normalization by making TrimmedString trim on both decode and encode (with test updates to expect encoded wire shapes).

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

Note

Add configurable automatic Git fetch interval to server settings

  • Adds automaticGitFetchInterval (default 30s) to ServerSettings and ServerSettingsPatch in settings.ts, stored as DurationFromMillis.
  • Exposes a UI in SourceControlSettings.tsx to view, adjust, and reset the fetch interval, with collapsible Git details row.
  • WS RPC layer in ws.ts reads the interval from ServerSettingsService and passes it to VcsStatusBroadcaster.streamStatus, falling back to the default on read failure.
  • Background remote refresh in VcsStatusBroadcaster.ts can now be disabled by passing Duration.zero and uses the configured interval per subscription.
  • Background fetch runs with SSH_ASKPASS_REQUIRE=never via a new env override in GitVcsDriverCore.ts to prevent interactive prompts.

Macroscope summarized 8c99160.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

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

Run ID: a8142f3b-71c8-431b-bb02-6e809c80d787

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
  • Commit unit tests in branch t3code/bf29617b

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

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels May 8, 2026
@@ -253,6 +266,7 @@ export const layer = Layer.effect(

const retainRemotePoller = Effect.fn("VcsStatusBroadcaster.retainRemotePoller")(function* (
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.

🟢 Low vcs/VcsStatusBroadcaster.ts:267

When retainRemotePoller finds an existing poller for a cwd, it increments the subscriber count but ignores the new caller's automaticRemoteRefreshEnabled preference. The first subscriber's effect controls refresh behavior for all subsequent subscribers to the same cwd, so callers expecting different refresh settings receive the wrong behavior silently.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/server/src/vcs/VcsStatusBroadcaster.ts around line 267:

When `retainRemotePoller` finds an existing poller for a `cwd`, it increments the subscriber count but ignores the new caller's `automaticRemoteRefreshEnabled` preference. The first subscriber's effect controls refresh behavior for all subsequent subscribers to the same `cwd`, so callers expecting different refresh settings receive the wrong behavior silently.

Evidence trail:
apps/server/src/vcs/VcsStatusBroadcaster.ts lines 267-290: `retainRemotePoller` function definition showing the `existing` branch (lines 273-279) ignores `automaticRemoteRefreshEnabled` while the new-poller branch (line 285) uses it. apps/server/src/vcs/VcsStatusBroadcaster.ts lines 47-49: `StreamStatusOptions` interface defines `automaticRemoteRefreshEnabled` as an optional public option. apps/server/src/ws.ts lines 958-963: production caller passes `automaticGitFetchesEnabled`. apps/server/src/vcs/VcsStatusBroadcaster.test.ts lines 300-302: test caller passes `Effect.succeed(false)` showing the API is intended to accept different values.

@merrkry
Copy link
Copy Markdown

merrkry commented May 8, 2026

I would suggest adding something like SSH_ASKPASS_REQUIRE=never in auto fetch, see #1921.

@juliusmarminge juliusmarminge changed the title [codex] add setting to disable automatic git fetches [codex] add configurable automatic git fetch interval May 8, 2026
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels May 8, 2026
Copy link
Copy Markdown
Member Author

Screenshot of the new Source Control setting:

Source Control fetch interval setting

Copy link
Copy Markdown
Member Author

Full-page screenshot of the Source Control settings page:

Full Source Control settings page with fetch interval setting

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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 and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: layerTest deepMerge corrupts Duration when overrides include interval
    • Destructured automaticGitFetchInterval out of overrides before calling deepMerge, then applied it atomically afterward, mirroring the same protection used in applyServerSettingsPatch.

Create PR

Or push these changes by commenting:

@cursor push c9ba6464c7
Preview (c9ba6464c7)
diff --git a/apps/server/src/serverSettings.ts b/apps/server/src/serverSettings.ts
--- a/apps/server/src/serverSettings.ts
+++ b/apps/server/src/serverSettings.ts
@@ -139,9 +139,14 @@
     Layer.effect(
       ServerSettingsService,
       Effect.gen(function* () {
-        const initialSettings = yield* normalizeServerSettings(
-          deepMerge(DEFAULT_SERVER_SETTINGS, overrides),
-        );
+        const { automaticGitFetchInterval, ...overridesForMerge } = overrides;
+        const merged = deepMerge(DEFAULT_SERVER_SETTINGS, overridesForMerge);
+        const initialSettings = yield* normalizeServerSettings({
+          ...merged,
+          ...(automaticGitFetchInterval !== undefined
+            ? { automaticGitFetchInterval: automaticGitFetchInterval as Duration.Duration }
+            : {}),
+        });
         const currentSettingsRef = yield* Ref.make<ServerSettings>(initialSettings);
 
         return {

You can send follow-ups to the cloud agent here.

Comment thread apps/server/src/serverSettings.ts Outdated
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 8, 2026

Approvability

Verdict: Needs human review

New feature adding configurable Git fetch interval with UI controls and runtime behavior changes. An unresolved review comment identifies a bug where multiple subscribers to the same directory receive incorrect refresh settings.

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

cursoragent and others added 2 commits May 8, 2026 22:31
The layerTest method called deepMerge(DEFAULT_SERVER_SETTINGS, overrides)
without excluding automaticGitFetchInterval from the merge. Since Duration
values are internally structured objects, deepMerge would recurse into them
and produce a corrupted plain object instead of a valid Duration.

Mirror the same protection used in applyServerSettingsPatch: destructure
automaticGitFetchInterval out before merging, then apply it atomically.
- Add expandable Git details row in source control settings
- Keep fetch interval controls alongside Git discovery info
@juliusmarminge
Copy link
Copy Markdown
Member Author

@cursor push c9ba646

The layerTest method called deepMerge(DEFAULT_SERVER_SETTINGS, overrides)
without excluding automaticGitFetchInterval from the merge. Since Duration
values are internally structured objects, deepMerge would recurse into them
and produce a corrupted plain object instead of a valid Duration.

Mirror the same protection used in applyServerSettingsPatch: destructure
automaticGitFetchInterval out before merging, then apply it atomically.

Applied via @cursor push command
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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 and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Manual field conversion in settingsInputForDecode is fragile
    • Replaced the fragile manual settingsInputForDecode function with the already-available encodeServerSettingsSync which properly encodes all fields, making normalizeServerSettings robust against future schema changes.

Create PR

Or push these changes by commenting:

@cursor push 6294961d2c
Preview (6294961d2c)
diff --git a/apps/server/src/serverSettings.ts b/apps/server/src/serverSettings.ts
--- a/apps/server/src/serverSettings.ts
+++ b/apps/server/src/serverSettings.ts
@@ -55,17 +55,10 @@
 const textEncoder = new TextEncoder();
 const textDecoder = new TextDecoder();
 
-function settingsInputForDecode(settings: ServerSettings): unknown {
-  return {
-    ...settings,
-    automaticGitFetchInterval: Duration.toMillis(settings.automaticGitFetchInterval),
-  };
-}
-
 const normalizeServerSettings = (
   settings: ServerSettings,
 ): Effect.Effect<ServerSettings, ServerSettingsError> =>
-  decodeServerSettings(settingsInputForDecode(settings)).pipe(
+  decodeServerSettings(encodeServerSettingsSync(settings)).pipe(
     Effect.mapError(
       (cause) =>
         new ServerSettingsError({

You can send follow-ups to the cloud agent here.

Comment thread apps/server/src/serverSettings.ts Outdated
@juliusmarminge
Copy link
Copy Markdown
Member Author

@cursor push 6294961

… in normalizeServerSettings

settingsInputForDecode manually converted only automaticGitFetchInterval to
millis while spreading the rest of the decoded object. This is fragile because
any future field with a non-identity encoding (e.g. another DurationFromMillis)
would need to be added manually, with no type-level safety net.

Use the already-available encodeServerSettingsSync which properly handles all
fields, making normalizeServerSettings robust against future schema changes.

Applied via @cursor push command
- Switch archived thread state to `effect/Cause`, `effect/Effect`, and `effect/Option` imports
Comment thread apps/server/src/serverSettings.ts
- Replace `new Date(0).toISOString()` with the canonical epoch string
- Keep server tests aligned with the snapshot fallback
- Encode settings through schema effects before persisting
- Emit sparse settings as pretty JSON when saving
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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 and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue. You can view the agent here.

Reviewed by Cursor Bugbot for commit f27a9aa. Configure here.

Comment thread apps/server/src/serverSettings.ts Outdated
- Normalize provider and settings string fields
- Add tests for trimmed patch decoding and encoded output
- Write sparse server settings directly from the default-stripped object
- Extend tests to cover automatic Git fetch interval serialization
@juliusmarminge juliusmarminge merged commit 34ec8a8 into main May 8, 2026
12 checks passed
@juliusmarminge juliusmarminge deleted the t3code/bf29617b branch May 8, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment