Help us shape the future of Go! Take the 2026 Go Developer Survey

app

package
v0.65.0 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 108 Imported by: 0

Documentation

Overview

Package app is the headless core's facade: the App value driving adapters hold, the error vocabulary they translate, and the per-domain services that own orchestration. The domain packages it composes live in cmd/desktop/internal/app/<domain>/.

Index

Constants

View Source
const (
	PresentationModal = "modal"
	PresentationToast = "toast"
)

How a pending set of release notes should be surfaced.

View Source
const (
	AgentTargetSession = "session"
	AgentTargetChat    = "chat"
)
View Source
const AgentSessionEndPath = "/api/sessions/end"

AgentSessionEndPath lives here so the URL a launch writes into the agent's environment and the route httpapi serves cannot drift apart.

View Source
const ClientLogComponent = "webview"
View Source
const DefaultProfileName = "Default"

DefaultProfileName names the profile the app creates so that one always exists. First run never asks for a name: a profile is the container the starter feeds land in, and there is nothing to say about it before there is anything in it.

View Source
const DryRunDocumentID = "dryrun"

DryRunDocumentID is the flow id an inline document runs under when it names none. It scopes the run's node KV and the feed ids in its would-be outputs, both of which are flow-qualified; it never has to match anything installed, because a dry run reads and writes nothing that survives it.

View Source
const ScratchSlug = "Scratch"

ScratchSlug is the tmux session name of the scratch terminal — the one terminal in the app that belongs to no piece of tracked work.

It is a slug hive cannot mint: Slugify lowercases before it replaces, so no session a user can name reaches a capital letter, and nothing hive creates can therefore shadow the scratch session or be shadowed by it. `scratch` would have been that session's slug the first time someone named one that.

Variables

This section is empty.

Functions

func HTTPBaseURLAt

func HTTPBaseURLAt(host string, port int) string

HTTPBaseURLAt is the loopback server's base URL, which the catalogue joins with each app-hosted entry's RuntimePath to resolve its live address.

func MCPEndpointAt

func MCPEndpointAt(host string, port int) string

MCPEndpointAt is the URL of the agent MCP server — the same loopback server the webhook listener uses (ADR agent-http-api), at the /mcp path (ADR mcp-replaces-the-agent-facing-http-api). It lives here, not in the adapter, because the prompt text embeds it; the /mcp literal avoids an import cycle back into the adapter.

func WebhookBaseURLAt

func WebhookBaseURLAt(host string, port int) string

WebhookBaseURLAt is the URL prefix sources.webhook node paths are served under, for a validated listener host. It lives here rather than in the adapter because the prompt text embeds it, and a prompt is core-owned.

func Wrap

func Wrap(err error, kind Kind, format string, args ...any) error

Wrap classifies an existing failure. It returns nil for a nil err so a caller can wrap unconditionally — which is the whole point of it, and the reason it returns error rather than *Error: a nil *Error assigned to an error return is a non-nil interface holding a nil pointer, so every `return x, Wrap(err, ...)` would report success as a failure.

Types

type ActionRunLocation added in v0.62.0

type ActionRunLocation struct {
	ItemID    int64  `json:"itemId"`
	ProfileID string `json:"profileId"`
	FeedID    string `json:"feedId,omitempty"`
}

type ActionRunLogLine added in v0.62.0

type ActionRunLogLine struct {
	ID      int64  `json:"id"`
	Attempt int64  `json:"attempt"`
	Stream  string `json:"stream"`
	Text    string `json:"text"`
	At      int64  `json:"at"`
}

type ActionRunLogPage added in v0.62.0

type ActionRunLogPage struct {
	Lines       []ActionRunLogLine `json:"lines"`
	NextAfterID int64              `json:"nextAfterId"`
	More        bool               `json:"more"`
}

ActionRunLogPage is one read of a run's log. NextAfterID is what the next read passes to continue; More reports lines past this page.

type ActionRunSummary added in v0.62.0

type ActionRunSummary struct {
	ID         int64  `json:"id"`
	ActionID   string `json:"actionId"`
	Label      string `json:"label"`
	Type       string `json:"type,omitempty"`
	Status     string `json:"status"`
	Attempts   int64  `json:"attempts"`
	Lane       string `json:"lane"`
	Rerun      bool   `json:"rerun"`
	Key        string `json:"key"`
	CreatedAt  int64  `json:"createdAt"`
	StartedAt  int64  `json:"startedAt,omitempty"`
	FinishedAt int64  `json:"finishedAt,omitempty"`
	Error      string `json:"error,omitempty"`
	ProfileID  string `json:"profileId,omitempty"`
	ItemID     int64  `json:"itemId,omitempty"`
	ItemTitle  string `json:"itemTitle,omitempty"`
}

type ActionRunsService added in v0.62.0

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

ActionRunsService reads what output commands did: the run history and the log each attempt wrote. Terminal-target actions have no durable command and so no run here.

func (*ActionRunsService) Get added in v0.62.0

func (s *ActionRunsService) Get(ctx context.Context, commandID int64) (ActionRunSummary, error)

func (*ActionRunsService) List added in v0.62.0

func (s *ActionRunsService) List(ctx context.Context, beforeID int64, limit int) ([]ActionRunSummary, error)

List returns runs newest first, before the given run id (zero for the newest). Limits outside 1..500 default to 100.

func (*ActionRunsService) Log added in v0.62.0

func (s *ActionRunsService) Log(ctx context.Context, commandID, afterID int64, limit int) (ActionRunLogPage, error)

Log reads lines after afterID, oldest first.

func (*ActionRunsService) Tail added in v0.62.0

func (s *ActionRunsService) Tail(ctx context.Context, commandID int64, lines int) (ActionRunLogPage, error)

Tail reads the last lines of a run's log, for a reader that wants where it ended rather than where it began.

type ActionsService

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

ActionsService owns the editable actions catalog.

func (*ActionsService) Create

func (*ActionsService) CreateLauncher

func (s *ActionsService) CreateLauncher(ctx context.Context, l actions.Launcher) (actions.Launcher, error)

func (*ActionsService) Delete

func (s *ActionsService) Delete(ctx context.Context, id string) error

func (*ActionsService) DeleteLauncher

func (s *ActionsService) DeleteLauncher(ctx context.Context, id string) error

func (*ActionsService) List

List returns the effective last-good catalog plus a current parse error, if a hand edit made the latest actions.yml invalid.

func (*ActionsService) Reorder

func (s *ActionsService) Reorder(ctx context.Context, ids []string) error

Reorder persists the catalog order. A stale list — a hand edit added or removed an action meanwhile — is rejected so the caller reloads, which is the caller's view having moved rather than a failure.

func (*ActionsService) Update

func (*ActionsService) UpdateLauncher

func (s *ActionsService) UpdateLauncher(ctx context.Context, id string, l actions.Launcher) (actions.Launcher, error)

type ActivityService

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

ActivityService validates and persists activity events and implements the fire-and-forget activity.Recorder port. Validation stays here because data stores must not import activity's enums.

func (*ActivityService) Append

Append returns validation and persistence errors. Backend emitters that cannot fail use Record.

func (*ActivityService) List

func (s *ActivityService) List(ctx context.Context, before int64, limit int) ([]activity.Event, error)

List returns up to limit events with id < before, newest first. Pass before <= 0 to start from the most recent event.

func (*ActivityService) Record

func (s *ActivityService) Record(ctx context.Context, e activity.Event)

Record implements activity.Recorder: an emit site should never fail or block because the audit log couldn't be written, so a persistence failure is logged and swallowed rather than returned.

type AgentTarget added in v0.65.0

type AgentTarget struct {
	AgentTargetRef
	Label  string `json:"label"`  // "<repo> / <session> · <window>" or "<workspace> / <chat>"
	Status string `json:"status"` // ready | active | approval
}

type AgentTargetRef added in v0.65.0

type AgentTargetRef struct {
	Kind string `json:"kind"` // AgentTargetSession or AgentTargetChat
	ID   string `json:"id"`   // hive session id or chat id
	Pane string `json:"pane"` // tmux pane id; session targets only
}

AgentTargetRef names one agent that can take text. The frontend sends it back as it got it; Send resolves it again and never trusts it as a tmux target.

type AgentWorkspacesDeps

type AgentWorkspacesDeps struct {
	Store     *agentws.Store
	Terminals *tmuxcc.Manager
	// Stores supplies the session and schedule stores and the transaction a
	// workspace delete spans them with.
	Stores          *stores.Stores
	Skills          *SkillsService
	ProfileCommands func() map[string]string
	RootProblem     string
	ExecEnv         *execenv.Resolver
	// EditorCommand nil means NopEditorCommandReader.
	EditorCommand EditorCommandReader
	// MCPBase nil means NopMCPBaseReader.
	MCPBase MCPBaseReader
	// EndDelay nil means the shipped defaultEndDelay.
	EndDelay SessionEndDelayReader
	Events   *events.Bus
	Logger   zerolog.Logger
}

type AgentWorkspacesService

type AgentWorkspacesService struct {

	// OnSchedulesChanged is a field rather than a constructor argument because
	// the scheduler it reloads is built after this service, over it.
	OnSchedulesChanged func(workspace string)
	// contains filtered or unexported fields
}

AgentWorkspacesService opens agent workspaces and drives the sessions run inside them: an agent CLI in a tmux session named agentws-<terminal id>, resolved through the workspace's command template (agentws.Resolve) and addressed by a durable stores.AgentSession record. Sessions are tmux's, not this process's -- they outlive App.Close by design, which is what makes reopening a codex session (no resume form) a real reattach instead of a fresh relaunch.

func (*AgentWorkspacesService) AddDriveMCP added in v0.65.0

func (s *AgentWorkspacesService) AddDriveMCP(ctx context.Context, agent, url string) error

AddDriveMCP installs Hive Drive in the selected agent's user configuration.

func (*AgentWorkspacesService) AllSessions

func (s *AgentWorkspacesService) AllSessions(ctx context.Context) ([]SessionView, error)

AllSessions lists every session across every workspace, newest record first — the sidebar's cross-workspace read, unlike Sessions which scopes to one workspace.

func (*AgentWorkspacesService) Available

func (s *AgentWorkspacesService) Available(ctx context.Context) error

Available reports tmux availability -- the same axis terminal mode reports (TerminalsService.Available), since a session is now a tmux session rather than a ptyterm one.

func (*AgentWorkspacesService) CloseSession

func (s *AgentWorkspacesService) CloseSession(ctx context.Context, id string) (bool, error)

CloseSession ends a session's live tmux session and reports whether there was one running. The record is untouched, so it still lists afterward.

func (*AgentWorkspacesService) CreateWorkspace

func (s *AgentWorkspacesService) CreateWorkspace(ctx context.Context, req WorkspaceEdit) (WorkspaceView, error)

CreateWorkspace makes a directory under the root with a fresh manifest and an AGENTS.md scaffold, and returns its view.

func (*AgentWorkspacesService) DeleteSession

func (s *AgentWorkspacesService) DeleteSession(ctx context.Context, id string) error

DeleteSession ends any live tmux session, then removes the record. The session is killed first: its name lives on the record, so deleting the record around a live one would orphan a running agent no UI could address again until it happened to be found by name.

func (*AgentWorkspacesService) DeleteWorkspace

func (s *AgentWorkspacesService) DeleteWorkspace(ctx context.Context, dir string) error

DeleteWorkspace ends every live tmux session the workspace's sessions hold, deletes the workspace directory, then removes the session records (ADR deleting-a-workspace-deletes-its-directory).

That order is what a failure leaves behind. Terminals go first because the directory under their working directory is about to disappear. The directory goes before the records so a delete that cannot finish — a permission, an unreachable root — still has the chat history to come back to, rather than reporting a failure that already threw it away.

func (*AgentWorkspacesService) Editor

func (s *AgentWorkspacesService) Editor(ctx context.Context) (command, title string)

Editor reports the configured "open in editor" target: the command from settings and the display title the UI labels the action with. An empty command means none is configured.

func (*AgentWorkspacesService) EndOwnSession

func (s *AgentWorkspacesService) EndOwnSession(ctx context.Context, token string) (SessionEnding, error)

EndOwnSession answers as soon as the token is matched and deletes the chat, record included, after the delay in the background: a schedule that runs hourly must not leave a row per run in the sidebar.

func (*AgentWorkspacesService) ImportMCPServers

func (s *AgentWorkspacesService) ImportMCPServers(_ context.Context, raw string) ([]string, error)

ImportMCPServers parses pasted MCP JSON (claude's mcpServers wrapper or a bare id-to-server map) into mcps.yaml and returns the added ids, sorted. An id already declared in the library is a conflict — the file is where an existing entry is changed — while shadowing a shipped id is allowed, the same rule mcps.yaml itself follows.

func (*AgentWorkspacesService) LaunchWorkspaceSession

LaunchWorkspaceSession refreshes generated files before starting the detached chat.

func (*AgentWorkspacesService) List

List returns every recognized workspace, valid or not — a broken manifest carries its last-good content plus Problem, rather than vanishing.

func (*AgentWorkspacesService) MCPCatalogue

func (s *AgentWorkspacesService) MCPCatalogue(ctx context.Context) []MCPCatalogueItem

MCPCatalogue lists the merged MCP catalogue — the choices a workspace editor offers for its mcps: list.

func (*AgentWorkspacesService) Open

Open regenerates the workspace's disposable artifacts and returns its sessions. It is the only entry point that writes into a workspace.

func (*AgentWorkspacesService) OpenWorkspaceInEditor

func (s *AgentWorkspacesService) OpenWorkspaceInEditor(ctx context.Context, dir string) error

OpenWorkspaceInEditor launches the configured editor on the workspace directory, detached — the editor outlives the request and Hive never waits on it.

func (*AgentWorkspacesService) Presets

Presets lists the starter command templates the editor offers: the ones this build ships, plus one per agent profile in hive's own config. A hive profile contributes its command AND its flags, unlike the old seam that stripped them — the flags are the reason to pick that profile, and here they land in a manifest field the user reviews and can edit rather than being spliced in at every launch (ADR the-workspace-command-is-a-template).

Nothing here gates a launch. A user who ignores every preset and types their own command gets exactly that.

func (*AgentWorkspacesService) PutSchedule

func (s *AgentWorkspacesService) PutSchedule(ctx context.Context, dir string, patch SchedulePatch) (ScheduleView, error)

PutSchedule upserts one schedules: entry by id and leaves the rest of the manifest alone.

func (*AgentWorkspacesService) RemoveMCPServer

func (s *AgentWorkspacesService) RemoveMCPServer(_ context.Context, id string) error

RemoveMCPServer deletes a user-declared server from mcps.yaml. A shipped entry cannot be removed — a workspace disables it by dropping the id from its own mcps: list instead.

func (*AgentWorkspacesService) RemoveSchedule

func (s *AgentWorkspacesService) RemoveSchedule(ctx context.Context, dir, id string) error

RemoveSchedule leaves the run history, which outlives its entry on purpose; the cursor is pruned by the scheduler's next pass.

func (*AgentWorkspacesService) RenameSession

func (s *AgentWorkspacesService) RenameSession(ctx context.Context, id, name string) error

RenameSession sets a session's display name. Purely a record edit: the tmux session name comes from an immutable terminal id, so a live terminal keeps running under the same name.

func (*AgentWorkspacesService) ResizeSession

func (s *AgentWorkspacesService) ResizeSession(ctx context.Context, id string, cols, rows int) error

ResizeSession votes a size for a session's attached control client — the same refresh-client vote the Code view's panes cast. tmux answers over the stream with a window 'layout-changed' event, which is what actually sets the pane's grid; see AgentsMode's resize wiring.

func (*AgentWorkspacesService) ResumeSession

func (s *AgentWorkspacesService) ResumeSession(ctx context.Context, id string, cols, rows int) (SessionView, error)

func (*AgentWorkspacesService) RevealSharedSkills

func (s *AgentWorkspacesService) RevealSharedSkills(context.Context) error

RevealSharedSkills opens the shared skills directory in the OS file manager — where a skill a package can select is authored, since it is a SKILL.md a user writes. The directory is created if missing: startup seeds it, but a user who deleted it must still be able to open it and drop a skill back in.

func (*AgentWorkspacesService) RevealSkillPackages

func (s *AgentWorkspacesService) RevealSkillPackages(context.Context) error

RevealSkillPackages opens skills.yml in the OS file manager's default handler — packages are defined by editing that file, which is the authoring act this release offers. A missing file is seeded first, so the action always lands somewhere real.

func (*AgentWorkspacesService) RevealWorkspace

func (s *AgentWorkspacesService) RevealWorkspace(_ context.Context, dir string) error

RevealWorkspace opens the workspace directory in the OS file manager.

func (*AgentWorkspacesService) RootProblem

func (s *AgentWorkspacesService) RootProblem(context.Context) string

RootProblem reports why the configured root could not be created or opened at startup, or "" when it is fine. Spec §14: a root on an unmounted volume or a signed-out iCloud Drive is reported rather than silently replaced with a second, empty root elsewhere -- the UI is what points at the setting to fix.

func (*AgentWorkspacesService) RunningChats added in v0.65.0

func (s *AgentWorkspacesService) RunningChats(ctx context.Context) ([]RunningChat, error)

RunningChats lists the live chats with their agent pane and status. One tmux call finds the live sessions, so the cost follows the running chats rather than every chat ever saved. A chat whose pane cannot be read is left out.

func (*AgentWorkspacesService) SessionActivity

func (s *AgentWorkspacesService) SessionActivity(ctx context.Context, dir string) ([]SessionActivityItem, error)

SessionActivity captures each live session's tmux pane and classifies it with classifyAgentScreen: capture-pane through Hive's assessment engine, the same input SessionStatuses/FetchBatch use for hive's own sessions (hc-ou4o02zx). An empty dir spans every workspace — the sidebar shows every session at once, so its indicators poll the whole set the way the Code view's do; the work is bounded by maxConcurrentAgentSessions either way. A session with no live tmux session is omitted rather than reported dead -- a row's TerminalID already carries that.

func (*AgentWorkspacesService) SessionLaunchWorkspaces

func (*AgentWorkspacesService) SessionLive

func (s *AgentWorkspacesService) SessionLive(ctx context.Context, id string) (bool, error)

func (*AgentWorkspacesService) Sessions

func (s *AgentWorkspacesService) Sessions(ctx context.Context, dir string) ([]SessionView, error)

Sessions lists a workspace's session rows without regenerating its disposable artifacts — the read the Agents area uses to refresh a session list after starting, resuming, closing, or deleting one, without paying Open's generation cost.

func (*AgentWorkspacesService) SkillPackages

SkillPackages lists the packages a workspace editor offers for its skills: list, the name-space they select over, and the problem skills.yml itself has, if any. A source that cannot be read contributes no names rather than failing the listing: an open is where that is reported, because that is the call whose result changes.

func (*AgentWorkspacesService) StartFirstRunChat

func (s *AgentWorkspacesService) StartFirstRunChat(ctx context.Context) (SessionView, error)

StartFirstRunChat opens the seeded Hive workspace on the interview that ends first run. The workspace is regenerated first, as a scheduled launch is: on a fresh install nothing has opened it yet, so its .mcp.json and skills do not exist until this does. The launch is detached because the onboarding screen has no pane; the route it hands off to attaches.

func (*AgentWorkspacesService) StartScheduledSession

func (s *AgentWorkspacesService) StartScheduledSession(ctx context.Context, req StartScheduledSession) (SessionView, error)

StartScheduledSession regenerates the workspace first, as Open does for the UI's launch: otherwise a scheduled run would drive an agent whose .mcp.json and skills are stale. The run history keeps the unframed prompt.

func (*AgentWorkspacesService) StartSession

func (s *AgentWorkspacesService) StartSession(ctx context.Context, req StartSession) (SessionView, error)

func (*AgentWorkspacesService) UpdateWorkspace

func (s *AgentWorkspacesService) UpdateWorkspace(ctx context.Context, req WorkspaceEdit) (WorkspaceView, error)

UpdateWorkspace rewrites the editable fields of an existing workspace's manifest in place — comments and keys the editor does not own survive.

type App

type App struct {
	// The per-domain services. Driving adapters call these — never the
	// unexported domain stores further down, which is what they are built
	// over.
	Inbox      *InboxService
	Sessions   *SessionsService
	Flows      *FlowsService
	Actions    *ActionsService
	Settings   *SettingsService
	MenuBar    *MenuBarService
	System     *SystemService
	HiveConfig *HiveConfigService
	Webhooks   *WebhookService
	GitHub     *GitHubService
	Gitea      *GiteaService
	Grafana    *GrafanaService
	PostHog    *PostHogService
	// Integrations lists the connector registry with each entry's connection
	// state. Generic; GitHub, Gitea, Grafana and PostHog above are the
	// provider-specific acquisition halves.
	Integrations *IntegrationsService
	Activity     *ActivityService
	Jobs         *JobService
	ActionRuns   *ActionRunsService
	Prompts      *PromptsService
	Skills       *SkillsService
	Report       *ReportService
	Diagnostics  *DiagnosticsService
	// ReleaseNotes serves the changelog embedded in this binary and remembers
	// which version's notes the user has seen.
	ReleaseNotes   *ReleaseNotesService
	Terminals      *TerminalsService
	TerminalImages *TerminalImagesService
	// Perf records UI spans to a JSONL file when development.perf.enabled is
	// on. Always non-nil; a disabled recorder is a no-op (ADR ui-performance-spans-are-recorded-to-jsonl).
	Perf      *PerfService
	ClientLog *ClientLogService
	// Observability owns process sampling and telemetry startup status.
	Observability *ObservabilityService
	DevTools      *DevToolsService
	// Sources runs ingestion on demand — the refresh a user pressed, and the
	// one a flow edit earns.
	Sources *SourcesService

	PopupTerminals  *PopupTerminalsService
	AgentWorkspaces *AgentWorkspacesService
	Tasks           *TasksService
	Drive           *DriveService
	Review          *ReviewService
	Schedules       *SchedulesService

	// Events is the typed bus adapters project into transport-specific events.
	// Stores is exposed only so the e2e harness can seed fixtures.
	Events *events.Bus
	Stores *datastores.Stores
	// contains filtered or unexported fields
}

App is the headless core. Driving adapters hold *App and the concrete types on it; there are no driving-port interfaces.

func New

func New(ctx context.Context, cfg Config) (*App, error)

New builds the core: the store, the domain stores and their watchers, the Hive action runtime, and the background subsystems. Nothing is running when it returns — call Start.

func (*App) Close

func (a *App) Close() error

Close stops the background subsystems and releases resources. It is the single teardown path: the adapter's own shutdown hook covers only what it owns (a tray, a window).

Each subsystem's own Stop/Close is idempotent (its own stopOnce; webhook's Stop below is the one that gained one, see docs/decisions/0016), so the hand-written sequence below — unchanged from before this phase — stays safe to call in this reverse-startup order even if something upstream already tore part of it down.

A plugs.Manager (docs/architecture.md's "Background lifecycle") was evaluated to replace this sequence and declined for now: appkit/plugs v0.0.0-20260423210245's Manager.Start unconditionally calls signal.NotifyContext, which permanently adds Go's one-time os/signal watcher goroutine to the process (confirmed against the stdlib source — there is no way to opt out; passing no signals means "watch all signals," not "watch none," per signal.Notify's own documented behavior) and that goroutine has nowhere to go before TestAppLifecycle's strict before-vs-after goroutine count runs. Revisit once either that test tolerates it or a plugs release makes signal registration optional.

func (*App) HiveConfigLocation

func (a *App) HiveConfigLocation() HiveConfigLocation

HiveConfigLocation reports where the Hive config resolved on the last load. It is a method rather than a field read because a reload replaces it.

func (*App) HiveConn

func (a *App) HiveConn() *sql.DB

HiveConn exposes hive.db (sessions, messages) as a plain *sql.DB for the e2e harness's table resets and read-only snapshots.

func (*App) MCPBaseURL

func (a *App) MCPBaseURL(ctx context.Context) string

MCPBaseURL returns this run's loopback base URL, or empty while the server is down. App-hosted catalogue entries have no static URL because startup allocates the port; callers join this base with RuntimePath (ADR mcp-replaces-the-agent-facing-http-api).

func (*App) MountAPI

func (a *App) MountAPI(prefix string, h http.Handler) bool

MountAPI mounts h onto the loopback webhook listener at prefix so the HTTP API shares its port. It reports false when no listener exists. Call before Start.

func (*App) PipelineDB

func (a *App) PipelineDB() *queries.DB

PipelineDB exposes the raw pipeline database handle to driving adapters that need it directly: the e2e harness's table resets and read-only snapshots. Everything else reaches persistence through Stores.

func (*App) PublishFlowsUpdated

func (a *App) PublishFlowsUpdated(reason string)

PublishFlowsUpdated announces a change to the flow set, reinstalls the engine's runners against it, and drains the sources. The app's own writes go through it too, so a save and an external edit are one path.

The drain is what makes an edit visible: without it a new or retyped source node produces nothing until the next poll tick, which is up to settings.MinPollInterval away and reads as a broken canvas. One deploy earns one drain — the flows watcher coalesces a deploy's flow and layout writes into a single reload before this is called.

func (*App) PublishLogAppended

func (a *App) PublishLogAppended(nextOffset int64)

PublishLogAppended announces that the event log grew and wakes the engine to route it. The producer and the webhook listener go through the same path; this method is exported for the one caller that writes through the store directly — the e2e source-to-commit harness, which stands in for a producer tick.

func (*App) RefreshSources

func (a *App) RefreshSources(ctx context.Context) (ingest.TickSummary, error)

RefreshSources clears fetch caches and runs one producer tick. Engine commits are asynchronous, so callers should retry reads briefly. Mock modes return KindUnavailable.

func (*App) ReloadHiveRuntime

func (a *App) ReloadHiveRuntime(ctx context.Context) error

ReloadHiveRuntime re-reads the Hive config and has the engine rebuild its services from it, so a config the app just wrote takes effect without a relaunch.

A failed load changes nothing: the running services keep serving the config they were built from, which is strictly better than a process left with no session service because someone saved a typo.

What it does not reload is deliberate and documented in docs/architecture.md: the database pool, the event bus, and the honeycomb store keep their startup settings, so database: and a changed data dir still need a restart.

func (*App) RuntimePaths

func (a *App) RuntimePaths() settings.Paths

RuntimePaths returns the immutable location snapshot used by this process.

func (*App) Start

func (a *App) Start(ctx context.Context) error

Start runs the background subsystems: the config watchers, the output worker, retention, the poll producer, and the webhook listener. Mock modes deliberately skip the worker loop and have no producer, so a fixture run stays deterministic.

type AppearanceSettings

type AppearanceSettings struct {
	Theme                           string
	FontFamily                      string
	MonoFontFamily                  string
	TerminalFontSizePx              int
	TerminalFontFamily              string
	TerminalFontWeight              int
	TerminalFontWeightBold          int
	TerminalLineHeight              float64
	TerminalLetterSpacing           int
	TerminalShowWindows             bool
	TerminalShowStatusBar           bool
	TerminalPoolSize                int
	TerminalShowSessionAge          bool
	TerminalSessionAgeThresholdDays int
	CanvasFontSize                  string
	CanvasLineSpacing               string
	CanvasPageWidth                 string
}

AppearanceSettings is the persisted presentation configuration. The string values are opaque here: the frontend owns each valid set and heals unknown values, so "" means "nothing persisted" rather than an error.

type ClientLogEntry added in v0.64.0

type ClientLogEntry struct {
	At      time.Time
	Level   string
	Name    string
	Message string
	Error   string
	Kind    string
	Stack   string
	Window  string
	Route   string
	Count   int
	Fields  map[string]any
}

type ClientLogService added in v0.64.0

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

Input is untrusted in size and rate (ADR webview-logs-and-uncaught-errors-are-written-to-hive-log-through-the-root-logger).

func (*ClientLogService) Level added in v0.64.0

func (s *ClientLogService) Level(_ context.Context) string

func (*ClientLogService) Write added in v0.64.0

func (s *ClientLogService) Write(_ context.Context, entries []ClientLogEntry)

type CommentInput added in v0.65.0

type CommentInput struct {
	StartLine int    `json:"startLine"` // 1-based source line, front matter included
	EndLine   int    `json:"endLine"`   // inclusive
	Context   string `json:"context"`
	Text      string `json:"text"`
}

CommentInput is a new comment on a source line range.

type Config

type Config struct {
	Settings      settings.Settings
	SettingsStore *settings.Store
	Paths         settings.Paths
	MockMode      string
	Logger        zerolog.Logger
	// ExecEnv is the login-shell environment main resolved the paths with,
	// shared so the shell is probed once. nil builds one.
	ExecEnv *execenv.Resolver

	// CredentialKeyringService isolates development credentials from the installed app.
	CredentialKeyringService string

	// GUI-owned dependencies enter through consumer-defined driven ports.
	Notifier dispatch.SystemNotifier
	Gate     dispatch.NotificationGate

	// Build stamps the running binary into report bundles.
	Build report.Build

	// TelemetryRuntime is the startup result for exporters constructed before
	// App so their log writer can participate in logger construction.
	TelemetryRuntime TelemetryRuntime
}

Config is everything App needs that it cannot resolve itself.

type DefaultAgentReader

type DefaultAgentReader interface {
	DefaultAgent(ctx context.Context) string
}

DefaultAgentReader reads HIVE_DEFAULT_AGENT from the user's resolved terminal environment.

type DevToolsService

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

DevToolsService reports whether the developer-only diagnostic pane is reachable in this build (ADR developer-tools-are-reachable-in-a-shipped-build-behind-a-setting).

func (*DevToolsService) Enabled

func (s *DevToolsService) Enabled() bool

Enabled reports whether this build was asked to expose the developer tools.

type DiagnosticsAgents added in v0.63.0

type DiagnosticsAgents struct {
	Names        []string `json:"names"`
	DefaultAgent string   `json:"defaultAgent"`
}

type DiagnosticsContext added in v0.63.0

type DiagnosticsContext struct {
	Text    string `json:"text"`
	Path    string `json:"path"`
	Dir     string `json:"dir"`
	Command string `json:"command"`
}

type DiagnosticsIncident added in v0.63.0

type DiagnosticsIncident struct {
	Query       DiagnosticsQuery `json:"query"`
	Description string           `json:"description"`
	Agent       string           `json:"agent"`
}

type DiagnosticsQuery added in v0.63.0

type DiagnosticsQuery struct {
	Source      string   `json:"source"`
	Since       string   `json:"since"`
	Until       string   `json:"until"`
	Levels      []string `json:"levels"`
	Search      string   `json:"search"`
	Reference   string   `json:"reference"`
	Limit       int      `json:"limit"`
	OmitRoutine bool     `json:"omitRoutine"`
}

type DiagnosticsService added in v0.63.0

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

func (*DiagnosticsService) Agents added in v0.63.0

func (*DiagnosticsService) Context added in v0.63.0

func (*DiagnosticsService) Prepare added in v0.63.0

Prepare saves evidence and renders a command; only the authenticated PTY transport may execute it.

func (*DiagnosticsService) Read added in v0.63.0

func (*DiagnosticsService) Reveal added in v0.63.0

func (s *DiagnosticsService) Reveal(ctx context.Context, source string) error

func (*DiagnosticsService) Save added in v0.63.0

type DiagnosticsSnapshot added in v0.63.0

type DiagnosticsSnapshot struct {
	CapturedAt string               `json:"capturedAt"`
	Version    string               `json:"version"`
	Commit     string               `json:"commit"`
	BuildDate  string               `json:"buildDate"`
	Sources    []diagnostics.Source `json:"sources"`
	Entries    []diagnostics.Entry  `json:"entries"`
	Truncated  bool                 `json:"truncated"`
	Query      DiagnosticsQuery     `json:"query"`
}

type DocumentReview added in v0.65.0

type DocumentReview struct {
	SessionID string // "" until the first comment
	// Current is false when the comments belong to an earlier version of the
	// document.
	Current  bool
	Comments []review.Comment // by StartLine
}

DocumentReview is the open review of one Drive document.

type DocumentView added in v0.64.0

type DocumentView struct {
	Space    drive.Space   `json:"space"`
	Entry    drive.Entry   `json:"entry"`
	Markdown string        `json:"markdown,omitempty"` // raw: the frontend's sanitizing renderer handles it
	HTML     string        `json:"html,omitempty"`     // CSP meta injected first
	Canvas   *drive.Canvas `json:"canvas,omitempty"`   // html blocks sanitized
}

DocumentView is one document as the reader shows it. Exactly one of Markdown, HTML, and Canvas is set for those kinds; a plain file carries only its entry.

type DriveDeps added in v0.64.0

type DriveDeps struct {
	Engine   func() *hive.Engine
	Sessions canvasSessionResolver
	Events   *events.Bus
	Logger   zerolog.Logger
	// Reveal shows an absolute path in the file manager; nil is osopen.Reveal.
	Reveal func(string) error
}

type DriveService added in v0.64.0

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

DriveService is the desktop's door onto Hive Drive. Agents read and write documents and canvas blocks through the hive-drive MCP tools; the UI reads and reorganizes a space by its key.

func (*DriveService) ClearCanvas added in v0.64.0

func (s *DriveService) ClearCanvas(ctx context.Context, session, name string) (drive.Canvas, error)

ClearCanvas removes every block at once; the canvas, its title and its file survive.

func (*DriveService) CreateFolder added in v0.64.0

func (s *DriveService) CreateFolder(ctx context.Context, space, path string) (drive.Entry, error)

CreateFolder makes one folder, and any folders above it, in a space.

func (*DriveService) Delete added in v0.64.0

func (s *DriveService) Delete(ctx context.Context, space, path string) error

Delete removes a document or an empty folder. A canvas publishes with the author that wrote it, so the pane beside that chat or session wakes.

func (*DriveService) DeleteCanvas added in v0.64.0

func (s *DriveService) DeleteCanvas(ctx context.Context, session, name string) error

func (*DriveService) DeleteDocument added in v0.64.0

func (s *DriveService) DeleteDocument(ctx context.Context, session, path string) error

DeleteDocument removes one document, a canvas included, or an empty folder.

func (*DriveService) Document added in v0.64.0

func (s *DriveService) Document(ctx context.Context, space, path string) (DocumentView, error)

Document is one document read for the reader. The kind comes from the name, so a plain file is answered from the snapshot without reading what may be a large binary, and a canvas is read once, by the canvas load that parses it.

func (*DriveService) Export added in v0.64.0

func (s *DriveService) Export(ctx context.Context, space, path, dest string) error

Export writes one document's Markdown to dest, the pane's save action. dest comes from the native save dialog, which is why it must already be absolute.

func (*DriveService) GetCanvas added in v0.64.0

func (s *DriveService) GetCanvas(ctx context.Context, session, name string) (drive.Canvas, error)

GetCanvas is one canvas in the calling session's space. A name nothing was ever written under is not_found: unlike the pane, an agent asking by name should learn the name is wrong, not see a blank surface.

func (*DriveService) GetCanvasAt added in v0.64.0

func (s *DriveService) GetCanvasAt(ctx context.Context, space, path string) (drive.Canvas, error)

GetCanvasAt is the pane's read: by space key and canvas name or path. A canvas nothing was written under answers empty rather than an error, so the pane never flashes a failure for one deleted while it was open. html blocks leave here sanitized: this is the one seam between stored agent source and the app's own webview, so the frontend holds no policy of its own (ADR canvas-html-blocks-are-sanitized-in-go-and-styled-by-an-app-owned-class-vocabulary).

func (*DriveService) ListCanvases added in v0.64.0

func (s *DriveService) ListCanvases(ctx context.Context, session string) ([]drive.CanvasMeta, error)

ListCanvases is the calling session's space, most recently updated first.

func (*DriveService) ListDocuments added in v0.64.0

func (s *DriveService) ListDocuments(ctx context.Context, session, path string, tree bool) (drive.Space, drive.Entry, error)

ListDocuments is the calling session's space and the entry at path in it: a folder with one level of children, or its whole subtree when tree is set. "" is the space root. A document path answers that document alone.

func (*DriveService) Locate added in v0.64.0

func (s *DriveService) Locate(_ context.Context, space, path string) (string, error)

Locate is the absolute path on disk of a document or folder in a space; path "" is the space's own folder.

func (*DriveService) Markdown added in v0.64.0

func (s *DriveService) Markdown(ctx context.Context, space, path string) (string, error)

Markdown is one document as standalone markdown, the reader's copy action: a markdown document's own body, or a canvas rendered. A canvas nothing was written under is not_found: exporting nothing is a mistake worth surfacing, unlike showing it. An html document or a plain file has no markdown form and is refused here, so the policy does not live only in the frontend.

func (*DriveService) Move added in v0.64.0

func (s *DriveService) Move(ctx context.Context, space, path, dir string) (drive.Entry, error)

Move puts a document or folder into dir, a folder in the same space, under its own name. dir "" is the space root.

func (*DriveService) MoveDocument added in v0.64.0

func (s *DriveService) MoveDocument(ctx context.Context, session, from, to string) (drive.Entry, error)

MoveDocument renames a document or a folder inside the calling session's space. The drive refuses a move that changes a document's kind or files a canvas where no canvas name reaches it.

func (*DriveService) OpenDocument added in v0.64.0

func (s *DriveService) OpenDocument(ctx context.Context, session, path string) error

OpenDocument asks the UI to open the drive pane beside the calling chat or Code session, pinned to path when one is given. Like SetPaneOpen it is UI intent, applied only while the user is viewing that chat or session.

func (*DriveService) PutBlock added in v0.64.0

func (s *DriveService) PutBlock(ctx context.Context, session, name, title, before string, b drive.Block) (drive.Canvas, error)

PutBlock creates or replaces one block, creating the canvas on its first write. A non-empty title renames the canvas; empty leaves the stored one. A non-empty before places the block ahead of that existing block id instead of appending.

func (*DriveService) PutBlocks added in v0.64.0

func (s *DriveService) PutBlocks(ctx context.Context, session, name, title string, blocks []drive.Block) (drive.Canvas, error)

PutBlocks writes a batch of blocks as one canvas write: one file write, one pane render. Every block is validated before any is written, so a rejected batch leaves the canvas untouched.

func (*DriveService) ReadDocument added in v0.64.0

func (s *DriveService) ReadDocument(ctx context.Context, session, path string) (drive.Entry, []byte, error)

ReadDocument is one markdown, html, or plain UTF-8 file and its bytes, as stored. A canvas is a structure of blocks rather than a body, so it is read with read_canvas. Hive's own state files answer not_found, as they are absent from every listing.

func (*DriveService) RemoveBlock added in v0.64.0

func (s *DriveService) RemoveBlock(ctx context.Context, session, name, blockID string) (drive.Canvas, error)

RemoveBlock deletes one block by id and answers the canvas that remains.

func (*DriveService) Rename added in v0.64.0

func (s *DriveService) Rename(ctx context.Context, space, path, name string) (drive.Entry, error)

Rename gives a document or folder a new name in the same folder. name is a name, not a path. A name with no extension takes the document's: "b" renames a.md to b.md. The drive refuses "b.html", which would turn a markdown document into an html one.

func (*DriveService) Reveal added in v0.64.0

func (s *DriveService) Reveal(ctx context.Context, space, path string) error

Reveal shows a document or folder in the OS file manager.

func (*DriveService) Search added in v0.64.0

func (s *DriveService) Search(ctx context.Context, query string, limit int) ([]drivesvc.Hit, error)

Search matches query against every space's paths and titles; limit 0 is the drive's default cap.

func (*DriveService) SetFrontmatter added in v0.64.0

func (s *DriveService) SetFrontmatter(ctx context.Context, session, name string, fm drive.Frontmatter) (drive.Canvas, error)

SetFrontmatter replaces the editable front matter on an existing canvas. created_at and updated_at stay derived from the canvas timestamps.

func (*DriveService) SetPaneOpen added in v0.64.0

func (s *DriveService) SetPaneOpen(ctx context.Context, session, name string, open bool) error

SetPaneOpen asks the UI to open or close the canvas pane beside the calling chat or Code session. It is UI intent, applied only while the user is viewing it, so an agent can surface what it made without ever dragging the user away from something else. Opening with a name requires that canvas to exist; empty leaves the pane's own pick.

func (*DriveService) Spaces added in v0.64.0

func (s *DriveService) Spaces(ctx context.Context) ([]drive.Space, error)

Spaces is every space in the drive: repositories, then workspaces, then shared.

func (*DriveService) Tree added in v0.64.0

func (s *DriveService) Tree(ctx context.Context, space string) (drive.Entry, error)

Tree is one space's whole folder tree. A space with no directory yet is an empty root.

func (*DriveService) WriteDocument added in v0.64.0

func (s *DriveService) WriteDocument(ctx context.Context, session, path string, body []byte) (drive.Entry, error)

WriteDocument replaces a markdown or html document with body, creating it and the folders above it as needed.

type EditorChoice

type EditorChoice struct {
	Command string
	Title   string
	Found   bool
}

EditorChoice is one editor the Settings selector offers: a CLI command, the display title it is shown as, and whether the command resolves on the subprocess PATH right now.

type EditorCommandReader

type EditorCommandReader interface {
	Editor(ctx context.Context) (string, error)
}

EditorCommandReader reads the configured editor on each call, so settings changes take effect without a restart. Empty means no configured editor.

type Error

type Error struct {
	Kind Kind
	Msg  string
	Err  error
}

Error is the only error type an app service returns across the adapter boundary. Msg is safe to show a user; Err is the cause, kept for logs and for errors.Is/As.

func Errorf

func Errorf(kind Kind, format string, args ...any) *Error

Errorf classifies a new failure with no cause.

func (*Error) Error

func (e *Error) Error() string

func (*Error) MarshalJSON

func (e *Error) MarshalJSON() ([]byte, error)

MarshalJSON emits {"kind":…,"message":…} so a driving adapter can put the Kind on the wire without re-deriving it. The cause is deliberately absent: it is for the log, not for the frontend.

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ExportStatus

type ExportStatus struct {
	Enabled         bool
	Configured      bool
	Running         bool
	RestartRequired bool
}

ExportStatus distinguishes valid local configuration from exporter startup. Running does not confirm that the backend accepted data.

type FixedSessionEndDelay

type FixedSessionEndDelay time.Duration

func (FixedSessionEndDelay) SessionEndDelay

func (d FixedSessionEndDelay) SessionEndDelay(context.Context) time.Duration

type FlowDryRun

type FlowDryRun struct {
	// FlowID names an installed flow, enabled or not.
	FlowID string
	// Document is a flow document in the flows/*.yaml shape, as YAML or as
	// JSON. It is parsed and validated exactly as a file would be, and nothing
	// is written.
	Document []byte
	// DocumentID is the id Document runs under; empty means DryRunDocumentID.
	// Ignored when FlowID is set.
	DocumentID string

	// NodeID is the node the input is delivered to. Any node will do, not only
	// a source: injecting straight at a function node is how one node is
	// exercised in isolation against a captured payload.
	NodeID string
	// Messages is the input. A message with a Snapshot expands into its items
	// and declares feed reconciliation, the same as a source poll would.
	Messages []models.Msg
	// KV seeds the sandbox node KV: node id -> key -> the value's JSON text.
	// Durable KV is never read and never written, so dedup and notify-once
	// logic is exercised against exactly what is seeded here and nothing else.
	KV map[string]map[string]string
}

FlowDryRun asks for one flow execution against caller-supplied input.

Exactly one of FlowID and Document identifies the flow: an installed one, or a document that is not on disk — which is what makes this a testing tool rather than "run the installed flow harder". An unsaved edit can be executed before it is deployed.

type FlowDryRunResult

type FlowDryRunResult struct {
	FlowID   string
	Warnings []string
	Run      runtime.DryRunResult
}

FlowDryRunResult is a dry run's outcome: the flow it resolved to, whatever soft warnings parsing it produced, and what every node did.

type FlowsDeps

type FlowsDeps struct {
	Flows *flow.FlowStore
	// Profile deletion spans aggregates in one transaction.
	Stores   *stores.Stores
	Creds    credentials.Store
	Images   *profileimg.Store
	Marks    *sourcemark.Store
	Scripts  *runtime.ScriptRegistry
	Settings *settings.Store
	Events   *events.Bus
}

type FlowsService

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

FlowsService owns the flow definitions: the listing the picker renders, the CRUD the editor drives, the layout files the canvas persists, and each profile's sidebar-rail avatar.

func (*FlowsService) ClearNodeImage

func (s *FlowsService) ClearNodeImage(ctx context.Context, flowID, nodeID string) error

ClearNodeImage clears a source node's feed-mark image. The stored blob is left in place; it is content-addressed and may be shared.

func (*FlowsService) ClearProfileImage

func (s *FlowsService) ClearProfileImage(ctx context.Context, id string) (flow.Flow, error)

ClearProfileImage removes a profile's avatar: the reference is dropped first so the rail stops drawing it even if the file removal that follows fails, leaving at worst an orphaned file the next set or delete reclaims.

func (*FlowsService) Create

func (s *FlowsService) Create(ctx context.Context, name string) (flow.Flow, error)

Create makes a new flow named name, seeded with the starter graph when exactly one GitHub account is connected and empty otherwise.

Creating is never refused for want of a credential. First run has the default profile before it offers to connect anything, so the unseeded case is the expected one there, not a failure — SeedStarter is what fills it in once the account exists.

func (*FlowsService) Delete

func (s *FlowsService) Delete(ctx context.Context, id string) error

Delete removes a profile's files before purging its durable state, in that order.

Deleting something that is not there is KindNotFound rather than a silent success. This is the one irreversible operation on the surface, so a caller that mistyped an id has to learn that nothing was deleted — a constant success answer is indistinguishable from having destroyed the wrong profile.

"Not there" means no flow file *and* no inbox rows, which is what keeps the files-first retry working: a deletion whose purge failed leaves the rows behind, and refusing the retry would strand them with no id left to name them by.

func (*FlowsService) DryRun

DryRun executes a flow against supplied input and reports what each node emitted, without touching live state.

Nothing is committed: no feed membership, no inbox rows, no notifications, no output_commands, no durable KV. The outputs those would have come from are returned instead, so "what would this flow have done with this input" is answered without doing it. Sources do not fetch — a source node is a relay at run time, so its output during a dry run is exactly what the caller injected.

The runner is built for this call and closed after it. That is load-bearing rather than tidy: a Runner carries each function node's `state` object across messages, so reusing the engine's installed runner would let a dry run mutate the state a live run depends on. It also makes repeated calls with the same input give the same answer, which is the property an agent debugging in a loop is relying on.

func (*FlowsService) EnsureProfile

func (s *FlowsService) EnsureProfile(ctx context.Context) error

EnsureProfile creates the default profile when the flows directory holds no flow file at all. It runs at startup and after a delete, the two moments the set can be empty, so neither the rail nor first run ever faces an app with no profile. A broken file counts as a profile: it is listed with its error, and writing a Default beside it would hide that.

func (*FlowsService) Get

func (s *FlowsService) Get(_ context.Context, id string) (flow.Flow, error)

Get returns one flow's full definition for the editor.

func (*FlowsService) Layout

func (s *FlowsService) Layout(_ context.Context, id string) flow.Layout

Layout returns a flow's canvas positions. A missing or broken layout file is not an error: an empty Layout tells the editor to lay out nodes fresh.

func (*FlowsService) MarkImage

func (s *FlowsService) MarkImage(_ context.Context, hash string) (data []byte, ok bool, err error)

MarkImage returns the stored PNG for a mark hash, or ok=false when none is stored. A missing or malformed reference is not an error.

func (*FlowsService) NodeImage

func (s *FlowsService) NodeImage(_ context.Context, flowID, nodeID string) ([]byte, error)

NodeImage returns a source node's stored feed-mark PNG, or nil when it has none or its hash resolves to no file.

func (*FlowsService) ProfileImage

func (s *FlowsService) ProfileImage(_ context.Context, id string) ([]byte, error)

ProfileImage returns a profile's stored avatar PNG, or nil when it has none.

func (*FlowsService) Rename

func (s *FlowsService) Rename(ctx context.Context, id, name string) (flow.Flow, error)

Rename changes a flow's display name while preserving its stable id and graph definition.

func (*FlowsService) Save

func (s *FlowsService) Save(_ context.Context, f flow.Flow) error

Save validates and persists a flow's definition. An invalid flow is rejected and the last-good file on disk — and the served flow — are left untouched.

func (*FlowsService) SaveLayout

func (s *FlowsService) SaveLayout(_ context.Context, id string, layout flow.Layout) error

func (*FlowsService) SaveSidebar

func (s *FlowsService) SaveSidebar(_ context.Context, id string, layout flow.SidebarLayout) error

func (*FlowsService) SeedStarter

func (s *FlowsService) SeedStarter(ctx context.Context, id string) (flow.Flow, error)

SeedStarter fills an empty profile with the starter graph, fetching as the one connected GitHub account. First run calls it when the account it offered to connect finally exists: the profile was created a step earlier, before there was anything to seed it with.

A profile that already has nodes is refused rather than appended to. Appending a second starter graph onto a graph someone has since edited is not a mistake they can undo.

func (*FlowsService) SetEnabled

func (s *FlowsService) SetEnabled(ctx context.Context, id string, enabled bool) (flow.Flow, error)

SetEnabled controls whether a flow participates in polling and execution while preserving its feed data and graph definition.

func (*FlowsService) SetNodeImage

func (s *FlowsService) SetNodeImage(ctx context.Context, flowID, nodeID string, raw []byte) (string, error)

SetNodeImage normalizes raw into a feed-mark PNG, stores it, records its hash on source node nodeID in flow flowID, saves the flow, and returns the hash.

func (*FlowsService) SetOrder

func (s *FlowsService) SetOrder(ctx context.Context, ids []string) error

SetOrder persists the rail order as profiles.order and applies it to the live listing, so a reorder shows up without a restart. ids is the whole rail, top first — an id it leaves out falls back to sorting alphabetically behind the ones it names, which is also what a profile created later gets.

Ids are not checked against the loaded flows. An id naming nothing is already ignored when the order is read, and refusing the write would make deleting a profile able to fail an unrelated reorder.

func (*FlowsService) SetProfileImage

func (s *FlowsService) SetProfileImage(ctx context.Context, id string, raw []byte) (flow.Flow, error)

SetProfileImage normalizes raw into the square avatar the rail draws, stores it under the data dir, and records its content hash on the flow. Replacing an existing image overwrites it.

func (*FlowsService) Sidebar

Sidebar returns how a flow's feed nodes are grouped into folders and ordered. A missing or broken file is not an error — an empty layout falls back to flow-node order.

func (*FlowsService) Statuses

func (s *FlowsService) Statuses(context.Context) []flow.FlowStatus

Statuses returns one status per flow file — valid and invalid alike — so a broken file shows up with its error instead of silently vanishing.

func (*FlowsService) StoreMarkImage

func (s *FlowsService) StoreMarkImage(_ context.Context, raw []byte) (string, error)

StoreMarkImage normalizes raw into a feed-mark PNG, stores it, and returns its content hash — the value a source node records in its `image` config. It does not touch the flow; the graph save records the hash.

type GitHubService

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

GitHubService wraps the GitHub connector's connection with context threading. It is provider-specific because acquisition is: the device flow is GitHub's, and a connector that takes a pasted API token needs none of these methods. Enumerating what is connected, across every connector, is the Integrations surface's job rather than this one's.

func (*GitHubService) CancelDeviceFlow

func (s *GitHubService) CancelDeviceFlow(context.Context)

func (*GitHubService) Disconnect

func (s *GitHubService) Disconnect(context.Context) error

func (*GitHubService) SetToken

func (s *GitHubService) SetToken(ctx context.Context, token string) (ghsource.ConnectionStatus, error)

func (*GitHubService) StartDeviceFlow

func (s *GitHubService) StartDeviceFlow(ctx context.Context) (ghsource.DeviceFlowInfo, error)

func (*GitHubService) Status

type GiteaService

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

GiteaService wraps the Gitea instance auth. Connecting is one call: a token belongs to exactly one account on exactly one instance, so there is nothing to enumerate and pick between the way a PostHog key's projects are.

func (*GiteaService) Connect

func (s *GiteaService) Connect(ctx context.Context, url, token string) (gitea.Instance, error)

func (*GiteaService) Disconnect

func (s *GiteaService) Disconnect(ctx context.Context, account string) error

type GithubSettings

type GithubSettings struct {
	PollInterval    time.Duration
	MinPollInterval time.Duration
}

GithubSettings is the GitHub integration's polling configuration. It is carried as a Duration: the seconds encoding is a wire concern.

type GrafanaService

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

GrafanaService wraps the Grafana stack auth with context threading and error mapping. Leaner than GitHubService: no device flow, no polled status.

func (*GrafanaService) Connect

func (s *GrafanaService) Connect(ctx context.Context, url, token string) (grafana.Stack, error)

func (*GrafanaService) Disconnect

func (s *GrafanaService) Disconnect(ctx context.Context, account string) error

type HiveConfigLocation

type HiveConfigLocation struct {
	Path                string
	EnvironmentOverride bool
}

HiveConfigLocation is the Hive config path this process loaded and whether HIVE_CONFIG selected it.

type HiveConfigService

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

HiveConfigService reads and writes the Hive CLI configuration the desktop shares with the `hive` binary.

It is separate from SystemService, which owns the app's own locations: this one owns a file another product also writes, and the whole of its contract is that an edit touches the two keys the desktop asked about and nothing else.

func (*HiveConfigService) InspectWorkspace

func (s *HiveConfigService) InspectWorkspace(_ context.Context, path string) (hiveconf.Workspace, error)

InspectWorkspace validates a candidate parent folder and reports its immediate repository count.

func (*HiveConfigService) Save

Save writes the edit and reloads the runtime from it.

The write is validated first, checked against hive's loader, and atomic, so a rejected edit leaves the file exactly as it was. A reload failure after that is reported, not swallowed: the file on disk loads, so the honest answer is that it needs a restart to take effect.

func (*HiveConfigService) Setup

Setup reports the current configuration and the agents this machine can run.

type HiveSetup

type HiveSetup struct {
	Config hiveconf.Setup `json:"config"`
	// Agents is the catalog marked by what resolved on the launch PATH.
	Agents []hiveconf.AgentOption `json:"agents"`
	// DefaultAgentOverride is HIVE_DEFAULT_AGENT when it is set and names a
	// profile the file declares — that is, when it would actually win over
	// agents.default at load. It is reported rather than hidden because
	// without it, a user who exports the variable picks an agent in the UI,
	// sees it saved, and watches sessions start with a different one.
	DefaultAgentOverride string `json:"defaultAgentOverride"`
}

HiveSetup is the external Hive configuration as the first-run and settings screens see it: what the file declares, what this machine could run, and whether the environment is overriding the choice.

type HiveSetupRequest

type HiveSetupRequest struct {
	DefaultAgent string             `json:"defaultAgent"`
	Profiles     []hiveconf.Profile `json:"profiles"`
	Workspaces   []string           `json:"workspaces"`
}

HiveSetupRequest is a whole edit, not a delta: the screen holds every profile and every workspace while it is open, so a save reconciles the file to exactly this set. Profiles the screen loaded and did not touch come back unchanged, which is what keeps a hand-written profile from being dropped by an edit that was only about workspaces.

type InboxDeps

type InboxDeps struct {
	Items    *stores.InboxItemStore
	Commands *stores.OutputCommandStore
	NodeRuns *stores.NodeRunStore
	Catalog  *actions.ActionStore
	Worker   *dispatch.Worker
}

type InboxService

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

InboxService owns the durable inbox as a *reader and triager* sees it: the item views the sidebar renders and the explicit action invocations a user confirms from the detail pane.

The event log itself is deliberately not here. Reading it, committing runs against it, and the replay protocol are the flow engine's, and the engine talks to the store directly — routing them through a service would only put a facade between two parts of the core with no caller in between.

func (*InboxService) ActionRun

func (s *InboxService) ActionRun(ctx context.Context, commandID int64) (dispatch.ActionRunView, error)

func (*InboxService) ActionRunLocation added in v0.62.0

func (s *InboxService) ActionRunLocation(ctx context.Context, commandID int64) (ActionRunLocation, error)

func (*InboxService) ActionViews

func (s *InboxService) ActionViews(ctx context.Context, itemID int64) ([]actions.View, error)

ActionViews returns the configured actions applicable to an inbox item: shown-in-detail, applies_to matches the item's canonical kind, and every hard template capability is satisfiable for the item's payload.

func (*InboxService) Events

func (s *InboxService) Events(ctx context.Context, itemID int64, limit int) ([]stores.InboxEvent, error)

Events returns KindNotFound when the item does not exist; an existing item can have an empty event list.

func (*InboxService) Feed

func (s *InboxService) Feed(ctx context.Context, profileID string, itemID int64) (string, error)

Feed returns the claiming feed, or empty for an unrouted item.

func (*InboxService) FeedCounts

func (s *InboxService) FeedCounts(ctx context.Context, profileID string) ([]stores.FeedCount, error)

func (*InboxService) Feeds

func (s *InboxService) Feeds(ctx context.Context, itemIDs []int64) (map[int64]string, error)

func (*InboxService) FindItems

func (s *InboxService) FindItems(ctx context.Context, profileID, externalID string) ([]stores.InboxItem, error)

FindItems returns every inbox item sharing an external id, optionally scoped to a profile (empty profileID matches all). The same external id can exist across profiles and source scopes, hence a slice.

func (*InboxService) InvokeAction

InvokeAction records the user's explicit confirmation and executes.

It carries the whole authorization chain: the item must decode, the action must exist in the catalog, be shown in the detail pane, apply to the item's kind, and the item must have an id. Executable configuration is always re-resolved from the catalog rather than taken from the caller.

func (*InboxService) ListArchivedByFeed

func (s *InboxService) ListArchivedByFeed(ctx context.Context, profileID, feedID string, limit int) ([]stores.InboxItem, error)

func (*InboxService) ListByFeed

func (s *InboxService) ListByFeed(ctx context.Context, profileID, feedID string, limit int) ([]stores.InboxItem, error)

func (*InboxService) ListItems

func (s *InboxService) ListItems(ctx context.Context, profileID string, limit int) ([]stores.InboxItem, error)

ListItems returns inbox items newest-first, optionally scoped to a profile (empty matches all), unfiltered by feed or triage — a debug/observation read.

func (*InboxService) ListTrash

func (s *InboxService) ListTrash(ctx context.Context, profileID string, limit int) ([]stores.InboxItem, error)

ListTrash returns unrouted and ignored items for the Trash view.

func (*InboxService) MarkRead

func (s *InboxService) MarkRead(ctx context.Context, profileID, feedID string) (int64, error)

MarkRead clears unread in one feed, or the whole profile when feedID is empty. Archived and ignored items retain their state.

func (*InboxService) NewSessionDraft

func (s *InboxService) NewSessionDraft(ctx context.Context, itemIDs []int64) (dispatch.SessionDraft, error)

NewSessionDraft projects ordered inbox items into one prefilled New Session form.

func (*InboxService) NodeRuns

func (s *InboxService) NodeRuns(ctx context.Context, flowID string, limit int) ([]stores.NodeRunRecord, error)

NodeRuns returns up to limit of a flow's most recent node_run rows, newest first, for the canvas's live per-node status and recent activity list.

func (*InboxService) RenderClipboardAction

func (s *InboxService) RenderClipboardAction(ctx context.Context, actionID string, itemIDs []int64, inputs map[string]string) (string, error)

RenderClipboardAction renders one clipboard action once per ordered item and joins the entries into the single block the desktop writes to the clipboard. It never enqueues an output command, so copying remains repeatable.

func (*InboxService) SetUnread

func (s *InboxService) SetUnread(ctx context.Context, itemID, revision int64, unread bool) (stores.InboxItem, error)

func (*InboxService) ToggleArchived

func (s *InboxService) ToggleArchived(ctx context.Context, itemID, revision int64) (stores.InboxItem, error)

func (*InboxService) ToggleIgnored

func (s *InboxService) ToggleIgnored(ctx context.Context, itemID, revision int64) (stores.InboxItem, error)

type Integration

type Integration struct {
	Key       string `json:"key"`
	Title     string `json:"title"`
	Stability string `json:"stability"`
	// Provider is empty when the connector needs no credential, which also means
	// the account fields below are meaningless rather than merely empty.
	Provider string   `json:"provider"`
	Types    []string `json:"types"`
	// Accounts is every connected account for Provider, sorted. Names only — a
	// value never leaves the credential store.
	Accounts []string `json:"accounts"`
	// EnvOverride reports this provider's environment override is set, which
	// authenticates every fetch without a stored account. Without it a headless
	// or CI run would show "Not connected" beside a working feed.
	EnvOverride bool `json:"envOverride"`
}

Integration is one card on the Integrations screen: a projection of the registry, not a second list — an unregistered connector is not an integration. Cards are grouped by credentials provider, so a provider that ships several connector types (Grafana's metrics and alerts) shows as one card; a connector with no provider (the webhook listener) is keyed by its type.

func (Integration) Connected

func (i Integration) Connected() bool

type IntegrationsService

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

IntegrationsService lists the connector registry with each entry's connection state. It is deliberately generic — acquiring a credential is provider-specific and lives on that connector's own service (GitHubService's device flow), so adding a connector is a change to cmd/desktop/internal/app/sources alone.

func (*IntegrationsService) List

List returns one card per connector family, sorted by key so the screen's order is stable — Go map iteration is randomized.

type InvokeActionRequest

type InvokeActionRequest struct {
	ActionID string
	ItemID   int64
	Input    dispatch.ActionInvocationInput
}

InvokeActionRequest is one explicit, user-confirmed action invocation.

type ItemChatView

type ItemChatView struct {
	ID        string    `json:"id"`
	Workspace string    `json:"workspace"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"createdAt"`
}

ItemChatView is an agent workspace chat an inbox item opened.

type ItemSessionView

type ItemSessionView struct {
	ID        string    `json:"id"`
	Name      string    `json:"name"`
	Slug      string    `json:"slug"`
	Repo      string    `json:"repo"`
	State     string    `json:"state"`
	Running   bool      `json:"running"`
	CreatedAt time.Time `json:"createdAt"`
}

ItemSessionView is one hive session an inbox item spawned. Only CreatedAt comes from the link. Everything else is read live from hive, so a session renamed or recycled outside this app reports what it actually is.

type JobService

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

JobService persists jobs and implements jobs.Recorder for background work.

func (*JobService) Begin

func (s *JobService) Begin(ctx context.Context, label, actionID, target string) int64

Persistence failures are logged and return zero.

func (*JobService) Cancel added in v0.62.0

func (s *JobService) Cancel(ctx context.Context, id int64, reason string)

A zero ID is a no-op.

func (*JobService) CancelCommand added in v0.62.0

func (s *JobService) CancelCommand(_ context.Context, commandID int64) error

func (*JobService) Done

func (s *JobService) Done(ctx context.Context, id int64)

A zero ID is a no-op.

func (*JobService) Fail

func (s *JobService) Fail(ctx context.Context, id int64, reason string)

A zero ID is a no-op.

func (*JobService) List

func (s *JobService) List(ctx context.Context, before int64, limit int) ([]jobs.Job, error)

List defaults limits outside 1..1000 to 200.

func (*JobService) ListActive

func (s *JobService) ListActive(ctx context.Context) ([]jobs.Job, error)

ListActive returns non-terminal jobs plus terminal jobs completed within the lingering window, so a just-finished run stays visible briefly.

func (*JobService) Resume

func (s *JobService) Resume(ctx context.Context, commandID int64) int64

Missing jobs and lookup failures return zero; failures are logged.

func (*JobService) Running

func (s *JobService) Running(ctx context.Context, id int64, commandID int64)

Running links the job to its output command. A zero job ID is a no-op.

func (*JobService) Track

func (s *JobService) Track(ctx context.Context, label, actionID, target string, fn func(context.Context) error) int64

Track starts fn asynchronously on a context detached from caller cancellation. Persistence failures do not stop fn.

Do not call Track inside Stores.WithinTx: context.WithoutCancel preserves transaction values, which must not cross into Track's goroutine.

type Kind

type Kind string

Kind is the transport-neutral classification of a core failure. Each adapter maps Kind to its own vocabulary exactly once, and nothing anywhere may match on error text.

const (
	// KindInternal is the zero classification: something broke and the caller
	// can do nothing about it.
	KindInternal Kind = "internal"
	// KindInvalid means the caller supplied bad input.
	KindInvalid Kind = "invalid"
	// KindNotFound means the named thing does not exist.
	KindNotFound Kind = "not_found"
	// KindConflict means the caller's view is stale: an inbox item revision or
	// an action catalog order that moved underneath them. Re-read and retry.
	KindConflict Kind = "conflict"
	// KindUnauthenticated means the operation needs GitHub credentials that
	// are absent, rejected, or expired. The user's remedy is to sign in.
	KindUnauthenticated Kind = "unauthenticated"
	// KindUnavailable means the operation is temporarily or structurally
	// impossible through no fault of the caller: a subsystem not wired in this
	// mock mode, or an upstream cooldown. Retrying later may work; signing in
	// will not. Rate limiting is deliberately here rather than under
	// KindUnauthenticated — the token is fine, the quota is not.
	KindUnavailable Kind = "unavailable"
)

func AllKinds

func AllKinds() []Kind

AllKinds is the closed set, in declaration order. It exists so a boundary that has to mirror the vocabulary — the frontend's AppErrorKind union — can be checked against it rather than kept in sync by hand.

func KindOf

func KindOf(err error) Kind

KindOf returns the Kind of the first *Error in err's chain, or KindInternal. An unclassified error is internal by definition: nobody decided otherwise.

type LastTicker

type LastTicker interface {
	LastTick() time.Time
}

type MCPBaseReader

type MCPBaseReader interface {
	MCPBaseURL(ctx context.Context) string
}

MCPBaseReader reads this run's loopback base URL. Empty means the server is down. Read per call, because the port is unknown when the service is built.

type MCPCatalogueItem

type MCPCatalogueItem struct {
	ID          string `json:"id"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Shipped     bool   `json:"shipped"`
	Stability   string `json:"stability"`
	Shadows     string `json:"shadows"`
	Transport   string `json:"transport"`
	// Command is the resolved invocation — the command line for stdio, the
	// URL for http/sse. Nothing is enabled whose command the user could not
	// read first (ADR a-workspace-declares-its-own-authority §5).
	Command string `json:"command"`
	Problem string `json:"problem"`
}

MCPCatalogueItem is one row of the merged MCP catalogue as the UI shows it: a shipped entry, a user mcps.yaml entry, or a user entry shadowing a shipped one.

type MenuBarAction struct {
	ID        string
	Label     string
	Clipboard bool
}
type MenuBarDeps struct {
	Settings *settings.Store
	Flows    *flow.FlowStore
	Items    *stores.InboxItemStore
	Catalog  *actions.ActionStore
	Polls    LastTicker
	Events   *events.Bus
}
type MenuBarFeedChoice struct {
	Feed string `json:"feed"`
	MenuBarFeedName
}
type MenuBarFeedName struct {
	ProfileName string `json:"profileName"`
	Folder      string `json:"folder"`
	Name        string `json:"name"`
}

MenuBarFeedName uses an empty Folder for feeds at the sidebar's top level.

type MenuBarFeedView struct {
	ProfileID string
	Feed      string
	MenuBarFeedName
	Total int64
	Items []MenuBarItem
}
type MenuBarItem struct {
	ID      int64
	Title   string
	URL     string
	Unread  bool
	Actions []MenuBarAction
}
type MenuBarPin struct {
	Feed  string `json:"feed"`
	Limit int    `json:"limit"`
}
type MenuBarService struct {
	// contains filtered or unexported fields
}
func (s *MenuBarService) FeedChoices(context.Context) []MenuBarFeedChoice

FeedChoices preserves profile rail and feed declaration order.

func (s *MenuBarService) LastPolled() time.Time

LastPolled returns zero before the first poll and in mock modes.

func (s *MenuBarService) SetPins(ctx context.Context, pins []MenuBarPin) error

SetPins preserves list order but does not require feeds to exist; missing feeds are skipped when read.

func (s *MenuBarService) Snapshot(ctx context.Context) (MenuBarSnapshot, error)
type MenuBarSnapshot struct {
	Pinned     []MenuBarFeedView
	LastPolled time.Time
}

type MissingPackageItem

type MissingPackageItem struct {
	Name       string   `json:"name"`
	Skill      bool     `json:"skill"`
	SelectedBy []string `json:"selectedBy"`
}

MissingPackageItem is one enabled name skills.yml does not define. Skill separates the two causes that produce an identical report: a name that is actually a skill (a manifest predating packages) from one that matches nothing at all (a typo, or a package since deleted). SelectedBy names the packages that already select the skill — the fix, when there is one.

type NopDefaultAgentReader

type NopDefaultAgentReader struct{}

NopDefaultAgentReader leaves Hive's configured agent unchanged.

func (NopDefaultAgentReader) DefaultAgent

type NopEditorCommandReader

type NopEditorCommandReader struct{}

func (NopEditorCommandReader) Editor

type NopMCPBaseReader

type NopMCPBaseReader struct{}

func (NopMCPBaseReader) MCPBaseURL

func (NopMCPBaseReader) MCPBaseURL(context.Context) string

type NotificationSettings

type NotificationSettings struct {
	Enabled bool
	// Delivery is where an eligible notification surfaces: "auto" (an OS
	// banner only while the app is unfocused), "system", or "app".
	Delivery string
	Sound    bool
}

NotificationSettings is the resolved notification configuration.

type ObservabilityService

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

func (*ObservabilityService) Settings

func (*ObservabilityService) Stats

type ObservabilitySettings

type ObservabilitySettings struct {
	OTLP       ExportStatus
	Profiles   ExportStatus
	StartError string
}

type OpenPopupTerminal

type OpenPopupTerminal struct {
	// Launcher is a configured launcher's id, and supplies the command line and
	// optionally the directory. The caller sends the id rather than the command
	// so what a launcher runs is the catalog's answer and not the client's.
	Launcher string
	// SessionSlug is a tmux session name, not a hive session id. Any slug the
	// Code view attaches answers here, which is what lets a launcher open on
	// the scratch terminal or a pinned chat as readily as on a checkout.
	SessionSlug string
	Dir         string
	Command     string
	Cols        int
	Rows        int
}

OpenPopupTerminal is one launch. The directory is resolved in order — Launcher's own cwd, where SessionSlug's terminal currently is, then Dir, then the user's home — so a caller with a terminal in hand does not have to know where it lives, and one with neither still gets a shell somewhere sensible rather than wherever the app happened to be started from. The home fallback is the bare shell's alone: a launcher that takes its directory from the terminal is refused without one (ADR quick-terminal-launchers-are-session-scoped, ADR a-new-tab-and-a-launcher-open-where-the-terminal-s-active-pane-is).

type OpenResult

type OpenResult struct {
	Workspace   WorkspaceView
	Sessions    []SessionView
	MissingMCPs []string
	// MissingPackages reports every name the workspace enables that
	// skills.yml does not define, each carrying why it did not resolve.
	MissingPackages []MissingPackageItem
}

OpenResult is what opening a workspace reports back to the UI.

type PathInfo

type PathInfo struct {
	Path string
	// Exists reports whether the path is present right now (a log file or
	// database may not exist until first written).
	Exists bool
	// Overridden reports whether an explicit override selected this location.
	Overridden bool
}

PathInfo describes a single on-disk location.

type PendingNotes

type PendingNotes struct {
	Show bool
	// Presentation is PresentationModal or PresentationToast; empty when
	// Show is false.
	Presentation string
	// Version is the running version the notes describe.
	Version string
	// Entries are the stable releases crossed to reach Version plus this
	// build's draft, newest first. It can be empty on a genuine upgrade when
	// nothing in the range carries notes.
	Entries releasenotes.Entries
}

PendingNotes is the answer to "did this launch land on a newer version, and what should the user be told about it".

type PerfInfo

type PerfInfo struct {
	Enabled  bool
	Path     string
	MaxBytes int64
}

PerfInfo tells the caller whether to instrument at all, and where the file is so an agent can read it without knowing the state-directory layout.

type PerfSample

type PerfSample struct {
	At         time.Time
	Scope      string
	Name       string
	DurationMs float64
	Attrs      map[string]any
	ID         string
	Parent     string
}

PerfSample is one completed span. DurationMs comes from the caller's own clock — the browser's performance.now() — because a timestamp round-tripped through the RPC boundary would measure the boundary as much as the work.

type PerfService

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

PerfService takes performance spans from the UI and appends them to the recorder's file. It is a development facility: when development.perf.enabled is off the recorder is disabled, Info reports that, and the frontend stops buffering rather than sending batches nothing will write.

func (*PerfService) Close

func (s *PerfService) Close() error

func (*PerfService) Info

func (s *PerfService) Info(_ context.Context) PerfInfo

func (*PerfService) Record

func (s *PerfService) Record(_ context.Context, samples []PerfSample) (int, error)

Record appends a batch and reports how many samples landed. A batch sent to a disabled recorder is not an error the UI should surface — instrumentation left in the code is expected to run against a build with recording off.

type PopupLauncher

type PopupLauncher struct {
	ID    string `json:"id"`
	Label string `json:"label"`
	Icon  string `json:"icon"`
	// RequiresSession reports that this launcher opens wherever the terminal on
	// screen is, so a surface offering it with no terminal attached is offering
	// a launch the core will refuse (ADR quick-terminal-launchers-are-session-scoped).
	RequiresSession bool `json:"requiresSession"`
}

PopupLauncher is one configured launcher, as much of it as a menu needs. What it runs is deliberately absent: a caller invokes it by id.

type PopupTerminalsDeps

type PopupTerminalsDeps struct {
	Manager   *ptyterm.Manager
	Terminals terminalWorkingDirectory
	Directory terminalDirectory
	Catalog   *actions.ActionStore
}

type PopupTerminalsService

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

PopupTerminalsService opens ephemeral terminals: a shell, or a command run through one, that this process owns outright and that ends when it is closed or when the app exits (ADR ephemeral-popup-terminals). It holds no token, base URL or stream path — what it is reached over is the adapter's (ADR terminal-transport).

func (*PopupTerminalsService) Available

func (s *PopupTerminalsService) Available(ctx context.Context) error

Available reports build and platform support. There is no external program to find, so unlike tmux this cannot become available while the app is running.

func (*PopupTerminalsService) Close

Close ends a terminal and every process in it, and reports whether there was one to close.

func (*PopupTerminalsService) Launchers

Launchers returns the configured launchers in file order.

func (*PopupTerminalsService) List

List reports the open terminals, oldest first.

func (*PopupTerminalsService) Open

Open launches a terminal and returns it.

func (*PopupTerminalsService) Resize

func (s *PopupTerminalsService) Resize(_ context.Context, id string, cols, rows int) error

Resize sets the terminal's size outright. Nothing else is attached to these PTYs, so unlike the tmux backend this is not a vote.

func (*PopupTerminalsService) Subscribe

func (s *PopupTerminalsService) Subscribe(_ context.Context, id string) (<-chan ptyterm.Event, func(), error)

Subscribe returns a terminal's event stream and its unsubscribe func. There is one active subscriber per terminal; a second call closes the first channel.

func (*PopupTerminalsService) Write

func (s *PopupTerminalsService) Write(_ context.Context, id string, p []byte) error

type PostHogService

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

PostHogService wraps the PostHog project auth. Connecting is two calls rather than one because a personal API key spans projects: Projects lists what the key can reach so the user can pick, Connect binds the one they picked.

func (*PostHogService) Connect

func (s *PostHogService) Connect(ctx context.Context, url, token string, projectID int) (posthog.Project, error)

func (*PostHogService) Disconnect

func (s *PostHogService) Disconnect(ctx context.Context, account string) error

func (*PostHogService) Projects

func (s *PostHogService) Projects(ctx context.Context, url, token string) ([]posthog.Project, error)

type PreviewRequest

type PreviewRequest struct {
	Workspace string
	Cron      string
	Prompt    string
}

type PreviewView

type PreviewView struct {
	Next           []int64
	Prompt         string
	FirstRunPrompt string
	CronError      string
	PromptError    string
}

A bad cron or template lands in CronError or PromptError rather than failing the call, so the editor can show it beside the field the user is still typing in.

type PromptsService

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

PromptsService owns the paste-ready LLM prompts. Prompt text lives in app/prompts; this resolves the install-specific environment they render against.

func (*PromptsService) Catalog

func (s *PromptsService) Catalog(ctx context.Context, input prompts.Input) ([]prompts.Prompt, error)

Catalog returns every prompt that belongs in a settings listing, rendered against this install.

func (*PromptsService) Render

func (s *PromptsService) Render(ctx context.Context, id string, input prompts.Input) (prompts.Prompt, error)

Render returns one prompt by id, including the context-scoped prompts Catalog omits.

type PullRequestStatus

type PullRequestStatus string

PullRequestStatus is why a session has no pull request to show, or that it does. The four are kept apart deliberately: rendering "no pull request" for a failed lookup or a disconnected account states a different, wrong fact.

const (
	PullRequestStatusNone         PullRequestStatus = "none"
	PullRequestStatusFound        PullRequestStatus = "found"
	PullRequestStatusDisconnected PullRequestStatus = "disconnected"
	PullRequestStatusUnsupported  PullRequestStatus = "unsupported"
)

type ReleaseNotesService

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

ReleaseNotesService decides what the What's New surface shows and remembers what the user has already seen. The running version is an argument rather than a field because the ldflags that carry the build identity bind to package main — the adapter supplies it, the same way SystemService receives it.

func NewReleaseNotesService

func NewReleaseNotesService(paths settings.Paths, logger zerolog.Logger) *ReleaseNotesService

NewReleaseNotesService builds the service over the embedded changelog. It is exported for the same reason NewSettingsService is: it depends on nothing but a path and a logger, so the adapter can build one without standing up an App.

func (*ReleaseNotesService) Acknowledge

func (s *ReleaseNotesService) Acknowledge(_ context.Context, version string) error

Acknowledge records version as seen. The modal defers this to its dismissal, so a crash while it is open does not cost the user the notes; the toast has nothing to dismiss and acknowledges on sight.

The context is deliberately discarded: the marker write must finish whether or not the caller is still listening. A frontend component unmounting mid launch cancels its call, and a cancelled write here would resurface the notes on every subsequent launch.

func (*ReleaseNotesService) History

History is every set of notes this build carries, newest first: the draft for what it has that no stable release does, then the stable releases themselves. It is the About pane's list, and where a dismissed surface can be read again.

func (*ReleaseNotesService) Pending

func (s *ReleaseNotesService) Pending(_ context.Context, version string) PendingNotes

Pending reports what this launch should show. It is the launch-time half of the feature: an install ends by relaunching the app, so there is no in-process moment after an update to hook — the reliable trigger is finding, on the next start, that the running version outranks the last one the user acknowledged. That also covers updates this app did not perform, like a package manager or a manual reinstall.

Recording on first run is a deliberate write from a read: a fresh install has no prior version to have upgraded *from*, so it silently adopts the running version and shows nothing.

type ReportPreview

type ReportPreview struct {
	HasSettings bool
	FlowCount   int
	HasActions  bool
	HasLogs     bool
	LogBytes    int
}

ReportPreview is the inventory of what a report could attach, so the dialog can label each toggle and hide the ones with nothing behind them.

type ReportRequest

type ReportRequest struct {
	IncludeLogs     bool
	IncludeSettings bool
	IncludeFlows    bool
	IncludeActions  bool
}

type ReportResult

type ReportResult struct {
	Path string
	// Dir is returned rather than derived from Path because the caller is the
	// webview, which has no path handling of its own.
	Dir string
}

type ReportService

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

ReportService exposes both halves of a bug report as separate actions, and they must not be recombined (ADR problem-reports-are-github-issues).

The saved file is shown through SystemService.OpenPath, which already guards the app's known locations; ReportsDir is one of them.

func (*ReportService) IssueURL

func (s *ReportService) IssueURL(_ context.Context) string

IssueURL builds no bundle and reads no config, so "Report a problem" cannot expose anything the About pane does not already show.

func (*ReportService) Preview

func (*ReportService) Save

type ReviewDeps added in v0.65.0

type ReviewDeps struct {
	Reviews review.Store
	Drive   *DriveService
	Code    codeAgents
	Chats   chatAgents
	Input   agentInput
	Logger  zerolog.Logger
}

type ReviewService added in v0.65.0

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

ReviewService keeps the comments a user leaves on Drive Markdown documents and delivers them as feedback. Reviews live in hive.db under a drive:// key, apart from the TUI's: the TUI anchors comments to rendered lines, and these are source lines.

A review is never finalized. Send and Clear delete it, so the user can comment again on unchanged content, and a finalized row under the key is treated as absent. Stale reviews are never cleaned up: an agent may rewrite a plan while the user reviews it, and the comments must survive that.

func (*ReviewService) AddComment added in v0.65.0

func (s *ReviewService) AddComment(ctx context.Context, space, path string, in CommentInput) (review.Comment, error)

AddComment creates the session for the current content on first use. It is KindConflict while the review is on an earlier version.

func (*ReviewService) AgentTargets added in v0.65.0

func (s *ReviewService) AgentTargets(ctx context.Context) ([]AgentTarget, error)

AgentTargets lists the agents that can take text: classified agent panes in active Code sessions, and running chats. A pane with no detected tool or no status may be a shell, which would run the feedback as commands, so it is left out.

func (*ReviewService) Clear added in v0.65.0

func (s *ReviewService) Clear(ctx context.Context, space, path string) error

func (*ReviewService) DeleteComment added in v0.65.0

func (s *ReviewService) DeleteComment(ctx context.Context, space, path, id string) error

func (*ReviewService) Feedback added in v0.65.0

func (s *ReviewService) Feedback(ctx context.Context, space, path, note string) (string, error)

Feedback formats the open review with the document's absolute path, so any agent can read the file whatever its working directory.

func (*ReviewService) Review added in v0.65.0

func (s *ReviewService) Review(ctx context.Context, space, path string) (DocumentReview, error)

Review loads the open review of a document: the session for its current content, else the newest unfinalized session for an older version.

func (*ReviewService) Send added in v0.65.0

func (s *ReviewService) Send(ctx context.Context, space, path, note string, to AgentTargetRef) error

Send delivers the open review's feedback to one agent and clears the review. The review stays when delivery fails.

func (*ReviewService) UpdateComment added in v0.65.0

func (s *ReviewService) UpdateComment(ctx context.Context, space, path, id, text string) error

type RunView

type RunView struct {
	ID           int64   `json:"id"`
	Workspace    string  `json:"workspace"`
	ScheduleID   string  `json:"scheduleId"`
	ScheduleName string  `json:"scheduleName"`
	ScheduledFor int64   `json:"scheduledFor"`
	StartedAt    int64   `json:"startedAt"`
	Reason       string  `json:"reason"`
	Status       string  `json:"status"`
	Missed       int     `json:"missed"`
	SessionID    *string `json:"sessionId"`
	Prompt       string  `json:"prompt"`
	Error        string  `json:"error"`
}

RunView timestamps are unix ms; SessionID is nil when the run launched no chat.

type RunningChat added in v0.65.0

type RunningChat struct {
	ID        string
	Workspace string
	Name      string
	// Pane is the first pane of the chat's tmux session, where the agent was
	// launched.
	Pane   string
	Status terminal.Status
}

RunningChat is a chat whose tmux session is live, with its agent's pane and status.

type ScheduleEdit

type ScheduleEdit struct {
	ID       string
	Name     string
	Cron     string
	Prompt   string
	Disabled bool
	OnMissed string
}

type SchedulePatch

type SchedulePatch struct {
	ID       string
	Name     *string
	Cron     *string
	Prompt   *string
	Disabled *bool
	OnMissed *string
}

A nil SchedulePatch field keeps its stored value, so an agent told to re-time a paused schedule does not re-enable it.

type ScheduleView

type ScheduleView struct {
	Workspace string `json:"workspace"`
	ID        string `json:"id"`
	// Name is empty when the entry has none; the reader falls back to the id.
	// Resolving the fallback here would round trip through the editor and
	// persist the id as a name the user never typed.
	Name     string `json:"name"`
	Cron     string `json:"cron"`
	Prompt   string `json:"prompt"`
	Disabled bool   `json:"disabled"`
	OnMissed string `json:"onMissed"`
	// NextRunAt is unix ms, nil when the schedule is disabled or its cron does
	// not parse.
	NextRunAt *int64 `json:"nextRunAt"`
	// LastRun is the newest run whatever its status, not the newest launched
	// one: a schedule that has been failing must say so where it is listed.
	LastRun *RunView `json:"lastRun"`
}

type SchedulesDeps

type SchedulesDeps struct {
	Workspaces *agentws.Store
	Schedules  *stores.ScheduleStore
	Sessions   *stores.AgentSessionStore
	Scheduler  *schedule.Scheduler
	Logger     zerolog.Logger
}

type SchedulesService

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

SchedulesService reads and fires schedules. Writing one is AgentWorkspacesService's, because a schedule is a manifest key.

func (*SchedulesService) List

func (s *SchedulesService) List(ctx context.Context, workspace string) ([]ScheduleView, error)

List refuses a manifest that does not parse rather than answering with last-good rows the file no longer says.

func (*SchedulesService) Preview

func (*SchedulesService) RunNow

func (s *SchedulesService) RunNow(ctx context.Context, workspace, id string) (RunView, error)

RunNow leaves the cursor untouched, so the next real occurrence still happens.

func (*SchedulesService) Runs

func (s *SchedulesService) Runs(ctx context.Context, workspace, id string, limit int) ([]RunView, error)

Runs answers for a broken manifest: that is exactly when a caller wants to read what its schedules did. A removed schedule still answers because history outlives its entry, but an id that is neither declared nor has run is not_found rather than an empty list a caller would read as "it never fired".

type ScratchTerminal

type ScratchTerminal struct {
	Slug string `json:"slug"`
	Name string `json:"name"`
}

ScratchTerminal declares the scratch terminal to the surfaces that draw it. There is exactly one, it is created on first use, and it holds no hive session, checkout or agent — its tabs are whatever the user opened.

type SessionActivityItem

type SessionActivityItem struct {
	ID string `json:"id"`
	// Status is one of terminal.Status's simplified values: ready, active, or
	// approval -- approval is the highest-urgency state.
	Status string `json:"status"`
}

SessionActivityItem is one live session's detected activity, keyed by session id so the caller does not have to re-derive a tmux session name.

type SessionEndDelayReader

type SessionEndDelayReader interface {
	SessionEndDelay(ctx context.Context) time.Duration
}

SessionEndDelayReader reads agent_workspaces.session_end_delay on each call. A non-positive answer takes the shipped value.

type SessionEnding

type SessionEnding struct {
	Session SessionView
	EndsAt  time.Time
}

type SessionPullRequest

type SessionPullRequest struct {
	Status  PullRequestStatus `json:"status"`
	Number  int               `json:"number"`
	Title   string            `json:"title"`
	State   string            `json:"state"`
	IsDraft bool              `json:"isDraft"`
	URL     string            `json:"url"`
	// ReviewDecision is GitHub's own vocabulary (APPROVED, CHANGES_REQUESTED,
	// REVIEW_REQUIRED), or empty when review is not required.
	ReviewDecision string `json:"reviewDecision"`
	// Checks is passing, pending, failing, or empty for a head commit with no
	// checks configured.
	Checks string `json:"checks"`
	// The pull request's own line counts, deliberately not the git status's:
	// those measure the working tree and drift as the branch moves on.
	Additions int `json:"additions"`
	Deletions int `json:"deletions"`
	// Cached distinguishes "this just arrived" from "this was already known".
	// The bar animates only the former.
	Cached bool `json:"cached"`
}

SessionPullRequest is the branch's pull request as the session status bar shows it. Everything below Status is meaningful only for PullRequestStatusFound.

type SessionPullRequestKey

type SessionPullRequestKey struct {
	Host   string `json:"host"`
	Owner  string `json:"owner"`
	Repo   string `json:"repo"`
	Branch string `json:"branch"`
}

SessionPullRequestKey addresses the pull request a session's branch has. Host decides which forge is asked, so a lookup carries it rather than inferring one from owner and repo, which every forge spells the same.

type SessionRisk

type SessionRisk struct {
	UncommittedChanges bool `json:"uncommittedChanges"`
	UnpushedCommits    bool `json:"unpushedCommits"`
	// RecycleDeletes reports that recycling this session destroys it: hive
	// routes a worktree session's recycle straight to DeleteSession, because a
	// worktree has no clone of its own to reset.
	RecycleDeletes bool `json:"recycleDeletes"`
}

SessionRisk is the pre-flight a destructive operation confirms against: what unsaved work the session holds, and whether recycling it is really a delete.

type SessionStatus

type SessionStatus struct {
	SessionID string                `json:"sessionId"`
	Running   bool                  `json:"running"`
	Windows   []SessionWindowStatus `json:"windows"`
}

SessionStatus separates tmux liveness from the activity detected in each agent window.

type SessionStatusSnapshot

type SessionStatusSnapshot struct {
	Items          []SessionStatus `json:"items"`
	PollIntervalMS int64           `json:"pollIntervalMs"`
}

SessionStatusSnapshot carries one poll result and the hive-configured delay the caller should use before requesting the next one, in the milliseconds a browser timer takes.

type SessionView

type SessionView struct {
	ID           string `json:"id"`
	LegacyID     string `json:"legacyId"`
	Workspace    string `json:"workspace"`
	Name         string `json:"name"`
	Agent        string `json:"agent"`
	LastOpenedAt int64  `json:"lastOpenedAt"`
	// Slug is the tmux session name (agentws-<terminal id>) this session is addressed by
	// whether or not it is running, so a caller can key a row, a route or an
	// attach pool on it without deriving the name itself. TerminalID, not this,
	// is what reports liveness.
	Slug string `json:"slug"`
	// TerminalID is the tmux session name (agentws-<terminal id>) a live session rides,
	// addressed on the same tmux stream terminal mode uses (ADR terminal-transport); empty
	// when nothing is running.
	TerminalID string `json:"terminalId"`
	// WindowID is TerminalID's active tmux window at the moment this session
	// was attached -- the tmux wire frames output and input by window id,
	// unlike the flat ptyterm wire sessions rode before. It is set only by a
	// call that attaches (StartSession, ResumeSession); a listing read
	// (Sessions, Open) leaves it empty even for a live session, since nothing
	// there attaches.
	WindowID string `json:"windowId"`
	// PaneID is WindowID's active pane at attach and frames client input.
	PaneID string `json:"paneId"`
	// Cols and Rows are tmux's own size for that window at attach — whichever
	// attached client tmux's window-size option picked, not necessarily the
	// caller's cols/rows vote. The pane must open its grid at this size or the
	// TUI's cursor-addressed output tears; 0 means tmux has not reported one.
	// Set only by a call that attaches, like WindowID.
	Cols int `json:"cols"`
	Rows int `json:"rows"`
	// ResumeAttempted is false when this launch could not even try to resume —
	// the agent has no resume form, or it provably persisted nothing under the
	// session's id to resume. It is deliberately not named Resumed: Hive sees
	// only pane content, so a pruned agent history would report a successful
	// resume while the agent prints its own error in the pane, which is the
	// "pretending it was" spec §6.2 forbids.
	ResumeAttempted bool `json:"resumeAttempted"`
	// Notice carries a fresh-launch, unbounded-MCP or missing-MCP explanation.
	Notice string `json:"notice"`
	// ExitedEarly is what the scheduler reads instead of Notice, so the reason
	// it treats a launch as failed does not depend on a notice's wording.
	ExitedEarly bool `json:"exitedEarly"`
	// ScheduleID is a column on the session record rather than a lookup in the
	// run history because history is pruned and cannot remain the authority.
	ScheduleID string `json:"scheduleId"`
}

SessionView is one row of a workspace's session list.

type SessionWindowStatus

type SessionWindowStatus struct {
	WindowID string `json:"windowId"`
	Status   string `json:"status"`
	Tool     string `json:"tool"`
}

SessionWindowStatus is one tmux window's detected agent activity. Status is simplified: ready, active, or approval.

type SessionsDeps

type SessionsDeps struct {
	Hive              *hive.Engine
	Launcher          sessionLauncher
	WorkspaceLauncher workspaceSessionLauncher
	// Windows maps a session's windows to their stable tmux ids. nil leaves
	// liveness to hive's own status detection.
	Windows       sessionWindowSource
	Tmux          sessionTmux
	AgentWindows  sessionAgentWindows
	AgentCommands func() map[string]string
	Jobs          sessionJobRunner
	Items         inboxItemRefReader
	Links         itemSessionStore
	Catalog       *actions.ActionStore
	Dispatcher    *dispatch.Dispatcher
	Recorder      activity.Recorder
	PullRequests  *sessionPullRequests
	ExecEnv       *execenv.Resolver
	// EditorCommand reads the configured editor from settings on every call,
	// so a settings change applies without restarting. nil means
	// NopEditorCommandReader.
	EditorCommand EditorCommandReader
	// DefaultAgentEnv reads HIVE_DEFAULT_AGENT the way the user's terminal
	// would. nil means NopDefaultAgentReader.
	DefaultAgentEnv DefaultAgentReader
	Events          *events.Bus
	Logger          zerolog.Logger
}

type SessionsService

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

SessionsService is the desktop's session surface: the New Session form's launch path, read plus lifecycle management of the sessions that exist, and the configured actions a terminal session or window offers.

It reads every hive service from the engine per call, so a hive config reload reaches the next call.

func (*SessionsService) CanonicalSpace added in v0.64.0

func (s *SessionsService) CanonicalSpace(space drive.Space) drive.Space

ListSessions returns every session, whatever its state. Only an active one can be attached to — Slug is its tmux session name — but a recycled or corrupted session still has to be readable and deletable. CanonicalSpace is space spelled as its directory is on disk, so a session whose remote differs only by case from the checkout still names the space the drive watches.

func (*SessionsService) CreateSession

func (s *SessionsService) CreateSession(ctx context.Context, req dispatch.CreateSessionRequest) (int64, error)

CreateSession validates a New Session form, then launches a repository session or workspace chat as a background job and returns its id. Creation runs asynchronously and its outcome surfaces in the jobs UI, so only validation errors are returned here.

func (*SessionsService) DeleteSession

func (s *SessionsService) DeleteSession(ctx context.Context, id string) (int64, error)

DeleteSession removes a session, its worktree or clone, and its tmux session, as a background job: it runs git and filesystem work that a caller must not block on. The caller is expected to have confirmed against SessionRisk first.

func (*SessionsService) DismissFailedSession

func (s *SessionsService) DismissFailedSession(context.Context) error

DismissFailedSession drops the pending failed attempt.

func (*SessionsService) FailedSessionDraft

func (s *SessionsService) FailedSessionDraft(context.Context) (dispatch.SessionDraft, error)

FailedSessionDraft returns the last failed New Session form. A nil Failure is what says there is no attempt waiting.

func (*SessionsService) InvokeTerminalAction

func (s *SessionsService) InvokeTerminalAction(ctx context.Context, actionID string, target dispatch.TerminalTarget, inputs map[string]string) (int64, error)

InvokeTerminalAction runs one configured action against a terminal target as a background job, and returns the job id — the run outlives the call the way every other session job does, and the jobs UI is where its outcome lands.

It deliberately enqueues no output_command. A durable command's UNIQUE (action_id, key) is what stops an already-run action from re-firing, and that is exactly wrong here: "open the worktree in Finder" is a manual operation against live local state, meant to be repeatable without a rerun confirmation and meaningless to replay after a restart.

The authorization chain: the action must exist, declare the surface it was invoked from, and satisfy its declared inputs; the session must exist and be active. Everything the templates read is resolved here from the session record rather than taken from the caller.

func (*SessionsService) ItemChats

func (s *SessionsService) ItemChats(ctx context.Context, itemID int64) ([]ItemChatView, error)

ItemChats returns the agent workspace chats an inbox item opened, newest first.

func (*SessionsService) ItemSessions

func (s *SessionsService) ItemSessions(ctx context.Context, itemID int64) ([]ItemSessionView, error)

ItemSessions returns the hive sessions an inbox item spawned, newest first, joined to the state hive reports for them now. The read is also what reconciles (ADR macos-dmg-installer).

func (*SessionsService) ListSessions

func (s *SessionsService) ListSessions(ctx context.Context) ([]session.Session, error)

func (*SessionsService) NewAgentWindow

func (s *SessionsService) NewAgentWindow(ctx context.Context, slug, agent string) (windowID string, resultErr error)

NewAgentWindow starts a configured profile beside the session's existing windows, sharing its checkout without creating another Hive record.

func (*SessionsService) OpenSessionInEditor

func (s *SessionsService) OpenSessionInEditor(ctx context.Context, id string) error

OpenSessionInEditor launches the configured editor on the session's checkout, detached. It takes a session id, never a path: launching a configured program on a caller-supplied directory is not this API's to offer.

func (*SessionsService) PruneSessions

func (s *SessionsService) PruneSessions(ctx context.Context) (int64, error)

PruneSessions deletes every recycled and corrupted session as a background job, and reports the job id rather than the count: the work outlives the call, so the count is not known yet.

Hive's Prune also has a mode that only trims each pool back to max_recycled. That is a config reconciliation, not something a menu entry can honestly name, so the desktop exposes the unambiguous one.

func (*SessionsService) RecycleSession

func (s *SessionsService) RecycleSession(ctx context.Context, id string) (int64, error)

RecycleSession resets a session for reuse, as a background job for the same reason DeleteSession is one. For a worktree session hive recycles by deleting, which is what SessionRisk.RecycleDeletes warns about.

The recycle commands' output is discarded. They are the user's own (hive's recycle_commands) and the job records whether they succeeded; streaming their stdout would need a job log to stream into.

func (*SessionsService) RenameSession

func (s *SessionsService) RenameSession(ctx context.Context, id, name string) (session.Session, error)

RenameSession renames a session and returns its new summary.

Desktop preflights the live tmux rename so a collision cannot move the record onto another session's target. The shared Hive service then updates the record and its persisted multiplexer target. If that update fails, Desktop puts the live tmux name back.

func (*SessionsService) RenderTerminalClipboardAction

func (s *SessionsService) RenderTerminalClipboardAction(ctx context.Context, actionID string, target dispatch.TerminalTarget, inputs map[string]string) (string, error)

RenderTerminalClipboardAction resolves a clipboard action against a terminal target and returns the text for the desktop adapter to place on the clipboard. It is the render-only sibling of InvokeTerminalAction, mirroring the split the detail pane already makes: re-copying just renders again.

func (*SessionsService) RevealSession

func (s *SessionsService) RevealSession(ctx context.Context, id string) error

RevealSession opens the session's checkout in the OS file manager.

func (*SessionsService) SessionDetail

func (s *SessionsService) SessionDetail(ctx context.Context, id string) (session.Session, error)

SessionDetail reads one session in full.

func (*SessionsService) SessionDirectory

func (s *SessionsService) SessionDirectory(ctx context.Context, slug string) (string, error)

SessionDirectory answers the checkout a slug's terminal should open in. A session with no checkout left is a conflict rather than an empty path, so a terminal is never opened somewhere the caller did not ask for.

func (*SessionsService) SessionDraftFromActivity

func (s *SessionsService) SessionDraftFromActivity(_ context.Context, metadata map[string]string) (dispatch.SessionDraft, error)

SessionDraftFromActivity decodes the form an activity row carries. It takes the row's metadata rather than its id because the caller already holds the row it rendered, and forwarding an opaque bag keeps the encoding in Go.

A bag carrying no retry is KindInvalid rather than an empty draft: a form silently prefilled with nothing is worse than a refused one.

func (*SessionsService) SessionGitStatus

func (s *SessionsService) SessionGitStatus(ctx context.Context, id string) (gitstatus.Status, error)

SessionGitStatus reads the session's checkout for the status bar: branch, dirty, unpushed, and the line delta against the default branch. A session with no live checkout answers an unresolved status rather than an error — there is nothing wrong, there is just nothing to read.

Unlike SessionRisk it reports failures instead of assuming the risky answer (gitstatus.Status).

func (*SessionsService) SessionLaunchOptions

func (s *SessionsService) SessionLaunchOptions(ctx context.Context) (dispatch.SessionLaunchOptions, error)

SessionLaunchOptions supplies the repository, workspace, and agent choices the New Session form presents.

Local source paths stay here: the form gets labels, remotes, and agent keys.

func (*SessionsService) SessionLaunchWorkspaces

func (s *SessionsService) SessionLaunchWorkspaces(ctx context.Context) []dispatch.SessionLaunchWorkspace

SessionLaunchWorkspaces supplies workspace choices without resolving repository options.

func (*SessionsService) SessionPullRequest

func (s *SessionsService) SessionPullRequest(ctx context.Context, key SessionPullRequestKey, refresh bool) (SessionPullRequest, error)

SessionPullRequest resolves the pull request for a branch SessionGitStatus already reported. The branch is passed rather than read again: resolving it costs a git subprocess the caller has just paid for, and the two halves refresh on different cadences.

func (*SessionsService) SessionRisk

func (s *SessionsService) SessionRisk(ctx context.Context, id string) (SessionRisk, error)

SessionRisk reports the work a delete or recycle of id would discard, so the caller can name it in its confirmation instead of guessing. Hive reports no risk for a non-active session, which is correct: there is no live clone left to hold unsaved work.

func (*SessionsService) SessionStatuses

func (s *SessionsService) SessionStatuses(ctx context.Context) (SessionStatusSnapshot, error)

SessionStatuses detects the live agent state for active sessions. Missing or unavailable terminals are data, so only a failure to read the session set fails the request.

func (*SessionsService) StartTmuxSession

func (s *SessionsService) StartTmuxSession(ctx context.Context, slug string) (multiplexer.LaunchResult, error)

StartTmuxSession spawns the tmux session a slug names. A session hive knows about does not have to have one — its tmux server was restarted, the machine rebooted, or it was created by something that never spawned one — and this is what lets the terminal attach to it anyway.

The windows are hive's: what a session's terminal holds is its spawn configuration for the remote, and a second definition of that here would drift from the one `hive` itself uses. Spawning a session tmux already has is a no-op, so this is safe to call before every cold attach.

func (*SessionsService) TerminalActionViews

func (s *SessionsService) TerminalActionViews(_ context.Context, target string) ([]actions.View, error)

TerminalActionViews returns the configured actions offered on one terminal surface: actions.TargetSession for a session row, actions.TargetWindow for a window row inside it.

Unlike a feed item's, the set does not depend on which session: a terminal action declares the surface it belongs on and there is no item kind to narrow it further. Presentation order is the catalog's, same as everywhere else actions are offered.

type SettingsDeps

type SettingsDeps struct {
	Store    *settings.Store
	Producer *ingest.Producer
	Fetchers *ghsource.Fetchers
	LookPath func(context.Context, string) (string, error)
}

Producer and Fetchers may be nil when no live source subsystem is available.

type SettingsService

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

SettingsService owns settings.yaml: reading the resolved values, validating a change, persisting it, and applying what can be applied to the running subsystems without a restart.

Every setter is load-modify-save so unrelated fields survive; writing a fresh single-field Settings would clobber them.

func NewSettingsService

func NewSettingsService(store *settings.Store) *SettingsService

NewSettingsService builds the settings-only service an adapter can use before App exists. It does not wire live source updates.

func (*SettingsService) Appearance

func (*SettingsService) Editor

func (s *SettingsService) Editor(context.Context) (string, error)

Editor returns the configured editor command, or "" when none is set.

func (*SettingsService) EditorChoices

func (s *SettingsService) EditorChoices(ctx context.Context) []EditorChoice

EditorChoices reports the known editor catalogue with each command resolved against the subprocess PATH, for the Settings selector.

func (*SettingsService) EditorTitle

func (s *SettingsService) EditorTitle(command string) string

EditorTitle is the display title a configured command is labelled with, and "" for no command at all.

func (*SettingsService) Github

func (*SettingsService) Keybindings

func (s *SettingsService) Keybindings(context.Context) (map[string][]string, error)

Keybindings returns the persisted shortcut overrides keyed by command id. A nil map is normalized to an empty one so callers never null-check it.

func (*SettingsService) Notifications

func (*SettingsService) OnboardingCompleted

func (s *SettingsService) OnboardingCompleted(context.Context) (bool, error)

OnboardingCompleted reports whether first run has been walked to its end.

func (*SettingsService) ReviewLabels added in v0.65.0

func (s *SettingsService) ReviewLabels(context.Context) ([]settings.ReviewLabel, error)

ReviewLabels are the preset comments the Drive comment composer offers, the shipped ones when settings.yaml names none.

func (*SettingsService) SessionEndDelay

func (s *SettingsService) SessionEndDelay(context.Context) time.Duration

SessionEndDelay is zero when settings cannot be read; the caller takes the shipped value.

func (*SettingsService) SetCanvasFontSize

func (s *SettingsService) SetCanvasFontSize(_ context.Context, size string) error

func (*SettingsService) SetCanvasLineSpacing

func (s *SettingsService) SetCanvasLineSpacing(_ context.Context, spacing string) error

func (*SettingsService) SetCanvasPageWidth added in v0.61.0

func (s *SettingsService) SetCanvasPageWidth(_ context.Context, width string) error

func (*SettingsService) SetEditor

func (s *SettingsService) SetEditor(_ context.Context, command string) error

SetEditor persists the editor command. Empty clears the setting; anything else must be a single word — a command name or path, never a command line — the same rule agent commands follow (ADR a-workspace-declares-its-own-authority).

func (*SettingsService) SetFontFamily

func (s *SettingsService) SetFontFamily(_ context.Context, family string) error

func (*SettingsService) SetGithub

func (s *SettingsService) SetGithub(_ context.Context, in GithubSettings) error

SetGithub validates against the floor, persists, and applies to the running producer and fetch layer. A caller below the floor is rejected rather than clamped: an API caller asking to poll every second should be told no, where a settings.yaml written by hand is clamped at load.

func (*SettingsService) SetKeybindings

func (s *SettingsService) SetKeybindings(_ context.Context, overrides map[string][]string) error

SetKeybindings persists shortcut overrides. An empty map clears the section entirely, which is how "reset everything to defaults" is expressed.

func (*SettingsService) SetMonoFontFamily

func (s *SettingsService) SetMonoFontFamily(_ context.Context, family string) error

func (*SettingsService) SetNotifications

func (s *SettingsService) SetNotifications(_ context.Context, in NotificationSettings) error

func (*SettingsService) SetOnboardingCompleted

func (s *SettingsService) SetOnboardingCompleted(context.Context) error

SetOnboardingCompleted retires first run. There is no way back through the API on purpose: a person who wants to walk it again deletes the key.

func (*SettingsService) SetReviewLabels added in v0.65.0

func (s *SettingsService) SetReviewLabels(_ context.Context, labels []settings.ReviewLabel) error

SetReviewLabels persists the composer's labels in order. A list equal to the shipped one, or an empty one, clears the key so settings.yaml keeps no copy of the defaults.

func (*SettingsService) SetTerminalFontFamily

func (s *SettingsService) SetTerminalFontFamily(_ context.Context, family string) error

func (*SettingsService) SetTerminalFontSize

func (s *SettingsService) SetTerminalFontSize(_ context.Context, px int) error

func (*SettingsService) SetTerminalFontWeights

func (s *SettingsService) SetTerminalFontWeights(_ context.Context, weight, weightBold int) error

SetTerminalFontWeights writes both weights at once: they are picked together in one control, and a normal weight above the bold one is the kind of state two independent setters would let a caller land in.

func (*SettingsService) SetTerminalLetterSpacing

func (s *SettingsService) SetTerminalLetterSpacing(_ context.Context, spacing int) error

func (*SettingsService) SetTerminalLineHeight

func (s *SettingsService) SetTerminalLineHeight(_ context.Context, lineHeight float64) error

func (*SettingsService) SetTerminalPoolSize

func (s *SettingsService) SetTerminalPoolSize(_ context.Context, size int) error

func (*SettingsService) SetTerminalSessionAge added in v0.61.0

func (s *SettingsService) SetTerminalSessionAge(_ context.Context, enabled bool, thresholdDays int) error

func (*SettingsService) SetTerminalShowStatusBar

func (s *SettingsService) SetTerminalShowStatusBar(_ context.Context, show bool) error

func (*SettingsService) SetTerminalShowWindows

func (s *SettingsService) SetTerminalShowWindows(_ context.Context, show bool) error

func (*SettingsService) SetTheme

func (s *SettingsService) SetTheme(_ context.Context, theme string) error

func (*SettingsService) SetUpdatesEnabled

func (s *SettingsService) SetUpdatesEnabled(enabled bool) (bool, error)

SetUpdatesEnabled persists the user's value and returns the effective value after any process environment override is reapplied.

type SkillNameItem

type SkillNameItem struct {
	Slug       string   `json:"slug"`
	Shipped    bool     `json:"shipped"`
	SelectedBy []string `json:"selectedBy"`
}

SkillNameItem is one name in the skills name-space with the packages that select it. The editor needs the whole name-space, not just the packages: an enabled name it cannot find among the packages is either a skill (fix: enable a package in SelectedBy) or nothing at all (fix: a typo), and only the name-space tells those apart.

type SkillPackageItem

type SkillPackageItem struct {
	Name        string               `json:"name"`
	Title       string               `json:"title"`
	Description string               `json:"description"`
	Members     []SkillPackageMember `json:"members"`
}

SkillPackageItem is one row of the package catalogue as the UI shows it: a package from skills.yml and the skills it currently resolves to. Members are what the patterns select right now, not a stored list — adding a matching skill changes every workspace that enabled the package.

type SkillPackageMember

type SkillPackageMember struct {
	Slug    string `json:"slug"`
	Shipped bool   `json:"shipped"`
}

SkillPackageMember is one skill a package selects, with where it came from.

type SkillsService

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

SkillsService presents the paste-ready prompts as agent skills: what this build ships, and one skill rendered as a SKILL.md. It installs nothing — a workspace declares the skills it carries and the workspace generator writes them (ADR skills-are-declared-by-a-workspace).

func (*SkillsService) RenderSkill

func (s *SkillsService) RenderSkill(ctx context.Context, id string) (name, body string, err error)

RenderSkill renders one listed prompt as a SKILL.md for installation into a workspace, returning the slug it installs under and the file contents.

func (*SkillsService) ShippedSkills

func (s *SkillsService) ShippedSkills(ctx context.Context) ([]agentws.ShippedSkill, error)

ShippedSkills lists every skill this build ships as a workspace can enable it: the installed slug plus the labels the skill catalogue shows. A prompt that cannot render without caller-supplied context is absent from the listing, so the catalogue never offers a skill a workspace open could not resolve.

type SourcesService

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

SourcesService is ingestion on demand: a producer tick someone asked for rather than the next one settings.polling.interval would have run. Both entry points force the tick, so a source that declared an hourly cadence still runs.

They differ in what happens to the fetch caches. A user pressing refresh is asserting that something upstream changed, so Refresh drops the caches and pays for the refetch. A flow edit asserts nothing about upstream — an added or retyped source node has nothing cached under its query anyway — so Run keeps them and stays cheap enough to fire on every deploy.

func (*SourcesService) Refresh

Refresh clears the fetch caches and drains every source now. Engine commits are asynchronous, so a caller reading items back should retry briefly. Mock modes have no producer and return KindUnavailable.

func (*SourcesService) Run

Run drains every source now against whatever the fetch caches already hold.

type StartScheduledSession

type StartScheduledSession struct {
	Workspace    string
	ScheduleID   string
	ScheduleName string
	Name         string
	Prompt       string
}

StartScheduledSession has no cols/rows because it is always detached. Prompt is the schedule's own template, rendered; the launch frames it.

type StartSession

type StartSession struct {
	Workspace string
	Name      string
	Cols      int
	Rows      int
	// Prompt empty produces exactly the interactive launch line.
	Prompt string
	// Detached skips the control-client attach, so the session has no
	// TerminalID or WindowID. A scheduled launch has no pane to render into.
	Detached   bool
	ScheduleID string
}

StartSession is one new session's launch.

type SystemInfo

type SystemInfo struct {
	DataDir         PathInfo
	ConfigDir       PathInfo
	HiveDataDir     PathInfo
	LogFile         PathInfo
	Database        PathInfo
	AgentWorkspaces PathInfo
	HiveConfig      PathInfo
}

SystemInfo is the full set of locations the settings screens show.

type SystemService

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

SystemService owns the app's on-disk locations and the operations the settings screens offer over them: open, reveal, config creation, and the point-only data/config directory overrides.

Directory overrides take effect after a restart: they are written to the bootstrap pointer file and seeded into the environment at next launch. Nothing is moved.

The native directory picker and Quit stay in the adapter — both are GUI, not domain.

func (*SystemService) ClearConfigDir

func (s *SystemService) ClearConfigDir(context.Context) error

ClearConfigDir removes the config-directory override.

func (*SystemService) ClearDataDir

func (s *SystemService) ClearDataDir(context.Context) error

ClearDataDir removes the data-directory override, reverting to the default location on the next launch.

func (*SystemService) Info

Info returns the effective locations for this process and their override state.

func (*SystemService) OpenHiveConfig

func (s *SystemService) OpenHiveConfig(_ context.Context) error

OpenHiveConfig creates the resolved Hive config when needed, then opens it in the OS default application.

func (*SystemService) OpenPath

func (s *SystemService) OpenPath(_ context.Context, path string) error

OpenPath opens one of the known system locations in the OS default application.

func (*SystemService) RevealPath

func (s *SystemService) RevealPath(_ context.Context, path string) error

RevealPath reveals one of the known system locations in the OS file manager.

func (*SystemService) SetConfigDir

func (s *SystemService) SetConfigDir(_ context.Context, path string) error

SetConfigDir persists a config-directory override (flows, actions). Same semantics as SetDataDir.

func (*SystemService) SetDataDir

func (s *SystemService) SetDataDir(_ context.Context, path string) error

SetDataDir persists a data-directory override. It validates the target and creates it if missing, but does not move existing data.

type TaskBlocker

type TaskBlocker struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Status string `json:"status"`
}

TaskBlocker is one explicit blocker on a task. A blocker whose item has since been deleted keeps its ID with an empty Title rather than being dropped.

type TaskComment

type TaskComment struct {
	ID        string    `json:"id"`
	Message   string    `json:"message"`
	CreatedAt time.Time `json:"createdAt"`
}

type TaskDetail

type TaskDetail struct {
	hc.Item
	Blockers []TaskBlocker
	Comments []TaskComment
}

type TasksService

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

TasksService methods return KindUnavailable when the engine is nil.

func (*TasksService) DeleteTask

func (s *TasksService) DeleteTask(ctx context.Context, id string) error

DeleteTask deletes id and its whole subtree, comments included. GetItem runs first so a missing id reports KindNotFound instead of DeleteItem's silent no-op on an unknown ID.

func (*TasksService) ListTasks

func (s *TasksService) ListTasks(ctx context.Context, repoKey string) ([]hc.Item, error)

ListTasks returns every item for repoKey, epics and tasks alike, with no status filter: the tasks view's filter groups do not map to hc's single status field, so it filters the full list itself.

func (*TasksService) PruneTasks

func (s *TasksService) PruneTasks(ctx context.Context, olderThanDays int, repoKey string, dryRun bool) (int, error)

PruneTasks removes terminal, stale items. It takes olderThanDays because that is the unit the prune dialog collects. Leaving the statuses unset keeps the store's done-and-cancelled default.

func (*TasksService) SetTaskStatus

func (s *TasksService) SetTaskStatus(ctx context.Context, id, status string) error

SetTaskStatus sets id's status. A terminal status on an epic cascades to every non-terminal descendant when it changes the epic's status (hcsvc.Service.UpdateItem).

func (*TasksService) TaskDetail

func (s *TasksService) TaskDetail(ctx context.Context, id string) (TaskDetail, error)

TaskDetail reads one item in full: its own fields, its comments, and a title for each explicit blocker. ListItems never fills BlockerIDs, so each blocker's title costs its own GetItem.

func (*TasksService) TaskRepoKeys

func (s *TasksService) TaskRepoKeys(ctx context.Context) ([]string, error)

TaskRepoKeys returns every distinct repo key that has at least one hc item.

type TelemetryRuntime

type TelemetryRuntime struct {
	OTLPRunning     bool
	ProfilesRunning bool
	StartError      string
}

TelemetryRuntime reports which exporters this process started. Running means the SDK pipeline started, not that the remote backend has accepted a signal.

type TerminalImagesService

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

func (*TerminalImagesService) Prepare

func (s *TerminalImagesService) Prepare(ctx context.Context, paths []string) ([]string, error)

func (*TerminalImagesService) Save

func (s *TerminalImagesService) Save(ctx context.Context, images []io.Reader) ([]string, error)

type TerminalsDeps

type TerminalsDeps struct {
	Manager *tmuxcc.Manager
	Starter terminalStarter
	Home    func() (string, error)
	Logger  zerolog.Logger
}

type TerminalsService

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

TerminalsService is the slug-keyed driving service both the HTTP and the Wails adapter call. It holds no token, base URL or stream path: what the terminal is reached over is the adapter's, not the core's (ADR terminal-transport).

func (*TerminalsService) Attach

func (s *TerminalsService) Attach(ctx context.Context, slug string, cols, rows int) ([]tmuxcc.Window, error)

Attach opens, or returns the windows of, the control client for slug, and leaves a first paint on its stream either way: a control client that outlived the transport rendering it is repainted rather than handed back with nothing to draw. cols and rows are the caller's opening size vote, read only when the attach opens a client; 0x0 attaches without setting a client size at all, which leaves the session at the size its other clients gave it until the first Resize.

A slug tmux is not running is a KindNotFound the caller is expected to answer with Start — attaching never spawns on its own, because spawning runs the session's agent command and that is the user's call to make (ADR terminal-start-is-an-offered-action). That answer comes from a has-session probe rather than from a dead control stream's message, which is unclassifiable and reads as an internal fault.

func (*TerminalsService) Available

func (s *TerminalsService) Available(ctx context.Context) error

Available reports tmux/build/platform availability only. Whether the loopback server that carries the transport is up is composed by the adapter that owns that transport.

func (*TerminalsService) ClosePane

func (s *TerminalsService) ClosePane(ctx context.Context, slug, paneID string) error

ClosePane kills one pane; the last pane of a window takes the window with it.

func (*TerminalsService) CloseWindow

func (s *TerminalsService) CloseWindow(ctx context.Context, slug, windowID string) error

func (*TerminalsService) Detach

func (s *TerminalsService) Detach(ctx context.Context, slug string) error

Detach closes slug's control client, leaving the tmux session itself alone. An unknown slug is not an error: detaching what is already gone succeeded.

func (*TerminalsService) Kill

func (s *TerminalsService) Kill(ctx context.Context, slug string) (bool, error)

Kill kills the tmux session slug names and reports whether there was one to kill. It is the terminal's own lifecycle only: the hive session, its checkout and its record are untouched, which is what separates this from a delete or a recycle. Whatever was running inside — the agent included — stops with it.

func (*TerminalsService) ListAllWindows

func (s *TerminalsService) ListAllWindows(ctx context.Context, slugs []string) (map[string][]tmuxcc.Window, error)

ListAllWindows answers the window sets of every slug in one tmux call, keyed by slug. This is what the sidebar sweeps with: asking per slug spawned two tmux processes for each unattached session. A slug with no tmux session behind it is absent from the result rather than an error.

func (*TerminalsService) MoveWindow

func (s *TerminalsService) MoveWindow(ctx context.Context, slug, windowID string, position int) ([]tmuxcc.Window, error)

MoveWindow moves a window to a position in the session's window order and answers with the order tmux settled on, so a caller renders what happened rather than what it asked for. Window order is tmux session state: the move reaches every other client attached to the same session.

func (*TerminalsService) NewWindow

func (s *TerminalsService) NewWindow(ctx context.Context, slug string) (windowID string, resultErr error)

NewWindow creates a window and returns its id; the tab set itself follows from the notification tmux sends afterwards.

Attaching is not a precondition. A session's windows are its own, and the row offering a new one is offering it for the session rather than for what happens to be on screen — so a slug with no control client is served by a one-shot, and the attach that follows lists what it made. Either way the window opens where the session's active pane is, not where the session was started.

func (*TerminalsService) ObserveFrameLatency

func (s *TerminalsService) ObserveFrameLatency(ctx context.Context, latency time.Duration)

ObserveFrameLatency records how long an output frame took from tmux decode to the moment a transport put it on the wire. Only the transport knows when the send happened, so it measures and reports it here.

func (*TerminalsService) PaneForeground

func (s *TerminalsService) PaneForeground(ctx context.Context, slug, paneID string) (WindowForeground, error)

PaneForeground reports whether closing paneID would kill work.

func (*TerminalsService) Paste

func (s *TerminalsService) Paste(ctx context.Context, slug, paneID string, p []byte) error

Paste inserts text into a pane as a paste rather than as keystrokes, so the pane's program decides how to read it.

func (*TerminalsService) RenameWindow

func (s *TerminalsService) RenameWindow(ctx context.Context, slug, windowID, name string) error

func (*TerminalsService) Resize

func (s *TerminalsService) Resize(ctx context.Context, slug string, cols, rows int) error

Resize renegotiates the control client's size. Every client attached to a window renders the same grid, and tmux's window-size option decides whose size that is, so this is a vote rather than a resize.

func (*TerminalsService) ResizePane

func (s *TerminalsService) ResizePane(ctx context.Context, slug, paneID string, width, height int) error

ResizePane sets width and/or height in cells; zero leaves that axis unchanged.

func (*TerminalsService) Scratch

Scratch declares the scratch terminal. It is a constant rather than a probe: whether tmux is holding the session is what Start and the window listing answer, and a caller that draws the row needs it before either.

func (*TerminalsService) SelectPane

func (s *TerminalsService) SelectPane(ctx context.Context, slug, paneID string, direction tmuxcc.PaneDirection) error

SelectPane selects paneID when direction is empty; otherwise it selects the neighbor in that direction.

func (*TerminalsService) SelectWindow

func (s *TerminalsService) SelectWindow(ctx context.Context, slug, windowID string) error

func (*TerminalsService) SplitPane

func (s *TerminalsService) SplitPane(ctx context.Context, slug, paneID string, direction tmuxcc.SplitDirection) (string, error)

SplitPane splits a pane of an attached session and returns the new pane's id. The new layout, and the new pane's first paint, follow on the stream.

func (*TerminalsService) Start

Start spawns the tmux session slug names, from the hive session's own spawn configuration, and reports whether it had to. A session tmux is already running is left alone: the probe is what keeps a spawn configuration the desktop cannot drive — hive's command-based `spawn:` rather than `windows:` — from failing a start for a session that needs none.

ScratchSlug is the one slug this does not ask hive about — see startScratch.

func (*TerminalsService) Subscribe

func (s *TerminalsService) Subscribe(_ context.Context, slug string) (<-chan tmuxcc.Event, func(), error)

Subscribe returns slug's event stream and its unsubscribe func. There is one active subscriber per session: a second call closes the first channel, which is how a replaced transport learns it was replaced.

func (*TerminalsService) WindowForeground

func (s *TerminalsService) WindowForeground(ctx context.Context, slug, windowID string) (WindowForeground, error)

WindowForeground reports whether closing a window would kill work. Running is false only when every live pane in it is a shell sitting at its prompt; anything else — an agent, an editor, a script — answers true and names the process, so a caller can say what it is about to stop.

Uncertainty answers true. A pane whose state cannot be read is one whose work this cannot account for, and the two ways of being wrong do not cost the same: a confirmation nobody needed against a process killed without one.

func (*TerminalsService) WorkingDirectory

func (s *TerminalsService) WorkingDirectory(ctx context.Context, slug string) (string, error)

WorkingDirectory is where a session's terminal currently is — the directory its active pane would print, not the one the session was started in. It is the core's answer to "here" for a caller that has a slug and needs a path: a launcher with no cwd of its own, and anything else opened against the terminal on screen.

It is answered from tmux rather than from the session record on purpose. A slug in this view is not always a hive session — the scratch terminal and a pinned chat are tmux sessions with no checkout behind them — and a pane that has been cd'd somewhere else is where its user is, whichever kind it is. A slug tmux is not running is KindNotFound, which leaves the caller to decide what a terminal that is not up should fall back to.

func (*TerminalsService) Write

func (s *TerminalsService) Write(ctx context.Context, slug, paneID string, p []byte) error

Write sends bytes to a pane. The pane is named rather than resolved from a window's active pane, because the keystrokes that follow a click into a pane are sent while the select-pane it caused is still in flight.

func (*TerminalsService) ZoomPane

func (s *TerminalsService) ZoomPane(ctx context.Context, slug, paneID string) error

ZoomPane toggles a pane between filling its window and its place in the layout.

type WebhookCapture

type WebhookCapture struct {
	ReceivedAt    int64
	Body          []byte
	FeedShaped    bool
	MissingFields []string
}

WebhookCapture is one sources.webhook node's most recent delivery. ReceivedAt of 0 means nothing has been captured yet.

type WebhookDeps

type WebhookDeps struct {
	Settings *settings.Store
	Captures *stores.WebhookCaptureStore
	Listener *webhook.Listener
	Host     string
	Port     int
}

type WebhookService

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

WebhookService owns the local webhook listener's configuration and the per-node capture the editor shows. The listener is nil when webhooks are disabled, or in mock modes without an explicit port claim; the configured port still describes the endpoint a live run would serve.

func (*WebhookService) Capture

func (s *WebhookService) Capture(ctx context.Context, flowID, nodeID string) (WebhookCapture, error)

Capture returns the last request body posted to a sources.webhook node, with the non-blocking feed-shape verdict: a payload missing feed-item fields ingests fine but renders minimally in feeds.

func (*WebhookService) Endpoint

func (s *WebhookService) Endpoint(context.Context) (running bool, port int)

Endpoint reports the listener's live state and the port endpoints are served on.

func (*WebhookService) GeneratePort

func (s *WebhookService) GeneratePort(ctx context.Context) (int, error)

GeneratePort returns a fresh random port from the generation range without persisting it: it is offered as a candidate, and saving is what commits it.

func (*WebhookService) Host

func (s *WebhookService) Host() string

Host reports the actual bound host when running, else the startup host.

func (*WebhookService) SetState

func (s *WebhookService) SetState(_ context.Context, enabled bool, host string, port int) error

SetState persists the enable toggle and port. Neither is applied to the running listener: both are startup-time decisions, and State reports the pending restart.

func (*WebhookService) State

State returns the persisted configuration alongside the listener's state.

type WebhookState

type WebhookState struct {
	Enabled bool
	Host    string
	Port    int
	PortMin int
	PortMax int
	// PortOverridden reports that the env override is in force, in which case
	// Port is the override and editing it has no effect.
	PortOverridden bool
	// Running and BoundPort describe this session's listener. BoundPort is 0
	// when it never bound.
	Running    bool
	BoundHost  string
	BoundPort  int
	StartError string
	// RestartRequired reports that the persisted configuration and the running
	// listener disagree — both toggles only take effect at startup.
	RestartRequired bool
}

WebhookState joins the persisted configuration with this session's running listener, so a caller sees what is configured and what is live in one read.

type WindowForeground

type WindowForeground struct {
	Running bool
	Command string
}

WindowForeground is what a window has in front of it: whether it is running anything other than a prompt, and the name of what that is — empty when there is nothing running, or when the name could not be read.

type WorkspaceEdit

type WorkspaceEdit struct {
	Dir     string
	Name    string
	Command string
	MCPs    []string
	Skills  []string
	// Schedules is the whole list: a write reconciles the manifest to exactly
	// this, so an entry the editor dropped is deleted by the same call.
	Schedules []ScheduleEdit
}

WorkspaceEdit names the manifest fields the in-app editor writes. Anything else the manifest says is untouched — WriteManifest edits the document in place, so comments and keys the editor does not own stay the user's.

type WorkspaceView

type WorkspaceView struct {
	Dir     string   `json:"dir"`
	Name    string   `json:"name"`
	Command string   `json:"command"`
	MCPs    []string `json:"mcps"`
	Skills  []string `json:"skills"`
	Problem string   `json:"problem"`
	// Danger reports that Command carries a known permission bypass. It
	// replaces the posture enum's self-labelling: `full` used to name itself,
	// a free-form command has to be read
	// (ADR the-workspace-command-is-a-template).
	Danger bool `json:"danger"`
	// Notice mirrors SessionView.Notice's MCP explanation, shown on the
	// workspace row itself: an agent whose wiring cannot bound its tool set to
	// what the workspace declares says so before any session is even started
	// (spec §7.2, ADR a-workspace-declares-its-own-authority).
	Notice string `json:"notice"`
	// Schedules rides the workspace view because the editor that writes it is
	// the workspace editor, and the sidebar names the next run.
	Schedules []ScheduleView `json:"schedules"`
}

WorkspaceView is one row of the area's list. Command is on it because a workspace that can actuate the physical world says so where it is opened, not where it was configured (spec §7.2) — and with a free-form command the only honest way to say it is to show the command.

Directories

Path Synopsis
Package actions implements the desktop pipeline's actions.yml schema: the output/action layer a flow's terminal `action` node targets (see cmd/desktop/internal/app/flow's ActionConfig) and the source for the desktop detail pane's action buttons.
Package actions implements the desktop pipeline's actions.yml schema: the output/action layer a flow's terminal `action` node targets (see cmd/desktop/internal/app/flow's ActionConfig) and the source for the desktop detail pane's action buttons.
Package activity is the desktop app's user-facing audit log.
Package activity is the desktop app's user-facing audit log.
Package agentws owns the on-disk agent-workspace root: the directory tree holding mcps.yaml, .shared/, and one directory per workspace (spec §4).
Package agentws owns the on-disk agent-workspace root: the directory tree holding mcps.yaml, .shared/, and one directory per workspace (spec §4).
Package canvas renders canvas documents for the desktop: the html sanitizer the pane and the export run through, and the markdown export.
Package canvas renders canvas documents for the desktop: the html sanitizer the pane and the export run through, and the markdown export.
Package configmigrate upgrades an older on-disk config document to the version the running build expects, forward-only and one step per version.
Package configmigrate upgrades an older on-disk config document to the version the running build expects, forward-only and one step per version.
data
queries
Package queries is the desktop app's dedicated SQLite store: the event log (event_log/consumer_offset), durable inbox substrate (inbox_item/inbox_event), feed membership claims, output commands, activity events and jobs, and per-node run metrics.
Package queries is the desktop app's dedicated SQLite store: the event log (event_log/consumer_offset), durable inbox substrate (inbox_item/inbox_event), feed membership claims, output commands, activity events and jobs, and per-node run metrics.
Package dirwatch runs a debounced callback when matching files in a directory change.
Package dirwatch runs a debounced callback when matching files in a directory change.
Package events is the core's typed publish/subscribe bus.
Package events is the core's typed publish/subscribe bus.
Package flow implements the flows/*.yaml config schema for the desktop pipeline's Node-RED-style graph: a strict decoder, a per-node-type registry, cross-file reference validation, and directory loaders.
Package flow implements the flows/*.yaml config schema for the desktop pipeline's Node-RED-style graph: a strict decoder, a per-node-type registry, cross-file reference validation, and directory loaders.
Package fonts enumerates the font families installed on this machine so the app's chrome and its terminals can be pointed at one of them.
Package fonts enumerates the font families installed on this machine so the app's chrome and its terminals can be pointed at one of them.
Package hiveconf reads the hive config file the `hive` binary shares.
Package hiveconf reads the hive config file the `hive` binary shares.
Package hivewatch observes hive.db state that another process writes.
Package hivewatch observes hive.db state that another process writes.
Package icons holds the curated glyph set feed rows and sidebar entries draw from.
Package icons holds the curated glyph set feed rows and sidebar entries draw from.
Package ingest is the pipeline's producer side: the poll loop that turns configured source connectors into event_log rows, and the resolver that turns the current flow set into the connector instances it drives.
Package ingest is the pipeline's producer side: the poll loop that turns configured source connectors into event_log rows, and the resolver that turns the current flow set into the connector instances it drives.
Package jobs is the desktop app's live action-run lifecycle.
Package jobs is the desktop app's live action-run lifecycle.
Package mcpcatalog is the shipped MCP server catalogue: the vocabulary one entry is declared in (Stability, Transport, Server, Descriptor) and the registry that holds every entry.
Package mcpcatalog is the shipped MCP server catalogue: the vocabulary one entry is declared in (Stability, Transport, Server, Descriptor) and the registry that holds every entry.
Package perf records UI performance spans to a size-capped JSONL file for offline analysis.
Package perf records UI performance spans to a size-capped JSONL file for offline analysis.
Package procstats samples what this install is costing the machine: the desktop process, the processes it parents (a terminal's shell, an agent), and the Go runtime's own view of itself.
Package procstats samples what this install is costing the machine: the desktop process, the processes it parents (a terminal's shell, an agent), and the Go runtime's own view of itself.
Package profileimg stores a profile's (flow's) avatar as a normalized square PNG under the app data dir — one file per flow id.
Package profileimg stores a profile's (flow's) avatar as a normalized square PNG under the app data dir — one file per flow id.
Package prompts owns every paste-ready LLM prompt Hive Desktop offers, and the templates they are composed from.
Package prompts owns every paste-ready LLM prompt Hive Desktop offers, and the templates they are composed from.
Package ptyterm runs ephemeral terminals: this process owns a PTY and the process on the far end of it, with no terminal multiplexer in between.
Package ptyterm runs ephemeral terminals: this process owns a PTY and the process on the far end of it, with no terminal multiplexer in between.
Package report builds the two halves of a bug report, which are deliberately not one artifact.
Package report builds the two halves of a bug report, which are deliberately not one artifact.
Package runtime is the flow engine: it executes one flow over one batch of event-log messages and produces the CommitBatch that batch is worth.
Package runtime is the flow engine: it executes one flow over one batch of event-log messages and produces the CommitBatch that batch is worth.
js
Package js implements the engine's ScriptRuntime port with goja, a pure-Go ECMAScript interpreter.
Package js implements the engine's ScriptRuntime port with goja, a pure-Go ECMAScript interpreter.
Package schedule launches recurring agent chats.
Package schedule launches recurring agent chats.
Package settings resolves the desktop app's typed settings and on-disk locations.
Package settings resolves the desktop app's typed settings and on-disk locations.
Package skills renders Hive Desktop's paste-ready prompts in the Agent Skills format: a SKILL.md with YAML frontmatter (name, description) over the prompt text.
Package skills renders Hive Desktop's paste-ready prompts in the Agent Skills format: a SKILL.md with YAML frontmatter (name, description) over the prompt text.
Package slug is the id rule the flow and action schemas share.
Package slug is the id rule the flow and action schemas share.
Package sourcemark stores a source node's custom feed mark as a normalized square PNG under the app data dir, content-addressed by hash.
Package sourcemark stores a source node's custom feed mark as a normalized square PNG under the app data dir, content-addressed by hash.
Package sources is the source connector registry: the one place every connector type is declared, and the lookups the rest of the app resolves a connector through.
Package sources is the source connector registry: the one place every connector type is declared, and the lookups the rest of the app resolves a connector through.
bindingstore
Package bindingstore persists each connected account's non-secret binding — the host, stack, or project a credential was connected to — keyed by credential ref.
Package bindingstore persists each connected account's non-secret binding — the host, stack, or project a credential was connected to — keyed by credential ref.
canonical
Package canonical is the item contract a connector uses when its payload is the canonical item shape itself (docs/decisions/0008) rather than a provider's own: the top-level `state` vocabulary, the classifier that maps it to lifecycle, and the rewrite an authoritative snapshot mints for an item that left it.
Package canonical is the item contract a connector uses when its payload is the canonical item shape itself (docs/decisions/0008) rather than a provider's own: the top-level `state` vocabulary, the classifier that maps it to lifecycle, and the rewrite an authoritative snapshot mints for an item that left it.
connector
Package connector is the vocabulary a source connector is declared in: the Descriptor that describes one, the Config it parses, and the Instance the app constructs per use.
Package connector is the vocabulary a source connector is declared in: the Descriptor that describes one, the Config it parses, and the Instance the app constructs per use.
exec
Package exec is the command source connector: it runs the user's own command on the poll tick and ingests its stdout as an authoritative snapshot, so a CLI is a first-party source with no external scheduler, no webhook bridge, and no hand-rolled state file.
Package exec is the command source connector: it runs the user's own command on the poll tick and ingests its stdout as an authoritative snapshot, so a CLI is a first-party source with no external scheduler, no webhook bridge, and no hand-rolled state file.
gitea
Package gitea is the Gitea source connector: the config a gitea source node carries, the descriptor declaring what the connector supports, and the instance the producer drains on a tick.
Package gitea is the Gitea source connector: the config a gitea source node carries, the descriptor declaring what the connector supports, and the instance the producer drains on a tick.
gitea/giteaclient
Package giteaclient is the desktop's Gitea/Forgejo REST client: token validation, the issue/PR search, the notification inbox, and the single-issue lookup absence confirmation needs.
Package giteaclient is the desktop's Gitea/Forgejo REST client: token validation, the issue/PR search, the notification inbox, and the single-issue lookup absence confirmation needs.
github
Package github is the GitHub source connector: the config a github source node carries, the descriptor declaring what the connector supports, and the instance the producer drains on a tick.
Package github is the GitHub source connector: the config a github source node carries, the descriptor declaring what the connector supports, and the instance the producer drains on a tick.
github/feed
Package feed is the desktop's GitHub fetch layer: the wire Item type and a cached, coalesced LiveProvider the pipeline producer uses to turn a source into event_log rows.
Package feed is the desktop's GitHub fetch layer: the wire Item type and a cached, coalesced LiveProvider the pipeline producer uses to turn a source into event_log rows.
github/ghclient
Package ghclient is the desktop's own GitHub REST/GraphQL client: in-app authentication (OAuth device flow, PAT validation via User) and the typed API calls the connector needs (batched search, notifications, single-issue hydration).
Package ghclient is the desktop's own GitHub REST/GraphQL client: in-app authentication (OAuth device flow, PAT validation via User) and the typed API calls the connector needs (batched search, notifications, single-issue hydration).
grafana
Package grafana is the Grafana source connector: the metrics and alerts source nodes and the stack auth that connects a stack.
Package grafana is the Grafana source connector: the metrics and alerts source nodes and the stack auth that connects a stack.
grafana/client
Package client is the desktop's Grafana HTTP client: token validation, a PromQL query through the datasource proxy, the firing-alerts list, and the IRM/OnCall alert groups.
Package client is the desktop's Grafana HTTP client: token validation, a PromQL query through the datasource proxy, the firing-alerts list, and the IRM/OnCall alert groups.
itemtext
Package itemtext derives the session text an inbox item suggests: the branch name a session on it would use, and the default prompt the launch dialog opens with.
Package itemtext derives the session text an inbox item suggests: the branch name a session on it would use, and the default prompt the launch dialog opens with.
posthog
Package posthog is the PostHog source connector: the error-tracking and insight-alert source nodes and the project auth that connects a project.
Package posthog is the PostHog source connector: the error-tracking and insight-alert source nodes and the project auth that connects a project.
posthog/client
Package client is the desktop's PostHog HTTP client: project listing (which doubles as token validation), the error-tracking issue query, and the insight-alert list.
Package client is the desktop's PostHog HTTP client: project listing (which doubles as token validation), the error-tracking issue query, and the insight-alert list.
rss
Package rss is the feed source connector: it fetches one RSS, Atom, or JSON Feed URL on the poll tick and ingests its entries as items, so a blog, a release feed, or a status page is a first-party source with no bridge in between.
Package rss is the feed source connector: it fetches one RSS, Atom, or JSON Feed URL on the poll tick and ingests its entries as items, so a blog, a release feed, or a status page is a first-party source with no bridge in between.
sourcehttp
Package sourcehttp is the HTTP toolkit a pull connector's API client is built over: the failure taxonomy, status and rate-limit mapping, conditional requests, and a logging transport.
Package sourcehttp is the HTTP toolkit a pull connector's API client is built over: the failure taxonomy, status and rate-limit mapping, conditional requests, and a logging transport.
webhook
Package webhook is the webhook source connector: the config a webhook source node carries, the descriptor declaring what the connector supports, and the local HTTP listener deliveries arrive on.
Package webhook is the webhook source connector: the config a webhook source node carries, the descriptor declaring what the connector supports, and the local HTTP listener deliveries arrive on.
Package telemetry configures the OpenTelemetry and Pyroscope SDKs, registers the OTel providers globally, and owns their shutdown (ADR continuous-profiles-are-pushed-directly-with-pyroscope).
Package telemetry configures the OpenTelemetry and Pyroscope SDKs, registers the OTel providers globally, and owns their shutdown (ADR continuous-profiles-are-pushed-directly-with-pyroscope).

Jump to

Keyboard shortcuts

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