db

package
v0.3.31 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package db provides SQLite database operations.

Index

Constants

View Source
const (
	ModelFable  = "fable"
	ModelOpus   = "opus"
	ModelSonnet = "sonnet"
	ModelHaiku  = "haiku"
	// ModelOpusPlan is Claude Code's planning alias (Opus to plan, Sonnet to
	// execute). Accepted as an override but kept out of the UI picker.
	ModelOpusPlan = "opusplan"
)

Per-task model overrides pick which model an executor's CLI runs (its `--model` flag). An empty value means "no override": the task uses the agent's own default, leaving the user's global setting untouched.

Overrides are validated before they are stored because a bad one is invisible: the task launches, the agent CLI rejects the flag inside tmux, and the card just sits there looking busy. An early default baked the executor slug "claude" into every row (see the clear-model repair in sqlite.go) — exactly that failure.

View Source
const (
	RoutineRunStatusRunning = "running"
	RoutineRunStatusOK      = "ok"
	RoutineRunStatusFailed  = "failed"
)

Routine run statuses.

View Source
const (
	// OutcomeApplied means the transition happened. Only these are folded.
	OutcomeApplied = "applied"
	// OutcomeRefused means a gate rejected it. Recorded so an attempt to bury a
	// task leaves a trace instead of a silent no-op.
	OutcomeRefused = "refused"
)

Transition outcomes recorded in the log.

View Source
const (
	// GateEvidenceRequired: a terminal transition arrived with nothing observed.
	GateEvidenceRequired = "evidence-required"
	// GateNeverStarted: automation tried to complete a task that never ran.
	GateNeverStarted = "never-started"
	// GateOpenPR: a done-write for a task whose pull request is still open.
	GateOpenPR = "open-pr"
	// GateHumanOnly: automation tried to finish or archive a task. Only a
	// person does that; the one exception is a workflow step with dependents.
	GateHumanOnly = "human-only"
	// GateUnknownStatus: the target status is not a status.
	GateUnknownStatus = "unknown-status"
	// GateMissingActor / GateMissingReason: the write did not say who or why.
	GateMissingActor  = "missing-actor"
	GateMissingReason = "missing-reason"
)

Gate names. A refusal always carries one, so the reason a write bounced is a value you can grep for and not prose you have to parse.

View Source
const (
	StatusBacklog    = "backlog"    // Created but not yet started
	StatusQueued     = "queued"     // Waiting to be processed
	StatusProcessing = "processing" // Currently being executed
	StatusBlocked    = "blocked"    // Needs input/clarification
	StatusDone       = "done"       // Completed
	StatusArchived   = "archived"   // Archived (hidden from view)
)

Task statuses

View Source
const (
	// PermissionModeDefault prompts for every permission (the historical default).
	// Maps to Claude's --permission-mode default.
	PermissionModeDefault = "default"
	// PermissionModeAcceptEdits auto-accepts file edits but still prompts for
	// risky actions (shell, network, etc.). Maps to Claude's
	// --permission-mode acceptEdits.
	PermissionModeAcceptEdits = "accept-edits"
	// PermissionModeAuto is Claude Code's auto mode (--permission-mode auto): an
	// AI classifier auto-approves a broad set of safe actions (edits and safe
	// commands) while still hard-denying dangerous ones. More autonomous than
	// accept-edits, but far safer than fully bypassing permissions.
	PermissionModeAuto = "auto"
	// PermissionModeDangerous bypasses all permission checks
	// (Claude's --dangerously-skip-permissions).
	PermissionModeDangerous = "dangerous"
)

Permission modes control how the underlying agent handles permission prompts. They map one-to-one onto Claude Code's --permission-mode choices (plus the --dangerously-skip-permissions shortcut). There are four sets, from most to least gated: default → accept-edits → auto → dangerous.

HISTORY: TaskYou originally used the value "auto" for what is really Claude's acceptEdits mode — that predated Claude Code shipping its own "auto mode". The value "auto" now means Claude Code's actual auto mode (--permission-mode auto), and the old acceptEdits set has the explicit value "accept-edits". A one-time DB migration rewrites pre-existing "auto" rows (which meant acceptEdits) to "accept-edits"; see migrate() in sqlite.go.

View Source
const (
	TypeCode     = "code"
	TypeWriting  = "writing"
	TypeThinking = "thinking"
)

Task types (default values, actual types are stored in task_types table)

View Source
const (
	ExecutorClaude   = "claude"   // Claude Code CLI (default)
	ExecutorCodex    = "codex"    // OpenAI Codex CLI
	ExecutorGemini   = "gemini"   // Google Gemini CLI
	ExecutorGrok     = "grok"     // Grok CLI (https://x.ai/cli)
	ExecutorCursor   = "cursor"   // Cursor CLI (https://cursor.com/docs/cli)
	ExecutorOpenClaw = "openclaw" // OpenClaw AI assistant (https://openclaw.ai)
	ExecutorOpenCode = "opencode" // OpenCode AI assistant (https://opencode.ai)
	ExecutorPi       = "pi"       // Pi coding agent (https://github.com/mariozechner/pi-coding-agent)
)

Task executors

View Source
const (
	EffortLow    = "low"
	EffortMedium = "medium"
	EffortHigh   = "high"
	EffortXHigh  = "xhigh"
	EffortMax    = "max"
)

Effort levels are per-task overrides for Claude's reasoning effort (claude --effort). An empty value means "no override" — the task uses Claude's global default, leaving the user's global setting untouched.

View Source
const (
	PortRangeStart = 3100 // First port in the allocation range
	PortRangeEnd   = 4099 // Last port in the allocation range (1000 ports total)
)

Port allocation constants

View Source
const DefaultBusyTimeout = 5 * time.Second

DefaultBusyTimeout is how long a normal connection waits for a locked database before giving up. Long enough to ride out the daemon's writes.

View Source
const MaxSavedViewName = 40

MaxSavedViewName bounds a view name so it stays renderable in the TUI picker and in `ty views list`.

View Source
const SchemaVersion = 3

SchemaVersion is the migration level this build brings a database up to.

It is a hand-maintained counter, bumped by one every time a migration is added to migrate() below — there is no automatic derivation, because the migrations are idempotent statements rather than numbered files and nothing in the list can be counted reliably (ALTER TABLEs are allowed to fail, and remoteMigrations is appended from another file).

Two things read it. `ty doctor` compares the stamp in a database against this constant to tell "current" from "last touched by an older ty". And handshake.Protocol must be bumped whenever a schema change means a daemon and a client of different builds would disagree about a row — see internal/handshake.

View Source
const SchemaVersionKey = "schema_version"

SchemaVersionKey is where SchemaVersion is stamped in the settings table.

View Source
const SessionEndedLogPrefix = "Agent session ended"

SessionEndedLogPrefix starts the log line an agent's own "I am exiting" hook writes (Claude's SessionEnd). It is the one exit signal that is not an inference: a missing tmux window can equally mean the pane was moved into a UI session, or that the window has not come up yet.

Variables

View Source
var DefaultProjectColors = []string{
	"#C678DD",
	"#61AFEF",
	"#56B6C2",
	"#98C379",
	"#E5C07B",
	"#E06C75",
	"#D19A66",
	"#ABB2BF",
}

DefaultProjectColors is a palette of distinct colors for projects. These are assigned to projects that don't have a color set.

View Source
var ErrProjectNotFound = fmt.Errorf("project not found")

ErrProjectNotFound is returned when a task is created with a non-existent project.

View Source
var ErrReplyTimeout = errors.New("timed out waiting for the agent to reply")

ErrReplyTimeout is returned by WaitForAgentReply when no new turn completed inside the timeout. It says nothing about the agent's health: a long task is indistinguishable here from a dead one.

View Source
var NoEvidence = Evidence{}

NoEvidence is the explicit "nothing observed" value. It is fine for ordinary transitions (queueing, starting, parking) and is refused for terminal ones.

PermissionModeCycle is the order the UI cycles permission modes, from most to least gated. Cycling keeps the four modes reachable on a running task; each step relaunches the live session so it matches the stored mode.

Functions

func DefaultExecutor

func DefaultExecutor() string

DefaultExecutor returns the default executor if none is specified.

func DefaultPath

func DefaultPath() string

DefaultPath returns the default database path.

func EffortLevels added in v0.2.40

func EffortLevels() []string

EffortLevels returns the valid per-task effort override values, in ascending order.

func ExecutorSupportsModel added in v0.3.26

func ExecutorSupportsModel(executor string) bool

ExecutorSupportsModel reports whether the executor's CLI takes a --model flag. An empty executor means the default (claude).

func ExpandHomePath added in v0.3.22

func ExpandHomePath(path string) string

ExpandHomePath turns a leading "~" into the user's home directory.

A project path reaches the DB from several places — the settings form, the project-detect flow, `ty project add`, a hand-edited row — and some of them store the shell's own shorthand, "~/Projects/foo". Nothing downstream runs through a shell: the executor and the pipeline hand these paths straight to exec.Command("git", "-C", dir, ...), where a literal "~" is just a directory name that does not exist. The failure is remote from its cause — a pipeline aborting with

fatal: cannot change to '~/Projects/rails/offerlab': No such file or directory

and a GetProjectByPath that silently never matches, so project detection and project-local workflow dirs quietly do nothing.

Callers used to be expected to remember config.GetProjectDir; the ones that read Project.Path directly (three of them, at the time of writing) did not. Normalizing on both write and read removes the chance to forget.

A "~user/..." form is left alone: resolving another user's home is not something we can do reliably, and it has never been a path we support.

func FoldStatus added in v0.3.31

func FoldStatus(events []StatusEvent) string

FoldStatus projects a task's status from its event log: the target of the last APPLIED transition. Refused attempts are in the log for the audit trail and are deliberately not folded — a refusal changed nothing.

Events must be in append order (ascending id), which is what GetStatusEvents returns.

func FoldStatusAt added in v0.3.31

func FoldStatusAt(events []StatusEvent, throughID int64) string

FoldStatusAt projects the status as of event throughID — the same fold, rewound. This is what makes the log a source of truth rather than a changelog: any past state can be reproduced from it.

func GlobalDefaultPermissionMode added in v0.2.40

func GlobalDefaultPermissionMode() string

GlobalDefaultPermissionMode returns the fallback permission mode used when a project has no explicit default. It can be overridden with the TASKYOU_DEFAULT_PERMISSION_MODE environment variable. Defaults to "auto" (Claude Code's auto mode) so tasks start maximally unblocked while the classifier still gates dangerous actions; set the env var to "accept-edits" or "default" to dial back autonomy.

func IsInProgress

func IsInProgress(status string) bool

IsInProgress returns true if the task is actively being worked on.

func IsKnownExecutor added in v0.3.24

func IsKnownExecutor(name string) bool

IsKnownExecutor reports whether name is a built-in executor slug.

func IsRefused added in v0.3.31

func IsRefused(err error) bool

IsRefused reports whether err is a gate refusal (as opposed to an I/O error).

func IsValidEffortLevel added in v0.2.40

func IsValidEffortLevel(s string) bool

IsValidEffortLevel reports whether s is a valid effort level. The empty string is valid and means "use the global/Claude default" (no per-task override).

func IsValidModel added in v0.3.14

func IsValidModel(s string) bool

IsValidModel reports whether s is an acceptable per-task model override for *some* executor. The empty string is valid and means "use the agent default". Prefer ValidateModel when the executor is known; this looser form exists for callers holding a remembered value with no executor in hand (the new-task form's per-project default).

func KnownExecutors added in v0.3.24

func KnownExecutors() []string

KnownExecutors returns the built-in executor slugs in display order.

func ModelBackendIsCustom added in v0.3.26

func ModelBackendIsCustom(configDir string, env map[string]string) bool

ModelBackendIsCustom reports whether a Claude run is pointed at something other than Anthropic's API — a CLAUDE_CONFIG_DIR override or an ANTHROPIC_BASE_URL env override (the two ways ty routes a task through a proxy such as ollama). Model names are the proxy's there, so overrides must not be validated against Anthropic's.

func ModelCapableExecutors added in v0.3.26

func ModelCapableExecutors() []string

ModelCapableExecutors returns the executors that accept a model override, in KnownExecutors display order.

func ModelOptions added in v0.3.14

func ModelOptions() []string

ModelOptions returns the per-task model override aliases offered in the UI picker. It is a curated shortlist, not the set ValidateModel accepts: full model IDs and opusplan are valid overrides but not picker entries.

func ModelsForExecutor added in v0.3.26

func ModelsForExecutor(executor string) []string

ModelsForExecutor returns the model names ty knows about for an executor, in display order — used for `ty create --model` shell completion and error messages. It is not exhaustive: any ID carrying the executor's vendor prefix is also accepted. Nil when the executor has no --model flag.

func NextPermissionMode added in v0.3.2

func NextPermissionMode(mode string) string

NextPermissionMode returns the next mode after the given one in PermissionModeCycle, wrapping around. Unknown input starts the cycle at accept-edits (one past default), so "advance from wherever you are" is sane.

func NormalizePermissionMode added in v0.2.40

func NormalizePermissionMode(mode string) string

NormalizePermissionMode coerces a raw value into a known permission mode. "prompt" and "" are treated as default; Claude's own "acceptEdits" spelling (and "accept_edits") normalizes to PermissionModeAcceptEdits. Matching is case- and whitespace-insensitive. Unknown values return "".

func NormalizeViewName added in v0.3.31

func NormalizeViewName(name string) string

NormalizeViewName trims a view name and folds internal whitespace, so " In Progress " and "In Progress" are the same view rather than two rows that look identical in the picker.

func PermissionModeLabel added in v0.3.2

func PermissionModeLabel(mode string) string

PermissionModeLabel returns a short human-facing label for a permission mode.

func RefusalGate added in v0.3.31

func RefusalGate(err error) string

RefusalGate returns the gate that refused err, or "".

func TaskSettingKey added in v0.3.31

func TaskSettingKey(base string, taskID int64) string

TaskSettingKey namespaces a setting to a single task. Per-task preferences live in the settings table under "<base>:<taskID>", beside the global default stored under "<base>" alone.

func ValidateModel added in v0.3.26

func ValidateModel(executor, model string) error

ValidateModel reports whether model is a model the executor's CLI would actually accept. The empty string is always valid and means "no override".

A model is accepted when it is one of the executor's aliases (optionally with a "[1m]" variant suffix) or a well-formed ID carrying the executor's vendor prefix — "claude-opus-5" and "grok-4-fast" pass without ty having to track every release. Everything else is rejected, which catches the two mistakes that actually happen: a typo ("opuss") and a model belonging to some other vendor ("gpt-5", or the "claude" executor slug).

Callers must skip this check when the agent is routed at a non-stock backend — a CLAUDE_CONFIG_DIR override or ANTHROPIC_BASE_URL pointing at a proxy like ollama — because the model names are then the proxy's (e.g. "glm-5.2:cloud") and ty has no way to know them. See ModelBackendIsCustom.

func ValidateViewName added in v0.3.31

func ValidateViewName(name string) error

ValidateViewName reports why a view name is unusable, or nil when it is fine.

Types

type Actor added in v0.3.31

type Actor string

Actor names what made a status change. It is not decoration: "the sweep did it" versus "a human did it" is the difference between a bug and a decision, and after the fact the log is the only place that distinction survives.

const (
	// ActorTUI is the interactive kanban UI, driven by a human at a keyboard.
	ActorTUI Actor = "tui"
	// ActorCLI is a `ty` subcommand, run by a human in a shell.
	ActorCLI Actor = "cli"
	// ActorWeb is the HTTP API (web UI, desktop app, remote control).
	ActorWeb Actor = "web"
	// ActorMCP is an agent calling a taskyou_* MCP tool about its own task.
	ActorMCP Actor = "mcp"
	// ActorDaemon is the executor's own lifecycle bookkeeping — queueing,
	// starting, and parking the tasks it runs.
	ActorDaemon Actor = "daemon"
	// ActorSweep is a periodic reconciler acting on a task no one asked about.
	// The most dangerous actor in the system, and the one with the strictest
	// evidence requirement.
	ActorSweep Actor = "sweep"
	// ActorHook is an executor hook (Claude's Stop/Notification/PreToolUse)
	// reporting what the agent process just did.
	ActorHook Actor = "hook"
	// ActorPipeline is workflow construction wiring a DAG's steps into their
	// initial states.
	ActorPipeline Actor = "pipeline"
	// ActorSystem is ty itself doing structural bookkeeping — creating a task,
	// releasing a dependent whose blockers all finished.
	ActorSystem Actor = "system"
	// ActorMigration is the one-time backfill that gave pre-log tasks a genesis
	// event. It never appears on a transition made after this feature shipped.
	ActorMigration Actor = "migration"
)

func KnownActors added in v0.3.31

func KnownActors() []Actor

KnownActors lists every actor, for validation and for `ty debug`.

type AgentTurn added in v0.3.31

type AgentTurn struct {
	Started   int64
	Completed int64
}

AgentTurn is a task's turn counters: how many turns the agent has begun, and how many it has finished. Started is always >= Completed while the agent is working.

func (AgentTurn) RepliedAfter added in v0.3.31

func (t AgentTurn) RepliedAfter(prev AgentTurn) bool

RepliedAfter reports whether t is a completed reply to a prompt sent when the counters read prev — a turn that both started after the send and has since finished.

Completed >= Started is what keeps the PREVIOUS turn's Stop from being read as this turn's answer: a stale Stop can only raise Completed to a value Started has already passed.

type Attachment

type Attachment struct {
	ID        int64
	TaskID    int64
	Filename  string
	MimeType  string
	Size      int64
	Data      []byte
	CreatedAt LocalTime
}

Attachment represents a file attached to a task.

type DB

type DB struct {
	*sql.DB
	// contains filtered or unexported fields
}

DB wraps the SQLite database connection.

func Open

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

Open opens or creates a SQLite database at the given path.

func OpenReadOnly added in v0.3.31

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

OpenReadOnly opens an existing database without migrating it.

`ty doctor` exists to report what is on this machine, not to change it, and db.Open's first act is to run every migration — which on an old file is a repair. Opening read-only means doctor can say "this database was last migrated by an older build" instead of quietly making that untrue.

The file must already exist: creating one would itself be a change.

func OpenWithOptions added in v0.3.31

func OpenWithOptions(path string, opts OpenOptions) (*DB, error)

OpenWithOptions opens a database with explicit options. See Open.

The agent-facing hooks pass a short busy timeout and skip migrations: a hook runs in the agent's critical path, so a database another process holds locked must make it give up quickly and silently rather than hold the agent at a stopped cursor. Everything else should use Open.

func (*DB) AddAttachment

func (db *DB) AddAttachment(taskID int64, filename, mimeType string, data []byte) (*Attachment, error)

AddAttachment adds a file attachment to a task.

func (*DB) AddDependency

func (db *DB) AddDependency(blockerID, blockedID int64, autoQueue bool) error

AddDependency creates a dependency where blockerID blocks blockedID. Returns an error if the dependency already exists or would create a cycle.

func (*DB) AgentTurnState added in v0.3.31

func (db *DB) AgentTurnState(taskID int64) (AgentTurn, error)

AgentTurnState returns a task's turn counters. A task nothing has been sent to yet reads as zero, which is the right answer: nothing has started and nothing has finished.

func (*DB) AllocatePort

func (db *DB) AllocatePort(taskID int64) (int, error)

AllocatePort assigns an available port to a task. Returns the allocated port, or an error if no ports are available.

func (*DB) AppendTaskLog

func (db *DB) AppendTaskLog(taskID int64, lineType, content string) error

AppendTaskLog appends a log entry to a task.

func (*DB) AttachmentDirectory added in v0.3.31

func (db *DB) AttachmentDirectory() string

AttachmentDirectory is durable storage owned by this database. Back up both. Worktrees hold execution copies and may be deleted independently.

func (*DB) BeginAgentTurn added in v0.3.31

func (db *DB) BeginAgentTurn(taskID int64) (AgentTurn, error)

BeginAgentTurn records that the agent started a turn (its UserPromptSubmit hook fired) and returns the counters as they now stand.

func (*DB) BeginRemoteRun added in v0.3.28

func (db *DB) BeginRemoteRun(taskID int64, host string) (string, error)

BeginRemoteRun fences signals from every earlier attempt of the same task.

func (*DB) CheckStatusConsistency added in v0.3.31

func (db *DB) CheckStatusConsistency() ([]StatusMismatch, error)

CheckStatusConsistency asserts the invariant this whole design rests on: for every task, the cached tasks.status equals the fold over its status events.

If this ever reports a mismatch, something wrote the status column outside SetTaskStatus — which is the bug class this package exists to make impossible. `ty debug status-consistency` runs it against a real DB.

func (*DB) ClearArchiveState

func (db *DB) ClearArchiveState(taskID int64) error

ClearArchiveState clears the archive state for a task after unarchiving.

func (*DB) ClearTaskLogs

func (db *DB) ClearTaskLogs(taskID int64) error

ClearTaskLogs clears all logs for a task.

func (*DB) ClearTaskPaneIDs added in v0.3.18

func (db *DB) ClearTaskPaneIDs(taskID int64) error

ClearTaskPaneIDs clears only the tmux pane IDs for a task, leaving the window ID intact. Called when a task reaches a terminal state: its executor pane is torn down, which frees the pane ID for tmux to recycle onto a *different* task's pane. Leaving the stale ID in the DB is what let a finished task's pane pointer resolve to another live task's pane. Window IDs are not recycled as aggressively and are already staleness-checked on lookup, so we keep them.

func (*DB) ClearTaskPlacement added in v0.3.28

func (db *DB) ClearTaskPlacement(taskID int64) error

ClearTaskPlacement forgets a task's placement decision so the next spawn asks the resolver again. This is what `ty retry --replace` does, and it is the ONLY way a placed task moves hosts: a host that has gone away fails the task visibly rather than silently re-placing it, because a silent move orphans the worktree, branch and executor session the first attempt left behind.

func (*DB) ClearTaskSessionPlacement added in v0.3.30

func (db *DB) ClearTaskSessionPlacement(taskID int64) error

ClearTaskSessionPlacement tears down a task's tmux placement in one statement: the window ID, both pane IDs, and the daemon session that owned the window. It deliberately leaves claude_session_id alone — that is what `--resume` needs to bring the conversation back, and dropping it turns a suspend into a discard. Used by both the idle-suspend sweep and `ty sessions suspend`, which must agree on what "suspended" means.

func (*DB) ClearTaskTmuxIDs

func (db *DB) ClearTaskTmuxIDs(taskID int64) error

ClearTaskTmuxIDs clears all tmux-related IDs for a task. This should be called before retrying/restarting a task to prevent stale references. Clears: tmux_window_id, claude_pane_id, shell_pane_id

func (*DB) ClearTaskWorktreePath

func (db *DB) ClearTaskWorktreePath(taskID int64) error

ClearTaskWorktreePath clears just the worktree_path for a task. Used during async archive cleanup to avoid overwriting other fields.

func (*DB) ClearTaskWorktreeRefs added in v0.3.30

func (db *DB) ClearTaskWorktreeRefs(taskID int64) error

ClearTaskWorktreeRefs drops every reference a task holds to a directory on disk: the live worktree_path and the archive_worktree_path recorded when it was archived. Used when the recorded path turns out not to be a worktree at all (most commonly the project's own main checkout), where there is nothing to remove and nothing to restore.

Deliberately does NOT touch updated_at: the row is being corrected by a background sweep, not modified by the user, and bumping the timestamp makes a months-old task resurface at the top of every recently-touched view — which is exactly what the hourly re-archive of task 1201 did for five months.

func (*DB) ClearWorktreeSweepFailure added in v0.3.30

func (db *DB) ClearWorktreeSweepFailure(taskID int64) error

ClearWorktreeSweepFailure removes the un-sweepable marker. Called whenever a task gets a worktree set up again: the new worktree has never failed to archive, so the old verdict no longer applies.

func (*DB) CommitTaskPlacement added in v0.3.28

func (db *DB) CommitTaskPlacement(taskID int64, target, reason, workDir, branch string) error

CommitTaskPlacement atomically publishes a carried branch and its destination, clears stale remote references, and fences the outgoing run's late signals.

func (*DB) CompleteAgentTurn added in v0.3.31

func (db *DB) CompleteAgentTurn(taskID int64) (AgentTurn, error)

CompleteAgentTurn records that the agent finished the turn it was on (its Stop hook fired).

Completed is set to Started rather than incremented: a Stop with no turn behind it — an agent whose prompt predates turn tracking, or a hook that fired twice — must not push Completed past Started and make the next wait return on a turn that never began.

func (*DB) CompleteOnboarding

func (db *DB) CompleteOnboarding() error

CompleteOnboarding marks the onboarding as complete.

func (*DB) CoordinatorID added in v0.3.28

func (db *DB) CoordinatorID() (string, error)

CoordinatorID is stable across daemon restarts and scoped to this database.

func (*DB) CountAttachments

func (db *DB) CountAttachments(taskID int64) (int, error)

CountAttachments returns the number of attachments for a task.

func (*DB) CountRecentExecutorStarts added in v0.3.31

func (db *DB) CountRecentExecutorStarts(taskID int64, window time.Duration) (int, error)

CountRecentExecutorStarts counts the executor launches logged for a task within the last window. It reads the shared database, so every process that can start an executor (each TUI, the web API) sees the same count; a counter held in one process let two TUIs relaunch one task 19 times between them without either tripping.

func (*DB) CountStatusEvents added in v0.3.31

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

CountStatusEvents returns the total number of rows in the status log. Used by `ty debug status-consistency` to say how much it actually checked — "0 mismatches" over an empty table is not the same claim as over a full one.

func (*DB) CountTasksByProject

func (db *DB) CountTasksByProject(projectName string) (int, error)

CountTasksByProject returns the number of tasks associated with a project name.

func (*DB) CountTasksByStatus

func (db *DB) CountTasksByStatus(status string) (int, error)

CountTasksByStatus returns the count of tasks with a given status.

func (*DB) CreateProject

func (db *DB) CreateProject(p *Project) error

CreateProject creates a new project.

func (*DB) CreateRoutineRun added in v0.3.7

func (db *DB) CreateRoutineRun(routine string) (int64, error)

CreateRoutineRun inserts a new run in the running state and returns its ID.

func (*DB) CreateTask

func (db *DB) CreateTask(t *Task) error

CreateTask creates a new task.

func (*DB) CreateTaskType

func (db *DB) CreateTaskType(t *TaskType) error

CreateTaskType creates a new task type.

func (*DB) DeleteAttachment

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

DeleteAttachment removes an attachment.

func (*DB) DeleteProject

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

DeleteProject deletes a project.

func (*DB) DeleteRoutineRuns added in v0.3.7

func (db *DB) DeleteRoutineRuns(routine string) error

DeleteRoutineRuns removes all recorded runs for a routine. Used when the routine itself is deleted so run history doesn't orphan.

func (*DB) DeleteSavedView added in v0.3.31

func (db *DB) DeleteSavedView(name string) error

DeleteSavedView removes a view by name. Deleting a view that does not exist is not an error — the end state the caller asked for is already true.

func (*DB) DeleteTask

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

DeleteTask deletes a task.

func (*DB) DeleteTaskSettings added in v0.3.31

func (db *DB) DeleteTaskSettings(taskID int64) error

DeleteTaskSettings removes every per-task setting belonging to a task.

func (*DB) DeleteTaskType

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

DeleteTaskType deletes a task type (only non-builtin types can be deleted).

func (*DB) FinishRoutineRun added in v0.3.7

func (db *DB) FinishRoutineRun(id int64, status string, exitCode int, output string) error

FinishRoutineRun records a run's terminal state.

func (*DB) GetActiveTaskPorts

func (db *DB) GetActiveTaskPorts() (map[int]bool, error)

GetActiveTaskPorts returns all ports currently in use by active (non-done, non-archived) tasks.

func (*DB) GetAllDependencies

func (db *DB) GetAllDependencies(taskID int64) (blockers []*Task, blockedBy []*Task, err error)

GetAllDependencies returns all dependencies for a given task (both blockers and blocked).

func (*DB) GetAllSettings

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

GetAllSettings returns all settings as a map.

func (*DB) GetAppliedStatusEvents added in v0.3.31

func (db *DB) GetAppliedStatusEvents(taskID int64) ([]StatusEvent, error)

GetAppliedStatusEvents returns only the transitions that actually happened — the sequence FoldStatus projects over.

func (*DB) GetAttachment

func (db *DB) GetAttachment(id int64) (*Attachment, error)

GetAttachment retrieves an attachment by ID.

func (*DB) GetBlockedBy

func (db *DB) GetBlockedBy(taskID int64) ([]*Task, error)

GetBlockedBy returns all tasks that are blocked by the given task.

func (*DB) GetBlockers

func (db *DB) GetBlockers(taskID int64) ([]*Task, error)

GetBlockers returns all tasks that block the given task.

func (*DB) GetConversationHistoryLogs

func (db *DB) GetConversationHistoryLogs(taskID int64) ([]*TaskLog, error)

GetConversationHistoryLogs retrieves only logs relevant for building conversation history. This is much more efficient than GetTaskLogs for the executor's prompt building, as it skips large output/tool log content that isn't needed for conversation context. Only fetches: continuation markers, questions, and user feedback.

func (*DB) GetDependency

func (db *DB) GetDependency(blockerID, blockedID int64) (*Dependency, error)

GetDependency returns the dependency between two tasks, or nil if none exists.

func (*DB) GetExecutorUsageByProject

func (db *DB) GetExecutorUsageByProject(project string) (map[string]int, error)

GetExecutorUsageByProject returns a map of executor names to their usage counts for a project. This counts how many tasks have been created with each executor for the given project.

func (*DB) GetLastEffortForProject added in v0.3.3

func (db *DB) GetLastEffortForProject(project string) (string, error)

GetLastEffortForProject returns the last used Claude effort override for a project ("" means the global/Claude default was used).

func (*DB) GetLastExecutorForProject

func (db *DB) GetLastExecutorForProject(project string) (string, error)

GetLastExecutorForProject returns the last used executor for a project.

func (*DB) GetLastModelForProject added in v0.3.14

func (db *DB) GetLastModelForProject(project string) (string, error)

GetLastModelForProject returns the last used Claude model override for a project ("" means the global/Claude default was used).

func (*DB) GetLastPermissionForProject added in v0.3.3

func (db *DB) GetLastPermissionForProject(project string) (string, error)

GetLastPermissionForProject returns the last used permission mode for a project ("" means none recorded yet).

func (*DB) GetLastQuestion

func (db *DB) GetLastQuestion(taskID int64) (string, error)

GetLastQuestion retrieves the most recent question log for a task.

func (*DB) GetLastTaskTypeForProject

func (db *DB) GetLastTaskTypeForProject(project string) (string, error)

GetLastTaskTypeForProject returns the last used task type for a project.

func (*DB) GetLastUsedProject

func (db *DB) GetLastUsedProject() (string, error)

GetLastUsedProject returns the last used project name.

func (*DB) GetLatestLogPerTask added in v0.2.27

func (db *DB) GetLatestLogPerTask(taskIDs []int64) (map[int64]*TaskLog, error)

GetLatestLogPerTask returns the most recent log entry for each of the given task IDs. Returns a map of taskID -> latest TaskLog. Seek to the last indexed row per task instead of scanning its entire history with GROUP BY / MAX(id).

func (*DB) GetMostRecentlyCreatedTask

func (db *DB) GetMostRecentlyCreatedTask() (*Task, error)

GetMostRecentlyCreatedTask returns the task with the most recent created_at timestamp. This is used to get the last task's project for defaulting in new task forms.

func (*DB) GetNextQueuedTask

func (db *DB) GetNextQueuedTask() (*Task, error)

GetNextQueuedTask returns the next task to process.

func (*DB) GetOpenBlockerCount

func (db *DB) GetOpenBlockerCount(taskID int64) (int, error)

GetOpenBlockerCount returns the number of incomplete blockers for a task.

func (*DB) GetPipelineArtifact added in v0.3.18

func (db *DB) GetPipelineArtifact(branch, name string) (string, error)

GetPipelineArtifact returns the content of a single artifact by (branch, name). A missing artifact returns an empty string and no error (same convenience as GetProjectContext) so callers can treat "not written yet" as empty.

func (*DB) GetProjectByName

func (db *DB) GetProjectByName(name string) (*Project, error)

GetProjectByName returns a project by name or alias.

func (*DB) GetProjectByPath

func (db *DB) GetProjectByPath(cwd string) (*Project, error)

GetProjectByPath returns a project whose path matches the given directory. It checks if cwd equals or is a subdirectory of any project's path.

func (*DB) GetProjectContext

func (db *DB) GetProjectContext(projectName string) (string, error)

GetProjectContext returns the auto-generated context for a project. This context is cached exploration results that can be reused across tasks.

func (*DB) GetQueuedTasks

func (db *DB) GetQueuedTasks() ([]*Task, error)

GetQueuedTasks returns all queued tasks (waiting to be processed).

func (*DB) GetRetryFeedback

func (db *DB) GetRetryFeedback(taskID int64) (string, error)

GetRetryFeedback returns the feedback from the most recent retry, or empty string if not a retry. Looks for "Feedback: ..." log entry after "--- Continuation ---" marker.

func (*DB) GetRoutineRun added in v0.3.7

func (db *DB) GetRoutineRun(id int64) (*RoutineRun, error)

GetRoutineRun fetches a single run by ID.

func (*DB) GetSavedView added in v0.3.31

func (db *DB) GetSavedView(name string) (*SavedView, error)

GetSavedView looks a view up by name, case-insensitively. It returns (nil, nil) when no such view exists, so callers can tell "missing" from "broken" without inspecting the error.

func (*DB) GetSetting

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

GetSetting returns a setting value.

func (*DB) GetStaleWorktreeTasks

func (db *DB) GetStaleWorktreeTasks(maxAge time.Duration) ([]*Task, error)

GetStaleWorktreeTasks returns done/archived tasks that have worktree paths set and were completed more than maxAge ago. These are candidates for cleanup.

Rows already marked un-sweepable (worktree_sweep_failed_at set, see MarkWorktreeSweepFailed) are excluded: their archive has already failed once and nothing about a retry would go differently, so the automatic sweep must not keep attempting them.

func (*DB) GetStaleWorktreeTasksIncludingFailed added in v0.3.30

func (db *DB) GetStaleWorktreeTasksIncludingFailed(maxAge time.Duration) ([]*Task, error)

GetStaleWorktreeTasksIncludingFailed is GetStaleWorktreeTasks plus the rows a prior sweep marked un-sweepable. Used by the on-demand `task worktrees cleanup` command: a human asking for a cleanup is entitled to a retry (and to see the error again), which is exactly what the unattended hourly sweep must not do.

func (*DB) GetStatusEvents added in v0.3.31

func (db *DB) GetStatusEvents(taskID int64) ([]StatusEvent, error)

GetStatusEvents returns a task's full transition history in append order, refusals included.

func (*DB) GetStepVerify added in v0.3.18

func (db *DB) GetStepVerify(taskID int64) (string, error)

GetStepVerify returns the evidence-gate command for a step task, or "" when the step has no gate (the common case) — so callers treat "no row" as "no gate".

func (*DB) GetSweepableTrashedTasks added in v0.3.16

func (db *DB) GetSweepableTrashedTasks(maxAge time.Duration) ([]*TrashedTask, error)

GetSweepableTrashedTasks returns trashed tasks whose retention has expired — i.e. deleted_at is older than maxAge — so the daemon can hard-delete them.

func (*DB) GetTagsList

func (db *DB) GetTagsList() ([]string, error)

GetTagsList returns all unique tags used across all tasks.

func (*DB) GetTask

func (db *DB) GetTask(id int64) (*Task, error)

GetTask retrieves a task by ID.

func (*DB) GetTaskBaseCommit added in v0.3.16

func (db *DB) GetTaskBaseCommit(taskID int64) (string, error)

GetTaskBaseCommit returns the commit a task's worktree was created at, or "" if it was never recorded (a task from before the column existed).

func (*DB) GetTaskBaseDirty added in v0.3.16

func (db *DB) GetTaskBaseDirty(taskID int64) (string, error)

GetTaskBaseDirty returns the paths dirty in the worktree when the task started.

func (*DB) GetTaskByWorktreePath added in v0.3.22

func (db *DB) GetTaskByWorktreePath(path string) (*Task, error)

GetTaskByWorktreePath returns the task that owns a worktree directory, or nil.

Used when a branch turns out to be checked out somewhere: git names the worktree holding it, and the only way to decide whether that branch can be reclaimed is to ask what the owning task is doing. Trashed tasks are excluded — a deleted task's worktree is nobody's live work.

func (*DB) GetTaskLogCount

func (db *DB) GetTaskLogCount(taskID int64) (int, error)

GetTaskLogCount returns the number of logs for a task. This is a fast operation useful for checking if logs have changed.

func (*DB) GetTaskLogs

func (db *DB) GetTaskLogs(taskID int64, limit int) ([]*TaskLog, error)

GetTaskLogs retrieves logs for a task.

func (*DB) GetTaskLogsBefore added in v0.3.28

func (db *DB) GetTaskLogsBefore(taskID, beforeID int64, limit int) ([]*TaskLog, error)

GetTaskLogsBefore returns a bounded history page, newest first. A zero beforeID selects the latest page.

func (*DB) GetTaskLogsSince

func (db *DB) GetTaskLogsSince(taskID int64, sinceID int64) ([]*TaskLog, error)

GetTaskLogsSince retrieves logs after a given ID.

func (*DB) GetTaskLogsSinceLimit added in v0.3.28

func (db *DB) GetTaskLogsSinceLimit(taskID, sinceID int64, limit int) ([]*TaskLog, error)

GetTaskLogsSinceLimit bounds streaming catch-up without discarding older rows. A zero limit preserves the unbounded internal API for existing callers.

func (*DB) GetTaskPlacement added in v0.3.28

func (db *DB) GetTaskPlacement(taskID int64) (target, reason string, err error)

GetTaskPlacement returns the host a task ran on and why, both empty when the task ran locally or predates the placement hook.

func (*DB) GetTaskPlacementDecision added in v0.3.28

func (db *DB) GetTaskPlacementDecision(taskID int64) (TaskPlacement, error)

GetTaskPlacementDecision returns the placement already decided for a task.

func (*DB) GetTaskRemoteWorktree added in v0.3.28

func (db *DB) GetTaskRemoteWorktree(taskID int64) (path, branch string, err error)

GetTaskRemoteWorktree returns the remote worktree path and branch, both empty for a task that has never run remotely.

func (*DB) GetTaskType

func (db *DB) GetTaskType(id int64) (*TaskType, error)

GetTaskType retrieves a task type by ID.

func (*DB) GetTaskTypeByName

func (db *DB) GetTaskTypeByName(name string) (*TaskType, error)

GetTaskTypeByName retrieves a task type by name.

func (*DB) HasContinuationMarker

func (db *DB) HasContinuationMarker(taskID int64) (bool, error)

HasContinuationMarker checks if a task has any continuation markers. This is a fast EXISTS-style query to avoid loading logs just to check.

func (*DB) HasLogLineContaining added in v0.3.16

func (db *DB) HasLogLineContaining(taskID int64, substr string) (bool, error)

HasLogLineContaining reports whether the task has any log line whose content contains substr. Used to make a periodic sweep idempotent — e.g. logging a "parked for merge review" note exactly once for a terminal workflow step.

func (*DB) HasOpenTaskWithTitle added in v0.3.7

func (db *DB) HasOpenTaskWithTitle(title string) (bool, error)

HasOpenTaskWithTitle reports whether a non-done, non-archived task with the exact title exists. Used to dedupe automatically created alert tasks.

func (*DB) HasQuestionLog added in v0.3.16

func (db *DB) HasQuestionLog(taskID int64) (bool, error)

HasQuestionLog reports whether the task ever recorded a needs-input question (line_type "question"). The workflow "finished but couldn't signal" sweep uses this to avoid auto-completing a step that is genuinely waiting on a human answer.

func (*DB) HasSessionEnded added in v0.3.31

func (db *DB) HasSessionEnded(taskID int64) (bool, error)

HasSessionEnded reports whether the task's CURRENT executor session has told us it exited, i.e. a SessionEndedLogPrefix line was written after the most recent session-start line. Comparing the two is what keeps a retry honest: a task relaunched after an earlier exit has a newer start line, so the old exit no longer counts.

This never says anything about how the session ended, only that it did — the caller still has to look at the task's status and its evidence to decide what that means.

func (*DB) HasSessionStarted added in v0.3.16

func (db *DB) HasSessionStarted(taskID int64) (bool, error)

HasSessionStarted reports whether the task's executor session actually began. A task flips to 'processing' and then spends tens of seconds on worktree setup (clone, bundle, migrations) before any session exists — so this, not the absence of a tmux window, is how to tell "hasn't started yet" from "ran and finished". Conflating the two let the sweep complete steps before their agent ever launched.

func (*DB) IsBlocked

func (db *DB) IsBlocked(taskID int64) (bool, error)

IsBlocked returns true if the task has any incomplete blockers.

func (*DB) IsFirstRun

func (db *DB) IsFirstRun() bool

IsFirstRun returns true if this is the first time the app is being used. This is determined by checking if onboarding has been completed.

func (*DB) LatestRoutineRuns added in v0.3.7

func (db *DB) LatestRoutineRuns() (map[string]*RoutineRun, error)

LatestRoutineRuns returns the most recent run per routine, keyed by name.

func (*DB) ListAttachments

func (db *DB) ListAttachments(taskID int64) ([]*Attachment, error)

ListAttachments retrieves all attachments for a task (without data for efficiency).

func (*DB) ListAttachmentsWithData

func (db *DB) ListAttachmentsWithData(taskID int64) ([]*Attachment, error)

ListAttachmentsWithData retrieves all attachments for a task including data.

func (*DB) ListPipelineArtifacts added in v0.3.18

func (db *DB) ListPipelineArtifacts(branch string) ([]PipelineArtifact, error)

ListPipelineArtifacts returns every artifact for a branch, oldest first, so a phase can enumerate all upstream documents when no specific name is requested.

func (*DB) ListPlacementHosts added in v0.3.31

func (db *DB) ListPlacementHosts() ([]string, error)

ListPlacementHosts returns the hosts tasks have actually been placed on, most used first. It is the source for the filter's `@host` autocomplete: the fleet is not configured anywhere central — a placement hook names whatever hosts it likes — so the tasks themselves are the only record of which machines exist.

Local runs (an empty placement_target) are not hosts and never appear here.

func (*DB) ListProjects

func (db *DB) ListProjects() ([]*Project, error)

ListProjects returns all projects, with "personal" always first.

func (*DB) ListRoutineRuns added in v0.3.7

func (db *DB) ListRoutineRuns(routine string, limit int) ([]*RoutineRun, error)

ListRoutineRuns returns the most recent runs for a routine, newest first.

func (*DB) ListSavedViews added in v0.3.31

func (db *DB) ListSavedViews() ([]*SavedView, error)

ListSavedViews returns every saved view in display order.

func (*DB) ListTaskTypes

func (db *DB) ListTaskTypes() ([]*TaskType, error)

ListTaskTypes returns all task types ordered by sort_order.

func (*DB) ListTasks

func (db *DB) ListTasks(opts ListTasksOptions) ([]*Task, error)

ListTasks retrieves tasks with optional filters.

func (*DB) ListTrashedTasks added in v0.3.16

func (db *DB) ListTrashedTasks() ([]*TrashedTask, error)

ListTrashedTasks returns soft-deleted tasks, most recently trashed first.

func (*DB) ListWorktreeRefs added in v0.3.30

func (db *DB) ListWorktreeRefs() ([]WorktreeRef, error)

ListWorktreeRefs returns every non-deleted task that names a directory on disk through worktree_path or archive_worktree_path.

func (*DB) MarkTaskStarted

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

MarkTaskStarted sets the started_at timestamp if not already set.

func (*DB) MarkWorktreeSweepFailed added in v0.3.30

func (db *DB) MarkWorktreeSweepFailed(taskID int64) error

MarkWorktreeSweepFailed records that the stale-worktree sweeper could not archive this task's worktree, excluding the row from future automatic sweeps. Like ClearTaskWorktreeRefs it leaves updated_at alone.

func (*DB) MigrateAttachmentFiles added in v0.3.31

func (db *DB) MigrateAttachmentFiles() error

MigrateAttachmentFiles moves legacy blobs only after their files are durable. It is restartable. SQLite reuses the freed pages; shrinking the database is a separate maintenance operation. Legacy blobs remain readable until migrated.

func (*DB) Path

func (db *DB) Path() string

Path returns the path to the database file.

func (*DB) ProcessCompletedBlocker

func (db *DB) ProcessCompletedBlocker(blockerID int64) ([]*Task, error)

ProcessCompletedBlocker checks tasks blocked by the completed task and updates their status if they become unblocked. Returns the list of tasks that were unblocked.

func (*DB) ReadSchemaVersion added in v0.3.31

func (db *DB) ReadSchemaVersion() (int, bool)

ReadSchemaVersion returns the schema version recorded in the file, and whether one was recorded at all. A database last opened by a build from before the stamp existed reports (0, false) — old, but not corrupt.

func (*DB) RecordHostHealth added in v0.3.28

func (db *DB) RecordHostHealth(host, problem string, observed bool) error

func (*DB) RecoverStaleTmuxRefs

func (db *DB) RecoverStaleTmuxRefs(activeSessions map[string]bool, validWindowIDs map[string]bool) (int, int, error)

RecoverStaleTmuxRefs clears stale daemon_session and tmux_window_id references from tasks. Called automatically on daemon startup to recover from crashes. Returns (staleDaemonCount, staleWindowCount) of cleaned references.

Only LOCAL references are swept: see placedElsewhere.

func (*DB) RemoteHostHealth added in v0.3.28

func (db *DB) RemoteHostHealth(host string) (HostHealth, error)

func (*DB) RemoteSignal added in v0.3.28

func (db *DB) RemoteSignal(taskID int64, host string) (RemoteEvent, bool, error)

RemoteSignal returns the latest persisted event for the current host and run. It is deliberately not deleted: a crash before finalization must replay it.

func (*DB) RemoveDependency

func (db *DB) RemoveDependency(blockerID, blockedID int64) error

RemoveDependency removes a dependency between two tasks.

func (*DB) RequeueReadyTasks added in v0.3.16

func (db *DB) RequeueReadyTasks() ([]*Task, error)

RequeueReadyTasks is the eventually-consistent safety net for ProcessCompletedBlocker. That runs once, best-effort, the instant a blocker completes; a single dropped write (SQLITE_BUSY, a crash) would orphan the dependent in 'blocked' forever, stalling a workflow. This sweep re-queues any task still waiting in the DAG — blocked, never started — whose blockers have all completed. Idempotent: it only touches tasks that are genuinely ready. Returns the tasks it moved.

func (*DB) RestartIdleClock added in v0.3.31

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

RestartIdleClock stamps a blocked task's completed_at with now. The idle sweep measures a parked task's idle time from completed_at, so a session the user resumes by hand, without typing into it, would otherwise be suspended again on the sweep's next pass, a minute later. Only a task that actually ran (completed_at already set) is touched; a staged pipeline step stays unstamped.

This refreshes an existing stamp and never writes status, so it is not a way around the status log: a task it touches is already blocked and has already completed a turn.

func (*DB) RestoreTask added in v0.3.16

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

RestoreTask clears the trashed flag, returning a soft-deleted task to the board with its original status, worktree and session intact.

func (*DB) RetryTask

func (db *DB) RetryTask(id int64, feedback string) error

RetryTask clears logs, appends feedback to body, and re-queues a task. Also clears stale tmux window/pane IDs to prevent duplicate window issues.

func (*DB) SaveArchiveState

func (db *DB) SaveArchiveState(taskID int64, archiveRef, archiveCommit, worktreePath, branchName string) error

SaveArchiveState saves the archive state for a task. This stores the git ref, commit hash, worktree path, and branch name that were active at the time of archiving.

func (*DB) SaveRemoteEvent added in v0.3.28

func (db *DB) SaveRemoteEvent(ev RemoteEvent) error

SaveRemoteEvent deduplicates delivery and discards signals from old runs or other hosts. Success is permission to acknowledge the remote spool file.

func (*DB) SaveView added in v0.3.31

func (db *DB) SaveView(name, query string) (*SavedView, error)

SaveView creates or updates a view by name and returns the stored row. Saving over an existing name replaces its query, which is what "save current filter as <name>" should do when the name is already taken.

func (*DB) SearchTasks

func (db *DB) SearchTasks(query string, limit int) ([]*Task, error)

SearchTasks searches for tasks by query string across title, project, ID, and PR number. This is used by the command palette to search all tasks, not just the preloaded ones.

func (*DB) SetAutoQueue

func (db *DB) SetAutoQueue(blockerID, blockedID int64, autoQueue bool) error

SetAutoQueue updates the auto_queue flag for a dependency.

func (*DB) SetEventEmitter

func (db *DB) SetEventEmitter(emitter EventEmitter)

SetEventEmitter sets the event emitter for this database. This is called by the executor to enable event emission.

func (*DB) SetLastEffortForProject added in v0.3.3

func (db *DB) SetLastEffortForProject(project, effort string) error

SetLastEffortForProject saves the last used Claude effort override for a project so the next task in it defaults to the same choice.

func (*DB) SetLastExecutorForProject

func (db *DB) SetLastExecutorForProject(project, executor string) error

SetLastExecutorForProject saves the last used executor for a project.

func (*DB) SetLastModelForProject added in v0.3.14

func (db *DB) SetLastModelForProject(project, model string) error

SetLastModelForProject saves the last used Claude model override for a project so the next task in it defaults to the same choice.

func (*DB) SetLastPermissionForProject added in v0.3.3

func (db *DB) SetLastPermissionForProject(project, mode string) error

SetLastPermissionForProject saves the last used permission mode for a project so the next task in it defaults to the same choice.

func (*DB) SetLastTaskTypeForProject

func (db *DB) SetLastTaskTypeForProject(project, taskType string) error

SetLastTaskTypeForProject saves the last used task type for a project.

func (*DB) SetLastUsedProject

func (db *DB) SetLastUsedProject(project string) error

SetLastUsedProject saves the last used project name.

func (*DB) SetPipelineArtifact added in v0.3.18

func (db *DB) SetPipelineArtifact(branch, name, content string) error

SetPipelineArtifact upserts an artifact document keyed by (branch, name). A second write to the same key overwrites the previous content (and bumps updated_at), mirroring SetProjectContext's overwrite semantics.

func (*DB) SetProjectContext

func (db *DB) SetProjectContext(projectName string, context string) error

SetProjectContext saves auto-generated context for a project. This overwrites any existing context.

func (*DB) SetRoutineRunLogPath added in v0.3.7

func (db *DB) SetRoutineRunLogPath(id int64, logPath string) error

SetRoutineRunLogPath records where the run's full log lives.

func (*DB) SetSetting

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

SetSetting sets a setting value.

func (*DB) SetStepVerify added in v0.3.18

func (db *DB) SetStepVerify(taskID int64, command string) error

SetStepVerify records the opt-in evidence-gate command for a workflow step, keyed by the step's task id. It is written once at workflow-build time (see pipeline.Create) for steps whose YAML sets `verify:`. A second write overwrites.

func (*DB) SetTaskBaseCommit added in v0.3.16

func (db *DB) SetTaskBaseCommit(taskID int64, sha string) error

SetTaskBaseCommit records the commit a task's worktree was created at. Written once, right after the worktree exists and before any agent session starts.

func (*DB) SetTaskBaseDirty added in v0.3.16

func (db *DB) SetTaskBaseDirty(taskID int64, paths string) error

SetTaskBaseDirty records the paths already dirty in the task's worktree when it started (newline-separated). Worktree init regularly rewrites tracked files, so this is the baseline that "did the step leave uncommitted work?" is measured against.

func (*DB) SetTaskPlacement added in v0.3.28

func (db *DB) SetTaskPlacement(taskID int64, target, reason string) error

SetTaskPlacement records where a task ran: the host the task.placement hook named and the reason it gave. Written once, just before the executor spawns.

An empty target is a real answer, not a missing one — it means the resolver chose this machine — so it is stored alongside its reason rather than skipped. Tasks that were never consulted (no placement plugin installed) keep both fields empty and read exactly as they always have.

func (*DB) SetTaskPlacementDecision added in v0.3.28

func (db *DB) SetTaskPlacementDecision(taskID int64, target, reason, workDir string) error

SetTaskPlacementDecision records a placement decision, stamping the time it was made. Called once, at the first spawn; every later spawn reads it back with GetTaskPlacementDecision instead of asking the resolver again.

func (*DB) SetTaskRemoteWorktree added in v0.3.28

func (db *DB) SetTaskRemoteWorktree(taskID int64, path, branch string) error

SetTaskRemoteWorktree records the isolated worktree a remotely placed task was given on its host, so the TUI can say where the task actually is and a retry can find the same directory.

func (*DB) SetTaskStatus added in v0.3.31

func (db *DB) SetTaskStatus(id int64, to string, actor Actor, reason string, evidence Evidence) error

SetTaskStatus is the ONE path that may change a task's status.

actor and reason are positional and required precisely so a future caller cannot take the old shortcut: there is no signature that compiles without answering "who" and "why". evidence answers "on what grounds" and is checked by the gates below — pass NoEvidence for an ordinary transition and mean it.

It appends the transition and updates the cached row in one transaction, so the two can never diverge. Gates run here rather than in callers, so the CLI, the web API, the MCP tool and the TUI all get them without each remembering to ask.

func (*DB) SoftDeleteTask added in v0.3.16

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

SoftDeleteTask marks a task as trashed (deleted_at = now) instead of removing it. The row, worktree and Claude transcript all stay intact and recoverable via RestoreTask until the daemon trash sweep hard-deletes it after the retention window (see Executor.sweepTrashedTasks). Trashed tasks are hidden from the board and every default query. No-op if the task is already trashed.

func (*DB) UpdateProject

func (db *DB) UpdateProject(p *Project) error

UpdateProject updates a project.

func (*DB) UpdateTask

func (db *DB) UpdateTask(t *Task) error

UpdateTask updates a task's editable fields.

It deliberately does NOT write status. Status is append-only: it changes only through SetTaskStatus, which records who and why. This method was the second back door into the status column — a caller could load a task, assign t.Status and save, producing a status change with no transition behind it and a cached row the log could not explain. Assigning t.Status and calling this is now a loud error rather than a silent bypass.

func (*DB) UpdateTaskClaudeConfigDir added in v0.3.28

func (db *DB) UpdateTaskClaudeConfigDir(taskID int64, configDir string) error

UpdateTaskClaudeConfigDir sets the per-task CLAUDE_CONFIG_DIR override, which is how a task is pinned to one Claude profile (account). Writing it as its own column update — rather than through UpdateTask — matters at spawn time: the routing decision is made from a task struct the daemon has been holding, and a full-row write would stomp any field another surface (the TUI, a hook) changed in the meantime.

func (*DB) UpdateTaskClaudeSessionID

func (db *DB) UpdateTaskClaudeSessionID(taskID int64, sessionID string) error

UpdateTaskClaudeSessionID updates only the Claude session ID for a task.

func (*DB) UpdateTaskDaemonSession

func (db *DB) UpdateTaskDaemonSession(taskID int64, daemonSession string) error

UpdateTaskDaemonSession updates the tmux daemon session name for a task. This is used to track which daemon session owns the task's tmux window, so we can properly kill the Claude process when the task completes.

func (*DB) UpdateTaskDangerousMode

func (db *DB) UpdateTaskDangerousMode(taskID int64, dangerousMode bool) error

UpdateTaskDangerousMode updates the dangerous_mode flag for a task, keeping the authoritative permission_mode column in sync. Toggling dangerous off resets the task to the default (prompt) mode.

func (*DB) UpdateTaskLastAccessedAt

func (db *DB) UpdateTaskLastAccessedAt(taskID int64) error

UpdateTaskLastAccessedAt updates the last_accessed_at timestamp for a task. This is used to track when a task was last accessed/opened in the UI, enabling the command palette to show recently visited tasks first.

func (*DB) UpdateTaskPRInfo

func (db *DB) UpdateTaskPRInfo(taskID int64, prURL string, prNumber int, prInfoJSON string) error

UpdateTaskPRInfo updates only the PR-related fields for a task. This is used to persist PR state from GitHub API responses without touching other fields.

When the cached PR JSON actually changes, it records a board-change event so the HTTP API's SSE stream re-pushes the board — this is how a live PR badge reaches the web/desktop without a restart. We compare against the stored value first so idle refreshes (state unchanged) don't spam the change feed every tick.

func (*DB) UpdateTaskPaneIDs

func (db *DB) UpdateTaskPaneIDs(taskID int64, claudePaneID, shellPaneID string) error

UpdateTaskPaneIDs updates the tmux pane IDs for a task. This is used to track the unique pane IDs (e.g., "%1234") for reliable pane identification when joining/breaking panes between the daemon and the TUI.

func (*DB) UpdateTaskPermissionMode added in v0.2.40

func (db *DB) UpdateTaskPermissionMode(taskID int64, mode string) error

UpdateTaskPermissionMode updates the permission_mode for a task and keeps the legacy dangerous_mode boolean consistent.

func (*DB) UpdateTaskPinned

func (db *DB) UpdateTaskPinned(taskID int64, pinned bool) error

UpdateTaskPinned updates only the pinned flag for a task.

func (*DB) UpdateTaskStartedAt

func (db *DB) UpdateTaskStartedAt(taskID int64, t time.Time) error

UpdateTaskStartedAt updates the started_at timestamp for a task. This is primarily used for testing.

func (*DB) UpdateTaskSummary

func (db *DB) UpdateTaskSummary(taskID int64, summary string) error

UpdateTaskSummary updates the task summary and distillation timestamp.

func (*DB) UpdateTaskType

func (db *DB) UpdateTaskType(t *TaskType) error

UpdateTaskType updates a task type.

func (*DB) UpdateTaskWindowID

func (db *DB) UpdateTaskWindowID(taskID int64, windowID string) error

UpdateTaskWindowID updates the tmux window ID for a task. This is used to track the unique window ID (e.g., "@1234") for reliable window targeting.

func (*DB) ValidateTaskModel added in v0.3.26

func (db *DB) ValidateTaskModel(t *Task) error

ValidateTaskModel checks a task's model override against the executor that will run it, skipping the check when the task is routed at a non-stock backend. This is the entry point every write path should use — it resolves the escape hatch (per-task config dir or env, the project's config dir, an ambient ANTHROPIC_BASE_URL) that a bare ValidateModel call cannot see.

func (*DB) WaitForAgentReply added in v0.3.31

func (db *DB) WaitForAgentReply(ctx context.Context, taskID int64, since AgentTurn, timeout time.Duration) (AgentTurn, error)

WaitForAgentReply blocks until a turn that began after since has finished, and returns the counters at that moment. The waiting lives here so no caller has to write its own polling loop, and so there is one definition of what counts as "the agent answered me".

since is the counters read BEFORE the prompt was sent. Returns ErrReplyTimeout if nothing qualifies within timeout, or ctx.Err() if the caller gives up first.

func (*DB) WorktreeSweepFailedAt added in v0.3.30

func (db *DB) WorktreeSweepFailedAt(taskID int64) (*time.Time, error)

WorktreeSweepFailedAt returns when the sweeper marked this task un-sweepable, or nil if it never did.

type Dependency

type Dependency struct {
	ID        int64     `json:"id"`
	BlockerID int64     `json:"blocker_id"`
	BlockedID int64     `json:"blocked_id"`
	AutoQueue bool      `json:"auto_queue"` // If true, auto-queue blocked task when unblocked
	CreatedAt time.Time `json:"created_at"`
}

Dependency represents a blocking relationship between two tasks. The blocker task must be completed before the blocked task can proceed.

type EventEmitter

type EventEmitter interface {
	EmitTaskCreated(task *Task)
	EmitTaskUpdated(task *Task, changes map[string]interface{})
	EmitTaskDeleted(taskID int64, title string)
	EmitTaskPinned(task *Task)
	EmitTaskUnpinned(task *Task)
	EmitTaskBlocked(task *Task, reason string)
	EmitTaskCompleted(task *Task)
}

EventEmitter is an interface for emitting task events. This allows the DB to emit events without depending on the events package.

type Evidence added in v0.3.31

type Evidence struct {
	// Observed is what the caller saw, in its own words. "the agent called
	// taskyou_complete", "HEAD is 3 commits past base and pushed".
	Observed string `json:"observed,omitempty"`
	// Human records that a person asked for this, and how. A human closing a
	// backlog item is legitimate even with nothing to point at; automation
	// closing one is the bug.
	Human string `json:"human,omitempty"`
	// BaseCommit / HeadCommit are the step's starting commit and where it ended
	// up. Different values are the only proof a step produced work.
	BaseCommit string `json:"base_commit,omitempty"`
	HeadCommit string `json:"head_commit,omitempty"`
	// PRNumber / PRState carry a pull request's identity and observed state.
	// PRState of MERGED or CLOSED is what lets a done-write past the open-PR gate.
	PRNumber int    `json:"pr_number,omitempty"`
	PRState  string `json:"pr_state,omitempty"`
	// PRDisowned is the other way past the open-PR gate: the caller says, in
	// its own words, why the PR recorded against this task is not this task's
	// work. A workflow's steps share one branch, so every step matches the
	// terminal step's PR; without this the gate would stall every DAG at step
	// one. It is a positive claim a caller has to make and defend in the log,
	// not an absence the gate can be talked into.
	PRDisowned string `json:"pr_disowned,omitempty"`
	// Gate names the completion gate that was run and passed (e.g. a step's
	// `verify:` command).
	Gate string `json:"gate,omitempty"`
}

Evidence is the positive fact a transition rests on.

The rule the sweep broke was "never infer completion from absence": no tmux window and no diff against origin look exactly like a step that has not started yet. Evidence is how a caller says what it actually OBSERVED, and a transition into a terminal state is refused without it — which is precisely the thing a caller reasoning from absence cannot produce.

func ByHuman added in v0.3.31

func ByHuman(format string, args ...interface{}) Evidence

ByHuman builds Evidence recording that a person asked for this transition.

func Observedf added in v0.3.31

func Observedf(format string, args ...interface{}) Evidence

Observedf builds Evidence from what the caller saw.

func (Evidence) DisownSharedBranchPR added in v0.3.31

func (e Evidence) DisownSharedBranchPR(prNumber int, branch string) Evidence

DisownSharedBranchPR marks evidence as belonging to a workflow step that carries a PR number it did not open.

Every step of a workflow shares one branch, so a PR lookup on any of them finds the terminal step's PR. A non-terminal step completing is therefore a legitimate done-write with an open PR on the row — the one case the open-PR gate must let through. It is let through because the caller SAYS it is not its PR and the log keeps that claim, not because the gate inferred anything. A no-op when the task has no PR number.

func (Evidence) IsEmpty added in v0.3.31

func (e Evidence) IsEmpty() bool

IsEmpty reports whether the evidence says nothing at all.

func (Evidence) String added in v0.3.31

func (e Evidence) String() string

String renders evidence for a human reading the audit trail.

type HostHealth added in v0.3.28

type HostHealth struct {
	State    string `json:"state"`
	LastSeen string `json:"last_seen,omitempty"`
	Problem  string `json:"problem,omitempty"`
}

HostHealth keeps transport health separate from task state and is shared by the daemon, HTTP server and TUI through the coordinator database.

type ListTasksOptions

type ListTasksOptions struct {
	Status         string
	Type           string
	Project        string
	Tag            string // Filter to tasks carrying this exact tag (delimiter-safe; "gm:cortex" does not match "gm:cortex-2")
	Limit          int    // Zero defaults to 100; negative means no limit.
	Offset         int
	IncludeClosed  bool // Include closed tasks even when Status is empty
	IncludeTrashed bool // Include soft-deleted (trashed) tasks; by default they are hidden
	OrderByRecency bool // Sort purely by recency, ignoring pinned-first ordering
	OpenPROnly     bool // Only tasks whose stored PR is still open or draft (not merged/closed)
}

ListTasksOptions defines options for listing tasks.

type LocalTime

type LocalTime struct {
	time.Time
}

LocalTime wraps time.Time and converts from UTC to local timezone when scanning.

func (*LocalTime) Scan

func (lt *LocalTime) Scan(value interface{}) error

Scan implements sql.Scanner, converting scanned time to local timezone.

func (LocalTime) Value

func (lt LocalTime) Value() (driver.Value, error)

Value implements driver.Valuer for inserting LocalTime into database.

type OpenOptions added in v0.3.31

type OpenOptions struct {
	// BusyTimeout is how long to wait on a locked database. Zero means
	// DefaultBusyTimeout.
	BusyTimeout time.Duration
	// SkipMigrate opens the database without running migrations. For short-lived
	// processes that only read and write rows in a schema ty already created —
	// the agent-facing hooks — where a migration is both unnecessary and, against
	// a database somebody else has locked, several seconds of the agent's time.
	SkipMigrate bool
}

OpenOptions tunes Open for callers that cannot take its defaults.

type PipelineArtifact added in v0.3.18

type PipelineArtifact struct {
	Branch    string
	Name      string
	Content   string
	CreatedAt time.Time
	UpdatedAt time.Time
}

PipelineArtifact is one inter-phase document produced by a workflow step and read by a later step on the same shared branch. It is the TaskYou-native hand-off store: document phases (research-questions, research, design, ...) write their output here instead of committing docs to git.

type Project

type Project struct {
	ID              int64
	Name            string
	Path            string
	Aliases         string          // comma-separated
	Instructions    string          // project-specific instructions for AI
	Actions         []ProjectAction // actions triggered on task events (stored as JSON)
	Color           string          // hex color for display (e.g., "#61AFEF")
	ClaudeConfigDir string          // override CLAUDE_CONFIG_DIR for this project
	UseWorktrees    bool            // whether to use git worktrees for task isolation (default true)
	// DefaultPermissionMode is the permission mode new tasks in this project
	// inherit ("default", "auto", "dangerous"). Empty means use the global default.
	DefaultPermissionMode string
	CreatedAt             LocalTime
}

Project represents a configured project.

func (*Project) EffectiveDefaultPermissionMode added in v0.2.40

func (p *Project) EffectiveDefaultPermissionMode() string

EffectiveDefaultPermissionMode returns the permission mode new tasks in this project should inherit, falling back to the global default when unset.

func (*Project) GetAction

func (p *Project) GetAction(trigger string) *ProjectAction

GetAction returns the action for a given trigger, or nil if not found.

func (*Project) UsesWorktrees

func (p *Project) UsesWorktrees() bool

UsesWorktrees returns whether this project uses git worktrees for task isolation. Defaults to true for backward compatibility.

type ProjectAction

type ProjectAction struct {
	Trigger      string `json:"trigger"`      // "on_create", "on_status:queued", etc.
	Instructions string `json:"instructions"` // prompt/instructions for this action
}

ProjectAction defines an action that runs on tasks for a project.

type RefusedError added in v0.3.31

type RefusedError struct {
	TaskID int64
	From   string
	To     string
	Gate   string
	Detail string
}

RefusedError is returned when a gate rejects a transition. Callers that want to render the refusal (the TUI notice, the MCP tool result, an HTTP 409) check for it with IsRefused.

func (*RefusedError) Error added in v0.3.31

func (e *RefusedError) Error() string

type RemoteEvent added in v0.3.28

type RemoteEvent struct {
	ID     string
	TaskID int64
	RunID  string
	Host   string
	Kind   string
	Detail string
}

RemoteEvent is a durable inbox entry. The sender retains it until this DB accepts it; reads are repeatable until the task's next run replaces its fence.

type RoutineRun added in v0.3.7

type RoutineRun struct {
	ID         int64      `json:"id"`
	Routine    string     `json:"routine"`
	Status     string     `json:"status"` // running, ok, failed
	ExitCode   int        `json:"exit_code"`
	Output     string     `json:"output"` // tail of combined output; full log on disk
	LogPath    string     `json:"log_path"`
	StartedAt  LocalTime  `json:"started_at"`
	FinishedAt *LocalTime `json:"finished_at,omitempty"`
}

RoutineRun is one recorded execution of a routine (see internal/routine). Routines themselves live on disk; only run history lives in the database.

type SavedView added in v0.3.31

type SavedView struct {
	ID        int64     `json:"id"`
	Name      string    `json:"name"`
	Query     string    `json:"query"`
	SortOrder int       `json:"sort_order"`
	CreatedAt LocalTime `json:"created_at"`
	UpdatedAt LocalTime `json:"updated_at"`
}

SavedView is a named filter query — "the tasks I care about right now".

A view is nothing but its query string, in the grammar internal/taskfilter parses ("status:in-progress status:blocked", "is:pinned", "[offerlab]"). That keeps every surface honest: the TUI, the CLI and the HTTP API all resolve a view name to the same string and run the same matcher over it, so a view cannot mean one thing on the board and another in a script.

type StatusEvent added in v0.3.31

type StatusEvent struct {
	ID        int64
	TaskID    int64
	From      string
	To        string
	Actor     Actor
	Reason    string
	Evidence  Evidence
	Outcome   string
	Gate      string
	CreatedAt LocalTime
}

StatusEvent is one appended fact about a task's status.

type StatusMismatch added in v0.3.31

type StatusMismatch struct {
	TaskID   int64
	Title    string
	Cached   string
	Folded   string
	NumEvent int
}

StatusMismatch is one task whose cached status disagrees with its log.

func (StatusMismatch) String added in v0.3.31

func (m StatusMismatch) String() string

type Task

type Task struct {
	ID              int64
	Title           string
	Body            string
	Status          string
	Type            string
	Project         string
	Executor        string // Task executor: "claude" (default), "codex", "gemini", "grok", "cursor"
	EffortLevel     string // Per-task Claude effort override ("" = use global/Claude default; otherwise low/medium/high/xhigh/max)
	Model           string // Per-task Claude model override ("" = use global/Claude default; otherwise an alias like opus/sonnet/haiku or a full model name)
	ClaudeConfigDir string // Per-task CLAUDE_CONFIG_DIR override ("" = use the project's/default config dir). Lets a single step route through a different Claude config (e.g. an ollama-backed one) without changing the project.
	EnvJSON         string // Per-task env overrides for the spawned Claude, stored as a JSON object (e.g. {"ANTHROPIC_BASE_URL":"http://127.0.0.1:11434","ANTHROPIC_AUTH_TOKEN":"ollama"}). Injected as a process-env prefix on the claude command so a step can route through a non-Anthropic proxy (ollama) WITHOUT swapping CLAUDE_CONFIG_DIR — the default config dir (plugins, MCP, trusted worktrees) stays intact and process env wins over stored creds. "" = no overrides.
	WorktreePath    string
	BranchName      string
	Port            int    // Unique port for running the application in this task's worktree
	ClaudeSessionID string // Claude session ID for resuming conversations
	DaemonSession   string // tmux daemon session name (e.g., "task-daemon-12345")
	TmuxWindowID    string // tmux window ID (e.g., "@1234") for unique window identification
	ClaudePaneID    string // tmux pane ID (e.g., "%1234") for the Claude/executor pane
	ShellPaneID     string // tmux pane ID (e.g., "%1235") for the shell pane
	PRURL           string // Pull request URL (if associated with a PR)
	PRNumber        int    // Pull request number (if associated with a PR)
	PRInfoJSON      string // Cached PR state as JSON (state, checks, mergeable, etc.)
	DangerousMode   bool   // Whether task is running in dangerous mode (--dangerously-skip-permissions). Kept for backward compat; PermissionMode is authoritative.
	PermissionMode  string // Permission mode for execution: "default" (prompt), "accept-edits" (Claude's acceptEdits — auto-accept file edits, still prompts for risky actions), "auto" (Claude Code's auto mode — classifier auto-approves safe actions, blocks risky ones), "dangerous" (skip permissions). Empty falls back to DangerousMode/global default.
	RemoteControl   bool   // Whether to launch claude with --remote-control (interactive, remote-drivable)
	Pinned          bool   // Whether the task is pinned to the top of its column
	Tags            string // Comma-separated tags for categorization (e.g., "customer-support,email,influence-kit")
	SourceBranch    string // Existing branch to checkout for worktree (e.g., "fix/ui-overflow") instead of creating new branch
	Summary         string // Distilled summary of what was accomplished (for search and context)
	CreatedAt       LocalTime
	UpdatedAt       LocalTime
	StartedAt       *LocalTime
	CompletedAt     *LocalTime
	// Distillation tracking
	LastDistilledAt *LocalTime // When task was last distilled for learnings
	// UI tracking
	LastAccessedAt *LocalTime // When task was last accessed/opened in the UI
	// Archive state for preserving worktree state when archiving
	ArchiveRef          string // Git ref storing stashed changes (e.g., "refs/task-archive/123")
	ArchiveCommit       string // Commit hash at time of archiving
	ArchiveWorktreePath string // Original worktree path before archiving
	ArchiveBranchName   string // Original branch name before archiving
	// Where this task ran, as decided by the task.placement hook. An empty target
	// means this machine, which is every task unless a placement plugin is
	// installed. Recorded so a result can be traced back to the machine that
	// produced it: once tasks run on four hosts, a suite that only fails on one of
	// them is indistinguishable from a real bug without it.
	PlacementTarget string // Host the task ran on ("" = local)
	PlacementReason string // The resolver's explanation for that choice
}

Task represents a task in the database.

func (*Task) EffectivePermissionMode added in v0.2.40

func (t *Task) EffectivePermissionMode() string

EffectivePermissionMode resolves the permission mode a task should run with, falling back to the legacy DangerousMode boolean and finally the default.

func (*Task) EnvMap added in v0.3.16

func (t *Task) EnvMap() map[string]string

EnvMap parses a task's EnvJSON override blob into a map. A malformed or empty blob yields an empty (never nil) map, so callers can range over it without a nil check. This is the read side of the per-step env feature: the pipeline stores a step's `env:` map as JSON in EnvJSON, and the executor renders it into a process-env prefix on the claude command.

func (*Task) HasArchiveState

func (t *Task) HasArchiveState() bool

HasArchiveState returns true if the task has saved archive state.

func (*Task) IsAcceptEdits added in v0.3.1

func (t *Task) IsAcceptEdits() bool

IsAcceptEdits reports whether the task runs in accept-edits (acceptEdits) mode.

func (*Task) IsAutoPermission added in v0.2.40

func (t *Task) IsAutoPermission() bool

IsAutoPermission reports whether the task runs in Claude Code's auto mode.

func (*Task) IsDangerous added in v0.2.40

func (t *Task) IsDangerous() bool

IsDangerous reports whether the task runs with permissions fully bypassed.

type TaskLog

type TaskLog struct {
	ID        int64
	TaskID    int64
	LineType  string // "output", "tool", "error", "system"
	Content   string
	CreatedAt LocalTime
}

TaskLog represents a log entry for a task.

type TaskPlacement added in v0.3.28

type TaskPlacement struct {
	Target  string // Host the task runs on ("" = this machine)
	Reason  string // The resolver's explanation
	WorkDir string // The checkout on that host ("" for local)
	Decided bool   // Whether placement has been decided at all
}

TaskPlacement is a task's recorded placement decision: where it runs, why, and the checkout it was given on that host.

Decided is the state placement_target alone cannot express. An empty target is a real answer meaning "run here", so without a separate marker "the resolver chose local" and "the resolver was never asked" read identically — and a task that had been deliberately placed locally would be re-asked on every retry.

type TaskType

type TaskType struct {
	ID           int64
	Name         string // e.g., "code", "writing", "thinking"
	Label        string // Display label
	Instructions string // Prompt template for this type
	SortOrder    int    // For UI ordering
	IsBuiltin    bool   // Protect default types from deletion
	CreatedAt    LocalTime
}

TaskType represents a configurable task type with its prompt instructions.

type TrashedTask added in v0.3.16

type TrashedTask struct {
	ID           int64
	Title        string
	Project      string
	WorktreePath string
	DeletedAt    time.Time
}

TrashedTask is a lightweight view of a soft-deleted task for the trash listing and the sweep — it deliberately avoids the full Task scan so new columns there never need threading through here.

type WorktreeRef added in v0.3.30

type WorktreeRef struct {
	TaskID       int64
	Title        string
	Project      string
	Status       string
	WorktreePath string
	ArchivePath  string
}

WorktreeRef is one task row's claim on a directory: the live worktree and the path an archive would be restored to. Used by the worktree audit, which needs every row that names a directory regardless of status.

Jump to

Keyboard shortcuts

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