1---
2name: using-silverbullet
3description: Manages notes in SilverBullet/SB via the CLI and Space Lua. Use when the user mentions notes, SilverBullet, pages, journal, tasks in their space, or asks to search/read/write/edit notes.
4license: GPL-3.0-or-later
5metadata:
6 author: Amolith <amolith@secluded.site>
7---
8
9SilverBullet is a self-hosted Markdown note-taking app with a Lua scripting layer. Do not write top-level `# Titles`; SilverBullet puts the page title at the top of the page and `Title\n\n# Title` is redundant.
10
11# Prefer the high-level CLI
12
13`sb` talks to a running SilverBullet instance through the Runtime API. Prefer `get`, `describe`, and `query` before dropping into Lua. Use `sb <command> -h` for full flags and edge cases.
14
15Most useful commands:
16
17- `sb space ls`, `sb space add`, `sb space rm <name>` β manage saved space connections. Use `-s <name>` to select a space when more than one is configured.
18- `sb get` β list indexed tag names in the space.
19- `sb describe [tag]` β show query syntax and live schemas, e.g. `sb describe page` or `sb describe task`.
20- `sb get <tag> [ref]` β list indexed objects or fetch one object by ref. For pages, the ref is the page name.
21- `sb query '<sliq-expression>'` β run Space Lua Integrated Query; this wraps the argument in `query[[...]]`.
22- `sb eval '<expression>'` β evaluate one Space Lua expression and print its return value.
23- `sb script [code]`, `sb script -f file.lua`, or stdin β run multi-statement Space Lua. The positional argument is inline code, not a filename.
24- `sb logs`, `sb logs -n 20`, `sb logs -f` β inspect or follow headless client logs.
25
26Use `--json` for parseable output, `-o jsonl` for line-oriented pipelines, and `--text` for human-readable output. `--text` is an output format, not βpage textβ.
27
28# Common operations
29
30```bash
31# List recent page metadata
32sb get page --sort-by lastModified:desc --limit 10 --select name,lastModified
33
34# Find pages by name/prefix metadata
35sb get page --where name:contains=meeting --select name,lastModified
36sb get page --where name:startsWith=Journal/ --select name,lastModified
37
38# Fetch one page metadata object. This does NOT return the Markdown body.
39sb get page "Journal/2026-06-07" --json
40
41# Read the Markdown body of a page
42sb eval 'space.readPage("Journal/2026-06-07")'
43
44# Full-text search; returns matches with excerpts, scores, and offsets
45sb eval 'silversearch.search("search terms", {silent=true})'
46
47# Tasks: prefer get filters for routine list/filter/sort work
48sb get task --where done=false --sort-by priority:desc --limit 20
49sb get task --where due:lte=2026-06-30 --where done=false
50
51# Query when get cannot express the relationship
52sb query 'from l = index.tag "link" where l.toPage == "TargetPage" select l.fromPage'
53sb query 'from p = index.tag "page" order by p.lastModified desc limit 10 select p.name'
54
55# Write/create only when asked to change the space
56sb eval 'space.writePage("PageName", "Content without a duplicate top heading")'
57
58# Delete only when explicitly asked
59sb eval 'space.deletePage("PageName")'
60```
61
62`sb get` supports `--where`, `-l/--selector`, `--sort-by`, `--limit`, `--offset`, and `--select`; run `sb get -h` rather than memorising every filter operator.
63
64# Editing pages safely
65
66`string.gsub` treats the search string as a Lua pattern, not plain text. Characters like `-`, `.`, and `%` are magic and can silently break replacements. Use a helper that returns only the replacement string:
67
68```lua
69local function plainReplace(str, old, new, n)
70 old = old:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0")
71 new = new:gsub("%%", "%%%%")
72
73 local replaced
74 if n == nil then
75 replaced = str:gsub(old, new)
76 else
77 replaced = str:gsub(old, new, n)
78 end
79 return replaced
80end
81```
82
83Use `sb script` for multi-step edits:
84
85```bash
86sb script <<'EOF'
87local function plainReplace(str, old, new, n)
88 old = old:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0")
89 new = new:gsub("%%", "%%%%")
90
91 local replaced
92 if n == nil then
93 replaced = str:gsub(old, new)
94 else
95 replaced = str:gsub(old, new, n)
96 end
97 return replaced
98end
99
100local text = space.readPage("PageName")
101text = plainReplace(text, "old literal text", "new literal text", 1)
102space.writePage("PageName", text)
103return "done"
104EOF
105```
106
107For multi-line Markdown literals, prefer `[==[...]==]` over `[[...]]` so wiki links and templates do not terminate the string accidentally. If the content itself contains `]==]`, use a normal quoted string with `\n` escapes or edit existing content with `plainReplace`.
108
109# Space Lua tripwires
110
111- Space Lua APIs are camelCase: `space.readPage`, not `space.read_page`.
112- Use `return`; `print()` output is swallowed.
113- Do not chain `:gsub()` calls. `gsub` returns `(string, count)`, so reassign each step.
114- Do not use `query` as a variable or parameter name; it can parse as SLIQ syntax.
115- The standard Lua `utf8` library is unavailable.
116- In SLIQ, use explicit binding: `from p = ...`.
117- Use current command names: `eval` and `script`. Old `lua`/`lua-script` aliases are hidden compatibility shims.
118
119# SilverBullet docs
120
121The official docs space serves raw Markdown pages. Fetch docs directly when you need detail on Space Lua, SLIQ, or the CLI:
122
123```bash
124curl -fsSL 'https://silverbullet.md/.fs/CLI.md'
125curl -fsSL 'https://silverbullet.md/.fs/Space%20Lua.md'
126```
127
128URL-encode page names (`%20` for spaces, `%2F` for `/`). If `sb` is unavailable, read `https://silverbullet.md/.fs/CLI.md` yourself and link the user to `https://silverbullet.md/CLI`.