Documentation
¶
Overview ¶
Package stdio provides a unified adapter framework for CLI tools that communicate via stdin/stdout using structured JSON protocols.
It supports two communication patterns:
- Persistent mode: Long-lived process with bidirectional JSON (e.g., Claude Code)
- Per-turn mode: New process per message (e.g., Codex exec, Gemini, OpenCode)
Adding a new CLI tool requires only implementing the CLISpec interface.
Index ¶
- func IsStdioCLIType(cliType string) bool
- type CLISpec
- type ClaudeSpec
- func (ClaudeSpec) Binary() string
- func (ClaudeSpec) BuildArgs(opts StartOptions) []string
- func (ClaudeSpec) FormatInput(message string) ([]byte, error)
- func (ClaudeSpec) FormatPermissionResponse(requestID string, optionID string) ([]byte, error)
- func (ClaudeSpec) Mode() StdioMode
- func (ClaudeSpec) Name() string
- func (ClaudeSpec) ParseLine(line string) ([]Event, error)
- type CodexSpec
- func (CodexSpec) Binary() string
- func (CodexSpec) BuildArgs(opts StartOptions) []string
- func (CodexSpec) FormatInput(message string) ([]byte, error)
- func (CodexSpec) FormatPermissionResponse(requestID, optionID string) ([]byte, error)
- func (CodexSpec) Mode() StdioMode
- func (CodexSpec) Name() string
- func (CodexSpec) ParseLine(line string) ([]Event, error)
- type Engine
- type Event
- type EventType
- type GeminiSpec
- func (GeminiSpec) Binary() string
- func (GeminiSpec) BuildArgs(opts StartOptions) []string
- func (GeminiSpec) FormatInput(message string) ([]byte, error)
- func (GeminiSpec) FormatPermissionResponse(requestID, optionID string) ([]byte, error)
- func (GeminiSpec) Mode() StdioMode
- func (GeminiSpec) Name() string
- func (GeminiSpec) ParseLine(line string) ([]Event, error)
- type NeedsStdioAdapter
- type OpenCodeSpec
- func (OpenCodeSpec) Binary() string
- func (OpenCodeSpec) BuildArgs(opts StartOptions) []string
- func (OpenCodeSpec) FormatInput(message string) ([]byte, error)
- func (OpenCodeSpec) FormatPermissionResponse(requestID, optionID string) ([]byte, error)
- func (OpenCodeSpec) Mode() StdioMode
- func (OpenCodeSpec) Name() string
- func (OpenCodeSpec) ParseLine(line string) ([]Event, error)
- type PendingPermission
- type PermissionOption
- type PermissionRequest
- type StartOptions
- type StdioAdapter
- func (a *StdioAdapter) Close() error
- func (a *StdioAdapter) CreateSession(sessionName string, opts ...cli.SessionOption) error
- func (a *StdioAdapter) GetPendingPermission(sessionName string) *PendingPermission
- func (a *StdioAdapter) HandleHookData(data []byte) (string, string, string, error)
- func (a *StdioAdapter) IsSessionAlive(sessionName string) bool
- func (a *StdioAdapter) RespondPermission(sessionName, requestID, optionID string) error
- func (a *StdioAdapter) SendInput(sessionName, input string) error
- func (a *StdioAdapter) SetEngine(engine Engine)
- func (a *StdioAdapter) StopSession(sessionName string) error
- type StdioAdapterConfig
- type StdioMode
- type StdioProcess
- type ToolUseInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsStdioCLIType ¶
IsStdioCLIType checks if a cli_type string refers to a stdio-mode adapter.
Types ¶
type CLISpec ¶
type CLISpec interface {
// Name returns the CLI tool identifier (e.g., "claude", "codex").
Name() string
// Mode returns the communication pattern for this CLI.
Mode() StdioMode
// Binary returns the command name or path to execute.
Binary() string
// BuildArgs returns command-line arguments for starting the process.
BuildArgs(opts StartOptions) []string
// ParseLine parses a single JSON line from stdout into events.
// May return zero or more events per line.
ParseLine(line string) ([]Event, error)
// FormatInput formats a user message for writing to stdin.
FormatInput(message string) ([]byte, error)
// FormatPermissionResponse formats a permission response for stdin.
// optionID is the ID from the selected PermissionOption.
FormatPermissionResponse(requestID string, optionID string) ([]byte, error)
}
CLISpec defines how to interact with a specific CLI tool. Implementing this interface is all that's needed to add a new CLI.
type ClaudeSpec ¶
type ClaudeSpec struct{}
ClaudeSpec implements CLISpec for Claude Code. Claude Code uses a persistent process with bidirectional JSON over stdio.
Launch flags:
--output-format stream-json → stdout emits NDJSON events --input-format stream-json → stdin accepts NDJSON messages --permission-prompt-tool stdio → permission requests as JSON on stdout
func (ClaudeSpec) Binary ¶
func (ClaudeSpec) Binary() string
func (ClaudeSpec) BuildArgs ¶
func (ClaudeSpec) BuildArgs(opts StartOptions) []string
func (ClaudeSpec) FormatInput ¶
func (ClaudeSpec) FormatInput(message string) ([]byte, error)
func (ClaudeSpec) FormatPermissionResponse ¶
func (ClaudeSpec) FormatPermissionResponse(requestID string, optionID string) ([]byte, error)
FormatPermissionResponse writes a control_response for allow or deny. optionID "allow" → allow, anything else → deny.
func (ClaudeSpec) Mode ¶
func (ClaudeSpec) Mode() StdioMode
func (ClaudeSpec) Name ¶
func (ClaudeSpec) Name() string
type CodexSpec ¶
type CodexSpec struct{}
CodexSpec implements CLISpec for OpenAI Codex CLI. Codex uses per-turn mode: each invocation is a separate process. Session continuity is achieved via `codex exec resume --last`.
Launch pattern:
First turn: codex exec --json - (reads prompt from stdin) Resume: codex exec resume --last --json -
func (CodexSpec) BuildArgs ¶
func (CodexSpec) BuildArgs(opts StartOptions) []string
func (CodexSpec) FormatPermissionResponse ¶
FormatPermissionResponse is not applicable for per-turn mode.
type Engine ¶
type Engine interface {
SendToBot(platform, channel, message string)
SendResponseToSession(sessionName, message string)
SendPermissionPrompt(sessionName, message string)
}
Engine interface matches cli.Engine — duplicated here to avoid circular import (this package is under internal/cli/).
type Event ¶
type Event struct {
Type EventType
Text string // For EventText and EventResult
ToolUse *ToolUseInfo // For EventToolUse
Permission *PermissionRequest // For EventPermission
Error error // For EventError
Done bool // True when the turn is fully complete
SessionID string // Populated when a new session is detected
}
Event represents a single event from a CLI process.
type EventType ¶
type EventType int
EventType identifies the kind of event emitted by a CLI process.
type GeminiSpec ¶
type GeminiSpec struct{}
GeminiSpec implements CLISpec for Google Gemini CLI. Gemini uses per-turn mode: each invocation is a separate process. Session continuity is achieved via --resume latest.
Launch pattern:
First turn: gemini --output-format stream-json -p PROMPT Resume: gemini --resume latest --output-format stream-json -p PROMPT
func (GeminiSpec) Binary ¶
func (GeminiSpec) Binary() string
func (GeminiSpec) BuildArgs ¶
func (GeminiSpec) BuildArgs(opts StartOptions) []string
func (GeminiSpec) FormatInput ¶
func (GeminiSpec) FormatInput(message string) ([]byte, error)
FormatInput returns nil — Gemini takes prompt via -p flag, not stdin.
func (GeminiSpec) FormatPermissionResponse ¶
func (GeminiSpec) FormatPermissionResponse(requestID, optionID string) ([]byte, error)
FormatPermissionResponse is not applicable for per-turn mode.
func (GeminiSpec) Mode ¶
func (GeminiSpec) Mode() StdioMode
func (GeminiSpec) Name ¶
func (GeminiSpec) Name() string
type NeedsStdioAdapter ¶
type NeedsStdioAdapter interface {
GetPendingPermission(sessionName string) *PendingPermission
RespondPermission(sessionName, requestID, optionID string) error
}
NeedsStdioAdapter is a marker interface that adapters can implement to indicate they need the stdio permission flow. The engine checks for this interface to route permission responses.
type OpenCodeSpec ¶
type OpenCodeSpec struct{}
OpenCodeSpec implements CLISpec for OpenCode CLI. OpenCode uses per-turn mode: each invocation is a separate process. Session continuity is achieved via --continue flag.
Launch pattern:
First turn: opencode run --format json PROMPT Resume: opencode run --format json --continue PROMPT
func (OpenCodeSpec) Binary ¶
func (OpenCodeSpec) Binary() string
func (OpenCodeSpec) BuildArgs ¶
func (OpenCodeSpec) BuildArgs(opts StartOptions) []string
func (OpenCodeSpec) FormatInput ¶
func (OpenCodeSpec) FormatInput(message string) ([]byte, error)
FormatInput returns nil — OpenCode takes prompt as positional arg, not stdin.
func (OpenCodeSpec) FormatPermissionResponse ¶
func (OpenCodeSpec) FormatPermissionResponse(requestID, optionID string) ([]byte, error)
FormatPermissionResponse is not applicable for per-turn mode.
func (OpenCodeSpec) Mode ¶
func (OpenCodeSpec) Mode() StdioMode
func (OpenCodeSpec) Name ¶
func (OpenCodeSpec) Name() string
type PendingPermission ¶
type PendingPermission struct {
Request *PermissionRequest
Session string
Timer *time.Timer
Responded bool
}
PendingPermission holds a pending permission request waiting for user response.
type PermissionOption ¶
type PermissionOption struct {
ID string // Machine-readable identifier
Text string // Human-readable label
}
PermissionOption represents one choice in a permission prompt.
type PermissionRequest ¶
type PermissionRequest struct {
RequestID string
ToolName string
Input string
Options []PermissionOption
}
PermissionRequest represents a permission prompt from the CLI. It contains multiple numbered options the user can choose from.
func (*PermissionRequest) FormatOptions ¶
func (p *PermissionRequest) FormatOptions() string
FormatOptions formats the permission request as a numbered list for display.
func (*PermissionRequest) OptionByID ¶
func (p *PermissionRequest) OptionByID(id string) *PermissionOption
OptionByID returns the option with the given ID.
func (*PermissionRequest) OptionByIndex ¶
func (p *PermissionRequest) OptionByIndex(idx int) *PermissionOption
OptionByIndex returns the option at the given 1-based index. Returns nil if the index is out of range.
type StartOptions ¶
type StartOptions struct {
WorkDir string
Model string
Env map[string]string
Context context.Context
Prompt string // User's input message (for CLIs that take prompt as arg)
Resume bool // Whether to resume a previous session
SessionID string // Explicit session ID to resume (optional)
Yolo bool // Auto-approve all permission prompts
}
StartOptions contains parameters for starting a CLI process.
type StdioAdapter ¶
type StdioAdapter struct {
// contains filtered or unexported fields
}
StdioAdapter implements cli.CLIAdapter for stdio-based CLI tools. It supports multiple CLI tools via the CLISpec interface.
func NewStdioAdapter ¶
func NewStdioAdapter(spec CLISpec, config StdioAdapterConfig) *StdioAdapter
NewStdioAdapter creates a new stdio adapter for the given CLISpec.
func (*StdioAdapter) Close ¶
func (a *StdioAdapter) Close() error
Close shuts down all sessions and releases resources.
func (*StdioAdapter) CreateSession ¶
func (a *StdioAdapter) CreateSession(sessionName string, opts ...cli.SessionOption) error
CreateSession creates a new session and starts the CLI process.
func (*StdioAdapter) GetPendingPermission ¶
func (a *StdioAdapter) GetPendingPermission(sessionName string) *PendingPermission
GetPendingPermission returns the pending permission request for a session.
func (*StdioAdapter) HandleHookData ¶
HandleHookData returns an error — stdio adapters don't use hooks.
func (*StdioAdapter) IsSessionAlive ¶
func (a *StdioAdapter) IsSessionAlive(sessionName string) bool
IsSessionAlive checks if the CLI process is still running.
func (*StdioAdapter) RespondPermission ¶
func (a *StdioAdapter) RespondPermission(sessionName, requestID, optionID string) error
RespondPermission sends a permission response to the CLI process.
func (*StdioAdapter) SendInput ¶
func (a *StdioAdapter) SendInput(sessionName, input string) error
SendInput sends a user message to the CLI process. For PersistentMode: writes to stdin and waits for result events. For PerTurnMode: spawns a new process per message.
func (*StdioAdapter) SetEngine ¶
func (a *StdioAdapter) SetEngine(engine Engine)
SetEngine sets the engine reference for sending responses.
func (*StdioAdapter) StopSession ¶
func (a *StdioAdapter) StopSession(sessionName string) error
StopSession stops a single session and removes it from the adapter.
type StdioAdapterConfig ¶
type StdioAdapterConfig struct {
PermissionTimeout time.Duration
IdleTimeout time.Duration
Env map[string]string
}
StdioAdapterConfig holds configuration for stdio adapters.
type StdioProcess ¶
type StdioProcess struct {
// contains filtered or unexported fields
}
StdioProcess manages a CLI subprocess with stdin/stdout pipes.
func NewStdioProcess ¶
func NewStdioProcess(ctx context.Context, spec CLISpec, opts StartOptions) (*StdioProcess, error)
NewStdioProcess spawns a new CLI process and starts reading stdout.
func (*StdioProcess) Close ¶
func (p *StdioProcess) Close() error
Close shuts down the process gracefully.
func (*StdioProcess) CloseInput ¶
func (p *StdioProcess) CloseInput() error
CloseInput closes stdin, signaling EOF to the process. Required for per-turn CLIs (e.g., codex) that read prompt from stdin. Safe to call multiple times.
func (*StdioProcess) Events ¶
func (p *StdioProcess) Events() <-chan Event
Events returns the channel of events from the CLI process.
func (*StdioProcess) WriteInput ¶
func (p *StdioProcess) WriteInput(message string) error
WriteInput writes a formatted user message to stdin. If FormatInput returns nil, the write is skipped (for CLIs that take prompt as arg).
func (*StdioProcess) WritePermissionResponse ¶
func (p *StdioProcess) WritePermissionResponse(requestID, optionID string) error
WritePermissionResponse writes a formatted permission response to stdin. If FormatPermissionResponse returns nil, the write is skipped.
type ToolUseInfo ¶
ToolUseInfo describes a tool invocation.