types

package
v0.17.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: MIT Imports: 6 Imported by: 0

README

pkg/types

Shared type definitions used across packages to avoid circular imports.

Files

File Role
types.go All shared types, constants, and the JSONL scanner factory

Key Types

ClaudeHookInput

Union type for all Claude Code hook events. A single struct carries fields for every hook type — unused fields are zero-valued. This is intentional: the number of hook types is small and their fields are largely orthogonal, so splitting into separate types would add complexity without benefit.

Always-present fields: SessionID (validated by ReadClaudeHookInput). TranscriptPath is present for session hooks but not validated at this level — the Claude provider adds that validation.

Hook-specific fields:

  • UserPromptSubmit: Prompt
  • PreToolUse / PostToolUse: ToolName, ToolInput, ToolUseID, ToolResponse
  • SessionStart / SessionEnd: Reason
ClaudeHookResponse / PreToolUseResponse

Response types written to stdout for the harness to consume. PreToolUseResponse includes HookSpecificOutput (a PreToolUseOutput) with permission decisions (allow/deny with instructions). PreToolUseResponse is provider-agnostic — Claude Code and Codex both accept the same shape.

CodexHookInput / CodexHookResponse

Codex counterparts to the Claude types. CodexHookInput is a union type carrying fields from all Codex hook events; ToolResponseMap() normalizes Codex's tool_response value (the shell tool sends a plain string, other tools send a map) into a map[string]any. CodexHookResponse is the JSON response sent back to Codex hooks.

InboxEvent

Used for inter-process communication between the sync stop command and the running daemon. Serialized as JSONL in the inbox file.

ValidateSessionID(id)

Validates that a session ID contains only safe characters (alphanumeric, hyphens, underscores) using the sessionIDPattern regex. Called by ReadClaudeHookInput to reject malformed session IDs before they reach downstream code.

NewJSONLScanner(reader)

Factory that creates a bufio.Scanner with a 10MB buffer (MaxJSONLLineSize). Transcript lines can be very large (thinking blocks, tool results), so the default 64KB buffer is insufficient.

How to Extend

Adding a field to ClaudeHookInput: Add the field with json:",omitempty". No need to update ReadClaudeHookInput()json.Unmarshal handles new fields automatically. If the field requires validation, add it to the validation block in ReadClaudeHookInput().

Adding a new shared type: Add it here only if it's needed by 2+ packages that would otherwise create a circular import. Package-specific types belong in their own package.

Invariants

  • ClaudeHookInput.SessionID is validated as non-empty and safe (alphanumeric, hyphens, underscores only) in ReadClaudeHookInput() — all downstream code can assume it's set and safe for use in file paths.
  • ReadClaudeHookInput() uses bounded io.ReadAll (limited to MaxJSONLLineSize) to prevent memory exhaustion from oversized input.
  • MaxJSONLLineSize (10MB) must accommodate the largest possible transcript line. Changing this affects every JSONL reader in the codebase.
  • NewJSONLScanner must be used everywhere JSONL files are read — never create a bare bufio.Scanner for transcript files.

Dependencies

Uses: standard library only

Used by: nearly every package (cmd/, pkg/daemon/, pkg/git/, pkg/provider/, pkg/redactor/, pkg/sync/)

Documentation

Index

Constants

View Source
const MaxJSONLLineSize = 10 * 1024 * 1024 // 10MB

MaxJSONLLineSize is the maximum size for a single JSONL line Default bufio.Scanner buffer is 64KB, but transcript lines with thinking blocks and tool results can exceed 1MB

View Source
const MaxMetadataFieldLength = 8 * 1024 // 8KB

MaxMetadataFieldLength is the maximum byte length for provider session metadata fields (first_user_message, summary) sent to the backend. Callers should use MaxMetadataFieldLength/2 (4KB) for first_user_message to leave headroom for JSON serialization overhead below the backend's 8192-character limit.

Variables

This section is empty.

Functions

func NewJSONLScanner

func NewJSONLScanner(r io.Reader) *bufio.Scanner

NewJSONLScanner creates a bufio.Scanner configured for large JSONL files with a 10MB buffer to handle long transcript lines

func ValidateSessionID added in v0.15.0

func ValidateSessionID(id string) error

ValidateSessionID checks that a session ID contains only safe characters.

Types

type ClaudeHookInput added in v0.16.0

type ClaudeHookInput struct {
	SessionID      string `json:"session_id"`
	TranscriptPath string `json:"transcript_path"`
	CWD            string `json:"cwd"`
	PermissionMode string `json:"permission_mode"`
	HookEventName  string `json:"hook_event_name"`
	Reason         string `json:"reason"`
	ParentPID      int    `json:"parent_pid,omitempty"` // Claude Code process ID (set by confab, not Claude Code)

	// UserPromptSubmit-specific fields
	Prompt string `json:"prompt,omitempty"`

	// PreToolUse/PostToolUse-specific fields
	ToolName     string         `json:"tool_name,omitempty"`
	ToolInput    map[string]any `json:"tool_input,omitempty"`
	ToolUseID    string         `json:"tool_use_id,omitempty"`
	ToolResponse map[string]any `json:"tool_response,omitempty"` // PostToolUse only
}

ClaudeHookInput represents hook data from Claude Code.

This is a union type containing fields from all hook types (SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, etc.). JSON unmarshaling handles missing fields gracefully. This approach is pragmatic for a small number of hooks with mostly orthogonal fields. Consider splitting into separate types if hooks start having conflicting field semantics or the number of hook types grows significantly.

func ReadClaudeHookInput added in v0.16.0

func ReadClaudeHookInput(r io.Reader) (*ClaudeHookInput, error)

ReadClaudeHookInput reads and parses hook input JSON from a reader. Used by PreToolUse, PostToolUse, and other hook handlers.

type ClaudeHookResponse added in v0.16.0

type ClaudeHookResponse struct {
	Continue       bool   `json:"continue"`
	StopReason     string `json:"stopReason"`
	SuppressOutput bool   `json:"suppressOutput"`
	SystemMessage  string `json:"systemMessage,omitempty"`
}

ClaudeHookResponse is the JSON response sent back to Claude Code

type CodexHookInput added in v0.16.0

type CodexHookInput struct {
	SessionID      string `json:"session_id"`
	TranscriptPath string `json:"transcript_path"`
	CWD            string `json:"cwd"`
	HookEventName  string `json:"hook_event_name"`
	Model          string `json:"model,omitempty"`
	Source         string `json:"source,omitempty"`
	TurnID         string `json:"turn_id,omitempty"`
	ParentPID      int    `json:"parent_pid,omitempty"` // Codex process ID (set by confab, not Codex)

	// PreToolUse/PostToolUse-specific fields. Codex normalizes its shell
	// tool's tool_name to "Bash" in hook stdin (HookToolName::bash() in
	// codex-rs/core/src/tools/hook_names.rs), so our Bash matcher and
	// gitCommit/ghPRCreate regexes work without per-provider tweaks.
	//
	// ToolResponse is json.RawMessage rather than map[string]any because
	// Codex's PostToolUse schema types tool_response as `any` JSON value:
	// the shell tool emits a plain JSON string (the aggregated exec output
	// from format_exec_output_str), while other tools emit objects. Use
	// ToolResponseMap to get a normalized map[string]any for either shape.
	ToolName     string          `json:"tool_name,omitempty"`
	ToolInput    map[string]any  `json:"tool_input,omitempty"`
	ToolUseID    string          `json:"tool_use_id,omitempty"`
	ToolResponse json.RawMessage `json:"tool_response,omitempty"` // PostToolUse only
}

CodexHookInput contains the shared fields Confab needs from Codex command hooks. The fields follow the current official Codex hook schemas, while provider-specific parsing owns validation. Like ClaudeHookInput, this is a union type carrying fields from all Codex hook events (SessionStart, PreToolUse, PostToolUse); JSON unmarshaling handles missing fields gracefully.

func (*CodexHookInput) ToolResponseMap added in v0.16.1

func (c *CodexHookInput) ToolResponseMap() map[string]any

ToolResponseMap normalizes the Codex tool_response value into a map[string]any so downstream provider-agnostic code can use a single shape. Codex's shell tool sends a plain string; other tools send objects. Strings get wrapped under "stdout" because that's how our PR-URL extractor and success heuristics read shell output.

type CodexHookResponse added in v0.16.0

type CodexHookResponse struct {
	Continue       bool   `json:"continue"`
	StopReason     string `json:"stopReason,omitempty"`
	SystemMessage  string `json:"systemMessage,omitempty"`
	SuppressOutput bool   `json:"suppressOutput,omitempty"`
}

CodexHookResponse is the JSON response sent back to Codex hooks.

type InboxEvent

type InboxEvent struct {
	Type      string           `json:"type"`                 // Event type: "session_end"
	Timestamp time.Time        `json:"timestamp"`            // When the event was written
	HookInput *ClaudeHookInput `json:"hook_input,omitempty"` // Full hook payload for session events
}

InboxEvent represents an event written to the daemon's inbox file. The inbox is a JSONL file where each line is an event.

type OpenCodeHookInput added in v0.17.0

type OpenCodeHookInput struct {
	SessionID string `json:"session_id"`
	CWD       string `json:"cwd"`
	ParentPID int    `json:"parent_pid,omitempty"`
	// ParentID is the OpenCode session's parent session id, set by the plugin
	// only for subagent (non-root) sessions. Used to suppress daemons for
	// non-root sessions (CF-537); root sessions omit it. Distinct from
	// ParentPID, which is an OS process id.
	ParentID string `json:"parent_id,omitempty"`
}

OpenCodeHookInput represents hook data from OpenCode. Unlike Claude/Codex, OpenCode doesn't pipe hook data via stdin from a settings-file hook system. Instead, the TypeScript plugin constructs this struct from the event payload and passes it via stdin to the confab hook commands. The daemon then reads OpenCode session data directly from the local SQLite DB at ~/.local/share/opencode/opencode.db (or CONFAB_OPENCODE_DB), so no per-session URL is required.

type PreToolUseOutput

type PreToolUseOutput struct {
	HookEventName            string `json:"hookEventName"`
	PermissionDecision       string `json:"permissionDecision,omitempty"` // "allow", "deny", or "ask"
	PermissionDecisionReason string `json:"permissionDecisionReason,omitempty"`
}

PreToolUseOutput contains PreToolUse-specific decision fields.

type PreToolUseResponse

type PreToolUseResponse struct {
	HookSpecificOutput *PreToolUseOutput `json:"hookSpecificOutput,omitempty"`
}

PreToolUseResponse is the JSON response for PreToolUse hooks. The shape is provider-agnostic: Claude Code and Codex both accept the same hookSpecificOutput.permissionDecision contract per their respective schemas.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL