Overview
Crewship provides real-time event streaming so you can:
- Monitor crew execution as it happens
- Build responsive UIs that update live
- Debug issues by watching the event flow
- Log events to external systems
Streaming via CLI
The simplest way to stream events:
crewship invoke --input '{"topic": "AI"}' --stream
Output updates in real-time:
▶ Run started: run_abc123
├─ [10:30:01] Starting crew execution
├─ [10:30:02] Researcher agent starting task
├─ [10:30:05] Tool: web_search("AI agents 2024")
├─ [10:30:12] Researcher agent completed task
├─ [10:30:13] Writer agent starting task
├─ [10:30:45] Writer agent completed task
├─ [10:30:46] Artifact: report.md
✅ Run completed in 45.2s
Streaming via API
Server-Sent Events (SSE)
Connect to the events endpoint with SSE:
curl -N \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: text/event-stream" \
"https://api.crewship.dev/v1/runs/run_abc123/events"
JavaScript/TypeScript
const eventSource = new EventSource('https://api.crewship.dev/v1/runs/run_abc123/events', {
headers: {
Authorization: 'Bearer YOUR_API_KEY',
},
})
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data)
console.log(data.type, data.payload)
}
eventSource.onerror = (error) => {
console.error('Stream error:', error)
eventSource.close()
}
Python
import requests
response = requests.get(
"https://api.crewship.dev/v1/runs/run_abc123/events",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Accept": "text/event-stream"
},
stream=True
)
for line in response.iter_lines():
if line:
# Parse SSE format
if line.startswith(b"data: "):
data = json.loads(line[6:])
print(data["type"], data["payload"])
Event Types
Run Lifecycle Events
| Event | Description | Payload |
|---|
run.started | Execution began | { run_id, started_at } |
run.completed | Success | { run_id, duration_ms, result } |
run.failed | Error | { run_id, error, stack_trace } |
run.canceled | Manually stopped | { run_id, canceled_at } |
Agent Events
| Event | Description | Payload |
|---|
agent.started | Agent began task | { agent, task } |
agent.completed | Agent finished | { agent, task, output } |
agent.error | Agent failed | { agent, error } |
| Event | Description | Payload |
|---|
tool.called | Tool invoked | { tool, input } |
tool.result | Tool returned | { tool, output } |
tool.error | Tool failed | { tool, error } |
Log Events
| Event | Description | Payload |
|---|
log | Log message | { level, message, timestamp } |
Artifact Events
| Event | Description | Payload |
|---|
artifact | File produced | { name, size, content_type } |
Each SSE event follows this format:
event: <event_type>
data: <json_payload>
id: <event_id>
Example:
event: agent.started
data: {"agent":"Researcher","task":"Research AI trends","timestamp":"2024-01-15T10:30:02Z"}
id: evt_001
event: tool.called
data: {"tool":"web_search","input":"AI agents 2024","timestamp":"2024-01-15T10:30:05Z"}
id: evt_002
event: log
data: {"level":"info","message":"Found 15 relevant results","timestamp":"2024-01-15T10:30:06Z"}
id: evt_003
Reconnection
SSE supports automatic reconnection. Use the Last-Event-ID header:
let lastEventId = localStorage.getItem('lastEventId')
const eventSource = new EventSource(`https://api.crewship.dev/v1/runs/${runId}/events`, {
headers: {
Authorization: `Bearer ${apiKey}`,
'Last-Event-ID': lastEventId || '',
},
})
eventSource.onmessage = (event) => {
localStorage.setItem('lastEventId', event.lastEventId)
// Process event...
}
Building a Live UI
Example React component:
function RunProgress({ runId }: { runId: string }) {
const [events, setEvents] = useState<Event[]>([])
const [status, setStatus] = useState<'running' | 'completed' | 'failed'>('running')
useEffect(() => {
const eventSource = new EventSource(`https://api.crewship.dev/v1/runs/${runId}/events`)
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data)
setEvents((prev) => [...prev, data])
if (data.type === 'run.completed') {
setStatus('completed')
eventSource.close()
} else if (data.type === 'run.failed') {
setStatus('failed')
eventSource.close()
}
}
return () => eventSource.close()
}, [runId])
return (
<div>
<StatusBadge status={status} />
<EventList events={events} />
</div>
)
}
Filtering Events
Request specific event types:
curl -N \
-H "Authorization: Bearer YOUR_API_KEY" \
"https://api.crewship.dev/v1/runs/run_abc123/events?types=agent.started,agent.completed,artifact"
Webhooks (Coming Soon)
Webhook delivery is on our roadmap. For now, use SSE for real-time events.