[Bug]: `t3_project_update` saves scripts and project defaults that are ignored once project settings are folded#14991

openedOct 3, 2026byAAngeloTadeucci

Note

Written by Claude Opus 5.5 on behalf of @AngeloTadeucci, and filed at Angelo's request.

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Use an install whose settings.json has projectSettingsFolded: true. The one-time fold of legacy project settings sets it at serverSettings.ts#L615.
  2. From an agent, call t3_project_update with a setup action: scripts: [{ id: "setup", name: "Setup", command: "...", icon: "configure", runOnWorktreeCreate: true }]. The response echoes the new scripts, and t3_project_read returns them.
  3. Call t3_thread_launch for that project with workspaceStrategy: { type: "worktree", ... }.

Expected behavior

The setup action runs in the new worktree. If the tool can no longer change this setting, it should say so instead of reporting success.

Actual behavior

The worktree is created and no setup action runs. Once settings are folded, resolveProjectScripts returns the projectSettingsOverrides entry or the environment default and never reads the project's own scripts at projectScripts.ts#L23. t3_project_update still writes to the project aggregate, so the change is saved and then never read.

Writing the same action into projectSettingsOverrides.<projectId>.defaultProjectScripts in settings.json made it run on the next launch, which confirms where the runtime reads from.

The same gate covers defaultModelSelection and defaultThreadEnvMode in resolveProjectOverrides at projectSettings.ts#L151, so I expect those fields of t3_project_update to be ignored too. I only verified scripts at runtime, and I did not check autoPull.

Impact

Minor bug or occasional failure

Version or commit

desktop 0.0.46-nightly.20261003.2610; source read at 8ed276c246b6

Environment

Windows 11 Pro 10.0.26200, agent on Claude Code through the T3 MCP server

Workaround

Edit projectSettingsOverrides in settings.json, or set the action in the project settings UI.

Note

Grok responding on behalf of Julius.

Triage

Thanks for the precise report, @AngeloTadeucci. We confirmed it on main at 8ed276c246. Once project settings have been folded, t3_project_update still saves scripts on the project and returns them, but launch never reads that copy. We didn't find an existing issue for this.

What launch reads: ProjectSetupScriptRunner calls resolveProjectScripts in projectScripts.ts. If there's a projectSettingsOverrides[projectId].defaultProjectScripts entry, it wins. If projectSettingsFolded is set and there's no entry, launch uses the environment default and never looks at the project's own scripts. t3_thread_launch does pass project.scripts to the runner (ThreadLaunchService.ts), but the resolver drops them. The folded-settings test already expects that behavior.

What the tool writes: t3_project_update only calls projects.update (handlers.ts), which saves to the project record. The tool says it updates project settings through the same service as the app (tools.ts), but the app's Actions UI now writes to projectSettingsOverrides instead. t3_project_read returns the project record, so the echo you saw is the stored value, not the list launch will run. t3_project_create also tells callers to set scripts or defaultModelSelection afterwards with t3_project_update (handlers.ts), so that follow-up hits the same gap. No MCP tool writes per-project overrides, and t3_environment_preferences_update only covers the whole environment.

Folded is the normal state: foldLegacyProjectSettings turns the flag on at the next trusted settings load once any project row or legacy override exists, and after that it never reads the project record again (serverSettings.ts).

The other fields: you read resolveProjectOverrides correctly (projectSettings.ts). Once folded, the project record's defaultModelSelection and defaultThreadEnvMode are ignored for new threads created in the app. autoPull is also never read on this path, even before folding. Auto-pull reads defaultAutoPull from the resolved settings (VcsStatusBroadcaster.ts), and the fold copies the stored value there only once. Title, icon, favicon, and workspace root still belong on the project record, so updating those works fine.

Workaround: set the action in the project settings UI, or write projectSettingsOverrides.<projectId>.defaultProjectScripts the way you already did. The model, env mode, and auto-pull work the same way, through defaultModelSelection, defaultThreadEnvMode, and defaultAutoPull.

We're leaving this open as a bug. When t3_project_update reports success, the change should actually reach what launch and the new-thread UI read, which means writing these fields into projectSettingsOverrides.

Synced from GitHub

Confirming on macOS (0.0.46-nightly.20261007.2774), and it's broader than t3_project_update. A "Setup worktree" action (runOnWorktreeCreate: true) added after projectSettingsFolded was set is ignored too, and so is the checked-in t3.json. Every new worktree thread silently skipped setup: ProjectSetupScriptRunner.runForThread returned no-script in about 0.02 ms and never opened a terminal, with nothing shown in the UI.

Writing projectSettingsOverrides.<projectId>.defaultProjectScripts fixed it immediately, without a restart.

Suggest falling back to project.scripts when there's no override, or showing a warning when a runOnWorktreeCreate script won't run. For us the impact was "every new worktree unusable until set up by hand", higher than "Minor".

Synced from GitHub

Note

Written by Claude Opus 5.5 on behalf of @jheinem1, and posted at their request.

