Goals are defined on the Purpose page (Success
Criteria and per-stage criteria). This page covers how goal completion is verified:
the per-turn Auto-check evaluator and per-goal Goal Checks (owner code).
Why verification exists
Without verification, goal completion is self-reported: the agent decides it is done and calls themark_goal_complete tool with a value for every goal. The platform validates
that required values are present — but not that they are true. An agent could claim
appointment_booked: true without any appointment existing.
Two optional layers close that gap:
The two compose: with Auto-check on, conversational goals are assessed by a small LLM
pass while code-backed goals are verified by your Goal Check — and the code’s verdict
always wins.
Where to edit Goal Checks
The same code is editable in two places (it is stored once, on the goal itself in thepurpose section):
- Purpose page — each goal card has an Add Code Check button that opens an inline editor with a Test button.
- Events page — under the Goals & Handoff channel, each goal with code appears as a Goal Check row; create new ones by picking Channel → Goal → Event. Unlike ordinary event actions, a Goal Check is not fire-and-forget: its return value is the verdict.
The handler contract
Write the body ofhandle(goal, ctx) (JavaScript or Python — a pasted full
handle definition also works) and return a verdict:
status— the verdict.partialmeans real progress that isn’t complete yet.value— the confirmed value (persisted, shown to the agent, fed back asgoal.candidate_valuenext time).note— one short line of evidence, or what is still missing. Shown to the agent and in rejection messages, so make it actionable.
true/false or a bare status string also works. Anything
unrecognizable fails closed to unmet.
When your code runs
Goals already verified
met by code are skipped on subsequent end-passes (the gate
always re-checks live). Sandbox time is billed per second; the Auto-check LLM pass is
billed to the owner like other auxiliary calls.
The goal object
Your handler’s first argument:
The goal status map (goal.goals)
Each subscriber’s verified progress is persisted per goal (the same state that renders
the [x] / [~] / [ ] checkboxes in the agent’s context). Your code receives all of it,
keyed by goal key:
statusismet,partial,unmet, orunchecked(never assessed yet — also the case for anonymous visitors, whose state has nowhere to persist).tagis the goal’s positional citation tag — the sameGOAL-1,GOAL-2, … labels shown on the Purpose page and in the agent’s own context. Tags are numbered per active checklist (top-level goals, or the active stage’s criteria).
The ctx object
The second argument is the same tool bridge custom code tools get — see the full
reference at Custom tool ctx. In short:
await ctx.tools.<name>(input)— call any enabled built-in tool. Goal Checks get a curated, read-oriented bundle: subscriber memory + structured memory, knowledge-graph query, web search/fetch, calculate.await ctx.audit(event, data)— record a structured audit note.ctxidentity fields (agentId,agentUserId, …) and plainfetchfrom inside the sandbox are also available.
Example 1 — simple: validate the claimed value
No I/O at all: the goal is met only when the claimed contact detail actually looks like an email address or phone number. Pure validation ofgoal.candidate_value.
Goal definition (Purpose → Success Criteria):
handle(goal, ctx)):
"will provide later" — the gate
rejects the call and relays your note, so the agent knows exactly what to fix.
Example 2 — medium: verify against stored data
The goal claims a booking was recorded. The check doesn’t trust the claim — it reads the subscriber’s structured memory throughctx.tools and looks for the actual record,
returning partial when a booking exists but is missing its confirmation.
Goal definition:
[~] appointment_booked (partially met; booking recorded but not yet confirmed…) until the confirmation lands — the agent
knows to close the loop instead of declaring victory.
Example 3 — high complexity: external system + cross-goal ordering
A payment-collection goal that (a) refuses to pass until the other goals are verified, using the goal status map, (b) confirms the payment against an external API with plainfetch, and (c) uses stage_context from an earlier stage. This is the
kind of check that makes a multi-stage funnel trustworthy end-to-end.
Goal definition (on a checkout stage):
mark_goal_complete, the stage cannot auto-advance past
checkout until the payment provider itself confirms settlement — regardless of what
the model believes.
Python works everywhere JS does — write the body of
async def handle(goal, ctx)
with the same return shape: return { "status": "met", "value": ... }.Testing a check
- Purpose page — the Test button under the editor runs your (unsaved) code in
the real sandbox against the goal’s metadata and shows the verdict, note, runtime
and provider. No subscriber state is touched; every entry in
goal.goalsreadsunchecked. - API —
POST /api/test-goal-evaluatorwith{ agent_name, goal_key, code?, sample_value? }(owner session required).
Semantics reference
- One check per goal. Empty code = no check; the goal stays LLM-assessed (or presence-only when Auto-check is off).
- Hard gate: a required code-backed goal must verify
metformark_goal_completeto succeed; a failing optional goal is subtracted from the optional-satisfied count. Verdicts are persisted even when the call is rejected. - Stage scoping: state is kept per stage (and
_flatfor stage-less agents), so reused keys across stages never collide. Tags number within the active checklist. - Anonymous visitors: no per-goal state is persisted (nothing to key it on); the gate still runs your code live at completion time.
- Fail-open vs fail-closed: see the table under When your code runs.
Ask the AI Designer
The AI Designer can author all of this for you — goal definitions,evaluator_code Goal Checks, the auto_eval toggle, and fire-and-forget
event actions. Try: “Add a goal ‘deposit paid’ with a code
check that verifies the deposit against our structured memory record, and turn on
Auto-check.”
Manage via the Management MCP
Goal Checks live on thepurpose section — each criterion’s evaluator_code field
(see the purpose field reference). Event actions live in the
events section. Both are readable and writable through the
Management MCP.