Documentation
¶
Overview ¶
Package hearth provides The Forge's TUI dashboard using Bubbletea.
The TUI has three columns:
- Queue / Ready to Merge / Needs Attention (left column, stacked): Pending, mergeable, and stuck beads
- Workers (center column): Active Smith processes
- Live Activity / Events (right column, stacked): Streaming log + event log
Tab switches focus between panels, j/k scrolls the focused panel, q quits the app.
Index ¶
- Constants
- Variables
- func FetchAll(ds *DataSource, logCache *LogTailerCache) tea.Cmd
- func FetchAnvilHealth(ds *DataSource) tea.Cmd
- func FetchCrucibles() tea.Cmd
- func FetchDaemonHealth() tea.Cmd
- func FetchEvents(db *state.DB, limit int) tea.Cmd
- func FetchIngotCounts(db *state.DB) tea.Cmd
- func FetchNeedsAttention(ds *DataSource) tea.Cmd
- func FetchOpenPRs(db *state.DB) tea.Cmd
- func FetchPendingOrphans(db *state.DB) tea.Cmd
- func FetchQueue(db *state.DB) tea.Cmd
- func FetchReadyToMerge(ds DataSource) tea.Cmd
- func FetchUsage(ds *DataSource) tea.Cmd
- func FetchWorkers(db *state.DB, logCache *LogTailerCache) tea.Cmd
- func FormatCost(usd float64) string
- func FormatTokens(n int) string
- func SpinnerTick() tea.Cmd
- func Tick() tea.Cmd
- type ActionMenuChoice
- type AnvilHealth
- type AttentionReason
- type CrucibleActionMenuChoice
- type CrucibleActionResultMsg
- type CrucibleItem
- type DataSource
- type EventItem
- type KillWorkerMsg
- type LogTailerCache
- type MergeMenuChoice
- type MergeResultMsg
- type Model
- type NeedsAttentionErrorMsg
- type NeedsAttentionItem
- type NotesResultMsg
- type OpenPRsErrorMsg
- type OrphanDialogChoice
- type OrphanResolveResultMsg
- type PRActionMenuChoice
- type PRActionResultMsg
- type PRItem
- type Panel
- type PendingOrphanItem
- type ProviderUsage
- type QueueActionMenuChoice
- type QueueActionResultMsg
- type QueueErrorMsg
- type QueueItem
- type ReadyToMergeErrorMsg
- type ReadyToMergeItem
- type SpinnerTickMsg
- type TickMsg
- type UpdateAnvilHealthMsg
- type UpdateCruciblesMsg
- type UpdateDaemonHealthMsg
- type UpdateEventsMsg
- type UpdateIngotCountsMsg
- type UpdateNeedsAttentionMsg
- type UpdateOpenPRsMsg
- type UpdatePendingOrphansMsg
- type UpdateQueueMsg
- type UpdateReadyToMergeMsg
- type UpdateUsageMsg
- type UpdateWorkersMsg
- type UsageData
- type WorkerItem
Constants ¶
const EventFetchLimit = 100
EventFetchLimit is the maximum number of events retrieved for the Events panel.
const SpinnerInterval = 100 * time.Millisecond
SpinnerInterval is how often the spinner animation advances.
const TickInterval = 2 * time.Second
TickInterval is how often the TUI refreshes data.
Variables ¶
var SpinnerFrames = []string{"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"}
SpinnerFrames are the animation frames for active workers (braille dots pattern).
Functions ¶
func FetchAll ¶
func FetchAll(ds *DataSource, logCache *LogTailerCache) tea.Cmd
FetchAll returns a batch command that refreshes all panels. Daemon health is NOT included here; it is fetched on a slower cadence controlled by healthTickDivisor in the TickMsg handler.
func FetchAnvilHealth ¶ added in v0.5.0
func FetchAnvilHealth(ds *DataSource) tea.Cmd
FetchAnvilHealth queries the last poll result per anvil and returns health status items for the Queue panel headers.
func FetchCrucibles ¶
FetchCrucibles reads active Crucible statuses from the daemon via IPC.
func FetchDaemonHealth ¶ added in v0.2.0
FetchDaemonHealth probes the daemon via IPC and returns connectivity status.
func FetchEvents ¶
FetchEvents reads recent events from the state DB. Poll events (poll, poll_error) are excluded because anvil health is now displayed inline in the Queue panel headers. The filter is applied at the SQL level via RecentEventsExcluding so the LIMIT returns the expected count.
func FetchIngotCounts ¶ added in v0.9.0
FetchIngotCounts queries the state DB for ingot counts grouped by status. It runs a single GROUP BY status aggregation query directly against the DB.
func FetchNeedsAttention ¶
func FetchNeedsAttention(ds *DataSource) tea.Cmd
FetchNeedsAttention reads beads that need human intervention from the state DB. This includes both retry-exhausted beads and PRs that have exhausted their CI-fix, review-fix, or rebase attempt limits. Thresholds are taken from ds so the TUI stays in sync with the daemon's configured limits.
func FetchOpenPRs ¶ added in v0.5.0
FetchOpenPRs reads all non-terminal PRs with status detail from the state DB.
func FetchPendingOrphans ¶ added in v0.4.0
FetchPendingOrphans reads orphaned beads awaiting user decision from the state DB.
func FetchQueue ¶
FetchQueue reads the daemon's cached queue from the state DB. The daemon writes queue data on each poll cycle, so the Hearth TUI always reflects the daemon's view without running its own bd ready calls.
func FetchReadyToMerge ¶
func FetchReadyToMerge(ds DataSource) tea.Cmd
FetchReadyToMerge reads PRs that are ready to merge from the state DB.
func FetchUsage ¶ added in v0.2.0
func FetchUsage(ds *DataSource) tea.Cmd
FetchUsage reads today's per-provider costs and copilot premium requests.
func FetchWorkers ¶
func FetchWorkers(db *state.DB, logCache *LogTailerCache) tea.Cmd
FetchWorkers reads active workers from the state DB and enriches with log activity via incremental log tailing. When logCache is nil, falls back to full-file reading (for tests or one-shot use).
func FormatTokens ¶ added in v0.2.0
FormatTokens formats a token count for compact display. Returns "1.2M" for millions, "340k" for thousands, or the raw number for small values.
func SpinnerTick ¶ added in v0.3.0
SpinnerTick returns a Bubbletea command that sends a SpinnerTickMsg after SpinnerInterval.
Types ¶
type ActionMenuChoice ¶
type ActionMenuChoice int
ActionMenuChoice represents an action the user can take on a Needs Attention bead.
const ( ActionRetry ActionMenuChoice = iota ActionDismiss ActionViewLogs ActionWardenRerun ActionApproveAsIs ActionForceSmith )
type AnvilHealth ¶ added in v0.5.0
type AnvilHealth struct {
Anvil string
OK bool // true = last poll succeeded
Message string // e.g. "5 ready" or error text
Timestamp string // "15:04:05" format
Age string // e.g. "2m", "1h"
}
AnvilHealth holds per-anvil poll health status for the Queue panel.
type AttentionReason ¶
type AttentionReason int
AttentionReason categorizes why a bead needs human attention.
const ( AttentionUnknown AttentionReason = iota AttentionDispatchExhausted // Circuit breaker tripped after repeated dispatch failures AttentionCIFixExhausted // CI fix attempts exhausted AttentionReviewFixExhausted // Review fix attempts exhausted AttentionRebaseExhausted // Rebase attempts exhausted AttentionClarification // Bead flagged as needing clarification AttentionStalled // Worker stalled (no log activity) )
type CrucibleActionMenuChoice ¶ added in v0.6.0
type CrucibleActionMenuChoice int
CrucibleActionMenuChoice represents an action the user can take on a paused Crucible.
const ( CrucibleActionResume CrucibleActionMenuChoice = iota // Resume — retry parent to re-enter crucible loop CrucibleActionStop // Stop — close the parent bead )
type CrucibleActionResultMsg ¶ added in v0.6.0
type CrucibleActionResultMsg struct {
ParentID string
Action string // "resume" or "stop"
Err error
}
CrucibleActionResultMsg is delivered asynchronously when a crucible action completes.
type CrucibleItem ¶
type CrucibleItem struct {
ParentID string
ParentTitle string
Anvil string
Branch string
Phase string // "started", "dispatching", "waiting", "final_pr", "complete", "paused"
TotalChildren int
CompletedChildren int
CurrentChild string
StartedAt string
}
CrucibleItem represents an active Crucible in the TUI.
type DataSource ¶
type DataSource struct {
DB *state.DB
// Exhaustion thresholds from config. Zero values fall back to state package defaults.
MaxCIFixAttempts int
MaxReviewFixAttempts int
MaxRebaseAttempts int
// AnvilNames lists all registered anvil names (sorted) so the Queue panel
// can show empty anvils with a (0) count.
AnvilNames []string
// Cost limits from config for the Usage panel display.
DailyCostLimit float64
CopilotDailyRequestLimit int
// AutoMergeAnvils returns the set of anvil names that have auto_merge
// enabled. The map is built once at Hearth startup from the loaded config;
// reflecting config changes requires restarting Hearth.
// When nil, no PRs are tagged [auto].
AutoMergeAnvils func() map[string]bool
}
DataSource holds the dependencies needed to feed the TUI panels.
type KillWorkerMsg ¶
KillWorkerMsg requests killing the selected worker by PID.
type LogTailerCache ¶ added in v0.8.0
type LogTailerCache struct {
// contains filtered or unexported fields
}
LogTailerCache manages incremental log file reading for all active workers. Instead of re-reading entire log files on each tick, each tailer tracks its read offset and only parses newly appended lines.
func NewLogTailerCache ¶ added in v0.8.0
func NewLogTailerCache() *LogTailerCache
NewLogTailerCache creates an empty cache.
func (*LogTailerCache) Prune ¶ added in v0.8.0
func (c *LogTailerCache) Prune(activePaths map[string]bool)
Prune removes tailers for log paths not in the active set.
func (*LogTailerCache) ReadIncremental ¶ added in v0.8.0
func (c *LogTailerCache) ReadIncremental(logPath string, maxEntries int) (entries []string, lastRaw string)
ReadIncremental reads only newly appended bytes from logPath, parses them into activity entries, and returns the last maxEntries lines plus the last raw JSON line. It is safe for concurrent use (the cache is mutex-protected).
type MergeMenuChoice ¶
type MergeMenuChoice int
MergeMenuChoice represents an action on a ready-to-merge PR.
const (
MergeActionMerge MergeMenuChoice = iota
)
type MergeResultMsg ¶
MergeResultMsg is delivered asynchronously when a merge IPC call completes.
type Model ¶
type Model struct {
// Callback for killing a worker (set by the caller)
OnKill func(workerID string, pid int)
// Callback for stopping a bead entirely: kills worker, sets clarification,
// releases to open (set by the caller).
OnStopBead func(beadID, anvil string) error
// Callbacks for Needs Attention actions (set by the caller)
OnRetryBead func(beadID, anvil string, prID int) error
OnDismissBead func(beadID, anvil string, prID int) error
OnViewLogs func(beadID string) (logPath string, lines []string)
OnWardenRerun func(beadID, anvil string) error
OnApproveAsIs func(beadID, anvil string) error
OnForceSmith func(beadID, anvil, userNote string) error
// Callback for tagging a bead (set by the caller).
// Called with (beadID, anvil) when user presses 'l' on an unlabeled bead.
OnTagBead func(beadID, anvil string) error
// Callback for closing a bead (set by the caller).
OnCloseBead func(beadID, anvil string) error
// Callback for force-running a bead independently (set by the caller).
// Dispatches via bd show, bypassing bd ready and crucible/parent checks.
OnForceRunBead func(beadID, anvil string) error
// Callback for merging a PR (set by the caller).
OnMergePR func(prID, prNumber int, anvil string) error
// Callback for PR panel actions (set by the caller).
// Called with (prID, prNumber, anvil, beadID, branch, action).
OnPRAction func(prID, prNumber int, anvil, beadID, branch, action string) error
// Callback for triggering PR reconciliation with GitHub (set by the caller).
OnReconcilePRs func() error
// Callback for resolving an orphaned bead (set by the caller).
// Called with (beadID, anvil, action) where action is "recover", "close", or "discard".
OnResolveOrphan func(beadID, anvil, action string) error
// Callback for crucible actions (resume/stop) on a paused crucible (set by caller).
// Called with (parentID, anvil, action) where action is "resume" or "stop".
OnCrucibleAction func(parentID, anvil, action string) error
// Callback for appending notes to a bead via bd update --append-notes (set by caller).
// Called with (beadID, anvil, notes).
OnAppendNotes func(beadID, anvil, notes string) error
// contains filtered or unexported fields
}
Model is the Bubbletea model for the Hearth TUI.
func NewModel ¶
func NewModel(ds *DataSource) Model
NewModel creates a new Hearth TUI model. Pass nil for DataSource to run in display-only mode (no polling).
func (*Model) SetMouseEnabled ¶ added in v0.4.0
SetMouseEnabled records whether mouse reporting was initially enabled so the toggle keybind ('m') can flip the state at runtime.
type NeedsAttentionErrorMsg ¶
type NeedsAttentionErrorMsg struct{ Err error }
NeedsAttentionErrorMsg signals that reading the needs-attention beads failed.
type NeedsAttentionItem ¶
type NeedsAttentionItem struct {
BeadID string
Title string
Description string
Anvil string
Reason string
ReasonCategory AttentionReason
PRID int // Non-zero when item originates from an exhausted PR
PRNumber int
LastWardenReject string // Most recent warden_reject message, if any
}
NeedsAttentionItem represents a bead requiring human attention.
type NotesResultMsg ¶ added in v0.4.0
NotesResultMsg is delivered asynchronously when an append-notes action completes.
type OpenPRsErrorMsg ¶ added in v0.5.0
type OpenPRsErrorMsg struct{ Err error }
OpenPRsErrorMsg signals that reading open PRs failed.
type OrphanDialogChoice ¶ added in v0.4.0
type OrphanDialogChoice int
OrphanDialogChoice represents an action for an orphaned bead.
const ( OrphanActionRecover OrphanDialogChoice = iota OrphanActionClose OrphanActionDiscard )
type OrphanResolveResultMsg ¶ added in v0.4.0
OrphanResolveResultMsg is delivered asynchronously when an orphan resolve action completes.
type PRActionMenuChoice ¶ added in v0.5.0
type PRActionMenuChoice int
PRActionMenuChoice represents an action the user can take on an open PR.
const ( PRActionOpenBrowser PRActionMenuChoice = iota // Open in GitHub PRActionMerge // Merge the PR PRActionFixCI // Trigger cifix worker PRActionFixComments // Trigger reviewfix worker PRActionResolveConflicts // Trigger rebase worker PRActionClosePR // Close the PR PRActionAssignBellows // Assign bellows to monitor & autofix )
type PRActionResultMsg ¶ added in v0.5.0
PRActionResultMsg is delivered asynchronously when a PR action IPC call completes.
type PRItem ¶ added in v0.5.0
type PRItem struct {
PRID int
PRNumber int
Anvil string
BeadID string
Branch string
Status string // "open", "approved", "needs_fix"
Title string
CIPassing bool
IsConflicting bool
HasUnresolvedThreads bool
HasPendingReviews bool
HasApproval bool
CIFixCount int
ReviewFixCount int
RebaseCount int
IsExternal bool // true for PRs discovered via GitHub reconciliation
BellowsManaged bool // true when bellows runs lifecycle workers for this PR
}
PRItem represents an open PR in the PR panel overlay.
type PendingOrphanItem ¶ added in v0.4.0
PendingOrphanItem represents an orphaned bead awaiting user decision in Hearth.
type ProviderUsage ¶ added in v0.2.0
ProviderUsage holds cost/token data for a single provider.
type QueueActionMenuChoice ¶
type QueueActionMenuChoice int
QueueActionMenuChoice represents an action the user can take on an unlabeled queue bead.
const ( QueueActionLabel QueueActionMenuChoice = iota QueueActionForceRun // Run independently — bypass bd ready, skip crucible QueueActionClose QueueActionStop )
type QueueActionResultMsg ¶
type QueueActionResultMsg struct {
BeadID string
Action string // "tag", "force_run", "close", or "stop"
Err error
}
QueueActionResultMsg is delivered asynchronously when a queue action completes.
type QueueErrorMsg ¶
type QueueErrorMsg struct{ Err error }
QueueErrorMsg signals that reading the queue cache failed. The model preserves the previous queue data so the UI doesn't flip to "No pending beads" on a transient DB error.
type QueueItem ¶
type QueueItem struct {
BeadID string
Title string
Description string
Anvil string
Priority int
Status string
Section string // "ready", "unlabeled", "in_progress"
Assignee string
}
QueueItem represents a bead in the queue panel.
type ReadyToMergeErrorMsg ¶
type ReadyToMergeErrorMsg struct{ Err error }
ReadyToMergeErrorMsg signals that reading the ready-to-merge PRs failed.
type ReadyToMergeItem ¶
type ReadyToMergeItem struct {
PRID int
PRNumber int
BeadID string
Anvil string
Branch string
Title string
AutoMerge bool // true when the anvil has auto_merge enabled
}
ReadyToMergeItem represents a PR ready to merge.
type SpinnerTickMsg ¶ added in v0.3.0
SpinnerTickMsg advances the spinner animation frame.
type UpdateAnvilHealthMsg ¶ added in v0.5.0
type UpdateAnvilHealthMsg struct{ Items []AnvilHealth }
UpdateAnvilHealthMsg delivers per-anvil health data.
type UpdateCruciblesMsg ¶
type UpdateCruciblesMsg struct{ Items []CrucibleItem }
UpdateCruciblesMsg updates the crucibles panel.
type UpdateDaemonHealthMsg ¶ added in v0.2.0
type UpdateDaemonHealthMsg struct {
Connected bool
Workers int
QueueSize int
LastPoll string
Uptime string
}
UpdateDaemonHealthMsg carries the result of a daemon health check to the TUI.
type UpdateEventsMsg ¶
type UpdateEventsMsg struct{ Items []EventItem }
UpdateEventsMsg updates the event log panel.
type UpdateIngotCountsMsg ¶ added in v0.9.0
UpdateIngotCountsMsg carries aggregated ingot status counts to the TUI.
type UpdateNeedsAttentionMsg ¶
type UpdateNeedsAttentionMsg struct{ Items []NeedsAttentionItem }
UpdateNeedsAttentionMsg updates the needs attention panel.
type UpdateOpenPRsMsg ¶ added in v0.5.0
type UpdateOpenPRsMsg struct {
Items []PRItem
}
UpdateOpenPRsMsg carries refreshed open PR data to the TUI.
type UpdatePendingOrphansMsg ¶ added in v0.4.0
type UpdatePendingOrphansMsg struct {
Items []PendingOrphanItem
}
UpdatePendingOrphansMsg carries the list of pending orphans to the TUI.
type UpdateQueueMsg ¶
type UpdateQueueMsg struct{ Items []QueueItem }
UpdateQueueMsg updates the queue panel.
type UpdateReadyToMergeMsg ¶
type UpdateReadyToMergeMsg struct{ Items []ReadyToMergeItem }
UpdateReadyToMergeMsg updates the ready to merge panel.
type UpdateUsageMsg ¶ added in v0.2.0
type UpdateUsageMsg struct {
Data UsageData
}
UpdateUsageMsg carries refreshed usage data to the TUI.
type UpdateWorkersMsg ¶
type UpdateWorkersMsg struct{ Items []WorkerItem }
UpdateWorkersMsg updates the workers panel.
type UsageData ¶ added in v0.2.0
type UsageData struct {
Providers []ProviderUsage
TotalCost float64
CostLimit float64 // 0 = no limit
CopilotUsed float64
CopilotLimit int // 0 = no limit
}
UsageData holds the aggregated usage information for the Usage panel.
type WorkerItem ¶
type WorkerItem struct {
ID string
BeadID string
Title string // Bead title for display
Anvil string
Status string
Duration string
CostUSD float64
Type string // "smith", "warden", "temper", "quench", "burnish", "rebase"
PRNumber int // PR number for bellows-triggered workers
LastLog string // Last line from the worker log
PID int // Process ID for kill
LogPath string // Path to the worker's log file
ActivityLines []string // Recent parsed activity from the log (tool calls, thinking, text)
}
WorkerItem represents a worker in the workers panel.