Skip to content

Add built-in --jq flag via gojq#101

Open
robzolkos wants to merge 11 commits intomasterfrom
rz/built-in-jq
Open

Add built-in --jq flag via gojq#101
robzolkos wants to merge 11 commits intomasterfrom
rz/built-in-jq

Conversation

@robzolkos
Copy link
Collaborator

@robzolkos robzolkos commented Mar 13, 2026

Summary

  • Add --jq persistent flag powered by gojq (pure Go jq implementation) so users and agents can filter/extract JSON inline without needing an external jq binary installed
  • --jq implies --json (or --quiet with --agent), string results print as plain text, invalid expressions surface parse errors immediately
  • Early validation: parse + compile before RunE so invalid expressions are rejected with no side effects
  • Sentinel error infrastructure (ErrJQValidation, ErrJQNotSupported, ErrJQConflict, ErrJQRuntime) with IsJQError predicate for proper error handling
  • Env access via env.VAR and $ENV.VAR in jq expressions
  • Compact single-line JSON output (no indented encoder)
  • Error handler hardening: jq-related errors bypass the jq filter to avoid rendering loops
  • Command guards: --jq rejected by completion, skill (non-interactive), and version
  • Version command outputs plain text (fizzy version X.Y.Z) matching basecamp-cli
  • Update SKILL.md examples to use --jq flag instead of piping to external jq

Mirrors the same approach from basecamp/basecamp-cli#286, including Jeremy's improvements for error types, early validation, env access, compact output, and command coverage.

Add a --jq persistent flag powered by gojq (pure Go jq implementation)
so users and agents can filter/extract JSON inline without needing an
external jq binary installed.

- --jq implies --json (or --quiet with --agent), no need to pass both
- String results print as plain text, everything else as indented JSON
- Invalid expressions surface parse errors immediately
- Non-JSON output passes through unchanged

Update SKILL.md to use --jq flag syntax instead of piping to external
jq, and update README with new output format examples.
@robzolkos robzolkos requested a review from a team as a code owner March 13, 2026 00:35
Copilot AI review requested due to automatic review settings March 13, 2026 00:35
@github-actions github-actions bot added the enhancement New feature or request label Mar 13, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a built-in --jq flag (powered by gojq) to filter/extract JSON output directly in the fizzy CLI, and updates documentation/examples to use it instead of piping to an external jq binary.

Changes:

  • Introduces --jq as a persistent flag and wires it into output formatting/writing.
  • Adds jqWriter implementation plus unit/integration tests around filtering behavior.
  • Updates SKILL.md/README examples and the generated CLI surface list to document the new flag.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
internal/commands/root.go Registers --jq, makes it imply JSON/quiet format, and wraps output writer with a jq-filtering writer.
internal/commands/jq.go Implements jqWriter to apply a compiled gojq query to JSON output.
internal/commands/jq_test.go Adds tests for flag registration, format implications, writer behavior, and cobra integration.
internal/commands/format_test.go Resets cfgJQ in shared test harness setup.
skills/fizzy/SKILL.md Updates skill docs/examples to use --jq instead of external jq piping.
internal/skills/SKILL.md Mirrors SKILL docs updates for internal skill copy.
README.md Updates output format examples to use --jq.
SURFACE.txt Updates generated command surface to include --jq everywhere.
go.mod / go.sum Adds github.com/itchyny/gojq (+ indirect deps) and bumps some indirect versions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/jq.go">

<violation number="1" location="internal/commands/jq.go:46">
P2: Write error from `fmt.Fprintln` is silently discarded. If writing to `dest` fails, this path reports success while the parallel JSON-encoding path correctly propagates errors. Check the error to keep both paths consistent.</violation>
</file>

<file name="internal/commands/root.go">

<violation number="1" location="internal/commands/root.go:237">
P2: `--jq` combined with non-JSON format flags (`--styled`, `--markdown`, `--ids-only`, `--count`) silently ignores the jq filter. The explicit format flag wins in the switch, producing non-JSON output that passes through `jqWriter` unchanged. Consider returning an error for these combinations, similar to the `--agent --styled` check.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

- Check fmt.Fprintln error in jqWriter to avoid silently swallowing
  write failures (broken pipe, closed stdout)
- Reject --jq with incompatible format flags (--styled, --markdown,
  --ids-only, --count) with a clear error message
- Clarify docs: --jq implies --json, or --quiet with --agent
- Add tests for all --jq + format flag combinations
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a built-in --jq persistent flag (powered by gojq) so users/agents can filter/extract JSON inline without relying on an external jq binary, and updates docs/examples accordingly.

Changes:

  • Introduces --jq flag and integrates it into output format resolution (including --jq--json, or --quiet with --agent).
  • Implements a jqWriter to apply jq expressions to JSON output and adds tests covering flag interactions and filtering behavior.
  • Updates SKILL/README examples to use --jq instead of piping to external jq, and updates dependencies + surface snapshot.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/commands/root.go Registers --jq, validates flag compatibility, and wraps the output writer to apply filtering.
internal/commands/jq.go Adds the jq-filtering io.Writer implementation.
internal/commands/jq_test.go Adds unit + integration tests for --jq behavior and output.
internal/commands/format_test.go Resets cfgJQ in the cobra test harness to avoid test leakage.
skills/fizzy/SKILL.md Updates skill guidance and examples to prefer --jq.
internal/skills/SKILL.md Mirrors the skill doc updates for the embedded/internal copy.
README.md Updates output-format examples to demonstrate --jq.
go.mod / go.sum Adds gojq and related indirect deps; bumps a couple of indirect deps.
SURFACE.txt Records the new --jq flag across commands in the surface snapshot.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Error responses (ok: false) now bypass the jq filter so error messages
are never hidden by expressions like .data that would render them as null.
Port improvements from basecamp-cli PR #286 (Jeremy's commits):

Sentinel error infrastructure:
- errJQUnsupported sentinel with ErrJQValidation, ErrJQNotSupported,
  ErrJQConflict, ErrJQRuntime constructors and IsJQError predicate

Early validation in PersistentPreRunE (root.go):
- Parse + Compile before RunE so invalid expressions are rejected with
  no side effects
- Mutual exclusion: --jq with --ids-only or --count returns ErrJQConflict

Error handler hardening (root.go Execute):
- Bypass jq filter when rendering jq-related errors to avoid loops

jqWriter improvements (jq.go):
- Store *gojq.Code instead of *gojq.Query
- Compile with gojq.WithEnvironLoader for env.VAR / $ENV.VAR access
- Compact single-line JSON via json.Marshal (no indented encoder)
- All errors return structured *output.Error with CodeUsage and the
  errJQUnsupported sentinel

Command guards:
- completion: reject --jq (outputs shell scripts, not JSON)
- skill (non-interactive): reject --jq (outputs raw SKILL.md)
Match basecamp-cli: version prints plain text ("fizzy version X.Y.Z")
instead of structured JSON, so --jq is not applicable.
Copilot AI review requested due to automatic review settings March 14, 2026 05:12
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/jq.go">

<violation number="1" location="internal/commands/jq.go:71">
P1: Write error from `fmt.Fprintln` is silently ignored for non-string jq results. The string branch a few lines above checks this error, but this branch does not. This means broken pipes or closed writers won't surface errors for JSON output.</violation>
</file>

<file name="internal/commands/root.go">

<violation number="1" location="internal/commands/root.go:80">
P2: Flag conflict checks should come before `Parse`/`Compile` so the user sees the actionable conflict message (`--jq cannot be used with --ids-only`) instead of a cryptic jq syntax error when both issues are present.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a built-in --jq persistent flag (powered by gojq) to let users filter/extract JSON output inline without requiring an external jq binary, and updates docs/tests accordingly.

Changes:

  • Add --jq as a persistent flag, validate expressions early, and apply filtering via an io.Writer wrapper.
  • Define jq-specific error constructors/sentinel detection and block --jq on commands that don’t emit JSON envelopes.
  • Update README/SKILL docs to use --jq instead of piping to external jq; add comprehensive tests and update module deps.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
