Skip to content

Add per-project settings #2567

Open
shivamhwp wants to merge 27 commits into
pingdotgg:mainfrom
shivamhwp:per-project-settings
Open

Add per-project settings #2567
shivamhwp wants to merge 27 commits into
pingdotgg:mainfrom
shivamhwp:per-project-settings

Conversation

@shivamhwp

@shivamhwp shivamhwp commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a project settings page for configuring behavior that belongs to one project without changing global server settings or renaming the folder on disk.

Project settings are persisted by the server and applied throughout source-control detection, VCS status, provider selection, thread startup, setup scripts, and project actions.

What changed

Project settings UI

  • Open project settings directly from the project row in the sidebar; the separate caret still expands and collapses its threads.
  • Configure the project display name, default model, and inspect its workspace path.
  • Enable or disable provider instances per project while requiring at least one provider to remain available.
  • Configure a custom source-control provider, remote name, remote URL, and web URL when automatic detection is not sufficient.
  • Inspect the detected Git root and branch and set a project-specific background fetch interval.
  • Add and edit project-scoped actions and their keybindings.
  • Configure project action environment variables with validation for duplicate, invalid, and reserved T3CODE_* keys.

Runtime integration

  • Adds projects.getDetails and projects.updateSettings RPCs backed by per-project settings in ServerSettings.
  • Applies project remote overrides to provider resolution, Git actions, status broadcasting, diff/branch UI, and stacked VCS actions.
  • Keys relevant VCS caches by project context and refreshes sibling entries for the same repository.
  • Filters disabled providers in the composer and blocks thread.turn.start when the selected provider is disabled for that project.
  • Merges the project action environment into project scripts and setup-script execution.
  • Seeds new-thread model selection from the project default before falling back to sticky/global defaults.

Save and refresh safeguards

  • Project-settings map patches merge by project instead of replacing unrelated project entries.
  • Optimistic values are rolled back on failed saves and are cleared only after refreshed details contain the committed values.
  • Commit queues are isolated across project route changes so an older refresh cannot clear a newer project's draft.
  • Disabling the current default provider clears the default model only after the provider update succeeds.

UI

Grouped project environments

Project environment selector with grouped entries

General settings and provider availability

Project settings general section and provider controls

Custom remote, fetch interval, and project actions

Project custom remote, fetch interval, and actions

Action environment

Project action environment variables

Validation

  • 16 focused test files passed: 470 tests.
  • Targeted formatting, lint, and type checks passed for the affected server, web, shared, contracts, and client-runtime scopes.
  • Verified in a real Helium browser against an isolated local environment.
  • Confirmed persistence after reload for project name, provider policy, default-model fallback, custom remote, fetch interval, and action environment values.

Checklist

  • I explained what changed and why.
  • I included current screenshots for the new UI.
  • Focused automated tests pass.
  • The affected web flow was verified in a real browser.
  • No video needed; no animation or motion behavior changed.

Note

High Risk
Large changes to Git status caching, provider resolution, and orchestration dispatch gates affect core workflows; incorrect override or cache behavior could mis-attribute PRs/remotes or block turns.

Overview
Adds persisted per-project settings (remote override, disabled providers, action env, fetch interval) with projects.getDetails and projects.updateSettings RPCs that return detected Git state plus an effective remote (override when valid, otherwise detected).

Source control and Git status now accept optional projectId: overrides drive provider resolution (with cache invalidation on settings changes), status/PR caches are keyed by (cwd, projectId), and refreshes fan out to sibling cache entries for the same repo. Hosting provider on status prefers project overrides, then the branch’s configured remote, then detected context. Turn start is rejected when the chosen provider is disabled for that project; setup scripts merge actionEnvironment when settings load.

Supporting changes include getProjectSettings / updateProjectSettings on server settings (semaphore-backed merges), shared platformError helpers for looser PlatformError typing in tests/CLI paths, and small tooling fixes (CLI entry cast, @pierre/diffs import, Vitest ws interop).

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

Note

