Recipes
A recipe is an immutable snapshot of a finished agent-session — the structured intent_log plus the full transcript at the moment of capture. Recipes preserve a completed flow as a durable reference without re-running decomposition to inspect its intent plan.
The current surface covers create, list, read, and delete:
POST /v1/recipes, GET /v1/recipes, GET /v1/recipes/{id}, and
DELETE /v1/recipes/{id}. There is no recipe-execution endpoint;
start a new agent-session to run another task.
Resource shape
{
"id": "rec_<uuid>",
"account_id": "<account-uuid>",
"agent_session_id": "agt_<uuid> | null",
"label": "my checkout flow",
"description": "Snapshot of the example.com checkout session.",
"intent_count": 12,
"created_at": "<ISO-8601>",
"updated_at": "<ISO-8601>"
}
agent_session_id is null when the originating agent-session
has been deleted (ON DELETE SET NULL — the recipe survives the
source session’s lifecycle). intent_count is the length of the
flattened intent_log. The list endpoint omits the intent array for
payload weight; fetch a single recipe with GET /v1/recipes/{id}
to get its public intent_log. Sensitive type steps retain their
selector, order, and sensitive: true marker but omit value. The
exact value remains inside the server’s encrypted recipe payload and
is never exposed to an ordinary read-scope caller.
Create
POST /v1/recipes
Request body:
{
"agent_session_id": "agt_<uuid>",
"label": "my checkout flow",
"description": "Snapshot of the example.com checkout session."
}
agent_session_id— required. Must belong to the calling account; cross-account references return 404.label— required. 1-120 characters after trim.description— optional. Up to 2000 characters.
Response 201 Created returns the resource above.
List
GET /v1/recipes
Lists the calling account’s recipes, newest first. Cursor-paginated:
limit— optional. 1-100, defaults to 50.cursor— optional. Opaque cursor from a prior page’snext_cursor.
Response 200 OK:
{
"data": [],
"has_more": true,
"next_cursor": "<opaque> | null"
}
Each data entry is the resource shape above without the
intent_log array — list items carry only intent_count for
payload weight. Fetch a single recipe to get the public saved
steps. next_cursor is null on the last page.
Suggest a label/description
GET /v1/agent-sessions/{id}/recipe-suggestion
Before deciding whether to save a session as a recipe, fetch a
deterministic label + description suggestion derived from that
session’s own intent_log — the same data POST /v1/recipes would
capture. Read-only; safe to call speculatively (no recipe is created).
Response 200 OK:
{
"suggested_label": "Fill form on example.com",
"suggested_description": "Navigates to example.com, fills 2 fields, taps 1 element, submits.",
"intent_count": 5
}
The suggestion is a heuristic over the session’s own intents (distinct
navigate hostnames, interact-action counts) — not a cross-customer ML
model. It never inspects or trains on any other account’s data. A
session with no navigate/interact intents still returns a usable
generic suggestion rather than an error. id uses the same cross-account
404 contract as the rest of this surface (existence not leaked).
Get one
GET /v1/recipes/{id}
Returns a single recipe including its public intent_log array (the
list endpoint omits it). Sensitive type intents omit value, even
when sensitivity is inferred from a password, OTP, PIN, card, or API
key selector; these steps still carry sensitive: true so clients can
render them accurately. Other intent fields are unchanged. A
non-existent id — or one belonging to another account — returns 404;
the server doesn’t distinguish missing from forbidden, to avoid
leaking existence.
Delete
DELETE /v1/recipes/{id}
Deletes a recipe. Response 204 No Content. A non-existent id — or
one belonging to another account — returns 404, the same
anti-enumeration contract as the rest of the customer surface.
Delete is not idempotent: deleting an already-deleted recipe
returns 404, not 204.
Intent log assembly
When the route fires, the server walks the source agent-session’s
transcript and flatMaps every plan-executed agent turn’s
structured intents array into a single intent_log. The result
is captured atomically (insert-once; never edited) so the
historical snapshot survives any later session activity.
Recipe payloads are encrypted at rest. Public detail serialization works from a copy and removes sensitive type values without changing the stored intent log, preserving the exact server-side snapshot while preventing a read-only API key or device key from retrieving saved credentials.
Operator + user transcript entries don’t carry intents — only
agent turns from a successful decompose+execute step contribute.
A session that ran exclusively in mode='manual' will produce a
recipe with intent_count: 0 (because manual sessions log
operator entries, not decomposer plans). That’s expected — the
recipe is still useful as a transcript-only snapshot.
Errors
| Status | Type | When |
|---|---|---|
| 400 | validation | body fails schema (missing label, label > 120 chars, description > 2000) |
| 404 | not-found | agent_session_id doesn’t exist or belongs to another account |
| 401 | unauthorized | missing or invalid bearer token |
| 503 | feature-unavailable | activation gate off (recipe library or agent-sessions repo not wired) |