Confirming on 0.0.46-nightly.20261008.2819 (Windows desktop app connected to a WSL server). It isn't limited to setup actions: scripts saved through t3_project_update also never appear in the thread header's project scripts menu. The menu shows only Add project script, even after a reload. Two projects were affected. In both, t3_project_read and projection_projects.scripts_json show the scripts, and the client's IndexedDB cache contains them, but the menu is empty because projectSettingsFolded is true.

A script added through the UI went to projectScriptOverrides and projectSettingsOverrides.<projectId>.defaultProjectScripts in settings.json and showed up right away. Writing the tool-set scripts into those same keys is the workaround.

Synced from GitHub

Note

Written by Claude Opus 5.5 and posted at the account holder's request.

This still happens on macOS 0.0.46-nightly.20261014.3132 (5a4e998). Two MCP entry points not covered above hit the same gap:

  • t3_project_create with a workspaceRoot accepts scripts in the same call and saves them on the project record (handlers.ts#L248-L249). On a folded install, a project created with a runOnWorktreeCreate action has no setup action from the start.
  • delegate_task with isolation: "worktree" promises a checkout "with project setup completed before the child starts" (tools.ts#L68). For a project created as above, the worktree was created and the child started without setup. ProjectSetupScriptRunner.runForThread returned in about 0.03 ms without opening a terminal, so the setup stage was marked skipped (ThreadLaunchService.ts#L617). Both the delegate_task and task_status results reported completed, with nothing to show setup had not run. The file the setup action writes was missing in the child's worktree.

Agents use worktree isolation to get a prepared checkout, so until this is fixed, a skipped setup should at least appear in the delegate_task and task_status results.

Synced from GitHub

Still happens on macOS 0.1.1-nightly.20261017.3272. Scripts set through t3_project_update were saved to the project record and returned by t3_project_read, but the header's scripts menu stayed empty, including after quitting and reopening the app. Writing the same scripts to projectSettingsOverrides.<projectId>.defaultProjectScripts in settings.json made them appear.

Synced from GitHub

Confirming this behavior on October 19, 2026 in a T3 Code MCP-connected project. It also reproduces with a regular project action, not only a setup/worktree hook:

  • t3_project_update succeeded with a script named Build release APK, using id build-release-apk, icon build, and runOnWorktreeCreate: false.
  • t3_project_read returns that script from the project record, but it does not appear in the project's actions menu.
  • A separate action (a) added through the UI does appear in the menu, but is not returned by t3_project_read.

The script id is a valid slug and the icon is an allowed value, so this does not appear to be a malformed payload. This confirms the project-record/settings-override mismatch described here for a normal menu action too. I verified persistence and visibility; I have not tested whether the MCP-written action runs.

Synced from GitHub

Note

Written by Claude Opus 5.5 on behalf of @dmeyerhoff.

Possibly the same root cause from the other side: on a folded install, scripts added through the GUI are saved in settings.json → projectSettingsOverrides.<projectId>.defaultProjectScripts, but t3_project_read returns scripts: [] for that project (and projection_projects.scripts_json is []). So an agent can't see the project's actions. T3 Code (Beta) 0.1.0, macOS.

Synced from GitHub

Still happens on 0.1.3-nightly.20261024.3617 (Linux server, macOS desktop client), and confirming the defaultThreadEnvMode case at runtime. An agent set a project to defaultThreadEnvMode: "local" through t3_project_update, and t3_project_read still returns local, but new threads follow the global default instead. After switching global to worktree, every new thread created from web/desktop (26 of 26) and mobile (3 of 3) got a fresh worktree, leaving 29 unneeded worktrees in about 2.5 days. I've applied the project-scope override from triage as a workaround.

On #22827: it notes that existing aggregate-only saves stay inactive until re-saved. This install is that case. The value was saved through the tool after the fold and is still ignored, while t3_project_read keeps reporting it, so nothing tells the user to re-save. Reconciling existing project values into overrides once (or showing the mismatch) would cover them.

Synced from GitHub

Confirming this exact mismatch on October 29, 2026 in T3 Code: t3_project_update accepted the four Listwork actions and returned them, but the Settings → Code → Projects → Actions panel still showed “No actions configured.” The reason matches this issue: the project tool writes the legacy project record while the panel reads projectSettingsOverrides.<projectId>.defaultProjectScripts. I cleared the misleading legacy scripts and applied the actions through the settings override workaround.

Synced from GitHub

Note

Written by Claude Opus 5.5 on behalf of @stanley50z, and posted at their request.

Still happens on Windows desktop 0.1.6-preview.20261030.3948 and macOS 0.1.3-nightly.20261025.3669, both with projectSettingsFolded: true.

One case not covered above: removing scripts is lost too. With actions saved in projectSettingsOverrides.<projectId>.defaultProjectScripts, t3_project_update with scripts: [] returns an empty list and t3_project_read agrees, but the override in settings.json is unchanged. resolveProjectScripts keeps returning the old actions, so an agent asked to remove stale actions reports success while they stay in the menu. Writing "defaultProjectScripts": [] into the override removes them.