feat: add print mode flag to run command
Summary
Adds a -p/--print flag to the run command that enables print mode with multiple output formats, solving the feature request in #278. The implementation uses dynamic data sources to accurately reflect the actual runtime configuration.
Changes
-
Print Mode Flag: Added
-p/--printflag toruncommand -
Output Formats: Support for
text(default),json, andstream-jsonformats - Dynamic Data: Replaced hard-coded values with dynamic functions that reflect actual runtime state
-
Validation:
stream-jsonformat requires--verboseflag - Error Handling: Proper validation and error messages for edge cases
-
Backward Compatibility: Existing
runcommand behavior is unchanged
Usage Examples
Text Output (Default)
$ opencode run -p "what is 2+2?"
4
JSON Output
$ opencode run --print --output-format json "what is 2+2?"
{"type":"result","subtype":"success","is_error":false,"duration_ms":2231,"duration_api_ms":2227,"num_turns":1,"result":"4","session_id":"ses_844cdda80ffeaNCnvw65ycUC6k","total_cost_usd":0,"usage":{"input_tokens":4,"cache_creation_input_tokens":0,"cache_read_input_tokens":11329,"output_tokens":5,"server_tool_use":{"web_search_requests":0},"service_tier":"standard"}}
Stream JSON Output (with verbose)
$ opencode run -p --output-format stream-json --verbose "what is 2+2?"
{"type":"system","subtype":"init","cwd":"/path/to/project","session_id":"ses_844cdd08affeNGo8Caw4wSm6Gw","tools":["Bash","Edit","WebFetch","Glob","Grep","LS","lsp_diagnostics","lsp_hover","Read","Edit","Write","TodoWrite","TodoRead"],"mcp_servers":[],"model":"anthropic-claude-sonnet-4-20250514","permissionMode":"default","apiKeySource":"ANTHROPIC_OAUTH"}
{"type":"assistant","message":{"id":"msg_7bb322f8c001n8Ehhz6liEBL9L","type":"message","role":"assistant","model":"anthropic-claude-sonnet-4-20250514","content":[{"type":"text","text":"4"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":4,"cache_creation_input_tokens":0,"cache_read_input_tokens":11329,"output_tokens":5,"service_tier":"standard"}},"parent_tool_use_id":null,"session_id":"ses_844cdd08affeNGo8Caw4wSm6Gw"}
{"type":"result","subtype":"success","is_error":false,"duration_ms":2508,"duration_api_ms":2504,"num_turns":1,"result":"4","session_id":"ses_844cdd08affeNGo8Caw4wSm6Gw","total_cost_usd":0,"usage":{"input_tokens":4,"cache_creation_input_tokens":0,"cache_read_input_tokens":11329,"output_tokens":5,"server_tool_use":{"web_search_requests":0},"service_tier":"standard"}}
Validation & Error Handling
Stream-JSON requires verbose flag
$ opencode run -p --output-format stream-json "test"
Error: When using --print, --output-format=stream-json requires --verbose
Empty message validation
$ opencode run -p
Error: No message provided
Features
-
Multiple Output Formats:
-
text: Simple text output (default) -
json: Structured JSON with session metadata, timing, costs, and token usage -
stream-json: Multiple JSON objects including system init, assistant message, and final result
-
-
Dynamic Runtime Data: System init output reflects actual configuration:
-
Tools: Shows available tools from
Provider.tools()and active MCP tools -
MCP Servers: Lists active MCP server names from
MCP.clients() - API Key Source: Detects actual authentication method (API key, OAuth, env vars)
-
Tools: Shows available tools from
-
Comprehensive Metadata: JSON formats include:
- Session ID and timing information
- API call duration and total duration
- Token usage (input, output, cache read/write)
- Cost tracking
- Error status and handling
-
Validation:
-
stream-jsonformat requires--verboseflag - Empty message validation with appropriate error responses
- Proper exit codes for error conditions
-
-
Backward Compatibility: Normal
runcommand behavior is completely unchanged
Implementation Details
- Integrated into existing
RunCommandrather than creating a separate command - Reuses existing session management and chat infrastructure
- Maintains all existing
runcommand functionality (continue, session, share, model options) - Clean separation between print mode and interactive mode logic
- Dynamic data functions that query actual runtime state instead of using hard-coded values
- Proper TypeScript interfaces for all output formats
Testing
All output formats and validation scenarios have been tested:
- ✅ Text output format
- ✅ JSON output format with full metadata
- ✅ Stream-JSON output format with verbose mode
- ✅ Dynamic tools, MCP servers, and API key source detection
- ✅ Validation error for stream-json without verbose
- ✅ Empty message validation
- ✅ Normal run command behavior unchanged
- ✅ Error handling and exit codes
Closes #278
🤖 Generated with opencode
https://opencode.ai/s/YvSr19ug
+1 for this!
Curious as to the status of this as it seems to have stalled out and is collecting dust. The output format is a pretty big piece of functionality that a lot of Claude Code frameworks use so having it here is one less reason for people to use Claude Code