Documentation
¶
Overview ¶
Package store is worklog's persistence layer: a per-project SQLite database (`.solstice/work.db`) holding the task tree, its blocking edges, and the durable record of what was decided and done across agent sessions.
Index ¶
- Constants
- Variables
- func DetectKind(url string) string
- func GetSectionFromBody(body, path string) (string, bool)
- func Resolve(dir string) (string, error)
- func SetSectionInBody(body, path, content string) (string, bool)
- type ChildRef
- type CreateTaskInput
- type Decision
- type FindOpts
- type FindResult
- type JournalEntry
- type Link
- type ListOpts
- type Section
- type Session
- type Store
- func (s *Store) ActiveBlockers(taskID int64) ([]Task, error)
- func (s *Store) AddDecision(slug, decision, rationale string) (*Decision, error)
- func (s *Store) AddDep(slug, blockerSlug string) error
- func (s *Store) AddJournal(slug, text string) (*JournalEntry, error)
- func (s *Store) AddLink(slug, url, kind, label string) (*Link, error)
- func (s *Store) Close() error
- func (s *Store) CreateTask(in CreateTaskInput) (*Task, error)
- func (s *Store) CurrentSessionID() int64
- func (s *Store) Decisions(taskID int64) ([]Decision, error)
- func (s *Store) Detail(slug string) (*TaskDetail, error)
- func (s *Store) EndCurrentSession() error
- func (s *Store) EndLatestOpenSession(summary string) (*Session, error)
- func (s *Store) EndSession(id int64, summary string) (*Session, error)
- func (s *Store) Find(o FindOpts) (*FindResult, error)
- func (s *Store) GetSection(slug, path string) (string, error)
- func (s *Store) GetSession(id int64) (*Session, error)
- func (s *Store) GetTask(slug string) (*Task, error)
- func (s *Store) Links(taskID int64) ([]Link, error)
- func (s *Store) ListTasks(o ListOpts) ([]TaskView, error)
- func (s *Store) NextTask() (*TaskView, error)
- func (s *Store) RecentJournal(limit int) ([]JournalEntry, error)
- func (s *Store) RemoveDep(slug, blockerSlug string) error
- func (s *Store) SetSection(slug, path, content string) (*Task, error)
- func (s *Store) StartSession(agent string) (*Session, error)
- func (s *Store) TOC(slug string) ([]Section, error)
- func (s *Store) TaskJournal(taskID int64, limit int) ([]JournalEntry, error)
- func (s *Store) Tree(rootSlug string) ([]TreeNode, error)
- func (s *Store) UpdateTask(in UpdateTaskInput) (*Task, error)
- func (s *Store) WarmContext(journalLimit int) (string, error)
- type Task
- type TaskDetail
- type TaskView
- type TreeNode
- type UpdateTaskInput
Constants ¶
const DirName = ".solstice"
DirName is the per-project directory that holds the database, reusing the existing `.solstice/` convention.
const FileName = "work.db"
FileName is the database file within DirName.
Variables ¶
var ErrNotFound = errors.New("not found")
ErrNotFound is returned when a task or other record does not exist.
var Statuses = []string{"pending", "in_progress", "blocked", "done", "dropped"}
Statuses are the five values a task may hold, aligned with the harness's own task vocabulary. "blocked" is a manual override; blocking is also computed from dependency edges (see ActiveBlockers).
Functions ¶
func DetectKind ¶
DetectKind infers a link kind from a URL so callers can just pass the URL.
func GetSectionFromBody ¶
GetSectionFromBody returns the content under a heading path (its subsections included), excluding the heading line itself.
func Resolve ¶
Resolve returns the database path for the project containing dir, walking up from dir to find an existing DirName; if none is found it returns the path dir/DirName/FileName so a fresh database is created in place.
func SetSectionInBody ¶
SetSectionInBody replaces the content under a heading path, preserving the heading line, and returns the new body.
Types ¶
type ChildRef ¶
type ChildRef struct {
Slug string `json:"slug"`
Title string `json:"title"`
Status string `json:"status"`
}
ChildRef is a lightweight reference to a child task.
type CreateTaskInput ¶
type CreateTaskInput struct {
Title string
Slug string // optional; derived from Title when empty
Parent string // optional parent slug
Body string
Status string // optional; defaults to pending
Priority int // optional; defaults to 3
BlockedBy []string
}
CreateTaskInput carries the fields for a new task.
type Decision ¶
type Decision struct {
ID int64 `json:"id"`
TaskSlug string `json:"task_slug,omitempty"`
SessionID int64 `json:"session_id,omitempty"`
Ts string `json:"ts"`
Decision string `json:"decision_md"`
Rationale string `json:"rationale_md,omitempty"`
}
Decision is a choice made while executing a task — the "why we did it this way" record that turns a finished task into something you can learn from later. Stored as rows (queryable) but rendered as a "## Decisions" section when a task is shown.
type FindOpts ¶
type FindOpts struct {
Query string // free text matched against titles, bodies, decisions, journal, link URLs
Status string // restrict matched tasks to this status
Since string // RFC3339 lower bound on decision/journal timestamps
HasDecisions bool // only tasks that carry at least one decision
}
FindOpts constrains a work-find search. Any subset may be set.
type FindResult ¶
type FindResult struct {
Tasks []TaskView `json:"tasks,omitempty"`
Decisions []Decision `json:"decisions,omitempty"`
Journal []JournalEntry `json:"journal,omitempty"`
}
FindResult is what a search turned up, kept in three buckets so "what was decided" and "what was done" are answerable, not just "what's open".
type JournalEntry ¶
type JournalEntry struct {
ID int64 `json:"id"`
TaskSlug string `json:"task_slug,omitempty"`
SessionID int64 `json:"session_id,omitempty"`
Ts string `json:"ts"`
Kind string `json:"kind"`
Text string `json:"text_md"`
}
JournalEntry is one line in the running log of what happened — the trail a fresh session reads to reconstruct where the last one left off.
type Link ¶
type Link struct {
ID int64 `json:"id"`
Kind string `json:"kind"`
URL string `json:"url"`
Label string `json:"label,omitempty"`
CreatedAt string `json:"created_at"`
}
Link ties a task to an external artifact — most importantly a GitHub issue or PR by its full URL, so "which task touched issue #412" is a lookup, not a grep through prose.
type ListOpts ¶
type ListOpts struct {
Status string // exact status filter; empty for any
Parent string // parent slug; "" for any parent
IncludeClosed bool // when false, done/dropped tasks are omitted
}
ListOpts filters ListTasks.
type Section ¶
type Section struct {
Path string `json:"path"`
Level int `json:"level"`
Title string `json:"title"`
}
Section identifies one markdown heading within a task body. Path is the slash-joined chain of ancestor headings ("Design/Storage"), so nested sections are addressable without ambiguity.
func TOCFromBody ¶
TOCFromBody lists the sections in a body.
type Session ¶
type Session struct {
ID int64 `json:"id"`
StartedAt string `json:"started_at"`
EndedAt string `json:"ended_at,omitempty"`
Agent string `json:"agent"`
Summary string `json:"summary_md,omitempty"`
}
Session is one agent working session: the unit worklog attributes decisions and journal entries to, so a later session can see who did what and when.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a handle to one project's worklog database.
func Open ¶
Open opens (creating if needed) the database at path, applies the schema, and enables WAL so concurrent agent sessions sharing the tree do not clobber each other. Pass ":memory:" for an ephemeral database (tests).
func (*Store) ActiveBlockers ¶
ActiveBlockers returns the tasks still blocking the given task — those dependency targets that are not yet closed. A done or dropped dependency no longer blocks and is omitted, matching solstice's rule.
func (*Store) AddDecision ¶
AddDecision records a decision against a task, attributed to the current session, and journals it.
func (*Store) AddJournal ¶
func (s *Store) AddJournal(slug, text string) (*JournalEntry, error)
AddJournal appends a freeform note, optionally against a task (slug "" records a project-level note).
func (*Store) AddLink ¶
AddLink attaches a link to a task. When kind is empty it is detected from the URL. The addition is journaled.
func (*Store) CreateTask ¶
func (s *Store) CreateTask(in CreateTaskInput) (*Task, error)
CreateTask inserts a task, optionally under a parent and with blocking edges, and records a "created" journal entry.
func (*Store) CurrentSessionID ¶
CurrentSessionID returns the session writes are attributed to, or 0 if none.
func (*Store) Detail ¶
func (s *Store) Detail(slug string) (*TaskDetail, error)
Detail assembles the full record for one task.
func (*Store) EndCurrentSession ¶
EndCurrentSession closes the in-process session (set by StartSession), if any. Safe to call more than once.
func (*Store) EndLatestOpenSession ¶
EndLatestOpenSession closes the most recent session that has no end time, recording summary when non-empty. It is the entry point a Stop hook uses, so it need not know the session id. A no-op when nothing is open.
func (*Store) EndSession ¶
EndSession records summary against the session and stamps its end time. When summary is empty the existing summary is left untouched.
func (*Store) Find ¶
func (s *Store) Find(o FindOpts) (*FindResult, error)
Find searches across tasks, decisions, and the journal.
func (*Store) GetSection ¶
GetSection returns one section of a task's body.
func (*Store) GetSession ¶
GetSession returns one session by id.
func (*Store) NextTask ¶
NextTask returns the highest-priority actionable task — pending or in_progress, with no active blockers — or nil when nothing is actionable.
func (*Store) RecentJournal ¶
func (s *Store) RecentJournal(limit int) ([]JournalEntry, error)
RecentJournal returns the most recent entries across the whole project, newest first, joined to their task slug when they have one.
func (*Store) SetSection ¶
SetSection replaces one section of a task's body, leaving the rest untouched.
func (*Store) StartSession ¶
StartSession opens a new session and marks it current, so subsequent writes (decisions, journal) are attributed to it. agent is a free label, typically the client name from the MCP handshake.
func (*Store) TaskJournal ¶
func (s *Store) TaskJournal(taskID int64, limit int) ([]JournalEntry, error)
TaskJournal returns a task's own journal entries, newest first.
func (*Store) Tree ¶
Tree returns the forest of top-level tasks (rootSlug == "") or the subtree rooted at a given slug. Every node carries closed tasks too, so the full history of a branch stays visible.
func (*Store) UpdateTask ¶
func (s *Store) UpdateTask(in UpdateTaskInput) (*Task, error)
UpdateTask applies a partial update. A status change to a terminal value stamps closed_at (and clears it when reopened), and is journaled.
type Task ¶
type Task struct {
ID int64 `json:"id"`
Slug string `json:"slug"`
ParentID int64 `json:"parent_id,omitempty"`
Title string `json:"title"`
Body string `json:"body_md,omitempty"`
Status string `json:"status"`
Priority int `json:"priority"`
Position int `json:"position"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
ClosedAt string `json:"closed_at,omitempty"`
}
Task is one node in the work tree.
type TaskDetail ¶
type TaskDetail struct {
Task
Blockers []string `json:"blocked_by,omitempty"`
Children []ChildRef `json:"children,omitempty"`
Links []Link `json:"links,omitempty"`
Decisions []Decision `json:"decisions,omitempty"`
Journal []JournalEntry `json:"journal,omitempty"`
}
TaskDetail is the full picture of one task: its body, what still blocks it, its children, and — the point of worklog — the links, decisions, and journal that record what was done and why.
func (*TaskDetail) Markdown ¶
func (d *TaskDetail) Markdown() string
Markdown renders a task detail as human-readable markdown, overlaying the stored links and decisions as their own sections beneath the authored body.
type TaskView ¶
type TaskView struct {
Task
Blockers []string `json:"blocked_by,omitempty"`
ChildCount int `json:"child_count,omitempty"`
Actionable bool `json:"actionable"`
}
TaskView is a task plus the derived facts a reader needs to decide what to do next: its still-active blockers and whether it has children.