Documentation
¶
Index ¶
- Constants
- Variables
- func DetectInstalled() []string
- func NormalizeName(name string) (string, error)
- func ResetStateDBPathCacheForTest()
- func ResetWalkUpRetryForTest()
- func SetWalkUpRetryForTest(attempts int, backoff time.Duration)
- type AnnotationResult
- type ChunkView
- type ClaudeCode
- func (p ClaudeCode) AnnotateChunk(c ChunkView, _ bool, redact func(string) string) AnnotationResult
- func (ClaudeCode) CLIBinaryName() string
- func (p ClaudeCode) DefaultCWD(transcriptPath string) string
- func (ClaudeCode) DiscoverDescendants(DescendantRegistrar, string) error
- func (ClaudeCode) ExtractAgentIDsFromMessage(message map[string]interface{}) []string
- func (p ClaudeCode) ExtractMetadata(lines []string) SessionMetadata
- func (p ClaudeCode) FindParentPID() int
- func (p ClaudeCode) FindSessionByID(partialID string) (string, string, error)
- func (ClaudeCode) InitTranscript(TranscriptRegistrar, string, string) error
- func (p ClaudeCode) InstallHooks() (string, error)
- func (p ClaudeCode) InstallSkills() error
- func (ClaudeCode) IsHooksInstalled() (bool, error)
- func (p ClaudeCode) IsProcess(pid int) bool
- func (p ClaudeCode) IsSkillInstalled(name string) bool
- func (ClaudeCode) MatchesProcess(cmd string) bool
- func (ClaudeCode) Name() string
- func (p ClaudeCode) ParseSessionHook(r io.Reader) (HookInput, error)
- func (p ClaudeCode) ProjectsDir() (string, error)
- func (ClaudeCode) ReadHookInput(r io.Reader) (*types.ClaudeHookInput, error)
- func (p ClaudeCode) ReadSessionHookInput(r io.Reader) (*types.ClaudeHookInput, error)
- func (p ClaudeCode) ScanSessions() ([]SessionInfo, error)
- func (p ClaudeCode) SettingsPath() (string, error)
- func (ClaudeCode) ShouldSpawnForInput(HookInput) bool
- func (ClaudeCode) StateDir() (string, error)
- func (ClaudeCode) SupportsCommitLinking() bool
- func (p ClaudeCode) UninstallHooks() (string, error)
- func (p ClaudeCode) UninstallSkills() error
- func (p ClaudeCode) ValidateTranscriptPath(path string) error
- func (ClaudeCode) WalkUpToRoot(sessionID string) (string, string, error)
- func (ClaudeCode) WriteHookResponse(w io.Writer, suppressOutput bool, systemMessage string) error
- type Codex
- func (p Codex) AnnotateChunk(c ChunkView, sentFirstUserMessage bool, redact func(string) string) AnnotationResult
- func (Codex) CLIBinaryName() string
- func (p Codex) ConfigPath() (string, error)
- func (p Codex) DefaultCWD(transcriptPath string) string
- func (p Codex) DiscoverDescendants(reg DescendantRegistrar, rootThreadUUID string) error
- func (Codex) ExtractFirstUserMessageFromLines(lines []string) string
- func (p Codex) ExtractMetadata(lines []string) SessionMetadata
- func (p Codex) FindParentPID() int
- func (p Codex) FindSessionByID(partialID string) (string, string, error)
- func (p Codex) InitTranscript(target TranscriptRegistrar, transcriptPath, externalID string) error
- func (p Codex) InstallHooks() (string, error)
- func (p Codex) InstallSkills() error
- func (p Codex) IsHooksInstalled() (bool, error)
- func (p Codex) IsProcess(pid int) bool
- func (p Codex) IsSkillInstalled(name string) bool
- func (p Codex) ListSubtree(rootThreadUUID string) ([]CodexThreadRow, error)
- func (Codex) MatchesProcess(cmd string) bool
- func (Codex) Name() string
- func (p Codex) ParseSessionHook(r io.Reader) (HookInput, error)
- func (p Codex) ReadHookInput(r io.Reader) (*types.CodexHookInput, error)
- func (p Codex) ReadSessionHookInput(r io.Reader) (*types.CodexHookInput, error)
- func (p Codex) ReadSessionInfo(path string) (CodexSessionInfo, error)
- func (p Codex) ScanCodexSessions() ([]CodexSessionInfo, error)
- func (p Codex) ScanSessions() ([]SessionInfo, error)
- func (Codex) SessionIDFromRolloutPath(path string) (string, bool)
- func (p Codex) SessionsDir() (string, error)
- func (p Codex) ShouldSpawnForInput(in HookInput) bool
- func (p Codex) StateDBPath() (string, error)
- func (Codex) StateDir() (string, error)
- func (Codex) SupportsCommitLinking() bool
- func (p Codex) UninstallHooks() (string, error)
- func (p Codex) UninstallSkills() error
- func (p Codex) ValidateRolloutPath(path string) error
- func (p Codex) WalkUpToRoot(threadUUID string) (rootUUID, rootRolloutPath string, err error)
- func (Codex) WriteHookResponse(w io.Writer, suppressOutput bool, systemMessage string) error
- type CodexRolloutMetadata
- type CodexSessionInfo
- type CodexThreadRow
- type DescendantRegistrar
- type HookInput
- type Provider
- type SessionInfo
- type SessionMetadata
- type SummaryLink
- type TranscriptRegistrar
Constants ¶
const ( NameClaudeCode = "claude-code" NameCodex = "codex" )
const ClaudeStateDirEnv = "CONFAB_CLAUDE_DIR"
ClaudeStateDirEnv is the environment variable to override the default Claude state directory.
const CodexStateDBEnv = "CONFAB_CODEX_STATE_DB"
CodexStateDBEnv overrides automatic state DB discovery. When set, points directly at a state_N.sqlite file (or any SQLite file with the expected schema). Used by tests; can also be set by power users debugging Codex state inconsistencies.
const CodexStateDirEnv = "CONFAB_CODEX_DIR"
Variables ¶
var LookPath = exec.LookPath
LookPath is the package-level seam tests stub to simulate CLI presence.
Functions ¶
func DetectInstalled ¶
func DetectInstalled() []string
DetectInstalled returns the canonical names of providers whose CLI binary is on PATH, in fixed registry order. Result is never nil but may be empty.
func NormalizeName ¶
NormalizeName returns the canonical provider name. Backed by the registry so it can't drift from the Provider list.
func ResetStateDBPathCacheForTest ¶
func ResetStateDBPathCacheForTest()
ResetStateDBPathCacheForTest clears the cached state DB path so the next StateDBPath call re-evaluates the env var and glob. Production code resolves the path once per process; tests need to swap fixtures between cases. Lives in non-test code so cross-package tests (sync, daemon, cmd) can call it.
func ResetWalkUpRetryForTest ¶
func ResetWalkUpRetryForTest()
ResetWalkUpRetryForTest restores production retry defaults.
func SetWalkUpRetryForTest ¶
SetWalkUpRetryForTest shrinks WalkUpToRoot's retry budget for tests that would otherwise wait for the full production timeout. Pair with ResetWalkUpRetryForTest in t.Cleanup.
Types ¶
type AnnotationResult ¶
type AnnotationResult struct {
IncludedFirstUserMessage bool
SummaryLinks []SummaryLink
}
AnnotationResult is the structured return from AnnotateChunk. IncludedFirstUserMessage tells the engine whether to flip its sentFirstUserMessage flag. SummaryLinks (Claude only) tells the engine which parent summaries to link via the backend.
type ChunkView ¶
type ChunkView interface {
FileType() string
FirstLine() int
Lines() []string
FileCodexRollout() *CodexRolloutMetadata
SetCodexRolloutMetadata(*CodexRolloutMetadata)
SetSummary(string)
SetFirstUserMessage(string)
}
ChunkView is the structural view of a chunk + its source file that AnnotateChunk reads from and writes back into. pkg/sync's chunkView adapter satisfies it. Setters mutate the underlying chunk's metadata in place; accessors return read-only snapshots.
type ClaudeCode ¶
type ClaudeCode struct{}
ClaudeCode contains Claude Code-specific local behavior.
func (ClaudeCode) AnnotateChunk ¶
func (p ClaudeCode) AnnotateChunk(c ChunkView, _ bool, redact func(string) string) AnnotationResult
AnnotateChunk extracts the local summary, first user message, and summary-link records from a Claude Code transcript chunk. Summary links are returned via AnnotationResult.SummaryLinks so the engine can perform the backend HTTP after AnnotateChunk returns — keeping the provider side-effect-free.
Non-transcript files are a no-op (Claude extracts only from transcripts).
Claude does not gate first-user-message extraction on a "first time" flag — the discovery helper handles dedup internally and the engine historically does not flip sentFirstUserMessage for Claude. The returned IncludedFirstUserMessage stays false so the engine's flag is untouched.
func (ClaudeCode) CLIBinaryName ¶
func (ClaudeCode) CLIBinaryName() string
CLIBinaryName returns "claude" — the binary `claude` users install via the Claude Code installer.
func (ClaudeCode) DefaultCWD ¶
func (p ClaudeCode) DefaultCWD(transcriptPath string) string
DefaultCWD returns filepath.Dir(transcriptPath); Claude has no richer per-session CWD source.
func (ClaudeCode) DiscoverDescendants ¶
func (ClaudeCode) DiscoverDescendants(DescendantRegistrar, string) error
DiscoverDescendants is a no-op for Claude Code. Claude's agent files are discovered transitively from transcript content (agent IDs embedded in JSONL messages) inside tracker.DiscoverNewFiles — no external state DB lookup is required.
func (ClaudeCode) ExtractAgentIDsFromMessage ¶
func (ClaudeCode) ExtractAgentIDsFromMessage(message map[string]interface{}) []string
ExtractAgentIDsFromMessage extracts agent IDs from a parsed Claude transcript message. Checks both root-level toolUseResult.agentId and nested content blocks. Empty slice on non-user messages or missing fields.
func (ClaudeCode) ExtractMetadata ¶
func (p ClaudeCode) ExtractMetadata(lines []string) SessionMetadata
ExtractMetadata parses summary, first user message, and summary links from in-memory Claude transcript lines. Lines beyond maxLinesForExtraction are ignored.
For summaries:
- Entries with a leafUuid go to SummaryLinks (links to previous sessions).
- Entries without leafUuid become the local Summary (last one wins).
For user messages: the first one encountered sets FirstUserMessage.
func (ClaudeCode) FindParentPID ¶
func (p ClaudeCode) FindParentPID() int
FindParentPID walks up the process tree to find the Claude Code process.
func (ClaudeCode) FindSessionByID ¶
func (p ClaudeCode) FindSessionByID(partialID string) (string, string, error)
FindSessionByID resolves a full or partial Claude session ID to its full ID and transcript path. Walk-up is identity for Claude (no thread tree). Returns an error on no-match or ambiguous prefix.
func (ClaudeCode) InitTranscript ¶
func (ClaudeCode) InitTranscript(TranscriptRegistrar, string, string) error
InitTranscript is a no-op for Claude Code — there is no root rollout metadata to attach (Codex-only concern).
func (ClaudeCode) InstallHooks ¶
func (p ClaudeCode) InstallHooks() (string, error)
InstallHooks installs all four Confab hook bundles (sync, PreToolUse, PostToolUse, UserPromptSubmit). Returns the settings.json path.
func (ClaudeCode) InstallSkills ¶
func (p ClaudeCode) InstallSkills() error
InstallSkills installs the Claude Code skills shipped with confab (/til and /retro).
func (ClaudeCode) IsHooksInstalled ¶
func (ClaudeCode) IsHooksInstalled() (bool, error)
IsHooksInstalled reports whether all four Confab hook bundles for Claude Code are installed. Mirrors InstallHooks: true only when every bundle is present.
func (ClaudeCode) IsProcess ¶
func (p ClaudeCode) IsProcess(pid int) bool
IsProcess checks if the given PID is a Claude Code process.
func (ClaudeCode) IsSkillInstalled ¶
func (p ClaudeCode) IsSkillInstalled(name string) bool
IsSkillInstalled reports whether a shipped Claude Code skill exists.
func (ClaudeCode) MatchesProcess ¶
func (ClaudeCode) MatchesProcess(cmd string) bool
MatchesProcess checks if a command string matches Claude Code.
func (ClaudeCode) Name ¶
func (ClaudeCode) Name() string
Name returns the canonical Claude Code provider name.
func (ClaudeCode) ParseSessionHook ¶
func (p ClaudeCode) ParseSessionHook(r io.Reader) (HookInput, error)
ParseSessionHook reads a Claude SessionStart hook payload and returns the provider-agnostic view.
func (ClaudeCode) ProjectsDir ¶
func (p ClaudeCode) ProjectsDir() (string, error)
ProjectsDir returns the Claude projects directory.
func (ClaudeCode) ReadHookInput ¶
func (ClaudeCode) ReadHookInput(r io.Reader) (*types.ClaudeHookInput, error)
ReadHookInput reads and validates Claude hook JSON.
func (ClaudeCode) ReadSessionHookInput ¶
func (p ClaudeCode) ReadSessionHookInput(r io.Reader) (*types.ClaudeHookInput, error)
ReadSessionHookInput reads Claude session hook JSON and validates transcript_path.
func (ClaudeCode) ScanSessions ¶
func (p ClaudeCode) ScanSessions() ([]SessionInfo, error)
ScanSessions walks ~/.claude/projects/ and returns all user sessions sorted oldest first. Permission errors per path are reported to stderr and don't fail the scan.
func (ClaudeCode) SettingsPath ¶
func (p ClaudeCode) SettingsPath() (string, error)
SettingsPath returns the Claude settings file path.
func (ClaudeCode) ShouldSpawnForInput ¶
func (ClaudeCode) ShouldSpawnForInput(HookInput) bool
ShouldSpawnForInput is unconditional for Claude Code.
func (ClaudeCode) StateDir ¶
func (ClaudeCode) StateDir() (string, error)
StateDir returns the Claude state directory. Defaults to ~/.claude but can be overridden with CONFAB_CLAUDE_DIR.
func (ClaudeCode) SupportsCommitLinking ¶ added in v0.16.1
func (ClaudeCode) SupportsCommitLinking() bool
SupportsCommitLinking reports that Claude Code installs PreToolUse + PostToolUse hooks that drive bidirectional GitHub linking.
func (ClaudeCode) UninstallHooks ¶
func (p ClaudeCode) UninstallHooks() (string, error)
UninstallHooks removes all four Confab hook bundles. Returns the settings.json path even if no hooks were present.
func (ClaudeCode) UninstallSkills ¶
func (p ClaudeCode) UninstallSkills() error
UninstallSkills removes the Claude Code skills shipped with confab.
func (ClaudeCode) ValidateTranscriptPath ¶
func (p ClaudeCode) ValidateTranscriptPath(path string) error
ValidateTranscriptPath checks that a Claude transcript path is safe: - Must be absolute - Must not contain ".." components - Must resolve to a location under the Claude projects directory
func (ClaudeCode) WalkUpToRoot ¶
func (ClaudeCode) WalkUpToRoot(sessionID string) (string, string, error)
WalkUpToRoot is the identity walk for Claude Code: there is no thread tree, so the firing session is always its own root and rootPath is "".
func (ClaudeCode) WriteHookResponse ¶
WriteHookResponse writes a ClaudeHookResponse to w.
type Codex ¶
type Codex struct{}
func (Codex) AnnotateChunk ¶
func (p Codex) AnnotateChunk(c ChunkView, sentFirstUserMessage bool, redact func(string) string) AnnotationResult
AnnotateChunk attaches Codex-specific chunk metadata. Two concerns are handled independently:
first_user_message: extracted via ExtractMetadata from the root transcript's chunks (Codex emits the user prompt once at the start). Gated by c.FileType() == "transcript" + !sentFirstUserMessage. The closure `redact` (nil-safe) is applied before attaching.
codex_rollout: per-rollout metadata so the backend can upsert the `codex_rollouts` row. Emitted on the FIRST chunk of any Codex rollout (root or descendant) — detected via c.FirstLine() == 1. No persistent state flag is needed; retries preserve FirstLine == 1. Backend upsert is idempotent.
func (Codex) CLIBinaryName ¶
CLIBinaryName returns "codex" — the binary users install via Codex.
func (Codex) ConfigPath ¶
func (Codex) DefaultCWD ¶
DefaultCWD reads session_meta.cwd from the rollout. Falls back to filepath.Dir on read failure or empty CWD so the upload still has a directory to record.
func (Codex) DiscoverDescendants ¶
func (p Codex) DiscoverDescendants(reg DescendantRegistrar, rootThreadUUID string) error
DiscoverDescendants queries the local Codex SQLite state DB for every descendant of rootThreadUUID, verifies each rollout file exists and looks like an actual subagent (ValidateRolloutPath + !IsUserSession check on session_meta), and registers verified ones via reg.RegisterCodexRollout.
Idempotent across calls (skips already-tracked filenames). Degrades gracefully when the state DB is missing or its schema doesn't match — ListSubtree returns (nil, nil) and we return nil. Per-descendant verification failures log at warn level and skip the row.
func (Codex) ExtractFirstUserMessageFromLines ¶
ExtractFirstUserMessageFromLines returns the first non-empty user message found in the given rollout lines, truncated to MaxFirstUserMessageLength bytes on a UTF-8 boundary. Returns "" when no user message is present.
func (Codex) ExtractMetadata ¶
func (p Codex) ExtractMetadata(lines []string) SessionMetadata
ExtractMetadata returns the in-memory metadata for a Codex chunk. Summary and SummaryLinks stay empty — those are Claude-only concepts. Lines are capped to maxLinesForExtraction to mirror Claude's bound.
func (Codex) FindParentPID ¶
FindParentPID walks up the process tree to find the Codex process. Mirrors ClaudeCode.FindParentPID for daemon parent-liveness monitoring.
func (Codex) FindSessionByID ¶
FindSessionByID resolves a full or partial UUID to the ROOT thread's UUID and rollout path. If partialID matches a subagent, this walks up to the top-most user session via WalkUpToRoot so callers transparently upload the whole tree.
func (Codex) InitTranscript ¶
func (p Codex) InitTranscript(target TranscriptRegistrar, transcriptPath, externalID string) error
InitTranscript reads the root rollout's session_meta and attaches the resulting CodexRolloutMetadata to the transcript file so the very first uploaded chunk carries codex_rollout metadata. On read failure (missing or malformed rollout file) logs at warn level and still attaches the bare-minimum metadata (ThreadUUID + RolloutPath) so the backend can upsert a row; CWD/Model/etc. stay empty. Matches pre-CF-397 behavior. Never returns an error — failure modes are recoverable.
func (Codex) InstallHooks ¶
InstallHooks delegates to pkg/hookconfig.
func (Codex) InstallSkills ¶
InstallSkills installs the Codex skills shipped with confab (/til and /retro).
func (Codex) IsHooksInstalled ¶
IsHooksInstalled delegates to pkg/hookconfig, which parses ~/.codex/config.toml and returns true iff a confab command is registered under [[hooks.SessionStart]].
func (Codex) IsSkillInstalled ¶
IsSkillInstalled reports whether a shipped Codex skill exists.
func (Codex) ListSubtree ¶
func (p Codex) ListSubtree(rootThreadUUID string) ([]CodexThreadRow, error)
ListSubtree returns every descendant of rootThreadUUID, at any depth, via a recursive CTE over `thread_spawn_edges` JOIN `threads`. Each returned row's ParentThreadUUID is the immediate parent (which may itself be a descendant of rootThreadUUID for grandchildren). The root itself is NOT returned.
Returns (nil, nil) when the DB doesn't exist or the schema doesn't match — degrades gracefully so daemon sync cycles continue uninterrupted.
func (Codex) MatchesProcess ¶
MatchesProcess checks if a command string matches a Codex invocation.
func (Codex) ParseSessionHook ¶
ParseSessionHook reads a Codex SessionStart hook payload and returns the provider-agnostic view.
func (Codex) ReadHookInput ¶
func (Codex) ReadSessionHookInput ¶
func (Codex) ReadSessionInfo ¶
func (p Codex) ReadSessionInfo(path string) (CodexSessionInfo, error)
ReadSessionInfo reads a rollout's session_meta line and returns the parsed CodexSessionInfo (with file stat info populated).
func (Codex) ScanCodexSessions ¶
func (p Codex) ScanCodexSessions() ([]CodexSessionInfo, error)
ScanCodexSessions returns the rich Codex-specific session info for every user-initiated rollout. Internal callers that need CodexSessionInfo's extras (CWD, Model, AgentRole, ...) use this directly; the cross-provider Provider.ScanSessions interface method projects to []SessionInfo.
func (Codex) ScanSessions ¶
func (p Codex) ScanSessions() ([]SessionInfo, error)
ScanSessions projects ScanCodexSessions to the cross-provider SessionInfo shape. FirstUserMessage is extracted from each rollout's first event_msg.user_message line (capped to maxLinesForExtraction). Sessions are returned oldest first to match Claude's ordering.
func (Codex) SessionIDFromRolloutPath ¶
SessionIDFromRolloutPath parses the UUID embedded in a Codex rollout filename. Returns ("", false) on filenames that don't match the rollout pattern.
func (Codex) SessionsDir ¶
func (Codex) ShouldSpawnForInput ¶
ShouldSpawnForInput inspects the rollout file's session_meta to decide whether the firing hook represents a user-initiated rollout (true) or a subagent (false).
func (Codex) StateDBPath ¶
StateDBPath resolves the path to Codex's local state SQLite DB. Resolution order:
- CONFAB_CODEX_STATE_DB env var (escape hatch for tests/debugging).
- Glob `<StateDir>/state_*.sqlite`, parse the integer suffix between `_` and `.sqlite`, return the entry with the highest numeric suffix. If suffixes don't parse as integers, falls back to alphabetical max.
- Returns os.ErrNotExist if no candidate file exists.
The result is cached for the lifetime of the process via sync.Once.
func (Codex) SupportsCommitLinking ¶ added in v0.16.1
SupportsCommitLinking reports that Codex installs PreToolUse + PostToolUse hooks that drive bidirectional GitHub linking. See pkg/hookconfig/codex.go for the managed-block contents.
func (Codex) UninstallHooks ¶
UninstallHooks delegates to pkg/hookconfig.
func (Codex) UninstallSkills ¶
UninstallSkills removes the Codex skills shipped with confab.
func (Codex) ValidateRolloutPath ¶
func (Codex) WalkUpToRoot ¶
WalkUpToRoot walks the parent_thread_id chain in `thread_spawn_edges` starting from threadUUID until it reaches a thread with no parent edge. Returns the top-most root's UUID + that root's rollout_path.
If threadUUID is already a root (no parent edge), returns it unchanged. If the DB is unavailable or the thread isn't in the DB at all, returns (threadUUID, "", nil) — graceful degradation so callers don't need to branch on transient errors.
Built-in retry: the FIRST parent lookup retries up to walkUpRetryAttempts times with walkUpRetryBackoff between attempts. This absorbs the spawn-vs-edge race where Codex fires the SessionStart hook for a fresh subagent before the `thread_spawn_edges` row has been committed.
The retry only fires on the first hop; subsequent hops (grandchild → child → root walks) assume the chain is already stable in Codex's DB.
Logs the retry-attempt count + wall time at info level so we can later tune the retry budget against observed race timing.
type CodexRolloutMetadata ¶
type CodexRolloutMetadata struct {
ThreadUUID string `json:"thread_uuid"`
ParentThreadUUID string `json:"parent_thread_uuid,omitempty"` // "" for roots
RolloutPath string `json:"rollout_path"`
CWD string `json:"cwd,omitempty"`
Model string `json:"model,omitempty"`
// Source is the flattened discriminator from Codex's polymorphic
// session_meta.source field — a short string like "cli" or "subagent".
// The backend's `codex_rollouts.source` column caps this at 64 chars.
Source string `json:"source,omitempty"`
ThreadSource string `json:"thread_source,omitempty"`
AgentPath string `json:"agent_path,omitempty"`
AgentRole string `json:"agent_role,omitempty"`
AgentNickname string `json:"agent_nickname,omitempty"`
}
CodexRolloutMetadata is the per-rollout metadata transmitted on the FIRST chunk of a Codex rollout (root or descendant). The backend upserts it into the `codex_rollouts` table keyed by ThreadUUID. Omitted on chunks where chunk.FirstLine != 1, so the backend handler treats absence as "no metadata to record this round."
Codex-only; the backend rejects this field on non-codex sessions with 400.
Lives in pkg/provider so both pkg/sync (wire format) and pkg/provider's Codex implementation can construct one without a package import cycle. pkg/sync re-exports it via `type CodexRolloutMetadata = provider.CodexRolloutMetadata`.
Redaction: fields below are sourced from Codex's session_meta (and the SQLite state DB for descendants) and ride on the first chunk unredacted. Rollout *content* is redacted in pkg/sync.FileTracker.ReadChunk; these metadata fields are not. Current fields are short, structured values (path, model name, agent role). Before adding a field that could carry free-text user content, plumb the redactor into Codex.InitTranscript / Codex.DiscoverDescendants rather than extending this struct.
type CodexSessionInfo ¶
type CodexSessionInfo struct {
SessionID string
RolloutPath string
CWD string
Model string
// Source is a short discriminator extracted from the rollout's `source`
// field. Codex writes that field as either a bare string ("cli") for
// user-initiated rollouts or a tagged object ({"subagent":{...}}) for
// spawned subagents. The string case is passed through; the object case
// is collapsed to its top-level key. Empty when session_meta omits the
// field. Matches the backend's 64-char `codex_rollouts.source` column.
Source string
ThreadSource string
AgentPath string
AgentRole string
AgentNickname string
ModTime time.Time
SizeBytes int64
}
CodexSessionInfo is the rich Codex-specific session metadata returned by ScanCodexSessions and ReadSessionInfo. Internal callers (cmd/save.go, engine init paths) need the extras (CWD, Model, AgentRole, ...) that don't fit on the cross-provider SessionInfo.
func (CodexSessionInfo) IsUserSession ¶
func (s CodexSessionInfo) IsUserSession() bool
IsUserSession reports whether this rollout is a top-level user session (not a subagent or memory rollout).
type CodexThreadRow ¶
type CodexThreadRow struct {
ThreadUUID string
ParentThreadUUID string
RolloutPath string
CWD string
Model string
Source string
ThreadSource string
AgentPath string
AgentRole string
AgentNickname string
}
CodexThreadRow describes a single Codex thread as recorded in the local state DB's `threads` table. ParentThreadUUID is the immediate parent recorded in `thread_spawn_edges`, or "" for a root thread.
type DescendantRegistrar ¶
type DescendantRegistrar interface {
IsTracked(fileName string) bool
RegisterCodexRollout(path, fileName string, isRoot bool, meta CodexRolloutMetadata)
}
DescendantRegistrar is the surface DiscoverDescendants uses to register newly-discovered sidechain files. *sync.FileTracker satisfies it via IsTracked + RegisterCodexRollout.
type HookInput ¶
type HookInput interface {
SessionID() string
TranscriptPath() string
CWD() string
HookEventName() string
ParentPID() int
}
HookInput is the provider-agnostic view of a hook payload, exposing the fields used by daemon spawning and bookkeeping. Concrete shapes (types.ClaudeHookInput, types.CodexHookInput) satisfy this via adapter types defined in hookinput.go.
type Provider ¶
type Provider interface {
Name() string
// CLIBinaryName is the OS-level binary name to look up via
// exec.LookPath when detecting whether the provider is installed
// locally (e.g. "claude" for Claude Code, "codex" for Codex).
CLIBinaryName() string
StateDir() (string, error)
FindParentPID() int
IsProcess(pid int) bool
// SupportsCommitLinking reports whether this provider's hook system
// can drive bidirectional GitHub linking (commit-trailer + PR-body
// injection via PreToolUse; commit/PR URL linking via PostToolUse).
// Used by cmd/ handlers to silently no-op for providers that don't
// install those events.
SupportsCommitLinking() bool
// ParseSessionHook reads a SessionStart-style hook payload from r and
// returns the provider-agnostic view.
ParseSessionHook(r io.Reader) (HookInput, error)
InstallHooks() (string, error)
UninstallHooks() (string, error)
IsHooksInstalled() (bool, error)
// InstallSkills installs the bundled skills for this provider's local
// skill layout.
InstallSkills() error
UninstallSkills() error
IsSkillInstalled(name string) bool
// WalkUpToRoot returns the root session ID and its rollout path. For
// providers without a separate root file identifier (Claude Code),
// rootPath is "".
WalkUpToRoot(sessionID string) (rootID, rootPath string, err error)
// ShouldSpawnForInput is the per-provider gate on whether a fresh
// SessionStart should result in a daemon. Codex returns false for
// subagent rollouts; Claude is always true.
ShouldSpawnForInput(in HookInput) bool
// WriteHookResponse writes a hook response payload to w. The response
// shape is provider-specific but the (continue, suppressOutput,
// systemMessage) tuple is shared.
WriteHookResponse(w io.Writer, suppressOutput bool, systemMessage string) error
// InitTranscript is called from sync.Engine.Init AFTER the backend has
// returned the initial sync state and the transcript file has been
// registered in the tracker. Codex reads session_meta and attaches
// codex_rollout metadata to the root transcript so the first chunk
// uploaded carries it. Claude is a no-op. The engine logs+continues on
// error; implementations may return one for true I/O failures.
InitTranscript(target TranscriptRegistrar, transcriptPath, externalID string) error
// DiscoverDescendants is called once per SyncAll cycle, BEFORE the BFS
// loop. Providers with an external discovery model (Codex: SQLite
// subtree walk) register newly-discovered sidechain files via reg.
// Must be idempotent across calls (skip already-tracked filenames).
// Claude is a no-op (its agents are discovered transitively from
// transcript content, handled in tracker.DiscoverNewFiles).
DiscoverDescendants(reg DescendantRegistrar, externalID string) error
// AnnotateChunk is called for every chunk read from a tracked file,
// BEFORE upload. Providers attach provider-specific chunk metadata
// (codex_rollout, first_user_message, summary). The redact closure is
// nil-safe; providers must guard `if redact != nil { ... }` before
// applying. Engine inspects the returned AnnotationResult to flip its
// sentFirstUserMessage flag and dispatch any extracted summary links.
AnnotateChunk(c ChunkView, sentFirstUserMessage bool, redact func(string) string) AnnotationResult
// ScanSessions returns the user-initiated sessions discoverable on
// disk for this provider, sorted oldest first. Subagent rollouts and
// other non-user transcripts are filtered out.
ScanSessions() ([]SessionInfo, error)
// FindSessionByID resolves a full or partial session ID to its full
// ID and transcript path. For providers with a thread tree (Codex)
// this walks up to the root so the returned (id, path) refer to the
// top-most user session — callers that want the unwalked rollout use
// provider-specific methods.
FindSessionByID(partialID string) (id, transcriptPath string, err error)
// ExtractMetadata parses summary, first user message, and
// (Claude-only) summary links from in-memory transcript lines.
// Implementations cap the line count to bound cost.
ExtractMetadata(lines []string) SessionMetadata
// DefaultCWD returns the working directory to record alongside an
// upload for this transcript path. Claude derives from the path;
// Codex reads session_meta.cwd with a path-dir fallback.
DefaultCWD(transcriptPath string) string
}
Provider abstracts per-tool local behavior. Adding a new provider means implementing this interface and registering the instance.
type SessionInfo ¶
type SessionInfo struct {
SessionID string
TranscriptPath string
ProjectPath string
ModTime time.Time
SizeBytes int64
Summary string
FirstUserMessage string
}
SessionInfo is the cross-provider shape returned by Provider.ScanSessions and Provider.FindSessionByID. Concrete provider types may keep richer internal forms (e.g. CodexSessionInfo) and project to SessionInfo at the seams.
type SessionMetadata ¶
type SessionMetadata struct {
Summary string
FirstUserMessage string
SummaryLinks []SummaryLink
}
SessionMetadata is the parsed metadata for a transcript file or in-memory chunk. SummaryLinks are Claude-only and stay nil for other providers.
type SummaryLink ¶
SummaryLink describes a parent-session summary link extracted from a Claude transcript chunk. The engine HTTPs them after AnnotateChunk returns; the provider remains side-effect-free.
type TranscriptRegistrar ¶
type TranscriptRegistrar interface {
SetCodexRollout(*CodexRolloutMetadata)
}
TranscriptRegistrar is the minimal surface InitTranscript sees on the root transcript's TrackedFile. *sync.TrackedFile satisfies it structurally via SetCodexRollout. Lives here (not pkg/sync) to avoid an import cycle.