skills/fizzy/SKILL.md Updates skill guidance/examples to use built-in --jq instead of external jq.
internal/skills/SKILL.md Mirrors SKILL doc updates for embedded/internal skill distribution.
internal/errors/errors.go Adds jq-specific error constructors and IsJQError sentinel detection.
internal/errors/errors_test.go Adds unit tests for the new jq error constructors/sentinel behavior.
internal/commands/root.go Registers --jq, validates/compiles early, wires jq writer, adjusts format resolution and error rendering.
internal/commands/jq.go Introduces jqWriter that applies compiled jq filters to JSON output.
internal/commands/jq_test.go Adds tests for flag behavior, writer filtering, passthrough, env access, and command-level rejections.
internal/commands/version.go Rejects --jq for version and changes version output to plain text.
internal/commands/skill.go Rejects --jq for skill when in machine-output mode.
internal/commands/completion.go Rejects --jq for completion script generation.
internal/commands/format_test.go Resets cfgJQ in the Cobra integration-test helper to avoid state leakage.
README.md Updates output format examples to showcase --jq usage.
SURFACE.txt Records the new --jq flag in the surface area manifest.
go.mod Adds gojq (+ indirect deps) and bumps a few indirect dependencies.
go.sum Updates checksums for the new/updated dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Check write error from fmt.Fprintln for non-string jq results
- Move flag conflict checks before Parse/Compile so the user sees
  the actionable conflict message first
- Rename errJQUnsupported sentinel to errJQ (covers all jq error types)
- Update IsJQError comment to include runtime failures
- Return original error from newJQWriter instead of re-wrapping (preserves
  Cause sentinel and structured fields)
Copilot AI review requested due to automatic review settings March 14, 2026 05:20
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a built-in --jq persistent flag to the Fizzy CLI (powered by gojq) so users can filter/extract JSON inline without relying on an external jq binary, and updates docs/tests accordingly.

Changes:

  • Add --jq flag with early parse/compile validation and a streaming jqWriter that filters JSON output (with env access + compact output).
  • Introduce jq-specific sentinel errors (ErrJQValidation, ErrJQNotSupported, ErrJQConflict, ErrJQRuntime) and an IsJQError predicate for error handling/bypass.
  • Update README + SKILL docs/examples to prefer --jq, and add comprehensive tests for jq behavior and flag interactions.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
skills/fizzy/SKILL.md Updates user/agent guidance and examples to use built-in --jq instead of piping to external jq.
internal/skills/SKILL.md Mirrors SKILL documentation updates for internal skill content.
internal/errors/errors.go Adds jq sentinel error constructors and IsJQError helper.
internal/errors/errors_test.go Adds unit tests covering the new jq error constructors and predicate behavior.
internal/commands/root.go Registers --jq, validates expressions early, wraps output writer with jq filtering, and bypasses jq for jq-related errors.
internal/commands/jq.go Implements jqWriter that applies compiled jq filters to JSON output (passthrough for non-JSON and ok:false envelopes).
internal/commands/jq_test.go Adds extensive tests for jq writer behavior, early validation, env access, compact output, edge cases, and command-level rejection.
internal/commands/version.go Changes version output to plain text and rejects --jq.
internal/commands/skill.go Rejects --jq when skill runs in machine-output mode.
internal/commands/completion.go Rejects --jq for completion script generation.
internal/commands/format_test.go Resets cfgJQ in integration helper to avoid test state leakage.
go.mod Adds github.com/itchyny/gojq dependency (and related indirect deps).
go.sum Records checksums for new/updated module dependencies.
SURFACE.txt Updates CLI surface/flag inventory to include --jq across commands.
README.md Updates output-format examples to demonstrate built-in --jq filtering.
Comments suppressed due to low confidence (1)

internal/commands/root.go:101

  • When resolveFormat() returns an error while cfgJQ is set (e.g. --jq combined with --styled/--markdown or multiple format flags), this path returns a plain output.Error that is not tagged as a jq sentinel. In Execute(), only IsJQError(err) triggers rebuilding the output writer to JSON/quiet, so these errors can render in FormatAuto (styled on TTY) even though --jq implies machine output. Consider wrapping these resolveFormat errors into errors.ErrJQConflict(...) (or otherwise tagging them as jq errors), or updating Execute() to force JSON/quiet output whenever cfgJQ is non-empty to keep error output consistent and machine-consumable.
		// Resolve output format from parsed flags (must happen post-parse).
		format, err := resolveFormat()
		if err != nil {
			return &output.Error{Code: output.CodeUsage, Message: err.Error()}
		}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

PersistentPreRunE now caches the compiled *gojq.Code and passes it
to newJQWriterWithCode, avoiding a redundant parse + compile cycle.
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/jq.go">

<violation number="1" location="internal/commands/jq.go:41">
P2: `compileJQ` duplicates the parse+compile logic already in `newJQWriter`. Refactor `newJQWriter` to delegate to the new helpers so compilation options are maintained in one place.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

