Runs, Events & Streams
Hot Platform uses three core primitives for workflow execution: Runs, Events, and Streams. Understanding these concepts is essential for building effective Hot applications.
Runs
A Run is a single execution of a Hot function. Every function call creates a run, whether triggered by an API request, event, or schedule.
Run Lifecycle
| State | Description |
|---|---|
running | Worker is executing the function |
succeeded | Function completed successfully |
failed | Function threw an error or timed out |
cancelled | Run was cancelled before completion |
pending_retry | Function failed but will be retried automatically |
Runs with "retry" metadata that fail are temporarily set to pending_retry until the retry executes. See Retry Configuration for details.
Run Data
Every run captures:
{
"run_id": "run_abc123xyz",
"function": "::myapp::orders/process-order",
"status": "succeeded",
"input": {
"order_id": "ord_12345"
},
"result": {
"status": "processed",
"total": 99.99
},
"started_at": "2024-12-04T10:30:00Z",
"completed_at": "2024-12-04T10:30:02Z",
"duration_ms": 2150,
"trigger": {
"type": "event",
"event_id": "evt_xyz789"
}
}
Execution Trace
Hot captures a full execution trace for every run, showing:
- Each expression evaluated
- Intermediate values
- Function calls and returns
- Timing for each step
- Any errors with stack traces
Triggering Runs
Runs can be triggered in several ways:
1. API Call (via hot:call event)
curl -X POST https://api.hot.dev/v1/events \
-H "Authorization: Bearer $HOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "hot:call", "data": {"fn": "::myapp::orders/process-order", "args": [{"order_id": "12345"}]}}'
2. Event Handler
on-order-created
meta {on-event: "order:created"}
fn (event) {
process-order(event.data.order_id)
}
3. Schedule (recurring)
daily-report
meta {schedule: "0 0 * * *"}
fn () {
generate-report()
}
4. Dynamic Schedule (one-time or created at runtime)
// Schedule a function to run in 10 minutes
send("hot:schedule:new", {
fn: "::myapp::tasks/process",
args: [{task_id: "123"}],
schedule: "in 10 minutes"
})
See Dynamic Schedules for more details.
5. Direct Call (from another run)
process-batch fn (orders) {
// Each send creates a separate run
map(orders, (order) {
send("hot:call", {
fn: "::myapp::orders/process-order",
args: [order]
})
})
}
Events
Events are messages that trigger asynchronous workflows. They decouple event producers from consumers, enabling scalable and maintainable systems.
Event Structure
An Event in Hot has two fields:
Event type {
type: Str,
data: Any
}
The send function has two arities:
// Pass event type and data directly
send("user:created", {id: "usr_12345", email: "alice@example.com"})
// Or pass an Event
send(Event({type: "user:created", data: {id: "usr_12345", email: "alice@example.com"}}))
Sending Events
From Hot Code:
// Send an event after user creation
create-user fn (data) {
user insert-user(data)
// Send event for other handlers (send is a core function)
send("user:created", {
id: user.id,
email: user.email,
name: user.name
})
user
}
From the API:
curl -X POST https://api.hot.dev/v1/events \
-H "Authorization: Bearer $HOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "user:created",
"data": {"id": "usr_12345", "email": "alice@example.com"}
}'
From External Systems (Webhooks): Configure webhooks to forward events from services like Stripe, GitHub, or Slack directly to Hot.
Event Handlers
Define handlers using the on-event metadata:
::myapp::notifications ns
// Handle a specific event type
on-user-created meta {on-event: "user:created"}
fn (event) {
send-welcome-email(event.data.email)
}
Event Delivery
Hot guarantees at-least-once delivery for events:
- Events are persisted before acknowledgment
- Failed handlers can be retried automatically with configurable attempts and delay
- Retry status is visible in the Hot App UI
Streams
Streams provide real-time, bidirectional data flow for scenarios where request/response isn't sufficient.
Use Cases
- AI/LLM Responses - Stream tokens as they're generated
- Live Updates - Push data to clients in real-time
- Long-Running Operations - Report progress incrementally
- Bidirectional Communication - WebSocket-style interactions
Server-Sent Events (SSE)
Stream data to clients in real-time using ::hot::stream/data.
Hot code — emit chunks as they arrive:
handle-chat
meta { on-event: "chat:message" }
fn (event) {
// Call a streaming AI API
response ::anthropic::messages/post-stream({
model: "claude-sonnet-4-20250514",
max_tokens: 4096,
messages: [{role: "user", content: event.data.message}]
})
// Process stream and emit chunks to the client
process-stream(response.body, "")
}
// Recursive stream processor
process-stream fn (iter, accumulated: Str): Str {
result next(iter)
cond {
result.done => { accumulated }
=> {
delta or(result.value.data.delta.text, "")
// Emit chunk to client in real-time
::hot::stream/data("ai:delta", { text: delta })
process-stream(iter, concat(accumulated, delta))
}
}
}
JavaScript client — publish an event, then subscribe to the stream:
// 1. Publish event to trigger the handler
const eventRes = await fetch('/v1/events', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_type: 'chat:message',
event_data: { message: 'Hello!' }
})
});
const { data: { stream_id } } = await eventRes.json();
// 2. Subscribe to stream for real-time updates
const response = await fetch(`/v1/streams/${stream_id}/subscribe`, {
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Accept': 'text/event-stream'
}
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const text = decoder.decode(value);
// Parse SSE events (data: {...}\n\n format)
for (const line of text.split('\n')) {
if (line.startsWith('data: ')) {
const event = JSON.parse(line.slice(6));
if (event.type === 'stream:data') {
// Real-time chunk from ::hot::stream/data
appendToResponse(event.payload.text);
}
if (event.type === 'run:stop') {
// Run completed
console.log('Final result:', event.run.result);
}
}
}
}
Stream States
┌─────────┐ ┌─────────┐ ┌─────────┐
│ open │ -> │ active │ -> │ closed │
└─────────┘ └─────────┘ └─────────┘
│
v
┌─────────┐
│ error │
└─────────┘
Viewing Streams
Active and completed streams are visible in the Hot App:
- Connection status and duration
- Messages sent/received
- Bandwidth usage
- Error details
Monitoring
All runs, events, and streams are visible in the Hot App with:
- Real-time updates as executions happen
- Filtering by status, function, event type
- Full-text search across payloads
- Detailed drill-down views