AI agent notifications
You kicked off an agent run. It’s working through a task that takes 20 minutes. You’re doing something else. When it finishes — or gets stuck — you find out by refreshing the terminal.
Here’s how to make your agents tell you instead.
The basic pattern
Agents do work in phases. Notify at the end of each meaningful one:
import fyi from "trigger.fyi"
async function runAgent(task) {
const start = Date.now()
fyi.log("Agent started", { body: task.description, taskId: task.id })
try {
const result = await agent.run(task)
const elapsed = Math.round((Date.now() - start) / 1000)
fyi("Agent complete", {
body: `${task.description.slice(0, 60)} · ${elapsed}s`,
taskId: task.id,
steps: result.steps.length,
tokens: result.usage.totalTokens
})
return result
} catch (err) {
fyi.critical("Agent failed", {
body: err.message,
taskId: task.id
})
throw err
}
}fyi.log() records the start without pushing. fyi() pushes when it’s done. fyi.critical() pushes if it fails.
With the Vercel AI SDK
import { generateText, stepCountIs } from "ai"
import { anthropic } from "@ai-sdk/anthropic"
import fyi from "trigger.fyi"
async function runResearchAgent(query) {
const start = Date.now()
const { text, usage, steps } = await generateText({
model: anthropic("claude-sonnet-4.6"),
tools: { /* your tools */ },
stopWhen: stepCountIs(10),
prompt: query,
onStepFinish({ stepType, toolCalls, toolResults }) {
if (stepType === "tool-result") {
fyi.log(`Tool: ${toolCalls[0]?.toolName}`, {
body: toolResults[0]?.result?.slice?.(0, 100)
})
}
}
})
const elapsed = Math.round((Date.now() - start) / 1000)
fyi("Research complete", {
body: `${elapsed}s · ${usage.totalTokens} tokens · ${steps.length} steps`,
query: query.slice(0, 50)
})
return text
}Tool calls go to the feed as fyi.log() — visible in the TUI, no push. Completion pushes.
Long-running agents: heartbeats
For agents that run for 30+ minutes, send periodic updates:
from trigger_fyi import fyi
import time
def run_agent_with_heartbeat(task, interval_minutes=10):
start = time.time()
last_heartbeat = start
step_count = 0
for result in agent.stream(task):
step_count += 1
# Heartbeat every N minutes
now = time.time()
if now - last_heartbeat > interval_minutes * 60:
elapsed = int((now - start) / 60)
fyi.log(f"Running: {elapsed}m elapsed",
body=f"{step_count} steps so far",
task_id=task.id
)
last_heartbeat = now
elapsed = int((time.time() - start) / 60)
fyi("Agent complete",
body=f"{elapsed}m · {step_count} steps",
task_id=task.id
)Multi-agent pipelines
When agents hand off to each other, track the handoffs:
async function pipeline(input) {
fyi.log("Pipeline started", { body: input.slice(0, 60) })
const research = await researchAgent.run(input)
fyi.log("Research done", { body: `${research.sources} sources`, stage: "research" })
const draft = await writingAgent.run(research)
fyi.log("Draft done", { body: `${draft.wordCount} words`, stage: "writing" })
const final = await editingAgent.run(draft)
fyi("Pipeline complete", {
body: `${final.wordCount} words · ready for review`,
stage: "editing"
})
return final
}Filter the feed by stage: research to see only research events. Each stage is filterable.
When the agent needs you
Some agents need human input before continuing:
async function runWithApproval(task) {
const plan = await agent.planTask(task)
fyi("Approval needed", {
body: plan.summary,
taskId: task.id,
actions: plan.actions.length
})
// Wait for your approval (polling, webhook, or manual resume)
await waitForApproval(task.id)
return await agent.executeTask(task, plan)
}The notification tells you what the agent plans to do before it does it.
Token and cost tracking
const { text, usage } = await generateText({ ... })
const estimatedCost = (usage.promptTokens * 0.000003) + (usage.completionTokens * 0.000015)
fyi("Agent complete", {
body: `$${estimatedCost.toFixed(4)} · ${usage.totalTokens} tokens`,
prompt_tokens: usage.promptTokens,
completion_tokens: usage.completionTokens
})Filter the feed by cost range or token count to find expensive runs.
Setup
npx trigger.fyiGenerates a key, subscribes your device. In your agent environment:
TRIGGER_FYI_SECRET_KEY=your_key_here
The feed TUI (npx trigger.fyi) is useful when you’re at your desk watching a run live. Your phone is useful when you’re not.
Related: Background job notifications · Monitoring without dashboards · Get a push notification when Claude Code finishes · Push notifications from Python