You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I run every thread in its own worktree, so each thread gets its own dev server. Two things get awkward:
Starting and stopping a dev server means dealing with the terminal pane. I can start an action from the top bar, but to stop it I have to find the right terminal among several and Ctrl-C it myself.
A settled thread's dev server keeps running. The work is done and the worktree is finished with, but the process stays up until I notice. With a worktree per thread these accumulate.
Today there is also no way to tell an action is running at all. Below, the dev server is running in both cases — the left is current main:
Today
Proposed
The idea
Give each action its own terminal derived from its id (script-<id>), mirroring the setup-<id> convention the server already uses for setup scripts. Because the id is derived rather than tracked at launch, any client attached to the thread can tell an action is running — including a phone, or a browser on another machine.
That makes three things possible:
A running action shows a steady dot, and the split button becomes Stop.
Clicking a running action interrupts it — no terminal pane required.
An action can opt into Stop when the thread settles, handled server-side so it works with no client connected.
Today
Proposed
Allow multiple instances is the escape hatch: pinning means a second click stops the action, which is right for a dev server but wrong for a bun test you want to fire repeatedly. With it on, every run opens its own terminal and the action reports no running state — one switch, not three.
Notes and limitations
Stopping writes Ctrl-C to the action's terminal. It reaches the foreground process group, so the terminal survives for a re-run, but a process that traps SIGINT keeps running and the indicator honestly stays lit.
Stop-on-settle only covers actions started in a persisted thread. An action started from an unsaved draft has no thread to settle, so nothing stops it. I hit this while testing.
Settlement fires server-side on thread.settled, so it covers both manual settling and auto-settle.
I have a working branch if there's interest: viicslen/t3code@feat/project-action-running-state. It's ~1,000 lines across web, mobile, server, and contracts, so per CONTRIBUTING I'm raising it here rather than opening a PR. Happy to split it, shrink it, or drop parts.
If you'd rather review it in pieces
The branch is already committed as independent slices, so this splits cleanly. Each row is shippable on its own and leaves the app in a coherent state:
#
PR
Size
Depends on
1
feat(web): show running actions and stop them from the action button — derives the script-<id> terminal, adds the shared helper, and wires the dot + Stop in web
~260
—
2
feat(mobile): show running actions and stop them from the action menu
~140
1
3
fix(server): run setup scripts in the action's own terminal — unifies setup-<id> with the new id so an auto-run shows as running
~15
1
4
feat: add an "Allow multiple instances" opt-out for project actions — contracts, t3.json, editor toggle, both clients
~100
1, 2
5
feat: stop opted-in project actions when their thread settles — server reactor on thread.settled, plus the editor toggle
~420
1, 4
Notes on the boundaries:
1 is the only one that has to land first. Everything else is additive on top of the derived terminal id.
3 is three lines of behavior and could fold into 1 if you'd rather not have a PR that small.
5 is the largest and the most separable concern. It is a distinct feature from the indicator, and if you like one idea but not the other, this is the seam. It depends on 4 only for the allowMultipleInstances guard; without 4 it stands alone with that check dropped.
If only part of this is interesting, 1–3 alone deliver "see it running, click to stop it" on every surface, at ~415 lines total.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The problem
I run every thread in its own worktree, so each thread gets its own dev server. Two things get awkward:
Today there is also no way to tell an action is running at all. Below, the dev server is running in both cases — the left is current
main:The idea
Give each action its own terminal derived from its id (
script-<id>), mirroring thesetup-<id>convention the server already uses for setup scripts. Because the id is derived rather than tracked at launch, any client attached to the thread can tell an action is running — including a phone, or a browser on another machine.That makes three things possible:
Allow multiple instances is the escape hatch: pinning means a second click stops the action, which is right for a dev server but wrong for a
bun testyou want to fire repeatedly. With it on, every run opens its own terminal and the action reports no running state — one switch, not three.Notes and limitations
thread.settled, so it covers both manual settling and auto-settle.I have a working branch if there's interest:
viicslen/t3code@feat/project-action-running-state. It's ~1,000 lines across web, mobile, server, and contracts, so per CONTRIBUTING I'm raising it here rather than opening a PR. Happy to split it, shrink it, or drop parts.If you'd rather review it in pieces
The branch is already committed as independent slices, so this splits cleanly. Each row is shippable on its own and leaves the app in a coherent state:
feat(web): show running actions and stop them from the action button— derives thescript-<id>terminal, adds the shared helper, and wires the dot + Stop in webfeat(mobile): show running actions and stop them from the action menufix(server): run setup scripts in the action's own terminal— unifiessetup-<id>with the new id so an auto-run shows as runningfeat: add an "Allow multiple instances" opt-out for project actions— contracts,t3.json, editor toggle, both clientsfeat: stop opted-in project actions when their thread settles— server reactor onthread.settled, plus the editor toggleNotes on the boundaries:
allowMultipleInstancesguard; without 4 it stands alone with that check dropped.All reactions