Documentation
¶
Overview ¶
Package agent watches the JSONL transcripts that Codex and Claude Code write while their TUI runs, and projects those files as normalized events. The PTY byte stream stays the source of truth; this is a side channel for clients (notably Web) that want a structured view of the same process.
Index ¶
- Constants
- func BindDir() string
- func BindEnvironment(warrenSessionID, kind string) []string
- func BindPath(warrenSessionID string) string
- func ClaudeConfigDir() string
- func ClaudeProjectsRoot() string
- func ClaudeTranscriptPath(claudeRoot, workspacePath, sessionID string) string
- func CodexHome() string
- func EnsureClaudeBindHook(claudeConfigDir string) (changed bool, err error)
- func EnsureCodexBindHook(codexHome string) (changed bool, err error)
- func InjectClaudeSessionID(command, warrenSessionID string) string
- func ProjectEvents(events []api.AgentEvent, options ReadOptions) ([]api.AgentEvent, error)
- func ReadAgentStatus(path string) (api.AgentStatus, error)
- func ReadTranscript(ctx context.Context, provider, path string, options ReadOptions) ([]api.AgentEvent, error)
- func RemoveBinding(warrenSessionID string)
- func StatePath(warrenSessionID string) string
- func WriteAgentStatus(path string, status api.AgentStatus) error
- func WriteBinding(path string, binding Binding) error
- type ActivityTracker
- func (t *ActivityTracker) Activity() api.AgentActivity
- func (t *ActivityTracker) ClearAttention()
- func (t *ActivityTracker) DrainTurns() []api.AgentTurn
- func (t *ActivityTracker) Exited()
- func (t *ActivityTracker) MarkAttention(kind api.AgentAttentionKind, reason, requestID string, since time.Time)
- func (t *ActivityTracker) Observe(event api.AgentEvent)
- func (t *ActivityTracker) Status() api.AgentStatus
- func (t *ActivityTracker) Tick(now time.Time)
- func (t *ActivityTracker) Turn() uint64
- func (t *ActivityTracker) TurnAborted()
- func (t *ActivityTracker) TurnComplete()
- func (t *ActivityTracker) TurnFailed()
- func (t *ActivityTracker) TurnStarted()
- type Binding
- type DefaultFinder
- type Finder
- type ReadOptions
- type Watcher
Constants ¶
const ( // BindEnvSession marks the Warren session owning the CLI process. Hooks // and tool subprocesses see it, but only the managed hook uses it. BindEnvSession = "WARREN_SESSION_ID" // BindEnvFile points the managed hook at the file it must write with the // CLI session ID and transcript path. BindEnvFile = "WARREN_BIND_FILE" // BindEnvKind names the agent kind (codex or claude) for the hook. BindEnvKind = "WARREN_AGENT_KIND" // BindEnvState points the managed hook at the file it must update when the // CLI session changes lifecycle, so the daemon can update the status overlay. BindEnvState = "WARREN_STATE_FILE" // CodexSessionID and CodexThreadID are launcher-provided identity hints. // An interactive shell can inherit them from its parent Codex process; an // independently-created Warren session must not reuse that conversation. BindEnvCodexSessionID = "CODEX_SESSION_ID" BindEnvCodexThreadID = "CODEX_THREAD_ID" )
const ( // DefaultReadRecent bounds a command result so an external agent does not // accidentally ingest an entire long-running conversation. DefaultReadRecent = 20 // DefaultReadContentLimit is measured in Unicode code points, not bytes. DefaultReadContentLimit = 2000 // MaxReadActivities bounds an unbounded (--all) read. Callers that need a // smaller response should set Recent explicitly. MaxReadActivities = 100000 )
Variables ¶
This section is empty.
Functions ¶
func BindEnvironment ¶
BindEnvironment returns the runtime environment entries a session needs so the managed hook can report an agent CLI's own session ID to Warren.
func ClaudeConfigDir ¶
func ClaudeConfigDir() string
ClaudeConfigDir returns the directory Claude reads settings from, honoring CLAUDE_CONFIG_DIR just like the CLI itself.
func ClaudeProjectsRoot ¶
func ClaudeProjectsRoot() string
ClaudeProjectsRoot returns the directory Claude writes transcripts into, honoring CLAUDE_CONFIG_DIR just like the CLI itself.
func ClaudeTranscriptPath ¶
ClaudeTranscriptPath computes the transcript file Claude writes for a given session ID in a given working directory.
func CodexHome ¶
func CodexHome() string
CodexHome returns the Codex configuration directory the daemon's children inherit, honoring CODEX_HOME just like the CLI itself.
func EnsureClaudeBindHook ¶
EnsureClaudeBindHook installs the same two hooks into Claude's user settings file, preserving every existing entry.
func EnsureCodexBindHook ¶
EnsureCodexBindHook installs the Warren SessionStart and SessionEnd hooks into Codex's user hooks file, preserving every existing entry.
func InjectClaudeSessionID ¶
InjectClaudeSessionID makes Claude's transcript path deterministic for a Warren session. Existing resume/session flags are left untouched so a user who explicitly resumes an older conversation keeps their intent.
func ProjectEvents ¶
func ProjectEvents(events []api.AgentEvent, options ReadOptions) ([]api.AgentEvent, error)
ProjectEvents applies the same filtering and content limits as ReadTranscript to events already retained by a live Host watcher. This is used by remote session readers, where the transcript file lives on the Host rather than on the CLI machine.
func ReadAgentStatus ¶
func ReadAgentStatus(path string) (api.AgentStatus, error)
ReadAgentStatus returns the status recorded by the managed hook, or a zero status when the file is missing or malformed.
func ReadTranscript ¶
func ReadTranscript(ctx context.Context, provider, path string, options ReadOptions) ([]api.AgentEvent, error)
ReadTranscript parses one Codex or Claude JSONL transcript into the same normalized events used by Warren's live agent view. The file is consumed line by line, so the reader never loads the whole transcript into memory.
func RemoveBinding ¶
func RemoveBinding(warrenSessionID string)
RemoveBinding cleans up the per-session file when the session is deleted.
func StatePath ¶
StatePath is the per-session file the managed hook uses to report lifecycle changes to the daemon.
func WriteAgentStatus ¶
func WriteAgentStatus(path string, status api.AgentStatus) error
WriteAgentStatus persists a status reported by a hook. The write is atomic so the daemon never reads a half-written status file.
func WriteBinding ¶
WriteBinding persists the binding reported by a hook. It is safe for the hook and the daemon to race: both write the same structured JSON and the daemon only starts a watcher for a path that exists on disk.
Types ¶
type ActivityTracker ¶
type ActivityTracker struct {
// contains filtered or unexported fields
}
ActivityTracker folds normalized transcript events into an AgentStatus. It owns lifecycle and liveness state; provider-specific attention observations can be applied through MarkAttention without teaching the tracker provider event names.
func NewActivityTracker ¶
func NewActivityTracker() *ActivityTracker
NewActivityTracker starts an agent in the ready state: open and idle.
func (*ActivityTracker) Activity ¶
func (t *ActivityTracker) Activity() api.AgentActivity
Activity returns the lifecycle portion of Status.
func (*ActivityTracker) ClearAttention ¶
func (t *ActivityTracker) ClearAttention()
ClearAttention removes a pending human-facing condition without changing the current lifecycle state.
func (*ActivityTracker) DrainTurns ¶
func (t *ActivityTracker) DrainTurns() []api.AgentTurn
DrainTurns returns lifecycle transitions observed since the previous call.
func (*ActivityTracker) Exited ¶
func (t *ActivityTracker) Exited()
Exited marks the agent process as gone.
func (*ActivityTracker) MarkAttention ¶
func (t *ActivityTracker) MarkAttention(kind api.AgentAttentionKind, reason, requestID string, since time.Time)
MarkAttention applies a provider-neutral human-facing observation. The reducer owns the resulting activity so callers cannot accidentally create a yellow state without the corresponding blocked/warning lifecycle state.
func (*ActivityTracker) Observe ¶
func (t *ActivityTracker) Observe(event api.AgentEvent)
Observe advances the tracker from one normalized transcript event.
func (*ActivityTracker) Status ¶
func (t *ActivityTracker) Status() api.AgentStatus
Status returns the current complete presentation state.
func (*ActivityTracker) Tick ¶
func (t *ActivityTracker) Tick(now time.Time)
Tick notices a tool call that has made no progress for the liveness grace period. It intentionally produces a stalled warning, never an input or approval request.
func (*ActivityTracker) Turn ¶
func (t *ActivityTracker) Turn() uint64
Turn returns the current turn number. It remains stable after completion so events emitted at the boundary can still be associated with that turn.
func (*ActivityTracker) TurnAborted ¶
func (t *ActivityTracker) TurnAborted()
TurnAborted marks a turn the user interrupted. An intentional interruption is a normal return to idle, not an outstanding request for attention.
func (*ActivityTracker) TurnComplete ¶
func (t *ActivityTracker) TurnComplete()
TurnComplete marks a finished turn. The agent is idle and ready for the next instruction.
func (*ActivityTracker) TurnFailed ¶
func (t *ActivityTracker) TurnFailed()
TurnFailed marks a turn that ended with an error.
func (*ActivityTracker) TurnStarted ¶
func (t *ActivityTracker) TurnStarted()
TurnStarted marks the beginning of a new turn and clears attention from a request that the new user turn supersedes.
type Binding ¶
type Binding struct {
Provider string `json:"provider"`
SessionID string `json:"sessionId"`
TranscriptPath string `json:"transcriptPath"`
Cwd string `json:"cwd,omitempty"`
UpdatedAt time.Time `json:"updatedAt"`
}
Binding records which Codex/Claude conversation belongs to one Warren session. It is written by the Warren-managed SessionStart hook (Codex) or derived from the deterministic `--session-id` flag (Claude), and read by the daemon so transcript discovery is keyed by the CLI's own session ID instead of guessing by cwd and mtime.
func ReadBinding ¶
ReadBinding returns nil when the file does not exist or is malformed; a malformed file is transient while a hook is mid-write, so callers retry.
type DefaultFinder ¶
type DefaultFinder struct {
// CodexRoot is the Codex sessions directory (default ~/.codex/sessions).
CodexRoot string
// ClaudeRoot is the Claude Code projects directory (default ~/.claude/projects).
ClaudeRoot string
}
DefaultFinder implements Finder for the stock Codex and Claude Code layouts.
type Finder ¶
type Finder interface {
Find(ctx context.Context, kind, workspacePath string, after time.Time) (string, error)
}
Finder locates the transcript file for a running Codex or Claude session. A missing file is not an error: the CLI may not be installed, may not have written a transcript yet, or may be running a version with a different layout. Callers retry until the file appears.
type ReadOptions ¶
type ReadOptions struct {
Recent int
ContentLimit int
Full bool
IncludeTypes []string
ExcludeTypes []string
}
ReadOptions controls how a transcript is projected for an external caller. A zero Recent means that every matching event is returned. ContentLimit is ignored when Full is true; a zero ContentLimit uses the default limit.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher tails one transcript file and emits normalized events. The first poll replays existing history; later polls only deliver newly appended lines. A truncated file restarts from byte zero without re-emitting the already-served prefix, which is acceptable for a best-effort side channel.
func Start ¶
func Start( sessionID, provider, path string, onEvents func([]api.AgentEvent, api.AgentStatus), onStatus func(api.AgentStatus), onTurns func([]api.AgentTurn, bool), ) *Watcher
Start begins tailing path immediately in a background goroutine.
func (*Watcher) Close ¶
func (w *Watcher) Close()
Close stops the poll loop and waits for it to finish.
func (*Watcher) Snapshot ¶
func (w *Watcher) Snapshot() []api.AgentEvent
Snapshot returns the retained event history.