newJQWriter now delegates to compileJQ so parse+compile options
are maintained in one place.
Copilot AI review requested due to automatic review settings March 14, 2026 05:31
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class JSON filtering to the Fizzy CLI via a new persistent --jq flag (powered by gojq), so users/agents can extract/transform JSON without an external jq binary.

Changes:

  • Introduce --jq flag with early validation/compilation and a writer wrapper that filters JSON output (including env access and compact output behavior).
  • Add jq-specific sentinel errors (ErrJQValidation, ErrJQNotSupported, ErrJQConflict, ErrJQRuntime) and tests.
  • Update docs/examples to prefer --jq over piping to jq, and adjust version output formatting.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/commands/root.go Registers --jq, validates/compiles early, wraps output writer, and hardens error handling for jq-related failures
internal/commands/jq.go Implements jqWriter and compileJQ using gojq + env loader
internal/commands/jq_test.go Adds extensive unit/integration coverage for --jq behavior and edge cases
internal/errors/errors.go Adds jq sentinel error constructors and IsJQError predicate
internal/errors/errors_test.go Tests jq error constructors and IsJQError behavior
internal/commands/version.go Rejects --jq and prints version as plain text
internal/commands/completion.go Rejects --jq for completion generation
internal/commands/skill.go Rejects --jq when skill is in machine/non-interactive mode
internal/commands/format_test.go Resets cfgJQ between cobra integration test runs
README.md Documents built-in --jq usage in output format examples
skills/fizzy/SKILL.md Updates skill docs/examples to use --jq instead of external jq
internal/skills/SKILL.md Same as above for the internal skill copy
go.mod / go.sum Adds gojq and indirect deps; bumps some indirect versions
SURFACE.txt Records new --jq flag across commands

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Re-resolve format via resolveFormat() so --agent --json stays JSON
- Use outWriter instead of os.Stdout to respect test mode buffer
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/root.go">

<violation number="1" location="internal/commands/root.go:202">
P2: Silently discarding the error from `resolveFormat()` causes the format to default to `FormatAuto` (zero value) when the JQ error is itself a flag conflict. In that case `resolveFormat()` hits the same `--jq` incompatibility check and returns an error. Fall back to a sensible default when resolution fails so the error still renders in a predictable format.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

When --jq conflicts with another format flag (e.g. --styled), resolveFormat()
returns an error. Fall back to FormatJSON (or FormatQuiet with --agent/--quiet)
instead of defaulting to FormatAuto.
Copilot AI review requested due to automatic review settings March 14, 2026 05:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a built-in --jq persistent flag (powered by gojq) to filter/extract JSON output inline, along with supporting error types, command guards, and updated documentation/examples.

Changes:

  • Introduces jq filtering at the output-writer layer with early parse/compile validation and compact output behavior.
  • Adds jq-specific sentinel error constructors (ErrJQValidation, ErrJQNotSupported, ErrJQConflict, ErrJQRuntime) plus an IsJQError predicate and associated tests.
  • Updates docs (README + SKILL guides) and CLI surface metadata to document and demonstrate --jq.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/commands/root.go Registers --jq, validates/compiles jq early, wraps output writer, and bypasses jq filtering when rendering jq-related errors.
internal/commands/jq.go Implements jqWriter and compileJQ using gojq, including env access and compact output formatting.
internal/commands/jq_test.go Adds extensive unit/integration tests for jq filtering, conflicts, env access, early validation, and command-level rejection.
internal/errors/errors.go Adds sentinel jq error constructors and IsJQError helper.
internal/errors/errors_test.go Adds coverage for the jq error constructors and IsJQError behavior.
internal/commands/version.go Switches version output to plain text and rejects --jq.
internal/commands/completion.go Rejects --jq for completion generation.
internal/commands/skill.go Rejects --jq for non-interactive skill output.
internal/commands/format_test.go Ensures cfgJQ is reset in shared test helper path.
README.md Updates output-format examples to use --jq instead of external jq.
skills/fizzy/SKILL.md Updates skill guidance/examples to use built-in --jq.
internal/skills/SKILL.md Mirrors SKILL.md updates for internal skill content.
go.mod / go.sum Adds github.com/itchyny/gojq and related indirect dependencies; updates a few indirect versions.
SURFACE.txt Updates CLI surface listing to include --jq across commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants