Conversation
Agents could only act while a user was driving a turn. Add scheduled work, ambient work and host background jobs that activate threads under unattended grants, with guarded idle starts and cancellation, an automation MCP toolkit and startup recovery (migrations 060, 061).
| yield* authority.authorize(job.ownerThreadId); | ||
| const captured = yield* wrap( | ||
| spawner.spawn( | ||
| ChildProcess.make(input.command, input.args, { | ||
| cwd: job.cwd, |
There was a problem hiding this comment.
Jobs use an old worktree If a job is still pending when its owner changes worktrees, this code checks the owner’s current workspace but discards that result. It starts the command in the worktree saved at submission, so the command can read or modify the wrong checkout.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/background/BackgroundJobs.ts
Line: 231-235
Comment:
**Jobs use an old worktree** If a job is still pending when its owner changes worktrees, this code checks the owner’s current workspace but discards that result. It starts the command in the worktree saved at submission, so the command can read or modify the wrong checkout.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| else | ||
| return yield* lock.withPermit( | ||
| update(job, { state: "cancelled", reason: "Cancelled before process activation." }), | ||
| ); |
There was a problem hiding this comment.
Pre-start cancellation skips notifications If a subscribed job is cancelled before its process starts, this branch marks it cancelled without delivering its terminal notification. The runner then exits because the job is terminal, so the notification or wake is delayed until a later startup reconciliation, if one occurs.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/background/BackgroundJobs.ts
Line: 459-462
Comment:
**Pre-start cancellation skips notifications** If a subscribed job is cancelled before its process starts, this branch marks it cancelled without delivering its terminal notification. The runner then exits because the job is terminal, so the notification or wake is delayed until a later startup reconciliation, if one occurs.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| const piece = bytes.subarray(start, start + remaining); | ||
| if (piece.length === 0) break; | ||
| chunks.push({ | ||
| cursor: row.cursor + start, | ||
| stream: row.stream, | ||
| text: new TextDecoder().decode(piece), | ||
| }); | ||
| nextCursor = row.cursor + start + piece.length; |
There was a problem hiding this comment.
Byte pages corrupt Unicode output When a page ends inside a UTF-8 character, this code decodes the incomplete bytes on their own and advances the cursor past them. For example, reading
é one byte at a time returns replacement characters on both pages, so a client following nextCursor cannot reconstruct the stored output.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/background/BackgroundJobs.ts
Line: 433-440
Comment:
**Byte pages corrupt Unicode output** When a page ends inside a UTF-8 character, this code decodes the incomplete bytes on their own and advances the cursor past them. For example, reading `é` one byte at a time returns replacement characters on both pages, so a client following `nextCursor` cannot reconstruct the stored output.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| yield* save(next); | ||
| if (!config.enabled && next.activeScheduleId) | ||
| yield* scheduled.cancel({ | ||
| callerThreadId: config.callerThreadId, | ||
| id: next.activeScheduleId, | ||
| }); |
There was a problem hiding this comment.
Grant changes strand ambient cycles If an enabled ambient owner changes grants while a cycle is queued, this code leaves that schedule under the old grant. Validation blocks it because the grant no longer matches, but ambient work continues to treat the blocked schedule as active and never starts another cycle.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/orchestration/AmbientWork.ts
Line: 127-132
Comment:
**Grant changes strand ambient cycles** If an enabled ambient owner changes grants while a cycle is queued, this code leaves that schedule under the old grant. Validation blocks it because the grant no longer matches, but ambient work continues to treat the blocked schedule as active and never starts another cycle.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| const rows = yield* wrap( | ||
| sql<{ | ||
| due_at: string; | ||
| }>`SELECT due_at FROM scheduled_work WHERE state = 'queued' ORDER BY due_at LIMIT 1`, | ||
| ); | ||
| const delay = rows[0] | ||
| ? Math.max(0, Date.parse(rows[0].due_at) - (yield* Clock.currentTimeMillis)) | ||
| : null; | ||
| if (delay === null) yield* Queue.take(wake); |
There was a problem hiding this comment.
Blocked schedules miss deadlines The timer only considers queued schedules. If a busy-wait schedule becomes blocked and no other event wakes the loop, its
latestStartAt can pass without another check. It remains blocked instead of being marked failed, leaving its reported state stale until unrelated activity occurs.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/server/src/orchestration/ScheduledWork.ts
Line: 374-382
Comment:
**Blocked schedules miss deadlines** The timer only considers queued schedules. If a busy-wait schedule becomes blocked and no other event wakes the loop, its `latestStartAt` can pass without another check. It remains blocked instead of being marked failed, leaving its reported state stale until unrelated activity occurs.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| Scheduling, ambient work, and background commands require a separate, | ||
| administrator-issued grant for the owning thread. Tool access alone is not that | ||
| grant. Revoking a grant prevents further work under it; it cannot be replaced by | ||
| an agent choosing a more permissive grant. |
There was a problem hiding this comment.
New features lack usage guidance This change adds a consent warning for scheduling, ambient work, and background commands, but does not explain how users start or use those major features. The repository’s user-documentation directive requires a concise, task-oriented section explaining what each major feature does, how to start it, and anything unintuitive. That requirement needs to be satisfied before merging.
Context Used: CLAUDE.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/user/project-settings.md
Line: 81-84
Comment:
**New features lack usage guidance** This change adds a consent warning for scheduling, ambient work, and background commands, but does not explain how users start or use those major features. The repository’s user-documentation directive requires a concise, task-oriented section explaining what each major feature does, how to start it, and anything unintuitive. That requirement needs to be satisfied before merging.
**Context Used:** CLAUDE.md ([source](https://github.com/siavz/t3code/blob/main/CLAUDE.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
Superseded. This stack was built on orchestration V1, which upstream deleted in pingdotgg#2829, so it can't be rebased. Upstream now covers this natively after the orchestration V2 rewrite (pingdotgg#2829): delegate_task and subagents, coordination through delegated tasks, and schedule_task with agent wakes and PR watching. Closed by Claude Opus 5.5 in Jcode. |
Agents could only act while a user was driving a turn.
Add scheduled work, ambient work and host background jobs that activate
threads under unattended grants, with guarded idle starts and cancellation,
an automation MCP toolkit and startup recovery (migrations 060, 061).
Stack
Part 6 of 14. Based on
parity/05-quality-records, so this diff shows only this layer. Merge in order.Scope
41 files changed, 3701 insertions(+), 54 deletions(-). Adds migration 060_ScheduledWork 061_BackgroundJobs. Migrations are numbered to follow the stack order.
Verification
vp run typecheckpasses for contracts, client-runtime, server, web, mobile and desktop at this commit, with the Effect-patched compiler.vp lint(0 errors) andvp fmt --checkpass on the changed files.ProviderRegistry > re-probes when settings change the codex binaryPath, also fails on untouchedmainon this machine (it finds/opt/homebrew/bin/brew).Implemented with GPT 6.1 and Opus 5.5 agents coordinated by Jcode.
The PR is not safe to merge until background-job execution and notification delivery, output pagination, and ambient grant changes are corrected.
Findings
Fix with agent prompt
Summary
The PR adds durable scheduled and ambient agent activation, bounded host background jobs, an automation MCP toolkit, RPC contracts, and startup recovery.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR Client[Client or MCP tool] --> Grant[Grant and capability checks] Grant --> Schedule[Scheduled work] Grant --> Job[Background job] Schedule --> Activation[Guarded thread activation] Job --> Process[Captured host process] Process --> Output[Persisted bounded output] Process --> Notification[Terminal notification] Notification --> Schedule Ambient[Ambient idle admission] --> ScheduleReviews (1) · Last reviewed commit: "feat(server): add scheduled, ambient and..."