byob-go-cli

Opt-in structured export via --json / --jq / --template

byob-output.2 output

Problem: scripters shouldn't have to parse your TTY output with regex. Every serious CLI needs a structured mode.

Idea: commands that print "resources" accept three opt-in flags: --json <fields> (emit JSON array with the listed fields), --jq <expr> (run the JSON through a jq filter before printing), --template <tmpl> (run the JSON through Go text/template). Resource types implement an ExportData(fields) map[string]any method that produces a stable JSON shape independent of the TTY rendering.

Tradeoffs: maintaining the JSON schema is a contract. Version it if needed. Alternative: --output=json that emits a fixed shape — simpler but less flexible. --json <fields> makes the client pick what they want.

Design

type Exporter interface {
    ExportData(fields []string) map[string]any
}

func AddJSONFlags(cmd *cobra.Command, exp *exportOptions) {
    cmd.Flags().StringSliceVar(&exp.Fields, "json", nil,
        "output JSON with the given fields")
    cmd.Flags().StringVar(&exp.JQ, "jq", "",
        "filter --json output with a jq expression")
    cmd.Flags().StringVar(&exp.Template, "template", "",
        "format --json output with a Go template")
}

// in runFunc:
if opts.JSON != nil {
    data := make([]map[string]any, 0, len(items))
    for _, it := range items {
        data = append(data, it.ExportData(opts.JSON))
    }
    return writeJSON(opts.IO.Out, data, opts.JQ, opts.Template)
}
// else fall through to table renderer