db

package
v0.22.2 Latest Latest
Warning

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

Go to latest
Published: Apr 13, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// DefaultMessageLimit is the default number of messages returned.
	DefaultMessageLimit = 100
	// MaxMessageLimit is the maximum number of messages returned.
	MaxMessageLimit = 1000
)
View Source
const (
	DefaultSearchLimit = 50
	MaxSearchLimit     = 500
)
View Source
const (
	// DefaultSessionLimit is the default number of sessions returned.
	DefaultSessionLimit = 200
	// MaxSessionLimit is the maximum number of sessions returned.
	MaxSessionLimit = 500
)
View Source
const MaxHeatmapDays = 366

MaxHeatmapDays is the maximum number of day entries the heatmap will return. Ranges exceeding this are clamped to the most recent MaxHeatmapDays from the end date.

Variables

View Source
var ErrInvalidCursor = errors.New("invalid cursor")

ErrInvalidCursor is returned when a cursor cannot be decoded or verified.

View Source
var ErrReadOnly = errReadOnly{}

ErrReadOnly is returned by write methods on read-only store implementations (e.g. the PostgreSQL reader).

View Source
var ErrSessionExcluded = errors.New("session excluded")

ErrSessionExcluded is returned by UpsertSession when the session was permanently deleted by the user. Callers should skip any follow-up writes (messages, tool_calls) for this session.

View Source
var SystemMsgPrefixes = []string{
	"This session is being continued",
	"[Request interrupted",
	"<task-notification>",
	"<command-message>",
	"<command-name>",
	"<local-command-",
	"Stop hook feedback:",
}

SystemMsgPrefixes lists content prefixes that identify system-injected user messages. These are excluded from search results even when the is_system column has not been backfilled (e.g. Claude sessions parsed before schema version 2). Keep in sync with the frontend list in frontend/src/lib/utils/messages.ts.

Functions

func IsAutomatedSession added in v0.18.0

func IsAutomatedSession(firstMessage string) bool

IsAutomatedSession returns true if the first message matches a known automated review/fix prompt pattern.

func SnapInterval added in v0.17.0

func SnapInterval(durationSec int64) int64

SnapInterval picks a bucket interval targeting ~30 buckets. For very long sessions the interval scales beyond the fixed step list so the total bucket count never exceeds maxBuckets.

func SystemPrefixSQL added in v0.16.0

func SystemPrefixSQL(contentCol, roleCol string) string

SystemPrefixSQL returns a SQL clause that excludes user messages matching any system prefix. The column alias for content must be passed (e.g. "m.content" or "m2.content"). Uses case-sensitive substr comparison, which behaves identically on SQLite and PostgreSQL (unlike LIKE, which is case-insensitive on SQLite).

Types

type ActivityEntry

type ActivityEntry struct {
	Date              string         `json:"date"`
	Sessions          int            `json:"sessions"`
	Messages          int            `json:"messages"`
	UserMessages      int            `json:"user_messages"`
	AssistantMessages int            `json:"assistant_messages"`
	ToolCalls         int            `json:"tool_calls"`
	ThinkingMessages  int            `json:"thinking_messages"`
	ByAgent           map[string]int `json:"by_agent"`
}

ActivityEntry is one time bucket in the activity timeline.

type ActivityResponse

type ActivityResponse struct {
	Granularity string          `json:"granularity"`
	Series      []ActivityEntry `json:"series"`
}

ActivityResponse wraps the activity series.

type AgentBreakdown added in v0.21.0

type AgentBreakdown struct {
	Agent               string  `json:"agent"`
	InputTokens         int     `json:"inputTokens"`
	OutputTokens        int     `json:"outputTokens"`
	CacheCreationTokens int     `json:"cacheCreationTokens"`
	CacheReadTokens     int     `json:"cacheReadTokens"`
	Cost                float64 `json:"cost"`
}

AgentBreakdown is the per-agent slice of a day's usage.

type AgentInfo added in v0.9.0

type AgentInfo struct {
	Name         string `json:"name"`
	SessionCount int    `json:"session_count"`
}

AgentInfo holds an agent name and its session count.

type AgentSummary

type AgentSummary struct {
	Sessions int `json:"sessions"`
	Messages int `json:"messages"`
}

AgentSummary holds per-agent counts for the summary.

type AnalyticsFilter

type AnalyticsFilter struct {
	From             string // ISO date YYYY-MM-DD, inclusive
	To               string // ISO date YYYY-MM-DD, inclusive
	Machine          string // optional machine filter
	Project          string // optional project filter
	Agent            string // optional agent filter
	Timezone         string // IANA timezone for day bucketing
	DayOfWeek        *int   // nil = all, 0=Mon, 6=Sun (ISO)
	Hour             *int   // nil = all, 0-23
	MinUserMessages  int    // user_message_count >= N
	ExcludeOneShot   bool   // exclude sessions with user_message_count <= 1
	ExcludeAutomated bool   // exclude automated (roborev) sessions
	ActiveSince      string // ISO timestamp cutoff
}

AnalyticsFilter is the shared filter for all analytics queries.

func (AnalyticsFilter) HasTimeFilter

func (f AnalyticsFilter) HasTimeFilter() bool

HasTimeFilter returns true when hour-of-day or day-of-week filtering is active.

type AnalyticsSummary

type AnalyticsSummary struct {
	TotalSessions          int                      `json:"total_sessions"`
	TotalMessages          int                      `json:"total_messages"`
	TotalOutputTokens      int                      `json:"total_output_tokens"`
	TokenReportingSessions int                      `json:"token_reporting_sessions"`
	ActiveProjects         int                      `json:"active_projects"`
	ActiveDays             int                      `json:"active_days"`
	AvgMessages            float64                  `json:"avg_messages"`
	MedianMessages         int                      `json:"median_messages"`
	P90Messages            int                      `json:"p90_messages"`
	MostActive             string                   `json:"most_active_project"`
	Concentration          float64                  `json:"concentration"`
	Agents                 map[string]*AgentSummary `json:"agents"`
}

AnalyticsSummary is the response for the summary endpoint.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB manages a write connection and a read-only pool. The reader and writer fields use atomic.Pointer so that concurrent HTTP handler goroutines can safely read while Reopen/CloseConnections swap the underlying *sql.DB.

func Open

func Open(path string) (*DB, error)

Open creates or opens a SQLite database at the given path. It configures WAL mode, mmap, and returns a DB with separate writer and reader connections.

If an existing database has an outdated schema (missing columns), it is deleted and recreated from scratch. If the schema is current but the data version is stale, the database is preserved and file mtimes are reset to trigger a re-sync on the next cycle.

func (*DB) BulkStarSessions added in v0.11.0

func (db *DB) BulkStarSessions(sessionIDs []string) error

BulkStarSessions stars multiple sessions in a single transaction. Used for migrating localStorage stars to the database.

func (*DB) Close

func (db *DB) Close() error

Close closes both writer and reader connections, plus any retired pools left over from previous Reopen calls.

func (*DB) CloseConnections added in v0.8.0

func (db *DB) CloseConnections() error

CloseConnections closes both connections without reopening, releasing file locks so the database file can be renamed. Also drains any retired pools from previous Reopen calls. Callers must call Reopen afterwards to restore service.

func (*DB) CopyExcludedSessionsFrom added in v0.11.0

func (d *DB) CopyExcludedSessionsFrom(
	sourcePath string,
) error

