Memory interface

Scheduler owns timing, execution, status, and results; Memory owns long-term semantic facts. Stable references and existing Memory tools connect them, but they share neither state files nor write transactions. Agents can explicitly maintain associated Memory records while planning, executing, and closing tasks.

1. Goals and boundaries

One-time tasks

Store a timezone-aware run_at and execute once when due. Migrate dated legacy Commitments to this type.

Recurring tasks

Reuse existing five-field cron parsing, owner signatures, frozen sandbox policies, and non-interactive execution boundaries.

Monitoring tasks

Periodically execute observation prompts with cron. The first version records execution logs and state without promising cross-channel exactly-once notifications.

Explicit exclusions

The Memory writer does not infer tasks; Memory pages do not show Commitments; Scheduler service does not implicitly create or modify Memory. No cross-store Scheduler/Memory transactions, external-token permission model, placeholders or ID forwarding for deleted records, second executor, project management, task dependencies, or subtasks are introduced.

2. Target data relationships

1 CreateOwner Web UI, an Agent tool, or an external API creates a Scheduler task.
2 FreezeThe runtime signs prompt/command, cwd, permissions, sandbox, and MemoryRef.
3 WakeThe persistent OpenProgram worker checks once/cron schedules every minute.
4 ResolveBefore execution, read current Memory content using workspace_id + memory_id.
5 ExecuteExecute within frozen non-interactive permission boundaries and write Scheduler logs and state.

Worker tick exception boundary

If the initial @reboot tick or subsequent ordinary ticks raise Exception, the daemon writes a warning and full traceback to stderr and continues at the next minute boundary. It neither immediately replays nor compensates. After initial failure, subsequent ticks use reboot=False. Redirected stderr from the persistent OpenProgram worker goes to the global worker log; standalone foreground scheduler-worker displays it in the current terminal. Neither is an individual task execution log.run_once, KeyboardInterrupt, SystemExit and other BaseException remain fail-fast.

3. Public MemoryRef contract

FieldRuleFailure
workspace_idMust equal the stable ID of the current Memory workspace.Reject implicit cross-workspace reads.
memory_idMust resolve to a unique Topic block at creation and update; reread content on every execution.Reject missing, duplicate, cross-workspace, or malformed references on write. An invalid reference before execution fails the task without falling back to an old snapshot.
Write capabilityMemoryRef itself grants no editing authority. Prompt tasks created by the local owner may use memory_status, memory_get and memory_update; all changes still use existing revision checks, format validation, derived views, and Git transactions.Missing current revisions, malformed Topics, or concurrent updates fail the Memory transaction independently; Scheduler state is not rolled back.

4. Agent lifecycle protocol

PhaseAgent behaviorBoundary
Planning or creationOnly if the task itself merits long-term retention does the agent use memory_update.create_record to create a task record, then attach the returned memory_id as memory_refs to the Scheduler task. Ordinary temporary reminders need not write to Memory.Execute the calls sequentially without treating them as one atomic transaction; explicitly report either failure to the agent.
Execution or state changeThe prompt task receives current MemoryRef content at execution. If the record describes this task, the agent first reads its revision and original content, then uses update_record to write current status, results, or information to retain for the next execution.Scheduler cannot use other side-effect tools such as shell, file writing, or network sending; added write capability is limited to existing Memory transaction tools.
ClosureIf long-term value remains, update the associated record as completed, closed, or with the final result; if no retention value remains, delete it using delete_record. An interactive agent may also disable or delete the Scheduler task.After deletion, the current Memory API no longer resolves the old ID. A Scheduler task still referencing it fails on the next resolution; remove or close the task first.

Git recovery boundary

Commits preceding record deletion remain retrievable and recoverable from reachable history in the same Memory Git repository, provided changes were committed, the repository still exists, and history was not rewritten or pruned. Current memory_get queries only HEAD. Recoverability through Git history therefore does not mean an old memory_id can be queried directly through the current API, nor does it provide an absolute 100% guarantee.

5. Legacy Commitments migration

6. Scheduler layout

The Scheduler uses the shared page header and theme tokens. Four compact filters occupy a horizontal row below the header instead of a full-height sidebar. Filters wrap at narrow container widths. Task rows retain their schedule, status and actions.

Empty state

The introduction and Create task action are centered within the available content area. Three suggestion cards share a centered, 960px maximum-width grid, with one column in narrow containers. Each card shows its title, schedule, prompt and a Use action that opens the existing form. Existing tasks remain a full-width list.

Acceptance: /scheduler has no dedicated category column; all four filters remain accessible at 360px, 768px and 1440px container widths; suggestions wrap without horizontal overflow; Create and Use open the existing form without creating a task; loading, search and error states retain their behavior. No scheduler API, persistence, execution or terminal TUI changes.

Implementation status: the layout passes specification and quality reviews, Web static checks, 152 unit tests, TypeScript checking, production build, and documentation link checks. Browser component previews at 360px, 768px and 1440px show no horizontal overflow; Create task and Use open the existing dialog. The default App also displays the layout correctly; Use opens the existing prefilled form and Escape returns to the Scheduler without creating a task.

7. Adoption, changes, and exclusions

ReferenceHandling
User-provided Scheduled tasks screenshotAdopt a standalone page, Create, search, and one-time/recurring/monitoring product categories. Exclude a repeated hero title and large whitespace. Reuse OpenProgram’s ManagePageHeader, ManageRow, theme-consistent filter buttons, and theme tokens.
Existing OpenProgram cronRetain execution safety and cron-compatible entry points, rename the product to Scheduler, and integrate it into the persistent worker.
Original Commitments/heartbeatDo not retain it as a Memory type. Keep migration reads only, without the Memory tab, status field, or special heartbeat.
Automatic Scheduler writes to MemoryReject implicit dual writes in the service layer. Let agents explicitly compose two existing tools and store the relationship in MemoryRef, avoiding new cross-store transactions and duplicate CRUD.

8. Implementation brief and acceptance

This change is limited to the internal Memory lifecycle of Scheduler prompt tasks: retain existing Scheduler service, REST, UI, and Memory data formats; permit Scheduler-origin calls to memory_status, memory_get and memory_update, and extend Agent tool descriptions and execution-context prompts. Public RED tests must prove these three tools execute while shell, ordinary file writes, network sending, and Scheduler self-modification remain strictly denied. Memory writes continue through existing authority, revision, transaction, and Git paths. External API permissions are outside this implementation. After record deletion, current queries for the old memory_id return NOT_FOUND.

The separate worker reliability change isolates complete tick exceptions in run_forever and lets scheduler-worker and cron-worker bypass stdio redirection intended only for Ink TUI startup. It does not change Scheduler service, REST, task state formats, claim, spawn, or run_once.

Acceptance itemCurrent evidence
Focused Python checksScheduler, permissions, cron CLI, and Memory routes/runtime total 133 passed; Ruff passes.
Memory lifecycleThe actual Scheduler prompt worker loads merged permission rules; local-owner tasks may use memory_status, memory_get and memory_update; deny/ask still take precedence and other side effects remain denied. An actual ScriptedProvider flow updated a Topic and created a Memory Git commit. If multiple MemoryRefs exceed the limit, retain every ID and Topic path, truncate only content, and mark truncation explicitly. Both specification and quality re-reviews passed.
Daemon-loop fault isolationrun_forever writes ordinary tick exceptions as warnings and full tracebacks to stderr (redirected to the global worker log for the persistent worker, displayed in the terminal for standalone foreground commands), waits for the original minute cadence, then continues with the next tick. Initial failure does not replay the @reboot tick. This output does not enter the task execution log.run_once still propagates exceptions immediately; KeyboardInterrupt and similar BaseException are not converted into retries. The canonical command, compatibility alias, and their --once/--list entry points all bypass TUI stdio redirection. Public regressions cover initial/ordinary ticks, normal waits, oversleep, the next tick, logging, CLI entry points, and both fail-fast boundaries.
Full Python checks5316 passed, 15 skipped, 2 deselected, 1 xfailed. The remaining four failures were individually reproduced on baseline commit 17db67dc and concern existing channel HTTP inventory and agentic harness scanning.
WebFull static checks, Scheduler checks, and tsc --noEmit pass. The standalone page includes initial-load errors, action errors, and accessible icon-button names. Visual acceptance requires one page title, a 64px management-page topbar, search and the primary action in one row, horizontal category filters below the topbar, task numbering in visible order, and centered responsive suggestion cards in the empty state, confirmed by screenshots in the default 18100 App.
Independent reviewSpecification review passed. All quality findings concerning permissions, state claims, concurrency, MemoryRef, compatibility entry points, and UI error handling were fixed and re-review passed. The separate management-page structural revision received specification PASS. Quality review requested narrow-column reflow, distinguishable action names, and executable view-logic checks; scoped re-review passed after repair.

Implementation status for this change: Internal-agent Scheduler–Memory lifecycle integration and ordinary daemon-tick exception isolation are implemented. Deleted records retain no placeholder or ID forwarding; current queries for the old memory_id return NOT_FOUND. The external-token permission model remains deferred as scoped.