Score-weighted relationship between a fresh prompt’s artifacts and
every prior task’s artifacts. Higher score = stronger continuation
signal. Threshold tuning is the caller’s job; v0.6.0 auto-link
keeps anything with score > 0.0.
One row of the task list rendered by the TUI: enough to render the
list view without round-tripping for each task. event_count joins
events_index so we don’t need a second query per row.
Append an external reference to tasks.external. The column is
stored as a comma-separated list — small, append-mostly, no
uniqueness constraint. Acceptable shapes (loose, not enforced):
beads:claude-memory-rsw, github:#42, jira:PROJ-1234.
Embed up to limit events that still need a vector for the embedder’s model,
and store them. Returns how many were embedded this call. Shared by
embed-on-ingest (small batch after ingest_new_events) and
embed --backfill (looped until it returns 0). Every pending text gets a
vector — including short boilerplate — so nothing is re-scanned next pass;
retrieval-side filtering (crate::embed::is_embeddable) decides what’s
worth surfacing.
Events that have no up-to-date embedding for model — either never embedded
or embedded by a different model. Pulls the text straight from search_fts.
limit bounds the batch; pass a large value to drain.
Find tasks whose events overlap the given artifacts on any
dimension we have a signal for. Weights:
shared linked_issue → +1.0 (strongest, ticket id is unique)
shared commit_hash → +0.8 (commits are nearly unique)
shared file path → +0.3 (files churn across tasks)
Find tasks (open or closed) whose events reference any of the given
issue identifiers (FIN-868, JIRA-123, INC-7…). Looks at the
per-event artifacts.linked_issues column populated on ingest.
Returns (task_id, status) deduplicated, most-recent first. Used
by the v0.5.0 Phase C auto-link flow to recognise that a fresh
prompt is a continuation of a prior task.
Read only the tail of the JSONL log since the last call. The cheap path
for hot loops (every MCP tool invocation): scan to the marker, ingest
the rest, update the marker.
All tasks for a project, ordered with open ones first (by recency)
then closed ones. The TUI list view binds directly to this — there
is no other consumer, so the shape is tuned for that callsite.
Re-run artifact extraction over every event of a task and write the
result back to events_index.artifacts. Used to backfill events
that were ingested before Phase B landed. Returns the number of
events touched. Wipes the pack cache for the task so the next
render reflects the freshly extracted artifacts.
Semantic search over a project’s embeddings. Scores every stored vector for
model against query_vec by cosine, returns the top k by score. The
caller embeds the query with the same embedder so the model ids match.
Pure vector ranking for now; recency / tier / contradiction weighting layer
on top in later phases.
Set or replace tasks.goal for an existing task. Caller is
expected to have validated the task exists (via task_exists); we
don’t error on no-op rows so the upsert pattern is uniform.
Set or replace the closure metadata. Pass None for outcome_tag
to leave it unset; pass Some("done"|"abandoned"|"superseded")
for a structured tag. Free-text outcome is the primary field.
Aggregate artifacts (commit hashes, PR URLs, ticket IDs, files,
branches) across every event of a task, deduplicated. Reads the
per-event JSON payload that ingest_new_events populated. Skips
events whose artifacts column is NULL or unparseable rather than
failing the pack render.
Returns whether a task with this id has been recorded in the derived
state. Cheap O(1) lookup against the tasks primary key. Callers
should run ingest_new_events first if they want to see the latest
JSONL state.
Status string for an existing task (e.g. “open”, “closed”). Returns
None when the task is unknown — caller decides whether that’s a
hard error or a route-to-pending case.
Top-level tasks for a project (those with no parent), ordered like
list_tasks_by_project — open first, then by recency. The roots of
the list --tree view.
True if setting new_parent as the parent of task_id would create a
cycle (i.e. new_parent is task_id itself or a descendant of it).
Walks ancestors of new_parent; a depth cap guards against pre-existing
corrupt cycles.