CopyExcludedSessionsFrom copies the excluded_sessions table from the source DB so permanently deleted sessions survive full DB rebuilds. The source must not have active connections.

func (*DB) CopyInsightsFrom added in v0.8.0

func (db *DB) CopyInsightsFrom(sourcePath string) error

CopyInsightsFrom copies all insights from the database at sourcePath into this database using ATTACH/DETACH.

func (*DB) CopyOrphanedDataFrom added in v0.10.0

func (d *DB) CopyOrphanedDataFrom(
	sourcePath string,
) (int, error)

CopyOrphanedDataFrom copies sessions (and their messages and tool_calls) that exist in the source database but not in this database. This preserves archived sessions whose source files no longer exist on disk.

Orphaned sessions are identified by ID-diff: any session present in the source but absent from the target after a full file sync. This correctly captures sessions whose source files were deleted, moved, or otherwise lost — exactly the set that would be dropped by a naive DB swap.

The source database must not have active connections (call CloseConnections on its DB handle first). Uses ATTACH DATABASE on a pinned connection for atomicity.

func (*DB) CopySessionMetadataFrom added in v0.11.0

func (d *DB) CopySessionMetadataFrom(
	sourcePath string,
) error

CopySessionMetadataFrom merges user-managed data from the source DB into sessions that were re-synced into this DB. This preserves display_name, deleted_at, starred_sessions, and pinned_messages across full DB rebuilds.

func (*DB) DecodeCursor

func (db *DB) DecodeCursor(s string) (SessionCursor, error)

DecodeCursor parses a base64-encoded cursor string.

func (*DB) DeleteInsight added in v0.4.0

func (db *DB) DeleteInsight(id int64) error

DeleteInsight removes an insight by ID.

func (*DB) DeleteSession

func (db *DB) DeleteSession(id string) error

DeleteSession removes a session and its messages (cascading). The session ID is recorded in excluded_sessions so the sync engine does not re-import it from disk. Both operations run in a single transaction. The exclusion is only written when a session row was actually deleted, preventing ghost entries for non-existent IDs.

func (*DB) DeleteSessionIfTrashed added in v0.11.0

func (db *DB) DeleteSessionIfTrashed(id string) (int64, error)

DeleteSessionIfTrashed atomically deletes a session only if it is currently in the trash (deleted_at IS NOT NULL). Returns the number of rows affected. This avoids a TOCTOU race between checking deleted_at and performing the delete.

func (*DB) DeleteSessions

func (db *DB) DeleteSessions(ids []string) (int, error)

DeleteSessions removes multiple sessions by ID in a single transaction. Batches operations in groups of 500 to stay under SQLite variable limits. Deleted IDs are recorded in excluded_sessions so the sync engine does not re-import them. Returns count of deleted rows.

func (*DB) DeleteSkippedFile added in v0.5.0

func (db *DB) DeleteSkippedFile(path string) error

DeleteSkippedFile removes a single skip cache entry.

func (*DB) DropFTS added in v0.8.0

func (db *DB) DropFTS() error

DropFTS drops the FTS table and its triggers. This makes bulk message delete+reinsert fast by avoiding per-row FTS index updates. Call RebuildFTS after to restore search.

func (*DB) EmptyTrash added in v0.11.0

func (db *DB) EmptyTrash() (int, error)

EmptyTrash permanently deletes all soft-deleted sessions. Session IDs are recorded in excluded_sessions so the sync engine does not re-import them. Both operations run in a single transaction to prevent ghost exclusions when the delete fails. Returns the count of deleted rows.

func (*DB) EncodeCursor

func (db *DB) EncodeCursor(endedAt, id string, total ...int) string

EncodeCursor returns a base64-encoded cursor string.

func (*DB) FileBackedSessionCount added in v0.8.0

func (db *DB) FileBackedSessionCount(
	ctx context.Context,
) (int, error)

FileBackedSessionCount returns the number of root sessions synced from files (excludes non-file-backed agents like OpenCode and Claude.ai). Used by ResyncAll to decide whether empty file discovery should abort the swap.

func (*DB) FindPruneCandidates

func (db *DB) FindPruneCandidates(
	f PruneFilter,
) ([]Session, error)

FindPruneCandidates returns sessions matching all filter criteria. Returns full Session rows including file metadata.

func (*DB) GetAgents added in v0.9.0

func (db *DB) GetAgents(
	ctx context.Context,
	excludeOneShot, excludeAutomated bool,
) ([]AgentInfo, error)

GetAgents returns distinct agent names with session counts.

func (*DB) GetAllMessages

func (db *DB) GetAllMessages(
	ctx context.Context, sessionID string,
) ([]Message, error)

GetAllMessages returns all messages for a session ordered by ordinal.

func (*DB) GetAnalyticsActivity

func (db *DB) GetAnalyticsActivity(
	ctx context.Context, f AnalyticsFilter,
	granularity string,
) (ActivityResponse, error)

GetAnalyticsActivity returns session/message counts grouped by time bucket.

func (*DB) GetAnalyticsHeatmap

func (db *DB) GetAnalyticsHeatmap(
	ctx context.Context, f AnalyticsFilter,
	metric string,
) (HeatmapResponse, error)

GetAnalyticsHeatmap returns daily counts with intensity levels.

func (*DB) GetAnalyticsHourOfWeek

func (db *DB) GetAnalyticsHourOfWeek(
	ctx context.Context, f AnalyticsFilter,
) (HourOfWeekResponse, error)

GetAnalyticsHourOfWeek returns message counts bucketed by day-of-week and hour-of-day in the user's timezone.

func (*DB) GetAnalyticsProjects

func (db *DB) GetAnalyticsProjects(
	ctx context.Context, f AnalyticsFilter,
) (ProjectsAnalyticsResponse, error)

GetAnalyticsProjects returns per-project analytics.

func (*DB) GetAnalyticsSessionShape

func (db *DB) GetAnalyticsSessionShape(
	ctx context.Context, f AnalyticsFilter,
) (SessionShapeResponse, error)

GetAnalyticsSessionShape returns distribution histograms for session length, duration, and autonomy ratio.

func (*DB) GetAnalyticsSummary

func (db *DB) GetAnalyticsSummary(
	ctx context.Context, f AnalyticsFilter,
) (AnalyticsSummary, error)

GetAnalyticsSummary returns aggregate statistics.

func (*DB) GetAnalyticsTools

func (db *DB) GetAnalyticsTools(
	ctx context.Context, f AnalyticsFilter,
) (ToolsAnalyticsResponse, error)

GetAnalyticsTools returns tool usage analytics aggregated from the tool_calls table.

func (*DB) GetAnalyticsTopSessions

func (db *DB) GetAnalyticsTopSessions(
	ctx context.Context, f AnalyticsFilter, metric string,
) (TopSessionsResponse, error)

GetAnalyticsTopSessions returns the top 10 sessions by the given metric ("messages", "duration", or "output_tokens") within the filter.

func (*DB) GetAnalyticsVelocity

func (db *DB) GetAnalyticsVelocity(
	ctx context.Context, f AnalyticsFilter,
) (VelocityResponse, error)

GetAnalyticsVelocity computes turn cycle, first response, and throughput metrics with breakdowns by agent and complexity.

func (*DB) GetChildSessions added in v0.7.0

