Skip to content

feat(mobile): allow several new-task drafts per project - #10327

Merged
juliusmarminge merged 3 commits into
t3code/mobile-drafts-in-listfrom
t3code/mobile-multi-draft
Sep 6, 2026
Merged

feat(mobile): allow several new-task drafts per project#10327
juliusmarminge merged 3 commits into
t3code/mobile-drafts-in-listfrom
t3code/mobile-multi-draft

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 6, 2026

Copy link
Copy Markdown
Member

Stacked on #10260 (which is stacked on #10245).

Problem

Mobile keyed new-task drafts by project (new-task:<environmentId>:<projectId>), one slot per project. Starting a new task in a project always landed in whatever draft already sat there, so there was no way to hold two ideas for the same repo. Web mints a draft id per draft and never had this limit. With #10260 listing drafts in the thread list, the single slot became visible.

Fix

Drafts are keyed new-task:<draftId> and carry their project in a project stamp (environmentId, projectId, createdAt). Everything that used to read the project out of the key now reads the stamp:

  • Migration. Legacy project-keyed entries are rewritten to id keys with the stamp filled in when the draft file loads, for live drafts and for drafts archived by sign-out, so nothing on users' devices is lost.
  • New Task mints a fresh draft. Each entry into the composer binds to its own draft, whether it came from the compose button, a project row, or the provider's project fallback. Tapping a Draft row resumes that draft by id through a new draftId route param; the screen waits for draft hydration and for the project list before deciding a draft is gone.
  • Switching projects or environments retargets the same draft (text and model/mode choices follow; branch and worktree are cleared since they belong to the old repo) instead of copy-if-empty across keys. copyComposerDraftContent* is removed.
  • Uploads and sign-out resolve a draft's environment from the stamp (composerDraftEnvironmentId now takes the draft), so id-keyed drafts upload attachments and survive relay sign-out.
  • A rejected pending task restores into its own message-keyed draft stamped with the project, rather than merging into whatever the user is typing.
  • Drafts list newest first by their own createdAt instead of a render-time stamp.

Verification

apps/mobile: vp test run across the draft store, list model, outbox drain/removal/editor, attachment upload queue, and thread-list suites — 239 passed. vpr typecheck passes. Lint on touched files shows only pre-existing warnings.

New tests: legacy key migration (live and archived), minting several drafts per project, retarget keeps text and clears workspace selection, environment lookup from the stamp, rejected-task restore into a stamped draft.

Before / after — starting a fresh New Task in a project that already has a draft

Before: the composer opens with the existing draft text "First idea, typed earlier" already in it. After: the composer opens empty; the earlier draft is kept separately

After — three drafts for the same project in the thread list

One migrated from a legacy project key, one already id-keyed, and one typed live and retargeted across environments. Tapping any row opens that draft.

Three Draft rows for pingdotgg/t3code above the Sends on reconnect row

Captured on an iPhone 17 Pro simulator with the dev client against a disposable backend; the "before" is the head of #10260 with the same seeded state. Captures were taken before the stack was rebased onto current main (which retinted the Pending pill and reworked carryDraftContentTo); the rebase changed no draft behaviour shown here.

Surfaces

  • Entry points: compose button, project row "new thread", Draft rows (v1 and v2 lists, Home and iPad sidebar), pending-task restore.
  • Clients: mobile only. Web already has per-draft ids; server untouched.
  • Reverse state: Discard from the row menu, or clear the composer; both drop the stamp so the row disappears.

Model: Claude Fable 5 · Harness: Claude Code in T3 Code

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.6 KiB 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.3 KiB
Codex Live turn WebSocket wire 6.5 KiB 7.8 KiB
Codex Live turn WebSocket decoded 57.0 KiB 66.4 KiB
Codex Live turn messages 8 21
Claude Total thread wire 13.6 KiB 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.3 KiB
Claude Live turn WebSocket wire 6.5 KiB 7.8 KiB
Claude Live turn WebSocket decoded 57.8 KiB 66.4 KiB
Claude Live turn messages 8 21

Baseline: unavailable · PR result: c1157a3 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.9 KiB
  • Claude decoded thread snapshot: 114.6 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Comment thread apps/mobile/src/state/use-composer-drafts.ts
