Skip to content

Commit 2a53fce

Browse files
andingerclaude
andcommitted
Add vaultquery reference command with embedded documentation
Embeds a canonical reference document (DQL syntax, functions, file.* fields, shell quoting, examples) in the binary via go:embed. Users can pipe it to a file for AI assistant context, ensuring every instance gets identical, version-matched documentation. Also overhauls README with command reference table, corrected DQL examples (double quotes instead of single quotes), shell quoting section, and complete DQL overview including all query types, FROM sources, and functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f48cd52 commit 2a53fce

4 files changed

Lines changed: 345 additions & 64 deletions

File tree

README.md

Lines changed: 149 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Query Obsidian vault files by YAML frontmatter using a DQL-like query language.
77
### Homebrew (macOS / Linux)
88

99
```bash
10-
brew install andinger/vaultquery/vaultquery
10+
brew install andinger/tap/vaultquery
1111
```
1212

1313
### Binary download
@@ -21,26 +21,160 @@ go install github.com/andinger/vaultquery/cmd/vaultquery@latest
2121
## Usage
2222

2323
```bash
24-
# Index the vault (run from vault root, or use --vault)
25-
vaultquery index --vault ~/my-vault
24+
# Query with DQL (auto-syncs index before each query)
25+
vaultquery query "TABLE customer, status FROM \"Clients\" WHERE type = \"Lead\" SORT customer ASC" --vault ~/my-vault
2626

27-
# Query with DQL
28-
vaultquery query "TABLE customer, kubectl_context WHERE type = 'Kubernetes Cluster' SORT customer ASC"
27+
# List all files with a specific tag
28+
vaultquery query "LIST FROM #project WHERE status != \"archived\"" --vault ~/my-vault
2929

30-
# List all leads that aren't lost
31-
vaultquery query "LIST FROM \"Sales\" WHERE type = 'Lead' AND status != 'lost'"
30+
# Find files linking to a specific page
31+
vaultquery query "TABLE file.name FROM [[My Note]]" --vault ~/my-vault
3232

33-
# Find files with a specific tag
34-
vaultquery query "TABLE customer WHERE tags contains 'linux'"
33+
# TOON output (recommended for LLM/agent workflows)
34+
vaultquery query "TABLE customer WHERE type = \"Server\"" --vault ~/my-vault --format toon
35+
```
36+
37+
Every `query` command automatically syncs the index before executing (incremental, mtime+size based). Pass `--index-only` to skip syncing and use the existing index as-is.
38+
39+
## Commands
40+
41+
| Command | Description |
42+
|---|---|
43+
| `vaultquery query "<DQL>"` | Execute a DQL query against the vault |
44+
| `vaultquery index` | Build or update the vault index (incremental) |
45+
| `vaultquery reindex` | Drop and rebuild the vault index from scratch |
46+
| `vaultquery status` | Show index status (file count, vault path) |
47+
| `vaultquery reference` | Print the full reference documentation to stdout |
48+
49+
### Options
50+
51+
| Flag | Applies to | Description | Default |
52+
|---|---|---|---|
53+
| `--vault <PATH>` | all | Vault root directory | current directory |
54+
| `--format <FORMAT>` | query | Output format: `json` or `toon` | from config or `json` |
55+
| `-v, --verbose` | all | Show detailed progress during indexing | off |
56+
| `--index-only` | query | Skip index sync, use existing index as-is | off |
57+
58+
## Built-in reference
3559

36-
# Check index status
37-
vaultquery status
60+
vaultquery ships with a comprehensive reference document embedded in the binary. This reference covers the full DQL syntax, all built-in functions, `file.*` metadata fields, shell quoting rules, and usage examples.
3861

39-
# Full reindex (drop + rebuild)
40-
vaultquery reindex --vault ~/my-vault
62+
The reference is designed as a machine-readable context file for AI coding assistants. Instead of each assistant session interpreting the tool's behavior on its own, every instance gets the exact same canonical documentation — matched to the installed version.
63+
64+
```bash
65+
# Print reference to stdout
66+
vaultquery reference
67+
68+
# Create a local reference file (e.g. for Claude Code)
69+
vaultquery reference > ~/.claude/references/vaultquery.md
70+
71+
# Update after upgrading vaultquery
72+
brew upgrade vaultquery && vaultquery reference > ~/.claude/references/vaultquery.md
4173
```
4274

