Dashboard job envelopes
std/dashboard/jobs defines the portable status event Harn emits for Jobs
surfaces in local Burin and Harn Cloud. The contract is intentionally a
dashboard-facing envelope, not a scheduler API: Harn runtimes and connectors
produce ordered events, and hosts render queue/run/approval/DLQ/receipt state
from normalized fields.
import { dashboard_job_event, dashboard_jobs_view } from "std/dashboard/jobs"
let event = dashboard_job_event(
"run.started",
{
job_id: "daily-digest",
run_id: "run-001",
source_timestamp: "2026-05-11T14:01:10Z",
workflow_id: "workflow://local/start-my-day",
},
)
let view = dashboard_jobs_view([event])
log(view.jobs[0].status)
Event envelope
dashboard_job_event(kind, input, options?) returns
harn.dashboard_job_event.v1:
| Field | Purpose |
|---|---|
kind | Event kind such as run.queued, approval.requested, dlq.created, or receipt.available |
source | Runtime and environment, for example local Harn or Harn Cloud |
source_clock | Source clock label plus timestamp for replayable ordering |
tenant_id, workspace_id | Optional partition keys for cloud and multi-workspace hosts |
job_id | Stable dashboard job key |
run_id, workflow_id, trigger_id, binding_id, event_id | Runtime lineage where applicable |
status | Host-renderable state: queued, running, waiting approval, succeeded, failed, DLQ, canceled, and related states |
queue, queue_depth, priority, attempt, max_attempts | Queue and retry rendering hints |
approval | First-class approval wait/decision state for approval events |
dlq | First-class DLQ state for replay and dismissal flows |
receipt_refs, replay_refs, related_refs | Links or ids for audit receipts, replay fixtures, and source records |
action_intents | Host-owned actions such as opening the job, reviewing an approval, replaying DLQ, or dismissing DLQ |
raw_payload | Original local or cloud payload kept separate from normalized render fields |
source_clock.timestamp is mandatory. Run events require run_id, approval
events require approval.request_id, DLQ events require dlq.dlq_id,
receipt.available requires at least one receipt ref, and
replay_fixture.available requires at least one replay ref.
Set raw_payload_retained: false when building an event to keep normalized
status fields while omitting the original runtime payload.
Event kinds
The stdlib maps these event kinds to default statuses:
| Kind | Default status |
|---|---|
scheduled_job.created, scheduled_job.updated | scheduled |
scheduled_job.canceled | canceled |
run.queued | queued |
run.started, run.progress, approval.approved | running |
approval.requested | waiting_approval |
run.succeeded | succeeded |
run.failed, approval.denied, approval.expired | failed |
dlq.created | dlq |
dlq.replayed | queued |
dlq.dismissed | canceled |
receipt.available, replay_fixture.available | unknown; these add refs without changing the current card status |
Callers can override status when a runtime has a more specific local state,
but hosts should be able to render a useful card from the default mapping.
Static jobs view
dashboard_jobs_view(events, {emit?}) dedupes an ordered event stream and
reduces it into harn.dashboard_job_card.v1 cards. The reducer is intentionally
order-based: deterministic fixtures can drive a static Burin Home Jobs view
without a live scheduler or database.
import { dashboard_job_event, dashboard_jobs_view } from "std/dashboard/jobs"
let events = [
dashboard_job_event(
"run.succeeded",
{job_id: "daily-digest", run_id: "run-001", source_timestamp: "2026-05-11T14:03:00Z"},
),
]
let view = dashboard_jobs_view(events, {emit: true, topic: "dashboard.jobs.events"})
for job in view.jobs {
log(job.job_id + ": " + job.status)
}
When emit is true, each unique event is appended to the EventLog as
kind = "dashboard_job_event" and the view returns
harn.dashboard_job_event_emit_receipt.v1 receipts.
Host boundary
Action intents are descriptive only. Non-navigation intents such as approval
decisions, DLQ replay, and DLQ dismissal must set requires_approval: true;
dashboard_job_validate rejects write-like intents that omit that gate. Hosts
own the approval UX, persistence, undo semantics, and concrete side effects.