Skip to content

[Bug]: No project isn't recognized when its folder is the target of a symlinked ~/.t3/scratch, so Turn into project disappears and a duplicate No project is created #34439

Closed

Description

@shubhambhattog

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 (also apps/web via packages/client-runtime)

Steps to reproduce

  1. Use T3 Code until ~/.t3/scratch holds some No project threads, each in its own ~/.t3/scratch/<date>-<words>-<id> folder.
  2. Move the scratch folder somewhere visible and symlink it back:
    mv ~/.t3/scratch ~/projects/t3-chats && ln -s ~/projects/t3-chats ~/.t3/scratch
  3. Point the No project at the real folder, ~/projects/t3-chats. I did this through t3_project_update with workspaceRoot; the project settings folder field would give the same result.
  4. Restart T3 Code and open the thread menu on one of the older No project threads. Their worktreePath is still ~/.t3/scratch/....

Both spellings name the same folder on disk.

Expected behavior

T3 Code still recognizes the project as No project, because its folder resolves to the scratch root:

  • The thread menu offers Turn into project.
  • New No project threads go to the existing No project.

Actual behavior

  • Turn into project is missing from the thread menu.
  • The server creates a second, empty "No project" rooted at ~/.t3/scratch. Settings then lists two "No project" entries on the same machine.
  • From code reading, ScratchThreadPromotion.promote would also refuse the thread with "Only a No project thread with its own folder can become a project.", because the parent of the thread's folder is checked with a plain string compare.

Every scratch check compares path spellings and never resolves symlinks:

  • apps/server/src/project/ManagedProjectFolders.ts: scratchRoot is path.resolve(baseDir, "scratch"), and isScratchRoot compares path.resolve(project.workspaceRoot) to it. path.resolve doesn't follow symlinks, so isScratchProject is false and ensureScratchProject bootstraps a new project.
  • apps/server/src/project/ScratchThreadPromotion.ts: path.dirname(folder) !== scratchRoot.
  • packages/client-runtime/src/state/projects.ts: isScratchProject compares the project root to the advertised scratchWorkspaceRoot as text. canTurnThreadIntoProject in apps/web/src/hooks/useThreadActions.ts therefore hides the action.

Other places in the server already compare real paths, for example KnownWorkspaces and AgentSessionScanner.

Impact

Minor bug or occasional failure

A No project thread can't be turned into a project, and a duplicate No project appears. There's a manual workaround (below).

Version or commit

0.1.9-nightly.20261110.4465 (code read at main @ 479ee74)

Environment

macOS 27.2, arm64, T3 Code Nightly desktop app

Related

Workaround

Delete the empty duplicate No project, then set the original No project's folder back to the symlink spelling ~/.t3/scratch. Turn into project then appears again.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions