Mitosis Labs

Memory

Asking a memory

cortex_ask, cortex_recall, and how to read what comes back.

cortex_ask

The default retrieval call. It fuses vector search, full-text search and graph expansion, then answers in natural language with citations attached.

{
  "question": "What did we decide about pricing last quarter?",
  "limit": 10,
  "since": "2026-04-01T00:00:00Z"
}
ArgumentTypeNotes
questionstringRequired. Natural-language question or search query.
limitnumberMax results. Defaults to 10.
source_tablestringRestrict to one source table, e.g. gmail_messages.
sincestringRFC 3339 lower bound on item time.
untilstringRFC 3339 upper bound on item time.

Follow-up questions are new questions

A result describes only the question it was fetched for. There is no conversational state on the server. A follow-up needs its own cortex_ask call with its own question, not a re-read of the previous result.

cortex_recall

Semantic-only vector search, returning source excerpts rather than a composed answer. Reach for it when you want nearest-neighbour matches on meaning and intend to do your own synthesis.

{ "query": "onboarding friction", "limit": 20 }

It takes query and limit, nothing else. There are no time bounds on cortex_recall; use cortex_ask when you need them.

Reading the response

Beyond the answer itself, three fields carry most of the operational meaning:

citationsstring[]

Universal ids for the nodes the answer drew on. Pass these to cortex_remember as source_universal_ids to keep provenance intact.

cited_graph_urlstring

Deep link into the user's own graph with the cited nodes highlighted. Good to surface directly to a human who asks "where did that come from?"

memory.office_namestring

Which memory answered. Note that a connector's display name is text the user typed and identifies nothing. This field is the real one.

Handling a gap instead of guessing

The mistake to avoid is treating weak results as an answer. Check for the gap blocks described in how memory works before you compose a reply:

const res = await askMemory(question);

if (res.memory_state) {
  // Nothing connected yet. Offer res.memory_state.cta.url, don't apologise
  // for a search that never had anything to search.
} else if (res.source_gap) {
  // The graph has data, just not this kind. Name the missing source and
  // offer res.source_gap.cta.url.
} else if (res.possible_source_gap) {
  // Answer, but hedge: these may be near-misses.
} else {
  // Trustworthy: either a real answer, or a real absence.
}

The cta.url in each block opens the user's own dashboard page for connecting sources. Handing it over is safe: the link only shows them that page, and connecting is an authorization they perform there.