CLS stands for Closed-Loop System. Nova uses it to treat browser actions as verifiable state transitions: an action is not reliable just because a click, input, or submit was dispatched.
CLS belongs to moments where an agent changes page state. Nova can check preconditions, dispatch the action, observe the result, and report whether the expected postcondition was confirmed, contradicted, or still unclear.
This prevents false success. If the page confirms the intended result, the agent can continue from the new state. If the page shows an error, remains ambiguous, or the action never reached the page, the next step should repair, observe again, or stop safely.
CLS connects execution with memory. TOB supplies observed evidence, OK supplies current service facts, PKS can learn from verified successes and failures, and ETM can use the result when deciding whether a task run is really complete.
In short
- Dispatch is not proof that a browser action succeeded.
- Commit-point actions need preconditions and postconditions when they can send, submit, log in, switch state, or otherwise change a service.
- CLS separates pre-dispatch blocks from post-dispatch uncertainty so agents do not repeat dangerous actions blindly.
- Verified outcomes can feed task progress, PKS health, ALP review, and later guidance.
- CLS does not grant permission by itself; Nova safety gates and user control still apply.
What CLS verifies
CLS checks the parts of an action that are easy to confuse when an agent only sees tool success.
- Preconditions Before dispatch, the current page must still match the expected starting state. If the precondition fails, the action should not run.
- Dispatch Nova reports whether the action actually reached the page. A pre-dispatch block is different from a click that fired but did not produce the expected result.
- Postconditions After dispatch, Nova checks success, forbidden, and ambiguous signals. This is where “sent” becomes “confirmed”, “failed”, or “unclear”.
- Retry safety CLS tells the agent whether it may retry, must not retry, or should check the postcondition first because a repeat could duplicate the action.
- Goal resume When a closed-loop goal is active, Nova can expose the current step so an agent can resume after context compression without guessing where it left off.
- Learning feedback Verified outcomes provide stronger evidence for task completion, PKS health, and later learning than a raw tool success.
When this matters
Use CLS for actions where the result changes state and a blind retry would be risky: sending a message, submitting a form, confirming a login, changing a model or workspace, dismissing an overlay that controls access, or closing a task step that should only count after visible proof.
CLS model for agents
For an agent, CLS answers four questions: what goal is active, what pre-action state must hold, what result proves success or failure, and what should happen if the result is unclear?
- Goal
- A durable work objective on a target. It can contain ordered steps and appears as
goalContextwhen active. - Step
- One action inside a goal. A step can be planned, dispatched, verifying, done, ambiguous, failed, blocked, or aborted.
- Transition contract
- The structured agreement for one meaningful action: preconditions, action kind, postconditions, retry policy, and ambiguity policy.
- Assertion
- A machine-checkable condition such as a fact existing, matching a value, changing, or becoming absent. Assertions can be grouped as all, any, or forbidden.
- Guarded commit
- The result object that tells the agent what CLS did: dispatch status, verification status, retry advice, failed assertions, and timing.
- Action dispatch
- The point where the page was actually touched. If
actionDispatchedis true, a retry may duplicate a submit, send, or state change. - Postcondition-first retry
- A recovery rule for non-idempotent actions: inspect the result first, then decide whether another dispatch is safe.
How agents use CLS information
CLS gives agents a verification loop around actions that matter. The agent should read the page, bind or resume the goal, use a guarded action, and then let the returned state decide the next move.
-
Read the page and goal context
The agent starts with
nova.perceive. IfgoalContextis present, it reads the active step before acting. -
Create or query a goal when work spans steps
For multi-step work,
nova.goal_registercan create, query, close, or annotate the active closed-loop goal. -
Use a guarded commit tool for meaningful actions
For common commit points, the agent prefers
nova.guarded_send_message,nova.guarded_submit_form,nova.guarded_login,nova.guarded_switch_model, ornova.guarded_switch_sandbox. -
Provide a transition contract when using raw input tools
If the agent uses
nova.click_selectorornova.type_selectorfor a commit point, it suppliestransitionContractwith preconditions and postconditions. -
Read dispatch and verification separately
The agent checks
actionDispatched,guardedCommit.dispatchStatus,guardedCommit.verificationStatus, andguardedCommit.retryAdvice. - Continue only from verified state Verified success can advance. Verified failure, a blocked precondition, or an indeterminate result should trigger repair, another observation, or a safe stop.
When CLS state applies
CLS state is trustworthy only inside the current target and action context. A previous result is not permission to assume the page still looks the same after navigation, reload, user interaction, or another agent action.
goalContext=null
- Meaning
- Nova has no active closed-loop goal for the current target or owner.
- Evidence required
- No
goalContextappears in the page read. Goal queries can still show terminal or stale states such ascompleted,failed,abortedororphaned. - Agent behavior
- Use normal page observation, or create a goal if the work needs durable step tracking.
- May continue
- Only for simple actions.
goalContext.state=active
- Meaning
- A closed-loop goal is active and can be resumed.
- Evidence required
- A current
goalId,summary,currentStep, and optionalstepStatusare visible to the agent. - Agent behavior
- Continue from the current step, not from memory or a guessed plan.
- May continue
- Yes, after checking the page.
blocked_precondition
- Meaning
- The action did not dispatch because the expected start state did not hold.
- Evidence required
- The response has
actionDispatched=falseandguardedCommit.preconditionVerdict=failedor a matching reason code. - Agent behavior
- Repair the page state or update the contract. Do not claim the action happened.
- May continue
- No.
actionDispatched=true
- Meaning
- The action reached the page. The result still needs postcondition interpretation.
- Evidence required
- The response says
actionDispatched=true, possibly withguardedCommit.verificationStatus. - Agent behavior
- Do not blindly repeat non-idempotent sends, submits, or login commits.
- May continue
- Only after verification.
verified_success
- Meaning
- Observed page or service state satisfies the success postcondition.
- Evidence required
- The guarded result returns
guardedCommit.verificationStatus=verified_success. - Agent behavior
- Advance the goal step, continue the task, and let learning systems use the result as stronger evidence.
- May continue
- Yes.
verified_fail
- Meaning
- A forbidden or failed outcome was observed after dispatch.
- Evidence required
- The guarded result returns
verified_failor top-levelreasonCode=guarded_commit.postcondition_failed. - Agent behavior
- Treat the step as failed and repair from the visible error state.
- May continue
- No.
indeterminate
- Meaning
- Nova could not prove success or failure from the available signals.
- Evidence required
- The result includes
indeterminateReasonsuch asambiguous_signal,page_navigated,timeout, oreval_error. - Agent behavior
- Follow
retryAdvice. For non-idempotent actions, check the postcondition before any retry. - May continue
- Not yet.
blocked_goal|blocked_coordinator
- Meaning
- The target or goal is already reserved, mismatched, or not in a dispatchable state.
- Evidence required
- Dispatch status or reason code shows
blocked_goal,blocked_coordinator,guarded_commit.coordinator_busy, orguarded_commit.dispatch_prepare_rejected. - Agent behavior
- Wait, query the goal, or re-check postconditions before retrying.
- May continue
- No.
Failure and guard conditions
These are the hard edges an agent or integration should expect from CLS contracts.
| Condition | Observed signal | Agent behavior |
|---|---|---|
| Commit point without contract | A raw click or submit-like typing action is classified as a commit point and lacks transitionContract; the reason code is guarded_commit.missing_contract. |
Use a guarded macro or provide transitionContract.postconditions. The action is blocked before dispatch. |
| Unknown contract field | Unknown fields inside transitionContract, postconditions or assertion sets produce invalid params. |
Fix the request shape instead of assuming extra fields are ignored. |
| Empty postconditions | Commit-point contracts without non-empty success, forbidden or ambiguous buckets fail closed. |
Define at least one observable result condition before dispatch. |
| Precondition failed | Reason code guarded_commit.precondition_failed and actionDispatched=false. |
Repair or re-read the page. Do not retry the action until the starting state is true. |
| Precondition evaluation error | Reason code guarded_commit.precondition_error. |
Treat this as fail-closed. Simplify the assertion or gather a better fact source. |
| Coordinator busy | Reason code guarded_commit.coordinator_busy and often retryAfterMs=1000. |
Wait for the in-flight guarded action to finish before trying again. |
| Postcondition failure | Top-level status can become failed with reasonCode=guarded_commit.postcondition_failed. |
Handle the visible failure; do not report the step as complete. |
| Ambiguous result after dispatch | Top-level status can become partial with reason codes such as guarded_commit.ambiguous_signal, guarded_commit.page_navigated, guarded_commit.frame_destroyed, guarded_commit.eval_error, guarded_commit.no_signal_yet or guarded_commit.timeout. |
Follow retryAdvice and inspect the postcondition before repeating non-idempotent actions. |
Agent interpretation example
The example shows CLS as a contract: the agent states the action goal, Nova verifies the postcondition, and the response tells the agent whether the next step may continue.
Guarded action request
{
"tool": "nova.guarded_send_message",
"arguments": {
"targetId": "active",
"text": "Please summarize the selected article.",
"transitionContract": {
"postconditions": {
"success": {
"any": [
{
"factKey": "chat.streamActive.started",
"operator": "eq",
"expected": true
},
{
"factKey": "chat.assistantTurnCreated",
"operator": "eq",
"expected": true
}
]
}
}
}
}
}
Relevant response fields
{
"structuredContent": {
"ok": true,
"status": "ok",
"actionDispatched": true,
"guardedCommit": {
"dispatchStatus": "dispatched",
"verificationStatus": "verified_success",
"retryAdvice": "do_not_retry",
"outcomeVerdict": "satisfied"
}
}
}
Agent interpretation
{
"treatAs": "verified action outcome",
"mayContinue": true,
"doNotRepeat": "actionDispatched is true and the send is non-idempotent",
"memorySignal": "success can support task progress and future learning"
}
MCP contract
This is the deterministic layer below the explanation. It lists CLS fields that agents and integrators should treat as contract signals rather than free prose.
Execution rule: No commit-point action is complete until its current postcondition is observed or uncertainty is explicitly surfaced.
| Variable | Type / values | Default | Effect |
|---|---|---|---|
goalContext |
object or null on perception responses | null when no active goal applies | Resume anchor for the active closed-loop goal on the current target. |
goalContext.goalId / summary |
string; string | computed | Identifies the current goal and gives the agent a compact human-readable goal anchor. |
goalContext.mode |
agent_driven | runtime_assisted | fully_autonomous | agent_driven on goal create | Indicates how much of the goal is controlled by the agent versus runtime assistance. |
goalContext.state |
active | active when surfaced | Perception surfaces only active goal context for resume. Goal queries can also show terminal states. |
goalContext.currentStep / totalSteps |
integer; integer | computed | Shows where the agent is inside the active step plan. |
goalContext.stepStatus |
planned | ready | blocked | dispatched | verifying | done | ambiguous | failed | aborted | null | null when no step exists | Tells the agent whether the current step is still planned, already dispatched, verifying, finished, or blocked. |
goalContext.stepAction |
string or null | null | Human-readable action description for the current step. |
nova.goal_register |
MCP tool | available in CLS-capable Nova sessions | Creates, queries, closes, or annotates closed-loop goals. |
op |
create | query | close | annotate | required | Selects the goal register operation. |
targetId |
string | create defaults to active; query optional; interaction tools default to active when omitted | Scopes a goal or action to the intended browser tab or sandbox target. |
agentId |
string | optional on guarded action tools | Identifies the calling agent for guarded macros and claim-aware execution. It is agent metadata, not user-visible page state. |
goalId |
string | required for close/annotate and targeted query | Identifies the goal being queried, closed, or annotated. |
summary |
string | required for create | Defines the goal summary that later appears in goalContext. |
mode |
agent_driven | runtime_assisted | fully_autonomous | agent_driven | Defines goal execution style. |
preconditions |
assertion set | optional on goal create | Stores goal-level conditions that should already hold when the goal opens. |
ownerAgentId / sidecarSessionId |
string; string | optional | Binds a goal to an agent owner or sidecar session for safer resume and handoff. When omitted, no owner or session binding is set. |
leaseMs |
integer 1000-600000 | 120000 | Limits how long a goal lease may stay alive without progress. |
steps |
array, max 50 | optional | Defines an ordered step plan for the goal. |
steps[].actionDesc |
string | required for each step | Names a goal step for agent resume and activity tracking. |
steps[].contract |
transitionContract object |
optional | Stores the closed-loop contract for this step. |
includeSteps / includeEvents / eventsLimit |
boolean; boolean; integer 1-200 | true; false; 50 | Controls how much step and event detail a goal query returns. |
state |
completed | failed | aborted | required for close | Closes a goal with a terminal state. |
content / source |
string; string | content required for annotate; source defaults to agent | Adds an annotation event to a goal. |
legacy aliases |
preconditionsJson, steps[].contractJson, ownerAgent, ownerSession, leaseTimeoutMs | accepted for compatibility | Compatibility names for older clients. New integrations should prefer structured fields and must not mix structured and legacy forms. |
transitionContract |
object on click/type/guarded tools | required for detected commit points; auto-generated by guarded macros | Defines preconditions, postconditions, retry policy, ambiguity policy, and stability settings for one state-changing action. |
transitionContract.actionKind |
dismiss_overlay | send_message | submit_form | select_option | custom | custom for raw contracts; macro-specific for guarded tools | Selects action-specific stability defaults. |
transitionContract.preconditions |
assertion set: all / any / forbidden | optional | Conditions that must be evaluated before dispatch. Failed preconditions block the action. |
transitionContract.postconditions.success / forbidden / ambiguous |
assertion sets | at least one non-empty bucket for commit points | Defines which observed outcomes count as success, failure, or ambiguity. |
assertion.factKey / operator / expected / frameId |
string; eq | not_eq | neq | exists | not_exists | contains | gt | lt | gte | lte; JSON; string or null | factKey and operator required | Single machine-checkable condition used inside preconditions or postconditions. |
transitionContract.retryPolicy |
idempotent | non_idempotent | no_retry | non_idempotent | Controls whether a repeat dispatch may be safe. Sends, submits, and logins are usually non-idempotent. |
transitionContract.ambiguityPolicy |
signal | retry_once | abort | signal | Controls how ambiguous postcondition matches influence retry advice. |
transitionContract.stabilityWindowMs / stabilityMs |
integer 500-30000; integer 0-5000 | action template defaults | Optional observation window and hold duration. Runtime clamps values to guarded-safe bounds. |
actionDispatched |
boolean | computed | True only after the page was actually touched. If true, agents must avoid blind duplicate sends/submits. |
guardedCommit.transitionId |
string | generated | Correlates one guarded transition through dispatch and verification. |
guardedCommit.dispatchStatus |
dispatched | blocked_precondition | blocked_goal | blocked_coordinator | computed | Says whether the action dispatched or was blocked before reaching the page. |
guardedCommit.verificationStatus |
verified_success | verified_fail | indeterminate | skipped | pending | computed | Post-action outcome classification. |
guardedCommit.indeterminateReason |
no_signal_yet | ambiguous_signal | page_navigated | frame_destroyed | timeout | eval_error | null | null | Explains why CLS could not prove success or failure. |
guardedCommit.retryAdvice |
safe_to_retry | do_not_retry | check_postcondition_first | computed | Guides recovery after failure or uncertainty. |
guardedCommit.preconditionVerdict / outcomeVerdict |
satisfied | failed | unknown | null | computed | Shows whether the evaluated precondition or postcondition assertion set passed. |
guardedCommit.failedAssertions[] |
factKey, op, expected, observed, passed, error | only when assertions fail or are unknown | Shows which assertion caused a block, failure, or ambiguous result. |
guardedCommit.startedAt / completedAt / durationMs |
integer timestamps; integer duration | computed | Shows when guarded verification started, when it ended, and how long it took. |
stage / verifyState / retryAdvice |
string; verified | likely | uncertain | failed; retry advice string or null | computed when supported by the tool | Compact top-level orientation for where the tool stopped, how strong ad-hoc verification was, and whether recovery needs caution. |
status / reasonCode / retryable / retryAfterMs |
top-level response signals | computed | Compact tool result signals for blocked, partial, failed, or retryable outcomes. |
Agent Tools
MCP tools for agents. These variables and tool names are intended for agents and integrators. They are not normal user controls in the interface.
| Variable | Meaning |
|---|---|
nova.goal_register |
Record a work goal |
nova.guarded_send_message |
Send a message with outcome checks |
nova.guarded_submit_form |
Submit a form with outcome checks |
nova.guarded_switch_model |
Switch model with outcome checks |
nova.guarded_switch_sandbox |
Switch sandbox with outcome checks |
nova.guarded_login |
Run a guarded login flow |
nova.perceive |
Reads the current page and can return the active closed-loop goal context. |
nova.click_selector |
Clicks a selector or CTA reference; commit-point clicks can use a transition contract and return a guarded commit result. |
nova.type_selector |
Types into a selector; submit-style typing can use a transition contract and return a guarded commit result. |