Skip to content

-o json is not honoured by most commands: human output precedes JSON on stdout, breaking pipes #98

Description

@GregHolmes

Summary

For most commands, -o json appends JSON after the human-readable rendering instead of replacing it, and the status lines / Rich tables go to stdout rather than stderr. Any | jq pipeline against those commands therefore fails, even though the JSON is present further down the stream.

listen and speak behave correctly. Everything else I tested does not.

Reproduction

$ dg -o json projects 2>/dev/null | head -c 130
Fetching projects...
Found 1 project(s):
  • <name>
    ID: <uuid>

The JSON does eventually arrive — it just isn't first:

command stdout bytes JSON starts at byte human text before it
dg -o json models 114,720 37,012 37 KB Rich table
dg -o json keys 2,255 1,252 Fetching API keys... + table
dg -o json usage 1,660 877 Fetching usage for current month... + summary
dg -o json projects 331 124 Fetching projects... + list
dg -o json read "good" --sentiment after Analyzing text..., Sentiment: positive (0.92)

Which commands are affected

honours -o json (JSON only on stdout) does not
listen, speak read, models, projects, keys, billing, usage, requests, members

dg -o json listen audio.mp3 \| jq '.results.channels[0].alternatives[0].transcript' works exactly as documented. The equivalent for projects, keys, models, etc. does not.

models additionally ignores the format entirely — -o json, -o yaml and -o csv all render the same table:

$ for f in json yaml csv; do dg -o $f models | head -c 30; done
   Deepgram Models   ...      (identical for all three)

Why it matters

This contradicts two promises made on cli.deepgram.com and in llms.txt:

Status messages always go to stderr to keep stdout clean.

Every command writes structured data to stdout and diagnostics to stderr. Switch formats with -o json or let it auto-switch when piped.

It also affects agent use: --agent-friendly and the auto-JSON-when-piped behaviour are advertised for scripting, and a polluted stdout defeats both. Note stdout was a pipe in every case above (piped to head), so the auto-switch didn't rescue it either.

Expected

With -o json (or when stdout is not a tty):

  1. stdout carries only the serialised payload
  2. status/progress/tables go to stderr
  3. -o yaml / -o csv are likewise respected, including by models

Notes

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