GeniffyDocs
Changelog Log In Get a key

Labels

Give what you add labels of your own, such as the channel it came from or the account it is about. Then keep any recall to them: context, ask, search, the list of memories and a brief all take a filter.

mem.memories.add(email.body, title=email.subject, labels={"channel": "email", "account": "lumen"})
mem.context("When does the renewal come up?", labels={"account": "lumen"})

Filters

  • Every name in a filter must match: {"channel": "email", "account": "lumen"} keeps to sources that carry both.
  • A list of values is any one of them: {"channel": ["email", "chat"]}.
  • A memory counts when any source that said it carries the labels. If an unlabelled note and a labelled email both said it, the filter finds it.
  • In a query string, a filter is label=name:value, repeated for another name or another value: GET /v1/memories?label=account:lumen&label=channel:email.
mem.search("pricing", labels={"channel": ["email", "chat"]})
mem.ask("Who signs the renewal?", labels={"account": "lumen"})
mem.memories.list(labels={"account": "lumen"})
mem.brief(labels={"account": "lumen"})

When nothing carrying the labels bears on the question, context says so in one sentence, as it does without a filter, so your model says it doesn't know instead of reaching for something outside them.

Every memory that comes back names the labels of the source it came from, as source.labels, so you can show where each one came from or sort them yourself.

Changing labels

Labels belong to a source. To change them, send the source again under your own id:

  • New labels: they replace the old ones at once. Nothing is read or learned again.
  • No labels: the source keeps the ones it has, and a part it gains when it grows carries them too.
  • {}: clears them.

Without an external_id, sending a source again adds a second one, so a source added that way keeps the labels it was added with. To change them, delete it and add it again. GET /v1/sources and GET /v1/sources/{id} show each source's labels.

Forget everything with a label

When your user disconnects a data source, delete everything you added from it in one call, if you added it under its label:

mem.sources.delete_labelled({"channel": "gmail"})      # how many sources went

Each source goes with every memory only it taught; a memory another source also said stays. One call deletes up to 100 sources and answers more: true while others carry the labels, and the SDKs call again for you. To see what would go first, GET /v1/sources?label=channel:gmail lists them, and so does sources.list(labels=...).

At the end of a sync that read everything from a data source, pass the ids of what it still has as keep, and every other source with the labels, such as what is gone from the data source, is deleted:

mem.sources.delete_labelled({"channel": "notion"}, keep=seen)   # seen: the external_ids this sync added

The SDKs read the whole list first, then delete the rest one by one. Gmail, Google Drive, Notion and OneDrive each show a full sync.

Labels or spaces?

A space is one of your users: a memory of its own that nothing else can read. Labels sort what one user's memory holds. Use a space for who it belongs to, and labels for what it is: the channel, the account, the project. A label never lets one space read another.

The rules

  • Up to 20 labels on a source.
  • A name is up to 64 letters, digits, dots, dashes or underscores, starting with a letter or digit.
  • A value is 1 to 200 characters; spaces at either end are trimmed.
  • A filter holds up to 20 names, each with up to 50 values.
  • Anything else is refused with bad_labels, before anything is stored.

Files take labels too, as a JSON form field: labels={"channel": "drive"}. So does each item of a batch.

Last updated October 6, 2026