Suggestions and pipelines
Grounded suggestions, independent pipeline feeds, and shared user context.
A Suggestion is a durable idea for something useful to do. Optima owns its identity, revision history, feedback and action state regardless of which pipeline produced it. Recorded words and generated text are data, never instructions to a client.
Automatic processing
The internal pipeline automatically processes Turns for every confirmed, active account with a ready internal pipeline. It starts at the beginning of recorded history when no checkpoint exists, then resumes from the last successfully processed input. Work runs in bounded batches; later batches can use already synthesized Memories and Conversations. Late-arriving Turns and corrections are tracked separately so older timestamps do not cause them to be skipped. Historical catch-up can take time before the feed reflects the most recent recordings.
Automatic processing saves and updates Suggestions. It does not create webhook subscriptions, send user notifications, or wake a connected harness. Clients read the feed through API/MCP or consume their existing account-event subscriptions. Staging and production process their own database inputs independently.
After a generated batch passes its complete response schema, Optima validates each optional Memory and Suggestion candidate independently. A candidate with invalid evidence, references, identity, or timing is omitted together with candidates that depend on it, while independent grounded results and the processed-input checkpoint can still publish. Malformed or truncated responses, provider failures, stale inputs, and repair failures reject the whole attempt and leave the checkpoint in place. Internal rejection diagnostics are bounded and contain no generated wording. Only resources that publish emit their ordinary account events; rejected candidates do not create events.
The automatic producer uses the account's original internal pipeline. Creating or selecting an experimental pipeline does not start another automatic producer. Cloudflare Agent Memory remains unavailable until its backend is enabled.
Select a pipeline
GET /pipelines lists the available selection. An account has one default pipeline.
Omit pipeline_id from suggestion lists, search and recall to use that default.
Responses include the resolved pipeline ID even when no results exist. Include it
in cache keys and reuse it while paginating. Switching the default invalidates a
cursor that was created for the old default; explicitly pin the original pipeline
to continue that feed.
Developer-enabled accounts can compare pipeline instances by supplying
pipeline_id. Each instance has independent suggestions, feedback, grouping and
learned preferences. The same idea can legitimately appear in two feeds. Completing,
dismissing or editing it in one feed does not change the other. Shared Turns,
Contacts and declared profile context remain the same inputs.
POST /pipelines creates an experimental instance. PATCH /pipelines/{id} changes
its label, status or default selection using expected_updated_at and an
idempotency_key. A pipeline instance persists across processing jobs. Use a new
instance for a clean experiment; changing labels does not clear prior state.
A backend's unavailable or disabled status must not be treated as an empty
successful analysis. Selecting an unavailable recall backend returns 503, with no
fallback to another pipeline.
Non-default pipelines require the pipelines:experimental permission, which comes
with developer access: creating or updating
a pipeline, listing every pipeline, or selecting a non-default one with pipeline_id
otherwise returns 403. Without it, GET /pipelines lists only the default pipeline.
With developer access, a token scoped pipelines:read, or with the scopes recall
needs (turns:read and insights:read), also lists every pipeline and selects a
non-default one; creating or updating still needs
pipelines:write.
Optima staff grant developer access; users cannot grant it themselves, and OAuth scopes
do not grant it on their own. Access only permits inspection of the account's own data.
Read suggestions and evidence
GET /suggestions defaults to the active feed. Use view=history for completed,
dismissed, withdrawn and other historical items. Pagination fixes an eligibility
cutoff; refresh after a suggestion event to see newer changes.
List items include the action, timing, roles, state, review status, grouping and
presentation hints, without Turn evidence. evidence_started_at and evidence_ended_at give the
capture time spanned by the cited Turns, such as the meeting a suggestion came
from; each is null when that capture time is unknown. created_at and
updated_at record processing, not when the conversation happened. Open GET /suggestions/{id} for the full current item and
its canonical Turn evidence; revision selects immutable content. Fetch the
detail before judging whether a suggestion is grounded or acting on its citations.
The full suggestion includes pipeline_id, action, why_now, basis,
evidence, optional timing, presentation, mutable state and a state version. Evidence is an
array of canonical Turn references, each with source, the state of the cited Turn's
transcript:
{
"turn_id": "fde322ec-07d5-44fd-9e16-cb4b5fdab007",
"word_start": null,
"word_end": null,
"source": { "state": "available", "removed_at": null }
}Null offsets cite the whole Turn. Otherwise offsets are zero-based, start-inclusive
and end-exclusive word indices. When source.state is expired or deleted, the cited
words are gone: GET /turns/{id} returns 410 for that Turn, and the suggestion keeps its
own action and reasoning. Public Suggestions do not require Memory IDs.
Pipeline-specific memories and conversations are developer diagnostics, with one
exception: a shared recorder's session summary gives the
session's host their titles and text, for that session only, with insights:read.
A suggestion the workspace's retention removed is left
out of GET /suggestions (both views), and reading, editing, giving feedback on, or
grouping it returns 410 CONTENT_EXPIRED or CONTENT_DELETED with removed_at; see
Removed content.
Source changes can mark suggestions for review or restrict evidence reads. Do not retain deleted source text in a client cache.
roles distinguishes speaker, mention, actor and recipient. A role can have
a contact ID, detected speaker ID, both or neither. wording preserves an unresolved
label; basis identifies detected, mentioned, inferred or user-supplied identity.
Recording ownership does not identify the speaker.
States are suggested, accepted, completed, dismissed and withdrawn.
Acceptance records the user's choice; it does not perform an outside action.
New evidence about an accepted item can set needs_review instead of silently
completing or withdrawing it.
Presentation hints
The pipeline classifies each suggestion when it writes the revision, so clients can
style and route cards without classifying the action text themselves. List items
and full suggestions carry the same presentation object:
{
"presentation": { "domain": "engineering", "intent": "review", "handoff": "codex" }
}domainis the work area:engineering,product(product and design),business(sales and partnerships),research(customer and user research), orgeneralfor work that spans several areas or matches none.intentis the requested interaction:do,decide,revieworfollow_up. It is independent ofneeds_review; a suggestion flagged for review keeps its own intent.handoffis where a user-reviewed draft of the action fits best:claude,codex,linearorslack. It is a default, not an instruction. Offer every destination you support, and create or send nothing without the user.
presentation is null on revisions written before hints existed and on pipelines
that do not produce them. Each field can gain values; treat an unrecognized value
like a missing hint and use your own fallback, such as general styling. Hints
belong to a revision. A user edit keeps the current hints, and PATCH cannot set
them. They never change state, review status or ordering. A hint change publishes
a new revision with the ordinary suggestion.updated event; event metadata never
includes hint values.
Edits and feedback
PATCH /suggestions/{id} edits action, why_now, roles or due. Supply
expected_revision, expected_state_version and a UUID idempotency_key.
Edits create an immutable revision and protect the changed fields from later model
overwrite. The revision keeps the current presentation hints. Conflicts return 409.
POST /suggestions/{id}/feedback accepts accept, complete, dismiss, snooze,
wrong, irrelevant and more_like_this. For example:
{
"shown_revision": 2,
"expected_state_version": 3,
"idempotency_key": "bd28c730-b5ca-4e2c-a54b-af149cd9d15c",
"action": "accept"
}Snooze requires a future snoozed_until; wrong and irrelevant may include reason.
Wrong disputes correctness. Irrelevant hides the occurrence without asserting that
its evidence is false. More-like-this is a relevance signal, not factual confirmation.
These signals belong to the suggestion's pipeline.
An ID-based read or mutation uses that Suggestion's own pipeline even if the default
has changed. An explicit mismatched pipeline_id is rejected. Reuse an idempotency
key only for an identical retry. Refetch after conflicts and before further writes
following a replayed receipt.
POST /suggestions/grouping creates or changes a presentation group, merges or
splits duplicates, or records keep_separate / allow_grouping. Supply member IDs
and expected revisions, plus the group version where applicable. Members must all
belong to the same pipeline. Grouping related suggestions does not share their
completion state.
Shared profile
GET /profile returns versioned declared_context: self_contact_id, role, current
priorities, useful vocabulary and stated preferences. PUT /profile replaces these
fields with expected_revision and idempotency_key. Revision zero is the first
write. All pipelines see declared context; inferred preferences remain separate
per pipeline and are available only in developer diagnostics.
Search and recall
GET /search?q=...&pipeline_id=... returns text with canonical Turn evidence and a
cursor. POST /recall accepts query, optional pipeline_id, and limit, and
returns retrieved context or an answer with evidence. Check mode.
The internal backend currently uses full-text retrieval. Search reports
mode=full_text; recall reports mode=retrieval, answer=null, and truncated
when more matches exist. This is not semantic ranking or an LLM-generated answer.
Use concrete search terms. An unavailable backend returns 503 rather than borrowed
results. Reading these endpoints does not start inference or incur model charges.
Search and recall leave out Turns whose transcript expired or was deleted.
Permissions and events
Suggestions are the insights layer: reading them needs insights:read, and editing,
grouping, or giving feedback needs insights:write. Search and recall read turns and
insights, so they need turns:read and insights:read. The other MCP scopes are
pipelines:read, pipelines:write, profile:read and profile:write. Reconnect and
approve new scopes; existing grants gain no new authority automatically. A grant
issued with an earlier scope name keeps
working. Raw Turn and audio APIs retain their own permissions.
Suggestion events include pipeline_id in bounded metadata. Pipeline creation and
selection changes emit pipeline.created / pipeline.updated. Declared profile
changes retain the memory_context.updated event name. Older retained events may
lack a pipeline ID. Events never include suggestion wording, profile contents or
transcripts. See Account events.