task

package
v0.18.6 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package task implements nt's todo.txt task model with the lossless round-trip guarantee from SPEC §4: a file is parsed into an ordered list of nodes (each a parsed task or a preserved raw line), and an unmodified line is re-emitted byte-for-byte. Only when a task is mutated do we re-render it from structured fields, touching only the tokens nt owns and preserving any unknown key:value tokens another todo.txt client may have written.

Index

Constants

View Source
const (
	BucketOverdue  = "Overdue"
	BucketToday    = "Today"
	BucketThisWeek = "This week"
	BucketLater    = "Later"
	BucketNoDate   = "No date"
	BucketDone     = "Done"
)

Date buckets for the planner/agenda grouping, in display order.

Variables

DueBuckets is the bucket order for a date-grouped task view.

Functions

func AdvanceDue added in v0.4.0

func AdvanceDue(t *Task, today string) string

AdvanceDue returns the task's due advanced to its next occurrence — one period past the current due (or today if undated), rolled forward to on/after today. Used by `nt skip` to move a recurring task forward without completing it. Returns "" if the task isn't recurring.

func BlockedIDs

func BlockedIDs(tasks []*Task) map[string]bool

BlockedIDs returns the set of task ULIDs that are blocked by an open task (SPEC §9). A task B with `blocks:X` blocks task X for as long as B is not done; X is then hidden from default listings. Tasks caught in a dependency cycle are deliberately NOT marked blocked — none could ever unblock, so hiding them all would be an invisible deadlock; they stay visible so the user can break the cycle (and `nt doctor` reports it).

func DanglingBlocks added in v0.4.0

func DanglingBlocks(tasks []*Task) []string

DanglingBlocks returns the ULIDs of tasks whose blocks: target no longer exists (e.g. the blocked task was deleted) — a stale edge `nt doctor` reports.

func DepCycles added in v0.4.0

func DepCycles(tasks []*Task) [][]string

DepCycles returns each dependency cycle among open tasks as a list of task ULIDs (e.g. A blocks B, B blocks A → ["A","B"]). Because the blocking graph is functional, a cycle is found by following each chain until it revisits a node already on the current path.

func DueBucket added in v0.4.0

func DueBucket(t *Task, today, weekEnd string) string

DueBucket assigns a task to a planner bucket relative to today and weekEnd (both YYYY-MM-DD). Comparisons use the date prefix, so a due with a time-of-day (due:…T17:00) still buckets by its calendar day — the rule the TUI and the web agenda share, kept here so they can't drift (and the TUI no longer mis-files a same-day timed due into "This week").

func EffectiveStatus

func EffectiveStatus(t *Task, isBlocked bool) string

EffectiveStatus is the display status accounting for dependency blocking: a not-done task that is the target of an open blocker shows as "blocked" even without an explicit s:blocked marker.

func IsPositional

func IsPositional(handle string) bool

IsPositional reports whether a handle is a positional "task:N" / "N" reference rather than a stable ULID — so adapters can refuse it from non-interactive callers, where the list index may have shifted between read and act (§7.2).

func NextDue added in v0.4.0

func NextDue(t *Task, today string) string

NextDue computes the next occurrence's due date for a recurring task, given the completion/reference date `today`:

  • Strict recurrences (rec:+3d, rec:+weekly) anchor to the task's scheduled due and roll FORWARD to the next slot on/after today — so a task completed late never spawns an already-overdue occurrence, and the cadence stays pinned to the calendar (e.g. "rent on the 1st").
  • Plain recurrences (rec:3d, rec:weekly) schedule from `today` itself — the "N days after I last did it" semantics (e.g. "water the plant 3d after").

Returns "" when the task isn't recurring.

func SortByUrgency

func SortByUrgency(ts []*Task)

SortByUrgency orders tasks most-urgent first (stable).

func Urgency

func Urgency(t *Task) float64

Urgency scores a task by priority, due-date proximity, and doing-state. It's the single ranking behind `nt list --sort urgency`, the TUI's grouping, and `nt ready` / the MCP server, so the three never drift (SPEC §9).

func VisibleInList added in v0.4.0

func VisibleInList(t *Task, blockedByDep, includeDone, includeBlocked bool) bool

VisibleInList reports whether a task should appear in a default task listing, given the show-done / show-blocked toggles. It is the one visibility rule every surface shares (SPEC §9), extracted here so the CLI, TUI, web, and MCP can't drift on it:

  • a done task hides unless includeDone;
  • an open task that is dependency-blocked hides unless includeBlocked.

blockedByDep is raw membership in the blocked set (see BlockedIDs) — the "& not-done" part is applied here so callers pass the set lookup directly.

Types

type Doc

type Doc struct {
	Nodes []Node
	// contains filtered or unexported fields
}

Doc is an ordered list of nodes — the in-memory model of a tasks file. It preserves line order and the file's trailing-newline state so an unmodified document renders byte-identically (SPEC §4).

func Parse

func Parse(data []byte) *Doc

Parse builds a Doc from raw file bytes.

func (*Doc) Append

func (d *Doc) Append(t *Task)

Append adds a task as a new node. If the document is non-empty and lacks a trailing newline, one is added first so the new task starts on its own line.

func (*Doc) FindByID

func (d *Doc) FindByID(id string) *Task

FindByID returns the task with the given ULID, or nil.

func (*Doc) Remove

func (d *Doc) Remove(id string) (before string, ok bool)

Remove deletes the node holding the task with id, returning the removed task's raw line (its before-image) for the undo journal.

func (*Doc) Render

func (d *Doc) Render() []byte

Render serializes the Doc back to file bytes.

func (*Doc) ReplaceByID

func (d *Doc) ReplaceByID(id string, t *Task) bool

ReplaceByID swaps in a new task for the node with the given id, returning false if no such task exists.

func (*Doc) Resolve

func (d *Doc) Resolve(handle string) (t *Task, ambiguous bool)

Resolve maps a user-supplied handle to a task. It accepts a full ULID, the displayed trailing short code (id[len-6:]), or a 1-based positional "task:N" reference (interactive-only, best-effort — SPEC §7.2). ambiguous is true when a short code matches more than one task.

func (*Doc) Tasks

func (d *Doc) Tasks() []*Task

Tasks returns the parsed tasks in document order.

type Node

type Node struct {
	Task *Task
	Raw  string // used when Task == nil
}

Node is one line of the file: a parsed Task, or a preserved raw line (blank lines, comments, anything that isn't a task). Exactly one field is set.

type Review added in v0.10.0

type Review struct {
	Overdue       []*Task  // actionable, past due
	Stale         []*Task  // open ≥ StaleDays, not overdue, no progress
	Undated       []*Task  // actionable, no due date
	StuckProjects []string // projects whose every open task is blocked
	StaleDays     int      // the threshold used, for display
}

Review is the weekly-triage breakdown surfaced by `nt review` (CLI) and the web /review: what needs a decision. Shared here so both surfaces bucket identically (SPEC §9, the shared query layer).

func BuildReview added in v0.10.0

func BuildReview(tasks []*Task, blocked map[string]bool, staleDays int, today string) Review

BuildReview triages tasks into the review buckets. today is ISO (YYYY-MM-DD); blocked maps task id → dependency-blocked (from BlockedIDs). A task appears in at most one task bucket (overdue wins over stale wins over undated).

type Task

type Task struct {
	Done      bool
	Priority  byte   // 0, or 'A'..'Z'
	Completed string // YYYY-MM-DD or ""
	Created   string // YYYY-MM-DD or ""
	Text      string // description, including inline +project / @tag / [[link]]
	// contains filtered or unexported fields
}

Task is a single todo.txt line, parsed.

func CompletedSince

func CompletedSince(tasks []*Task, since string) []*Task

CompletedSince returns the completed tasks, newest completion first, optionally bounded to those completed on or after `since` (a YYYY-MM-DD date; "" = no bound). This is the core rule behind both the TUI Logbook and `nt log`, so the ordering and the meaning of "completed" live in the domain, not an adapter.

A since bound excludes tasks with no completion date (an empty date sorts before any real one), which is the desired behaviour for "what did I finish in the last N days".

func New

func New(text string) *Task

New builds a fresh task with a ULID. Callers add text/metadata then it is appended to a Doc.

func ParseLine

func ParseLine(line string) (*Task, bool)

ParseLine parses a single line into a Task (raw, unmodified). Used by the undo engine to restore a before-image so it renders byte-identically.

func SpawnNext

func SpawnNext(t *Task, today string) *Task

SpawnNext builds the next occurrence of a recurring task (SPEC §9). The new task copies the description, priority, recurrence, source, workstream, and parent, gets a fresh ULID, and is scheduled by NextDue. Call it while the original is still open (before SetDone moves the priority to a pri: key). Returns nil if the recurrence spec is empty or unparseable (so no malformed duplicate spawns).

func (t *Task) AddLink(target string)

AddLink appends a [[target]] link to the description if not already present.

func (*Task) AddTag added in v0.16.0

func (t *Task) AddTag(tag string)

AddTag adds an @tag to the description if not already present (no leading @).

func (*Task) Blocks

func (t *Task) Blocks() string

func (*Task) Discovered

func (t *Task) Discovered() string

Discovered is the ULID of the task this one was discovered while working on — provenance for work an agent surfaced mid-task (key: discovered:<ULID>).

func (*Task) Due

func (t *Task) Due() string

func (*Task) EnsureID

func (t *Task) EnsureID()

EnsureID assigns a ULID if the task lacks one (SPEC §4: hand-added lines get an id on the next mutation that touches them).

func (*Task) ID

func (t *Task) ID() string

ID returns the task's ULID (empty if none yet).

func (*Task) Key added in v0.4.0

func (t *Task) Key(name string) string

Key returns the value of an arbitrary key:value token (empty if absent), so callers outside the package can read/normalize tokens nt doesn't model.

func (*Task) Line

func (t *Task) Line() string

Line returns the on-disk representation: the original raw line when unmodified, or a freshly rendered canonical line when mutated.

func (t *Task) Links() []string

func (*Task) Parent

func (t *Task) Parent() string

func (*Task) Projects

func (t *Task) Projects() []string

Projects, Tags, and Links are derived from the description text.

func (*Task) Recur

func (t *Task) Recur() string

func (*Task) RemoveTag added in v0.16.0

func (t *Task) RemoveTag(tag string)

RemoveTag drops an @tag from the description (no-op if absent).

func (*Task) SetDone

func (t *Task) SetDone(done bool, today string)

SetDone toggles completion. Marking done preserves any (A) priority as a pri:A key (SPEC §4); reopening restores it.

func (*Task) SetKey

func (t *Task) SetKey(key, val string)

SetKey sets or (empty val) deletes an arbitrary key:value, e.g. due, parent.

func (*Task) SetPriority

func (t *Task) SetPriority(p byte)

SetPriority sets (0 clears) the priority. No-op on done tasks beyond storing the pri key.

func (*Task) SetProject added in v0.16.0

func (t *Task) SetProject(project string)

SetProject replaces the task's +project(s) with the given one ("" clears them).

func (*Task) SetState

func (t *Task) SetState(s string)

SetState sets s:doing / s:blocked, or clears it for "open". "done"/"" are handled via SetDone by the caller.

func (*Task) SetText

func (t *Task) SetText(s string)

SetText replaces the description (used by rename).

func (*Task) SetTitle added in v0.16.0

func (t *Task) SetTitle(title string)

SetTitle replaces the prose description while preserving the inline metadata tokens (@tag, +project, [[link]]) — so a typo fix doesn't drop a task's tags.

func (*Task) Source

func (t *Task) Source() string

func (*Task) Start added in v0.4.0

func (t *Task) Start() string

Start is the threshold/defer date (todo.txt "t:" key): the task is not actionable until this date. Agenda/ready views hide future-start tasks.

func (*Task) State

func (t *Task) State() string

func (*Task) Status

func (t *Task) Status() string

Status returns a normalized status string for filtering/display.

func (*Task) Tags

func (t *Task) Tags() []string

Jump to

Keyboard shortcuts

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