Add per-project settings with dedicated route, VCS provider overrides, and project-scoped caches

  • Introduces a new /projects/$environmentId/$projectId route with a full project settings UI covering model/provider selection, remote overrides, action environment variables, script management, and git fetch intervals.
  • Clicking a project in the sidebar now navigates to this settings route instead of opening an inline dialog; sidebar expansion is controlled via a new dedicated toggle button.
  • Adds projects.getDetails and projects.updateSettings WebSocket RPC endpoints; server settings now store per-project settings keyed by ProjectId.
  • VcsStatusBroadcaster and GitManager caches are now segmented by (cwd, projectId) so project-scoped status entries are isolated; refreshes propagate to sibling project entries on the same repository.
  • SourceControlProviderRegistry resolution accepts an optional projectId and applies project-specific remote overrides (or infers the active project), invalidating the cache when server settings change.
  • Provider instances disabled for a project are filtered in the chat composer and block thread.turn.start dispatch at the RPC layer.
  • Project setup scripts and chat script runs now inject per-project actionEnvironment variables; T3CODE_* keys supplied via extraEnv are stripped so runtime values always take precedence.
  • Risk: sidebar project-click behavior changes from toggle-expand to navigate-to-settings, which may surprise users accustomed to the old interaction.

Macroscope summarized fa95fdc.

@coderabbitai

coderabbitai Bot commented May 6, 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: 94e2a788-252f-4b47-be91-226eb053f4d6

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-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels May 6, 2026
Comment thread apps/server/src/ws.ts Outdated
Comment thread apps/web/src/routes/projects.$projectId.tsx Outdated
Comment thread apps/web/src/routes/projects.$projectId.tsx Outdated
Comment thread apps/server/src/ws.ts Outdated
Comment thread apps/web/src/components/Sidebar.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

Diff is too large for automated approval analysis. A human reviewer should evaluate this PR.

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

@shivamhwp shivamhwp changed the title Add per-project settings and remote overrides Add per-project settings May 7, 2026
@shivamhwp shivamhwp changed the title Add per-project settings Add per-project settings (wip) May 7, 2026
Comment thread apps/server/src/sourceControl/RemoteOverride.ts
Comment thread apps/web/src/routes/projects.$projectId.tsx Outdated
Comment thread apps/server/src/git/GitManager.ts
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/server/src/ws.ts
Comment thread apps/web/src/hooks/useHandleNewThread.ts
Comment thread apps/web/src/routes/projects.$projectId.tsx Outdated
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx Outdated
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/server/src/ws.ts Outdated
Comment thread apps/web/src/lib/projectScriptKeybindings.ts Outdated
Comment thread apps/web/src/lib/projectScriptKeybindings.ts
Comment thread apps/server/src/provider/Layers/ProviderRegistry.test.ts
Comment thread apps/server/src/serverSettings.ts Outdated
Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/web/src/components/ChatView.tsx Outdated
Comment thread apps/web/src/lib/projectScriptKeybindings.ts
Comment thread apps/web/src/components/ChatView.tsx
@shivamhwp shivamhwp changed the title Add per-project settings (wip) Add per-project settings May 8, 2026
Comment thread apps/server/src/sourceControl/SourceControlProviderRegistry.ts
Comment thread apps/web/src/components/DiffPanel.tsx
Comment thread apps/web/src/components/ChatView.tsx
Comment thread apps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
Comment thread apps/server/src/ws.ts Outdated
Comment thread apps/web/src/components/chat/ChatComposer.tsx Outdated
Comment thread apps/server/src/provider/Layers/ProviderRegistry.test.ts
Comment thread apps/web/src/lib/gitStatusState.ts Outdated
shivamhwp and others added 2 commits July 4, 2026 02:02
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Key vcs action commands by environment and cwd again so all operations
  on a worktree share one serial lock; the project context rides along
  from the requesting target instead of forking the key
- Make ResolvedVcsActionTarget.projectId optional to match
- Log a warning when a settings read failure skips the override lookup
- Seed the canonical default model when neither a project default nor a
  sticky selection exists
- Resolve project script keybindings from the project's own environment
  config instead of always using the primary environment
