OpenProgram · Harness design

Restart recovery and Goal design for the complete session runtime

Design question: after an App or worker restart, how do previously running sessions and Goals automatically continue, restoring subtasks, approvals, context, and usage without repeating unknown writes or resuming work the user explicitly stopped?

For framework development and product acceptance. This page defines the target design; implementation status is collected at the end. Scope includes Web, TUI, ACP, background Jobs, and authorized subtasks. Goals use the same chat execution layer. Retain the Python Workflow API without duplicating the execution engine, introducing a general scheduler, or promising exactly-once execution for arbitrary external operations.

Verified current behavior · Automatic recovery contract · Complete recovery-state matrix · Failure acceptance matrix

Core contract:Resuming a session does not mean retrying its tools. An old turn may end as interrupted while its operations remain outcome_unknown; a new turn first checks actual state. Goal, Todo, chat history, and incurred usage remain preserved.
  1. 1. Save the objectiveOriginal objective, completion conditions, permission scope, and explicit budget.
  2. 2. Work through ordinary chatThe agent maintains Todo and uses existing tools and approvals.
  3. 3. Check at turn completionSettle usage and decide whether to continue, wait, pause, or verify acceptance.
  4. 4. Accept completionSubmit achieved once evidence supports every condition; otherwise continue working.

There is no default round cap. Round count is diagnostic information, not a substitute for progress or stopping conditions. Retain the short state tools create_goal/get_goal/update_goal; they only read and write objectives, rather than executing the entire task within one function call.

Five harnesses: what to adopt and what not to duplicate

Reference and evidenceVerified behaviorOpenProgram choice
Codex: history repair · Idle continuationMissing tool outputs become aborted; Goals continue through ordinary thread-idle admission.Adopt ordinary chat continuation, pairing repair, and current-state verification; do not interpret aborted as reversal of external effects.
Claude Code: recovery · Goal evaluationTools interrupted by a crash are not automatically rerun; an independent small model evaluates the Goal from conversational evidence. Only official contracts were verified, not internal source.Adopt recovery without blind reruns and independent completion review; do not add evaluation after every work turn, avoiding unnecessary latency and cost.
OpenCode: history conversion · Step usageConvert pending/running calls into interruption errors; record tokens and cost at model-step completion.Adopt continuable interrupted history and per-request usage; Todo is a work plan and does not independently determine completion.
OpenClaw: pairing repairMatch existing results, synthesize errors for missing ones, and handle duplicate or misplaced results.Adopt provider-request projection repair without overwriting original factual records or equating heartbeat with Goal.
DeepSeek harness: interruption closure · Continuation contractAppend repairs after exclusive write access; distinguish not-started from unknown outcomes; close old turns and require explicit authorization to continue recovered Goals.Adopt layered state and idempotent repair; do not copy its default round cap or the product policy requiring manual reactivation after restart.

The following are OpenProgram design choices based on these implementations, not claims that the five projects provide identical safety, acceptance, or cost guarantees. Reference source is pinned to inspected versions; external project tests were not run.

Verifiable Codex boundaries:Official App Server documentationdistinguishes thread/resume, turn/start, and persistent Goals;public extension sourceloads active Goals when resuming threads and attempts continuation while idle. This does not establish that arbitrary desktop exits, system restarts, or tool-process deaths can restore original memory or continue original tools. OpenProgram defines automatic continuation while prior run intent remains valid as its own explicit product contract, without relying on that unverified stronger assumption.

Current state: persistence exists, but consistent recovery decisions are missing

Inspected codeCurrent behaviorRequired changes or verification
execution/startup.py, execution/control/recovery.pyOwner checks, canonical recovery, wait-receipt recovery, and projection redelivery already exist; this is not a blank implementation.Unconfirmed effects can place an entire execution in reconciliation_required; separate operation reconciliation from whether the session can continue.
execution/restart.pyRestart pause intent, deduplicated continuation commands, and resource admission exist. Recovery has no default expiry; explicit disabling and finite deadlines remain, and unresolved effects are disallowed.Complete state recovery still needs acceptance. Existing finite deadlines in old records are not automatically extended, and removing the default expiry does not authorize replay of unresolved effects.
workflow/goal/chat.py, _webui/_exec_dag.pyChat Goals do not pause because of downtime or display-projection repair. Persist completion notifications before execution finishes, then continue under the original policy after restart. Old records without recovery provenance retain explicit Resume.Completion notifications and checkpoint recovery have focused tests; unknown effects, new-turn recovery, and complete subtask paths still require implementation and acceptance.
agent/job/runner/recovery.py, execution/control/waits.pyJob recovery, deferred inbox, durable answers, and deduplicated continue exist; some ordinary-chat restart paths exclude spawn/merge.Unify parent/child recovery decisions and result delivery. A saved Job does not imply a fully recovered child agent.
execution/waits.pyDurable waits differ from live producer waits; live waits are cancelled when their producer disappears.Recoverable approvals and questions cannot depend solely on process callbacks. Preserve expired question records and reconfirm rather than assuming approval.
usage/context.py, usage/event.pySession, agent, and Job attribution and a ledger exist; context does not directly retain Goal/revision/request-attempt identity.Fix attribution and unique keys before requests to support late receipts after restart; missing usage must not become zero.
browser_resources.py, terminal_resources.py, Web session storeResource identity, recovery state, and session projections exist; this does not mean every process, page state, or environment can be reconstructed.Accept real reconnection, invalidation reporting, and new identity separately for each resource; frontend reconnection must not trigger duplicate execution.

Inspection covers the shared entry points above, not individual failure tests for every adapter. A paused UI does not prove history was deleted, and existing records do not prove automatic continuation is possible.

Automatic recovery contract: run intent survives the process

Complete durable run_intent on top of existing admission / command / restart intent rather than adding a parallel scheduler. It records work_id, original input and unconsumed messages, desired_state (run / paused / cancelled / done), latest valid control version, permission scope, objective revision, execution host identity, parent/child relationships, last committed progress, and recovery policy. Acknowledge acceptance to the client only after reliably saving the original user request.

By default, automatically recover previously authorized work whose state remains run, consistently for ordinary sessions and Goals and without requiring the user to reopen the session. Preserve pauses, stops, completion, outstanding approval, and exhausted budgets. Ordinary requests without a Goal continue only until that request finishes, not as indefinite Goals. Background work retains its prior authorization and concurrency quota; restart does not authorize additional subtasks.

Closing a window or reloading the frontend only disconnects the client; “quit and stop all tasks” must persist user stop intent. Ordinary App exit, upgrades, worker crashes, and machine restarts do not implicitly mean user Pause. Graceful shutdown first stops new admission and saves accepted controls and checkpoints, then exits the worker; forced shutdown recovers from the last committed records. Client-only drafts without server acknowledgment must not be represented as submitted requests.

Remove the hidden two-hour recovery expiry. Long downtime preserves run intent, but continuation rechecks directory, host, model/tool availability, credentials, current permissions, and budget. Missing resources or revoked permissions show precise waiting reasons, without switching project, account, or model or expanding permissions automatically. Explicit automatic-recovery disabling remains effective; old paused records with unknown reasons stay paused with an explanation rather than being guessed to have been running.

  1. Load facts:Read run intent, user controls, messages, checkpoints, effects, waits, resources, usage, and projection cursors. Read/migration failures show recovery failure without clearing old state.
  2. Confirm ownership:Reconnect live executors; exclude dead executors through generation fencing. Only one host recovers each work item. Single-host recovery must not silently become cross-host takeover.
  3. Repair context:Merge real results, supply missing tool outputs, and record interruption. Resume from a complete safe checkpoint when available; otherwise start a new turn with the same work_id without re-appending user input.
  4. Decide:User stops take priority, followed by approval, permissions, budget, resources, and unknown effects. Runnable work becomes queued; dependency waits become waiting; faults expose retryable reasons. Persist all decisions in the same control service.
  5. Admit and continue:Use existing fair scheduling and resource quotas; derive a stable continuation key from work_id + control version + predecessor commit point. Admission persistence and recovery-intent consumption must leave no duplication window; converge cross-database steps through a retryable outbox.
  6. Restore the interface:App/Web/TUI reconstruct from canonical snapshots and monotonic event sequences, showing recovery, queueing, working, waiting, or failure; display is not a second control implementation.

Recovery coordination belongs to existing execution control. The server and JobRunner may call the same idempotent entry point but cannot make independent recovery decisions. UI orphan cleanup repairs only derived projections; Goal.after_terminal submits continuation requests only for the current version. Temporary faults use durable retry times and bounded backoff instead of idle model calls. Persistent faults retain pending-recovery records and show the error plus Retry / Pause / End without deleting tasks.

Complete recovery-state matrix

Before restartDefault behavior after restartRestrictions that must persist
Accepted ordinary request not yet scheduledRequeue with original input order and admit once.Deduplicate by client request ID; late retries must not override Stop.
Interrupted model streamPreserve committed text and tool results; label incomplete output and request the remaining work again.Do not fabricate a complete response by concatenation; a new provider attempt can incur additional cost.
An active Goal working or between turnsLoad objective, Todo, evidence, budget, and original run intent; automatically continue work or acceptance.Do not omit idle active Goals because no execution currently exists; 5/5 only triggers acceptance.
User Pause / End / StopRemain paused or terminated; completion notifications and automatic recovery cannot release it.Persist stop commands when accepted; separate visible execution-stopping progress from business intent.
Pending approval or user answerRestore the question, request summary, and scope; consume a committed durable answer only once.Restart is not approval; old approval does not authorize a new action after changes to implementation, arguments, or permissions.
Parent agent waiting for subtasksRestore existing subtask identities, outputs, inbox cursors, and wait relationships; after receiving terminal state, the parent continues under its original intent.Reconnect live subtasks and do not recreate finished ones. Propagate user pause policy to child executions within the same task scope without stopping independent tasks.
External process, terminal, or remote job runningQuery using host, process-start identity, or job handle; keep observing if alive.PID alone is insufficient; preserve unknown when completion is uncertain and do not resubmit.
Browser / MCP / temporary resourcePreserve stable resource references and verify identity on reconnection; report actual invalidation and create new resources only as authorized.Page forms, login state, JS memory, and REPL variables are not guaranteed to recover; a new tab or session must not impersonate the original object.
Context compaction or message persistence in progressUse the last committed history and summary; an uncommitted summary cannot replace original history.Partial tool arguments are not executable. Use currently effective permissions and display durable work configuration and unavailable dependencies explicitly.
Result written but completion notification undeliveredReplay terminal projections and inbox delivery without rerunning the task.Canonical terminal state and projection versions prevent UI rollback; parent aggregation must not double-charge.
Usage receipt absent or seen only in a streamReconcile obtainable receipts by provider attempt and deduplicate existing records.Unobtainable consumption remains unknown; downtime does not count as active time.

Recovery promises confirmed saved work state, run intent, and reconstructable execution, not arbitrary process-memory snapshots. Unpersisted stream fragments, interactive memory in a dead shell, and receipts lost by external services must be reported accurately, not hidden by clearing tasks or fabricated success.

One chat execution layer, five durable data categories

Data and sole ownerPreserved contentResponsibilities it must not assume
Goal / objective state servicegoal_id, revision, original objective, acceptance conditions, status, explicit budget, and blocking reasons.Does not hold provider streams or restore function-call stacks.
Todo / existing plan storeStable item_id, goal_id, revision, status, and evidence references; UI reads the same source.Deleting unfinished items must not reduce the objective; plan edits alone are insufficient evidence of progress.
Turn / canonical executionInput origin, permissions, objective attribution, owner generation, turn state, and subtasks.interrupted does not mean Goal failure or that all external processes stopped.
Tool attempt / effect storeCall and actual tool-implementation identity, input summary, start record, real/synthetic result provenance, and effect certainty.Unknown results must not masquerade as success or never executed; a tool name does not establish read-only behavior.
Usage receipt / usage ledgerUnique request/attempt identity, turn/goal/revision attribution, model, tokens, price snapshot, amount, and trust status.Do not infer Goal costs from session totals or present estimates as actual settlement.

Continue using existing session, execution, effect, todo, and usage stores without building a second event platform. Cross-database updates use existing retryable notifications and unique operation keys; do not assume cross-database atomic transactions. Derived UI and statistics can be reconstructed and must not overwrite original records.

Goal states remain active / paused / blocked / achieved / cancelled / budget_exhausted. Execution, waiting, and acceptance belong in phase or existing wait records instead of a redundant combined state machine. Retain compatibility reads for paused_recoverable. Revision or permission changes invalidate old acceptance and automatic-continuation reservations; old usage retains its original objective attribution.

Interruption recovery: confirm execution ownership before restoring context

  1. Confirm the old executor:Use the existing owner lease / generation; do not write repairs when the lease is uncertain or storage unreadable. A disconnected connection alone does not prove process death. Reject subsequent writes from the old generation.
  2. Verify child processes:Reconnect trackable live processes and wait or explicitly cancel; do not treat a running shell as stopped. Preserve unknown-effect records for unreachable remote operations.
  3. Choose exactly one recovery mode:Only reconnect a live owner. If death is confirmed and a verifiable safe checkpoint exists, create a new attempt under the same execution. Only when no reliable checkpoint exists, acquire exclusive recovery ownership, fill missing outputs using a stable repair key, end the old turn as interrupted, and admit a new turn. These choices are mutually exclusive and bind to the same durable recovery decision, control version, and continuation key; never resume a checkpoint and start a new turn together. Checkpoints must cover committed effects and satisfy current permission, wait, and safe-point contracts, without replaying unknown writes. Repeating repairs has no side effects; real results take priority and no usage is fabricated. Append late verifiable receipts as reconciliation events that replace synthetic placeholders in subsequent context.
  4. Restore run intent:Previously running ordinary requests and active Goals automatically enter unified admission; user-paused work does not resume automatically. Only specific permission, budget, resource, or unknown-operation issues need human intervention; restart itself is not a reason to require manual Resume.
  5. Decide tool behavior:New turns know which calls never started and which outcomes are unknown. Old unknown results do not globally block investigation or independent work; related writes retain original approval and recovery restrictions.
State before interruptionFacts after recoveryPermitted next action
Intent saved, dispatch not yet recordednot_started; every dispatch must be recorded durably first, otherwise this conclusion is invalid.Invoke again under current permissions if still needed.
Dispatch recorded, result missingoutcome_unknown; includes a crash between recording the start and making the actual call.Trusted read-only tools may reread; use the original idempotency key when the service supports deduplication; reconcile other writes first.
Result persistedcompleted / error with the actual return value preserved.Reuse the result; do not rerun because of restart.
External task still aliverunning_external + verifiable handle.Reconnect, wait, or cancel; do not resubmit.
Non-idempotent write outcome cannot be queriedoutcome_unknown + pending-operation details.Allow reads and investigation; retry or explicitly abandon the operation only after the user confirms the risk.

Safety boundary: read_only / idempotent / state_probe capabilities come from trusted tool registration and implementation identity saved at execution. Do not accept model claims of read-only behavior or infer them from a name containing read. General shell, third-party MCP, and custom tools default to unknown. Recovery turns related to unknown writes initially allow only trusted reads and state queries. Without reliable relevance determination, do not automatically allow writes; reconcile first or obtain explicit user authorization.

Request-history repair first matches the nearest call by original call ID, then converts provider IDs. Existing real outputs take priority; duplicate outputs use the last saved real record. Missing results get deterministic unknown placeholders. Calls and results are adjacent in the request projection while user-message order remains intact; original history is unchanged. Results without corresponding calls are not sent as valid tool-protocol items. Interrupted responses retain partial text and an interruption marker without reusing incomplete reasoning signatures. Ambiguous duplicate call IDs within one response produce an explicit error rather than guessed execution facts. This conversion grants no execution permission and cannot replace recovery decisions.

Recovery permission checks use the same conversation provenance to scope old executions and invoked Jobs, without expanding to all executions in the invoked session. Only actual built-in read, grep, glob, and list execution functions qualify for read-only investigation; names, acceptEdits flags, and plugin declarations cannot replace implementation identity. For uncertain effects within the applicable execution scope described below, all other operations require one-time approval; bypass, automatic classification, and existing allow rules cannot waive it. Durable approval binds to the new tool call and unknown-effect set; changes to that set require fresh approval and do not erase old effects. Reject execution if recovery state cannot be read. This check is a prerequisite for restricted new-turn recovery; it does not independently change old execution state or enable Resume.

This is neither an exception for one session nor a repair restricted to allowlisted files. Ordinary chat and Goals share the recovery entry point. Old effect audits may remain unresolved while their chat turns end as interrupted; adjust the old constraint that any unresolved effect prevents turn termination accordingly.

Only an explicitly activated Goal produces Goal UI. Starting, running, pausing and verifying do not add transcript cards. At termination, one compact record remains at the ending transcript position. It uses the existing attachment-card styling and opens the existing Goal details dialog in read-only historical mode. Each record carries its own Goal snapshot and transcript anchor; a later Goal cannot replace its contents. The composer continues to show the current Goal only. Canonically identified verifier messages are internal records, not assistant chat prose; ordinary agent replies remain unchanged. No assessment text, evidence identifiers or raw report is appended to chat. Terminal history is saved with the Goal state under optimistic concurrency. The implementation passes independent specification and quality review. Coverage includes terminal snapshot persistence, stable historical anchors, read-only reuse of the Goal dialog, keyboard focus restoration and preservation of ordinary JSON replies. Full verification and installed-App acceptance remain separate release gates.

Todo manages the plan; acceptance manages the objective

At creation, preserve the original objective and extract verifiable requirements; ask the user only when ambiguity would change scope. The working agent maintains Todo for multi-step tasks; simple tasks may omit it. Every necessary requirement has an evidence checkpoint; adding or removing Todo must not implicitly remove original requirements.

Ordinary work turns do not run a second judge. Enter verifying when the worker submits a complete candidate or all required Todo items finish without verification. First check current revision, required Todo, unfinished subtasks, and relevant unknown effects, then run one independent read-only acceptance review. The worker's completion text is not an acceptance fact.

Acceptance returns met / unmet / unknown and evidence references for each requirement. Deterministic requirements inspect actual test receipts, file versions, and runtime state; semantic requirements use independent model review. Tests retain ordinary tool approval and budget rules: calling shell verification does not make it read-only. Missing evidence returns to another work turn rather than fabricated acceptance.

Only the current goal_id + revision + verified result version may submit achieved. Recheck evidence versions and compare the Goal control version before committing. Controlled artifacts use version numbers or content digests; external facts retain verification time and query receipts without claiming atomic verification across all external systems. Completion means conditions held at that verification; it does not automatically monitor files or reopen the Goal afterward. Later edits, new requests, or explicit monitoring require separate acceptance. Human waivers must be explicit objective revisions with reasons; the agent cannot reduce scope itself. Independent acceptance can also err and does not guarantee absolute correctness.

Judge lack of progress by changes in results and evidence, not tool invocation count. Enter blocked only when the same real blocker recurs consecutively and no independent work is available. Waiting with a live handle enters waiting without idle model turns. A fixed total round count is not evidence of blocking or completion.

Waiting uses existing durable waits and execution-terminal notifications, saving work_id / Goal revision, handle, observed version, and unique consumption key. Completion, failure, or timeout notifications admit exactly once only if intent remains run, versions match, and no other current execution exists. Existing reconciliation polls for missing notifications with backoff. Save results arriving during restart, then automatically continue under the same rules. Pause, cancel, or revision invalidates old wakeups without discarding results; query timeout does not imply the external operation stopped.

Cost: attribute per request, settle per receipt

Fix goal_id / revision / turn_id / request_id before dispatch. Ordinary chat after pausing has no old Goal attribution. Subagent and acceptance requests explicitly inherit attribution; count each receipt once rather than adding both parent totals and child details. Retries are new provider attempts and count separately when they incur actual consumption.

Streaming cumulative usage updates a watermark for the same attempt; do not sum cumulative snapshots. Update Goal projections only after durable receipt writes succeed. Temporary failures retry with the same idempotency key, and restart can reconstruct statistics. Late receipts remain attributed to the original Goal even if paused, ended, or edited.

Store known tokens and known prices separately. Pricing-table changes do not rewrite historical quotes. Display estimates, known values, and partial unknowns separately, such as “Known $0.42; usage unknown for 1 additional request.” Preserve historical cursor data without inventing attribution. Accumulate active time from durable start/stop records, excluding pauses and downtime and without resetting on recovery. When an executor disappears, preserve its last heartbeat; crash-discovery time is not stop time. Show the known duration lower bound and unknown interruption interval. Late usage does not restart paused timers. If an explicit time limit cannot be verified, stop new admission without adding a default limit.

Budgets are unlimited by default. With a user-set hard cost budget, unknown prices or unverifiable consumption cannot be treated as available balance; pause new paid admission and explain why. Reserve a maximum request amount when calculable; otherwise do not promise absolute prevention of overspend. Recheck explicit budgets after ledger reload and before execution recovery or acceptance.

Background Jobs save Goal identity at the real active caller's admission boundary, restore it at startup, and clear unrelated temporary attribution. Cross-session calls preserve original caller provenance without creating a cross-session canonical parent. Goal and Job share start/settlement transactions in usage.db; receipts save Job reservation identity so metering can be reconstructed without an in-memory governor after restart. Unknown tokens and unknown costs retain separate reservations; partial cumulative data records only lower bounds. Expired unstarted reservations cannot dispatch; started requests are not automatically released. Hard budgets accept only audited input/output limits, explicit prices, and service tiers and add no default restriction to Goals without budgets.

Controls and interface: show state, reason, and action together

State before → action → state afterWhat the user seesExecution constraint
Running → restart → recovering / queued → investigation / executionNo Resume click required; specific obstacles show reasons, relevant actions, and Retry. Resume appears only for user-paused work.Restore intent without blindly resending old tools; admit only one turn per work item.
Todo 5/5 → begin acceptance → verifying“5/5 · Verifying,” not “Complete.”Missing evidence returns to work; show “Goal completed” only after acceptance.
active → Pause → pausedStop automatic continuation immediately; separately show whether current execution is still stopping.Block new admission and cancel current execution without pretending to undo existing effects.
Any unfinished Goal → End → cancelled“Goal ended”; still show unfinished processes or unknown operations.Ending objective intent does not depend on reconciling every effect; old executions no longer trigger automatic continuation.
Pending operation → inspect / query / human confirmation → reconciled or still unknownIdentify the exact call, input summary, original time, and available checks, rather than only linking to the entire Activity list.Risk-bearing retries require the current user's explicit authorization; models or page content cannot answer for them.

An empty Todo shows no progress placeholder or separator. Backend can_resume / can_verify / can_end and reason_code determine button permissions; the frontend must not infer them from status strings. UI read failures show “State temporarily unavailable” with refresh, not permanently disabled unexplained controls.

User input takes priority over automatic continuation using existing steer/queue semantics. Continuation keys bind goal_id, revision, and the previous committed turn; state checking and admission share version comparisons. Durable state and generation checks block stale actions when pause, edit, explicit cancellation, and admission race.

Implementation sequence and required acceptance

Stage and locationsBehavior that must be demonstrated
1. Unified recovery decisions: execution/startup, restart, control/recovery, JobRunner, _exec_dag projectionsOrdinary requests, active Goals, and existing subtasks recover automatically after restart; user-paused work does not. Remove the hidden time window and projection-layer business-state rewrites while preserving unique admission and current permissions.
2. Shared execution recovery: agent/production_driver, context construction, effects, waits, resource adaptersTerminate real child processes before dispatch, after start, and after result persistence. Restart appends repair once, preserves real results, and allows ordinary chat to continue. Late old-owner writes, live shells, and unknown non-idempotent writes must not be retried incorrectly.
3. Goal continuation and control: workflow/goal, HTTP/WS/TUI/ACP entry pointsResume does not replay tools. Double clicks, repeated completion events, and edit/pause races do not produce duplicate executions. Old revisions cannot complete new objectives. No Todo means no placeholder; 5/5 does not directly show achieved.
4. Evidence acceptance: Goal completion candidates and existing agent inspection capabilitiesReject completion separately for unfinished required items, missing evidence, failing tests, stale results, and relevant unknown effects; commit achieved once when actual evidence satisfies requirements. Verification cannot elevate tool permissions.
5. Request attribution and statistics: usage/recorder, ledger, Goal projectionsHandle duplicate/out-of-order usage, concurrent subtasks, streaming cumulative values, retries, ledger faults, and late post-pause receipts correctly. Unknown is not zero; exceeded budgets stop further paid requests.
6. Compatibility and local acceptanceOld Goals remain readable; unknown effects migrate without guessing; chat recovery policies do not break Python Workflow. After full regression and independent specification/quality reviews, update the single default App and verify actual controls, restart continuation, and cost display.

Each stage begins with a public-entry failure reproduction, followed by minimal implementation and regression. Recovery tests cover ordinary chat, not just one specific session. Acceptance distinguishes source, automated tests, local App, and remote release; designs without test or deployment evidence are not marked implemented.

Restart failure acceptance: more than testing Resume once

Create work through public chat, Goal, Job, approval, and control entry points; perform real termination using isolated test storage and non-user-visible process tests. Do not terminate the user's current work to demonstrate recovery. Final visible App acceptance uses only the default instance and first confirms that updating will not overwrite unrelated work.

  • Cover frontend reload, normal App exit, graceful worker restart, forced worker termination, downtime beyond the old two-hour window, and another crash during recovery. Test host-restart semantics through process-identity changes; list actual OS reboot separately as unverified and do not reboot the user's machine yourself.
  • Interruption points include before/after input acceptance, provider requests, before/after tool dispatch, before/after result commit, parent/child delivery, all Todo complete before acceptance, after completion commit before projection delivery, and before/after usage persistence.
  • Recover multiple sessions together to prove fair queueing, shared quotas, one owner per work item, and no duplicate execution from repeated notifications. User Pause / End, permission changes, and new input take priority during recovery; old versions cannot continue.
  • Live child processes only reconnect; unknown non-idempotent writes only undergo investigation. Consume accepted approvals once and never approve unaccepted requests automatically. Late results and usage retain their original identity.
  • Unavailable databases, broken migrations, missing credentials/directories, changed tool versions, and lost projection events all need explicit states and recoverable actions, without clearing history or leaving unexplained disabled controls.
Python Workflow compatibility path and existing detailed diagrams (do not define the chat Goal contract above)
Implementation Survey · Design Reference

Agent Goal capability: implementation comparison

This document compares actual Goal runtime responsibilities: where objectives reside, who triggers the next turn, who determines completion, how resources are limited, how waiting and human intervention work, and whether recovery survives process restart. The focus is control flow and state ownership, not feature names.

4 native Goal implementations 2 adjacent mechanisms Compatibility reference, not proof of chat Goal implementation 5 Archify SVGs embedded in the document
Already availableIndependent completion judgment with inspection toolsThe working agent produces results; an inspection judge checks evidence and decides to continue or complete.
Main current gapExternal-event wakeup is not implementedwaiting_external Explicit resume remains required; live Goals sharing a directory on one machine are protected by an exclusive controller lock.
Current designDurable snapshots, asynchronous questions, an independent judge, and hard budgets share one controllerRestart becomes recoverable pause; waiting consumes neither rounds nor active-time budget.

1. Scope and comparison criteria

A system counts as a native Goal here only if it stores objective state and uses that state after ordinary agent turns to decide whether to automatically start another turn. Todo, Plan, Task, and Cron may participate in Goals but are not Goals on their own.

Compared systems

OpenProgram, Codex, Claude Code, and Hermes Agent; OpenCode and OpenClaw as adjacent implementations; OpenAI Agents SDK, LangGraph, AutoGen, and CrewAI as general-framework baselines.

Fixed dimensions

Entry points, state structure, loop triggers, completion decisions, budgets, waiting, human intervention, persistence, recovery, concurrency control, events, and UI.

Evidence priority

Public and repository source take priority; official runtime documentation covers closed-source implementations. Product behavior illustrates interfaces, not inferred internal data structures.

Claude Code implementation source is not public. This document records only control contracts explicitly stated in official documentation:/goal is a session-scoped prompt Stop hook, including evaluator input, three verdicts, recovery, and background-task wait rules, without inferring tables or internal class names.

Control flow for compatible Python Workflow

This section describes the retained Python goal() Workflow. Ordinary chat uses the chat Goal contract at the top, not the refine/work/judge loop below.

All four native implementations decide whether to start another turn after work. Their differences center on who owns state, who determines completion, and whether waiting pauses execution.

Minimal complete Goal flow from input to terminationSolid lines are the current work path; dashed lines indicate re-execution after incomplete work or external changes.
WorkDecisionWaitStop
OpenProgram Goal control flow Workflow diagram generated by Archify. 01 / Web / TUI 02 / Goal Controller 03 / Agent Roles 04 / Evidence & State EX / Wait / Stop Definition and recovery Execution and decision Continue or terminate Goal input · Create / edit / continue · Web / TUI › Definition and recovery Goal input Create / edit / continue Durable state · goal_id · version · checkpoint · Goal Controller › Definition and recovery Durable state goal_id · version · checkpoint Atomic state transition · CAS version + event · Goal Controller › Continue or terminate Atomic state transition CAS version + event Working Agent · Invoke tools and advance work · Agent Roles › Execution and decision Working Agent Invoke tools and advance work Deterministic Gate · Commands · files · counts · permissions · Agent Roles › Execution and decision Deterministic Gate Commands · files · counts · permissions Judge Agent · Read-only inspection and semantic judgment · Agent Roles › Continue or terminate Judge Agent Read-only inspection and semantic judgment Evidence and usage · Results · files · tokens · time · Evidence & State › Execution and decision Evidence and usage Results · files · tokens · time Asynchronous question queue · Accumulate · deduplicate · answer later · Wait / Stop › Execution and decision Asynchronous question queue Accumulate · deduplicate · answer later Waiting boundary · No independent work / external events · Wait / Stop › Execution and decision Waiting boundary No independent work / external events Stop with evidence preserved · blocked · stalled · failed · Wait / Stop › Continue or terminate Stop with evidence preserved blocked · stalled · failed unmet → next round terminal verdict verifiable criteria gate result create / edit / resume typed verdict needs_user waiting_external No independent work Can continue → independent work lease + checkpoint result + tool evidence Legend User interface Agent logic Policy Tool operations Context / tracing External systems
A complete Goal implementation must genuinely pause on its yellow waiting branch, distinguish reasons on its red stopping branch, and recover control state across turns and processes. Implementing only the central work–judgment loop is insufficient.

Five implementation models

Level
Input
Progress
Termination
Across turns
Representative systems
Task input
User messageAs this turn's task
No requirement
Model stops
No
Ordinary agent turn
Progress ledger
Task + items
Todo / TaskFor prompting and UI
Does not determine overall termination
No automatic continuation
OpenCode Todo
Graph termination
graph state
Application-defined
edge / condition
Implemented by the application
LangGraph · AutoGen
Persisted controller
objective
usage / status
Agent declaration
Automatic continuation when idle
Codex
Evaluator loop
Goal spec
evidence
Independent evaluator
Continue if incomplete
OpenProgram · Claude · Hermes

D and E can combine. Codex lets the working agent declare completion while its control plane manages lifecycle and budget; the other three implementations delegate completion to an independent evaluator.

Four native Goal architectures in one diagram

Each row is a complete implementation. Read horizontally to see where each places state, work, judgment, and continuation.

State ownership and judgment paths of native GoalsCyan denotes independent evaluators, blue working agents, and yellow waiting or restricted states.
Control structures of four native Goal implementations Workflow diagram generated by Archify. 01 / OpenProgram 02 / Codex 03 / Claude Code 04 / Hermes Agent State ownership Work and judgment Continuation and waiting Versioned Goal snapshot · goal/run ID · CAS · OpenProgram › State ownership Versioned Goal snapshot goal/run ID · CAS Working Agent → Judge · Independent with read-only inspection · OpenProgram › Work and judgment Working Agent → Judge Independent with read-only inspection Controller / Wait · Asynchronous questions · restart recovery · OpenProgram › Continuation and waiting Controller / Wait Asynchronous questions · restart recovery SQLite ThreadGoal · typed status · usage · Codex › State ownership SQLite ThreadGoal typed status · usage Working Agent self-report · update_goal · Codex › Work and judgment Working Agent self-report update_goal Idle Controller · pause · resume · limits · Codex › Continuation and waiting Idle Controller pause · resume · limits Session Goal Prompt · Retained on resume · Claude Code › State ownership Session Goal Prompt Retained on resume Stop Hook Evaluator · Small model · no tools · Claude Code › Work and judgment Stop Hook Evaluator Small model · no tools Prevent stop or clear · Defer for background tasks · Claude Code › Continuation and waiting Prevent stop or clear Defer for background tasks GoalState + Contract · gates · waits · Hermes Agent › State ownership GoalState + Contract gates · waits Gate → Judge · Mechanical checks first · Hermes Agent › Work and judgment Gate → Judge Mechanical checks first Queue / Wait Barrier · Event wakeup · Hermes Agent › Continuation and waiting Queue / Wait Barrier Event wakeup three verdicts on Stop self-report run turn done / blocked / wait turn result verdict work + evidence Legend Agent logic Policy Tool operations Context / tracing

Implementation comparison matrix

The diagram explains control structure; the table preserves exact fields and boundaries for design review.

View the complete comparison matrix
SystemGoal representationNext-turn triggerCompletion decisionBudgetWaiting / human interventionPersistence and recoveryKey property
OpenProgram Python Workflow compatibility pathsession extra_meta.goal Versioned snapshot with goal/run ID, spec, checklist, question queue, and checkpointgoal() Controller commits state at the boundary before starting the next agent()Independent judge with read-only inspection tools; typed verdict and can_continueNo default round limit; optional total round/token/active-time/cost budgets accumulate after resumeQuestions accumulate asynchronously; independent work continues; enter the following state only when remaining work requires answers: waiting_userCAS writes to session; page reload retains state; worker restart converts active execution to paused_recoverableCompletion, stopping, recovery, and UI are unified; automatic external wakeup and multi-worker leases remain absent
CodexSQLite ThreadGoal; includes goal_id and typed statusThread-idle lifecycle reads the active Goal and starts a turnThe working agent calls update_goal(complete|blocked) for self-reporting; no independent judgeOptional token budget; cumulative tokens and elapsed timeUser/system controls pause/resume/usage-limit; blocked requires a three-turn auditSQLite persistence; resume restores the active controllerMost complete control plane and data model
Claude CodeOne completion condition per sessionPrompt-based Stop hook prevents stopping and supplies its reason as next-turn guidanceSmall fast model: not met / met / impossible; no toolsNo structured Goal budget; conditions may include stop clauses; outer limits separately support max turns / USDDefer judgment while background tasks run; idle check-ins use backoff and a finite countResume restores the active condition but resets round, time, and token baselinesReuses the general Hook protocol with the smallest surface
Hermes AgentGoalState + contract + subgoals + gates + wait barrierCLI/gateway queues an ordinary user-role continuation after a turnRun deterministic gates first, then an auxiliary judge returns done/blocked/continue/wait20 Goal turns by default; per-gate timeout/retryCan wait for PID, process session, or duration; user messages take prioritySessionDB.state_meta; resume and compression-session migrationMost complete combination of completion contracts, deterministic gates, and asynchronous waits
OpenCodeUser task + SQLite Todo rowsContinue within the same turn based on tool-call finish reasonEnds when the model stops calling tools; Todo completion does not control the overall loopagent steps limit; unlimited by defaultQuestion/permission belongs to the turn; no Goal pause/resumeSessions, messages, and todos persist; no active Goal controllerReliable progress ledger, not a Goal
OpenClawAutomation jobs, heartbeat scratch, commitments, and background tasks are modeled separatelyScheduler, events, or task completion wake the sessionRun success/failure, script exit code, or model stopping for this turn; no open-ended Goal evaluatorTimeout/tool budget per automation run, not a total Goal budgetNaturally supports scheduled waiting, event wakeup, delivery, and backoffSchedule definitions, run state, and history persist across gateway restartsSuited to long-term scheduling, not open-ended objective convergence

How controllers stop when tasks cannot be completed

Native Goals automatically decide whether to continue after ordinary agent turns, so they must distinguish incomplete work, missing external conditions, impossible objectives, and persistent lack of meaningful progress. Round limits alone cannot distinguish these causes; they only bound worst-case execution length.

State machine for difficult tasksGreen denotes success. Yellow states must stop automatic work until an explicit event. Red states require changes to the objective, budget, or environment before continuation.
DecisionPauseTermination
OpenProgram Goal lifecycle Lifecycle diagram generated by Archify. 01 / Main lifecycle 02 / Recoverable waiting + difficult-task categories 03 / Terminal states Draft · Objective saved · Main lifecycle 01 Draft Objective saved Refining · Form spec and checklist · Main lifecycle 02 Refining Form spec and checklist Running · Independent work continues and questions accumulate · Main lifecycle 03 Running Independent work continues and questions accumulate Evaluating · Gate + Judge · Main lifecycle 04 Evaluating Gate + Judge Achieved · Evidence meets completion contract · Main lifecycle 05 Achieved Evidence meets completion contract Paused · User pause or restart recovery · Recoverable waiting · recoverable Paused User pause or restart recovery recoverable Waiting User · Remaining work requires answers · Recoverable waiting · event Waiting User Remaining work requires answers event Waiting External · Waiting for jobs or external state · Recoverable waiting · event Waiting External Waiting for jobs or external state event Blocked · Missing permissions, dependencies, or input · Difficult-task categories · recoverable Blocked Missing permissions, dependencies, or input recoverable Stalled · Consecutive lack of meaningful progress · Difficult-task categories · recoverable Stalled Consecutive lack of meaningful progress recoverable Budget Exhausted · turn · token · time · cost · Difficult-task categories · recoverable Budget Exhausted turn · token · time · cost recoverable Impossible · Cannot satisfy current contract · Terminal states · terminal Impossible Cannot satisfy current contract terminal Failed · Unrecoverable execution error · Terminal states · terminal Failed Unrecoverable execution error terminal Cancelled · User explicitly terminates · Terminal states · terminal Cancelled User explicitly terminates terminal Legend Start Active state Wait Decision Success Failure / exit External state
View difficult-task stopping mechanisms by framework
SystemOutcome when completion is impossibleDeterministic stopping mechanismCan it still loop for a long time?Main gap
OpenProgram Python Workflow compatibility pathTyped verdict distinguishes blocked, impossible, waiting_external, needs_user, stalled, budget_exhausted and failedCompatible Workflow has no default round limit; optional token/active-time/cost budgets; 3 consecutive judge failures; 3 checklist stalls; 2 consecutive incomplete turns without toolsNo fixed round cap without a budget; current stall evidence mainly uses checklist increments and tool useNo general deterministic gate executor yet;waiting_external no automatic event wakeup
CodexWorking agent can declare blocked; the control plane can enter paused, usage_limited, budget_limited or completeOptional token budget; blocked requires three consecutive audits of the same blocker; user/system can pauseYes. Without a token budget and without an agent declaration of blocked/complete, the Goal controller continues turnsCompletion and blocking rely on worker self-report, without an independent evaluator verifying actual lack of progress
Claude CodeWhen the evaluator returns impossible , clear the Goal; consecutive absence of tool progress stops continuation but retains the GoalThe general Stop hook forces termination after 8 consecutive stop prevention events; background idle check-ins cap at 3; outer max-turn and USD budgets are configurableYes. Goals have no structured hard budget; if tool actions continue and the evaluator keeps returning not met , stopping depends on outer limitsThe evaluator has no tools and cannot directly inspect files, tests, or external state; Goal and runner budgets are separate
Hermes AgentThe judge may return blocked or wait; continuation stops at the Goal-turn limit20 Goal turns by default; gates have timeout/retry; the same failed gate is not rerun under the same workspace fingerprint; waiting consumes no work turnsNo infinite continuation, but low-value work may repeat within 20 turnsNo confirmed Goal-level total token/cost budget; the semantic judge can keep returning continue
OpenCodeThe current turn ends when the model stops invoking tools; unfinished Todo does not start another turn automaticallyConfigurable agent steps limitA single turn may be long because steps can default to unlimited, but Todo does not form a cross-turn Goal loopNo cross-turn stalled, blocked, budget, or recovery contract
OpenClawAn automation run succeeds, fails, or times out; explicit schedules determine subsequent runsPer-run timeout/tool budget, schedule backoff, and durable run stateNo indefinite automatic continuation merely because an objective is unfinished; Cron can repeat forever as configured by the userNo open-ended Goal evaluator to determine whether a long-term objective is achieved or impossible

Why invoking a tool is not progress

Tool calls prove actions, not movement toward acceptance conditions. Stall detection should compare newly added evidence refs, passed deterministic gates, unfinished checklist items, and external-state changes across consecutive turns. Repeated identical evidence should enter stalledrather than reset the stall counter.

Waiting must not consume work turns

Questions first enter a durable asynchronous queue; the controller continues while safe independent work remains. Enter the following state only when all remaining work requires answers: waiting_user. CI, background processes, time, or external events enter waiting_external; explicit resume is currently required.

Conclusion:Semantic evaluators alone cannot guarantee convergence in any of these implementations. Reliable controllers need hard budgets, evidence-based stall detection, explicit blocked/impossible/waiting categories, and waiting states released only by external events.

Native Goal implementation details

OpenProgram

One public Workflow handles Goal execution, judgment loops, and session-state projections.

Native Goal · Open source
Entrygoal(prompt, ...)
State ownersession extra_meta.goal
Completiontool-capable judge
ResumePreserve checkpoints; continue in a new execution
Write activePersist minimal GoalState first so status/clear can see it immediately
refineAn independent inspection turn creates the spec and fixed checklist
workPublic agent() executes one complete tool loop
collectRecord tool-use signals and this turn's result, then update turns
judgeAn independent subagent reads evidence and may inspect with bash/read/grep
transitionTyped verdict, asynchronous questions, budget, and stall checks
repeatContinue independent work or write waiting / achieved / stopped state

Data and judgment

  • The entry accepts only a single prompt; the same text goes to the worker, while refinement produces a completion specification and checklist.
  • Schema v3 snapshots include goal/run ID, revision/version, typed status, budget/usage, checkpoint, question queue, and unconsumed answers.
  • Session entry points run refinement and judgment as independent agent turns that do not advance the main conversation; sessionless programs run goal also executes independent refinement/judge turns with read-only tool constraints in the current runtime.
  • The judge reads more than worker claims: it can inspect files, command outputs, and checklist items. Strict JSON parse failure retries once; 3 consecutive judgment-failure rounds enter failed.

Stopping and recovery

  • Compatible Workflow has no default work-round cap and supports total token, active-time, and cost budgets; checklist stalls and consecutive tool-free turns enter stalled.
  • /goal clear writes cancelledand cancels old execution; CAS version prevents old controllers from overwriting new controls.
  • needs_user + can_continue adds questions to the queue while independent work continues; only no independent work produces actual waiting_user.
  • Worker restart moves executing Goals into paused_recoverable; objective, checklist, usage, questions, and checkpoint remain; resume creates a new run.
Implementation assessment: OpenProgram has an independent tool-capable judge, typed states, versioned durable snapshots, asynchronous questions, hard budgets, and explicit post-restart recovery. General deterministic gate execution, automatic external-event wakeup, and an independent evidence repository remain unimplemented. OS file locks provide exclusive ownership for multiple workers on one machine.

Codex

Goal is a durable thread-level control entity; the working agent declares completion or blocking through tools.

Native Goal · Open source
EntryUI/API + create_goal
State ownerSQLite ThreadGoal
Completionagent self-report tool
ResumeIdle-lifecycle recovery
create/setValidate objective and optional token budget; only one unfinished Goal per thread
persistwrites goal_id, status, usage, and time fields
start turnInject continuation steering when the Goal is active and the thread idle
workAn ordinary Codex turn uses existing tools, plans, and context
accountAt turn completion, accumulate tokens and elapsed seconds relative to the baseline
declareThe agent may only call update_goal(complete|blocked)
idle againContinue while active; external controls may pause/resume/clear

Separate data and permissions

  • ThreadGoal is a typed record:thread_id, goal_id, objective, status, token budget, tokens used, time used, created/updated.
  • Status is active, paused, blocked, usage_limited, budget_limited, or complete.
  • Model tools may only create, read, or set complete/blocked; user/system controls pause, resume, and budget/usage limited.
  • External app-server provides thread/goal/set|get|clear and updated/cleared notifications.

Concurrency and completion semantics

  • Goal mutation and idle continuation share a semaphore; writes use expected_goal_id to prevent an old turn from updating a new Goal.
  • Resume reads the durable Goal and registers idle continuation again only when active.
  • The continuation prompt contains the completion audit; the same worker uses actual evidence to decide whether to call update_goal, without independent model review.
  • Blocked requires the same blocker in at least 3 consecutive Goal turns; token exhaustion moves to budget_limited through system control.
Implementation assessment: Codex has first-class state, permission boundaries, CAS-style updates, resource accounting, and resume. Its risk is that the executor also judges completion, largely relying on prompt constraints and disciplined tool use. It accumulates elapsed time but currently has neither a time budget nor a dedicated external-process wait state.

Claude Code

/goal is a session-scoped prompt-evaluator configuration on the general Stop-hook mechanism.

Native Goal · Official runtime contract
Entry/goal <condition>
State ownersession-scoped condition
Completionsmall fast model
ResumeRestore condition; reset metering baselines
setOne condition per session; a new value replaces the old one and immediately starts a turn
workOrdinary Claude Code turn; Goal does not change permission mode
Stop eventThe session-scoped prompt hook triggers when the main agent is about to finish
deferSkip the evaluator this turn if a background task is still running
evaluateSend condition + conversation to a small fast model without tool access
verdictnot met / met / impossible, each with a reason
continue/clearnot met supplies its reason to the next turn; the other two clear the active Goal

Reuses the Hook protocol

  • An ordinary Stop hook may return decision:"block" and reason; the reason enters Claude's next-turn context.
  • A prompt hook may return model-generated ok, reason, impossible./goal adds condition, status display, and recovery to this general mechanism.
  • stop_hook_active prevents unconditional recursion by extension scripts; the runtime forces termination after 8 consecutive Stop-hook stop prevention events.
  • The Goal evaluator only sees evidence already in the conversation; it does not read files or run tests.

Waiting, errors, and budgets

  • Do not evaluate while background shells/subagents run; completion results trigger new turns. Long waits use backoff check-ins, with at most 3 automatic idle check-ins between user inputs in interactive sessions.
  • Several consecutive turns without tool progress stop automatic looping but retain the Goal for evaluation after the next user prompt.
  • Unrecoverable auth, balance, uncompactable context overflow, or model-unavailability errors clear the Goal; transient errors retain it.
  • Goal has no independent typed budget; turn/time termination conditions can be included in the condition. Outer print mode separately provides --max-turns and --max-budget-usd.
Implementation assessment: Claude Code demonstrates that Goal can specialize a general stop interceptor without a separate executor. Its background-work defer/check-in handling is complete, but the tool-free evaluator relies on the worker placing verification evidence in the transcript.

Hermes Agent

GoalManager Unifies free-text objectives, structured completion contracts, deterministic gates, and asynchronous waits at turn boundaries.

Native Goal · Open source
Entry/goal / /subgoal
State ownerGoalState in SessionDB
Completiongate → auxiliary judge
Resumesession resume + wait release
set/draftFree text or completion contract; subgoals may be appended
workUse ordinary run_conversation to complete a turn
gateRun shell quality gates with timeout/retry first
judgeAn auxiliary model returns done/blocked/continue/wait
waitMay bind PID, process session, or deadline; waiting consumes no Goal turns
enqueueQueue continue as an ordinary user-role message in CLI/gateway
persistWrite on every transition: state_meta[goal:session]

Completion contract and gates

  • GoalContract stores outcome, verification, constraints, boundaries, and stop_when separately and injects them into both worker and judge prompts.
  • GoalGate runs before the LLM judge; failures skip judgment, bound the output tail, and provide failure evidence as continuation.
  • Gates record attempts, exit code, output tail, and workspace fingerprint; reuse failed results when the workspace is unchanged to avoid repeating identical checks.
  • A subgoal is an additional user-specified acceptance condition; it neither restarts the main Goal nor resets the original objective.

State, waiting, and adapters

  • GoalState stores status, turn budget, judge-failure counters, subgoals, wait barrier, contract, and gates.
  • The judge returns done, blocked, continue, or wait; wait may specify PID, process session, or seconds.
  • CLI and gateway share GoalManagerbut separately queue continuation in their existing message queues, without changing system prompts or toolsets.
  • Goal state restores on session resume; when context compression rotates session ids, migrate the Goal and remove its old record.
Implementation assessment: Hermes separates verifiable completion from unfinished external work. Deterministic gates handle verification results, the judge handles open-ended semantics, and wait barriers handle asynchronous dependencies. The default remains one Goal per session with a turn budget; total token/cost budgets are not part of the confirmed GoalState contract.

Adjacent implementations without native Goals

These systems provide some Goal components but lack the complete contract in which one open-ended completion condition controls multiple turns until independently judged complete.

OpenCode

Durable Todo + single-turn agent loop; Todo records progress rather than terminating the loop.

Adjacent mechanism · Open source
Task sourcelatest user message
Progress stateSQLite Todo rows
Loop stopprovider finish reason
Boundagent.steps

Implementation

  • SessionPrompt.run The loop reads latest messages and exits when the assistant has a non-tool-call finish reason with no unhandled tool calls.
  • Each round resolves the agent profile and tools, handles compaction/subtasks, then invokes the provider.agent.steps Unlimited by default; the last step injects a max-steps hint into model messages.
  • Plan is a primary agent profile that mainly prohibits edits through permissions while allowing specific plan files; it is not Goal state.

Todo boundaries

  • Todo items contain only content, status, and priority; stored in SQLite by session ID, with publication of todo.updated.
  • todowrite replaces the entire list each time; UI shows completed/total; disabled for subagents by default.
  • Whether all Todo items are completed does not affect SessionPrompt.run the exit decision or automatically start a new turn after session idle.
  • It can therefore serve as a Goal progress projection, but not independently as its controller.

OpenClaw

Models durable work as schedulers, background tasks, heartbeats, standing instructions, and commitments rather than providing a general Goal evaluator.

Adjacent mechanism · Open source
Persistent intentautomation / standing order
Wake ownerGateway scheduler
Executionagent turn / command / script
Completionper-run outcome

Scheduling and state

  • Automation jobs store id, name, enabled, schedule, session target, wake mode, typed payload, delivery, failure alert, and run state.
  • Payloads include system event, agent turn, command, and script; session targets may be main, current, isolated, or named sessions.
  • Run results distinguish execution from delivery; jobs, run state, and history persist, and scheduling continues after gateway restart.
  • Scripts and commands can use exit codes for deterministic success, but that judges one run rather than an open-ended objective.

Heartbeat and commitment

  • Heartbeat is a system-owned monitor automation; it reads scratch or HEARTBEAT.mdand skips model calls when nothing is due.
  • Structured heartbeat tasks contain only name, interval, and prompt and enter subsequent monitor turns on their own schedules.
  • Commitments record agent promises or follow-ups inferred from user context, with due window, confidence, status, attempts, and delivery scope.
  • These mechanisms determine when to run or notify again but provide no met/unmet evaluator and do not constrain multiple runs to one completion condition.
Implementation assessment: OpenClaw is most useful as a reference for external Goal waiting and scheduling. Calling it Goal directly loses completion semantics. A better combination is for a Goal controller to create/bind automation when future time or an external event is needed, then resume the Goal on the event.

Independent judgment and compatibility constraints for Python Workflow

The independent work/judge contract below applies only to Python Workflow. Chat uses the design above: no judge during ordinary work turns, with independent acceptance only on a completion candidate.

Already adopted

Codex control-plane data model

Current snapshots already have stable goal_id, a separate per-execution run_id, typed status, budget/usage, time fields, and CAS version. User controls handle pause/resume/edit/answer/limit/clear; the judge only proposes candidate verdicts.

Adopt directly

Hermes three-stage judgment

The completion contract explicitly defines outcome/verification/constraints/boundaries/stop_when. Deterministic gates run first; semantic judgment runs only after they pass. Asynchronous dependencies enter a wait barrier instead of repeatedly starting work turns.

Adopt directly

Claude Code background-task deferral

If background tasks remain when a work turn ends, neither accept completion nor immediately continue. Completion events resume work; long waits use bounded backoff check-ins and supply the controller with the running-task list.

Already retained

OpenProgram tool-capable judge

An independent judge uses read-only inspection tools to verify files and command results directly and returns typed verdicts. The deterministic gate executor remains future work.

Use in combination

OpenCode Todo as progress projection

Goal checklists should have independent typed-item tables and events for stable UI display. Completed checklist status is only evidence, not equivalent to overall Goal completion, and UI state must not drive the controller.

Combine as needed

OpenClaw scheduling as wait adapter

Future times, CI, external events, and background jobs should not consume Goal turns. GoalRun stores wait handles; scheduler/task subsystems wake it; the controller re-evaluates or continues on the event.

Not adopted

Relying only on worker completion declarations

Codex self-report suits a low-cost general control plane, but OpenProgram already has an independent judge and should not regress to relying only on update_goal(complete). That tool may signal a candidate, while evaluator/controller commits final state.

Current boundary

Versioned session snapshot

extra_meta.goal Schema version, entity IDs, CAS writes, and migration reads already support the current single-session controller. This is not an append-only evidence repository; separate storage is needed only when audit-grade evidence history is required.

Not adopted

Naming Todo, Plan, or Cron as Goal

These address decomposition, change permissions, and timed triggers respectively, without the full semantics of completion conditions + judgment + automatic continuation. APIs and UI should retain those distinctions.

Compatible Python Workflow contract and remaining extensions

Independent judges, role configuration, and recovery checkpoints in this section belong to Python Workflow. Chat entry points share state storage and budget controls but do not invoke this controller.

Goal adds no second agent loop. The controller sits above existing session/dispatcher code, and work still executes through public agent() ; in the diagram, implemented denotes current code, andtarget denotes unimplemented extensions.

OpenProgram Goal: current controller and remaining extensions Architecture diagram generated by Archify. Goal entry · Programs / API / /goal · Architecture components Goal entry Programs / API / /goal GoalSpec · objective · contract · scope · Architecture components · target GoalSpec objective · contract · scope target GoalController · Sole state-transition owner · Architecture components · target GoalController Sole state-transition owner target Working agent · agent() / turn dispatcher · Architecture components Working agent agent() / turn dispatcher Deterministic gates · tests · commands · typed checks · Architecture components · target Deterministic gates tests · commands · typed checks target GoalEvaluator · inspection judge + evidence refs · Architecture components GoalEvaluator inspection judge + evidence refs Terminal state · achieved · blocked · failed · Architecture components Terminal state achieved · blocked · failed Async question queue · pending · answered · dependency · Architecture components · implemented Async question queue pending · answered · dependency implemented External wake adapter · job · timer · event · Architecture components · target External wake adapter job · timer · event target Session Goal snapshot · version · checkpoint · usage · Architecture components · implemented Session Goal snapshot version · checkpoint · usage implemented Goal projection · UI · goal.updated · Architecture components Goal projection UI · goal.updated create / resume / clear completion contract start one work turn new evidence verified results typed verdict + evidence refs needs_user + can_continue answer / safe continuation accepted terminal verdict CAS version + usage matching external event versioned projection Legend Frontend Backend Database Security Message bus External systems
Archify architecture · Showcase structure validation 9/9, 0 errors, 0 warnings. Zoomable SVG is embedded directly; typed source is stored beside this document. Purple dashed lines indicate waiting and recovery paths.
  1. Spec and run share a versioned snapshot.goal_id remains stable across resume, whilerun_id identifies one execution. Editing creates a new revision and refines the spec/checklist again. Refinement only restates user requirements and necessary correctness checks, preserving approximate constraints such as “about” without adding format ratios, benchmark names, numeric thresholds, or reference-work comparisons. Significant ambiguity remains a pending question.
  2. Stop policy checks accumulated budgets at phase boundaries.Rounds, tokens, active elapsed time, and cost accumulate across resume; waiting and pause consume no active-time budget. Work turns default to 300 seconds, and silent provider streams remain subject to the whole-call deadline; cumulative budgets are not precise preemptive limits on the current phase.
  3. The controller commits state transitions.Each phase saves a checkpoint; pause/edit/answer/cancel compete with old controllers through CAS versions, preventing stale execution from overwriting new state.
  4. The evaluator is an independent inspection agent.It returns met, unmet, blocked, impossible, waiting_external, needs_user, and can_continue. Besides local inspection it provides web_fetch, web_searchwith existing URL and network-permission checks; web-tool failures propagate as structured is_error receipts. If a judgment includes a failed tool-inspection receipt, the controller rejects metand re-evaluates first; persistent failure reports judge failure. This conservatively requires one acceptance evaluation free of inspection errors; successful receipts alone do not prove all semantic requirements. The general deterministic gate executor remains unimplemented.
  5. The asynchronous question queue does not block unrelated work.Questions accumulate and can be answered individually. Active execution consumes answers at the next boundary and enters the following state only when all remaining work requires answers: waiting_user. Questions occupy only the Goal detail panel without replacing or disabling the ordinary composer.
  6. Restart recovery uses an explicit new execution.Startup reconciliation converts leftover execution state to paused_recoverable; recovery reuses the snapshot rather than resurrecting an old call stack.
  7. External scheduling is a target extension.waiting_external State exists, but automatic job/timer/event wake handles are not implemented. Goal controllers sharing a session store on one machine use a separate OS file lock; startup recovery takes the same lock to avoid rewriting live siblings.
View the complete objective-state transition table
StateEntered byPermitted exitsAutomatic execution?Description
active / running / evaluatingcreate/resume; controllerwaiting_user / waiting_external / paused / blocked / impossible / stalled / achieved / budget_exhausted / failed / cancelledYesOne controller starts work turns and judgment sequentially and saves state at every boundary.
waiting_userevaluator/controllerAny new answer triggers resume, or edit/cancelNoOnly means all remaining work requires answers; partial answers may release some dependencies while other questions remain.
waiting_externalevaluatorExplicit resume / edit / cancelNoNo automatic wake handle currently exists; the user resumes after external dependencies change.
paused / paused_recoverableUser / startup reconciliationresume / edit / cancelNoPreserve budget, questions, checklist, and checkpoint; waiting time is excluded from active time.
blockedevaluatorResume after dependency changes, edit, or cancelNoNot success; reason records the current blocking facts.
impossibleevaluatorRead-only terminal state; may create a new GoalNoThe current objective and fixed constraints cannot both be satisfied.
stalledcontrollerresume / edit / cancelNoConsecutive checklist non-growth or tool-free work reaches the threshold.
achievedController accepts evaluator resultRead-only; new objectives create a new runNoSave evidence refs, gate results, and final usage.
budget_exhausted / failedcontroller / runtimeResume after adjusting budget, or edit/cancelNoBudget exhaustion is recorded separately from execution/judgment errors.

Goal controls and Workflow compatibility fields

Starting and resuming in Web/TUI both submit ordinary chat. Role fields below apply only to compatible Workflow records; chat Goals hide role configuration and use the current session model.

The bottom Goal status bar opens details rather than acting as a static label. After page reload or worker restart, it restores objective text, status, checklist, usage, and last reason from durable projection. If the previous execution was lost, it shows paused_recoverableinstead of appearing to still run.

Consistent Goal interaction in Web and TUI Workflow diagram generated by Archify. 01 / Web 02 / TUI 03 / Shared Goal Actions 04 / Durable State Bottom Goal status bar · State · progress · usage · Web Bottom Goal status bar State · progress · usage Goal detail panel · prompt · checklist · question queue · Web Goal detail panel prompt · checklist · question queue /goal status · Complete state and reason · TUI /goal status Complete state and reason /goal action · edit · answer · resume · clear · TUI /goal action edit · answer · resume · clear Goal Action API · Shared validation and error contract · Shared Goal Actions Goal Action API Shared validation and error contract Versioned transition · expected_version · lease · Shared Goal Actions Versioned transition expected_version · lease Goal Snapshot · checkpoint + question queue · Durable State Goal Snapshot checkpoint + question queue Goal Projection · hydrate + goal_update · Durable State Goal Projection hydrate + goal_update validate click / keyboard typed action reload / live update committed state atomic save same action Legend User interface Agent logic Policy Tool operations Context / tracing
Web panels and TUI commands call the versioned Goal Action API; the interface does not duplicate state transitions, concurrency checks, or recovery rules.
Web · Composer Goal PanelInteraction design
◎ Goal · Paused after restart · 4/9
Research and complete a survey of large-model knowledgegoal_7f2a · run 2 · version 18
StateRecoverable pause: worker restart interrupted the previous turn
Progress4 / 9 checklist · 7 rounds · 38k tokens
Recent evidence12 sources added; method-classification gate passed
Recovery pointCreate a new execution from saved spec, checklist, and session evidence
Pending questions2 items; answer individually later without affecting independent source verification
ContinueEdit objectiveAdjust budgetTermination
TUI · /goalSame contract
$ /goal status
Goal [paused_recoverable]
  Research and complete a survey of large-model knowledge
  progress  4/9
  usage     7 rounds · 38k tokens
  reason    worker restarted during round 8

$ /goal resume
Goal resumed as execution goal-exec-02.

$ /goal edit Narrow scope to knowledge editing and continual learning
Goal revision 3 saved; prior evidence retained.

$ /goal pause
Goal paused.

$ /goal
  pending questions: 2
  [?] scope: Include knowledge editing?
  [?] date: What is the literature cutoff date?

$ /goal answer scope Include it
Goal answer saved; resuming from the latest checkpoint.
Editing a Goal increments revision and regenerates the current spec/checklist; old unanswered questions remain as superseded audit records and no longer block the new revision. Continue retains goal_id, cumulative usage, and question history while creating a new run_id. Pause, waiting, and restart recovery do not reset consumed budgets; waiting is excluded from active-time limits.

Implementation and acceptance contract

Independent specification review requires two contracts: genuine human dependencies enter waiting without being overridden by ordinary no-progress counters; successful Web actions immediately update visible state and shared cache from HTTP snapshots, and old events cannot roll back newer state. Repairs stay within Goal transitions and frontend projections without changing other workflows. Acceptance uses public Goal → answer-command regression plus action-response/remount tests without WebSocket broadcasts. The original reviewer must re-review repairs before independent quality review.

Genuine human dependencies are not overridden by no-progress counters; budget checks remain independent. The frontend uses shared updateSessionGoal to apply HTTP, WebSocket, and hydration snapshots by session version. Four component tests cover pause without broadcasts, remounting, out-of-order messages, background sessions, and late loading. All 229 Web tests, TypeScript, static checks, and the 32-page production build passed; independent specification re-reviews passed for waiting-state and frontend repairs. The build retains an existing Next SWC lockfile-repair warning; dependency lockfiles were unchanged.

Controller saves use CAS. Concurrent updates within the same run merge the latest confirmed snapshot, current-round state, and latest disk state under the session write lock, without unbounded retries. Merging permits only the same goal_id/run_id while the latest state is still executing; preserve budgets, new answers, current progress, and consumed answers. Pause, cancel, or run replacement still rejects stale-controller writes. Terminal saves use the same path; new answers invalidate an old terminal decision and save as paused_recoverable / answer_receivedso the user can continue handling them, without falsely reporting achieved. Answers consumed in batches all enter later work prompts. On subsequent resume, rebuild confirmed decisions from durable questions for the current revision and restore a bounded evidence window. Objective edits isolate old-revision decisions and evidence.

Independent quality re-review of the concurrency repair returned PASSand covered the original reproduction where budget edits caused controller exit while the UI still showed running. The reviewer independently passed 9 focused regressions: budget/answer races during evaluating/terminal, pause/cancel/run replacement, new answers during consumption, and old CAS rejection. Integrated Goal, storage, and Web API tests passed; full counts are below. This conclusion is limited to the reviewed repair and does not replace full post-repair verification, unimplemented design capabilities, or default-App visual acceptance.

The following ties requirements to public entry points and observable results. Local source, tests, and independent repair reviews do not imply full acceptance. Final integrated full tests passed, while default-App refresh and visual acceptance are recorded separately. Implementation descriptions below refer only to existing worktree code, not publication or fulfillment of every requirement.

