Skip to content

Navigation Menu

Sign in
Sign up

feat(cli): machine-readable --json output for zg query #115

Open

Description

Motivation

zg query currently emits only human/agent-oriented text (default agent-markdown, or --human). That makes zg hard to use as a backend for scripts and wrapper tools, which need to parse results reliably rather than scrape formatted text. Concretely, a caller today has to regex the #N ... matchedBy=... score=... file:range lines, which is brittle across format changes.

A native --json flag would let tools consume query results directly, the way rg --json, semtools search -j, and similar tools already do.

Why this looks low-risk

From reading the source, the result already exists as a structured object before rendering:

  • The CLI render layer is cleanly separated in src/cli/format/context.ts (formatAgentContextResult, printCliHumanContextResult, ...), all operating on an already-structured result.
  • Result items already carry the fields a consumer wants, including score (src/engine/types.ts), matchedBy, rank, file/range, and query-group membership.

So this appears to be an additive serializer at the format layer plus arg parsing, rather than an engine change. Happy to be corrected if there's a reason the internal shape shouldn't be exposed directly.

Proposed behaviour

  • Add --json to zg query, emitting a single JSON object to stdout: a top-level envelope (query, routes, coverage, groups) with a hits array, mirroring how the human output is already grouped. Diagnostics stay on stderr so stdout is pure.
  • Output format is a single selection among agent-markdown (default), --human, and --json; passing more than one is an error.
  • Per-hit fields: rank, file (relative + absolute), range (start/end lines), matchedBy, score, per-route scores where available, queryGroup, and preview honouring --preview.
  • Score semantics are labelled explicitly, since hybrid ranking uses RRF (RRF_K = 60) while the vector route carries a cosine distance, and consumers need to know which they're getting.
  • --rg mode keeps ripgrep's own output rather than being remapped, consistent with the existing "options that replace rg's output format are rejected" stance.

Relationship to #68

Issue #68 (B) notes that failed vector/hybrid searches still print scored rows indistinguishable from real hits, so an Agent/MCP caller cannot tell whether to trust them. A structured output with explicit, labelled scores is a natural foundation for a confidence signal (and, later, an explicit low-confidence / no-strong-match flag) that programmatic callers can threshold on.

I'm happy to open a PR along these lines; flagging here first per CONTRIBUTING so the shape can be confirmed before implementation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      AltStyle によって変換されたページ (->オリジナル) /