Documentation
¶
Index ¶
- Constants
- Variables
- func CWDFromContext(ctx context.Context) string
- func CaptureAndRoute(ctx context.Context, provider HookProvider, event *Event, bh *broker.Handle, ...) error
- func CaptureAndRouteForRepo(ctx context.Context, provider HookProvider, event *Event, bh *broker.Handle, ...) (bool, error)
- func CaptureDirWritable() error
- func DeleteCaptureState(sessionID string) error
- func DeleteCaptureStateByKey(key string) error
- func Dispatch(ctx context.Context, provider HookProvider, event *Event, bh *broker.Handle, ...) error
- func ExtractBinary(command string) string
- func GuardedCommand(bin, args string) string
- func HookTimestampFromContext(ctx context.Context) int64
- func MarshalCompactJSON(v any) ([]byte, error)
- func MarshalSettingsJSON(v any) ([]byte, error)
- func ModelFromContext(ctx context.Context) string
- func SaveCaptureState(state *CaptureState) error
- func WithHookStart(ctx context.Context, start time.Time) context.Context
- type CaptureState
- type CwdGatedProvider
- type DirectHookEmitter
- type DiscoveryContext
- type Event
- type EventType
- type HookProvider
- type OffsetAuthoritativeReader
- type PendingTurnBoundary
- type Registry
- type SubagentDiscoverer
- type SweepReport
- type ToolWindowStatus
- type TranscriptPreparer
Constants ¶
const ManagedCommand = "semantica"
ManagedCommand is the CLI command provider hooks should invoke by default. It intentionally uses the bare executable name so hook configs survive moves between install locations like Homebrew, curl installs, and local rebuilds.
Variables ¶
var CWDKey = cwdKeyType{}
CWDKey carries the working directory from capture state into ReadFromOffset for providers whose transcripts don't embed a project path.
var CaptureTimestampKey = captureTimestampKeyType{}
CaptureTimestampKey carries the capture state's unix-ms timestamp into ReadFromOffset for turn-scoped enrichment.
var ErrNoCaptureState = errors.New("no capture state")
ErrNoCaptureState is returned when no capture state file exists for a session.
var HookEventTypeKey = hookEventTypeKeyType{}
HookEventTypeKey carries the current lifecycle event type into provider transcript preparation.
var HookTimestampKey = hookTimestampKeyType{}
HookTimestampKey carries the current hook timestamp into provider transcript preparation.
var ModelKey = modelKeyType{}
ModelKey carries the hook event's model name into ReadFromOffset.
Functions ¶
func CWDFromContext ¶
CWDFromContext extracts the working directory from the context, or "" if absent.
func CaptureAndRoute ¶
func CaptureAndRoute(ctx context.Context, provider HookProvider, event *Event, bh *broker.Handle, blobStore *blobs.Store) error
CaptureAndRoute reads a transcript delta, routes the resulting events, and advances the saved offset only after every repo write succeeds.
func CaptureAndRouteForRepo ¶ added in v0.6.0
func CaptureAndRouteForRepo(ctx context.Context, provider HookProvider, event *Event, bh *broker.Handle, blobStore *blobs.Store, repoRoot string) (bool, error)
CaptureAndRouteForRepo routes only when every event belongs to repoRoot. A cross-repository result leaves the offset unchanged and returns false.
func CaptureDirWritable ¶ added in v0.3.6
func CaptureDirWritable() error
CaptureDirWritable probes whether the global capture directory is writable.
func DeleteCaptureState ¶
DeleteCaptureState removes a capture state file by session ID.
func DeleteCaptureStateByKey ¶
DeleteCaptureStateByKey removes a capture state file by its key.
func Dispatch ¶
func Dispatch(ctx context.Context, provider HookProvider, event *Event, bh *broker.Handle, blobStore *blobs.Store) error
Dispatch routes a normalized hook event.
func ExtractBinary ¶ added in v0.3.3
ExtractBinary returns the binary path from a hook command string. Handles both guarded ("if command -v X ...; then X capture ...; fi") and unguarded ("X capture ...") formats.
func GuardedCommand ¶ added in v0.3.3
GuardedCommand wraps a capture command with a shell guard that silently no-ops when the binary is not on PATH. Ensures the hook never blocks the agent and never produces errors for teammates who don't have Semantica.
func HookTimestampFromContext ¶
HookTimestampFromContext extracts the current hook timestamp in unix-ms, or 0 if absent.
func MarshalCompactJSON ¶ added in v0.3.8
MarshalCompactJSON is the compact counterpart for json.RawMessage fragments embedded inside settings documents.
func MarshalSettingsJSON ¶ added in v0.3.8
MarshalSettingsJSON serializes hook settings as indented JSON without HTML escaping, keeping shell commands readable.
func ModelFromContext ¶
ModelFromContext extracts the model name from the context, or "" if absent.
func SaveCaptureState ¶
func SaveCaptureState(state *CaptureState) error
SaveCaptureState writes a capture state through a unique temp file.
Multiple hook processes can update the same session concurrently, so each writer gets its own staging path. The live file is replaced only after the JSON has been fully written and closed. Temp files end in .json.tmp so LoadActiveCaptureStates ignores in-flight writes.
Types ¶
type CaptureState ¶
type CaptureState struct {
SessionID string `json:"session_id"`
StateKey string `json:"state_key,omitempty"` // Override key; defaults to SessionID.
Provider string `json:"provider"`
TranscriptRef string `json:"transcript_ref"`
TranscriptOffset int `json:"transcript_offset"`
Timestamp int64 `json:"timestamp"`
TurnID string `json:"turn_id,omitempty"`
PromptSubmittedAt int64 `json:"prompt_submitted_at,omitempty"`
CWD string `json:"cwd,omitempty"` // working directory from hook payload
// TurnStartOffset is the transcript EOF at prompt submission.
TurnStartOffset int `json:"turn_start_offset,omitempty"`
// ScopedDeferrals counts cross-repository replay deferrals.
ScopedDeferrals int `json:"scoped_deferrals,omitempty"`
LastDeferredAt int64 `json:"last_deferred_at,omitempty"`
// PendingTurns records unresolved turn boundaries, oldest first.
PendingTurns []PendingTurnBoundary `json:"pending_turns,omitempty"`
// OrphanedAt marks deferred state retained after a transcript switch.
OrphanedAt int64 `json:"orphaned_at,omitempty"`
}
CaptureState tracks the current offset for an active transcript.
func LoadActiveCaptureStates ¶
func LoadActiveCaptureStates() ([]*CaptureState, error)
LoadActiveCaptureStates returns states that remain eligible for capture.
func LoadCaptureState ¶
func LoadCaptureState(sessionID string) (*CaptureState, error)
LoadCaptureState reads a capture state file for the given session. Returns ErrNoCaptureState if the file does not exist.
func LoadCaptureStateByKey ¶
func LoadCaptureStateByKey(key string) (*CaptureState, error)
LoadCaptureStateByKey reads a capture state file by its key. Returns ErrNoCaptureState if the file does not exist.
func LoadOrphanedCaptureStates ¶ added in v0.6.0
func LoadOrphanedCaptureStates() ([]*CaptureState, error)
LoadOrphanedCaptureStates returns deferred state from replaced transcripts.
type CwdGatedProvider ¶ added in v0.5.0
type CwdGatedProvider interface {
// ShouldCapture inspects the raw hook stdin payload and returns true
// when the session originates from a repo that should be captured.
// The payload is the unmodified bytes that ParseHookEvent would
// otherwise consume; implementations must not retain it. Returning
// false suppresses every downstream side effect for this invocation.
//
// activeRepos is the broker's current set of registered, active
// repos. Implementations match the payload's working directory
// against this set using whatever canonicalization rules fit the
// provider (typically resolving the cwd to a git repo root).
//
// Errors are treated as "do not capture" by the capture entrypoint;
// because that entrypoint suppresses every downstream side effect
// when the gate denies, errors do NOT reach the hook-error log
// either (logging a parse failure here would itself leak that a
// hook fired outside any registered repo, defeating the privacy
// boundary). Implementations should still return errors for genuine
// malformed input so callers writing structured tests can
// distinguish "deny" from "broken". Routine misses (cwd outside
// any registered repo) return false with a nil error.
ShouldCapture(ctx context.Context, payload []byte, activeRepos []broker.RegisteredRepo) (bool, error)
}
CwdGatedProvider is an optional interface for providers whose hook configuration may fire on sessions outside the user's registered repos. When implemented, the capture entrypoint inspects the raw stdin payload before parsing or dispatching and exits cleanly when the session's cwd does not resolve to an enabled repo - no transcript reading, no broker writes, no error logging.
Providers that prefer the default behavior (any registered repo gates capture, regardless of the session's cwd) simply do not implement this interface.
type DirectHookEmitter ¶
type DirectHookEmitter interface {
// BuildHookEvents constructs RawEvents from a hook Event's payload fields.
// Called by the dispatcher for ToolStepCompleted, SubagentPromptSubmitted,
// SubagentCompleted, and optionally PromptSubmitted. The provider stores
// blobs via bs and returns fully populated RawEvents ready for routing and
// writing.
BuildHookEvents(ctx context.Context, event *Event, bs api.BlobPutter) ([]broker.RawEvent, error)
}
DirectHookEmitter is an optional interface for providers that can emit RawEvents directly from hook payloads without waiting for transcript replay. Used by providers that expose structured hook payloads for prompt and tool events such as Write, Edit, Bash, and Agent.
type DiscoveryContext ¶ added in v0.3.8
type DiscoveryContext struct {
// Cwd is the parent session's working directory.
Cwd string
// PromptTime is the parent's PromptSubmitted timestamp in unix-ms.
PromptTime int64
// StopTime is the upper bound of the parent's active window in unix-ms.
StopTime int64
// ParentSessionID is the parent's hook session id.
ParentSessionID string
// ParentAgentName is the parent's agent name when the provider exposes it.
ParentAgentName string
}
DiscoveryContext carries lifecycle-known facts about the parent turn for providers that store child transcripts in a directory shared with unrelated sessions and need extra signals to disambiguate. Fields may be empty; implementations must tolerate that rather than fail outright.
type Event ¶
type Event struct {
Type EventType
SessionID string
TranscriptRef string // path to transcript file
Prompt string // user prompt (PromptSubmitted only)
Model string // LLM model name
Timestamp int64 // unix ms, from hook payload or time.Now()
ToolUseID string // for subagent events and tool steps
SubagentID string
Metadata map[string]string
// Step capture fields (ToolStepCompleted, SubagentPromptSubmitted).
TurnID string // resolved from capture state or set by dispatcher
CWD string // working directory from hook payload
ToolName string // Write, Edit, Bash, Agent, etc.
ToolInput json.RawMessage // raw tool_input from hook payload
ToolResponse json.RawMessage // raw tool_response from hook payload
}
Event is the provider-agnostic representation of an agent lifecycle event. Produced by HookProvider.ParseHookEvent from provider-specific stdin JSON.
type EventType ¶
type EventType int
EventType represents a normalized agent lifecycle event.
const ( PromptSubmitted EventType = iota AgentCompleted SessionOpened SessionClosed ContextCompacted SubagentSpawned SubagentCompleted ToolStepCompleted // state-changing PostToolUse (Write, Edit, Bash) SubagentPromptSubmitted // PreToolUse[Agent] prompt event IncrementalCapture // mid-turn trigger to scan transcript from saved offset ToolStepStarted // PreToolUse for tools with paired window capture (Bash) )
func HookEventTypeFromContext ¶
HookEventTypeFromContext extracts the current lifecycle event type from the context, or false if absent.
func (EventType) HookPhase ¶
HookPhase returns a short stable string for the event's lifecycle point. Used by providers to disambiguate event IDs when the same tool_use_id appears in both a pre and post hook (e.g., PreToolUse[Agent] and PostToolUse[Agent] share a tool_use_id but are different events).
type HookProvider ¶
type HookProvider interface {
// Name returns the provider identifier (e.g., "claude-code").
Name() string
// DisplayName returns a human-friendly label (e.g., "Claude Code").
DisplayName() string
// IsAvailable reports whether the provider can be discovered on this
// machine, either via an executable or provider-specific local state.
IsAvailable() bool
// InstallHooks writes hook configuration to the provider's config file
// (e.g., <repoRoot>/.claude/settings.local.json). Returns the number
// of hooks installed.
InstallHooks(ctx context.Context, repoRoot string, binaryPath string) (int, error)
// UninstallHooks removes Semantica hooks from the provider's repo-local
// config file.
UninstallHooks(ctx context.Context, repoRoot string) error
// AreHooksInstalled checks if Semantica hooks are configured in the
// given repo.
AreHooksInstalled(ctx context.Context, repoRoot string) bool
// HookBinary returns the executable name or path configured in the
// provider's hook settings for the given repo.
// Returns only the binary token, not the full command line with arguments.
// Used by health checks to verify the binary is actually reachable via
// exec.LookPath.
HookBinary(ctx context.Context, repoRoot string) (string, error)
// ParseHookEvent parses stdin JSON into a normalized Event.
ParseHookEvent(ctx context.Context, hookName string, stdin io.Reader) (*Event, error)
// TranscriptOffset returns the current position in the transcript
// (line count for JSONL, message count for JSON).
// Called during PromptSubmitted to capture the offset before the agent acts.
TranscriptOffset(ctx context.Context, transcriptRef string) (int, error)
// ReadFromOffset reads the transcript starting at the given offset and
// returns parsed RawEvents. This is the enrichment step - extracting
// file paths, token usage, tool calls from the provider's format.
ReadFromOffset(ctx context.Context, transcriptRef string, offset int, bs api.BlobPutter) ([]broker.RawEvent, int, error)
}
HookProvider is implemented by each agent provider for hook-based capture.
type OffsetAuthoritativeReader ¶ added in v0.6.0
type OffsetAuthoritativeReader interface {
OffsetReadsAuthoritative() bool
}
OffsetAuthoritativeReader marks providers whose offset reads are exact. Other providers use timestamp-based turn ownership.
type PendingTurnBoundary ¶ added in v0.6.0
type PendingTurnBoundary struct {
TurnID string `json:"turn_id"`
PromptSubmittedAt int64 `json:"prompt_submitted_at"`
StartOffset int `json:"start_offset,omitempty"`
}
PendingTurnBoundary records where an interrupted turn begins.
type Registry ¶ added in v0.5.1
type Registry struct {
// contains filtered or unexported fields
}
Registry stores hook providers. It is safe for concurrent reads after construction.
func NewRegistry ¶ added in v0.5.1
func NewRegistry(providers ...HookProvider) *Registry
NewRegistry constructs a registry. List returns providers in canonical order.
func (*Registry) Get ¶ added in v0.5.1
func (r *Registry) Get(name string) HookProvider
Get returns the named provider, or nil when it is not registered.
func (*Registry) List ¶ added in v0.5.1
func (r *Registry) List() []HookProvider
List returns the registered providers in canonical order.
func (*Registry) ListAvailable ¶ added in v0.5.1
func (r *Registry) ListAvailable() []HookProvider
ListAvailable returns providers available on this host in canonical order.
type SubagentDiscoverer ¶
type SubagentDiscoverer interface {
// DiscoverSubagentTranscripts returns paths to all subagent transcript
// files associated with the given parent transcript. Implementations
// consume only the DiscoveryContext fields they need.
DiscoverSubagentTranscripts(ctx context.Context, parentTranscriptRef string, dctx DiscoveryContext) ([]string, error)
// SubagentStateKey returns a stable key for the subagent's capture state
// file, derived from the subagent transcript path. Must be unique per
// subagent and safe for use as a filename component.
SubagentStateKey(subagentTranscriptRef string) string
}
SubagentDiscoverer is an optional interface for providers that support subagent (child) transcripts stored separately from the parent transcript. When implemented, the SubagentCompleted handler scans for child transcripts and reads each one with its own capture state.
type SweepReport ¶ added in v0.6.0
type SweepReport struct {
PartialsReplayed int
GroupsResumed int
GroupsTerminal int
GroupsReclaimed int
MembersTombstoned int
LinksSkipped int
Errors int
Maintenance toolsnap.MaintenanceReport
MaintenanceSkipped bool
}
SweepReport summarizes one tool-window recovery pass.
func SweepToolWindows ¶ added in v0.6.0
func SweepToolWindows(ctx context.Context, repoPath string) (SweepReport, error)
SweepToolWindows recovers pending evidence before running maintenance. Item failures are counted and do not stop later recovery work.
type ToolWindowStatus ¶ added in v0.6.0
type ToolWindowStatus struct {
ActiveWindows int
StaleWindows int
PendingFinalizations int
PendingPartials int
Tombstones int
MalformedTombstones int
// DegradedGroups counts groups awaiting partial-evidence reclamation.
DegradedGroups int
// BlockedMembers counts completed members in degraded groups.
BlockedMembers int
// OldestActiveAge is the age of the oldest active member.
OldestActiveAge time.Duration
// OldestGroupAge is the age of the oldest open group member.
OldestGroupAge time.Duration
}
ToolWindowStatus summarizes a repository's tool-window state.
func InspectToolWindows ¶ added in v0.6.0
func InspectToolWindows(_ context.Context, repoPath string) (ToolWindowStatus, error)
InspectToolWindows reads tool-window state without modifying it.
type TranscriptPreparer ¶
type TranscriptPreparer interface {
// PrepareTranscript ensures the transcript file is complete and readable.
// Called before ReadFromOffset. Must block until the file is ready or
// a timeout is reached. Return nil on timeout so
// capture proceeds with whatever data is available.
PrepareTranscript(ctx context.Context, transcriptRef string) error
}
TranscriptPreparer is an optional interface for providers whose transcripts may not be fully flushed to disk when the hook fires. If implemented, PrepareTranscript is called before every ReadFromOffset.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package builder provides shared helpers for converting provider hook payloads into broker.RawEvent values.
|
Package builder provides shared helpers for converting provider hook payloads into broker.RawEvent values. |
|
Package codex provides hook-based capture for OpenAI Codex sessions.
|
Package codex provides hook-based capture for OpenAI Codex sessions. |
|
Package testutil provides the shared golden-file harness for the direct-emit hook providers under internal/hooks/<provider>.
|
Package testutil provides the shared golden-file harness for the direct-emit hook providers under internal/hooks/<provider>. |