diff --git a/.claude/settings.json b/.claude/settings.json index 7eeecfac..bac52e64 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -5,7 +5,9 @@ "Bash(git commit *)", "Bash(dart *)", "Bash(flutter *)", - "Bash(make *)" + "Bash(make *)", + "Bash(pql)", + "Bash(pql *)" ], "deny": [ "Bash(rm -rf /*)", diff --git a/.claude/skills/pql/.pql-install.json b/.claude/skills/pql/.pql-install.json new file mode 100644 index 00000000..929ddc5c --- /dev/null +++ b/.claude/skills/pql/.pql-install.json @@ -0,0 +1,5 @@ +{ + "version": "1.0.0", + "hash": "sha256:98d7fa693fa4bcb6ccd6eb1d9d191c8f7332c9c97c221afb19741a7711bd9928", + "installed_at": "2026-04-22T11:22:39Z" +} diff --git a/.claude/skills/pql/SKILL.md b/.claude/skills/pql/SKILL.md new file mode 100644 index 00000000..176e2e6b --- /dev/null +++ b/.claude/skills/pql/SKILL.md @@ -0,0 +1,178 @@ +--- +name: pql +description: > + Query and plan against a markdown vault via the pql CLI. Two surfaces: + (1) structural queries — frontmatter, wikilinks, tags, headings, Bases, + DSL — use when the user asks about vault contents ("which notes…", "find + where…", "what tags", "who links to X", "run a Base", "query the vault"); + (2) planning — decision records, tickets, project status — use when the + user asks about decisions, tickets, work items, or project planning + ("sync decisions", "create a ticket", "what's the plan status", "show + D-005", "board"). Requires `pql` on PATH. JSON on stdout; exit 2 = zero + matches (not an error). +--- + +# pql — vault queries + project planning + +`pql` indexes a vault into SQLite and exposes structural queries plus a +planning layer for decision records and tickets. One binary, two surfaces. + +## Precondition + +```bash +command -v pql +``` + +If absent, tell the user to install from +https://github.com/postmeridiem/pql/releases/latest. Don't install it +yourself. Don't fall back to grep unless the user explicitly asks. + +## First touch: learn the vault + +```bash +pql schema +``` + +Returns one row per frontmatter key with observed types and file counts. +Run once per session before writing queries. + +--- + +## Surface 1: Vault queries + +### Subcommands + +| Command | Purpose | +|---|---| +| `pql files [glob]` | List indexed files; optional glob filter | +| `pql tags [--sort count]` | Distinct tags with counts | +| `pql backlinks ` | Files linking TO a path | +| `pql outlinks ` | Links FROM a file | +| `pql meta ` | Frontmatter + tags + outlinks + headings for one file | +| `pql schema` | Typed frontmatter schema | +| `pql base ` | Execute an Obsidian .base file | +| `pql shell` | Interactive REPL (indexes once, then query per line) | +| `pql query ""` | SQL-derived DSL for complex queries | +| `pql doctor` | Resolved vault/config/DB/index state | + +### DSL examples + +```sql +SELECT name, fm.date WHERE fm.type = 'meeting' ORDER BY fm.date DESC LIMIT 10 +SELECT path WHERE 'project' IN tags ORDER BY path +SELECT name, fm.prior_job WHERE fm.type = 'council-member' ORDER BY name +``` + +Use `--file q.pql` or `--stdin` for long queries. Don't interpolate vault +content into the command line. + +### Query cookbook + +- **Files in folder** → `pql files 'sessions/*'` +- **Top tags** → `pql tags --sort count --limit 20` +- **What links to X?** → `pql backlinks members/vaasa/persona.md` +- **Date range** → `pql query "SELECT name, fm.date WHERE fm.date BETWEEN '2024-01-01' AND '2024-12-31'"` +- **Run a Base** → `pql base council-sessions` +- **Inspect one file** → `pql meta members/vaasa/persona.md --pretty` + +--- + +## Surface 2: Planning (decisions + tickets) + +Planning state lives in `/.pql/pql.db` (user-authored state, not a +cache). Decision records come from `decisions/*.md`; tickets are +SQLite-native. + +### Decision subcommands + +| Command | Purpose | +|---|---| +| `pql decisions sync` | Parse decisions/*.md → upsert into pql.db | +| `pql decisions validate` | Dry-run parse; exits non-zero on malformed records | +| `pql decisions claim "title"` | Print next available ID | +| `pql decisions list [--type X] [--domain X] [--status X]` | List decisions | +| `pql decisions show [--with-refs] [--with-tickets]` | Show with joins | +| `pql decisions coverage` | Confirmed decisions without tickets | +| `pql decisions refs ` | Cross-references involving a decision | + +Always `pql decisions sync` before querying if decisions/*.md may have changed. + +### Ticket subcommands + +| Command | Purpose | +|---|---| +| `pql ticket new "title" [--decision D-NNN] [--priority P]` | Create (emits T-NNN) | +| `pql ticket list [--status S] [--team T] [--assigned A] [--label L]` | List with filters | +| `pql ticket show [--with-decision] [--with-blockers] [--with-children]` | Show with joins | +| `pql ticket status ` | Transition (enforces state machine) | +| `pql ticket assign ` | Set assignee | +| `pql ticket block --by ` | Add blocker | +| `pql ticket unblock --from ` | Remove blocker | +| `pql ticket team ` | Set team | +| `pql ticket label add\|rm