Skip to content

cli: session export only supports JSON — add --format md #59904

Open

Description

@zseagate

Summary

opencode session export can only emit JSON. There is no way to get a
human-readable transcript from the CLI, which is the most common reason to
export a session (archiving, sharing, pasting into docs/issues). Add a
--format <json|md> flag (or --markdown) that renders the same session data
as Markdown.

Environment

  • opencode version: 2.2.0
  • OS: Linux 6.8.0-147-generic (x64)
  • Terminal: TERM=xterm-256color, COLORTERM=truecolor, TERM_PROGRAM unset
  • Shell: /bin/bash
  • Install/channel: release, opencode --version → opencode v2.2.0
  • Active plugins: none (global opencode.json only sets $schema; no .opencode/plugin directories)

Reproduction

  1. opencode session export --help → the only flag is --sanitize; no format option.
  2. opencode session export <session-id> > session.json → JSON only, regardless of --sanitize.
  3. Check https://opencode.ai/v2/docs/cli → no Markdown/format option documented either.

Expected Behavior

A built-in way to produce Markdown directly, e.g.:

opencode session export <session-id> --format md -o session.md

Suggested rendering (what a user would otherwise write by hand):

  • a small metadata table at the top (session id, directory, start/update time, model, message count, cost, token usage)
  • ## user / ## assistant sections per message
  • assistant reasoning collapsed in <details> blocks
  • tool calls collapsed, titled by a short summary (command / file path), with input JSON and output in fenced blocks
  • optional --no-tools / --no-reasoning to keep the transcript compact
  • --sanitize should still apply to the Markdown output

Actual Behavior

Only JSON is available, so every user has to write their own renderer. Session
data is well structured (info + messages[] with user / assistant /
compaction / model-switched / system / idle types, and assistant
content[] parts of type text / reasoning / tool), so rendering is cheap
and lossless.

Additional Context

  • Possible related truncation bug: when the JSON is consumed through a pipe
    (e.g. Python subprocess.run(..., capture_output=True)), the payload was
    truncated at ~250 KB and failed to parse (Unterminated string starting at line 2780), while opencode session export <id> > file.json produced the
    complete 1.1 MB document. Worth checking stdout flushing on process exit; it
    makes scripted use of the current export unreliable.
  • --sanitize behaves as a full redaction, not a filter: every message body
    becomes [redacted:<kind>:<msg-id>], so the sanitized export is only usable
    for sharing structure. For a Markdown export this is fine, but it may be
    worth documenting explicitly.
  • Related but different issue: /export (TUI) and opencode export (CLI) are unrelated commands with the same name — causes silent-looking import failures #48105 (TUI /export vs opencode export
    naming confusion).
  • Workaround used in the meantime: a small Python script that runs the JSON
    export, then renders the Markdown as described above (metadata table,
    collapsible reasoning/tool blocks). Functionally fine, but it has to be
    maintained by every user who needs this.

Activity

  1. opencodejr commented on Oct 28, 2026

    @opencodejr

    Thanks for the detailed request! If I understand it right, you'd like opencode session export to have a --format md option (ideally with switches to leave out tools and reasoning, and still honoring --sanitize) that renders the session as a readable Markdown transcript instead of only JSON.

    I checked the code: the CLI export always writes JSON and only defines --sanitize, so this would be a new option. The TUI's /export already has a Markdown formatter with thinking/tool toggles, which could be a starting point. Maintainers will consider this as a feature request.

    Related issues:

  2. zseagate commented on Nov 1, 2026

    @zseagate
    Author

    Thanks for triaging and for the pointers — yes, that's exactly the request: --format json|md (JSON staying the default for compatibility), plus --no-tools / --no-reasoning, with --sanitize still applied to the Markdown output.

    A few data points that may help:

    1. The pipe truncation still reproduces on v2.2.5 (relevant to #57266 / #57347)

    Using a long session (794 messages) as the fixture:

    opencode session export <id> > a.json          # 4,482,919 bytes, valid JSON
    opencode session export <id> 2>/dev/null | cat > b.json
                                                   # 2,097,152 bytes (exactly 2 MiB), invalid JSON

    An earlier run through | wc -c gave 2,621,440 bytes (exactly 2.5 MiB). Both are suspiciously round MiB boundaries, and the piped payload fails with Unterminated string starting at line 2882 column 25. Redirecting to a file is currently the only reliable way to consume the export from a script.

    2. -o/--output would sidestep this entirely

    If --format md also gets -o/--output <file>, scripted use never has to depend on stdout redirection, which also avoids the class of bug in #57266 regardless of whether it is fixed. That would also make --format md usable with --sanitize for CI-style exports.

    3. Reusing the TUI formatter is the right call, with one caveat

    Agreed with the plan in #55542 to move the TUI Markdown formatter into shared code and reuse it from the CLI. One argument in favor of rendering from the export payload rather than the TUI's in-memory thread: the JSON export contains the complete history, so a shared formatter driven by it is immune to the "only the loaded portion" class of issue (#50014 / #50732). As a sanity check, a small renderer over the JSON here produced the full transcript for a 794-message session — 2.0 MB, 38,959 lines, 1,054 collapsible blocks, no missing history.

    4. Suggested shape

    opencode session export [<id>] [--format json|md] [--output <file>]
                            [--no-tools] [--no-reasoning] [--sanitize]
    • default --format json, so existing scripts keep working;
    • Markdown: metadata table (id, directory, time range, model, message count, cost, tokens), ## user / ## assistant sections, reasoning and tool calls collapsed in <details>, tool calls titled by command/path with input JSON and fenced output;
    • --no-tools / --no-reasoning for a compact transcript;
    • --sanitize applies before rendering (note: it currently redacts bodies to [redacted:<kind>:<id>], which is fine for structure sharing but worth documenting).

    Happy to test release builds against a long session, or share the ~250-line Python renderer if that is useful as a reference for the shared formatter's expected output. Just say the word.

  3. willsmanley commented on Nov 4, 2026

    @willsmanley

    Would you take Agent Session Record (ASR) as one of the formats?

    It's an open JSONL format for agent sessions that we wrote (agentsessionrecord.org), a sibling to ACP for the record a session leaves behind. Sessions from OpenCode, Claude Code, Codex and others can then be searched and traced back from a commit with the same tools.

    We have a patch that adds opencode session export <id> --format agent-session. It's rebased on latest and passes lint, typecheck and tests: https://github.com/agentsessionrecord/asr/tree/main/upstream/opencode

    Should we open a feature request for it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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