RequirementPublic entry / evidenceObservable resultCurrent status
Single-prompt Goal with separate work and judgmentgoal(prompt, ...); judge_goal()Working Agent executes; inspection judge independently verifies and returns a typed verdictImplemented with unit coverage
Difficult tasks do not continue indefinitelyround/token/active-time/cost budget; active-run usage cursor; stall and judge-failure guardsEnter respectively budget_exhausted, stalled, failed, blocked or impossible; other sessions' usage during waiting is excluded from the GoalImplemented with boundary tests
Unattended operation continues independent work without interruptionJudge's needs_user + can_continue; durable questions[]Questions accumulate; answer-dependent work does not execute; safe independent work continues; waiting starts only when all work is blockedImplemented with queue and continuation tests
Asynchronous answers and concurrency safetyGoal Action API; SessionStore CAS versionActive runs consume answers at boundaries; partial answers release some work; user pause persists; old controllers cannot overwrite new stateImplemented with race-path tests
Recovery after reload and worker restartsession hydration; startup reconciliation; /goal resumeReload restores the complete projection; restart-interrupted state becomes paused_recoverable; resume creates a new runComponent tests passed; default App verified restart-recovery state, edit/reload, and actual Resume execution
Consistent Web and TUI controlsGoal dialog; /goal commands; the same Action APIInspect objective, checklist, usage, and questions; edit, pause, answer, adjust budget, continue, and terminateType checks and automated tests passed; default App verified editing, budget, pause, resume, and completion judgment; the full asynchronous-answer interface flow is not yet accepted
Automatic external-event wakeupTarget: durable wait handle + scheduler eventIdempotent recovery after CI/job/timer completion without user resumeNot implemented
Multi-worker ownership of a shared state directoryownership.goal_owner(); independent nonblocking OS file lockExclusive controller per same-machine store; startup reconciliation skips live siblings; crashes release the lockCross-process and abnormal-exit tests cover this; no cross-host distributed lease
Deterministic gates and independent evidence repositoryTarget: gate runner + evidence refs/repositoryReusable command checks precede the judge; complete evidence does not depend on session snapshotsNot implemented
Current verification commands
  • python -m pytest tests/unit/agent/workflows/test_goal_loop.py tests/unit/agent/workflows/test_goal_functions.py tests/unit/agent/workflows/test_agentic_programming_goal.py tests/unit/agent/workflows/test_goal_single_workflow.py tests/component/webui/execution/test_goal_command_workflow.py -q
  • cd apps/web && npx tsc --noEmit
  • python -m scripts.docs_site.build, followed by python -m scripts.docs_site.checklinks

Web verification: the judge has web-reading and search tools; failed receipts are marked is_error=true. Existing real-model checks were limited by arXiv's NON_GLOBAL_ADDRESS rejection and missing Tavily credentials. Network policy was not bypassed, and that research output cannot be treated as a source-verified survey.

Integrated code ran python -m pytest -q -n 4: 7015 passed, 18 skipped, 1 expected failure, including paused-execution identity and in-Runtime inspection fixes. The full run exposed and fixed Goal wrapper source-location problems; execution databases for two agent-contract suites were isolated per test so startup recovery would not read other tests' records. TUI tests: 148 passed, 2 skipped; type checks passed. Actual default-App evidence is recorded separately from automated tests.

Real-model verification: through the public programs run goal entry point, MiniMax-M3 wrote an approximately 300-character Chinese article, read the file for verification, and judged it; the command exited normally and the artifact was independently read and checked. This example used supplied facts without networking and cannot replace source verification. The earlier survey attempt remained limited by source access and search credentials and still cannot be delivered as a verified survey. Failed-receipt protection blocks metwhen inspection receipts contain errors, but does not prove all semantic judgments reliable.

The default App verified restart-recovery state, edit/save, reload, budget change, pause, and resume for a test Goal. Pause moved the corresponding canonical execution into cancellingand then stopped it as cancelled / cancel.user while the Goal remained recoverably paused. After resuming, judgment first rejected excess output and then accepted corrected output; the final Goal showed achieved, checklist 4/4, and 0 judgment-parse errors. This is actual acceptance for a short-text task, not verification of external research or every task type.

Within an existing Runtime, Goal refiner/judge use public agent(): each retains its tools, model, and phase label while sharing the current execution owner and creating no separate Job, avoiding global startup recovery on initial JobRunner creation misclassifying the outer live execution. Standalone session helpers without Runtime retain their original path. This local repair does not resolve other processes invoking global recovery. Execution-tree summaries still have a field-mapping defect: persisted LLM replies reside in raw_replybut summaries read output; empty input parameters do not imply lost responses. A separate display inconsistency shows Completed on a function-result row while canonical execution is cancelled; that summary label cannot prove successful execution.

Completion acceptance also found that generic execution-end recording did not consistently converge: the Goal was achievedbut repeated completed-write retries for its canonical execution left finish_repair_stalledand state remained running. This unresolved issue does not invalidate generated work or Goal judgment, but prevents claiming full execution-lifecycle acceptance.

Implementation status and evidence boundaries

Chat Goals use existing ordinary chat execution and durable completion notifications for continuation; display projections do not rewrite run intent. There are no default round or recovery-expiry limits, while explicit user limits remain. Shared history pairing, unknown-effect approval, durable deduplicated new turns, restricted Resume, incompatible-checkpoint handling, background Job continuation with original resource authorization, independent read-only completion acceptance, durable request attribution, late/partially unknown usage, concurrent hard-budget reservations, and joint settlement passed independent specification and quality reviews. Unified backend action conditions, explicit Verify, exact execution checks, crash-time lower bounds, and related-background-work completion restrictions also passed review. Complete Python, Web, CLI, Desktop, documentation checks and browser regressions after an independent build passed; skipped tests do not prove capabilities. Isolated-process interruption matrices for ordinary chat and Goals and macOS live-background-process reconnection have actual process evidence. This does not extend to Windows process survival, OS restart, cross-host takeover, or general external-event scheduling. Installed version, default-App visual acceptance, and remote commits require separate checks against the implementation ledger and actual source markers; source tests do not prove the local App was updated.

Evidence boundaries: unknown outcomes always remain in effect records; new side effects require one-time approval for the current operation, and ordinary chat recovery never reruns old tool calls. All Todo complete produces only an acceptance candidate. Independent ordinary chat checks actual reads or session evidence against the original objective and fixed requirements; before commit, recheck control version, evidence digest, related background processes, and execution state. The same inspected plan is not automatically accepted repeatedly. Request statistics retain Goal/revision/execution identity and prices; the durable ledger restores cumulative usage watermarks, child attribution, reservations, and joint settlement. Missing receipts remain unknown; old session statistics are not inferred into new attribution. Sudden executor loss counts only verifiable duration lower bounds and excludes downtime. Completion acceptance remains evidence-constrained model judgment, not a guarantee of absolute correctness.

Compatibility-path records, not evidence for the new design

  • Python Workflow work/refine/judge controllers and budget policies remain.
  • Versioned Goal snapshots, goal/run ID, CAS writes, and legacy reads exist.
  • Web/TUI controls and restart-pause state exist, with the recovery gaps described above.
  • Existing detailed diagrams remain as compatibility references and do not establish that chat uses a separate Workflow.

Extensions outside this design

  • Cross-host distributed execution leases, a general workflow engine, and an independent audit repository.
  • Automatic bulk rewriting of historical Goal costs or tool effects.
  • Exactly-once execution guarantees for arbitrary non-idempotent external operations.
  • Rerunning Python Workflow's independent judge on every ordinary chat turn.
Version boundaries:Local reference repositories provide reproducible code paths; official online documentation and public main branches establish later contracts. The local Hermes snapshot's basic GoalManager lacks upstream completion contracts, quality gates, and wait barriers, so those sections rely on public upstream source. Claude Code relies on official documentation.

Goal completion presentation

A terminal historical Goal stays at its existing conversation anchor as a compact, clickable status row. A successful Goal shows an animated Lucide check icon and Goal achieved in 9m 42s using that Goal's active elapsed time. Missing time does not become zero; interrupted time retains its lower-bound label. Other terminal states keep their actual status and never appear successful. The row opens the existing read-only historical Goal details. Canonical completion, acceptance and accounting remain authoritative; presentation does not infer completion from the assistant text or Todo counts.

Implementation status

The compact completion row uses recorded Goal status and active duration and opens the original read-only details. Component and browser checks cover this presentation; installed-App acceptance is part of the release verification record.

A new interactive owner turn in Auto or bypass evaluates uncertain effects only in its current execution subtree. A nested Runtime uses this same boundary only when immutable admission proves a chat from that owner: the stored actor is interactive owner, the integrity-checked chat payload has the same source, and current execution, session and principal match. Executor-thread submission carries the existing ContextVars so scope capture checks the same current execution before spawning. Runtime stays non-interactive and cannot grant approval. Missing or mismatched evidence retains the existing restriction; unreadable or corrupt recovery state fails closed. Unknown effects in the current subtree still require exact one-time approval. Old receipts are never resolved or replayed by this filter. Explicit ask/deny, source constraints, plan mode and exact Page binding continue to apply.

Acceptance: reproduce an old interrupted effect followed by a new owner activation through permission_decision and real nested Runtime gates; check Auto classification and bypass, exact current/descendant uncertainty, mismatched provenance, rules, and real subprocess Page access. The nested-scope correction is implemented. Independent specification and quality reviews, actual subprocess Page access, browser components, and the final combined verification pass. Skipped environment-dependent cases do not establish those capabilities. Installed-App acceptance is recorded separately in release evidence.