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):
- stdout carries only the serialised payload
- status/progress/tables go to stderr
-o yaml / -o csv are likewise respected, including by models
Notes
Summary
For most commands,
-o jsonappends JSON after the human-readable rendering instead of replacing it, and the status lines / Rich tables go to stdout rather than stderr. Any| jqpipeline against those commands therefore fails, even though the JSON is present further down the stream.listenandspeakbehave correctly. Everything else I tested does not.Reproduction
The JSON does eventually arrive — it just isn't first:
dg -o json modelsdg -o json keysFetching API keys...+ tabledg -o json usageFetching usage for current month...+ summarydg -o json projectsFetching projects...+ listdg -o json read "good" --sentimentAnalyzing text...,Sentiment: positive (0.92)Which commands are affected
-o json(JSON only on stdout)listen,speakread,models,projects,keys,billing,usage,requests,membersdg -o json listen audio.mp3 \| jq '.results.channels[0].alternatives[0].transcript'works exactly as documented. The equivalent forprojects,keys,models, etc. does not.modelsadditionally ignores the format entirely —-o json,-o yamland-o csvall render the same table:Why it matters
This contradicts two promises made on cli.deepgram.com and in
llms.txt:It also affects agent use:
--agent-friendlyand 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 tohead), so the auto-switch didn't rescue it either.Expected
With
-o json(or when stdout is not a tty):-o yaml/-o csvare likewise respected, including bymodelsNotes
listen/speakreturn their result without that pre-render, which is why they behave.main@ 76ccdaf), macOS, Python 3.11.