Docs/Search/Metadata filters

Metadata filters

Every search box accepts inline metadata filters that AND with the remaining free text — narrow results by folder, tag, or frontmatter field without leaving the query. On the desktop/CLI/MCP path, filter terms compile to bases where-clause lines and feed through the bases parser, so bases stays the single grammar/semantics authority.

Easy mode

  • path:Tasks/ — only notes under that folder (segment-aware: Tasks/ never matches a sibling like TasksArchive/). Compiles to where __path under "Tasks/".
  • tag:ml — notes whose tags array contains ml (case-insensitive). Compiles to where tags is "ml".
  • has:status / -has:status — frontmatter field present / absent. Compile to where status exists / where status missing.
  • [status:active] — frontmatter field equals a value (case-insensitive is). Quote values with spaces: [status:"in progress"].
  • Mix filters with free text — path:Tasks/ [status:active] renewal finds notes under Tasks/ with status: active mentioning "renewal".

A query with no filter syntax at all behaves byte-identically to the pre-filter engine (this is a load-bearing invariant of the parser, not just a convenience) — filters never change behavior for a plain-text search.

Power

  • [key:!value]is not. [key:~value]contains.
  • [key:>n], [key:>=n], [key:<n], [key:<=n]gt/gte/lt/lte (numeric/date compares), e.g. [modified:>=2026-07-01]. modified is a special-cased alias for the computed __modified meta field (core parses ISO dates on it); the dunder spelling [__modified:>=…] also works.
  • Quoted text is never parsed as a filter — "path:Tasks/" searches for that literal string instead of applying it. This applies to any fully double-quoted token, not just path:.
  • Values with spaces must be double-quoted: [status:"in progress"]. A path: value may be quoted the same way: path:"My Folder/Sub".
  • A malformed bracket term (no colon, empty key or value, unbalanced/half quoting, a key containing whitespace/quotes/backslashes, or the literal key or — which would collide with bases' OR-line splitting) is never an error: it degrades to literal free text and is matched verbatim, exactly like any other search word.
  • Multiple filter terms AND together (bases' AND-of-lines semantics); there is no OR across filter terms.
  • From the CLI: solomon search "renewal" --path Tasks/ --where 'status is "active"' ANDs a folder prefix and a full bases where-clause onto the query, on top of whatever inline path:/[key:value] terms the query text itself contains. The MCP search tool takes the same path / where parameters, with identical semantics — one grammar, three ways to reach it (inline text, CLI flags, MCP params), all composing with AND.
  • Regex mode (--regex on the CLI, regex: true on the MCP tool) never mines path:/tag:/has:/[key:op value] out of the pattern itself — a regex like [a-z] or a literal tag:urgent runs as written. Only the structured path/where params are consulted in regex mode; inline filter syntax is not extracted from a regex pattern.
  • A malformed where clause (CLI --where, or the MCP where param) is surfaced as result.error ({message, line}), never a thrown/tool-call error — the same convention base_query/solomon base use for a bad DSL string.

Where each piece of syntax works

Surface path: / tag: / has: / -has: [key:value] not-equal / contains / numeric compares
Desktop, CLI, MCP full full full
Webapp, iOS path: / has: / -has: only (no tag:) yes (is, case-insensitive, array-any) degrades to plain equality — no is not/contains/numeric/date compares, no meta fields, no OR

The webapp's mirror is a deliberately minimal reimplementation supporting exactly is/exists/missing plus a segment-aware path: prefix — chosen because those three need no numeric/date coercion and so can't silently drift from core's evaluator the way a second full bases grammar in TypeScript could. Anything outside that subset (a bracket term using !/~/>/>=/</<=, or tag:) is not specially parsed there and falls through to plain equality/exists/missing on the literal key/value written, or is left as free text.

Recipes

  • Active tasks: path:Tasks/ [status:active]
  • Tasks missing a status: path:Tasks/ -has:status
  • Recently touched notes: [modified:>=2026-07-01] (desktop/CLI/MCP)
  • Not-done, not archived: [status:!done] -has:archived
  • Assignee substring match: [assignee:~david]
  • CLI, combining inline + flags: solomon search "renewal" --path Tasks/ --where 'status is "active"'
  • MCP search tool, same effect: {"query": "renewal", "path": "Tasks/", "where": "where status is \"active\""}

Related

  • [[solomon CLI reference]] — solomon search's --path/--where flags use this same grammar.
  • [[MCP tool surface]] — the search tool's path/where params.
  • [[Query your vault with bases]] — the shared bases where-clause grammar these filters compile down to.