Skip to content

feat(cli): add path query (jaq over the cache) and path kind#114

Open
benbaarber wants to merge 2 commits into
mainfrom
ben/query
Open

feat(cli): add path query (jaq over the cache) and path kind#114
benbaarber wants to merge 2 commits into
mainfrom
ben/query

Conversation

@benbaarber

@benbaarber benbaarber commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Adds path query — loads every step in the local cache into one JSON array and transforms it with an in-process jaq (pure-Rust jq) filter (selection, projection, ranking, grouping, top-N). Each element wraps a Toolpath step (step/change/meta verbatim) with cache_id, path, and dead_end. Scope flags pick which docs load (--source/--id/--input, --project/--kind); output mirrors jq (-c compact, -r raw).

Also adds path kind — the cold-start companion that lists bundled kind specs or prints a kind's schema.json (the field reference for writing filters).

Full design and rationale: docs/superpowers/specs/2026-06-22-path-query-command-design.md

Breaking (pre-1.0): path query ancestorspath p query ancestors; dead-ends/filter are now jaq forms (map(select(.dead_end)), map(select(.step.actor | startswith("agent:")))). path-cli 0.14.0 → 0.15.0; adds jaq-core/jaq-std/jaq-json.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

`path query` loads every step in the local cache into one JSON array and
transforms it with an in-process jaq (pure-Rust jq) filter — selection,
projection, ranking, grouping, and top-N are all jaq. Each array element
wraps a Toolpath step (step/change/meta verbatim) with `cache_id`, `path`
(the parent path's id/base/meta), and `dead_end` (off the head's ancestry).

Scope flags choose which docs load: `--source`/`--id`/`--input` (file
selection) and `--project`/`--kind` (content scoping, semver-prefix kind
match). Output mirrors jq: pretty on a TTY, compact when piped (`-c`), raw
strings with `-r`. Malformed cache docs are skipped with a stderr warning;
empty results exit 0, filter errors exit 1.

`path kind` is the cold-start companion: lists the bundled kind specs, or
prints a kind's schema.json (the field reference for writing filters).
`--kind` and `path kind` share one semver-prefix selector, sourced from a
new shared `kinds` module that `schema.rs` now also reads.

BREAKING (pre-1.0): the former `path query` subcommands change. `ancestors`
moves to `path p query ancestors`; `dead-ends`/`filter` become jaq forms
(`map(select(.dead_end))`, `map(select(.step.actor | startswith("agent:")))`).

path-cli 0.14.0 -> 0.15.0; adds jaq-core/jaq-std/jaq-json.
@github-actions

Copy link
Copy Markdown

🔍 Preview deployed: https://00ab4cfa.toolpath.pages.dev

@benbaarber benbaarber requested a review from akesling July 1, 2026 14:28
@akesling akesling assigned benbaarber and unassigned akesling Jul 1, 2026
…ache

`path query` no longer loads every cached step into one array up front. The
executor reads the filter — it parses the jaq into jaq's own AST and picks an
execution plan:

- **PerFileStream** — element-wise filters (`.[] | g`, distributive for any g)
  run per document and print as they go; nothing accumulates.
- **Decompose** — algebraic aggregations run the filter per file, concatenate
  the per-file outputs, then run a derived combine over them: `map` → `add`,
  top-N `sort_by(k) | .[:N]` → `add | sort_by(k) | .[:N]`, `length`/`add` →
  `add`, `min`/`max` → themselves. A global top-N is a subset of the per-file
  top-Ns, so the merge is exact and bounded (files × N).
- **Slurp** — the always-correct fallback for anything not provably
  decomposable (`group_by`, `unique`, `as`-bindings, `reduce`, …). Still lean:
  values are held once, with no whole-cache byte buffer.

Recognition is conservative (a non-distributive prefix such as `unique` before
a top-N slurps), so the planner never changes an answer. Unit tests assert the
streamed output equals the slurp output byte-for-byte across element-wise,
top-N, and scalar-reduction filters; integration tests confirm cross-file top-N
and sums end to end. `TOOLPATH_QUERY_EXPLAIN=1` prints the chosen plan to
stderr. No user-facing flag — it's automatic.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants