Documentation
¶
Index ¶
- Constants
- func FetchMainContent(ctx context.Context, rawURL string) (string, error)
- type Application
- type ApplicationTagsSlice
- type ApplicationUsage
- type ApplicationUsageTags
- type BlockedBreakdown
- type Classification
- type ClassificationResponse
- type ClassificationSource
- type ClassifyRequest
- type CommunicationBreakdown
- type DayInsights
- type DistractionBreakdown
- type ExecutionLogType
- type GetUsageListOptions
- type LLMAppTimeSummary
- type LLMDailySummary
- type LLMDaySummaryInput
- type LLMDeepWorkSession
- type LLMDistractionCascade
- type MetaData
- type Option
- func WithAppBlocker(...) Option
- func WithGenaiClient(genaiClient *genai.Client) Option
- func WithLLMDailySummaryReady(fn func(summary LLMDailySummary)) Option
- func WithProtectionPaused(onProtectionPaused func(pause ProtectionPause)) Option
- func WithProtectionResumed(onProtectionResumed func(pause ProtectionPause)) Option
- func WithSettingsService(settingsService *settings.Service) Option
- type PauseRequets
- type ProductivityPerHourBreakdown
- type ProductivityScore
- type ProjectBreakdown
- type ProtectionPause
- type ProtectionWhitelist
- type SandboxExecutionLog
- type Service
- func (s *Service) CalculateTerminationMode(ctx context.Context, appUsage *ApplicationUsage) (TerminationDecision, error)
- func (s *Service) ClassifyCustomRules(ctx context.Context, appName string, url *string, nowTime *time.Time) (*ClassificationResponse, error)
- func (s *Service) ClassifyCustomRulesWithSandbox(ctx context.Context, sandboxCtx sandboxContext) (*ClassificationResponse, error)
- func (s *Service) ClassifyWithLLM(ctx context.Context, appName, title string, url *string) (*ClassificationResponse, error)
- func (s *Service) GenerateLLMDailySummaryIfNeeded(ctx context.Context) error
- func (s *Service) GetDayInsights(date time.Time) (DayInsights, error)
- func (s *Service) GetPauseHistory(days int) ([]ProtectionPause, error)
- func (s *Service) GetProtectionStatus() (ProtectionPause, error)
- func (s *Service) GetSandboxExecutionLogs(logType string, search string, page, pageSize int) ([]SandboxExecutionLog, error)
- func (s *Service) GetUsageAggregation(options GetUsageListOptions) ([]UsageAggregation, error)
- func (s *Service) GetUsageList(options GetUsageListOptions) ([]ApplicationUsage, error)
- func (s *Service) GetWhitelist() ([]ProtectionWhitelist, error)
- func (s *Service) IdleChanged(ctx context.Context, isIdle bool) error
- func (s *Service) PauseProtection(durationSeconds int, reason string) (ProtectionPause, error)
- func (s *Service) RegisterHTTPHandlers(r *chi.Mux)
- func (s *Service) RemoveWhitelist(id int64) error
- func (s *Service) ResumeProtection(reason string) (ProtectionPause, error)
- func (s *Service) TitleChanged(ctx context.Context, executablePath, windowTitle, appName, icon string, ...) error
- func (s *Service) Whitelist(appname string, hostname string, duration time.Duration) error
- type TerminationDecision
- type TerminationMode
- type TerminationModeSource
- type UnpauseRequest
- type UnwhitelistRequest
- type UsageAggregation
- type WhitelistRequest
Constants ¶
const ( TerminationModeNone TerminationMode = "none" TerminationModeBlock TerminationMode = "block" TerminationModePaused TerminationMode = "paused" TerminationModeAllow TerminationMode = "allow" TerminationModeSourceApplication TerminationModeSource = "application" TerminationModeSourceCustomRules TerminationModeSource = "custom_rules" TerminationModeSourceWhitelist TerminationModeSource = "whitelist" TerminationModeSourcePaused TerminationModeSource = "paused" ClassificationSourceUserSet ClassificationSource = "user_set" ClassificationSourceObviously ClassificationSource = "obviously" ClassificationSourceCloudLLM ClassificationSource = "llm" ClassificationSourceCustomRules ClassificationSource = "custom_rules" IdleApplicationName = "Idle" ClassificationNone Classification = "none" ClassificationProductive Classification = "productive" ClassificationDistracting Classification = "distracting" ClassificationNeutral Classification = "neutral" ClassificationSystem Classification = "system" )
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Application ¶
type Application struct {
// mandatory fields
ID int64 `json:"id" gorm:"primaryKey;autoIncrement;not null"`
Name string `json:"name" gorm:"uniqueIndex:idx_name_hostname_id;not null"`
// optional fields
Icon *string `json:"icon"` // either app icon or favicon if host is present
Hostname *string `json:"hostname" gorm:"uniqueIndex:idx_name_hostname_id"`
Domain *string `json:"domain"`
// darwin only
BundleID *string `json:"bundle_id"`
}
Application represents a unique application that has been used by the user Application is unique by name and hostname that is
- if the application is not a browser it is unique by name
- if the application is a browser it is unique by name and domain eg. Chrome + google.com != Chrome + youtube.com, each of them will have its own application
func (Application) TableName ¶ added in v0.0.25
func (a Application) TableName() string
type ApplicationTagsSlice ¶ added in v0.0.25
type ApplicationTagsSlice []ApplicationUsageTags
func (ApplicationTagsSlice) Tags ¶ added in v0.0.25
func (a ApplicationTagsSlice) Tags() []string
type ApplicationUsage ¶
type ApplicationUsage struct {
// mandatory fields
ID int64 `json:"id" gorm:"primaryKey;autoIncrement;not null"`
WindowTitle string `json:"window_title" gorm:"not null"`
StartedAt int64 `json:"started_at" gorm:"not null"`
Classification Classification `json:"classification" gorm:"index:idx_classification"`
TerminationMode TerminationMode `json:"termination_mode" gorm:"not null"`
ExecutablePath string `json:"executable_path" gorm:"not null"`
// optional fields
BrowserURL *string `json:"browser_url" gorm:"type:text"`
EndedAt *int64 `json:"ended_at"`
DurationSeconds *int `json:"duration_seconds"`
ClassificationError *string `gorm:"index:idx_classification_error" json:"classification_error"`
ClassificationConfidence *float32 `json:"classification_confidence"`
ClassificationReasoning *string `json:"classification_reasoning"`
ClassificationSource *ClassificationSource `json:"classification_source"`
DetectedProject *string `gorm:"index:idx_detected_project" json:"detected_project"`
DetectedCommunicationChannel *string `gorm:"index:idx_detected_communication_channel" json:"detected_communication_channel"`
TerminationReasoning *string `json:"termination_reasoning"`
TerminationSource *TerminationModeSource `json:"termination_mode_source"`
TerminationError *string `gorm:"index:idx_termination_mode_error" json:"termination_mode_error"`
SandboxContext *string `json:"sandbox_context" gorm:"type:text;nullable"`
SandboxResponse *string `json:"sandbox_response" gorm:"type:text;nullable"`
SandboxLogs *string `json:"sandbox_logs" gorm:"type:text;nullable"`
// relations
Tags []ApplicationUsageTags `gorm:"foreignKey:UsageID" json:"tags"`
ApplicationID int64 `json:"application_id"`
Application Application `gorm:"foreignKey:ApplicationID" json:"application"`
}
func (*ApplicationUsage) Same ¶
func (a *ApplicationUsage) Same(windowTitle, appName string, bundleID, url *string) bool
Same returns true if the application usage is the same as the given application usage
Application usage is considered the same if:
- The url is not nil and the url is the same
- The application name and title are the same, eg. Slack + general discussion != Slack + funny memes
func (*ApplicationUsage) TableName ¶
func (a *ApplicationUsage) TableName() string
type ApplicationUsageTags ¶
type BlockedBreakdown ¶ added in v0.0.31
type Classification ¶
type Classification string
type ClassificationResponse ¶
type ClassificationResponse struct {
Classification Classification `json:"classification"`
ClassificationSource ClassificationSource `json:"classification_source"`
Reasoning string `json:"reasoning"`
ConfidenceScore float32 `json:"confidence_score"`
DetectedProject string `json:"detected_project"`
DetectedCommunicationChannel string `json:"detected_communication_channel"`
Tags []string `json:"tags"`
SandboxContext string `json:"sandbox_context"`
SandboxResponse *string `json:"sandbox_response"`
SandboxLogs string `json:"sandbox_logs"`
}
type ClassificationSource ¶
type ClassificationSource string
type ClassifyRequest ¶
type ClassifyRequest struct {
AppName string `json:"app_name"`
ExecutablePath string `json:"executable_path"`
Hostname string `json:"hostname"`
URL string `json:"url"`
Classification Classification `json:"classification"`
}
type CommunicationBreakdown ¶ added in v0.0.31
type DayInsights ¶
type DayInsights struct {
ProductivityScore ProductivityScore
ProductivityPerHourBreakdown ProductivityPerHourBreakdown
LLMDailySummary *LLMDailySummary
TopDistractions []DistractionBreakdown
TopBlocked []BlockedBreakdown
ProjectBreakdown []ProjectBreakdown
CommunicationBreakdown []CommunicationBreakdown
}
type DistractionBreakdown ¶ added in v0.0.31
type ExecutionLogType ¶ added in v0.0.21
type ExecutionLogType string
const ( ExecutionLogTypeClassification ExecutionLogType = "classification" ExecutionLogTypeTerminationMode ExecutionLogType = "termination_mode" )
type GetUsageListOptions ¶
type LLMAppTimeSummary ¶ added in v0.0.31
type LLMDailySummary ¶ added in v0.0.31
type LLMDailySummary struct {
ID int64 `json:"id" gorm:"primaryKey;autoIncrement"`
Date string `json:"date" gorm:"uniqueIndex;not null"`
Headline string `json:"headline"`
Narrative string `json:"narrative"`
KeyPattern string `json:"key_pattern"`
Wins string `json:"wins"` // JSON array of strings
Suggestion string `json:"suggestion"`
DayVibe string `json:"day_vibe"`
ContextSwitchCount int `json:"context_switch_count"`
LongestFocusMinutes int `json:"longest_focus_minutes"`
DeepWorkMinutes int `json:"deep_work_minutes"`
BlockedAttemptCount int `json:"blocked_attempt_count"`
CreatedAt int64 `json:"created_at"`
}
LLMDailySummary is the persisted daily summary generated by the LLM.
func (LLMDailySummary) TableName ¶ added in v0.0.31
func (LLMDailySummary) TableName() string
type LLMDaySummaryInput ¶ added in v0.0.31
type LLMDaySummaryInput struct {
Date string `json:"date"`
TotalProductiveMinutes int `json:"total_productive_minutes"`
TotalDistractiveMinutes int `json:"total_distractive_minutes"`
FocusScore int `json:"focus_score"`
ContextSwitchCount int `json:"context_switch_count"`
LongestFocusStretchMin int `json:"longest_focus_stretch_min"`
DeepWorkSessions []LLMDeepWorkSession `json:"deep_work_sessions"`
DeepWorkTotalMinutes int `json:"deep_work_total_minutes"`
DistractionCascades []LLMDistractionCascade `json:"distraction_cascades"`
TopDistractions []LLMAppTimeSummary `json:"top_distractions"`
TopProductiveApps []LLMAppTimeSummary `json:"top_productive_apps"`
MostProductiveHours string `json:"most_productive_hours"`
MostDistractiveHours string `json:"most_distractive_hours"`
BlockedAttemptCount int `json:"blocked_attempt_count"`
ProtectionPauseCount int `json:"protection_pause_count"`
AvgFocusScoreLast7Days int `json:"avg_focus_score_last_7_days"`
FocusScoreTrend string `json:"focus_score_trend"`
}
LLMDaySummaryInput is the pre-computed data that gets serialized and sent to the LLM. It is never stored -- only used as an intermediate representation.
type LLMDeepWorkSession ¶ added in v0.0.31
type LLMDistractionCascade ¶ added in v0.0.31
type Option ¶
type Option func(*Service)
Option is a function that configures a Service.
func WithAppBlocker ¶
func WithAppBlocker(appBlocker func(appName, title, reason string, tags []string, browserURL *string)) Option
WithAppBlocker configures the Service with a function to call when an application is blocked.
func WithGenaiClient ¶
WithGenaiClient configures the Service with a GenaiClient interface to allow using the Genai client.
func WithLLMDailySummaryReady ¶ added in v0.0.31
func WithLLMDailySummaryReady(fn func(summary LLMDailySummary)) Option
WithLLMDailySummaryReady configures the Service with a function to call when a daily LLM summary is generated.
func WithProtectionPaused ¶
func WithProtectionPaused(onProtectionPaused func(pause ProtectionPause)) Option
WithProtectionPaused configures the Service with a function to call when protection is paused.
func WithProtectionResumed ¶
func WithProtectionResumed(onProtectionResumed func(pause ProtectionPause)) Option
WithProtectionResumed configures the Service with a function to call when protection is resumed.
func WithSettingsService ¶
WithSettingsService configures the Service with a SettingsService interface to allow accessing settings from the database.
type PauseRequets ¶
type ProductivityPerHourBreakdown ¶
type ProductivityPerHourBreakdown map[int]ProductivityScore
type ProductivityScore ¶
type ProjectBreakdown ¶ added in v0.0.31
type ProtectionPause ¶
type ProtectionPause struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
RequestedDurationSeconds int `json:"requested_duration_seconds"`
ActualDurationSeconds int `json:"actual_duration_seconds"`
ResumedAt int64 `json:"resumed_at"`
ResumedReason string `json:"resumed_reason"`
CreatedAt int64 `json:"created_at"`
Reason string `json:"reason"`
}
func (*ProtectionPause) TableName ¶
func (p *ProtectionPause) TableName() string
type ProtectionWhitelist ¶
type ProtectionWhitelist struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
// ExpiresAt should be pre-calculated and set to the time when the whitelist expires
ExpiresAt int64 `json:"expires_at"`
AppName string `gorm:"uniqueIndex:idx_allow_usage_identity" json:"appname"`
Hostname *string `gorm:"uniqueIndex:idx_allow_usage_identity" json:"hostname"`
}
func (*ProtectionWhitelist) TableName ¶
func (p *ProtectionWhitelist) TableName() string
type SandboxExecutionLog ¶
type SandboxExecutionLog struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
Context string `json:"context" gorm:"type:text;nullable"`
Response *string `json:"response" gorm:"type:text;nullable"`
Logs string `json:"logs" gorm:"type:text;nullable"`
CreatedAt int64 `json:"created_at" gorm:"index:idx_created_at"`
FinishedAt *int64 `json:"finished_at" gorm:"index:idx_finished_at;nullable"`
Error *string `json:"error" gorm:"type:text;nullable"`
Type string `json:"type" gorm:"index:idx_type"`
}
type Service ¶
type Service struct {
// channel to receive usage updates
UsageUpdates chan *ApplicationUsage
// contains filtered or unexported fields
}
func NewService ¶
func (*Service) CalculateTerminationMode ¶
func (s *Service) CalculateTerminationMode(ctx context.Context, appUsage *ApplicationUsage) (TerminationDecision, error)
CalculateTerminationMode determines whether an application or website should be blocked, allowed, or paused based on classification, custom rules, protection status, and whitelist entries.
This function evaluates multiple factors in order of priority: 1. Custom rules (if configured) - highest priority 2. Classification - non-distracting usage is always allowed 3. Protection pause status - if protection is paused, usage is allowed 4. Whitelist entries - temporarily whitelisted bundle ID/hostname combinations are allowed 5. Default blocking - distracting usage is blocked when protection is active
Parameters:
- bundleID: The application bundle identifier (e.g., "com.example.app")
- hostname: The website hostname (e.g., "example.com") - empty string for non-browser apps
- domain: The domain name extracted from the URL
- url: The full URL being accessed
- classification: The classification result indicating whether the usage is distracting
- terminationMode: The requested termination mode (may be overridden by custom rules)
Returns:
- TerminationDecision: A decision containing the mode (Allow/Block/Paused), reasoning, and source
- error: Database error if protection status or whitelist lookup fails
func (*Service) ClassifyCustomRules ¶
func (*Service) ClassifyCustomRulesWithSandbox ¶
func (s *Service) ClassifyCustomRulesWithSandbox(ctx context.Context, sandboxCtx sandboxContext) (*ClassificationResponse, error)
func (*Service) ClassifyWithLLM ¶
func (*Service) GenerateLLMDailySummaryIfNeeded ¶ added in v0.0.31
GenerateLLMDailySummaryIfNeeded checks if it's time to generate yesterday's summary and produces one if it doesn't already exist.
func (*Service) GetDayInsights ¶
func (s *Service) GetDayInsights(date time.Time) (DayInsights, error)
func (*Service) GetPauseHistory ¶
func (s *Service) GetPauseHistory(days int) ([]ProtectionPause, error)
GetPauseHistory retrieves the history of protection pauses within the specified number of days.
Parameters:
- days: The number of days to look back (e.g., 7 for one week)
Returns:
- []ProtectionPause: A slice of pause records ordered by creation time (newest first)
- error: Database error if the query fails
func (*Service) GetProtectionStatus ¶
func (s *Service) GetProtectionStatus() (ProtectionPause, error)
GetProtectionStatus retrieves the current protection pause status.
It queries for an active ProtectionPause record where ResumedAt is greater than the current time (indicating the pause is still active and hasn't been resumed yet). When a pause is created, ResumedAt is set to a future timestamp representing when the pause should automatically expire. When manually resumed, ResumedAt is updated to the current time, making it no longer match this query.
Returns:
- ProtectionPause: The active pause record if protection is currently paused, or an empty ProtectionPause (ID == 0) if protection is active (not paused)
- error: Database error if the query fails
func (*Service) GetSandboxExecutionLogs ¶ added in v0.0.21
func (s *Service) GetSandboxExecutionLogs(logType string, search string, page, pageSize int) ([]SandboxExecutionLog, error)
GetSandboxExecutionLogs retrieves paginated sandbox execution logs from the database. It supports fuzzy search on context and response fields, and filtering by log type. Only returns logs from the last 7 days.
func (*Service) GetUsageAggregation ¶ added in v0.0.24
func (s *Service) GetUsageAggregation(options GetUsageListOptions) ([]UsageAggregation, error)
func (*Service) GetUsageList ¶
func (s *Service) GetUsageList(options GetUsageListOptions) ([]ApplicationUsage, error)
GetUsageList returns a list of application usages for the given date and pagination options
Parameters:
- options: GetUsageListOptions
- Date: The date to get usages for - useful for detailed analysis of a specific day usage
- Page: The page number to get
- PageSize: The number of usages per page
Returns:
- []ApplicationUsage: The list of application usages
func (*Service) GetWhitelist ¶
func (s *Service) GetWhitelist() ([]ProtectionWhitelist, error)
GetWhitelist returns all active whitelist entries that haven't expired.
Returns:
- []ProtectionWhitelist: A slice of active whitelist entries
- error: Database error if the query fails
func (*Service) IdleChanged ¶
IdleChanged is called when the idle state of the user changes (e.g. user starts or stops using the computer)
func (*Service) PauseProtection ¶
func (s *Service) PauseProtection(durationSeconds int, reason string) (ProtectionPause, error)
PauseProtection temporarily disables focus protection for the specified duration.
The function starts a background goroutine that automatically resumes protection after the duration expires. The pause state is persisted to the database, allowing the application to recover pause state across restarts.
Parameters:
- duration: The duration to pause protection (must be > 0)
Returns:
- error: Returns an error if protection is already paused
Side effects:
- Creates a ProtectionPause record in the database
- Emits a state update via the state channel
- Spawns a goroutine that calls ResumeProtection after the duration
func (*Service) RegisterHTTPHandlers ¶
func (*Service) RemoveWhitelist ¶
RemoveWhitelist removes a whitelist entry by ID.
Parameters:
- id: The ID of the whitelist entry to remove
Returns:
- error: Database error if the deletion fails
func (*Service) ResumeProtection ¶
func (s *Service) ResumeProtection(reason string) (ProtectionPause, error)
ResumeProtection re-enables focus protection and records the reason for resumption.
This function is called either automatically when a pause duration expires, or manually by the user to end a pause early. The reason is persisted to the database for auditing and analytics purposes.
Parameters:
- reason: A human-readable explanation for why protection was resumed (e.g., "protection paused for 5m0s expired" or "user manually resumed")
Returns:
- error: Returns an error if protection is not currently paused
Side effects:
- Updates the ProtectionPause record in the database with ResumedAt timestamp
- Clears the pause state and emits a state update via the state channel
func (*Service) TitleChanged ¶
func (s *Service) TitleChanged(ctx context.Context, executablePath, windowTitle, appName, icon string, bundleID, url *string) error
TitleChanged is called when the title of the current application changes, whether it's a new application or the same application title has changed
func (*Service) Whitelist ¶
Whitelist temporarily allows a specific blocked usage (by bundle ID and hostname) for the specified duration.
This function creates a ProtectionWhitelist entry that allows the specified application or website to bypass focus protection for a limited time. This enables users to temporarily access blocked content without pausing all protection. The whitelist entry is persisted to the database and can be checked during termination decision evaluation.
Parameters:
- bundleID: The application bundle identifier (e.g., "com.example.app")
- hostname: The website hostname (e.g., "example.com") - empty string for non-browser apps
- duration: The duration to allow the usage (defaults to 1 hour if 0)
Returns:
- error: Database error if the whitelist entry creation fails
Side effects:
- Creates a ProtectionWhitelist record in the database with expiration timestamp
type TerminationDecision ¶
type TerminationDecision struct {
Mode TerminationMode
Reasoning string
Source TerminationModeSource
}
type TerminationMode ¶
type TerminationMode string
type TerminationModeSource ¶
type TerminationModeSource string
type UnpauseRequest ¶
type UnpauseRequest struct {
Reason string `json:"reason"`
}
type UnwhitelistRequest ¶ added in v0.0.24
type UnwhitelistRequest struct {
ID int64 `json:"id"`
}
type UsageAggregation ¶ added in v0.0.24
type UsageAggregation struct {
Application Application `json:"application"`
TotalDuration int `json:"total_duration"` // in seconds
UsageCount int `json:"usage_count"`
}
type WhitelistRequest ¶ added in v0.0.24
Source Files
¶
- classifier_custom_rules.go
- classifier_llm.go
- classifier_llm_apps.go
- classifier_llm_website.go
- classifier_obviously.go
- http_handler.go
- insights_basic.go
- insights_daily_summary.go
- insights_report.go
- insights_summary.go
- protection.go
- sandbox.go
- sandbox_logs.go
- service.go
- service_option.go
- service_usage.go
- types_daily_summary.go
- types_db.go
- types_insights.go
- types_usage.go
- utils.go