Skip to content

Conversation

@sheikhlimon
Copy link
Contributor

@sheikhlimon sheikhlimon commented Nov 2, 2025

Summary

This pull request implements the requested --output-format json flag for the goose run command, enabling structured JSON output for programmatic parsing. The feature allows users to parse tool calls and responses programmatically, similar to Claude Code's --output-format json functionality.

Key changes:

  • Added --output-format flag with default value "text" (preserving backward compatibility)
  • Implemented JSON output mode that outputs structured data with messages, tool calls, responses, and metadata
  • Created JSON-serializable data structures for the output format
  • Modified message processing to capture data in JSON format when requested
  • Maintained all existing functionality while adding the new feature

Type of Change

  • Feature
  • Bug fix
  • Refactor / Code quality
  • Performance improvement
  • Documentation
  • Tests
  • Security fix
  • Build / Release
  • Other (specify below)

Testing

  • Manual Testing: Verified the feature works by running goose run --text "..." --output-format json and confirming structured JSON output
  • Backward Compatibility: Tested goose run --text "..." --output-format text and default behavior to ensure existing functionality preserved
  • CLI Integration: Verified the new flag appears in --help output and accepts valid values
  • Build Verification: Confirmed the project compiles successfully with cargo build and cargo check
  • Error Handling: Tested that the command still works correctly with various input scenarios

The changes have been manually validated to work as specified in the feature request while maintaining all existing functionality.

Related Issues

Relates to #4419

@angiejones angiejones requested a review from Copilot November 2, 2025 18:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds JSON output format support to the Goose CLI, allowing users to receive structured JSON responses instead of text-based output. The feature is controlled via a new --output-format command-line argument that accepts either "text" (default) or "json" values.

Key changes:

  • Added output_format field to session configuration, builder, and CLI arguments
  • Introduced JSON data structures (JsonOutput, JsonMessage, JsonToolCall, JsonToolResponse, JsonMetadata) for structured output
  • Modified message processing to capture and serialize messages, tool calls, and responses when JSON format is requested
  • Suppressed text-based rendering when JSON output is active

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
crates/goose-cli/src/session/mod.rs Added JSON structs, output_format field to CliSession, and logic to collect/serialize session data as JSON
crates/goose-cli/src/session/builder.rs Added output_format field to SessionBuilderConfig with default implementation, updated builder to pass format through
crates/goose-cli/src/cli.rs Added --output-format CLI argument with default value "text"
crates/goose-cli/src/scenario_tests/scenario_runner.rs Updated CliSession::new call to include default "text" output format
crates/goose-cli/src/commands/bench.rs Updated SessionBuilderConfig to include default "text" output format
Comments suppressed due to low confidence (1)

crates/goose-cli/src/session/mod.rs:1159

  • Similar to Comment 6, this progress_bars.log call at line 1159 is not guarded by output_format check, potentially contaminating JSON output with text messages in non-JSON mode contexts.
                                        progress_bars.log(&formatted_message);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@angiejones angiejones requested a review from Copilot November 2, 2025 18:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@angiejones
Copy link
Collaborator

thanks for your contribution! please be sure to sign the DCO

@sheikhlimon sheikhlimon force-pushed the feat/json-output-format branch from 712537b to 1fad026 Compare November 2, 2025 18:51
@sheikhlimon
Copy link
Contributor Author

sheikhlimon commented Nov 2, 2025

I've addressed all the Copilot AI suggestions from the recent code review. Happy to address any feedback.

@sheikhlimon
Copy link
Contributor Author

thanks for your contribution! please be sure to sign the DCO

Thank you for reviewing and pointing this out.

@sheikhlimon sheikhlimon force-pushed the feat/json-output-format branch from 9abdac1 to 54f2414 Compare November 2, 2025 20:38
Copy link
Collaborator

@alexhancock alexhancock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the idea and am surprised we don't support some form of this already. Left a question


let json_output = JsonOutput {
messages: json_messages,
tool_calls: json_tool_calls,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you adhering to anything that has become a standard for representing agent exchanges in json form?

Given that goose models ToolRequest and ToolResponse as message content, I think it should reflect these in the list of messages, not as separate lists.

ToolRequest(ToolRequest),
ToolResponse(ToolResponse),

Does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad.. I wasn't following any particular standard.. I'm a bit new to goose and rust. Seemed like a simple fix. I play around with json and flags stuff from time to time.. Anyway, I'll refactor this to serialize the the complete Message objects (including all MessageContent variants like ToolRequest/ToolResponse) directly in the messages array, rather than splitting them.
Just to clarify should the JSON output serialize the messages as-is using the existing serde derives on Message and MessageContent, or would you prefer a flattened/simplified format for the JSON output specifically?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"serialize the messages as-is" is what I would do

Copy link
Contributor Author

@sheikhlimon sheikhlimon Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Messages now should serialize as-is

Co-authored-by: Copilot <[email protected]>
Signed-off-by: sheikhlimon <[email protected]>

Signed-off-by: Sheikh Limon <[email protected]>
Co-authored-by: Copilot <[email protected]>
Signed-off-by: sheikhlimon <[email protected]>

Signed-off-by: Sheikh Limon <[email protected]>
Co-authored-by: Copilot <[email protected]>
Signed-off-by: sheikhlimon <[email protected]>

Signed-off-by: Sheikh Limon <[email protected]>
- Cache output_format check in process_agent_response to avoid repeated string comparisons
- Prevent empty messages from being included in JSON output
- Prevent MCP notification output leakage in JSON mode
- Add documentation for manual Default implementation in SessionBuilderConfig
- Fix test to include missing output_format field

Signed-off-by: sheikhlimon <[email protected]>

Signed-off-by: Sheikh Limon <[email protected]>
@sheikhlimon sheikhlimon force-pushed the feat/json-output-format branch from f96fe46 to d923b5c Compare November 4, 2025 05:03
@alexhancock
Copy link
Collaborator

Working nicely for me!

🐚 10:44:23 ~/Development/goose main $ ./target/debug/goose run --output-format json -t "hello"
starting session | provider: databricks model: databricks-claude-sonnet-4-5
    session id: 20251104_12
    working directory: /Users/alexhancock/Development/goose
{
  "messages": [
    {
      "id": null,
      "role": "user",
      "created": 1762271082,
      "content": [
        {
          "type": "text",
          "text": "hello"
        }
      ],
      "metadata": {
        "userVisible": true,
        "agentVisible": true
      }
    },
    {
      "id": "msg_bdrk_01GxCtrw1WHBM2oMXss8m9AF",
      "role": "assistant",
      "created": 1762271084,
      "content": [
        {
          "type": "text",
          "text": "Hello! 👋 \n\nI'm **goose**, an AI agent created by Block. I'm here to help you with a wide range of tasks, from coding and development work to answering questions and solving problems.\n\nI have access to several tools and capabilities:\n- **Code analysis and editing** - I can view, edit, and analyze code files\n- **Shell commands** - I can run commands in your terminal\n- **Chat recall** - I can search through our past conversations\n- **Extension management** - I can discover and enable additional extensions for specialized tasks\n\nSince I can see you're in the `/Users/alexhancock/Development/goose` directory, I'm ready to help with the goose project itself if needed, or anything else you'd like to work on!\n\nWhat would you like to do today?"
        }
      ],
      "metadata": {
        "userVisible": true,
        "agentVisible": true
      }
    }
  ],
  "metadata": {
    "total_tokens": 7066,
    "status": "completed"
  }
}

@sheikhlimon
Copy link
Contributor Author

sheikhlimon commented Nov 4, 2025

Getting a clippy error in goose-mcp/src/computercontroller/mod.rs:1119 (unrelated to my changes). Should I fix it here or skip?

- Remove separate JsonMessage, JsonToolCall, and JsonToolResponse structs
- Use Vec<Message> directly in JsonOutput to preserve MessageContent structure
- Fix conflict markers left from rebase in scenario_runner.rs and builder.rs

Signed-off-by: sheikhlimon <[email protected]>
@sheikhlimon sheikhlimon force-pushed the feat/json-output-format branch from cb211fd to df3aae7 Compare November 4, 2025 16:19
@alexhancock
Copy link
Collaborator

@sheikhlimon yeah those resolutions seem fine

@sheikhlimon
Copy link
Contributor Author

sheikhlimon commented Nov 4, 2025

Getting a clippy error in goose-mcp/src/computercontroller/mod.rs:1119 (unrelated to my changes). Should I fix it here or skip?

@alexhancock ok.. do i create an issue for this or are you aware already? this could be created by running cargo clippy --package goose-mcp -- -D warnings

@alexhancock alexhancock self-requested a review November 4, 2025 16:33
@alexhancock alexhancock merged commit d4a7bd3 into block:main Nov 4, 2025
13 checks passed
@alexhancock
Copy link
Collaborator

@sheikhlimon we'll deal with the other computercontroller thing

@alexhancock
Copy link
Collaborator

thanks!

katzdave added a commit that referenced this pull request Nov 4, 2025
…est-and-fix

* 'main' of github.com:block/goose:
  improve linux tray icon support (#5425)
  feat: log rotation (#5561)
  use app.isPackaged instead of checking for node env development (#5465)
  disable RPM build-ID generation to prevent package conflicts (#5563)
  Add Diagnostics Info to Q&A and Bug Report Templates (#5565)
  fix: improve server error messages to include HTTP status code (#5532)
  improvement: add useful error message when attempting to use unauthenticated cursor-agent (#5300)
  fix: unblock acp via databricks (#5562)
  feat: add --output-format json flag to goose run command (#5525)
wpfleger96 added a commit that referenced this pull request Nov 4, 2025
* main: (85 commits)
  improve linux tray icon support (#5425)
  feat: log rotation (#5561)
  use app.isPackaged instead of checking for node env development (#5465)
  disable RPM build-ID generation to prevent package conflicts (#5563)
  Add Diagnostics Info to Q&A and Bug Report Templates (#5565)
  fix: improve server error messages to include HTTP status code (#5532)
  improvement: add useful error message when attempting to use unauthenticated cursor-agent (#5300)
  fix: unblock acp via databricks (#5562)
  feat: add --output-format json flag to goose run command (#5525)
  Sessions required (#5548)
  feat: add grouped extension loading notification (#5529)
  we should run this on main and also test open models at least via ope… (#5556)
  info: print location of sessions.db via goose info (#5557)
  chore: remove yarn usage from documentation (#5555)
  cli: adjust default theme to address #1905 (#5552)
  Manual compaction counting fix + cli cleanup (#5480)
  chore(deps): bump prismjs and react-syntax-highlighter in /ui/desktop (#5549)
  fix: remove qwen3-coder from provider/mcp smoke tests (#5551)
  fix: do not build unsigned desktop app bundles on every PR in ci. add manual option. (#5550)
  fix: update Husky prepare script to v9 format (#5522)
  ...
wpfleger96 added a commit that referenced this pull request Nov 5, 2025
* main: (54 commits)
  add clippy warning for string_slice (#5422)
  improve linux tray icon support (#5425)
  feat: log rotation (#5561)
  use app.isPackaged instead of checking for node env development (#5465)
  disable RPM build-ID generation to prevent package conflicts (#5563)
  Add Diagnostics Info to Q&A and Bug Report Templates (#5565)
  fix: improve server error messages to include HTTP status code (#5532)
  improvement: add useful error message when attempting to use unauthenticated cursor-agent (#5300)
  fix: unblock acp via databricks (#5562)
  feat: add --output-format json flag to goose run command (#5525)
  Sessions required (#5548)
  feat: add grouped extension loading notification (#5529)
  we should run this on main and also test open models at least via ope… (#5556)
  info: print location of sessions.db via goose info (#5557)
  chore: remove yarn usage from documentation (#5555)
  cli: adjust default theme to address #1905 (#5552)
  Manual compaction counting fix + cli cleanup (#5480)
  chore(deps): bump prismjs and react-syntax-highlighter in /ui/desktop (#5549)
  fix: remove qwen3-coder from provider/mcp smoke tests (#5551)
  fix: do not build unsigned desktop app bundles on every PR in ci. add manual option. (#5550)
  ...
fbalicchia pushed a commit to fbalicchia/goose that referenced this pull request Nov 7, 2025
Signed-off-by: sheikhlimon <[email protected]>
Signed-off-by: Sheikh Limon <[email protected]>
Signed-off-by: fbalicchia <[email protected]>
@emma-squared emma-squared mentioned this pull request Nov 11, 2025
10 tasks
@sheikhlimon sheikhlimon deleted the feat/json-output-format branch November 13, 2025 08:16
BlairAllan pushed a commit to BlairAllan/goose that referenced this pull request Nov 29, 2025
Signed-off-by: sheikhlimon <[email protected]>
Signed-off-by: Sheikh Limon <[email protected]>
Signed-off-by: Blair Allan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants