How to Use gogcli --json-transform and --results-only for Clean JSON Output

Use gogcli --json --results-only to strip envelope metadata and output only the primary data array, then combine it with --select=<fields> to project specific columns for script-friendly automation.

When automating workflows with steipete/gogcli, raw JSON output often includes wrapper objects containing pagination tokens and metadata. The --json-transform pipeline, controlled by the --results-only and --select flags, lets you extract clean, focused data directly from the command line without external tools like jq.

Understanding the JSON Transform Pipeline

The transformation system is implemented in internal/outfmt/outfmt.go and orchestrated through the command context. When you invoke gogcli with JSON formatting flags, the application:

  1. Parses global flags in internal/cmd/root.go
  2. Builds a JSONTransform struct and injects it into the context via outfmt.WithJSONTransform
  3. Applies transformations during outfmt.WriteJSON through applyJSONTransform

How --results-only Strips the Envelope

The --results-only flag removes wrapper objects like nextPageToken and results, emitting only the primary payload.

In internal/cmd/root.go, the flag is defined as:

type RootFlags struct {
    ResultsOnly bool   `name:"results-only" help:"In JSON mode, emit only the primary result (drops envelope fields like nextPageToken)"`
    // ...
}

The flag value is stored in a JSONTransform struct:

type JSONTransform struct {
    ResultsOnly bool
    Select      []string
}

When outfmt.WriteJSON executes, it checks for the transform and calls unwrapPrimary to extract the core data:

if t.ResultsOnly {
    anyV = unwrapPrimary(anyV)
}

The unwrapPrimary function searches for common envelope keys and returns the first non-metadata field, making it ideal for piping into jq or other JSON processors.

Projecting Fields with --select

The --select flag (aliased as --fields in some contexts) projects specific fields from the JSON output, supporting dot-path notation for nested objects.

Defined in internal/cmd/root.go:

Select string `name:"select" aliases:"pick,project" help:"In JSON mode, select comma-separated fields (best-effort; supports dot paths)"`

The transformation applies via selectFields and selectFieldsFromItem, which recursively walk arrays and objects to retain only requested paths.

Practical Usage Examples

Combine both flags for automation scripts that need clean, minimal JSON.

Extract only the primary array:

gogcli drive ls --json --results-only

Output becomes a raw array without the {"files": [...], "nextPageToken": "..."} wrapper.

Project specific columns:

gogcli drive ls --json --results-only --select=id,name,size

Result:

[
  { "id": "abc123", "name": "report.pdf", "size": 12345 },
  { "id": "def456", "name": "notes.txt", "size": 678 }
]

Using the --fields alias:

gogcli calendar events --json --fields=summary,start,end

Implementation Deep Dive

The transform pipeline relies on context propagation through the command tree. In internal/cmd/root.go, the PersistentPreRun hook initializes the transform:

ctx = outfmt.WithJSONTransform(ctx, outfmt.JSONTransform{
    ResultsOnly: cli.ResultsOnly,
    Select:      splitCommaList(cli.Select),
})

This context is passed to all subcommands. When a command calls outfmt.WriteJSON(ctx, w, v), the function retrieves the transform via JSONTransformFromContext and applies it through applyJSONTransform.

The unwrapPrimary function in internal/outfmt/outfmt.go implements the envelope removal logic by checking for standard response keys like results, files, and threads, returning the first match to eliminate pagination metadata.

Summary

  • Use --results-only to strip envelope metadata and output only the primary data array from gogcli JSON responses.
  • Use --select=<fields> to project specific fields, supporting dot notation for nested objects.
  • Combine both flags for clean, script-friendly JSON output ideal for piping into jq or other automation tools.
  • The transformation pipeline is implemented in internal/outfmt/outfmt.go and activated via context in internal/cmd/root.go.

Frequently Asked Questions

What is the difference between --results-only and --select?

--results-only removes the outer wrapper object (containing metadata like nextPageToken) and outputs only the primary data array or object. --select filters the fields within each object, keeping only the specified properties. Use --results-only for envelope removal and --select for field projection.

Can I use dot notation with --select?

Yes. The --select flag supports dot-path notation for nested fields. For example, --select=name,owner.displayName extracts the top-level name field and the displayName property nested within the owner object.

Where are these flags defined in the source code?

The flags are defined in the RootFlags struct in internal/cmd/root.go (lines 30-39). The transformation logic is implemented in internal/outfmt/outfmt.go, specifically in the applyJSONTransform, unwrapPrimary, and selectFields functions.

Is --fields the same as --select?

Yes, --fields is an alias for --select in most contexts. The root command defines --select with aliases including pick and project, and some subcommands rewrite --fields to use the global --select mechanism for consistent JSON field projection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →