--- name: silverbullet-query description: Write Space Lua queries (SLIQ) for SilverBullet notes. Use this skill whenever the user wants to build a query, filter, or live view in their SilverBullet space — including filtering pages by folder or tag, listing tasks, showing recently modified notes, building dashboards, or embedding any kind of dynamic query widget in a note. Triggers on phrases like "make a query," "show all pages tagged," "build a filter," "list tasks in," "show recent notes," "create a silverbullet view," or "make a live widget." --- # SilverBullet Query Skill SilverBullet uses **SLIQ** (Space Lua Integrated Query) — an SQL-inspired query language embedded in Lua. Queries live inside `${...}` expressions that render as live widgets in any note. ## Quick reference ### Embedding a query in a note Queries render inline using the `${...}` expression syntax: ``` ${template.each(query[[ from p = index.tag "page" where p.name:startsWith("proj/") order by p.lastModified desc ]], templates.pageItem)} ``` Use `template.each(collection, template)` to render a list. Use `query[[...]]` alone when you just need the raw data or a single computed value. ### Data sources | What you want | `from` clause | |---|---| | All pages | `from p = index.tag "page"` | | All tasks | `from t = index.tag "task"` | | All bullet items | `from i = index.tag "item"` | | All paragraphs | `from p = index.tag "paragraph"` | | All tags | `from t = index.tag "tag"` | | A Lua list | `from n = {1, 2, 3}` | Always use the explicit variable binding form (`p =`) — it's more reliable and future-proof. ### Filtering (`where`) ``` -- Pages in a folder where p.name:startsWith("proj/") -- Pages with a specific tag where table.includes(p.tags, "account") -- Pages matching name where p.name:startsWith("Person") -- Tasks on the current page only where t.page == _CTX.currentPage.name -- Combine conditions where p.name:startsWith("proj/") and table.includes(p.tags, "active") ``` ### Sorting (`order by`) ``` order by p.lastModified desc -- newest first order by p.lastModified asc -- oldest first order by p.name -- alphabetical order by p.lastModified desc, p.name -- multi-key ``` Nulls default to last (asc) or first (desc). Override with `nulls first` / `nulls last`. ### Limits and offsets ``` limit 10 limit 10, 2 -- limit 10, skip first 2 (inline offset) offset 5 ``` ### Selecting / transforming results ``` select p.name -- just the name select { name = p.name, mod = p.lastModified } -- custom object select p -- full object (default) ``` ### Render templates | Template | Renders as | |---|---| | `templates.pageItem` | `* [[page name]]` | | `templates.fullPageItem` | `* [[page name\|page name]]` | | `templates.taskItem` | `* [state] [[ref]] task text` | | `templates.itemItem` | `* [[ref]] item text` | | `templates.paragraphItem` | `* [[ref]] paragraph text` | | `templates.tagItem` | `* [[tag:name\|#name]]` | ## Common patterns ### Pages in a folder, newest first ``` ${template.each(query[[ from p = index.tag "page" where p.name:startsWith("FOLDER/") order by p.lastModified desc ]], templates.pageItem)} ``` ### Pages with a given tag ``` ${template.each(query[[ from p = index.tag "page" where table.includes(p.tags, "TAGNAME") order by p.lastModified desc ]], templates.pageItem)} ``` ### Open tasks on the current page ``` ${template.each(query[[ from t = index.tag "task" where t.page == _CTX.currentPage.name and t.state == " " ]], templates.taskItem)} ``` ### 5 most recently modified pages ``` ${template.each(query[[ from p = index.tag "page" order by p.lastModified desc limit 5 ]], templates.pageItem)} ``` ### Inline count (no template) ``` ${#query[[from p = index.tag "page" where p.name:startsWith("proj/")]]} projects ``` ## How to write a query for the user 1. Ask what objects they want (pages, tasks, items, tags, etc.) 2. Ask what filter applies (folder prefix, tag, current page, a condition) 3. Ask how to sort (newest first is `lastModified desc`, alphabetical is `p.name`) 4. Ask if they want a limit 5. Pick the right `templates.*` for the object type 6. Wrap in `${template.each(...)}` and drop it into the note If the user already described the intent (e.g., "show all proj pages newest first"), skip the questions and just write it. ## Placing the query Queries go directly in the note as Markdown text — no fenced code block needed. The `${...}` syntax renders on Alt-click (or view mode). Drop the expression on its own line for clean rendering. If the user wants the query to live in a `space-lua` block as a reusable function rather than an inline expression, wrap it: ```space-lua function myView() return template.each(query[[ from p = index.tag "page" where p.name:startsWith("proj/") order by p.lastModified desc ]], templates.pageItem) end ``` Then call it anywhere: `${myView()}`