Best for
- 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
basicmachines-co/basic-memory/skills/memory-metadata-search/SKILL.md
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.
Decision brief
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 entitymetadata and becomes queryable.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/basicmachines-co/basic-memory --skill "skills/memory-metadata-search"Inspect the Agent Skill "memory-metadata-search" from https://github.com/basicmachines-co/basic-memory/blob/de4589d24155332002709f5529c9bdd4937861a4/skills/memory-metadata-search/SKILL.md at commit de4589d24155332002709f5529c9bdd4937861a4. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Filtering by status or priority — find all notes with status: draft or priority: high
All metadata searching uses searchnotes. Pass filters via metadatafilters, or use the tags and status convenience shortcuts. Omit query (or pass None) for filter-only searches.
Filters are a JSON dictionary. Each key targets a frontmatter field; the value specifies the match condition. Multiple keys combine with AND logic.
Review the “Equality” section in the pinned source before continuing.
Review the “Array Contains (all listed values must be present)” section in the pinned source before continuing.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 87/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 3,583 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
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.
status: draft or priority: highconfidence > 0.7 or score between 0.3 and 0.8All 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.
Filters are a JSON dictionary. Each key targets a frontmatter field; the value specifies the match condition. Multiple keys combine with AND logic.
{"status": "active"}
{"tags": ["security", "oauth"]}
$in (match any value in list){"priority": {"$in": ["high", "critical"]}}
$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]}}
{"schema.version": "2"}
| Operator | Syntax | Example |
|---|---|---|
| Equality | {"field": "value"} | {"status": "active"} |
| 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:
[A-Za-z0-9_-]+ (dots separate nesting levels)$in and array-contains require non-empty lists$between requires exactly [min, max]Warning: Operators MUST include the
$prefix — write$gte, notgte. 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}}.
search_notes with MetadataPass 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.
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")
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={"status": "in-progress", "type": "spec"})
# By numeric threshold
search_notes(metadata_filters={"confidence": {"$gt": 0.7}})
# By priority set
search_notes(metadata_filters={"priority": {"$in": ["high", "critical"]}})
# By tag shorthand
search_notes("tag:security")
# Combined text + metadata
search_notes("OAuth", metadata_filters={"status": "in-progress"})
{"status": "active", "priority": "high"} requires both conditions.query for filter-only searches. search_notes(metadata_filters={"status": "active"}) works without a text query.{"schema.version": "2"} queries the version key inside a schema object.tags and status are sugar for common fields. For anything else, use metadata_filters directly.