Goals¶
A Goal is one durable objective attached to a session. It keeps the objective in context across ordinary root conversation turns and continues while the session is idle. There is no Goal phase machine: planning, implementation, and review are ordinary model work.
Say "Create a goal for XYZ" in the ordinary root chat to start one. The
model uses CreateGoal, which preserves the full objective and returns its
active status and budget. Ordinary tasks do not implicitly authorize Goal
creation. Explicit user or trusted system/developer instructions do; no separate
Goal confirmation is added. Tool permissions still apply.
GetGoal inspects the current objective, status, reason, budget, known usage,
elapsed time, settled-turn count, and accepted-plan address. It also works for
inactive Goals without resuming them. An absent Goal returns goal: null;
null budget and remaining-token fields mean unbounded. Its usage includes
known usage of the current attributed turn, which can lag provider activity,
and does not change durable accounting.
An invalid accepted-plan address is reported as plan_reference_error, leaving
the Goal inspectable without changing its state.
Browser collaborators of every link tier can inspect the durable Goal from its
own status-strip chip. The read-only sheet shows the objective, status/reason,
budget and durable token/time/turn accounting, with incomplete usage marked as a
lower bound. Unlike GetGoal, this projection does not add the current request's
unaccounted usage; already-accounted child charges are included. Goal
changes remain in Emacs; opening the sheet never resumes work. Diagnostic reasons
from request, runtime, hook, or integrity failures are shown only as a safe public
category to every browser tier. Public model blockers, user pauses and budget
explanations retain their text; native inspection retains concrete diagnostics.
Durable state¶
The session sidecar stores a strict Goal record containing:
- a unique ID and free-form objective;
active,paused,blocked,budget-limited, orcompletestatus plus an optional reason;- token, elapsed-time, and turn accounting;
- an optional token budget, accepted-plan reference, and implementation policy; and
- creation and update timestamps.
An invalid persisted Goal record loads as no Goal. An active Goal loaded from a
saved session is demoted to paused with a session-resumed reason so recovery
cannot dispatch work without an explicit /goal resume.
Diagnostic reason producers set the optional :reason-diagnostic t marker.
Public reason updates clear it, and serialization omits it for public content.
Its absence means public text; existing unmarked reasons are not reclassified.
The required :implementation-policy field is nil for a Goal without an
accepted implementation override. A present policy is the strict serializable
record (:model-provider STRING :reasoning-effort SYMBOL-or-nil
:permission-mode MODE), with an exact BACKEND:MODEL label and canonical
ask, edits, or full-auto mode. No extra or missing fields are accepted.
Older Goal records lacking this field are rejected, not migrated; their
transcripts remain readable, but their Goal state is not restored.
The state controls whether another ordinary turn may start. Pausing ends a
running Goal turn at its next tool boundary: running tools finish and the turn
settles normally, without an abort. A turn waiting in WaitAgent is woken with
a steering note so it reaches that boundary; pending user steering is still
delivered first. Lowering the budget to current usage and editing the objective
end the turn the same way. Runtime failures pause execution; a task-level
impasse is a separate, model-reported blocked state.
stateDiagram-v2
state "budget-limited" as budget_limited
[*] --> active: Start
active --> paused: Pause or runtime failure
active --> blocked: Task impasse
active --> budget_limited: Budget reached
active --> complete: Verified objective achieved
complete --> [*]
The diagram shows how active execution stops. Resume returns paused or blocked Goals to active; a budget-limited Goal requires raising or removing its budget. Loading an active saved Goal pauses it. Lowering a budget to current usage can limit any nonterminal Goal. Clearing removes the record, and a completed Goal cannot be resumed.
Request context and authority¶
Before an active root request, mevedel derives current Goal facts from the
durable record: objective, token budget, turns run, and accepted-plan
reference. Live token usage is left out because it moves with every charge and
each change would re-send the whole block; crossing reminders and GetGoal
report it. Changed facts are delivered as retained context updates, hidden from
ordinary chat presentation but preserved in transcript audit records. Unchanged
facts remain in selected history; loss of that context causes delivery again.
The durable record supplies current authority, not the old observations.
The Goal's session must match the
request's workspace and working directory; stale ambient sessions contribute
no Goal context. Ordinary user messages that start a turn during a Goal receive
the same context and accounting as automatic turns. Same-turn steering instead
joins the already-running Goal turn at its next model interaction boundary and
does not create or charge another turn.
An accepted-plan Goal's implementation policy selects the root turn's backend,
model, reasoning effort, and permission-mode override. Each active ordinary
root turn captures it at admission, whether it comes from user input or
automatic continuation. /goal resume uses the same durable policy. Ordinary
chat while the Goal is paused, blocked, budget-limited, or complete uses the
session baseline; a turn already admitted retains its captured settings until
settlement. If accepted Goal authority changes during asynchronous preparation,
the unsent request is rejected rather than pairing a prepared model with new
permissions or a different Goal. A fresh submission uses the current policy.
Goals created without an implementation policy use ordinary session policy
throughout.
Policy resolution is exact: a missing provider/model or unsupported effort fails visibly and pauses active Goal execution rather than substituting the session model. The implementation selection never changes the session's stored model, effort, permission mode, or new-Goal budget default. No snapshot/restore cycle can overwrite a user change made while implementation runs.
The permission override follows the common permission resolver and is inherited by child implementation turns, including nested delegation. Current hard denies, shared rules, resource grants, and workflow restrictions remain live. Children keep their own model workload policies; unrelated child, summary, control, and directive work does not inherit an ambient root implementation policy. Directive settings remain separately request-local.
/goal edit <objective> revises the live objective and rotates the Goal ID
while retaining status, budget, accounting, accepted-plan reference,
implementation policy, and creation time. The revised objective has highest
authority; an accepted Plan remains binding only where consistent with it. An
already-running turn no longer
sees UpdateGoal and its stale calls are rejected, but that turn is still charged to the
revised Goal through a separate request-local accounting identity. Only edit
rotates that identity and queued follow-up ownership with the Goal, so editing
a paused Goal cannot release its held input. Clearing the Goal and starting an
unrelated replacement establishes no accounting lineage. Editing an active
Goal ends its running turn at the next tool boundary, so continuation starts a
turn from the revised objective; a turn waiting in WaitAgent is woken with
the refreshed context. The next prompt consumes one objective-updated reminder,
and an active Goal schedules continuation behind the current request gate.
When a Goal references an accepted Plan, each turn validates the reference against the session's accepted-path metadata, immutable artifact, and stored hash. A valid artifact receives exact read authority for that request. A missing, moved, mutated, or mismatched artifact pauses the Goal before provider dispatch; transcript prose is never a fallback source of Plan authority.
Child-agent, context-summary, and control requests are not Goal turns. A root turn
captures its Goal identity at request start and charges tokens, wall time, and
one turn at canonical success or failure settlement. Token accounting uses
normalized provider input plus output usage, excluding cached-input counts,
with the request estimate as fallback for gptel requests. Agents started from a Goal turn,
including nested agents and the completion verifier started by UpdateGoal,
are not Goal turns either, but they charge their normalized usage to the Goal
that root request is accounted to: after each tool batch and when the agent
request ends, whether it completes, fails, or is aborted. The budget therefore
bounds the whole run, not only the root conversation.
Claude subscription turns use the same accounting and continuation lifecycle. Top-level SDK message identities distinguish model samples; streamed deltas and consolidated snapshots update one sample rather than charging it repeatedly. Cache creation contributes to normalized input, while cache reads remain separate. Only reported nonnegative counters establish known usage. Final prompt totals replace the corresponding streamed totals; absent final fields retain known progress. The adapter's context-occupancy updates and cumulative model quota rows are not additional charges. These metrics do not measure subscription allowance or establish an exact monetary cost.
If any submitted native prompt in a turn or attributed child lacks complete
input and output counters at settlement, the durable Goal retains the known lower bound and marks its usage
incomplete. No estimate is manufactured from absent gptel request data.
GetGoal returns null tokens_used and remaining_tokens, alongside
known_tokens_used; the cockpit labels the count as incomplete. Unbudgeted
Goals can continue. A bounded active Goal becomes budget-limited at root
settlement (or when a late child settles after the root), because
its remaining allowance cannot be established. Raising its limit cannot repair
missing usage; remove the limit or start a new Goal to continue. A completed or
blocked decision still wins, and later known usage does not erase the gap.
Known usage from earlier prompts remains in the lower bound. A startup failure
before any prompt dispatch does not create a usage gap. While a prompt is still
running without complete counters, GetGoal also reports its total as unknown.
Automatic full-context continuation can use several native prompts within one admitted Goal turn. Each completed prompt contributes its usage once; later samples add to that frozen base. Delayed snapshots of completed sample identities cannot charge again, and the admitted turn is charged once at settlement.
Native child progress charges its owning root Goal while the child runs, and settlement charges only the remaining delta. Each retained follow-up has its own request accounting. Root and child budget reminders reach Claude through the existing post-tool hook and acknowledged context delivery. Usage observed after a tool result is checked again at that boundary, before the next sample. The normal budget remains a continuation limit with wrap-up instructions, not a hard server-side token ceiling.
Starting a Goal through CreateGoal or the user command also attributes an
already-running root turn, including its known token usage; elapsed time starts
at Goal activation. The next provider
interaction receives Goal facts and policy through the ordinary retained-context
delivery. The model may complete the Goal in that same turn. Replacing a Goal
completed earlier in the same turn settles the old Goal first and charges only
subsequent token usage to the new one. Repeated settlement cannot charge twice.
Compaction does not reconstruct the durable Goal from a summary. Retained observations can leave selected history; the context-delivery layer supplies current facts and policy again when needed. Ordinary steering remains ordinary conversation history: unresolved requests may survive as actionable summary steps, while satisfied requests retire to outcome or evidence under completed work. Current facts derived from the durable Goal supersede historical Goal observations.
Token budget¶
The optional token budget is the user-selected runaway bound. Request context
and the cockpit display bounded usage as used/limit and otherwise say
unbounded. Every charge, from a settling root turn or an agent, emits
one-shot crossing reminders: at 50% the model should prioritize the remaining
requirements, at 80% it should reassess the remaining work and avoid low-value
detours, and at 100% it should stop new substantive work and wrap up. These
need no durable reminder ledger because each charge compares usage immediately
before and after the monotonic charge, so every threshold is crossed exactly
once. A crossing reaches a root turn that is still running at its next
provider request, otherwise the next root request. Agents running for the
Goal are told the highest threshold reached so far at their next provider
request, counting the root turn's known in-flight usage; at 100% they are
asked to stop new work and return their findings.
Only an active Goal queues budget instructions; a turn that ends paused,
blocked, or complete queues none for later work. Goal context still reports
the budget, and GetGoal reports current usage, or only its known lower bound
when usage is incomplete.
CreateGoal accepts an optional positive token_budget, supplied only when
explicitly requested. Omission uses mevedel-goal-token-budget; the tool cannot
invent a limit or change the configured default.
An accepted Plan supplies its selected budget directly to the Goal record,
including nil for Unlimited. That selection does not change
mevedel-goal-token-budget in either a Here or Worktree session.
Crossing the limit never aborts an in-flight request or tool. At each root
tool-result boundary, durable usage plus the turn's known provider usage is
checked as well, so a long turn hears about each 50%, 80%, or 100% crossing
through a hidden turn event delivered at the same WAIT as the tool result. The
100% reminder asks the model to stop new substantive work and wrap up the
current response. It does not create a budget-exempt wrap-up turn. At
settlement, an otherwise-active Goal at or above the limit becomes
budget-limited; a complete or blocked decision from that turn wins.
/goal budget <N|none> replaces or removes the durable limit and queues one
reminder with the old limit, new limit, usage, remaining tokens, and resulting
status. Lowering the limit to current usage immediately limits a nonterminal
Goal and ends its running turn at the next tool boundary. Raising it above usage
or removing it from a budget-limited Goal reactivates the Goal and schedules
continuation behind the ordinary request gate. With incomplete usage, any limit
keeps the Goal budget-limited; only removing it reactivates the Goal.
Continuation¶
Starting or resuming a Goal schedules the ordinary continuation text:
Continue working toward the active Goal.
Successful and retryable failed root turns schedule the same continuation only after canonical request teardown. Dispatch requires all of the following:
- the Goal is active;
- no root request is running;
- no permission, Ask, Plan approval, or other interaction is pending in the root view, and no prompt hook is running;
- no queued follow-up remains to be delivered; and
- the session is not waiting for the user after an expired permission queue
(
absence; see permissions); and - the token budget is not exhausted.
Continuation is also offered again when a gate clears without a settling turn. Closing the last pending interaction in the root view, such as a child agent's permission card or Ask, or a Plan approval decided while the root session is idle, re-offers it, so the Goal resumes as soon as the user settles what held it. Queued follow-ups go first there too. While a queued follow-up waits for the user's composer draft, the Goal waits with it; sending or clearing the draft delivers the follow-up, whose settlement continues the Goal.
Same-turn steering stays with its owning active request. After that request settles, queued follow-ups run before generic Goal continuation, one normal turn per entry. Follow-ups owned by a paused, blocked, or budget-limited Goal remain held until the Goal resumes. Once a Goal is complete, the next queued follow-up is an ordinary non-Goal message. There is no maximum-turn or no-tool heuristic.
All mevedel-admitted native gptel backends first use
bounded sample recovery:
10 retries plus the initial attempt per model sample, independently for root
and child requests, including directive and shared-item requests, without
rerunning preparation, replaying completed tools, or charging extra Goal turns.
Claude Code/ACP remains separate and self-retrying; unadmitted background
gptel retry policies are unchanged. An exhausted controller marks its terminal
FSM info with
:mevedel-retry-exhausted; settlement charges known usage and one failed Goal
turn, then pauses the affected active Goal with the provider's concrete reason.
It does not use Goal's settled-turn retry allowance to multiply the 11-attempt
bound. An owned provider error classified as nonretryable similarly carries
:mevedel-retry-permanent and pauses the Goal even if its message resembles a
transient capacity or network failure. Structured quota/authentication or other
permanent errors cannot acquire extra settled-turn retries through misleading
text. Missing attempt usage remains unknown under the existing incomplete
usage policy. A completed or blocked Goal is not overwritten.
For failures without either controller marker, the existing policy is unchanged.
Transient transport failures are retried up to five consecutive times, after
15, 30, 60, 120, and 240 seconds, so a short network outage does not pause the
Goal. They include timeouts, connection and network errors, HTTP 502-504, and
curl's name-resolution, connect, transfer, TLS, empty-reply, send, and receive
exit codes. A successful turn resets the count. Terminal provider, transport,
compaction, and other runtime failures pause the Goal with a concrete reason.
This includes a failure to start the scheduled continuation. A new Goal or an
explicit resume resets the transient-retry allowance. An exhausted paused or
blocked Goal requires a budget increase or removal before it can resume.
A completion or blockage already recorded by UpdateGoal is terminal and is
not overwritten by later request failure handling. User interruption also
pauses the Goal.
Any successfully settled root turn that leaves an active Goal idle schedules
its continuation. A failed or interrupted turn not attributed to the Goal
schedules none, so stopping unrelated work never starts Goal work.
Goal tools¶
CreateGoal, GetGoal, and UpdateGoal use the ordinary tool pipeline and
are discoverable through ToolSearch and ToolCall in both the discuss and
implement presets. Goal turns keep the session's tools, so a Goal started in
read-only discussion can only investigate. They are session control
tools; creating a Goal never raises execution permissions. Native schemas and
the callable catalog use the same visibility checks, and handlers recheck the
owning root request before acting. An external engine's native roster is fixed
for its whole turn, so it keeps both CreateGoal and UpdateGoal while either
is visible; one can enable the other before that turn ends. Child-agent, context-summary, ephemeral,
and cancelled requests cannot call them.
Creation is unavailable in Plan mode, directive requests, while an unfinished Goal exists, or while accepted Plan implementation is reserved. An inactive Goal remains inspectable in the root conversation. A failed creation save restores the previous in-memory Goal and schedules no continuation.
UpdateGoal is a permission-free control tool visible only to a root request
attributed to the active Goal. It accepts exactly:
complete; orblockedwith a nonblank summary, stored as the Goal reason.
blocked takes effect at once. complete is a completion claim: the tool
runs the verifier agent in a separate request, using the goal-review
workload's model and effort, while the Goal stays active. The verifier receives
the exact objective and, when the Goal has one, the accepted plan verbatim, but
no account of the implementer's work or test results; it discovers the
changes and current state itself. Only a final VERDICT: PASS completes the
Goal, and only if it is still the same active Goal. FAIL, PARTIAL, a report
without exactly one final verdict line, or a verifier failure returns the
report as the tool result, leaves the Goal active, and ends the root turn at
that tool boundary. The rejected attempt therefore settles as its own Goal turn:
it is counted, captured by the journal, and checkpointed, queued follow-ups get
their turn, and ordinary continuation starts the next attempt with the report
in its history. The "same condition across three consecutive Goal turns" rule
for blocked thus counts completion attempts. An unreadable accepted
plan refuses verification. A user abort interrupts the verifier and pauses the
Goal as for any Goal turn. Canonical turn settlement still persists the final
accounting.
The goal-review workload defaults to the strong tier. It selects only the
completion check's model and reasoning effort; /verify and ordinary verifier
agents continue to use verifier. Empty tier fields inherit session policy.
For example, :model-workloads ((goal-review :tier strong)) configures completion
checks independently of plan-implementation and verifier. Invalid review
policy leaves the Goal active and reports an error rather than falling back.
The installed prompts/goals/active-context.md formats current objective,
accepted-plan reference, budget, and turns run. prompts/goals/policy.md separately
supplies the completion contract. It requires evidence for the full requested outcome; passing a
narrower set of checks does not establish completion. A model-reported block
requires the same impasse across at least three consecutive Goal turns with
no meaningful independent progress possible. These are judgment obligations.
The independent verifier checks a completion claim against workspace evidence,
but neither it nor the tool mechanically proves completion or classifies blockers.
Commands and UI¶
/goal <objective>starts a Goal and schedules its first turn.- Bare
/goalopens the Goal cockpit. /goal pausestops continuation and ends the running Goal turn at its next tool boundary without aborting it./goal budget <N|none>replaces or removes the token limit./goal edit <objective>replaces the objective without resetting the run./goal resume [steering]resumes, queueing steering before continuation./goal clearremoves Goal state while preserving transcript and artifacts.
A new Goal cannot replace an unfinished Goal or start while accepted Plan implementation is preparing or retryable. Ordinary Goal startup and Plan mode are mutually exclusive; accepted-plan Goal execution uses its dedicated handoff.
An accepted Plan may select Goal execution after any location and context preparation. The implementing session owns the resulting Goal and immutable accepted artifact: the planning session for Here, its Worktree fork for Worktree. Construction uses a deterministic objective that preserves the plan's outcomes, constraints, acceptance criteria, and validation evidence as the completion contract without parsing Markdown headings. The first ordinary Goal turn receives the prepared context, resolved artifact path, full plan, and kickoff; later turns use the small request-local Goal context and may reread the validated artifact.
The prepared Goal owns the Plan-selected implementation policy and token budget, not the session's ordinary defaults, which a Worktree fork copies from the planning session. Derived artifact authority exists only while the Goal is unfinished and never alters user grants.
Plan approval reserves the Goal identity before asynchronous preparation. The retry record blocks a competing Goal; a Worktree fork receives the reservation with its own retry record. Recovery reuses completed summary, segment, fork, artifact, and Goal construction steps. A durable Goal is recognized only by the reserved ID together with its accepted plan reference and matching implementation policy, so an unrelated unfinished Goal or a conflicting policy is never overwritten. A matching Goal restored as paused after a crash is reactivated without scheduling; the still-owned Plan handoff supplies its one explicit kickoff.
The Goal constructor persists the implementation policy and budget with the
Goal before Plan recovery is cleared and the explicit kickoff starts. A failed
construction save restores the previous Goal only if the provisional Goal is
still owned and unchanged; newer public Goal controls remain intact even when
they restore identical record contents, such as a pause followed by resume.
Kickoff retains that exact owner and reserved identity across publication.
Changed ownership, identity, status, or policy rejects stale kickoff authority
before dispatch. An actual startup failure pauses only the still-owned matching
Goal with the concrete error, and /goal resume uses the normal continuation
path. User input owned by that Goal
remains queued while paused; on resume it runs before a generic continuation.
During a Here handoff the same ordering keeps the prepared kickoff first and
post-acceptance input second. Worktree source input never transfers to or
steers the target Goal.
The cockpit and status surface show only objective, status/reason, accounting,
elapsed time, and accepted-plan reference. The cockpit header carries the
objective, status, turn count, and token accounting; i opens the Goal record
panel with the blocked reason, elapsed time, and accepted-plan reference. Their
redraws preserve the active composer draft.
Context delivery¶
Active root Goal facts (objective, accepted-plan reference, counters and budget) are retained current-context updates. Changed counters do not rewrite the system prefix. Goal execution policy is delivered separately on activation/context loss, so counter updates do not repeat its full instructions. New state supersedes older observations; leaving the active state delivers an explicit inactive observation. Retained workers do not inherit the root Goal.