Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
277 commits
Select commit Hold shift + click to select a range
4ce604c
fix(server): protect terminal commands during automatic updates
maria-rcks Oct 9, 2026
b059585
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
3ee11f1
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
f3a7dab
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
bc2441f
fix(server): clear canceled provider install queues
maria-rcks Oct 9, 2026
0b1a0a4
fix(server): keep replaced terminal shells busy during updates
maria-rcks Oct 9, 2026
772a756
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
6bcc2ed
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
a6b00b7
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
0df12e8
fix(server): mark launcher handoff as a terminal effect
maria-rcks Oct 9, 2026
aac65cf
fix(server): preserve maintenance admission effect types
maria-rcks Oct 9, 2026
702cf87
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
42e4416
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
526820e
fix(dev): serve web assets and settle closed lab sockets
maria-rcks Oct 9, 2026
a8b448b
chore(dev): sync update lab with main
maria-rcks Oct 9, 2026
a28690b
chore(server): sync service updates with main
maria-rcks Oct 9, 2026
82e6ca2
chore(server): sync provider updates with main
maria-rcks Oct 9, 2026
5c1d4fe
chore(desktop): sync background updates with main
maria-rcks Oct 9, 2026
eb9277c
chore(settings): sync update stack with main
maria-rcks Oct 9, 2026
22149e9
fix(dev): reject live update lab host changes
maria-rcks Oct 9, 2026
6d10aea
chore(server): carry update lab host guard
maria-rcks Oct 9, 2026
4234eee
chore(server): carry update lab host guard
maria-rcks Oct 9, 2026
aa964fe
chore(desktop): carry update lab host guard
maria-rcks Oct 9, 2026
d128aff
chore(settings): carry update lab host guard
maria-rcks Oct 9, 2026
65a7cb7
fix(dev): reuse existing projects for lab turns
maria-rcks Oct 9, 2026
7f4ba4c
chore(server): carry lab project recovery
maria-rcks Oct 9, 2026
db712fd
chore(server): carry lab project recovery
maria-rcks Oct 9, 2026
727c6d7
chore(desktop): carry lab project recovery
maria-rcks Oct 9, 2026
2c60a5a
chore(settings): carry lab project recovery
maria-rcks Oct 9, 2026
c1a98f4
fix(server): keep terminal input available during update checks
maria-rcks Oct 9, 2026
ecd8498
chore(desktop): carry update window input fix
maria-rcks Oct 9, 2026
1489f98
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
37abc15
chore(updates): keep simulation tooling local
maria-rcks Oct 9, 2026
82c35fd
chore(server): carry private simulation cleanup
maria-rcks Oct 9, 2026
45f9170
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
9690f8d
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
1f5eb23
docs(updates): explain pending background work
maria-rcks Oct 9, 2026
1bbd219
chore(desktop): carry queued-work documentation
maria-rcks Oct 9, 2026
00580b2
chore(settings): carry queued-work documentation
maria-rcks Oct 9, 2026
f3963cc
docs(updates): clarify terminal wait during server restarts
maria-rcks Oct 9, 2026
6aaeed6
chore(desktop): carry server restart documentation
maria-rcks Oct 9, 2026
ba4c20f
chore(settings): carry server restart documentation
maria-rcks Oct 9, 2026
fc5a321
fix(desktop): prevent stale updates after channel changes
maria-rcks Oct 9, 2026
f74ced0
chore(settings): carry desktop update channel guard
maria-rcks Oct 9, 2026
ce07c86
refactor(server): simplify background provider updates
maria-rcks Oct 9, 2026
9706027
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
8429186
refactor(server): simplify background server updates
maria-rcks Oct 9, 2026
e67c3f8
refactor(desktop): simplify background update downloads
maria-rcks Oct 9, 2026
0d8591a
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
00a8c88
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
e2fec1d
fix(server): frequent scheduled tasks no longer hold back background …
maria-rcks Oct 9, 2026
d120ba8
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
53fc18d
fix(server): retry a background server update after a failed download
maria-rcks Oct 9, 2026
c717b52
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
bd392d8
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
1bec6f3
fix(server): a canceled provider update no longer blocks background u…
maria-rcks Oct 9, 2026
ffe6f33
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
4102d58
docs(updates): describe when background updates retry and what they i…
maria-rcks Oct 9, 2026
33a86ab
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
f51629f
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
b759d5c
docs(desktop): note that desktop updates install on quit regardless o…
maria-rcks Oct 9, 2026
33b5506
fix(server): stop continuing a run restarted three times in a row
maria-rcks Oct 9, 2026
973dbe5
fix(server): keep background updates from stalling
maria-rcks Oct 9, 2026
fe54b11
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
f58dce4
fix(server): bound background server update handoffs
maria-rcks Oct 9, 2026
7cded2a
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
531eea4
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
66920cb
fix(server): a failed terminal poll no longer reads as idle before a …
maria-rcks Oct 9, 2026
7b9e2f9
fix(server): queued runs and incompatible releases no longer stall ba…
maria-rcks Oct 9, 2026
30d56f4
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 9, 2026
05a6980
fix(server): background server updates no longer delete runtimes or r…
maria-rcks Oct 9, 2026
a9e8789
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 9, 2026
94846cd
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 9, 2026
d36093c
fix(server): only a live owning session keeps background tasks blocki…
maria-rcks Oct 10, 2026
d45968c
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 10, 2026
ba70be2
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 10, 2026
bf89280
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 10, 2026
27c2d3d
fix(server): background server updates back off and stage one release…
maria-rcks Oct 10, 2026
11bd690
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 10, 2026
4ce6361
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 10, 2026
f887783
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 10, 2026
d0fb53f
fix(server): a corrupt scheduled task no longer closes the update window
maria-rcks Oct 10, 2026
ae78a28
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 10, 2026
104cd87
docs(updates): note that newer releases wait for a staged one to install
maria-rcks Oct 10, 2026
1e64f84
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 10, 2026
1005be9
test(server): cover the restart continuation chain limit
maria-rcks Oct 10, 2026
f387859
docs(server): keep the scheduled task poll comment on listDueTasks
maria-rcks Oct 10, 2026
0233b45
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 10, 2026
446a4a4
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 10, 2026
fa2c77d
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 10, 2026
c1f1861
fix(desktop): keep install on quit honest after failed downloads
maria-rcks Oct 11, 2026
2b34717
fix(server): an unreadable settings file keeps automatic updates off
maria-rcks Oct 11, 2026
4fc9c54
fix(server): background updates wait for agent background work and re…
maria-rcks Oct 11, 2026
c451188
fix(server): background provider installs never stall or race a provi…
maria-rcks Oct 11, 2026
660fa84
fix(opencode): a configured OpenCode server never updates the local CLI
maria-rcks Oct 11, 2026
f251eb4
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 11, 2026
89593cb
fix(server): background server restarts wait for first installs and s…
maria-rcks Oct 11, 2026
2cf1f33
docs(updates): an exact version only stays while automatic updates ar…
maria-rcks Oct 11, 2026
2467651
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 11, 2026
b5a018c
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 11, 2026
26a39af
fix(opencode): restart continuation follows a turn a surviving server…
maria-rcks Oct 11, 2026
ab2450e
fix(codex): restart continuation retries a goal hold and prompts a fr…
maria-rcks Oct 11, 2026
b2842df
fix(claude): restart resume skips a consumed rollback cursor and reje…
maria-rcks Oct 11, 2026
1ef4518
fix(acp): an agent that cannot reload sessions falls back to portable…
maria-rcks Oct 11, 2026
ea78d7a
fix(server): scheduled runs wait for restart continuation
maria-rcks Oct 11, 2026
076584f
fix(server): MCP write receipts survive provider session rotation
maria-rcks Oct 11, 2026
830b67c
fix(server): restart continuation never answers for a waiting user
maria-rcks Oct 11, 2026
dad17d3
fix(server): restart recovery cancels orphan native subagents and run…
maria-rcks Oct 11, 2026
ab46dcd
fix(server): MCP environment tools expose thread continuation, and an…
maria-rcks Oct 11, 2026
5948330
Merge remote-tracking branch 'origin/main' into t3/background-provide…
maria-rcks Oct 11, 2026
a00db84
Merge branch 't3/background-provider-updates' into t3/background-serv…
maria-rcks Oct 11, 2026
4dc70b7
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 11, 2026
1667170
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 11, 2026
ba5ff50
fix(server): restart continuation resumes a thread whose snooze elapsed
maria-rcks Oct 11, 2026
bd9e711
fix(claude): a roster update keeps a consumed rollback cursor cleared
maria-rcks Oct 11, 2026
e6e6c7a
fix(opencode): a surviving-server history replay no longer rolls back…
maria-rcks Oct 11, 2026
6d9bb9b
test(server): pin the clock for the elapsed snooze restart case
maria-rcks Oct 11, 2026
792dded
fix(opencode): following a surviving run never re-prompts a finished …
maria-rcks Oct 11, 2026
06a61c6
fix(opencode): a remote turn that finished while T3 was down is not p…
maria-rcks Oct 11, 2026
8f13ec7
fix(server): background provider installs only update installs they own
maria-rcks Oct 11, 2026
4ae068e
fix(server): provider installs wait for turns on every T3 server on t…
maria-rcks Oct 11, 2026
ee29b42
fix(server): every provider CLI launch waits for a running install
maria-rcks Oct 11, 2026
e55e0fd
fix(web): background provider updates stay out of the way in clients
maria-rcks Oct 11, 2026
0226f3c
fix(server): a standalone Codex reached through a linked home still u…
maria-rcks Oct 11, 2026
9c22c2a
fix(server): only servers share the user-wide provider install gate
maria-rcks Oct 11, 2026
dbbc727
fix(server): a manual update waiting for running turns says so
maria-rcks Oct 11, 2026
b74de47
test(server): other providers keep launching during a Codex first ins…
maria-rcks Oct 11, 2026
15911e9
fix(claude): unusable transcripts fall back to saved context and the …
maria-rcks Oct 11, 2026
26231f8
fix(opencode,pi): restarts keep finished turns, replayed text and sub…
maria-rcks Oct 11, 2026
ecd6163
fix(acp): respawned sessions renegotiate capabilities and fall back t…
maria-rcks Oct 11, 2026
4e53090
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
5d9e98a
fix(opencode): restarts admit each prompt once, rebind waiting questi…
maria-rcks Oct 11, 2026
7c5c624
fix(server): accepted webhooks survive restarts and stale scheduled d…
maria-rcks Oct 11, 2026
c54651b
fix(server): restart recovery continues every thread on a shared sess…
maria-rcks Oct 11, 2026
6d9ac3d
fix(server): steering and delegated launches survive restarts without…
maria-rcks Oct 11, 2026
b6aee55
fix(server): continuation keeps goal phases, held handoffs, clock cha…
maria-rcks Oct 11, 2026
24d4180
fix(server): background server updates roll back unhealthy releases a…
maria-rcks Oct 11, 2026
a708fcd
fix(server): a background server restart waits for idle terminals and…
maria-rcks Oct 11, 2026
bf11daf
fix(server): open tabs keep loading the previous web build's chunks a…
maria-rcks Oct 11, 2026
7645122
docs: a newer T3 Code release replaces one waiting for the update window
maria-rcks Oct 11, 2026
001b85f
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
6782535
fix(server): an interrupted provider install finishes its writes befo…
maria-rcks Oct 11, 2026
5267011
fix(web): About shows the desktop version and the sidebar shows updat…
maria-rcks Oct 11, 2026
821364b
fix(desktop): a downloaded update installs once at a real quit and a …
maria-rcks Oct 11, 2026
00b9170
fix(server): steering lost in a restart is prompted instead of folded…
maria-rcks Oct 11, 2026
1629953
test(server): cover the webhook queue migrations and a turn without a…
maria-rcks Oct 11, 2026
057df35
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
170ea48
fix(server): a service restarted by t3 update keeps external OpenCode…
maria-rcks Oct 11, 2026
5fb1d54
fix(server): migrate-dev-db drops queued webhook deliveries with othe…
maria-rcks Oct 11, 2026
15afd90
Merge remote-tracking branch 'origin/main' into t3/background-provide…
maria-rcks Oct 11, 2026
2df93d9
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
4416c32
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
755587c
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
38703ec
fix(server): background provider installs no longer stall or admit CL…
maria-rcks Oct 11, 2026
1e0c9e6
fix(server): older clients no longer show background provider install…
maria-rcks Oct 11, 2026
42aa115
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
c665cdb
fix(server): background server updates survive redirects, clock jumps…
maria-rcks Oct 11, 2026
efde7a7
perf(server): busy-terminal checks skip the process scan when a promp…
maria-rcks Oct 11, 2026
59f3900
docs: describe the launcher health period and post-commit rollback
maria-rcks Oct 11, 2026
78f1a2b
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
f115cab
fix(desktop): failed downloads, repeated quits, and AppImage detectio…
maria-rcks Oct 11, 2026
b4d78da
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
2268203
fix(pi): steering accepted before a restart is no longer lost
maria-rcks Oct 11, 2026
aba8a23
fix(server): restart continuation ignores ended runs and survives clo…
maria-rcks Oct 11, 2026
b7ff4b0
fix(server): restarts keep external OpenCode work, unanswered questio…
maria-rcks Oct 11, 2026
0db1be1
docs: describe continuation limits, waiting users, and accepted webho…
maria-rcks Oct 11, 2026
a2a5a16
fix(server): background updates recognize native pi, grok symlinks, C…
maria-rcks Oct 11, 2026
7e66636
fix(mobile): writable project settings follow write destinations and …
maria-rcks Oct 11, 2026
fe27fa0
fix(server): a detached supervisor finishes provider installs after t…
maria-rcks Oct 11, 2026
7e66549
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
73928d1
fix(server): a crash loop after an update commit never restores the o…
maria-rcks Oct 11, 2026
2e5508f
docs: describe crash-loop recovery without a post-commit database res…
maria-rcks Oct 11, 2026
4910b18
docs: describe the detached provider install supervisor
maria-rcks Oct 11, 2026
2a365b8
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
2c4068f
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
e23f87a
fix(desktop): quitting no longer waits on a provider install, which n…
maria-rcks Oct 11, 2026
ee81088
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
fe27f9e
fix(server): providers and terminals orphaned by a crash are stopped …
maria-rcks Oct 11, 2026
4f6f4c2
fix(server): a prompt accepted during a restart handoff resumes once …
maria-rcks Oct 11, 2026
23bb02a
fix(server): orphan cleanup never stops a provider install and surviv…
maria-rcks Oct 11, 2026
ccfa8cc
docs: describe orphaned provider cleanup before continuation
maria-rcks Oct 11, 2026
a57a275
fix(server): an undelivered prompt that is also pending steering cont…
maria-rcks Oct 11, 2026
87199d0
fix(server): a provider install keeps admission until its last child …
maria-rcks Oct 11, 2026
b2164c7
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
0dbeb87
fix(server): the service launcher stops a crashed server's orphaned p…
maria-rcks Oct 11, 2026
0b6bfb8
fix(client-runtime): a failed or rolled-back background server update…
maria-rcks Oct 11, 2026
7854446
fix(server): a provider cleanup failure no longer stops the service l…
maria-rcks Oct 11, 2026
27ea2d4
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
5d3c654
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
d389a5d
Merge remote-tracking branch 'origin/main' into t3/background-provide…
maria-rcks Oct 11, 2026
8507ed6
fix(server): pull request review guides wait for provider installs li…
maria-rcks Oct 11, 2026
dd1a08b
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
4ad7adb
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
6452e91
docs: describe the launcher stopping orphaned providers before it sta…
maria-rcks Oct 11, 2026
2628f0b
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
ab709bb
fix(server): orphan cleanup samples processes without blocking the se…
maria-rcks Oct 11, 2026
08d86d1
test(server): an initial prompt also saved as pending steering contin…
maria-rcks Oct 11, 2026
019b369
docs: point orphan cleanup at the shared process core and its server …
maria-rcks Oct 11, 2026
407fcbb
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
5c8be8a
test(server): the launcher cleanup failure case reaps a crashed serve…
maria-rcks Oct 11, 2026
105a160
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
3f6aa55
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
8a98dcc
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
ef4b9d6
Merge branch 't3/desktop-background-updates-int' into t3/continue-thr…
maria-rcks Oct 11, 2026
bf396d8
test(server): launcher tests never touch the real provider maintenanc…
maria-rcks Oct 11, 2026
7ebddc7
test(server): keep the host install gate test in a temporary cache
maria-rcks Oct 11, 2026
69a2f45
Merge branch 't3/background-server-updates-int' into t3/desktop-backg…
maria-rcks Oct 11, 2026
ac5fd46
fix(server): stale server registrations are pruned without dropping a…
maria-rcks Oct 11, 2026
740a721
fix(server): local file release mirrors still pass the download origi…
maria-rcks Oct 11, 2026
b367a97
fix(server): provider cleanup resumes a tree it froze when it cannot …
maria-rcks Oct 11, 2026
35b7f96
fix(server): installs drain readers, ignore foreign symlinks, and bou…
maria-rcks Oct 11, 2026
1e6bfc9
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
b26e418
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 11, 2026
8835719
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 11, 2026
651b3a2
fix(server): invalid server registrations no longer block startup, an…
maria-rcks Oct 11, 2026
2934544
fix(server): turns already holding the install lock never wait behind…
maria-rcks Oct 11, 2026
9039982
fix(server): restarts keep parent requests, frozen trees, and finishe…
maria-rcks Oct 11, 2026
ccc1014
Merge remote-tracking branch 'origin/main' into t3/background-provide…
maria-rcks Oct 11, 2026
99eb10f
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
c87b083
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 11, 2026
abda88b
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 11, 2026
b574fd0
fix(server): a reused process id never keeps a stale install lease alive
maria-rcks Oct 11, 2026
eb22e76
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
29b0303
fix(server): background server restarts wait for review guides, clone…
maria-rcks Oct 11, 2026
5f2e9d8
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 11, 2026
eab2bf2
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 11, 2026
838d87b
Merge remote-tracking branch 'origin/main' into t3/background-provide…
maria-rcks Oct 11, 2026
1990a52
Merge branch 't3/background-provider-updates-int' into t3/background-…
maria-rcks Oct 11, 2026
14ed50c
Merge branch 't3/background-server-updates' into t3/desktop-backgroun…
maria-rcks Oct 11, 2026
65975cb
Merge branch 't3/desktop-background-updates' into t3/continue-threads…
maria-rcks Oct 11, 2026
84c937c
test(server): drop a duplicate Fiber import left by the merge
maria-rcks Oct 11, 2026
9297264
fix(provider): retain install ownership through process exit and cleanup
maria-rcks Oct 11, 2026
d70a0d0
chore(stack): carry provider install ownership fixes
maria-rcks Oct 11, 2026
bb2e5f3
chore(stack): carry provider install ownership fixes
maria-rcks Oct 11, 2026
3fe0f41
chore(stack): carry provider install ownership fixes
maria-rcks Oct 11, 2026
6162219
fix(server): preserve active installer leases during startup cleanup
maria-rcks Oct 11, 2026
3844019
fix(server): preserve installer leases during launcher cleanup
maria-rcks Oct 11, 2026
b4d5600
test(server): cover installer leases created during cleanup
maria-rcks Oct 11, 2026
03e0982
chore(stack): carry launcher installer lease cleanup
maria-rcks Oct 11, 2026
a114cd5
chore(stack): carry launcher installer lease cleanup
maria-rcks Oct 11, 2026
70dcc18
test(server): await launcher startup without nesting promises
maria-rcks Oct 12, 2026
81e50c9
chore(stack): carry launcher regression setup fix
maria-rcks Oct 12, 2026
b36efe8
chore(stack): carry launcher regression setup fix
maria-rcks Oct 12, 2026
5fbd0b3
fix(server): reject stale server ancestry during crash cleanup
maria-rcks Oct 12, 2026
ed59b2a
fix(server): defer cleanup when a live launcher is unobservable
maria-rcks Oct 12, 2026
1429f1b
fix(server): restarts keep steering messages and stop duplicate launches
maria-rcks Oct 13, 2026
fdcd3cc
fix(server): restart recovery continues every thread on a shared session
maria-rcks Oct 13, 2026
b13f013
refactor(server): rebuild restart continuation fixes on main
maria-rcks Oct 13, 2026
70db8c3
fix(server): reconcile restart continuations with main
maria-rcks Oct 18, 2026
8fbd548
fix(server): retain context in restart steering
maria-rcks Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions apps/server/src/mcp/McpSessionRegistry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ it.effect("stores only a token hash, resolves the bearer token, and revokes by t
}),
);

