Cost Observability Hooks
Overview
This skill documents how to subscribe to Output's cost events so every priced LLM call and every HTTP call with attached cost (via addRequestCost, see output-dev-http-client-create) can be forwarded to your own observability system — a webhook, a structured log pipeline, a metrics backend, etc. Handler errors are caught and logged by the framework; they never affect the workflow or the request that triggered them.
When to Use This Skill
- Forwarding per-call spend to an external observability/webhook endpoint
- Logging cost events as structured fields for a log platform
- Building alerting or dashboards on top of workflow spend
- Auditing which workflows/activities are driving cost, in real time rather than after the fact
This skill is about project-wide hook registration for cost data already emitted by the framework. To make an HTTP client emit cost in the first place, see output-dev-http-client-create.
Setup
1. Create a hook file
2. Register the file
Add the file to outputai.hookFiles in package.json, alongside any existing hook files. Paths are relative to the package root and point at the built .js output — npm run output:worker:build compiles src/ to dist/ (per tsconfig.json's rootDir/outDir), so src/cost_hooks.ts is registered as dist/cost_hooks.js, not the .ts source itself. The worker loads these files at startup.
If you'd rather skip the build step, a hook file can also be plain, uncompiled JavaScript registered directly at its src/ path ("./src/cost_hooks.js") — see https://docs.output.ai/operations/error-hooks for that variant. The rest of this skill uses TypeScript + the built-output path, since that's what the framework's own examples (and every other file in a scaffolded project) use.
Events You Can Subscribe To
Every event carries the same envelope: eventId (UUID v4, stable idempotency key), eventDate (ms epoch), activityInfo and workflowDetails (present when emitted from within a step/evaluator), outputActivityKind, and payload (the event-specific data described above).
Pattern 1: Forward to an external endpoint
Use this when spend needs to reach an external observability system over HTTP. Forward the raw envelope plus payload; redact anything that might carry secrets (API keys or tokens embedded in query strings) before logging or sending the URL.
Pattern 2: Structured logging
Use this when spend just needs to land in your log platform as structured facets, without a separate network call. Use the framework Logger so fields are emitted consistently with the rest of the worker's logs.
Handler Safety Rules
- Handlers are wrapped in try/catch by the framework. A thrown or rejected handler is caught and logged (e.g.
<eventName> hook error) and never affects the workflow, the worker, or the request that triggered the event — the same guaranteeonErrorhandlers get. Adding your owntry/catchis still worthwhile so a forwarding failure logs with context you control, but it's not required for safety. - Skip incomplete events. Guard on
event.workflowDetailsandevent.payloadbefore using them — they're only populated when the event was emitted from within a step/evaluator context;eventIdandeventDate, by contrast, are always present. - Redact before logging or sending URLs. Some third-party APIs embed API keys or tokens in query strings. Strip the query string (and any path segments you know carry secrets) before it leaves the process.
- Use
eventIdas an idempotency key when forwarding to a system that might receive the same event more than once (e.g. retried delivery). - Expect one event per attempt. A step or evaluator that retries emits one cost event per attempt — that's correct, since each attempt is a real billed call.
- Prefer
llm:generation:meteringovercost:llm:requestfor new integrations; the legacy event's shape is frozen and misses newer cost types (e.g. tool/grounding charges).
Verification Checklist
- Hook file registered in
outputai.hookFilesinpackage.json, pointing at the built.jspath (dist/...), not the.tssource - Hook file imports
onfrom@outputai/core/hooks - Handlers guard on missing
workflowDetails/payload - URLs are redacted (query string stripped) before logging or forwarding
-
llm:generation:meteringused instead of legacycost:llm:requestfor new work
Related Skills
output-dev-http-client-create- Attaching cost to a paid API client withaddRequestCostoutput-dev-workflow-cost- Post-hoc cost calculation for a single completed workflow run via the CLIoutput-dev-credentials- Storing the observability endpoint URL/token as a credential


