Hooks and Instrumentation
Purpose and Scope
Hooks and instrumentation are eve's two complementary ways to observe an agent after it has been authored. Instrumentation configures process-level telemetry, especially OpenTelemetry export and AI SDK span behavior. Hooks subscribe to the runtime event stream and run side effects after events are durably recorded. Together, they let teams answer operational questions such as which sessions are active, which model calls are expensive, which tools are returning risky results, and whether messages or turns need to be copied into a separate audit or analytics store.
The most important distinction is where each surface sits in the runtime. Instrumentation is discovered as agent/instrumentation.ts and runs at server startup before agent code. A hook is an authored runtime extension under agent/hooks/ that reacts to stream events during sessions and turns. Use instrumentation when you need trace export, span payload policy, or per-model-call runtime context. Use hooks when you need event-by-event side effects such as logging, metrics, alerting, or persistence.
Sources: docs/guides/instrumentation.md
Relevant Source Files
docs/guides/instrumentation.md- Documentsagent/instrumentation.ts, auto-discovery,defineInstrumentation, OpenTelemetry setup, workflow run tags, runtime context events, and debugging guidance for observability configuration.
Core Primitives
The instrumentation primitive is defineInstrumentation from eve/instrumentation. An eve project exports its instrumentation definition as the default export from agent/instrumentation.ts. The framework auto-discovers that file and runs it at server startup before loading the rest of the agent. The file's presence is also the enablement signal for telemetry, so there is no separate isEnabled flag to remember or synchronize across environments. That design keeps observability filesystem-first: adding or removing one conventional file changes the agent's telemetry behavior.
import { BraintrustExporter } from "@braintrust/otel";
import { defineInstrumentation } from "eve/instrumentation";
import { registerOTel } from "@vercel/otel";
export default defineInstrumentation({
setup: ({ agentName }) =>
registerOTel({
serviceName: agentName,
traceExporter: new BraintrustExporter({
parent: `project_name:${agentName}`,
filterAISpans: true,
}),
}),
});Hooks use a different primitive: defineHook from eve/hooks. A hook file declares an events map keyed by runtime stream event type, and * can be used to match every event. The official hook model is observe-only: handlers run side effects after an event has already been durably recorded, but they do not inject model context. If the goal is to contribute instructions or model-visible messages, use dynamic instructions instead of a hook. If the goal is to react externally to what happened, a hook is the right abstraction.
Three Observability Surfaces
The instrumentation guide describes three observability surfaces, and keeping them separate prevents a common debugging mistake. Workflow run tags are automatic framework-owned attributes on Vercel Workflow runs. They are not configured in instrumentation.ts, and they are queried in the Workflow dashboard rather than in an OpenTelemetry backend. Their purpose is to help dashboards stitch session, turn, and subagent workflow runs into a tree and surface model and token usage at the workflow level.
OpenTelemetry export is the first configurable surface in instrumentation.ts. The setup callback receives the resolved agent name and should register an OTel provider, such as registerOTel from @vercel/otel, with the exporter appropriate for the deployment. The documentation names Braintrust, Raindrop, Arize, Honeycomb, Datadog, and Jaeger as examples of compatible backends. Because context.agentName is resolved at compile time from the project package name or app directory name, the service name does not need to be hard-coded.
Runtime context events are the second configurable surface in instrumentation.ts. They are written per model call into the AI SDK runtime context, and the AI SDK carries those values onto spans. This is useful when span consumers need agent-specific attributes that are not part of the automatic workflow tags. Treat runtime context as span enrichment, not as durable event subscription. For event-by-event side effects after runtime events are recorded, prefer hooks under agent/hooks/.
Sources: docs/guides/instrumentation.md
Defining OpenTelemetry Behavior
The setup callback is where exporter registration belongs. It runs at server startup, so it should be deterministic, safe to initialize once, and appropriate for the current environment. The guide's example wires @vercel/otel to a BraintrustExporter, using the agent name for both service naming and exporter project grouping. The same pattern applies to other OTel backends: install the exporter package, import it in agent/instrumentation.ts, and configure it inside setup.
Telemetry content is controlled by three additional fields. recordInputs records full message history on each step span and defaults to true. recordOutputs records model outputs on spans and also defaults to true. functionId overrides the function name on spans. These options are especially important for production agents because traces may contain user content, tool inputs, or model outputs. Before enabling export, review exporter destination, data categories, retention behavior, and any required legal approvals.
A practical production setup usually starts conservative. Disable recordInputs if messages may contain secrets, personal data, tenant-isolated content, or large attachments that would make spans expensive. Disable recordOutputs when model responses are sensitive or when output payload volume is high. Keep the setup callback small and focused on provider registration; push event-specific analytics, audit writes, and alerting into hooks so that tracing configuration does not become a general-purpose side-effect layer.
Sources: docs/guides/instrumentation.md
Hook Event Flow
A hook subscribes to runtime stream events and receives a HookContext containing the agent, channel, and session identity. The official shape includes agent.name, optional agent.nodeId, optional channel kind, optional continuationToken, and session.id. That context is intentionally compact: it gives the handler enough identity to write logs or correlate data without turning the hook into another model-context provider. Event payloads carry the event-specific data, while the context carries the stable runtime envelope.
import { defineHook } from "eve/hooks";
export default defineHook({
events: {
async "session.started"(_event, ctx) {
console.info("session started", { sessionId: ctx.session.id });
},
async "message.completed"(event) {
console.info("model finished", { length: event.data.message?.length ?? 0 });
},
},
});Hook slugs are derived from their path-relative basenames. For example, agent/hooks/audit.ts becomes audit, while a nested file such as agent/hooks/auth/load-profile.ts becomes auth/load-profile. Subscribe to lifecycle and runtime stream events such as session.started, turn.completed, message.completed, and action.result, or use * for a catch-all observer. For tool result processing, the official API includes toolResultFrom from eve/tools, which narrows an action.result event to a specific authored tool or MCP connection and returns typed output.
System-to-Code Mapping
| Concern | Authoring location | Public primitive | Runtime role |
|---|---|---|---|
| OpenTelemetry setup | agent/instrumentation.ts | defineInstrumentation from eve/instrumentation | Registers exporter/provider at server startup |
| Span content policy | agent/instrumentation.ts | recordInputs, recordOutputs, functionId | Controls what AI SDK spans record |
| Workflow run tags | Automatic framework behavior | $eve.* tags | Correlates Workflow runs, sessions, turns, subagents, models, and token usage |
| Runtime context events | agent/instrumentation.ts | events["step.started"] | Adds per-model-call values to AI SDK runtime context |
| Runtime event side effects | agent/hooks/*.ts | defineHook from eve/hooks | Observes recorded stream events and runs side effects |
This mapping is useful when deciding where to place new observability code. If a requirement says, "send spans to Datadog," implement it in agent/instrumentation.ts. If it says, "attach a tenant or experiment label to every model-call span," use runtime context events in instrumentation. If it says, "write every completed message to our warehouse," implement a hook. If it says, "show workflow hierarchy and token usage in Vercel Workflow," rely on automatic workflow run tags rather than trying to reproduce them in OTel spans.
Sources: docs/guides/instrumentation.md
Operational Guidance
Because instrumentation runs before any agent code, errors in agent/instrumentation.ts can affect startup rather than a single user turn. Keep imports explicit, make exporter configuration environment-aware, and test local startup before deploying. The guide also recommends using eve info and its common-failures table when debugging discovery, which is a good first step if traces do not appear or the framework does not seem to recognize the instrumentation file.
Hooks have a different operational risk profile. They run in response to durable runtime events, so handler code should be idempotent or safe to retry when external systems are temporarily unavailable. Avoid using hooks as a hidden control plane for model behavior; they are best for observation, persistence, and notification. When a handler needs to call a database or metrics API, include enough event and session identity to deduplicate writes, and avoid long-running work that could slow down event processing.
A good rollout sequence is to first create agent/instrumentation.ts with an exporter and conservative span recording settings, then verify traces with a local or staging run. Next, add runtime context values only when they answer a specific debugging or reporting question. Finally, add hooks for durable event side effects such as audit logs, warehouse replication, model-completion metrics, or alerts on selected action.result events. Read the sessions and streaming documentation next to understand the full event vocabulary before subscribing broadly.
Sources: docs/guides/instrumentation.md