- Roll back the optimistic settings draft when a commit RPC fails so the
  UI does not present rejected edits as saved

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/client-runtime/src/state/vcsAction.ts Outdated
Comment thread packages/client-runtime/src/state/vcsAction.ts Outdated
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx Outdated
shivamhwp and others added 3 commits July 4, 2026 02:39
The command cache is keyed by [environmentId, cwd], so a projectId
captured from the first requester leaked into later invocations from
other project views. Carry it on RunVcsStackedActionInput instead so
every call sends its own project context, and widen the PR resolution
input helper for exactOptionalPropertyTypes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refresh all sibling cache entries (bare-cwd and project-scoped) on any
status refresh instead of only project entries on bare-cwd refreshes,
and clear project-settings draft keys only after the post-commit
refresh lands so server-normalized values are not shadowed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx Outdated
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx Outdated
# Conflicts:
#	apps/mobile/app.config.ts
#	apps/mobile/src/features/agent-awareness/remoteRegistration.ts
#	apps/mobile/src/features/settings/SettingsRouteScreen.tsx
#	apps/server/src/git/GitManager.ts
#	apps/server/src/provider/providerSnapshot.ts
#	apps/server/src/vcs/VcsStatusBroadcaster.ts
#	apps/web/src/components/ChatMarkdown.tsx
#	apps/web/src/components/ChatView.tsx
#	apps/web/src/components/ProjectScriptsControl.tsx
#	apps/web/src/components/Sidebar.tsx
#	apps/web/src/components/chat/ChatComposer.tsx
#	apps/web/src/components/chat/MessagesTimeline.test.tsx
#	apps/web/src/components/chat/OpenInPicker.tsx
#	apps/web/src/composerDraftStore.ts
#	apps/web/src/hooks/useHandleNewThread.ts
#	apps/web/src/providerInstances.ts
#	apps/web/src/routeTree.gen.ts
#	apps/web/src/routes/_chat.$environmentId.$threadId.tsx
#	packages/client-runtime/src/operations/projects.test.ts
#	packages/contracts/src/model.ts
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/server/src/ws.ts
Comment thread apps/server/src/git/GitManager.ts
Comment thread apps/server/src/sourceControl/RemoteOverride.ts
<ServerIcon className="size-3.5 shrink-0" />
<span className="truncate">{currentEnvironmentLabel}</span>
</div>
)}

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.

Switcher hidden on details failure

Medium Severity

The new environment Select only renders after projectDetails.data loads. Sidebar V2 always opens the representative member first, and projectLocations already comes from local grouping state. When that representative’s details RPC fails, sibling environments never appear, so users cannot switch to a working entry.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 23eb95e. Configure here.

});
},
[],
[router],

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.

Grouped bulk remove removed

Medium Severity

The sidebar project dialog’s “Remove all entries” flow was deleted and not re-homed. Project settings only call deleteProject for the current route member, so V2 users with a multi-environment group must switch and remove each entry separately, with no remaining bulk cleanup path.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 23eb95e. Configure here.

Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx
Comment thread apps/web/src/components/SidebarV2.tsx
Comment thread apps/web/src/routes/projects.$environmentId.$projectId.tsx Outdated
Comment thread apps/server/src/vcs/VcsStatusBroadcaster.ts
Comment thread apps/server/src/ws.ts
Comment thread apps/server/src/project/ProjectSetupScriptRunner.ts Outdated
Comment thread apps/web/src/projectSettingsCommit.ts

@cursor cursor Bot 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 3 potential issues.

There are 5 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

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

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8e497de. Configure here.

Comment thread apps/server/src/ws.ts
toDispatchCommandError(cause, "Failed to dispatch orchestration command"),
toDispatchCommandError(cause, "Failed to read thread project settings"),
),
);

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.

Provider check still uses getSettings

Medium Severity

Some functions, like validateProjectProviderAccess and automaticGitFetchIntervalForProject, still fetch project settings via getSettings. This path materializes provider secrets, causing thread.turn.start commands to be rejected if secret materialization fails. These settings, such as the disabled provider list and project-specific fetch interval, don't actually require secrets.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8e497de. Configure here.

title: "Failed to remove grouped project",
description: error instanceof Error ? error.message : "An error occurred.",
}),
);

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.

Partial grouped project delete

Medium Severity

The removeProjectEverywhere function deletes grouped projects concurrently. If any deletion fails, successful ones are not rolled back, leading to an inconsistent state where some projects are removed and others remain. The UI also stays on a project that may no longer exist.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8e497de. Configure here.

),
{ concurrency: "unbounded", discard: true },
);
return result;

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.

Sibling refresh fails primary poller

Medium Severity

After a successful primary remote refresh, sibling cache updates run inside the same effect with no error isolation. A failure refreshing one sibling project fails the whole refreshRemoteStatus, so the remote poller treats the refresh as failed and applies backoff even though the initiating project's cache was already updated.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8e497de. Configure here.

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

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant