Skip to main content
A turn needs a caller whose authority it carries. A cron, a scheduled function or a webhook has none, so the agent declares the service such a turn acts as, once:
bijection/agents.ts
bijection/crons.ts
The application explicitly exports an internal mutation for the cron:
bijection/support.ts
The library schedules its internal worker under the declared service and returns the scheduled function ID. Current service grants authorize tools; a proposal requiring personal review stays pending. The internal worker refuses a different service identity. Personal sends use sendMessage; service scheduling requires the agent’s declared service and a live deployment credential. The service is the one the access model declares, with its ceiling, and a person grants it roles as for any service. The deployment acts as it only while an administrator’s deployment credential for it is live:
Revoking that credential refuses scheduled turns at their next boundary. A person’s call never becomes the service’s: scheduling as a service is refused from a person’s or another service’s call. The service is declared on the agent, not on each schedule, because it is the agent’s standing identity: every cron, timer and webhook that starts the agent gets the same authority, and no internal caller can pick a more powerful one.

How it works

The internal admission gate calls services.runAfter(0, "support", internal.agents.supportRun, args) from bijection/runtime. The application may schedule one of its own actions as a service from a mutation, only when the caller is no person, delegate, issued session or other service. The scheduled function records the service; when it runs, the scheduler acts as the service itself, authenticated by its deployment credential, and every boundary rechecks that credential as it rechecks any service’s. A _threads document the turn opens has the service’s token identifier as its owner.