Repository navigation
Record who schedules wakeups and starts cron runs, and run them for that person - #520
Draft
alex-clickhouse wants to merge 9 commits into
Draft
alex-clickhouse wants to merge 9 commits into
alex-clickhouse wants to merge 9 commits into
Conversation
This was referenced Oct 17, 2026
alex-clickhouse
added this pull request to stack #521
October 17, 2026 07:20
A scheduled turn must run for the principal that caused it, so that its
model requests and tool changes name that person. Until now a run-later
message, an agent wakeup and a "Run now" cron run all ran for the system
actor.
Migration v057 adds session_wakeups.created_by_actor_id and
.caused_by_actor_id, and cron_logs.actor_id and .caused_by_actor_id
(nullable foreign keys to actor_refs, no backfill). The registry lists
the four columns.
- Run later through REST records the person as scheduler and cause.
- An agent wakeup (the ScheduleWakeup hook of the Claude CLI, or the
schedule_wakeup tool) records the system actor and the session's
cause.
- A fired wakeup runs in its session, so its turn has the session's
cause.
- Scheduled, catch-up and missed cron runs log the system actor as
actor and cause. POST /api/cron/jobs/{id}/trigger logs the person,
and a session that the run creates (an isolated run, or a new
persistent generation) has that person as its cause.
- Session list rows and the session_running event carry
pending_wakeup_created_by_actor_id and
pending_wakeup_caused_by_actor_id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parked dot of a session that waits on a wake-up names who scheduled it: "by Alice" for a deferred message, "by Nerve for Bob" for a wakeup that the agent set in Bob's turn, "by Nerve" for autonomous work. The names come from the actor directory. A wake-up without a recorded scheduler shows only its time. The attribution hooks move from ActorLabel.tsx to hooks/useActorAttribution.ts, so that a component that needs the text for a tooltip can use the same "<actor> for <person>" rule as ActorAttribution. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/accounts.md lists the four new attribution columns and the actor and cause of "Run now", "Run later", agent wakeups and the turns they fire. docs/api.md describes the actor fields of cron logs, the trigger route and the pending wakeup fields of session rows. docs/cron.md lists the two cron_logs columns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The writing rules forbid em-dashes in docs and comments. Replace the four in the text that this branch adds with a colon, parentheses or a comma. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The inference principal header is in the base of this branch, so the tests of the header on fired wakeups and on a run-now session run unconditionally. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A cron job that declares a workflow run started the run for the system actor also when a person triggered the job through the REST API, so the run's turns and model requests named the system principal. The cron service now passes the cause of the cron run to the run: the system actor starts it, for the person who used "Run now", or for itself on a scheduled run. docs/accounts.md, docs/api.md and docs/workflow-runs.md say so, and the actor directory intro in docs/api.md names wakeups and cron run logs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under the session cause model a session has one cause, and every agent turn in it runs for that cause. A fired wakeup runs in its session, so the cron service no longer passes the wakeup's stored cause to the turn; the wakeup row keeps who scheduled it and for whom. A deferred message that Bob leaves in Alice's session therefore fires for Alice, the documented approximation. The comments of the wakeup store, the migration, the ScheduleWakeup hook and the schedule_wakeup tool say that an agent wakeup records the session's cause. Tests: the wakeup sweep passes no cause to the turn. The cron rotation test seeds a person as the session cause and expects the retitle to be the system actor's for that person. A persistent session that a person's "Run now" creates keeps that person as cause for a later scheduled run, its rotation retitle names the person, and the next session is the system actor's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Isolated cron runs and persistent generations got session IDs with the start time to the second. Two people who used "Run now" on one job in the same second shared one session, so both runs had the cause (and the inference principal) of whoever created it first. An immediate rotation could also reuse the retired generation. A run ID is now the UTC start second and eight random hex digits (new_cron_run_id in nerve/agent/sessions.py), used for isolated runs, persistent generations and run_cron's default. The cron:<job>: prefix stays. The usage report matches the new shape and the older one. Tests: two concurrent "Run now" requests of Alice and Bob in one second get two sessions with their own causes and principal headers; a manual rotation and a rotated generation in the same second get new sessions; the usage report groups both run ID shapes. docs/cron.md and docs/architecture.md describe the run ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/accounts.md lists three approximations of the session cause model (shared sessions, deferred messages and wakeups, a persistent cron session that a person started); the lead sentence said two. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alex-clickhouse
force-pushed
the
alex/attr-06-schedules
branch
from
October 17, 2026 11:43
4cc96c0 to
36520eb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Nerve records who scheduled a wakeup or a deferred message and who started a cron run, and a cron run that a person starts runs for that person. Scheduled work follows the session cause model (#515): the agent's work in a session, including a wakeup's turn, is for the session's cause.
How
session_wakeups.created_by_actor_id,session_wakeups.caused_by_actor_id,cron_logs.actor_idandcron_logs.caused_by_actor_id. They are nullable foreign keys toactor_refs, with no backfill. The attribution column registry lists them.ScheduleWakeup, or theschedule_wakeuptool) records the system actor and the session's cause.POST /api/cron/jobs/{id}/trigger) logs the person. A session that the run creates (an isolated run, or a new persistent generation) has that person as cause.GET /api/cron/logsrows carryactor_idandcaused_by_actor_id.session_runningevent carrypending_wakeup_created_by_actor_idandpending_wakeup_caused_by_actor_id.Why
The principal on a model request decides who pays for it, and that principal is the session's cause. A manual cron run must create its session for the person who started it; otherwise it counts as the agent's own work.
Approximations
Behaviour changes
cron:nightly:20260102-030405-ac21b72a), so two runs started in the same second get separate sessions. The usage report reads both the old and the new shape.Testing
Stack
main)🤖 Generated with Claude Code