pull_context’s filters.tags, and that is the whole of it. Creating and
applying tags happens in the app or over the SDK.
The filter is a hard scope: only sources you tagged (and the knowledge
distilled from them) come back. An untagged note never sneaks in, which is
the point of curating. Two more rules do the rest:
- The vocabulary is deliberate.
applynever invents tags: unknown names come back inunknownand the call still succeeds; the backend invalidates anything that doesn’t exist, on every surface. (Your personal vocabulary is seeded on first use withwork,health,personal,finance,tech,pii,confidential. Project vocabularies start empty on purpose.) - Visibility follows the scope. Personal tags are yours alone; team and project vocabularies are shared with every member. Agent-global tags belong to the account: an agent vault resolves the vault OWNER’s global registry, so collaborators on your projects can see and apply your global tags there. Anyone with vault access can apply a shared tag; detaching a team or project tag from a source needs writer access.
Tags or metadata keys?
One question decides it: should a source that says nothing about this still show up in a filtered search? If yes (keep the general refund-policy note when searching one customer’s context) you want a metadata key. If no (only my curated set) you want a tag.
Anti-example both ways: a tag per customer (
customer-sara) is a metadata
key wearing a tag costume; a declared key for vibes (topic: infra) is a
tag wearing a metadata costume. Values → metadata. Groups → tags.
Scoped pull_context
Agents connected over MCP get the same filter onpull_context:
- Unknown tag names fail loud. The SDK returns a 400 listing your
vocabulary; MCP returns
items: []with the reason incoverage_note, so readcoverage_notebefore concluding “no memory”. - An empty set is an explicit answer. If nothing carries the tag, you get an empty result immediately, not a low-relevance grab bag.
- Combines with metadata: your curated set, minus anyone else’s data (see the examples below).
Filtering examples
Only the launch set:launch or incident (a list means any-of):
Best practices
- Name the group, not the value.
launch,pii,needs-review, notticket-8841. Unbounded values are what metadata keys are for. - Keep the vocabulary small. Caps are 200 per user and 20 per source; a set you can hold in your head (10–30) is one you’ll actually apply.
- Create before apply. Unknown names are echoed, never auto-created. That’s typo protection, so don’t fight it by pre-creating variants.
- Delete is an archive. Sources stay tagged, the tag leaves the pickers, and restore brings it back, so organization is never lost.
- Don’t push
metadata={"tags": [...]}. That key is reserved for a future push-time shape; today it does nothing silently. Tag viatags.applyafter the push.
API
client.tags.list(project_id): the project’s vocabulary, live counts.client.tags.create(project_id, name)/rename(project_id, tag_id, name)/delete(project_id, tag_id)(archives) /restore(project_id, tag_id). All four need an agent key and project admin; reading the vocabulary needs only membership.client.tags.apply(vault_id, source_id, add=[...], remove=[...])resolves against the vault’s context: its project’s tags, then your agent-global registry.client.vaults.pull(vault_id, query, filters={"tags": [...]}).