43-
Every `query` command automatically syncs the index before executing (incremental, mtime+size based). Pass `--index-only` to skip syncing and use the existing index as-is.
75+
The reference is rebuilt with each release, so re-running the command after an upgrade keeps your local copy in sync.
76+
77+
## Shell quoting
78+
79+
DQL uses double quotes for string values and folder paths. **Always use double-quoted shell strings with escaped inner quotes:**
80+
81+
```bash
82+
# CORRECT — double quotes with escaped inner quotes
83+
vaultquery query "TABLE customer WHERE type = \"System\"" --vault ~/base
84+
85+
# CORRECT — no inner quotes needed
86+
vaultquery query "LIST FROM #project" --vault ~/base
87+
88+
# WRONG — single quotes break negation (!) in zsh (BANG_HIST)
89+
vaultquery query 'TABLE x WHERE status != "done"'
90+
```
91+
92+
## DQL overview
93+
94+
### Query types
95+
96+
| Type | Description |
97+
|---|---|
98+
| `TABLE field1, field2, ...` | Tabular output with specified frontmatter fields |
99+
| `LIST [expression]` | List of file links with optional expression |
100+
| `TASK` | Task items (`- [ ]` / `- [x]`) from file content |
101+
| `CALENDAR <date-field>` | Calendar view grouped by date |
102+
103+
### FROM sources
104+
105+
```
106+
FROM "folder/path" # Folder
107+
FROM #tag # Tag
108+
FROM [[link]] # Backlinks to page
109+
FROM outgoing([[link]]) # Outgoing links from page
110+
FROM #tag AND "folder" # Boolean combination
111+
FROM #tag OR #other-tag
112+
FROM !#excluded # Negation
113+
```
114+
115+
### WHERE operators
116+
117+
| Operator | Example |
118+
|---|---|
119+
| `=`, `!=` | `status = "active"`, `type != "archived"` |
120+
| `<`, `>`, `<=`, `>=` | `rating >= 4` |
121+
| `contains`, `!contains` | `tags contains "linux"` |
122+
| `exists`, `!exists` | `kubectl_context exists` |
123+
| `AND`, `OR`, `(...)` | `(type = "Server" OR type = "Cluster") AND status = "active"` |
124+
125+
### Clauses
126+
127+
```
128+
SORT due ASC # Sort (ASC or DESC)
129+
SORT status DESC, due ASC # Multi-field sort
130+
LIMIT 10 # Limit results
131+
GROUP BY status # Group results
132+
FLATTEN tags # Flatten array fields into rows
133+
WITHOUT ID # Omit file link column
134+
```
135+
136+
### Expressions and aliases
137+
138+
```
139+
TABLE status, due, file.name
140+
TABLE (due - date(today)) AS "Days Left"
141+
TABLE choice(status = "done", "Y", "N") AS Done
142+
```
143+
144+
### file.* metadata fields
145+
146+
Every indexed file exposes metadata via `file.*`:
147+
148+
| Field | Description |
149+
|---|---|
150+
| `file.name` | Filename without extension |
151+
| `file.folder` | Parent folder path |
152+
| `file.path` | Full relative path |
153+
| `file.link` | Link to the file |
154+
| `file.size` | File size in bytes |
155+
| `file.ctime` / `file.cday` | Creation time / date |
156+
| `file.mtime` / `file.mday` | Modification time / date |
157+
| `file.day` | Date parsed from filename (e.g. `2026-03-06.md`) |
158+
| `file.tags` / `file.etags` | All tags / explicit tags |
159+
| `file.inlinks` / `file.outlinks` | Incoming / outgoing links |
160+
| `file.aliases` | Aliases from frontmatter |
161+
| `file.frontmatter` | All frontmatter as object |
162+
163+
### Built-in functions
164+
165+
**Constructors:** `date()`, `dur()`, `number()`, `string()`, `link()`, `list()`, `object()`, `typeof()`
166+
167+
**Numeric:** `round()`, `floor()`, `ceil()`, `min()`, `max()`, `sum()`, `product()`, `average()`, `minby()`, `maxby()`
168+
169+
**Arrays:** `contains()`, `icontains()`, `econtains()`, `length()`, `sort()`, `reverse()`, `flat()`, `slice()`, `unique()`, `join()`, `nonnull()`, `all()`, `any()`, `none()`
170+
171+
**Strings:** `lower()`, `upper()`, `split()`, `replace()`, `startswith()`, `endswith()`, `substring()`, `truncate()`, `padleft()`, `padright()`, `regextest()`, `regexmatch()`, `regexreplace()`
172+
173+
**Utility:** `default()`, `choice()`, `dateformat()`, `durationformat()`, `striptime()`, `meta()`, `currencyformat()`
174+
175+
**Lambda support:** `all(list, (x) => cond)`, `any(list, (x) => cond)`, `none(list, (x) => cond)`
176+
177+
For full function signatures and detailed syntax, run `vaultquery reference`.
44178

45179
## Vault-local storage
46180

@@ -71,47 +205,7 @@ exclude:
71205
72206
Paths are relative to the vault root. Matching is prefix-based (e.g. `Archive/Old` excludes everything under that path). The `.vaultquery` directory itself is always excluded.
73207

74-
## DQL Reference
75-
76-
### Query Modes
77-
78-
| Mode | Description |
79-
|------|-------------|
80-
| `TABLE field1, field2, ...` | Returns specified frontmatter fields |
81-
| `LIST` | Returns only path and title |
82-
83-
### Clauses
84-
85-
| Clause | Description | Example |
86-
|--------|-------------|---------|
87-
| `FROM "path"` | Filter by vault subdirectory | `FROM "Clients"` |
88-
| `WHERE expr` | Filter by field conditions | `WHERE type = 'Server'` |
89-
| `SORT field [ASC\|DESC]` | Sort results | `SORT customer ASC` |
90-
| `LIMIT n` | Limit result count | `LIMIT 10` |
91-
| `GROUP BY field` | Group results | `GROUP BY customer` |
92-
| `FLATTEN field` | Flatten array fields | `FLATTEN tags` |
93-
94-
### WHERE Operators
95-
96-
| Operator | Description | Example |
97-
|----------|-------------|---------|
98-
| `=` | Equals | `status = 'active'` |
99-
| `!=` | Not equals | `status != 'lost'` |
100-
| `<`, `>`, `<=`, `>=` | Comparison | `value > '1000'` |
101-
| `contains` | Array contains value | `tags contains 'linux'` |
102-
| `!contains` | Array doesn't contain | `tags !contains 'deprecated'` |
103-
| `exists` | Field exists | `kubectl_context exists` |
104-
| `!exists` | Field doesn't exist | `notes !exists` |
105-
106-
### Logical Operators
107-
108-
Combine conditions with `AND`, `OR`, and parentheses:
109-
110-
```
111-
WHERE (type = 'Server' OR type = 'Cluster') AND status = 'active'
112-
```
113-
114-
## Output
208+
## Output formats
115209

116210
Default output is JSON:
117211

@@ -190,15 +284,6 @@ tags:
190284
- Arrays are stored as separate rows (enabling `contains` queries)
191285
- The title is extracted from the first `# heading` after frontmatter
192286

193-
## Configuration
194-
195-
| Flag | Default | Description |
196-
|------|---------|-------------|
197-
| `--vault` | Current directory | Vault root path |
198-
| `-v, --verbose` | false | Show detailed progress during indexing |
199-
| `--format` | `json` | Output format: `json` or `toon` (query only, overrides config) |
200-
| `--index-only` | false | Skip index sync, use existing index as-is (query only) |
201-
202287
## Development
203288

204289
```bash

internal/cli/cli.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func NewRootCmd(version, commit, date string) *cobra.Command {
2121
newIndexCmd(),
2222
newReindexCmd(),
2323
newStatusCmd(),
24+
newReferenceCmd(),
2425
)
2526

2627
root.PersistentFlags().String("vault", "", "path to vault root (default: current directory)")

internal/cli/reference.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package cli
2+
3+
import (
4+
_ "embed"
5+
"fmt"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
//go:embed reference.md
11+
var referenceDoc string
12+
13+
func newReferenceCmd() *cobra.Command {
14+
return &cobra.Command{
15+
Use: "reference",
16+
Short: "Print the vaultquery reference documentation to stdout",
17+
Long: "Prints a comprehensive reference for vaultquery usage, DQL syntax, and built-in functions. Pipe to a file to create a local reference: vaultquery reference > ~/.claude/references/vaultquery.md",
18+
Args: cobra.NoArgs,
19+
RunE: func(cmd *cobra.Command, args []string) error {
20+
fmt.Print(referenceDoc)
21+
return nil
22+
},
23+
}
24+
}

0 commit comments

Comments
 (0)