Nuggets workflow report
Type: agentic-system-analyses/types/agentic-system-workflow-report.md
Workflow account
Selected workflow and evidence
This account selects a user-requested one-shot reminder. It follows one shipped chain from an incoming message, through a model-selected schedule call and persisted job, to a later Pi turn and outbound message. This route is representative because it combines ordinary conversation with a consequential deferred handoff: the immediate confirmation and the later reminder have different acceptance and completion points. It is not an observed user episode. All source findings are implementation or doctrine/design evidence from SRC-1 at the frozen revision; no execution or successful reminder delivery was supplied.
The account uses RT-RTE-message-turn, RT-RTE-schedule-admission, RT-RTE-proactive-turn, RT-OBJ-cron-jobs and RT-BAP-scheduled-prompt. Its additional direct inspection covers .pi/extensions/proactive.ts, src/gateway/main.ts, src/gateway/cron.ts, src/gateway/router.ts and src/gateway/event-queue.ts. These files are already within SRC-1's registered scope. The external Pi model/tool loop remains outside the inspected implementation; the gateway is not a team of independently specified specialist agents.
For a straightforward recipient path, the selected configuration is Telegram with one allowlisted chat, a configured bot token, and no connected WhatsApp channel. The shipped driver then assigns that chat as cron's default and registers its sender. This is a conditional path, not a claim about deployed configuration. SRC-1: src/gateway/main.ts.
if (!waConnected && TELEGRAM_ALLOWLIST.size === 1) { const defaultId = [...TELEGRAM_ALLOWLIST][0]; cron.setDefaultJid(defaultId); heartbeat.register(defaultId); log.info({ chatId: defaultId }, "Default ID set from Telegram allowlist"); } ---
src/gateway/main.ts
1. Request reaches the delegated model context
An admitted Telegram message enters the router's per-chat promise chain. The queued task obtains or reuses that chat's Pi subprocess, marks it busy and supplies the message to promptAndWait. The pool supplies a continued per-chat session directory and configured provider/model controls. Pi, not the router, decides the model/tool steps. The supplied message-turn record retains the source passages and the external RPC limits for this handoff: RT-RTE-message-turn.
The handoff supplies the user's natural-language request, continued host context and appended instructions, not a structured, already validated reminder plan. If the memory extension is loaded, its selected local facts can also enter the system prompt; this conditional context supply does not establish that the model recalls anything or uses it correctly. See RT-RTE-memory-context and RT-BAP-facts-prompt.
2. Model proposes a schedule; the tool checks only its local boundary
The proactive extension instructs the model to use schedule for reminders, calculate a future cron expression for relative timing, use one-shot mode for one-time reminders, and confirm the schedule to the user. The model supplies cron, message content and one_shot; code does not independently interpret the user's intended deadline. There is no inspected answer oracle comparing the cron or message with the user's intent. This is open-request operation, not a bounded evaluation. SRC-1: .pi/extensions/proactive.ts; RT-RTE-schedule-admission.
"Use one_shot=true for one-time reminders, false for recurring", "Always confirm with the user what was scheduled", ---
.pi/extensions/proactive.ts
The create branch rejects missing cron/message and returns a tool error if its shell append fails. Otherwise it serializes an add request with the model's cron, prompt, one-shot flag and a timestamp into .gateway/cron/requests.jsonl. It supplies no originating chat identifier. The extension then returns a creation message to Pi after append success, before the gateway accepts the request. The immediate user-facing answer is subsequently generated by Pi and forwarded through the ordinary message route; compliance with the confirmation instruction is not established. SRC-1: .pi/extensions/proactive.ts; RT-RTE-schedule-admission.
text:
Schedule created: "${params.message}" with cron "${params.cron}"${params.one_shot ? " (one-shot)" : " (recurring)"}, ---.pi/extensions/proactive.ts
The user initiates the task, but there is no intervening per-job human approval of the model's fields. The extension's presence checks and shell result are not verification of the time, recipient or eventual delivery.
3. Gateway admits and persists a later request
The scheduler polls the request file every five seconds after initializing its offset to the file's existing size. New JSON lines are parsed; an add request must contain cron, prompt and either its own JID or the configured default. The gateway generates a short UUID-based job ID, enables the job and saves it in jobs.json. It does not return that admission decision or generated ID through an acknowledgement channel to the originating schedule tool. Existing accepted jobs reload at construction; existing request bytes are skipped at scheduler startup. SRC-1: src/gateway/cron.ts; RT-OBJ-cron-jobs, RT-RTE-schedule-admission.
For the selected single-chat configuration, the default supplies the missing recipient. This is configuration-based routing, not evidence that the reminder carries its initiating user's identity end to end. The retained object separates symbolic routing/time fields from the natural-language prompt that Pi will later interpret; the runtime declares those parts in RT-OBJ-cron-jobs and RT-BAP-scheduled-prompt.
4. Timer delegates the retained prompt to a later Pi turn
The scheduler evaluates enabled jobs at most once per local clock minute. Its matcher requires five cron fields and matches all five against local date/time values. A match pushes a timer event for a one-shot job, supplying JID, retained prompt and job-ID metadata. EventQueue is a synchronous emitter; its router listener enqueues asynchronous work on the same per-JID chain used for incoming messages. The event is not a durable delivery task. SRC-1: src/gateway/cron.ts, src/gateway/event-queue.ts, src/gateway/router.ts; RT-RTE-proactive-turn.
push(event: ProactiveEvent): void { log.info({ type: event.type, jid: event.jid }, "Proactive event queued"); this.emit("event", event); } ---
src/gateway/event-queue.ts
The scheduler removes and saves one-shot jobs after event emission, without waiting for Pi or channel delivery. The router gets or reuses the recipient's Pi process and sends the stored prompt, not the full job record or a verified reminder result. Pi owns the ensuing model/tool work; this is another invocation in the continued recipient session, not a dedicated isolated reminder-agent frame. See RT-RTE-proactive-turn and RT-BAP-scheduled-prompt, which supplies the prompt-forwarding passage.
if (toRemove.length > 0) { this.jobs = this.jobs.filter((j) => !toRemove.includes(j.id)); this.save(); } ---
src/gateway/cron.ts
5. Delivery means channel submission, not verified task completion
The RPC wrapper completes on Pi's agent_end and extracts assistant text, as described in RT-RTE-message-turn. The proactive handler trims the returned text, drops an empty response, splits nonempty text into chunks and awaits sequential sender calls. A one-shot reminder is a timer event, so the heartbeat-only NOTHING suppression does not apply. The router does not compare the response with the saved prompt, the requested time or a reference answer. SRC-1: src/gateway/router.ts; RT-RTE-proactive-turn.
for (const chunk of chunks) { await send(event.jid, chunk); } ---
src/gateway/router.ts
For the selected configuration, the driver has a sender registered for that chat. Successful completion of these calls is the local forwarding endpoint, not proof of recipient receipt, reading or correct reminder fulfilment. Even the general driver's resolution is weaker than a delivery receipt: without a registered sender it can log and resolve without sending. SRC-1: src/gateway/main.ts.
log.error({ id }, "No sender registered for this ID"); return Promise.resolve(); ---
src/gateway/main.ts
Rejection and recovery checks
Admission rejection after confirmation. If no default recipient is set, the same extension request can append successfully and receive “Schedule created” while the gateway subsequently rejects it. The inspected rejection is a log and return, not a callback to Pi or the user. Consequently neither the tool message nor the model's confirmation establishes admission. SRC-1: .pi/extensions/proactive.ts, src/gateway/cron.ts; RT-RTE-schedule-admission.
if (!jid) { log.error({ request }, "Schedule request missing jid and no default set"); return; } ---
src/gateway/cron.ts
Accepted but ineffective schedule. Admission checks field presence, whereas a cron expression with other than five fields merely fails later matching. An accepted job can therefore persist without firing. The scheduler's match result is a time-selection predicate, not validation that the model encoded the requested deadline. SRC-1: src/gateway/cron.ts.
const fields = expr.trim().split(/\s+/); if (fields.length !== 5) return false; ---
src/gateway/cron.ts
Failure after firing. An empty Pi result produces no outbound reminder. A thrown proactive-processing error is logged and the pool is marked idle; this handler does not kill the process as the ordinary-message handler does. There is no inspected retry or one-shot restoration in these handlers. Partial chunk delivery can precede a later sender failure. The scheduler has already removed the one-shot job, so recovery requires a new externally initiated request or other intervention, not a built-in delivery retry. SRC-1: src/gateway/router.ts, src/gateway/cron.ts; RT-RTE-proactive-turn.
} catch (err) { log.error({ jid: event.jid, type: event.type, err }, "Error handling proactive event"); } finally { pool.markIdle(event.jid); } ---
src/gateway/router.ts
Deletion by job ID is the shipped reversal for a retained job; listing reads the saved jobs and exposes IDs. Neither gives transactional rollback of a reminder already emitted. No autonomous repair agent is established by the inspected extension/scheduler/router chain. This bounded account establishes a wired multi-step workflow and its local acceptance gaps, not successful execution, reliable delivery or model correctness. SRC-1: .pi/extensions/proactive.ts, src/gateway/cron.ts, src/gateway/router.ts.
Shared records
Components
none declared in this member
Operative objects
none declared in this member
Routes
none declared in this member
Claims
none declared in this member
Evidenced absences
none declared in this member
Behavioral-authority paths
none declared in this member
Annotations
On RT-RTE-message-turn
Workflow role: receives the reminder request and later returns the immediate model answer. The router delegates next-step selection to Pi rather than executing a predeclared reminder plan. Its completion does not await schedule admission or deferred delivery.
On RT-RTE-schedule-admission
Workflow acceptance boundary: extension append success and gateway job admission are distinct. The selected path needs a configured default recipient because this tool does not convey its originating chat. Missing fields and shell failures can reach Pi as tool errors; missing gateway default is instead logged downstream. Human initiation is not per-content approval. Job deletion reverses retention only before downstream effects; there is no admission receipt closing the confirmation loop.
On RT-RTE-proactive-turn
Workflow delivery boundary: one-shot removal follows event emission, not asynchronous Pi or sender completion. The queued invocation receives the retained prompt through the same recipient session path as ordinary messages. Empty output or a logged processing failure leaves no built-in one-shot retry. A nonempty response is forwarded without a semantic acceptance test; sender-call completion does not establish recipient receipt or reminder correctness.