Skip to content
Agent Memory
Skill

/memory-metadata-search

Structured metadata search for Basic Memory: query notes by custom frontmatter fields using equality, range, array, and nested filters. Use when finding notes by status, priority, confidence, or any custom YAML field rather than free-text content.

BOOST
From plugin
basic-memory
4.1k26 skills5 commands1 MCP
Install
$ npx -y skills add basicmachines-co/basic-memory --skill memory-metadata-search --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/memory-metadata-search

Context preview

The summary Claude sees to decide when to auto-load this skill.

Structured metadata search for Basic Memory: query notes by custom frontmatter fields using equality, range, array, and nested filters. Use when finding notes by status, priority, confidence, or any custom YAML field rather than free-text content.

SKILL.md

memory-metadata-search.SKILL.md
name: memory-metadata-search
description: "Structured metadata search for Basic Memory: query notes by custom frontmatter fields using equality, range, array, and nested filters. Use when finding notes by status, priority, confidence, or any custom YAML field rather than free-text content."

Memory Metadata Search

Find notes by their structured frontmatter fields instead of (or in addition to) free-text content. Any custom YAML key in a note's frontmatter beyond the standard set (`title`, `type`, `tags`, `permalink`, `schema`) is automatically indexed as `entity_metadata` and becomes queryable.

When to Use

  • **Filtering by status or priority** — find all notes with `status: draft` or `priority: high`
  • **Querying custom fields** — any frontmatter key you invent is searchable
  • **Range queries** — find notes with `confidence > 0.7` or `score between 0.3 and 0.8`
  • **Combining text + metadata** — narrow a text search with structured constraints
  • **Tag-based filtering** — find notes tagged with specific frontmatter tags
  • **Schema-aware queries** — filter by nested schema fields using dot notation

The Tool

All metadata searching uses `search_notes`. Pass filters via `metadata_filters`, or use the `tags` and `status` convenience shortcuts. Omit `query` (or pass `None`) for filter-only searches.

Filter Syntax

Filters are a JSON dictionary. Each key targets a frontmatter field; the value specifies the match condition. Multiple keys combine with **AND** logic.

Equality

{"status": "active"}

Array Contains (all listed values must be present)

{"tags": ["security", "oauth"]}

`$in` (match any value in list)

{"priority": {"$in": ["high", "critical"]}}

Comparisons (`$gt`, `$gte`, `$lt`, `$lte`)

{"confidence": {"$gt": 0.7}}

Numeric values use numeric comparison; strings use lexicographic comparison.

`$between` (inclusive range)

{"score": {"$between": [0.3, 0.8]}}

Null (field missing or explicitly null)

{"owner": null}

Matches notes with no `owner` key and notes whose `owner` is explicitly null. Null works only as a plain equality value — inside `$in`, `$between`, an array-contains list, or a comparison it is rejected, because those compare against the value and a comparison with null is never true.

Nested Access (dot notation)

{"schema.version": "2"}

Quick Reference

| Operator | Syntax | Example | |----------|--------|---------| | Equality | `{"field": "value"}` | `{"status": "active"}` | | Is null | `{"field": null}` | `{"owner": null}` | | Array contains | `{"field": ["a", "b"]}` | `{"tags": ["security", "oauth"]}` | | `$in` | `{"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": [lo, hi]}}` | `{"score": {"$between": [0.3, 0.8]}}` | | Nested | `{"a.b": "value"}` | `{"schema.version": "2"}` |

**Rules:**

  • Keys must match `[A-Za-z0-9_-]+` (dots separate nesting levels)
  • Operator dicts must contain exactly one operator
  • `$in` and array-contains require non-empty lists
  • `$between` requires exactly `[min, max]`
  • `null` is an is-null match and only valid as a plain equality value
  • Comparison and `$between` bounds must be finite numbers — a magnitude no float

can hold (a 400-digit integer, which JSON keeps as an ordinary `int`) is refused rather than compared against an infinite bound

  • Metadata filters match Markdown notes only — indexed PDFs, images and other

regular files carry no frontmatter and are never hits, not even for `null`

> **Warning:** Operators MUST include the `$` prefix — write `$gte`, not `gte`. Without the prefix the filter is treated as an exact-match key and will silently return no results. Correct: `{"confidence": {"$gte": 0.7}}`. Wrong: `{"confidence": {"gte": 0.7}}`.

Using `search_notes` with Metadata

Pass `metadata_filters`, `tags`, or `status` to `search_notes`. Omit `query` for filter-only searches, or combine text and filters together.

# Filter-only — find all notes with a given status
search_notes(metadata_filters={"status": "in-progress"})

# Filter-only — high-priority specs in a specific project
search_notes(
    metadata_filters={"type": "spec", "priority": {"$in": ["high", "critical"]}},
    project="research",
    page_size=10,
)

# Filter-only — notes with confidence above a threshold
search_notes(metadata_filters={"confidence": {"$gt": 0.7}})

# Convenience shortcuts for tags and status
search_notes(status="active")
search_notes(tags=["security", "oauth"])

# Text search narrowed by metadata
search_notes("authentication", metadata_filters={"status": "draft"})

# Mix text, tag shortcut, and advanced filter
search_notes(
    "oauth flow",
    tags=["security"],
    metadata_filters={"confidence": {"$gt": 0.7}},
)

**Merging rules:** `tags` and `status` are convenience shortcuts merged into `metadata_filters` via `setdefault`. If the same key exists in `metadata_filters`, the explicit filter wins.

Tag Search Shorthand

The `tag:` prefix in a query converts to a tag filter automatically:

# These are equivalent:
search_notes("tag:tier1")
search_notes("", tags=["tier1"])

# Multiple tags (comma or space separated) — all must match:
search_notes("tag:tier1,alpha")

Example: Custom Frontmatter in Practice

A note with custom fields:

---
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]]

Queries that find it:

# By status and type
search_notes(metadata_filters={
Read more
Ships withbasic-memory

AI conversations that actually remember. Never re-explain your project to your AI again. Join our Discord: https://discord.gg/tyvKNccgqN

Get the whole plugin

Other skills on basic-memory.