Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
934 commits
Select commit Hold shift + click to select a range
c2e2f43
syncsetup: a paired computer lets go of an idle chat once everything …
AbirAbbas Nov 3, 2026
ea945b5
handoff: opening a released chat on a paired computer takes it withou…
AbirAbbas Nov 3, 2026
264eda7
tui3: a released window takes its chat back in place, and Home opens …
AbirAbbas Nov 3, 2026
ac27347
app: chat rows say when a chat can be opened here, and sends take a r…
AbirAbbas Nov 3, 2026
5dad3ae
synctake: a chat's copy folder keeps one bounded name however often i…
AbirAbbas Nov 3, 2026
f2d40e5
manual: an idle chat moves with you between paired computers
AbirAbbas Nov 3, 2026
eab2368
app, terminal: the new lock sections unlock from a defer
AbirAbbas Nov 3, 2026
7aa12fa
docs: number the change entry for #2287
AbirAbbas Nov 3, 2026
614c142
docs: the change entry names #2287
AbirAbbas Nov 3, 2026
63cff5f
A job has one manager, and all its spend counts against its budget (#…
santoshkumarradha Nov 3, 2026
067d619
Merge origin/dev into app/v3 with recorded ancestry
santoshkumarradha Nov 3, 2026
2531422
Merge latest origin/app/v3 after dev ancestry repair
santoshkumarradha Nov 3, 2026
c4a0834
Document dev ancestry repair for codeaf
santoshkumarradha Nov 3, 2026
db2c06f
Merge newest origin/dev into app/v3
santoshkumarradha Nov 3, 2026
3382362
Validate newest dev integration with app/v3 behavior
santoshkumarradha Nov 3, 2026
5b5a892
Memory resume test checks the sources it inherited (#2284)
santoshkumarradha Nov 3, 2026
15db2c5
Turn host pressure off in the E13 B2 recovery test (#2246)
santoshkumarradha Nov 3, 2026
750a39c
app tests: a fake's lane holds what is put on it until the backend wa…
santoshkumarradha Nov 3, 2026
c21dd17
tests: R2 and R3 wait for the startup publication instead of chats.li…
santoshkumarradha Nov 3, 2026
4b76586
tests: damage the teams store, not a teams.json, before continuing a …
santoshkumarradha Nov 3, 2026
ac2d14f
tests: keeping an unsent turn on an ownership check needs the store t…
santoshkumarradha Nov 3, 2026
92b3460
syncsetup: the takeover proof's own sessions run with routing off (#2…
santoshkumarradha Nov 3, 2026
a4937f0
Run the clock while a learner waits for a state write (#2227)
santoshkumarradha Nov 3, 2026
7ffd86e
Check pairing copy around the random check words (#2228)
santoshkumarradha Nov 3, 2026
d090b37
Merge remote-tracking branch 'origin/app/v3' into HEAD
santoshkumarradha Nov 3, 2026
a94d7e2
Correct the team sharing default in the manual and PERF.md
santoshkumarradha Nov 3, 2026
8ad21b3
Adapt team relay regression fixtures to SQLite and opt-in sharing
santoshkumarradha Nov 3, 2026
942993a
syncsetup: an idle terminal chat releases again, and a late notice ne…
AbirAbbas Nov 3, 2026
315cd1f
syncsetup: ordinary home-state rounds wait for a competing flush again
AbirAbbas Nov 3, 2026
b96dda3
synctake: a copy folder is reused only for the exact copy root it names
AbirAbbas Nov 3, 2026
1aebd7d
tui3: a setting changed in a released terminal window retakes the hol…
AbirAbbas Nov 3, 2026
dd8f90f
session: a persistent setting in a released window goes through the o…
AbirAbbas Nov 3, 2026
0335dc0
app: settings in a released window retake the hold or are refused
AbirAbbas Nov 3, 2026
2e3935d
manual: settings after an idle release, and offline work in a held chat
AbirAbbas Nov 3, 2026
759c2c9
notices: add the fsnotify section the binary already compiles (#2202)
santoshkumarradha Nov 3, 2026
c4c5fee
catalog: Recall reads the media standing from the clock it was given …
santoshkumarradha Nov 3, 2026
c04e959
head: the spending rate multiplies from the days it names (#2204)
santoshkumarradha Nov 3, 2026
26efa2a
raftcore: a wake restarts the idle minute, so a write's learner deliv…
santoshkumarradha Nov 3, 2026
1769c58
Merge app/v3 into dev merge
santoshkumarradha Nov 3, 2026
f23e01b
fix(app): keep distinct identities for cell-backed crew helpers (#1964)
santoshkumarradha Nov 3, 2026
98f007d
app: say an agent's live line as its turn moves to each call (#2068)
santoshkumarradha Nov 3, 2026
79d83f9
app: a suggested choice's clock runs only once a surface has drawn it…
santoshkumarradha Nov 3, 2026
77b17cd
Stop wins until the PR request is sent (#2299)
santoshkumarradha Nov 3, 2026
9fcdd6f
The resume heap test measures in isolation (#2300)
santoshkumarradha Nov 3, 2026
941f5a3
The eviction test waits for the engine before removing its folder (#2…
santoshkumarradha Nov 3, 2026
2f02530
session: run workers act as their task; task rows name their worker; …
santoshkumarradha Nov 3, 2026
e92a89d
session: under one model every role resolves to the one model, throug…
santoshkumarradha Nov 3, 2026
3f9d4cb
An added job step can carry a condition (#2293)
santoshkumarradha Nov 3, 2026
e82f71c
A job step's cost is the sum of its rounds (#2294)
santoshkumarradha Nov 3, 2026
1c6b940
Every crew watch is built one way (#2295)
santoshkumarradha Nov 3, 2026
9035a0a
Closed GitHub issues leave Backlog, and a closed issue can't be auto-…
santoshkumarradha Nov 3, 2026
427c35a
Cancelled calls keep the money that was measured (#2302)
santoshkumarradha Nov 3, 2026
b2d5b85
Asks keep their last period (#2304)
santoshkumarradha Nov 3, 2026
95c077b
syncsetup: Close always stops an ordinary writer, and a take-back cle…
AbirAbbas Nov 3, 2026
ce8e900
session: a person's durable write in a released window retakes the ho…
AbirAbbas Nov 3, 2026
ca395d0
cellstore: idle certification visits each path once, within fixed bounds
AbirAbbas Nov 3, 2026
8b0bfa6
app: a lent factory view keeps its model policy on the checked door
AbirAbbas Nov 3, 2026
e6dcd9f
manual: say sync service, and settings retake a released chat
AbirAbbas Nov 3, 2026
48466e5
Steps can carry an optional label (#2307)
santoshkumarradha Nov 3, 2026
29e1139
A job keeps its earlier spending when it runs again (#2305)
santoshkumarradha Nov 3, 2026
93755da
Merge newest app/v3 under Factory owner rule
santoshkumarradha Nov 3, 2026
5484a2c
Restore dev sharing defaults and ordinary file memo fallback
santoshkumarradha Nov 3, 2026
d08bca0
Require confirmed replacement for used solo computers
santoshkumarradha Nov 3, 2026
10d456a
Limit unsupported-effort repair to opted-in task clients
santoshkumarradha Nov 3, 2026
93d4b7f
Restore dev ownership expiry and exact-fence consent
santoshkumarradha Nov 3, 2026
6e1e37c
Factory: serve the stored repository list and refresh it in the backg…
santoshkumarradha Nov 3, 2026
8b88f75
fix: retain Factory client effort recovery
santoshkumarradha Nov 3, 2026
78011b1
fix: complete same-account replacement cleanup
santoshkumarradha Nov 3, 2026
1f5060e
fix: preserve unreadable profile spending authority
santoshkumarradha Nov 3, 2026
c202693
fix: distinguish Factory work from available tools
santoshkumarradha Nov 3, 2026
b66262a
Step conditions read the change's files (#2311)
santoshkumarradha Nov 3, 2026
f0d91d7
Step and My pipeline AI count as Factory AI (#2316)
santoshkumarradha Nov 3, 2026
72a4fda
Notes and the completion guard share one command outcome (#2298)
santoshkumarradha Nov 3, 2026
1960297
Merge latest app/v3 for Factory owner-rule follow-up
santoshkumarradha Nov 3, 2026
2a3c2eb
Opening a job doesn't count as a person's touch (#2312)
santoshkumarradha Nov 3, 2026
027c629
Scope Factory reasoning recovery to live calls and align pairing with…
santoshkumarradha Nov 3, 2026
056630e
Merge newest app/v3 Factory job touch tracking
santoshkumarradha Nov 3, 2026
8295923
Use one Factory AI classification for billing and refusal recovery
santoshkumarradha Nov 3, 2026
38d4382
syncdrive: a durable write reads the live drive without waiting on it…
AbirAbbas Nov 3, 2026
7d1fe24
syncsetup: taking a released chat back gets a write-sized budget, and…
AbirAbbas Nov 3, 2026
d7f023a
manual: what happens when taking a chat back cannot be confirmed
AbirAbbas Nov 3, 2026
a6d0989
fix: recover effort for job-owned Factory conversations
santoshkumarradha Nov 3, 2026
4474fb6
fix: prompt on unreadable ordinary profile policy
santoshkumarradha Nov 3, 2026
a042b31
fix: require human approval when profile rules cannot be read
santoshkumarradha Nov 3, 2026
0ef0e27
A budget raise isn't refused by spend progress (#2321)
santoshkumarradha Nov 3, 2026
b46824a
Merge app/v3 into dev merge
santoshkumarradha Nov 3, 2026
2421f5a
Manual names the two kinds of work an unreadable profile does not pro…
santoshkumarradha Nov 3, 2026
21e4bd6
Pairing QA fixes: failures, approvals, removed computers, devices loo…
ZeroPoint95 Nov 3, 2026
065da00
A person's pause survives a lost heartbeat reply (#2330)
santoshkumarradha Nov 3, 2026
79c8a94
Pairing follow-ups: app and pair approve settle a lost reply; chat ro…
ZeroPoint95 Nov 3, 2026
d5f07a3
Plugins: desktop protocol over the connect layer (#2331)
santoshkumarradha Nov 4, 2026
36d72a6
fix: restore automatic retries for ordinary memory builds
santoshkumarradha Nov 4, 2026
9d5573e
Merge newest dev into the dev merge
santoshkumarradha Nov 4, 2026
778b67b
A person's Stop stays stopped until a person starts it (#2335)
santoshkumarradha Nov 4, 2026
09d1d64
fix: bound ordinary memory build retries across restarts
santoshkumarradha Nov 4, 2026
758d98a
Merge newest app/v3 into the dev merge
santoshkumarradha Nov 4, 2026
b788f30
fix: preserve local chats when a removed computer re-pairs
santoshkumarradha Nov 4, 2026
0982bf6
A repository with no factory file starts quietly, and a job's rules a…
santoshkumarradha Nov 4, 2026
b62309a
fix: keep empty memory startup joinable
santoshkumarradha Nov 4, 2026
90acb78
merge: bring app/v3 0982bf6b41 into the dev merge
santoshkumarradha Nov 4, 2026
30a3400
Factory: a job that has not worked reads its issue instead of repeati…
santoshkumarradha Nov 4, 2026
94ca31d
Owed checks name the tool, not a machine's path (#2322)
santoshkumarradha Nov 4, 2026
22d06d4
Publish anyway: a person ships past correctly skipped checks (#2323)
santoshkumarradha Nov 4, 2026
419631c
Take tests judge rows only after the take starts (#2340)
santoshkumarradha Nov 4, 2026
414e036
merge: bring app/v3 419631c50c into the dev merge
santoshkumarradha Nov 4, 2026
57a8593
factory: shipped steps carry short engineering methods (#2286)
santoshkumarradha Nov 4, 2026
e256d4f
merge: bring app/v3 57a8593d9d into the dev merge
santoshkumarradha Nov 4, 2026
c50abac
A running step's chat streams like the manager's (#2329)
santoshkumarradha Nov 4, 2026
1950ba0
merge: bring app/v3 c50abac31a into the dev merge
santoshkumarradha Nov 4, 2026
012b87c
Other computers list more of this one's chats, sooner, and say how ma…
ZeroPoint95 Nov 4, 2026
8dc722d
docs: name pull request 2341 in its change entry (#2344)
santoshkumarradha Nov 4, 2026
a3ae454
Test runner names a shard mismatch instead of exiting silently (#2345)
santoshkumarradha Nov 4, 2026
0f8574e
A take no longer loses or double-counts cost (#2332)
santoshkumarradha Nov 4, 2026
59cdf22
Memory off skips the job marking, and the marking seeks by session (#…
santoshkumarradha Nov 4, 2026
aa11451
merge: bring app/v3 59cdf222b6 into the dev merge
santoshkumarradha Nov 4, 2026
8fc146c
test: pair before saving the key in the home-sharing tests
santoshkumarradha Nov 4, 2026
d35a0dc
Moving a chat says how far it has got, stops when stalled, and can be…
ZeroPoint95 Nov 4, 2026
1f1a733
Agent spend is complete: agents.open and agent.changed carry the save…
AbirAbbas Nov 4, 2026
3dea593
A person's choice survives a lost heartbeat reply (#2339)
santoshkumarradha Nov 4, 2026
1d17f14
Closing a conversation waits for its queued spending records (#2357)
santoshkumarradha Nov 4, 2026
95cc25a
fix: unlock the move lookup from a defer (#2359)
santoshkumarradha Nov 4, 2026
82d8fb3
A chat an older window holds opens in the app (#2349)
santoshkumarradha Nov 4, 2026
f483835
Shipped sidecars can say why they crashed (#2351)
santoshkumarradha Nov 4, 2026
a32c3f0
Merge remote-tracking branch 'origin/app/v3' into HEAD
santoshkumarradha Nov 4, 2026
efc60d8
Revert "Closing a conversation waits for its queued spending records …
santoshkumarradha Nov 4, 2026
1ee7043
Save the work folder at pauses, not after every tool batch (#2356)
AbirAbbas Nov 4, 2026
dafd6b6
Merge remote-tracking branch 'origin/app/v3' into HEAD
santoshkumarradha Nov 4, 2026
87c7f49
CheckLease waits for the branch when the hold is already lost
santoshkumarradha Nov 4, 2026
8376957
Merge pull request #2291 from Agent-Field/merge/dev-into-app-v3-1102
santoshkumarradha Nov 4, 2026
25ab625
fix: a Stop during lease reservation can't restart a job (#2362)
santoshkumarradha Nov 4, 2026
34735af
Agents cannot read credentials in any approval mode (#2354)
santoshkumarradha Nov 4, 2026
a8a9d8b
Closing a conversation waits for queued spending records (#2365)
santoshkumarradha Nov 5, 2026
6966064
An unreadable profile stops default Factory stages and task children …
santoshkumarradha Nov 5, 2026
7c4e02a
A step named provenance isn't a proof stage (#2368)
santoshkumarradha Nov 5, 2026
d406fec
Wait for the cut call's receipt in the cancelled-retry money test (#2…
santoshkumarradha Nov 5, 2026
7c07a80
Give cmd/codeaf 35 minutes in the full test run (#2372)
santoshkumarradha Nov 5, 2026
b574549
Commit recipe changes as codeaf, not the person's git identity (#2373)
santoshkumarradha Nov 5, 2026
a9a8609
Stop the pairing test's engine daemons before removing their folders …
santoshkumarradha Nov 5, 2026
ab96a99
Keep a receipt test's late recovery out of the next test's telemetry …
santoshkumarradha Nov 5, 2026
ea0ead4
Jobs from people without write access are refused for any step that c…
santoshkumarradha Nov 5, 2026
ce8e526
A job's budget covers all its runs (#2353)
santoshkumarradha Nov 5, 2026
a27b89d
Make the live Factory money tests wait for cut calls' receipts (#2378)
santoshkumarradha Nov 5, 2026
234ebc4
Give tests one helper that stops engine daemons before their folders …
santoshkumarradha Nov 5, 2026
4f93ac6
Remove abandoned task fork folders during fallback and startup (#2352)
santoshkumarradha Nov 5, 2026
086687f
Tasks on the home folder read it instead of copying it, and launch cl…
santoshkumarradha Nov 5, 2026
39e7387
Store a crew proposal in Inbox before its card goes out (#2382)
santoshkumarradha Nov 5, 2026
5ad0bac
Join the shared usage writer before task test homes are removed (#2383)
santoshkumarradha Nov 5, 2026
92e24a4
Join usage writers before Factory test homes are removed (#2384)
santoshkumarradha Nov 5, 2026
8a14096
Close waits for knowledge capture to finish (#2385)
santoshkumarradha Nov 5, 2026
4e7710a
A job budget stop explains itself to an idle chat (#2388)
santoshkumarradha Nov 5, 2026
d5eec9e
app: stop-all during an open stops what the owner holds (#2313)
santoshkumarradha Nov 5, 2026
8672049
Keep context deadline and cancel errors recognisable across the remot…
santoshkumarradha Nov 5, 2026
a2dee5c
Drain receipt writers before cellindex tests remove their engine (#2390)
santoshkumarradha Nov 5, 2026
db138db
Add desktop Library access to shared knowledge (#2369)
santoshkumarradha Nov 5, 2026
88383c8
Revert "Add desktop Library access to shared knowledge (#2369)" (#2410)
santoshkumarradha Nov 5, 2026
a9ab253
Describe task folders without promising copies (#2391)
santoshkumarradha Nov 5, 2026
44214a3
Old Factory jobs fill missing author access when read (#2392)
santoshkumarradha Nov 5, 2026
df95f69
Task prompts and manual describe folders without promising copies (#2…
santoshkumarradha Nov 5, 2026
115ae11
Stopped engines stay stopped and keep pending receipts (#2394)
santoshkumarradha Nov 5, 2026
ebffb55
Classify stage, plan and share tools for program holds (#2397)
santoshkumarradha Nov 5, 2026
6b12328
Pin the land maintenance fixture to the gc strategy (#2398)
santoshkumarradha Nov 5, 2026
964090f
Workers accept glob write scopes without allowing workspace escapes (…
santoshkumarradha Nov 5, 2026
a345d07
read_document returns short office documents instead of refusing them…
santoshkumarradha Nov 5, 2026
4ee4fe9
Sharing a file write already recorded records nothing new (#2402)
santoshkumarradha Nov 5, 2026
ba07394
Wait for render admission release before testing reuse (#2405)
santoshkumarradha Nov 5, 2026
06c72bf
Stop the beat before the withdrawn takeover test asks (#2406)
santoshkumarradha Nov 5, 2026
8200ddb
Say when a turn is running on the computer that holds a chat (#2375)
santoshkumarradha Nov 5, 2026
ba629a3
chat: message a chat working on another computer; it waits in the que…
santoshkumarradha Nov 5, 2026
046003e
manual: the desktop composer's destination chip (#2420)
santoshkumarradha Nov 5, 2026
9316d94
Revert #2420, #2408 and #2375: a second computer writes to a held cha…
santoshkumarradha Nov 5, 2026
6ec213f
Re-land #2375, #2408, #2420: working elsewhere, messages to a held ch…
santoshkumarradha Nov 5, 2026
0aa1d61
fix: preserve missing-pack share evidence and retry with a fresh plan…
santoshkumarradha Nov 5, 2026
abcbea7
Trim chat prefixes back under their byte budgets (#2396)
santoshkumarradha Nov 5, 2026
1d19115
codeaf's own git commands start no automatic maintenance (#2400)
santoshkumarradha Nov 5, 2026
fec38df
Empty crew plans explain their ending and allow a fresh retry (#2403)
santoshkumarradha Nov 5, 2026
c40c124
Stop an app child's engine daemon before its test removes the state (…
santoshkumarradha Nov 5, 2026
0ca430e
Re-land desktop Library access to shared knowledge, keeping the defau…
santoshkumarradha Nov 5, 2026
4148c6c
A cut-off opening planner reply retries instead of becoming an empty …
santoshkumarradha Nov 5, 2026
43ec2a9
ci: run the light PR gate for app/v3 (#2430)
santoshkumarradha Nov 5, 2026
c7ce782
fix: sync chat folders through the hosted relay (#2431)
santoshkumarradha Nov 5, 2026
466c3d5
fix: serialize first-share capture with concurrent store writers (#2433)
santoshkumarradha Nov 5, 2026
9104087
Refuse lost later planner amendments and give repairs room for the re…
santoshkumarradha Nov 5, 2026
11782a9
Count held-chat relay writes by sender, not by path (#2428)
santoshkumarradha Nov 5, 2026
9a87ed6
test: wait for the initial holder watch before the idle baseline (#2435)
santoshkumarradha Nov 5, 2026
5f5b87f
Preserve usage events when processes share a telemetry spool (#2437)
santoshkumarradha Nov 6, 2026
224aa97
Keep provider keys consistent when opening conversations (#2438)
santoshkumarradha Nov 6, 2026
849aa2b
ci: shard cmd/codeaf in the touched gate (#2443)
santoshkumarradha Nov 6, 2026
8b45c3e
test: strip retained pairing check words from copy assertions (#2441)
santoshkumarradha Nov 6, 2026
a7f15e4
test: join Factory fixture process before removing its profile (#2442)
santoshkumarradha Nov 6, 2026
faed775
fix: advertise working app chat turns on other computers (#2432)
santoshkumarradha Nov 6, 2026
8a34e7c
Show Library costs and enable learning for unset profiles (#2444)
santoshkumarradha Nov 6, 2026
83fc0c5
request_secret: credentials through a masked box, kept out of the con…
santoshkumarradha Nov 6, 2026
e8a0c11
A chat moved back keeps the other computer's turn, and the next messa…
ZeroPoint95 Nov 6, 2026
a2a444a
test: pin the immediate chat start and the kept tab text (#2447)
santoshkumarradha Nov 6, 2026
cb24f0e
Keep a removed computer quiet when it quits (#2448)
santoshkumarradha Nov 6, 2026
7b49cb8
Isolate engine factory state between test homes (#2449)
santoshkumarradha Nov 6, 2026
776bf2e
test: keep endpoint fetches out of truncated reply script (#2451)
santoshkumarradha Nov 6, 2026
543d7d7
test: isolate second interrupt from inherited SIGINT ignore (#2454)
santoshkumarradha Nov 6, 2026
c8f66b1
test: pin learning off in the identity startup fixture (#2455)
santoshkumarradha Nov 6, 2026
4f3fa6a
test: order returning tab update before hosted replay read (#2453)
santoshkumarradha Nov 6, 2026
3a6aa31
test: give quitting exchanges separate errand agents (#2456)
santoshkumarradha Nov 6, 2026
f9a24c5
Wait briefly for an in-progress lane save when quitting (#2457)
santoshkumarradha Nov 6, 2026
aaef2fa
test: settle setup before measuring idle release (#2467)
santoshkumarradha Nov 6, 2026
2c78de1
Let an idle desktop app's saving helper exit (#2466)
AbirAbbas Nov 6, 2026
2c717c0
Let idle desktop chat views beyond the three most recent go (#2472)
AbirAbbas Nov 6, 2026
34c832e
Revert: let idle desktop chat views beyond the three most recent go (…
AbirAbbas Nov 6, 2026
355e225
A blank conversation a collection holds is kept, never resumed, and s…
AbirAbbas Nov 6, 2026
27a417a
A message to another computer says why it did not go (#2486)
santoshkumarradha Nov 7, 2026
ba8d049
Claude Code as a provider, a task program and a crew seat (#2505)
santoshkumarradha Nov 8, 2026
fb3ddf1
factory: follow go-aheads itself — group policies and waits-on (#2524)
santoshkumarradha Nov 9, 2026
5d02f0d
sync: keep an unpublished export instead of sealing it again every pa…
santoshkumarradha Nov 9, 2026
32747af
engine: an idle job chat and an unchanged vault cost nothing per look…
santoshkumarradha Nov 9, 2026
f508fec
Factory: any-source intake, router and AI filter, and the factory as …
santoshkumarradha Nov 9, 2026
0dc2bd1
engine: on macOS a held chat's folder costs one watch handle, not one…
AbirAbbas Nov 9, 2026
a687c92
An effort set right after a conversation opens is no longer overwritt…
AbirAbbas Nov 10, 2026
453f3b1
Merge origin/app/v3 into feat/idle-chat-releases-to-relay
AbirAbbas Nov 10, 2026
b32e936
syncsetup: a self-released hold retakes at a new fence, never the rel…
AbirAbbas Nov 10, 2026
d8a1220
manual: an idle chat on paired computers opens directly; a held chat …
AbirAbbas Nov 10, 2026
df96db6
app: a desktop take says when the same computer picked the chat up again
AbirAbbas Nov 10, 2026
89871e2
tui3: Home's latest-chat offer follows presence, not a lapsed hold
AbirAbbas Nov 10, 2026
61cf89e
manual: same-computer take refusals and the presence-led latest-chat …
AbirAbbas Nov 10, 2026
2d2e434
syncsetup: a taken-back writer that idle-releases still counts as ins…
AbirAbbas Nov 10, 2026
2aa6cd7
manual: only Git-ignored files stay behind when a chat moves
AbirAbbas Nov 10, 2026
765b9fa
Revert "tui3: Home's latest-chat offer follows presence, not a lapsed…
AbirAbbas Nov 10, 2026
dbda6fd
Revert "manual: only Git-ignored files stay behind when a chat moves"
AbirAbbas Nov 10, 2026
6059677
Windows: a session can finish — stops that stop, state that survives,…
AbirAbbas Nov 10, 2026
db4583a
Merge origin/app/v3 (#2546) into feat/idle-chat-releases-to-relay
AbirAbbas Nov 10, 2026
5f7319f
tui3: the first Home open after a restart takes a chat no computer holds
AbirAbbas Nov 10, 2026
dee1cd1
tui3: opening a local chat never waits on, or fails on, the sync service
AbirAbbas Nov 10, 2026
e97be1b
tui3: rename the R5 restart test so it cannot spell the old product name
AbirAbbas Nov 10, 2026
4812dd3
tui3: add the R5b local-open tests the previous commit left out
AbirAbbas Nov 10, 2026
4125c03
tui3: with the sync service unreachable, Enter on your own chat opens it
AbirAbbas Nov 10, 2026
9f784d0
session: opening a chat that owes no turn never says "asking again"
AbirAbbas Nov 10, 2026
cb9a4d4
sync: only a released hold opens directly; a lapsed one still asks
AbirAbbas Nov 10, 2026
328b5d9
manual: a released chat opens directly; a lapsed one still asks Conti…
AbirAbbas Nov 10, 2026
b9fa2a2
tui3: the first Enter after the sync service returns sends, as it did…
AbirAbbas Nov 10, 2026
075f546
sync: a chat reopened after a failed close gets a fresh writer
AbirAbbas Nov 10, 2026
e480b0d
sync: read the drive and its closed state under a deferred unlock
AbirAbbas Nov 10, 2026
61ad993
fix(sync): an idle release that never left keeps holding the chat at …
AbirAbbas Nov 10, 2026
8723ae1
fix(chat): Enter on this computer's own live chat confirms the hold i…
AbirAbbas Nov 10, 2026
3662d90
sync: one ownership decision for work, and a lapsed fence never renew…
AbirAbbas Nov 10, 2026
4ecb459
chat: Enter after this computer's own hold lapsed takes the chat back…
AbirAbbas Nov 10, 2026
d2f99f8
sync: a call that finished after its hold expired drains or branches …
AbirAbbas Nov 10, 2026
4515297
chat: the first Enter after an outage checks again even after a faile…
AbirAbbas Nov 10, 2026
89ed168
An idle chat on a paired computer can hand its hold to the relay (opt…
AbirAbbas Nov 14, 2026
bb6bc45
syncsetup: the R9 matrix waits for the holder notice before cleanup
AbirAbbas Nov 14, 2026
d0d9017
gofmt two files from the #2287 port
AbirAbbas Nov 14, 2026
ad21cb5
settings: the idle handoff row no longer answers a search for "pair"
AbirAbbas Nov 14, 2026
76f501e
tui3: with idle handoff off, a storage-off or unchanged chat sends as…
AbirAbbas Nov 14, 2026
49ccbb9
Port onto dev: idle handoff behind an off-by-default setting, P9-X fixes
AbirAbbas Nov 14, 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
18 changes: 18 additions & 0 deletions PERF.md
Original file line number Diff line number Diff line change
Expand Up @@ -831,3 +831,21 @@ method and measurements are in [docs/perf/memory-2026-10-24.md](docs/perf/memory
once a minute. macOS keeps freed pages in a process's resident size until it
needs them (`MADV_FREE_REUSABLE`), so `ps` RSS shows the peak of a burst while
the footprint (`vmmap --summary`, Activity Monitor) shows what is held.

## Paired idle save certification

The idle-only `cellstore.SavedState` keeps the first fingerprint for each path
and stops climbing at an already visited ancestor. A proof admits at most
20,000 paths and 50,000 directory entries in total, 8 MiB per native output/diagnostic stream,
and 64 MiB of current/saved chat-file content reads. Directory reads request
only the remaining entry budget plus one. Native comparison uses its existing
30-second preparation deadline. Exceeding a budget retains the hold; it never
certifies a partial scope or limits ordinary saves or transfers.

`TestIdleRelease_R8_WideWorkspaceAndReceiptsAllocateLinearly` measures native
proofs over 100, 500 and 5,000 workspace files plus as many receipt records.
It caps retained paths and visited entries at `2*N+100`, and Go allocations at
`6 MiB + N*32,000` bytes. Before deduplication, 500+500 allocated 106,534,776
bytes; afterward it allocated 2,505,888 bytes. The 5,000+5,000 proof allocated
21,807,368 bytes. Bounds tests require refusal for paths, entries, reply size
and content bytes. Final metadata revalidation remains mandatory.
53 changes: 49 additions & 4 deletions cmd/codeaf/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1811,7 +1811,32 @@ func appSendUnsure(err error) bool {
}

// OpenAgent attaches a conversation to a saved agent and answers it.
func (b *appBackend) OpenAgent(id string) (appwire.Agent, error) { return b.openAgent(id, false) }
func (b *appBackend) OpenAgent(id string) (appwire.Agent, error) {
// Only a row already read for this paired identity can enable automatic
// pull. Ordinary local opens and single-device homes add no relay request.
if b.idleHandoffEnabled() {
row, found := b.chats.rowFor(id)
if found && row.CanOpen && !row.Here {
return b.takeAgent(appwire.TakeParams{Cell: row.Cell, Seen: row.Seen}, true)
}
}
return b.openAgent(id, false)
}

// rowFor is the last listed row for an agent id or a shared chat's cell id.
func (c *appChats) rowFor(id string) (appwire.ChatRow, bool) {
c.mu.Lock()
defer c.mu.Unlock()
if row, found := c.byAgent[id]; found {
return row, true
}
for _, row := range c.rows {
if row.Cell == id {
return row, true
}
}
return appwire.ChatRow{}, false
}

// WarmAgent is OpenAgent for a window's guess at a view (a hover's prefetch):
// an agent in Closed or the archive is refused, never taken out again
Expand Down Expand Up @@ -2549,7 +2574,7 @@ func (b *appBackend) sendLocked(a *appAgent, text, clientID string, shown *appSe
func (b *appBackend) knownWorkRefusalGated(a *appAgent) error {
a.gate.Lock()
defer a.gate.Unlock()
return b.knownWorkRefusal(a)
return b.idleWorkRefusal(a)
}

// Retry sends the words of the agent's last failed turn again.
Expand Down Expand Up @@ -4225,7 +4250,13 @@ func (b *appBackend) SetModel(id, model string) (appwire.Agent, error) {
if live.conn.Lent {
return appwire.Agent{}, errLentStage("model")
}
live.conn.Conv.SetModel(model)
if checked, ok := live.conn.Conv.(interface{ SetModelChecked(string) error }); ok {
if err := checked.SetModelChecked(model); err != nil {
return appwire.Agent{}, appEngineError(err)
}
} else {
live.conn.Conv.SetModel(model)
}
if now := live.conn.Conv.Model(); now != "" {
model = now
}
Expand Down Expand Up @@ -4270,7 +4301,18 @@ func (b *appBackend) SetEffort(id, word string) (appwire.Agent, error) {
SetConversationEffort(string) bool
ConversationEffort() string
})
if !ok || !dial.SetConversationEffort(rung.String()) {
took := false
if ok {
if checked, yes := dial.(interface{ SetConversationEffortChecked(string) (bool, error) }); yes {
took, err = checked.SetConversationEffortChecked(rung.String())
if err != nil {
return appwire.Agent{}, appEngineError(err)
}
} else {
took = dial.SetConversationEffort(rung.String())
}
}
if !ok || !took {
return appwire.Agent{}, appwire.Errorf(appwire.CodeEngine, "this conversation has no thinking dial; update the engine and reconnect")
}
chosen := dial.ConversationEffort()
Expand Down Expand Up @@ -5040,6 +5082,9 @@ func appEngineError(err error) error {
}
var refusal *executor.WorkRefusal
if errors.As(err, &refusal) {
if refusal.Retryable {
return &appwire.Error{Code: appwire.CodeUnreachable, Message: refusal.Line}
}
location := &appwire.Location{Here: false, Line: refusal.Line}
if refusal.HolderID != "" {
location.Holder = &appwire.LocationHolder{ID: refusal.HolderID, Name: refusal.HolderName}
Expand Down
14 changes: 14 additions & 0 deletions cmd/codeaf/app_chats.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
"github.com/Agent-Field/codeaf/internal/appwire"
"github.com/Agent-Field/codeaf/internal/cell"
"github.com/Agent-Field/codeaf/internal/chatlist"
"github.com/Agent-Field/codeaf/internal/config"
"github.com/Agent-Field/codeaf/internal/dirwatch"
"github.com/Agent-Field/codeaf/internal/env"
"github.com/Agent-Field/codeaf/internal/guard"
"github.com/Agent-Field/codeaf/internal/handoff"
"github.com/Agent-Field/codeaf/internal/pair"
Expand Down Expand Up @@ -406,6 +408,7 @@ func (b *appBackend) readChats(parent context.Context, s *syncsetup.Sync, feed d
_, installed := local[r.Cell]
here := r.Mine && (r.Status == chatlist.Here || installed)
row := appwire.ChatRow{Cell: r.Cell, Title: r.Title, Here: here, Status: string(r.Status), Seen: appwire.Seen{Device: r.DeviceID, Fence: r.Fence, Head: r.Head}, CanTake: !here && r.Head != ""}
row.CanOpen = s.IdleHandoffAllowed() && r.AutoOpen && r.Head != ""
if service, ok := s.Dir.(interface{ HeadTakes() bool }); ok && !service.HeadTakes() {
row.Seen.Head = ""
}
Expand Down Expand Up @@ -760,6 +763,17 @@ func (b *appBackend) cachedChatLocation(id string) *appwire.Location {
return chatLocation(row)
}

func (b *appBackend) idleHandoffEnabled() bool {
profile := strings.TrimSpace(b.profileDir)
if profile == "" {
profile = strings.TrimSpace(env.Get(config.ProfileDirEnv))
}
if profile == "" {
profile = b.relayHome()
}
return config.IdleHandoffAt(profile) && syncsetup.StorageForHome(b.relayHome()) != "off"
}

func (b *appBackend) dressChatLocation(view *appwire.Agent) {
fresh := b.cachedChatLocation(view.ID)
if fresh == nil {
Expand Down
7 changes: 7 additions & 0 deletions cmd/codeaf/app_lend.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ func endsAView(door session.StopDoor) bool {
// model change has no error to return.
func (l lentAgent) SetModel(string) {}

// SetModelChecked preserves the legacy wrapper's model policy at the checked
// RPC door; the embedded agent's promoted setter must not bypass it.
func (l lentAgent) SetModelChecked(model string) error {
l.SetModel(model)
return nil
}

// SetSpendRail refuses: the stage's rail is the factory's.
func (l lentAgent) SetSpendRail(float64) error { return errLentStage("spend limit") }

Expand Down
64 changes: 56 additions & 8 deletions cmd/codeaf/app_take.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,19 @@ var (
appTakeSeen = func(ctx context.Context, s *syncsetup.Sync, id string, seen *directory.LeaseExpectation, onMove func(syncsetup.MoveProgress)) (syncsetup.Continued, error) {
return chatMover(s, onMove).TakeSeen(ctx, id, seen)
}
appTakeOpen = (*appBackend).OpenAgent
appTakeOpen = func(b *appBackend, id string) (appwire.Agent, error) {
return b.openAgent(id, false)
}
)

// TakeAgent moves a chat here. Its row says the move is queued, then how far
// it has got, and, when it did not move the chat, how it ended, so a client
// that stopped waiting still learns the outcome.
func (b *appBackend) TakeAgent(p appwire.TakeParams) (agent appwire.Agent, err error) {
func (b *appBackend) TakeAgent(p appwire.TakeParams) (appwire.Agent, error) {
return b.takeAgent(p, false)
}

func (b *appBackend) takeAgent(p appwire.TakeParams, available bool) (agent appwire.Agent, err error) {
if p.Cell == "" || p.Seen.Device == "" {
return appwire.Agent{}, appwire.Errorf(appwire.CodeBadParams, "a chat and its seen computer are required")
}
Expand Down Expand Up @@ -131,8 +137,11 @@ func (b *appBackend) TakeAgent(p appwire.TakeParams) (agent appwire.Agent, err e
return appwire.Agent{}, err
}
seen := &directory.LeaseExpectation{Device: p.Seen.Device, Fence: p.Seen.Fence, Head: p.Seen.Head}
if available && view.Cell.Lease.Expires != 0 {
return appwire.Agent{}, appAvailableRefusal(ctx, s, view.Cell.Lease)
}
if !seen.Matches(view.Cell) {
return appwire.Agent{}, appTakeError(directory.ErrLeaseHeld)
return appwire.Agent{}, appTakeRefusal(ctx, s, p.Cell, seen, directory.ErrLeaseHeld)
}
if view.Cell.Archived || view.Cell.ParentCell != "" {
return appwire.Agent{}, appwire.Errorf(appwire.CodeNotFound, "that chat is not available")
Expand All @@ -159,7 +168,7 @@ func (b *appBackend) TakeAgent(p appwire.TakeParams) (agent appwire.Agent, err e
if busy {
return appwire.Errorf(appwire.CodeBusy, "Finish this chat's work before continuing it here.")
}
if moved {
if available || moved {
b.release(existing)
}
return nil
Expand All @@ -169,17 +178,27 @@ func (b *appBackend) TakeAgent(p appwire.TakeParams) (agent appwire.Agent, err e
}
}
report, stopReport := b.moveReporter(p.Cell, move)
got, err := appTakeSeen(ctx, s, p.Cell, seen, report)
var got syncsetup.Continued
if available {
got, err = chatMover(s, report).OpenAvailable(ctx, p.Cell, seen)
} else {
got, err = appTakeSeen(ctx, s, p.Cell, seen, report)
}
stopReport()
if err != nil {
return appwire.Agent{}, err
if available && (errors.Is(err, directory.ErrLeaseHeld) || errors.Is(err, directory.ErrFenceStale)) {
if fresh, readErr := s.Dir.Cell(ctx, p.Cell); readErr == nil && fresh.Cell.Lease.Expires > fresh.Now {
return appwire.Agent{}, appAvailableRefusal(ctx, s, fresh.Cell.Lease)
}
}
return appwire.Agent{}, appTakeRefusal(ctx, s, p.Cell, seen, err)
}
// The chat is this computer's from here on, even if opening it fails.
b.chats.landTake(p.Cell, got.Taken.Driving.Fence)
// The continuer's already-here shortcut may observe a local acquisition
// that happened after our preflight read. It must not accept older consent.
if got.AlreadyHere && (p.Seen.Device != s.Device.ID() || !seen.Matches(directory.Cell{Head: got.Taken.Driving.Head, Lease: directory.Lease{Device: s.Device.ID(), Fence: got.Taken.Driving.Fence}})) {
return appwire.Agent{}, appTakeError(directory.ErrLeaseHeld)
return appwire.Agent{}, appTakeRefusal(ctx, s, p.Cell, seen, directory.ErrLeaseHeld)
}
root := got.Taken.Cell.Root
meta, err := session.LoadMeta(root)
Expand All @@ -193,7 +212,7 @@ func (b *appBackend) TakeAgent(p appwire.TakeParams) (agent appwire.Agent, err e
}
b.remember(session.SessionRow{ID: id, Dir: root, Transcript: transcript, Workspace: meta.Workspace, Title: meta.Title, Created: meta.Created, Model: meta.Model, ModelIdentity: meta.ModelIdentity})
a := b.agent(id)
b.installTaken(a, transcript, meta, !got.AlreadyHere, moved)
b.installTaken(a, transcript, meta, !got.AlreadyHere, available || moved)
location := &appwire.Location{Here: true, Cell: p.Cell, Seen: &appwire.Seen{Device: s.Device.ID(), Fence: got.Taken.Driving.Fence, Head: got.Taken.Driving.Head}, Holder: &appwire.LocationHolder{ID: s.Device.ID(), Name: got.Device}}
if service, ok := s.Dir.(interface{ HeadTakes() bool }); ok && !service.HeadTakes() {
location.Seen.Head = ""
Expand Down Expand Up @@ -231,6 +250,35 @@ func (b *appBackend) TakeAgent(p appwire.TakeParams) (agent appwire.Agent, err e
return agent, nil
}

// appTakeRefusal reads ownership again because the observed computer may have
// reclaimed its own idle release while this take was on the way.
func appTakeRefusal(ctx context.Context, s *syncsetup.Sync, id string, seen *directory.LeaseExpectation, err error) error {
if !errors.Is(err, directory.ErrLeaseHeld) && !errors.Is(err, directory.ErrFenceStale) {
return err
}
wire := appTakeError(err).(*appwire.Error)
if seen != nil && seen.Fence > 0 {
if fresh, readErr := s.Dir.Cell(ctx, id); readErr == nil && fresh.Cell.Lease.Device == seen.Device && fresh.Cell.Lease.Fence > seen.Fence {
wire.Message = fmt.Sprintf(chatlist.PickedUpAgain, appHolderName(ctx, s, fresh.Cell.Lease.Device))
}
}
return wire
}

func appHolderName(ctx context.Context, s *syncsetup.Sync, device string) string {
name := chatlist.DeviceName(nil, device, nil)
if listing, err := s.Dir.List(ctx); err == nil {
key := directory.MetadataKey(s.Identity.CellKey())
name = chatlist.DeviceName(listing.Devices, device, func(sealed string) (string, error) { return directory.OpenName(key, sealed) })
}
return name
}

func appAvailableRefusal(ctx context.Context, s *syncsetup.Sync, lease directory.Lease) error {
name := appHolderName(ctx, s, lease.Device)
return appLocationRefusal(&appwire.Location{Holder: &appwire.LocationHolder{ID: lease.Device, Name: name}, Line: chatlist.Superseded(name)})
}

// installTaken points the agent at the chat a take installed. installed: the
// take replaced the saved conversation; moved: another computer held it.
// Under the agent's gate, as releaseForTake: a send waits for the reset
Expand Down
Loading