Comment thread apps/mobile/src/state/use-composer-drafts.ts
Comment thread apps/mobile/src/state/use-composer-drafts.ts
Comment thread apps/mobile/src/features/threads/new-task-flow-provider.tsx
Comment thread apps/mobile/src/features/threads/NewTaskDraftScreen.tsx Outdated
Comment thread apps/mobile/src/features/threads/new-task-flow-provider.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes mobile draft identity and persistence from one project slot to multiple ID-keyed drafts, adding migration, route resumption, project retargeting, attachment scoping, and recovery behavior across several production paths. The cross-cutting state and persisted-data changes have a broad runtime surface and warrant human review.

Not approved because:

  • Monthly spending limit reached (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Sep 6, 2026
juliusmarminge and others added 3 commits September 6, 2026 12:12
New-task drafts were keyed `new-task:<environmentId>:<projectId>`, one slot
per project, so starting a new task in a project always landed in whatever
draft already sat there and there was no way to hold two ideas for the same
repo. Web mints a draft id per draft and never had this limit; with drafts
now listed in the mobile thread list the single slot became visible.

Drafts are keyed `new-task:<draftId>` and carry their project in a
`project` stamp (environment, project, createdAt). Legacy project-keyed
entries are rewritten on load, so nothing on users' devices is lost. Each
New Task entry mints a fresh draft; tapping a Draft row resumes that draft
by id via a new `draftId` route param. Switching projects mid-compose
retargets the same draft (text and mode choices follow, branch/worktree
are cleared) instead of copy-if-empty across keys. A rejected pending task
restores into its own message-keyed draft rather than merging into
whatever the user is typing. Drafts list newest first by their own
createdAt instead of a render-time stamp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-ups from review on the id-keyed draft change:

- composerDraftEnvironmentId read the environment out of the key, so an
  id-keyed new-task draft had no owner: attachment uploads never started
  and sign-out archival skipped the draft while cleanup deleted it. It now
  takes the draft and reads the project stamp, falling back to the legacy
  key shape only for drafts not yet migrated.
- Archived signed-out drafts get the same legacy-key migration as live
  ones, so they surface and open after restore.
- Switching environments retargets the active draft to the matched
  project, like switching projects does, instead of leaving the stamp on
  the old machine.
- openDraft refuses a draft whose stamped project is not loaded rather
  than letting the composer fall back to the environment's first project.
- The draft screen waits for draft hydration before deciding a draftId is
  gone, and keeps retrying while the project list is still empty, so a
  cold launch into a Draft row lands on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The provider resolves selectedProject to the environment's first project
before setProject ever runs, and the draft screen skips setProject when
the route's project already matches. Text typed in that window had no
draft to land in and was lost on cancel. Mint the draft from an effect
keyed on the selected project instead of only inside setProject.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarminge force-pushed the t3code/mobile-multi-draft branch from 05bff4b to c1157a3 Compare September 6, 2026 19:14
@cursor

cursor Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@juliusmarminge
juliusmarminge merged commit 8e129a0 into main Sep 6, 2026
26 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/mobile-multi-draft branch September 6, 2026 19:31
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 6, 2026
## What's Changed
* fix(web): show Tux icon for WSL environments by @UtkarshUsername in pingdotgg/t3code#8511
* perf(web): speed up folder menu sorting by @AksharP5 in pingdotgg/t3code#10190
* style(web): fix inconsistencies in new settings layouts by @extoci in pingdotgg/t3code#10177
* feat(threads): persist manual active thread order by @juliusmarminge in pingdotgg/t3code#9729
* feat(mobile): arrange active threads from both thread lists by @juliusmarminge in pingdotgg/t3code#9730
* feat(web): drag threads across sections with consistent motion by @juliusmarminge in pingdotgg/t3code#9731
* feat(web): simplify sidebar drag destination cues by @juliusmarminge in pingdotgg/t3code#9750
* fix(mobile): keep pending tasks queued when a send fails in flight by @juliusmarminge in pingdotgg/t3code#10245
* feat(mobile): show new-task drafts alongside pending tasks in the thread list by @juliusmarminge in pingdotgg/t3code#10260
* feat(mobile): allow several new-task drafts per project by @juliusmarminge in pingdotgg/t3code#10327
* fix(mobile): slide settled threads out before collapsing by @StiensWout in pingdotgg/t3code#10345


**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260906.1303...v0.0.39-nightly.20260906.1316

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260906.1316
BarretoDiego pushed a commit to BarretoDiego/t3code that referenced this pull request Sep 7, 2026
)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

@RealJFX RealJFX 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.

Super cool

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

Labels

size:XL 500-999 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.

2 participants