it.effect("keeps the request namespace across credential reissue and splits it per thread", () =>
Effect.gen(function* () {
const registry = yield* makeRegistry(() => 1_000);
const request = {
threadId: ThreadId.make("thread-restarted"),
providerInstanceId: ProviderInstanceId.make("codex"),
};
const scopeOf = (issued: { readonly config: { readonly authorizationHeader: string } }) =>
registry.resolve(issued.config.authorizationHeader.replace(/^Bearer\s+/, ""));
const first = yield* scopeOf(yield* registry.issue(request));
const second = yield* scopeOf(yield* registry.issue(request));
const other = yield* scopeOf(
yield* registry.issue({ ...request, threadId: ThreadId.make("thread-other") }),
);
expect(second?.thread.providerSessionId).not.toBe(first?.thread.providerSessionId);
expect(second?.requestNamespace).toBe(first?.requestNamespace);
expect(other?.requestNamespace).not.toBe(first?.requestNamespace);
}),
);

it.effect("always grants pull-requests and gates browser and device access independently", () =>
Effect.gen(function* () {
const registry = yield* makeRegistry(() => 1_000);
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/mcp/McpSessionRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (
const browserToolsAvailable = request.browserToolsAvailable ?? true;
const scope: McpInvocationContext.McpThreadInvocationScope = {
environmentId,
requestNamespace: providerSessionId,
// Retrying an accepted write after a restart must reuse its receipt.
requestNamespace: `thread:${encodeURIComponent(request.threadId)}:${encodeURIComponent(request.providerInstanceId)}`,
thread: {
threadId: ThreadId.make(request.threadId),
providerSessionId,
Expand Down
91 changes: 91 additions & 0 deletions apps/server/src/mcp/toolkits/project/handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,97 @@ it.effect("attributes a launched thread's first message to the calling thread",
}),
);

it.effect(
"a launch retried with the same clientRequestId keeps its command after session rotation",
() =>
Effect.gen(function* () {
const sourceThreadId = ThreadId.make("source-thread");
const projectId = ProjectId.make("project");
const providerInstanceId = ProviderInstanceId.make("codex");
const modelSelection = { instanceId: providerInstanceId, model: "gpt-5" };
const caller = {
id: sourceThreadId,
projectId,
providerInstanceId,
modelSelection,
runtimeMode: "full-access",
interactionMode: "default",
activeRunId: "active-run",
archivedAt: null,
deletedAt: null,
} as OrchestrationV2ThreadShell;
const launches: Array<ThreadLaunch.ThreadLaunchInput> = [];
const launch = (clientRequestId: string | undefined, requestNamespace: string) =>
Effect.gen(function* () {
const dependencies = Layer.mergeAll(
ServerSettings.layerTest(),
NodeCrypto.layer,
Layer.succeed(McpInvocationContext.McpInvocationContext, {
environmentId: EnvironmentId.make("environment"),
requestNamespace,
thread: {
threadId: sourceThreadId,
providerSessionId: "session",
providerInstanceId,
},
client: undefined,
issuedAt: 0,
capabilities: new Set(["orchestration" as const]),
}),
Layer.mock(ThreadManagement.ThreadManagementService)({
getThreadShell: () => Effect.succeed(caller),
}),
Layer.mock(ThreadLaunch.ThreadLaunchService)({
launch: (input) => {
launches.push(input);
return Effect.succeed({
threadId: input.threadId,
projection: {
thread: { id: input.threadId, projectId, modelSelection },
runs: [],
},
resumed: false,
} as unknown as ThreadLaunch.ThreadLaunchResult);
},
}),
Layer.mock(Project.ProjectService)({}),
Layer.mock(ManagedProjectFolders.ManagedProjectFolders)({
namedProjectsRoot: "/projects",
}),
Layer.mock(GitVcsDriver.GitVcsDriver)({}),
NodeServices.layer,
ServerConfig.layerTest(process.cwd(), { prefix: "t3-launch-retry-" }).pipe(
Layer.provide(NodeServices.layer),
),
);
const toolkit = yield* ProjectToolkit.pipe(
Effect.provide(
McpToolAccess.HandlersLayer.layer(ProjectHandlers.layer).pipe(
Layer.provide(dependencies),
),
),
);
yield* toolkit
.handle("t3_thread_launch", {
title: "Audit",
message: "Review the change",
...(clientRequestId === undefined ? {} : { clientRequestId }),
})
.pipe(Stream.unwrap, Stream.runCollect, Effect.provide(dependencies));
});
// The namespace is stable per thread, so a rotated session still matches.
yield* launch("retry-launch", "thread:source-thread:codex");
yield* launch("retry-launch", "thread:source-thread:codex");
expect(launches[1]?.commandId).toBe(launches[0]?.commandId);
expect(launches[1]?.threadId).toBe(launches[0]?.threadId);
expect(launches[1]?.initialMessage?.messageId).toBe(launches[0]?.initialMessage?.messageId);
yield* launch("retry-launch", "thread:other-thread:codex");
yield* launch(undefined, "thread:source-thread:codex");
yield* launch(undefined, "thread:source-thread:codex");
expect(new Set(launches.map((input) => input.threadId)).size).toBe(4);
}),
);

it.effect("launches a scratch thread into the Scratch project", () =>
Effect.gen(function* () {
const sourceThreadId = ThreadId.make("source-thread");
Expand Down
15 changes: 13 additions & 2 deletions apps/server/src/mcp/toolkits/project/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { MessageId, ThreadId, OrchestratorMcpFailure, ProjectId } from "@t3tools/contracts";
import {
CommandId,
MessageId,
ThreadId,
OrchestratorMcpFailure,
ProjectId,
} from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Option from "effect/Option";
Expand Down Expand Up @@ -57,7 +63,12 @@ export const layer = McpToolAccess.toLayer(ProjectToolkit, {
Effect.gen(function* () {
const context = yield* readCaller();
const { caller } = context;
const commandId = yield* newCommandId();
const commandId =
input.clientRequestId === undefined
? yield* newCommandId()
: CommandId.make(
`command:mcp:${encodeURIComponent(context.scope.requestNamespace)}:thread-launch:${encodeURIComponent(input.clientRequestId)}`,
);
const threadId = ThreadId.make(commandId);
const messageId = MessageId.make(commandId);
const attachments = input.attachments ?? [];
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/mcp/toolkits/project/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ const ProjectCloneTool = Tool.make("t3_project_clone", {
const ThreadLaunchTool = Tool.make("t3_thread_launch", {
...shared,
description:
'Create an ordinary TOP-LEVEL thread with an explicit workspace binding before its agent starts. Use this when the user requests independent work, a new thread, or a PR stack in its own worktree; use delegate_task for child subagents. Set workspaceStrategy to {type:"worktree",baseRef:"parent-branch",branch:"new-branch",startFromOrigin:false} for a new worktree based on local commits, or {type:"existing_worktree",worktreePath:"/absolute/path",branch:"existing-branch"} to use an existing checkout. For upstream commits, set startFromOrigin:true. Omitted workspaceStrategy means the project root, NOT the caller\'s worktree. Omit projectId/modelSelection/modes to inherit those settings from the calling thread; a caller outside a T3 thread must pass projectId and gets the project\'s default model. Set scratch:true instead of projectId for a thread without a project: it runs in a fresh folder of its own, outside any repository. Put the task in message. Do not ask the agent to create its own worktree via shell: that does not update the thread binding. Each call creates a new launch with no retry key; retain threadId and use t3_thread_read/t3_thread_wait to follow preparation. To link a thread for the user, write `[title](t3-thread://v1/<threadId>)` with the threadId exactly as returned, not URL-encoded; T3 Code shows the thread\'s current title. After errors or lost responses, inspect t3_thread_list before retrying. Attachments must be pending uploads. The new thread may not run with broader runtime or interaction modes than the caller: the calling T3 thread\'s own modes, or the permission mode an outside agent was approved with.',
'Create an ordinary TOP-LEVEL thread with an explicit workspace binding before its agent starts. Use this when the user requests independent work, a new thread, or a PR stack in its own worktree; use delegate_task for child subagents. Set workspaceStrategy to {type:"worktree",baseRef:"parent-branch",branch:"new-branch",startFromOrigin:false} for a new worktree based on local commits, or {type:"existing_worktree",worktreePath:"/absolute/path",branch:"existing-branch"} to use an existing checkout. For upstream commits, set startFromOrigin:true. Omitted workspaceStrategy means the project root, NOT the caller\'s worktree. Omit projectId/modelSelection/modes to inherit those settings from the calling thread; a caller outside a T3 thread must pass projectId and gets the project\'s default model. Set scratch:true instead of projectId for a thread without a project: it runs in a fresh folder of its own, outside any repository. Put the task in message. Do not ask the agent to create its own worktree via shell: that does not update the thread binding. Pass a stable clientRequestId to retry the same launch after errors or restarts; retain threadId and use t3_thread_read/t3_thread_wait to follow preparation. To link a thread for the user, write `[title](t3-thread://v1/<threadId>)` with the threadId exactly as returned, not URL-encoded; T3 Code shows the thread\'s current title. After errors or lost responses, inspect t3_thread_list before retrying. Attachments must be pending uploads. The new thread may not run with broader runtime or interaction modes than the caller: the calling T3 thread\'s own modes, or the permission mode an outside agent was approved with.',
parameters: Schema.Struct({
clientRequestId: Schema.optional(TrimmedNonEmptyString.check(Schema.isMaxLength(256))),
projectId: Schema.optional(ProjectId),
scratch: Schema.optional(
Schema.Boolean.annotate({
Expand Down
148 changes: 148 additions & 0 deletions apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3458,6 +3458,154 @@ describe("CodexAdapterV2 post-settle continuation", () => {
),
);

it.effect.each(["active-goal", "no-goal"] as const)(
"a continuation Codex rejects as EmptyInput retries only on an active goal (%s)",
(state) =>
Effect.scoped(
Effect.gen(function* () {
const scenario = "codex-restart-empty-input";
const nativeThreadId = "native-restart-empty-input";
const nativeTurnId = "turn-restart-empty-input";
const prompt = "Continue where you left off.";
const preamble = codexReplayPreamble({
nativeThreadId,
nativeTurnId,
prompt: "unused",
}).slice(0, 5);
const turnParams = {
threadId: nativeThreadId,
cwd: "/workspace",
model: "gpt-5.4",
approvalPolicy: "never",
approvalsReviewer: "user",
sandboxPolicy: { type: "dangerFullAccess" },
summary: "detailed",
};
const transcript = makeCodexReplayTranscript({
scenario,
entries: [
...preamble,
{
type: "expect_outbound",
label: "resume",
frame: {
id: 3,
method: "thread/resume",
params: {
threadId: nativeThreadId,
excludeTurns: true,
config: CodexAdapterV2.CODEX_THREAD_CONFIG,
},
},
},
{
type: "emit_inbound",
label: "resume",
frame: { id: 3, result: { thread: { id: nativeThreadId, updatedAt: 1782622450 } } },
},
{
type: "expect_outbound",
label: "empty continue",
frame: { id: 4, method: "turn/start", params: { ...turnParams, input: [] } },
},
{
type: "emit_inbound",
label: "empty continue",
frame: {
id: 4,
error: { code: -32603, message: "failed to submit turn input: EmptyInput" },
},
},
{
type: "expect_outbound",
label: "read goal",
frame: { id: 5, method: "thread/goal/get", params: { threadId: nativeThreadId } },
},
{
type: "emit_inbound",
label: "read goal",
frame: {
id: 5,
result: {
goal:
state === "no-goal"
? null
: {
threadId: nativeThreadId,
objective: "Finish the work",
status: "active",
tokenBudget: null,
tokensUsed: 10,
timeUsedSeconds: 3,
createdAt: 1782622440,
updatedAt: 1782622450,
},
},
},
},
...(state === "active-goal"
? [
{
type: "expect_outbound" as const,
label: "prompted continue",
frame: {
id: 6,
method: "turn/start",
params: { ...turnParams, input: [{ type: "text", text: prompt }] },
},
},
{
type: "emit_inbound" as const,
label: "prompted continue",
frame: {
id: 6,
result: {
turn: makeCodexReplayTurn({ id: nativeTurnId, status: "inProgress" }),
},
},
},
]
: []),
],
});
const harness = yield* makeCodexReplayHarness(transcript);
const resumed = yield* harness.runtime.resumeThread({
providerThread: harness.providerThread,
modelSelection: CODEX_TEST_MODEL_SELECTION,
runtimePolicy: CODEX_TEST_RUNTIME_POLICY,
});
const started = yield* harness.runtime
.startTurn({
...makeCodexTestTurnInput({
threadId: harness.threadId,
providerThread: resumed,
now: yield* DateTime.now,
attemptId: RunAttemptId.make("attempt-restart-empty-input"),
text: prompt,
}),
restartContinuationOfRunId: RunId.make("run-before-restart"),
})
.pipe(Effect.result);
if (state === "active-goal") {
assert.equal(started._tag, "Success");
return;
}
assert.equal(started._tag, "Failure");
if (started._tag === "Failure") {
assert.nestedPropertyVal(
started.failure,
"cause.errorMessage",
"failed to submit turn input: EmptyInput",
);
}
}).pipe(
Effect.provide(
Layer.mergeAll(IdAllocator.layer, McpProviderSessions.layer, NodeServices.layer),
),
),
),
);

it.effect("resolves retryable app-server errors on resumed provider activity", () =>
Effect.scoped(
Effect.gen(function* () {
Expand Down
27 changes: 24 additions & 3 deletions apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6614,11 +6614,32 @@ export const makeCodexAdapterV2 = Effect.fn("makeCodexAdapterV2")(function* (
: null;
if (goalCommand !== null) return runGoalCommand(turnInput, goalCommand);
return Effect.gen(function* () {
yield* startNativeTurn(
turnInput,
const input =
turnInput.restartContinuationOfRunId === undefined
? yield* toCodexInput(turnInput)
: [],
: [];
yield* startNativeTurn(turnInput, input).pipe(
Effect.catchTags({
CodexAppServerRequestError: (cause) => {
// Codex rejects an empty continuation while a goal turn is
// still active. Send the continue prompt as real input.
if (
input.length !== 0 ||
cause.code !== -32603 ||
cause.errorMessage !== "failed to submit turn input: EmptyInput"
)
return Effect.fail(cause);
return Effect.gen(function* () {
const current = yield* client
.request("thread/goal/get", {
threadId: yield* getNativeThreadId(turnInput.providerThread),
})
.pipe(Effect.orElseSucceed(() => null));
if (current?.goal?.status !== "active") return yield* Effect.fail(cause);
yield* startNativeTurn(turnInput, yield* toCodexInput(turnInput));
});
},
}),
);
}).pipe(
Effect.mapError(
Expand Down
Loading
Loading