Keyword search
keyword_searchFind exact identifiers, code symbols, titles, or phrases in Obsidian notes with PostgreSQL full-text search; supports AND/OR/exclude operators, tag, folder, and frontmatter filters.
Instructions
Full-text keyword search via PostgreSQL tsvector. Use this for exact identifiers, code symbols, proper nouns, titles, or known phrases — anywhere semantic noise hurts.
Exact identifiers, code symbols, titles or known phrases: keyword_search.
Conceptual or paraphrased questions: semantic_search. Unsure which:
hybrid_search.
Bare terms are ANDed: budget forecast matches only notes containing
both stems. Notes matching every term come first, tagged match: all;
when they do not fill the page, notes matching some of the terms follow,
tagged match: any, in their own rank order. The operators:
"exact phrase" (adjacent words), budget OR forecast (either), -draft
(exclude; honoured in the any block too). A note's title and frontmatter
aliases are indexed above its body, so a query that is a note's title
ranks that note first. A note's tags (frontmatter and inline #tags; a
nested #a/b also as a and b) are indexed below its title and
aliases and above its body.
Each result carries rank (a relative score: a body-only match scores in
the thousandths, a title match near 1, and an any row is scored against
the fallback query, so ranks compare only within one block of one page),
match, matched_in (the parts that alone match: title — title or
aliases — tags, body, comma-joined; or, when the terms are split
between parts, the first of title+tags, title+body, tags+body,
title+tags+body that matches), terms (k/n: how many of the query's
terms the note contains), and a second line: snippet: — the matching
body text with the matches in «» — or head: — the note's opening
words when the body alone does not match or the match is beyond the
stored excerpt (a note with no body has no second line). Snippets are
computed for the first rows of the page (the header says
snippets: first N when the page is longer). The header always carries the all/any counts and how many
rows have no stored excerpt yet (notes indexed before this version; the
footer names the one-time rebuild). Call read_note on a result's path
for the full note.
Args: query: Keywords or phrase to match (websearch tsquery syntax: "foo bar", "foo OR bar", "-bar"). folder: Optional folder prefix (e.g. "Cards/", "Projects/"). limit: Maximum number of results (default 20). tags: Optional list of tag names; only notes carrying ALL listed tags match (e.g. ["project", "active"]). frontmatter: Optional dict of frontmatter key/value pairs; only notes whose JSONB frontmatter contains every pair match. Strict type matching — string "0" does not match integer 0 (e.g. {"status": "draft"}).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | ||
| limit | No | ||
| query | Yes | ||
| folder | No | ||
| frontmatter | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |