Skip to content

priority-triage Reference

The Loom workflow that powers the Morning Ritual feature. Source: optimalOS/workflows/priority-triage.ts.

Trigger

Manual only. No cron schedule attached.

Two trigger surfaces:

  • HTTP: POST /api/triage/rerun (optimalOS/src/routes/triage.ts:16-60).
  • Loom UI: the manual trigger on the workflow's strand row.

The Rerank button on the TODAY widget calls the HTTP endpoint.

Logical steps

The workflow currently runs as a single Loom step run with internal phasing. The 9 logical phases below are the conceptual steps the code executes. Per-step Loom UI visibility is on the roadmap.

#PhaseWhat it doesFailure handling
1snapshot_inputsQuery open unlocked tasks, unconsumed briefs, unapplied overrides, locked task ids. Hash for replay.If no open tasks, marks run succeeded with summary "No open unlocked tasks to score."
2assemble_promptBuild the system prompt + user content (CLAUDE.md, memories, tasks, briefs, overrides, caps). Estimate tokens, check vs 950 k hard limit per chunk.If estimated tokens exceed limit, throws an Error with the chunk number; workflow fails.
3ship_to_ollamaPOST to triage.ollama_url + "/v1/chat/completions" with stream=false, response_format={type:"json_object"}, temperature=0.2, 10-minute timeout. Bearer token added if configured.OllamaError with stage network / http. No retry.
4parse_responseJSON.parse model output, zod-validate against OllamaResponseSchema.OllamaError("parse") or OllamaError("schema").
5enforce_distributionServer-side: recompute scores from model's I/U/C/E values, snap each task's lane to the score-derived threshold, auto-demote excess past lane caps cascading (lowest unlocked first). Locked tasks exempt.No rejection. Populates distribution_warning if demotions occurred.
6write_backInsert score_history rows (one per scored task). Update tasks denorm columns (current_score, current_lane, current_rank, last_scored_at). All in one transaction. Locked tasks' denorm columns are not updated.Any insert/update failure rolls back the transaction.
7mark_briefs_consumedUPDATE briefs SET consumed_in_run_id = ? for every brief included in the prompt.Idempotent.
8apply_override_acksUPDATE score_overrides SET applied_to_run_id = ? for every unapplied override included in the prompt.Idempotent.
9emit_summaryUPDATE triage_runs SET run_summary, clash_summary, distribution_warning. Broadcast triage_run_completed (or triage_run_failed) on the state hub.Best-effort; top-level catch ensures the failure path still emits an event.

Code references: optimalOS/workflows/priority-triage.ts:74-244.

Inputs

The workflow snapshots three live data sources at the start of every run:

SourceFilter
tasksstatus NOT IN ('done','completed') AND score_locked = 0.
briefsconsumed_in_run_id IS NULL.
score_overridesapplied_to_run_id IS NULL.
Locked tasksscore_locked = 1 — included in the prompt as "user locked this at LANE" so the model sees the constraint, but their lane is preserved verbatim.

Outputs

Per-task in score_history (one row per scored task per run):

text
{
  task_id, run_id,
  impact, urgency, confidence, effort,  // 1-5 each
  score,                                 // 0-1 (server-recomputed, authoritative)
  rank,                                  // dense, 1-based, per-lane
  lane,                                  // now | next | later | backlog
  reasoning,                             // model's text rationale
  clash_resolution,                      // optional, populated when lane was snapped
  sources_used,                          // JSON array of brief ids the model cited
  scored_at
}

Per-run in triage_runs:

text
{
  id, started_at, completed_at, status,
  trigger,                              // manual | api | scheduled
  model, ollama_url,
  prompt_tokens, completion_tokens,
  task_count, brief_count,
  distribution_warning,                 // populated when caps overflowed
  clash_summary,                        // populated when lanes were snapped
  run_summary,                          // model's overall summary
  error                                 // populated on failure
}

Batching

Default triage.batch_size = 25. Tasks split into chunks ≤ batch size; each chunk gets its own Ollama call. Briefs and overrides are sent with every chunk so the model sees identical context. Server-side, raw scores from all chunks are merged, deduplicated by task_id, normalized globally, then capped.

Set batch_size = 0 to disable batching. See Configuration.

Failure modes (summary)

The run is rejected only on:

  • JSON parse failure
  • zod schema validation failure
  • empty scores[] array

Distribution overflow never rejects — it auto-demotes. DB lock contention is not retried; the transaction either commits or rolls back atomically. Token-budget overrun fails immediately; there is no automatic 30-day-trim retry.

WebSocket events

triage_run_completed and triage_run_failed are broadcast through the state hub from optimalOS/src/routes/triage.ts:39-53. The Command Center bridges them to a window-level CustomEvent("triage:updated", ...) that the TODAY widget listens for.

Step-level events not shipped

The charter calls for a triage_run_step event for each phase. These are not implemented yet; only the run-level events fire.

Built by Carlos Lenis in Miami