# Metadata Search Reference Basic Memory automatically indexes custom frontmatter fields so you can query them with structured filters. Any YAML key in a note's frontmatter beyond the standard set (`title`, `type`, `tags`, `permalink`, `schema`) is stored as `entity_metadata` and becomes searchable. ## Querying with `search_notes` `search_notes` is the single search tool for all queries — text, metadata filters, or both. The `query` parameter is optional, so you can use metadata filters alone without passing an empty string. ## Filter Syntax Filters are a JSON dictionary where each key targets a frontmatter field and the value specifies the match condition. Multiple keys combine with **AND** logic — every filter must match. ### Equality Match a single value exactly. ```json {"status": "active"} ``` Finds notes whose frontmatter contains `status: active`. ### Array Contains (all) Pass a list to require **all** listed values to be present in the field. ```json {"tags": ["security", "oauth"]} ``` Finds notes tagged with both `security` and `oauth`. ### `$in` (any of) Match if the field equals **any** value in the list. ```json {"priority": {"$in": ["high", "critical"]}} ``` ### `$gt`, `$gte`, `$lt`, `$lte` Numeric and text comparisons. Numeric values use numeric comparison; strings use lexicographic comparison. ```json {"confidence": {"$gt": 0.7}} {"score": {"$lte": 100}} ``` ### `$between` Range filter (inclusive). Takes a `[min, max]` pair. ```json {"score": {"$between": [0.3, 0.8]}} ``` ### Nested Access (dot notation) Access nested frontmatter values using dots. ```json {"schema.version": "2"} ``` This queries the `version` key inside a `schema` object in frontmatter. ### Summary Table | Operator | Syntax | Example | |----------|--------|---------| | Equality | `{"field": "value"}` | `{"status": "active"}` | | Array contains (all) | `{"field": ["a", "b"]}` | `{"tags": ["security", "oauth"]}` | | `$in` (any of) | `{"field": {"$in": [...]}}` | `{"priority": {"$in": ["high", "critical"]}}` | | `$gt` / `$gte` | `{"field": {"$gt": N}}` | `{"confidence": {"$gt": 0.7}}` | | `$lt` / `$lte` | `{"field": {"$lt": N}}` | `{"score": {"$lt": 0.5}}` | | `$between` | `{"field": {"$between": [min, max]}}` | `{"score": {"$between": [0.3, 0.8]}}` | | Nested access | `{"a.b": "value"}` | `{"schema.version": "2"}` | **Key rules:** - Filter keys must match `[A-Za-z0-9_-]+` (dots separate nesting levels). - Each operator dict must contain exactly one operator. - `$in` and array-contains require non-empty lists. - `$between` requires exactly two values `[min, max]`. ## MCP Tool — `search_notes` `search_notes` is the single search tool for text queries, metadata filters, or both. The `query` parameter is optional. **Relevant parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `query` | string (optional) | Text search query. Omit for filter-only searches. | | `metadata_filters` | dict | Structured filter dict (see syntax above) | | `tags` | list[str] | Convenience shorthand — merged into `metadata_filters["tags"]` | | `status` | string | Convenience shorthand — merged into `metadata_filters["status"]` | **Merging rules:** `tags` and `status` are convenience shortcuts. They are merged into `metadata_filters` using `setdefault` — if the same key already exists in `metadata_filters`, the explicit filter wins. **Examples:** ```python # Text search filtered by metadata await search_notes("authentication", metadata_filters={"status": "draft"}) # Filter-only search (no query needed) await search_notes(metadata_filters={"type": "spec"}) # Combine text, tags shortcut, and metadata await search_notes( "oauth flow", tags=["security"], metadata_filters={"confidence": {"$gt": 0.7}}, ) # Convenience shortcuts await search_notes("planning", status="active") await search_notes(tags=["tier1", "alpha"]) ``` ## Tag Search Shortcuts The `tag:` prefix in a search query is a shorthand for tag-based metadata filtering. When `search_notes` receives a query starting with `tag:`, it converts the query into a `tags` filter and clears the text query. ```python # These are equivalent: await search_notes("tag:tier1") await search_notes("", tags=["tier1"]) # Multiple tags (comma or space separated) — all must be present: await search_notes("tag:tier1,alpha") await search_notes("tag:tier1 alpha") ``` ## CLI Access The `bm tool search-notes` command exposes metadata filtering via `--meta` and `--filter` flags. ### `--meta` — simple key=value filters Repeatable flag for equality filters on frontmatter fields. ```bash # Single filter bm tool search-notes "my query" --meta status=draft # Multiple filters (AND logic) bm tool search-notes "" --meta status=active --meta priority=high ``` ### `--filter` — advanced JSON filters Pass a full JSON filter dictionary for operator-based queries. ```bash # Range filter bm tool search-notes "" --filter '{"score": {"$between": [0.3, 0.8]}}' # $in filter bm tool search-notes "" --filter '{"priority": {"$in": ["high", "critical"]}}' ``` ### `--tag` and `--status` — convenience shortcuts ```bash bm tool search-notes "query" --tag security --tag oauth bm tool search-notes "" --status draft ``` ### Combined example ```bash bm tool search-notes "authentication" --tag security --meta status=draft --type spec ``` ## Practical Examples ### Example notes with custom frontmatter **`specs/auth-design.md`:** ```markdown --- title: Auth Design type: spec tags: [security, oauth] status: in-progress priority: high confidence: 0.85 --- # Auth Design ## Observations - [decision] Use OAuth 2.1 with PKCE for all client types #security - [requirement] Token refresh must be transparent to the user ## Relations - implements [[Security Requirements]] ``` **`specs/search-redesign.md`:** ```markdown --- title: Search Redesign type: spec tags: [search, performance] status: draft priority: medium confidence: 0.6 --- # Search Redesign ## Observations - [goal] Sub-100ms search response times #performance - [approach] Hybrid FTS + vector retrieval ## Relations - depends_on [[Database Schema]] ``` ### Queries that find them ```python # Find all in-progress specs await search_notes(metadata_filters={"status": "in-progress", "type": "spec"}) # → Auth Design # Find high-confidence specs await search_notes(metadata_filters={"confidence": {"$gt": 0.7}}) # → Auth Design (confidence: 0.85) # Find specs with priority high or medium await search_notes(metadata_filters={"priority": {"$in": ["high", "medium"]}}) # → Auth Design, Search Redesign # Find specs in a confidence range await search_notes(metadata_filters={"confidence": {"$between": [0.5, 0.9]}}) # → Auth Design (0.85), Search Redesign (0.6) # Find notes tagged with security await search_notes("tag:security") # → Auth Design # Combined: text search + metadata filter await search_notes("OAuth", metadata_filters={"status": "in-progress"}) # → Auth Design ``` ### CLI equivalents ```bash bm tool search-notes "" --meta status=in-progress --type spec bm tool search-notes "" --filter '{"confidence": {"$gt": 0.7}}' bm tool search-notes "OAuth" --meta status=in-progress bm tool search-notes --tag security ```