You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
cfl's primary reader/writer is an LLM agent (CLI agents, MCP integrations), not a shell script. With that lens, -o json is the worst output mode we ship:
It's lossier than the human-readable views.page view -o json returns the content field as escape-encoded XHTML (<h2>...</h2>), even though the default table view already shows clean markdown. An agent has to mentally unescape the JSON string back into XHTML before it can be used — meanwhile --raw --content-only already gives us lossless XHTML in one step.
The "agent artifact" promise isn't kept.tools/cfl/CLAUDE.md says the JSON agent artifact returns "content as markdown"; in practice it returns XHTML (see view.go:130 — the source comment openly admits "until 7/8 test(cfl): establish fidelity fixtures for agent-facing content artifacts #196 validates markdown"). The format that's supposedly for agents is the one with the biggest doc/reality mismatch.
Double-escaped emoji.search -o json excerpts come through with literal \\uD83D\\uDDD3 (eight characters representing one codepoint), not a real surrogate pair. Agent has to know to decode twice.
Inconsistent shape.page list -o json returns a tidy artifact projection; page create -o json and attachment upload -o json return the raw Confluence API object (camelCase, _links, parentType, position, etc.). The contract in docs/ARTIFACT_CONTRACT.md is not uniformly applied.
Buggy in places.config show -o json emits broken pseudo-JSON (one {"key":"value (source: x)"} per line + a non-JSON footer). --full is a no-op for attachment list -o json (cfl attachment list: --full is a no-op for -o json #381).
There is no script-based consumer of cfl JSON that we know of — by design, the primary integration point is conversational. If we accept that, we can stop carrying the JSON contract and design something that's genuinely token-dense and easy for an LLM to parse on sight.
Proposal
Remove -o json entirely from cfl. The -o flag accepts table and plain only (or we collapse those too — see below).
Re-design human/agent output to be token-dense. Brainstorm in the discussion below.
Rethink --full. Currently --full only modifies JSON. If JSON is gone, --full becomes either (a) extra columns in the table view, (b) extra Key: value lines after the body for detail views, or (c) goes away entirely with the verbose set always present.
Resolve plain vs table. For detail views (page view, space view), -o plain and -o table are currently byte-identical (it's "no color" only). For list commands, -o plain is TSV. Either we keep plain strictly as the TSV mode for list-only commands and drop the redundant detail-view branch, or we drop plain entirely and use --no-color for the color toggle.
What "token-dense" should mean
Goals, in priority order:
One canonical shape per command that an LLM can parse without thinking. No "agent" vs "full" vs "raw" matrix.
Lossless markdown for page content. Today only --raw is lossless, and only as XHTML. We want lossless markdown to be the default reading mode.
No escape-encoded payloads. No <, no double-encoded surrogate pairs.
No structural redundancy. No {\"_meta\": {\"count\": N, \"hasMore\": false}} wrappers — count is wc -l and "hasMore" is one line at the bottom.
Minimal column padding. Today's ASCII tables pad with whitespace to align columns; this burns tokens. TSV or compact pipe-separated formats are tighter.
Pros: reads like email headers, trivially parseable, no escaping needed for values that don't have newlines.
G. Markdown all the way down
List commands return a markdown table. Detail commands return a markdown front-matter document. Search returns a markdown list with each result as a bullet.
Lossless for content. Maximally fluent for agents. Could double as something pasteable into Confluence/Slack.
My instinct: G or C are the most agent-friendly, with detail views landing on something like:
…and list views landing on a real markdown table. But this is a brainstorm — push back.
Open questions
Do we have downstream JSON consumers we don't know about? Worth asking on Slack / in the issue thread before removing.
What about set-credential --from-env and config test automation? Those don't currently emit JSON, so they're unaffected.
Migration path. Do we ship a feat!: breaking-change release, or gate -o json behind a deprecation period?
Apply the same treatment to jtk? Same arguments apply — the existing artifact contract is shared via atlassian-go/artifact. Worth scoping in a follow-up.
Related findings / bugs
Surfaced during the surface-inventory work (raw evidence at /tmp/cfl-outputs-60314/, summary at tools/cfl/cfl-outputs.md):
This issue is the parent for the JSON-removal + format-redesign work. Sub-issues to follow once we converge on a format.
Next step
Leave a comment with your preferred format (A–G or a hybrid), any consumer we'd break, and how aggressive you want to be on the migration (breaking release vs. deprecation window).
Motivation
cfl's primary reader/writer is an LLM agent (CLI agents, MCP integrations), not a shell script. With that lens,
-o jsonis the worst output mode we ship:page view -o jsonreturns thecontentfield as escape-encoded XHTML (<h2>...</h2>), even though the defaulttableview already shows clean markdown. An agent has to mentally unescape the JSON string back into XHTML before it can be used — meanwhile--raw --content-onlyalready gives us lossless XHTML in one step.tools/cfl/CLAUDE.mdsays the JSON agent artifact returns "content as markdown"; in practice it returns XHTML (seeview.go:130— the source comment openly admits "until 7/8 test(cfl): establish fidelity fixtures for agent-facing content artifacts #196 validates markdown"). The format that's supposedly for agents is the one with the biggest doc/reality mismatch.search -o jsonexcerpts come through with literal\\uD83D\\uDDD3(eight characters representing one codepoint), not a real surrogate pair. Agent has to know to decode twice.page list -o jsonreturns a tidy artifact projection;page create -o jsonandattachment upload -o jsonreturn the raw Confluence API object (camelCase,_links,parentType,position, etc.). The contract indocs/ARTIFACT_CONTRACT.mdis not uniformly applied.config show -o jsonemits broken pseudo-JSON (one{"key":"value (source: x)"}per line + a non-JSON footer).--fullis a no-op forattachment list -o json(cfl attachment list: --full is a no-op for -o json #381).There is no script-based consumer of cfl JSON that we know of — by design, the primary integration point is conversational. If we accept that, we can stop carrying the JSON contract and design something that's genuinely token-dense and easy for an LLM to parse on sight.
Proposal
-o jsonentirely from cfl. The-oflag acceptstableandplainonly (or we collapse those too — see below).--full. Currently--fullonly modifies JSON. If JSON is gone,--fullbecomes either (a) extra columns in the table view, (b) extraKey: valuelines after the body for detail views, or (c) goes away entirely with the verbose set always present.plainvstable. For detail views (page view,space view),-o plainand-o tableare currently byte-identical (it's "no color" only). For list commands,-o plainis TSV. Either we keepplainstrictly as the TSV mode for list-only commands and drop the redundant detail-view branch, or we dropplainentirely and use--no-colorfor the color toggle.What "token-dense" should mean
Goals, in priority order:
--rawis lossless, and only as XHTML. We want lossless markdown to be the default reading mode.<, no double-encoded surrogate pairs.{\"_meta\": {\"count\": N, \"hasMore\": false}}wrappers — count iswc -land "hasMore" is one line at the bottom.Candidate formats to discuss
(Pick or combine — this is the ideation space.)
A. TSV everywhere
B. Markdown-table-ish, no padding
C. Front-matter + body for detail views
D. Key-value lines + body (current
page viewtable, but stable)--fullfields inline.E. NDJSON (one JSON object per line, no escape-of-escape)
F. "Block" format — one field per line, blank-line-separated records
G. Markdown all the way down
My instinct: G or C are the most agent-friendly, with detail views landing on something like:
…and list views landing on a real markdown table. But this is a brainstorm — push back.
Open questions
set-credential --from-envandconfig testautomation? Those don't currently emit JSON, so they're unaffected.feat!:breaking-change release, or gate-o jsonbehind a deprecation period?atlassian-go/artifact. Worth scoping in a follow-up.Related findings / bugs
Surfaced during the surface-inventory work (raw evidence at
/tmp/cfl-outputs-60314/, summary attools/cfl/cfl-outputs.md):attachment downloadHTTP 401 on every branch (unrelated, but relevant context for the same audit).page createsilent\$EDITORfallthrough.--fullno-op forattachment list -o json.space viewvsspace listtype mismatch.This issue is the parent for the JSON-removal + format-redesign work. Sub-issues to follow once we converge on a format.
Next step
Leave a comment with your preferred format (A–G or a hybrid), any consumer we'd break, and how aggressive you want to be on the migration (breaking release vs. deprecation window).