func (db *DB) GetChildSessions(
	ctx context.Context, parentID string,
) ([]Session, error)

GetChildSessions returns sessions whose parent_session_id matches the given parentID, ordered by started_at ascending.

func (*DB) GetDailyUsage added in v0.20.0

func (db *DB) GetDailyUsage(
	ctx context.Context, f UsageFilter,
) (DailyUsageResult, error)

GetDailyUsage returns token usage and cost aggregated by day. It scans messages with non-empty token_usage JSON blobs, parses them in Go (faster than SQLite's json_extract per row), joins against an in-memory pricing map, and buckets by local date.

func (*DB) GetFileInfoByPath added in v0.4.1

func (db *DB) GetFileInfoByPath(
	path string,
) (size int64, mtime int64, ok bool)

GetFileInfoByPath returns file_size and file_mtime for a session identified by file_path. Used for codex/gemini files where the session ID requires parsing.

func (*DB) GetInsight added in v0.4.0

func (db *DB) GetInsight(
	ctx context.Context, id int64,
) (*Insight, error)

GetInsight returns a single insight by ID. Returns nil, nil if not found.

func (*DB) GetMachines

func (db *DB) GetMachines(
	ctx context.Context,
	excludeOneShot, excludeAutomated bool,
) ([]string, error)

GetMachines returns distinct machine names.

func (*DB) GetMessageByOrdinal

func (db *DB) GetMessageByOrdinal(
	sessionID string, ordinal int,
) (*Message, error)

GetMessageByOrdinal returns a single message by session ID and ordinal.

func (*DB) GetMessages

func (db *DB) GetMessages(
	ctx context.Context,
	sessionID string, from, limit int, asc bool,
) ([]Message, error)

GetMessages returns paginated messages for a session. from: starting ordinal (inclusive) limit: max messages to return asc: true for ascending ordinal order, false for descending

func (*DB) GetModelPricing added in v0.20.0

func (db *DB) GetModelPricing(
	model string,
) (*ModelPricing, error)

GetModelPricing returns pricing for an exact model match. Returns nil, nil if not found.

func (*DB) GetPinnedMessageIDs added in v0.11.0

func (db *DB) GetPinnedMessageIDs(
	ctx context.Context, sessionID string,
) (map[int64]bool, error)

GetPinnedMessageIDs returns message IDs that are pinned for a session.

func (*DB) GetPricingMeta added in v0.22.2

func (db *DB) GetPricingMeta(key string) (string, error)

GetPricingMeta reads a metadata value stored as a sentinel row in model_pricing. Returns "" if not found.

func (*DB) GetProjects

func (db *DB) GetProjects(
	ctx context.Context,
	excludeOneShot, excludeAutomated bool,
) ([]ProjectInfo, error)

GetProjects returns project names with session counts.

func (*DB) GetSession

func (db *DB) GetSession(
	ctx context.Context, id string,
) (*Session, error)

GetSession returns a single session by ID, excluding soft-deleted (trashed) sessions.

func (*DB) GetSessionActivity added in v0.17.0

func (d *DB) GetSessionActivity(
	ctx context.Context, sessionID string,
) (*SessionActivityResponse, error)

GetSessionActivity returns time-bucketed message counts for a session. Only visible messages are counted (system and prefix-detected injected messages excluded).

func (*DB) GetSessionFileInfo

func (db *DB) GetSessionFileInfo(
	id string,
) (size int64, mtime int64, ok bool)

GetSessionFileInfo returns file_size and file_mtime for a session. Used for fast skip checks during sync.

func (*DB) GetSessionFilePath added in v0.14.0

func (db *DB) GetSessionFilePath(id string) string

GetSessionFilePath returns the stored file_path for a session, or empty string if not found or NULL.

func (*DB) GetSessionForIncremental added in v0.13.0

func (db *DB) GetSessionForIncremental(
	path string,
) (*IncrementalInfo, bool)

GetSessionForIncremental returns session state needed for incremental parsing, looked up by file_path. Returns false when the path is unknown or maps to multiple sessions (e.g. Claude DAG forks), since incremental parsing cannot update multiple sessions from a single append.

func (*DB) GetSessionFull

func (db *DB) GetSessionFull(
	ctx context.Context, id string,
) (*Session, error)

GetSessionFull returns a single session by ID with all file metadata.

func (*DB) GetSessionMessageCount added in v0.13.0

func (db *DB) GetSessionMessageCount(
	id string,
) (count int, ok bool)

GetSessionMessageCount returns the message_count for a session. Returns (0, false) when the session does not exist.

func (*DB) GetSessionVersion added in v0.13.0

func (db *DB) GetSessionVersion(
	id string,
) (count int, fileMtime int64, ok bool)

GetSessionVersion returns the message count and file mtime for change detection in SSE watchers.

func (*DB) GetStats

func (db *DB) GetStats(
	ctx context.Context,
	excludeOneShot, excludeAutomated bool,
) (Stats, error)

GetStats returns database statistics, counting only root sessions with messages (matching the session list filter).

func (*DB) GetSyncState added in v0.16.0

func (db *DB) GetSyncState(key string) (string, error)

GetSyncState reads a value from the pg_sync_state table.

func (*DB) GetTopSessionsByCost added in v0.21.0

func (db *DB) GetTopSessionsByCost(
	ctx context.Context, f UsageFilter, limit int,
) ([]TopSessionEntry, error)

GetTopSessionsByCost returns sessions ranked by total cost over the filter range. Default limit 20, max 100.

func (*DB) GetUsageSessionCounts added in v0.21.0

func (db *DB) GetUsageSessionCounts(
	ctx context.Context, f UsageFilter,
) (UsageSessionCounts, error)

GetUsageSessionCounts returns distinct session counts grouped by project and agent. Sessions spanning multiple days count once. Soft-deleted sessions are excluded via usageMessageEligibility.

Like GetDailyUsage and GetTopSessionsByCost, this query pads the UTC bounds by +/-14h and applies a post-query localDate filter so timezone-boundary messages are counted correctly.

func (*DB) HasFTS

func (db *DB) HasFTS() bool

HasFTS checks if Full Text Search is available.

func (*DB) InsertInsight added in v0.4.0

func (db *DB) InsertInsight(s Insight) (int64, error)

InsertInsight inserts an insight and returns its ID.

func (*DB) InsertMessages

func (db *DB) InsertMessages(msgs []Message) error

InsertMessages batch-inserts messages for a session.

func (*DB) IsSessionExcluded added in v0.11.0

func (db *DB) IsSessionExcluded(id string) bool

IsSessionExcluded returns true if the session ID was permanently deleted by the user.

func (*DB) LinkSubagentSessions added in v0.14.0

func (db *DB) LinkSubagentSessions() error

LinkSubagentSessions sets parent_session_id and relationship_type on sessions that are referenced by tool_calls.subagent_session_id. Updates sessions that either have no parent yet or have a non-subagent relationship (e.g. a Zencoder session classified as "continuation" from header parentId that is actually a spawned subagent).

func (*DB) ListInsights added in v0.4.0

func (db *DB) ListInsights(
	ctx context.Context, f InsightFilter,
) ([]Insight, error)

ListInsights returns insights matching the filter, ordered by created_at DESC, capped at 500 rows.

func (*DB) ListPinnedMessages added in v0.11.0

func (db *DB) ListPinnedMessages(
	ctx context.Context, sessionID string, project string,
) ([]PinnedMessage, error)

ListPinnedMessages returns all pins, optionally filtered by session or project. Pass empty sessionID for all pins across all sessions. When listing all pins, message content and role are included. project is only applied when sessionID is empty.

func (*DB) ListSessions

func (db *DB) ListSessions(
	ctx context.Context, f SessionFilter,
) (SessionPage, error)

ListSessions returns a cursor-paginated list of sessions.

func (*DB) ListSessionsModifiedBetween added in v0.16.0

func (db *DB) ListSessionsModifiedBetween(
	ctx context.Context, since, until string,
	projects, excludeProjects []string,
) ([]Session, error)

ListSessionsModifiedBetween returns all sessions created or modified after since and at or before until.

Uses file_mtime (nanoseconds since epoch from the source file) as the primary modification signal so that active sessions with new messages are detected even when ended_at has not changed. Falls back to session timestamps for rows without file_mtime.

Precision note: file_mtime is compared as nanosecond integers, while text timestamps are normalized to millisecond precision (strftime '%f' -> 3 decimal places). Sub-millisecond differences in text timestamp fields are therefore truncated.

func (*DB) ListStarredSessionIDs added in v0.11.0

func (db *DB) ListStarredSessionIDs(
	ctx context.Context,
) ([]string, error)

ListStarredSessionIDs returns all starred session IDs.

func (*DB) ListTrashedSessions added in v0.11.0

func (db *DB) ListTrashedSessions(
	ctx context.Context,
) ([]Session, error)

ListTrashedSessions returns sessions that have been soft-deleted.

func (*DB) LoadSkippedFiles added in v0.5.0

func (db *DB) LoadSkippedFiles() (map[string]int64, error)

LoadSkippedFiles returns all persisted skip cache entries as a map from file_path to file_mtime.

func (*DB) MaxOrdinal added in v0.5.0

func (db *DB) MaxOrdinal(sessionID string) int

MaxOrdinal returns the highest ordinal for a session, or -1 if the session has no messages.

func (*DB) MessageContentFingerprint added in v0.16.0

func (db *DB) MessageContentFingerprint(sessionID string) (sum, max, min int64, err error)

MessageContentFingerprint returns a lightweight fingerprint of all messages for a session, computed as the sum, max, and min of content_length values.

func (*DB) MessageCount

func (db *DB) MessageCount(sessionID string) (int, error)

MessageCount returns the number of messages for a session.

func (*DB) MessageTokenFingerprint added in v0.18.0

func (db *DB) MessageTokenFingerprint(sessionID string) (string, error)

MessageTokenFingerprint returns an exact ordered fingerprint of stored token metadata for a session's messages. Used by PG push fast-paths to detect token metadata changes without rewriting unchanged sessions.

func (*DB) NeedsResync added in v0.10.0

func (db *DB) NeedsResync() bool

NeedsResync reports whether the database was opened with a stale data version, indicating the caller should trigger a full resync (build fresh DB, copy orphaned data, swap) rather than an incremental sync.

func (*DB) Path added in v0.8.0

func (db *DB) Path() string

Path returns the file path of the database.

func (*DB) PinMessage added in v0.11.0

func (db *DB) PinMessage(
	sessionID string, messageID int64, note *string,
) (int64, error)

PinMessage creates a pin for a message. If the message is already pinned, the note is updated. The message must belong to the specified session (enforced via INSERT ... SELECT).

func (*DB) PurgeExcludedSessions added in v0.11.0

func (db *DB) PurgeExcludedSessions() error

PurgeExcludedSessions removes any session rows whose IDs appear in excluded_sessions. Used after a resync to clean up sessions that were synced before their exclusion was recorded.

func (*DB) ReadOnly added in v0.16.0

func (db *DB) ReadOnly() bool

ReadOnly returns false for the local SQLite store.

func (*DB) Reader

func (db *DB) Reader() *sql.DB

Reader returns the read-only connection pool.

func (*DB) RebuildFTS added in v0.8.0

func (db *DB) RebuildFTS() error

RebuildFTS recreates the FTS table, triggers, and repopulates the index from the messages table.

func (*DB) RenameSession added in v0.11.0

func (db *DB) RenameSession(id string, displayName *string) error

RenameSession sets or clears the display_name for a session. Pass nil to clear a custom name (reverts to first_message).

func (*DB) Reopen added in v0.8.0

func (db *DB) Reopen() error

Reopen closes and reopens both connections to the same path. Used after an atomic file swap to pick up the new database contents. Preserves cursorSecret.

func (*DB) ReplaceSessionMessages

func (db *DB) ReplaceSessionMessages(
	sessionID string, msgs []Message,
) error

ReplaceSessionMessages deletes existing and inserts new messages in a single transaction. Any existing pins are preserved by re-attaching them to the new message rows that share the same ordinal (pins for ordinals that no longer exist are dropped).

func (*DB) ReplaceSkippedFiles added in v0.5.0

func (db *DB) ReplaceSkippedFiles(
	entries map[string]int64,
) error

ReplaceSkippedFiles replaces all skip cache entries in a single transaction. This is called after each sync cycle to persist the in-memory skip cache.

func (*DB) ResetAllMtimes added in v0.6.0

func (db *DB) ResetAllMtimes() error

ResetAllMtimes zeroes file_mtime for every session, forcing the next sync to re-process all files regardless of whether their size+mtime matches what was previously stored.

func (*DB) RestoreSession added in v0.11.0

func (db *DB) RestoreSession(id string) (int64, error)

RestoreSession clears deleted_at, making the session visible again. Returns the number of rows affected (0 if session doesn't exist or is not in trash).

func (*DB) Search

func (db *DB) Search(
	ctx context.Context, f SearchFilter,
) (SearchPage, error)

Search performs FTS5 full-text search across messages, grouped by session, plus a LIKE-based search on session display names and first messages.

Results come from two branches joined with UNION ALL:

  1. FTS branch — message content matches. ROW_NUMBER() picks the single best-ranked message per session (rank ASC, ordinal ASC, rowid ASC). The outer JOIN messages_fts includes a MATCH clause to prevent segment duplicates. Ordinal is the matched message's ordinal (≥ 0).

  2. Name branch — display_name / first_message LIKE matches that are NOT already covered by the FTS branch. Ordinal is -1 (no specific message to navigate to).

func (*DB) SearchSession added in v0.14.0

func (db *DB) SearchSession(
	ctx context.Context, sessionID, query string,
) ([]int, error)

SearchSession performs a case-insensitive substring search within a single session's messages, returning matching ordinals in document order. This is used by the in-session find bar (analogous to browser Cmd+F). Both message content and tool-call result_content are searched so that matches inside tool output blocks are reachable. Only fields that the frontend renders and highlights are included to avoid phantom matches.

func (*DB) SetCursorSecret

func (db *DB) SetCursorSecret(secret []byte)

SetCursorSecret updates the secret key used for cursor signing.

func (*DB) SetPricingMeta added in v0.22.2

func (db *DB) SetPricingMeta(key, value string) error

SetPricingMeta stores a metadata value as a sentinel row in model_pricing with zero pricing fields.

func (*DB) SetSyncState added in v0.16.0

func (db *DB) SetSyncState(key, value string) error

SetSyncState writes a value to the pg_sync_state table.

func (*DB) SoftDeleteSession added in v0.11.0

func (db *DB) SoftDeleteSession(id string) error

SoftDeleteSession marks a session as deleted by setting deleted_at.

func (*DB) StarSession added in v0.11.0

func (db *DB) StarSession(sessionID string) (bool, error)

StarSession marks a session as starred. Uses INSERT...SELECT with an EXISTS check so the operation is atomic and avoids FK errors if the session is concurrently deleted. Returns false if the session does not exist (idempotent for already-starred).

func (*DB) SystemMessageFingerprint added in v0.16.0

func (db *DB) SystemMessageFingerprint(sessionID string) (string, error)

SystemMessageFingerprint returns the ordered, comma-separated list of ordinals for system messages in a session (e.g. "0,2,5"). This is an exact fingerprint of the system-message ordinal set: any reclassification of which messages are system — even when counts, sums, or sums-of-squares remain equal — produces a different string. Used by the PG push fast-path.

func (*DB) ToolCallContentFingerprint added in v0.16.0

func (db *DB) ToolCallContentFingerprint(sessionID string) (int64, error)

ToolCallContentFingerprint returns the sum of result_content_length values for a session's tool calls, used as a lightweight content change detector.

func (*DB) ToolCallCount added in v0.16.0

func (db *DB) ToolCallCount(sessionID string) (int, error)

ToolCallCount returns the number of tool_calls rows for a session.

func (*DB) UnpinMessage added in v0.11.0

func (db *DB) UnpinMessage(sessionID string, messageID int64) error

UnpinMessage removes a pin.

func (*DB) UnstarSession added in v0.11.0

func (db *DB) UnstarSession(sessionID string) error

UnstarSession removes a session's star.

func (*DB) Update

func (db *DB) Update(fn func(tx *sql.Tx) error) error

Update executes fn within a write lock and transaction. The transaction is committed if fn returns nil, rolled back otherwise.

func (*DB) UpdateSessionIncremental added in v0.13.0

func (db *DB) UpdateSessionIncremental(
	id string,
	endedAt *string,
	msgCount, userMsgCount int,
	fileSize, fileMtime int64,
	totalOutputTokens, peakContextTokens int,
	hasTotalOutputTokens, hasPeakContextTokens bool,
) error

UpdateSessionIncremental updates only the fields that change during an incremental append: ended_at, message_count, user_message_count, file_size, file_mtime, and token aggregates. All values are absolute (not deltas) so the update is idempotent on retry.

func (*DB) UpsertModelPricing added in v0.20.0

func (db *DB) UpsertModelPricing(
	prices []ModelPricing,
) error

UpsertModelPricing inserts or replaces pricing rows in a single transaction.

func (*DB) UpsertSession

func (db *DB) UpsertSession(s Session) error

UpsertSession inserts or updates a session. Sessions that were permanently deleted (in excluded_sessions) are silently skipped.

type DailyUsageEntry added in v0.20.0

type DailyUsageEntry struct {
	Date                string             `json:"date"`
	InputTokens         int                `json:"inputTokens"`
	OutputTokens        int                `json:"outputTokens"`
	CacheCreationTokens int                `json:"cacheCreationTokens"`
	CacheReadTokens     int                `json:"cacheReadTokens"`
	TotalCost           float64            `json:"totalCost"`
	ModelsUsed          []string           `json:"modelsUsed"`
	ModelBreakdowns     []ModelBreakdown   `json:"modelBreakdowns,omitempty"`
	ProjectBreakdowns   []ProjectBreakdown `json:"projectBreakdowns,omitempty"`
	AgentBreakdowns     []AgentBreakdown   `json:"agentBreakdowns,omitempty"`
}

DailyUsageEntry holds token counts and cost for one day.

type DailyUsageResult added in v0.20.0

type DailyUsageResult struct {
	Daily  []DailyUsageEntry `json:"daily"`
	Totals UsageTotals       `json:"totals"`
}

DailyUsageResult wraps the daily entries and totals.

type DistributionBucket

type DistributionBucket struct {
	Label string `json:"label"`
	Count int    `json:"count"`
}

DistributionBucket is a labeled count for histogram display.

type HeatmapEntry

type HeatmapEntry struct {
	Date  string `json:"date"`
	Value int    `json:"value"`
	Level int    `json:"level"`
}

HeatmapEntry is one day in the heatmap calendar.

type HeatmapLevels

type HeatmapLevels struct {
	L1 int `json:"l1"`
	L2 int `json:"l2"`
	L3 int `json:"l3"`
	L4 int `json:"l4"`
}

HeatmapLevels defines the quartile thresholds for levels 1-4.

type HeatmapResponse

type HeatmapResponse struct {
	Metric      string         `json:"metric"`
	Entries     []HeatmapEntry `json:"entries"`
	Levels      HeatmapLevels  `json:"levels"`
	EntriesFrom string         `json:"entries_from"`
}

HeatmapResponse wraps the heatmap data.

type HourOfWeekCell

type HourOfWeekCell struct {
	DayOfWeek int `json:"day_of_week"` // 0=Mon, 6=Sun
	Hour      int `json:"hour"`        // 0-23
	Messages  int `json:"messages"`
}

HourOfWeekCell is one cell in the 7x24 hour-of-week grid.

type HourOfWeekResponse

type HourOfWeekResponse struct {
	Cells []HourOfWeekCell `json:"cells"`
}

HourOfWeekResponse wraps the hour-of-week heatmap data.

type IncrementalInfo added in v0.13.0

type IncrementalInfo struct {
	ID                   string
	FileSize             int64
	MsgCount             int
	UserMsgCount         int
	TotalOutputTokens    int
	PeakContextTokens    int
	HasTotalOutputTokens bool
	HasPeakContextTokens bool
}

IncrementalInfo holds the data needed for incremental re-parsing of an append-only session file.

type Insight added in v0.4.0

type Insight struct {
	ID        int64   `json:"id"`
	Type      string  `json:"type"`
	DateFrom  string  `json:"date_from"`
	DateTo    string  `json:"date_to"`
	Project   *string `json:"project"`
	Agent     string  `json:"agent"`
	Model     *string `json:"model"`
	Prompt    *string `json:"prompt"`
	Content   string  `json:"content"`
	CreatedAt string  `json:"created_at"`
}

Insight represents a row in the insights table.

type InsightFilter added in v0.4.0

type InsightFilter struct {
	Type       string // "daily_activity" or "agent_analysis"
	Project    string // "" = no filter
	GlobalOnly bool   // true = project IS NULL only
}

InsightFilter specifies how to query insights.

type Message

type Message struct {
	ID               int64           `json:"id"`
	SessionID        string          `json:"session_id"`
	Ordinal          int             `json:"ordinal"`
	Role             string          `json:"role"`
	Content          string          `json:"content"`
	Timestamp        string          `json:"timestamp"`
	HasThinking      bool            `json:"has_thinking"`
	HasToolUse       bool            `json:"has_tool_use"`
	ContentLength    int             `json:"content_length"`
	Model            string          `json:"model"`
	TokenUsage       json.RawMessage `json:"token_usage,omitempty"`
	ContextTokens    int             `json:"context_tokens"`
	OutputTokens     int             `json:"output_tokens"`
	HasContextTokens bool            `json:"has_context_tokens"`
	HasOutputTokens  bool            `json:"has_output_tokens"`
	ClaudeMessageID  string          `json:"claude_message_id,omitempty"`
	ClaudeRequestID  string          `json:"claude_request_id,omitempty"`
	ToolCalls        []ToolCall      `json:"tool_calls,omitempty"`
	ToolResults      []ToolResult    `json:"-"`         // transient, for pairing
	IsSystem         bool            `json:"is_system"` // persisted, filters search/analytics
}

Message represents a row in the messages table.

func (Message) TokenPresence added in v0.18.0

func (m Message) TokenPresence() (bool, bool)

TokenPresence reports whether context/output token fields were present in stored message metadata. It preserves explicit flags, falls back to non-zero numeric values for legacy rows, and inspects raw token_usage payload keys to preserve zero-valued coverage.

type ModelBreakdown added in v0.20.0

type ModelBreakdown struct {
	ModelName           string  `json:"modelName"`
	InputTokens         int     `json:"inputTokens"`
	OutputTokens        int     `json:"outputTokens"`
	CacheCreationTokens int     `json:"cacheCreationTokens"`
	CacheReadTokens     int     `json:"cacheReadTokens"`
	Cost                float64 `json:"cost"`
}

ModelBreakdown holds per-model token and cost breakdown.

type ModelPricing added in v0.20.0

type ModelPricing struct {
	ModelPattern         string  `json:"model_pattern"`
	InputPerMTok         float64 `json:"input_per_mtok"`
	OutputPerMTok        float64 `json:"output_per_mtok"`
	CacheCreationPerMTok float64 `json:"cache_creation_per_mtok"`
	CacheReadPerMTok     float64 `json:"cache_read_per_mtok"`
	UpdatedAt            string  `json:"updated_at"`
}

ModelPricing holds per-model token pricing (per million tokens).

type Percentiles

type Percentiles struct {
	P50 float64 `json:"p50"`
	P90 float64 `json:"p90"`
}

Percentiles holds p50 and p90 values.

type PinnedMessage added in v0.11.0

type PinnedMessage struct {
	ID        int64   `json:"id"`
	SessionID string  `json:"session_id"`
	MessageID int64   `json:"message_id"`
	Ordinal   int     `json:"ordinal"`
	Note      *string `json:"note,omitempty"`
	Content   *string `json:"content,omitempty"`
	Role      *string `json:"role,omitempty"`
	CreatedAt string  `json:"created_at"`

	// Session metadata — populated only for the "all pins" query.
	SessionProject      *string `json:"session_project,omitempty"`
	SessionAgent        *string `json:"session_agent,omitempty"`
	SessionDisplayName  *string `json:"session_display_name,omitempty"`
	SessionFirstMessage *string `json:"session_first_message,omitempty"`
}

PinnedMessage represents a row in the pinned_messages table.

type ProjectAnalytics

type ProjectAnalytics struct {
	Name           string         `json:"name"`
	Sessions       int            `json:"sessions"`
	Messages       int            `json:"messages"`
	FirstSession   string         `json:"first_session"`
	LastSession    string         `json:"last_session"`
	AvgMessages    float64        `json:"avg_messages"`
	MedianMessages int            `json:"median_messages"`
	Agents         map[string]int `json:"agents"`
	DailyTrend     float64        `json:"daily_trend"`
}

ProjectAnalytics holds analytics for a single project.

type ProjectBreakdown added in v0.21.0

type ProjectBreakdown struct {
	Project             string  `json:"project"`
	InputTokens         int     `json:"inputTokens"`
	OutputTokens        int     `json:"outputTokens"`
	CacheCreationTokens int     `json:"cacheCreationTokens"`
	CacheReadTokens     int     `json:"cacheReadTokens"`
	Cost                float64 `json:"cost"`
}

ProjectBreakdown is the per-project slice of a day's usage.

type ProjectInfo

type ProjectInfo struct {
	Name         string `json:"name"`
	SessionCount int    `json:"session_count"`
}

ProjectInfo holds a project name and its session count.

type ProjectsAnalyticsResponse

type ProjectsAnalyticsResponse struct {
	Projects []ProjectAnalytics `json:"projects"`
}

ProjectsAnalyticsResponse wraps the projects list.

type PruneFilter

type PruneFilter struct {
	Project      string // substring match (LIKE '%x%')
	MaxMessages  *int   // user messages <= N (nil = no filter)
	Before       string // ended_at < date (YYYY-MM-DD)
	FirstMessage string // first_message LIKE 'prefix%'
}

PruneFilter defines criteria for finding sessions to prune. Filters combine with AND. At least one must be set.

func (PruneFilter) HasFilters

func (f PruneFilter) HasFilters() bool

HasFilters reports whether at least one filter is set.

type SearchFilter

type SearchFilter struct {
	Query   string
	Project string
	Sort    string // "relevance" (default) or "recency"
	Cursor  int    // offset for pagination
	Limit   int
}

SearchFilter specifies search parameters.

type SearchPage

type SearchPage struct {
	Results    []SearchResult `json:"results"`
	NextCursor int            `json:"next_cursor,omitempty"`
}

SearchPage holds paginated search results.

type SearchResult

type SearchResult struct {
	SessionID      string  `json:"session_id"`
	Project        string  `json:"project"`
	Agent          string  `json:"agent"`
	Name           string  `json:"name"`
	Ordinal        int     `json:"ordinal"`
	SessionEndedAt string  `json:"session_ended_at"`
	Snippet        string  `json:"snippet"`
	Rank           float64 `json:"rank"`
}

SearchResult holds a session-level match with the best-ranked snippet.

type Session

type Session struct {
	ID                   string  `json:"id"`
	Project              string  `json:"project"`
	Machine              string  `json:"machine"`
	Agent                string  `json:"agent"`
	FirstMessage         *string `json:"first_message"`
	DisplayName          *string `json:"display_name,omitempty"`
	StartedAt            *string `json:"started_at"`
	EndedAt              *string `json:"ended_at"`
	MessageCount         int     `json:"message_count"`
	UserMessageCount     int     `json:"user_message_count"`
	ParentSessionID      *string `json:"parent_session_id,omitempty"`
	RelationshipType     string  `json:"relationship_type,omitempty"`
	TotalOutputTokens    int     `json:"total_output_tokens"`
	PeakContextTokens    int     `json:"peak_context_tokens"`
	HasTotalOutputTokens bool    `json:"has_total_output_tokens"`
	HasPeakContextTokens bool    `json:"has_peak_context_tokens"`
	IsAutomated          bool    `json:"is_automated"`
	DeletedAt            *string `json:"deleted_at,omitempty"`
	FilePath             *string `json:"file_path,omitempty"`
	FileSize             *int64  `json:"file_size,omitempty"`
	FileMtime            *int64  `json:"file_mtime,omitempty"`
	FileHash             *string `json:"file_hash,omitempty"`
	LocalModifiedAt      *string `json:"local_modified_at,omitempty"`
	CreatedAt            string  `json:"created_at"`
}

Session represents a row in the sessions table.

type SessionActivityBucket added in v0.17.0

type SessionActivityBucket struct {
	StartTime      string `json:"start_time"`
	EndTime        string `json:"end_time"`
	UserCount      int    `json:"user_count"`
	AssistantCount int    `json:"assistant_count"`
	FirstOrdinal   *int   `json:"first_ordinal"` // nil for empty buckets
}

SessionActivityBucket holds message counts for one time interval.

type SessionActivityResponse added in v0.17.0

type SessionActivityResponse struct {
	Buckets         []SessionActivityBucket `json:"buckets"`
	IntervalSeconds int64                   `json:"interval_seconds"`
	TotalMessages   int                     `json:"total_messages"`
}

SessionActivityResponse is the response for the activity endpoint.

type SessionCoverageCandidate added in v0.18.0

type SessionCoverageCandidate struct {
	ID                string
	TotalOutputTokens int
	PeakContextTokens int
	HasTotal          bool
	HasPeak           bool
}

SessionCoverageCandidate holds the current state of a session's token coverage flags, used as input to ComputeSessionCoverageUpdates.

type SessionCoverageUpdate added in v0.18.0

type SessionCoverageUpdate struct {
	ID       string
	HasTotal bool
	HasPeak  bool
}

SessionCoverageUpdate holds the computed coverage flags for a session that needs updating.

func ComputeSessionCoverageUpdates added in v0.18.0

func ComputeSessionCoverageUpdates(
	candidates []SessionCoverageCandidate,
	msgCoverage map[string][2]bool,
) []SessionCoverageUpdate

ComputeSessionCoverageUpdates computes which sessions need their coverage flags updated based on their current state and message-level coverage. msgCoverage maps session ID to [hasContext, hasOutput]. Returns only sessions whose flags would change.

type SessionCursor

type SessionCursor struct {
	EndedAt string `json:"e"`
	ID      string `json:"i"`
	Total   int    `json:"t,omitempty"`
}

SessionCursor is the opaque pagination token.

type SessionFilter

type SessionFilter struct {
	Project          string
	ExcludeProject   string // exclude sessions with this project name
	Machine          string
	Agent            string
	Date             string // exact date YYYY-MM-DD
	DateFrom         string // range start (inclusive)
	DateTo           string // range end (inclusive)
	ActiveSince      string // ISO-8601 timestamp; filters on most recent activity
	MinMessages      int    // message_count >= N (0 = no filter)
	MaxMessages      int    // message_count <= N (0 = no filter)
	MinUserMessages  int    // user_message_count >= N (0 = no filter)
	ExcludeOneShot   bool   // exclude sessions with user_message_count <= 1
	ExcludeAutomated bool   // exclude sessions where is_automated = 1
	IncludeChildren  bool   // include subagent sessions (for sidebar grouping)
	Cursor           string // opaque cursor from previous page
	Limit            int
}

SessionFilter specifies how to query sessions.

type SessionPage

type SessionPage struct {
	Sessions   []Session `json:"sessions"`
	NextCursor string    `json:"next_cursor,omitempty"`
	Total      int       `json:"total"`
}

SessionPage is a page of session results.

type SessionShapeResponse

type SessionShapeResponse struct {
	Count                int                  `json:"count"`
	LengthDistribution   []DistributionBucket `json:"length_distribution"`
	DurationDistribution []DistributionBucket `json:"duration_distribution"`
	AutonomyDistribution []DistributionBucket `json:"autonomy_distribution"`
}

SessionShapeResponse holds distribution histograms for session characteristics.

type Stats

type Stats struct {
	SessionCount    int     `json:"session_count"`
	MessageCount    int     `json:"message_count"`
	ProjectCount    int     `json:"project_count"`
	MachineCount    int     `json:"machine_count"`
	EarliestSession *string `json:"earliest_session"`
}

Stats holds database-wide statistics.

type Store added in v0.16.0

type Store interface {
	// Cursor pagination.
	SetCursorSecret(secret []byte)
	EncodeCursor(endedAt, id string, total ...int) string
	DecodeCursor(s string) (SessionCursor, error)

	// Sessions.
	ListSessions(ctx context.Context, f SessionFilter) (SessionPage, error)
	GetSession(ctx context.Context, id string) (*Session, error)
	GetSessionFull(ctx context.Context, id string) (*Session, error)
	GetChildSessions(ctx context.Context, parentID string) ([]Session, error)

	// Messages.
	GetMessages(ctx context.Context, sessionID string, from, limit int, asc bool) ([]Message, error)
	GetAllMessages(ctx context.Context, sessionID string) ([]Message, error)
	GetSessionActivity(ctx context.Context, sessionID string) (*SessionActivityResponse, error)

	// Search.
	HasFTS() bool
	Search(ctx context.Context, f SearchFilter) (SearchPage, error)
	SearchSession(ctx context.Context, sessionID, query string) ([]int, error)

	// SSE change detection.
	GetSessionVersion(id string) (count int, fileMtime int64, ok bool)

	// Metadata.
	GetStats(ctx context.Context, excludeOneShot, excludeAutomated bool) (Stats, error)
	GetProjects(ctx context.Context, excludeOneShot, excludeAutomated bool) ([]ProjectInfo, error)
	GetAgents(ctx context.Context, excludeOneShot, excludeAutomated bool) ([]AgentInfo, error)
	GetMachines(ctx context.Context, excludeOneShot, excludeAutomated bool) ([]string, error)

	// Analytics.
	GetAnalyticsSummary(ctx context.Context, f AnalyticsFilter) (AnalyticsSummary, error)
	GetAnalyticsActivity(ctx context.Context, f AnalyticsFilter, granularity string) (ActivityResponse, error)
	GetAnalyticsHeatmap(ctx context.Context, f AnalyticsFilter, metric string) (HeatmapResponse, error)
	GetAnalyticsProjects(ctx context.Context, f AnalyticsFilter) (ProjectsAnalyticsResponse, error)
	GetAnalyticsHourOfWeek(ctx context.Context, f AnalyticsFilter) (HourOfWeekResponse, error)
	GetAnalyticsSessionShape(ctx context.Context, f AnalyticsFilter) (SessionShapeResponse, error)
	GetAnalyticsTools(ctx context.Context, f AnalyticsFilter) (ToolsAnalyticsResponse, error)
	GetAnalyticsVelocity(ctx context.Context, f AnalyticsFilter) (VelocityResponse, error)
	GetAnalyticsTopSessions(ctx context.Context, f AnalyticsFilter, metric string) (TopSessionsResponse, error)

	// Usage (token cost).
	GetDailyUsage(ctx context.Context, f UsageFilter) (DailyUsageResult, error)
	GetTopSessionsByCost(ctx context.Context, f UsageFilter, limit int) ([]TopSessionEntry, error)
	GetUsageSessionCounts(ctx context.Context, f UsageFilter) (UsageSessionCounts, error)

	// Stars (local-only; PG returns ErrReadOnly).
	StarSession(sessionID string) (bool, error)
	UnstarSession(sessionID string) error
	ListStarredSessionIDs(ctx context.Context) ([]string, error)
	BulkStarSessions(sessionIDs []string) error

	// Pins (local-only; PG returns ErrReadOnly).
	PinMessage(sessionID string, messageID int64, note *string) (int64, error)
	UnpinMessage(sessionID string, messageID int64) error
	ListPinnedMessages(ctx context.Context, sessionID string, project string) ([]PinnedMessage, error)

	// Insights (local-only; PG returns ErrReadOnly).
	ListInsights(ctx context.Context, f InsightFilter) ([]Insight, error)
	GetInsight(ctx context.Context, id int64) (*Insight, error)
	InsertInsight(s Insight) (int64, error)
	DeleteInsight(id int64) error

	// Session management (local-only; PG returns ErrReadOnly).
	RenameSession(id string, displayName *string) error
	SoftDeleteSession(id string) error
	RestoreSession(id string) (int64, error)
	DeleteSessionIfTrashed(id string) (int64, error)
	ListTrashedSessions(ctx context.Context) ([]Session, error)
	EmptyTrash() (int, error)

	// Upload (local-only; PG returns ErrReadOnly).
	UpsertSession(s Session) error
	ReplaceSessionMessages(sessionID string, msgs []Message) error

	// ReadOnly returns true for remote/PG-backed stores.
	ReadOnly() bool
}

Store is the interface the HTTP server uses for all data access. The concrete *DB (SQLite) satisfies it implicitly. The pgdb package provides a read-only PostgreSQL implementation.

type ToolAgentBreakdown

type ToolAgentBreakdown struct {
	Agent      string              `json:"agent"`
	Total      int                 `json:"total"`
	Categories []ToolCategoryCount `json:"categories"`
}

ToolAgentBreakdown holds tool usage breakdown for one agent.

type ToolCall

type ToolCall struct {
	MessageID           int64             `json:"-"`
	SessionID           string            `json:"-"`
	ToolName            string            `json:"tool_name"`
	Category            string            `json:"category"`
	ToolUseID           string            `json:"tool_use_id,omitempty"`
	InputJSON           string            `json:"input_json,omitempty"`
	SkillName           string            `json:"skill_name,omitempty"`
	ResultContentLength int               `json:"result_content_length,omitempty"`
	ResultContent       string            `json:"result_content,omitempty"`
	SubagentSessionID   string            `json:"subagent_session_id,omitempty"`
	ResultEvents        []ToolResultEvent `json:"result_events,omitempty"`
}

ToolCall represents a single tool invocation stored in the tool_calls table.

type ToolCategoryCount

type ToolCategoryCount struct {
	Category string  `json:"category"`
	Count    int     `json:"count"`
	Pct      float64 `json:"pct"`
}

ToolCategoryCount holds a count and percentage for one tool category.

type ToolResult added in v0.4.0

type ToolResult struct {
	ToolUseID     string
	ContentLength int
	ContentRaw    string // raw JSON of the content field; decode lazily
}

ToolResult holds a tool_result content block for pairing.

type ToolResultEvent added in v0.17.0

type ToolResultEvent struct {
	ToolUseID         string `json:"tool_use_id,omitempty"`
	AgentID           string `json:"agent_id,omitempty"`
	SubagentSessionID string `json:"subagent_session_id,omitempty"`
	Source            string `json:"source"`
	Status            string `json:"status"`
	Content           string `json:"content"`
	ContentLength     int    `json:"content_length"`
	Timestamp         string `json:"timestamp,omitempty"`
	EventIndex        int    `json:"event_index"`
}

ToolResultEvent represents a canonical chronological result update.

type ToolTrendEntry

type ToolTrendEntry struct {
	Date  string         `json:"date"`
	ByCat map[string]int `json:"by_category"`
}

ToolTrendEntry holds tool call counts for one time bucket.

type ToolsAnalyticsResponse

type ToolsAnalyticsResponse struct {
	TotalCalls int                  `json:"total_calls"`
	ByCategory []ToolCategoryCount  `json:"by_category"`
	ByAgent    []ToolAgentBreakdown `json:"by_agent"`
	Trend      []ToolTrendEntry     `json:"trend"`
}

ToolsAnalyticsResponse wraps tool usage analytics.

type TopSession

type TopSession struct {
	ID           string  `json:"id"`
	Project      string  `json:"project"`
	FirstMessage *string `json:"first_message"`
	MessageCount int     `json:"message_count"`
	OutputTokens int     `json:"output_tokens"`
	DurationMin  float64 `json:"duration_min"`
}

TopSession holds summary info for a ranked session.

type TopSessionEntry added in v0.21.0

type TopSessionEntry struct {
	SessionID   string  `json:"sessionId"`
	DisplayName string  `json:"displayName"`
	Agent       string  `json:"agent"`
	Project     string  `json:"project"`
	StartedAt   string  `json:"startedAt"`
	TotalTokens int     `json:"totalTokens"`
	Cost        float64 `json:"cost"`
}

TopSessionEntry is one row in the "top sessions by cost" result.

type TopSessionsResponse

type TopSessionsResponse struct {
	Metric   string       `json:"metric"`
	Sessions []TopSession `json:"sessions"`
}

TopSessionsResponse wraps the top sessions list.

type UsageFilter added in v0.20.0

type UsageFilter struct {
	From           string // YYYY-MM-DD, inclusive
	To             string // YYYY-MM-DD, inclusive
	Agent          string // "" for all; supports comma-separated
	Project        string // "" for all; supports comma-separated
	Model          string // "" for all; supports comma-separated
	ExcludeProject string // comma-separated projects to exclude
	ExcludeAgent   string // comma-separated agents to exclude
	ExcludeModel   string // comma-separated models to exclude
	Timezone       string // IANA timezone, "" for UTC
	Breakdowns     bool   // populate Project/AgentBreakdowns per day
}

UsageFilter controls the date range, agent, and timezone for daily usage aggregation queries.

type UsageSessionCounts added in v0.21.0

type UsageSessionCounts struct {
	Total     int            `json:"total"`
	ByProject map[string]int `json:"byProject"`
	ByAgent   map[string]int `json:"byAgent"`
}

UsageSessionCounts holds distinct session counts grouped by project and agent over a filter range.

type UsageTotals added in v0.20.0

type UsageTotals struct {
	InputTokens         int     `json:"inputTokens"`
	OutputTokens        int     `json:"outputTokens"`
	CacheCreationTokens int     `json:"cacheCreationTokens"`
	CacheReadTokens     int     `json:"cacheReadTokens"`
	TotalCost           float64 `json:"totalCost"`
	// CacheSavings is the net dollar delta vs an uncached run:
	// cache reads save (input_rate - cache_read_rate) per token,
	// cache creations cost (input_rate - cache_creation_rate)
	// per token (usually negative because creation is billed
	// above the input rate). Computed from per-model rates so
	// mixed-model workloads get the right number, not a fixed
	// Sonnet proxy.
	CacheSavings float64 `json:"cacheSavings"`
}

UsageTotals holds aggregate token and cost totals.

type VelocityBreakdown

type VelocityBreakdown struct {
	Label    string           `json:"label"`
	Sessions int              `json:"sessions"`
	Overview VelocityOverview `json:"overview"`
}

VelocityBreakdown is velocity metrics for a subgroup.

type VelocityOverview

type VelocityOverview struct {
	TurnCycleSec          Percentiles `json:"turn_cycle_sec"`
	FirstResponseSec      Percentiles `json:"first_response_sec"`
	MsgsPerActiveMin      float64     `json:"msgs_per_active_min"`
	CharsPerActiveMin     float64     `json:"chars_per_active_min"`
	ToolCallsPerActiveMin float64     `json:"tool_calls_per_active_min"`
}

VelocityOverview holds aggregate velocity metrics.

type VelocityResponse

type VelocityResponse struct {
	Overall      VelocityOverview    `json:"overall"`
	ByAgent      []VelocityBreakdown `json:"by_agent"`
	ByComplexity []VelocityBreakdown `json:"by_complexity"`
}

VelocityResponse wraps overall and grouped velocity metrics.

Jump to

Keyboard shortcuts

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