This page is written for an AI coding agent (Claude Code, Cursor, …) asked
to add Foglamp tracing to a codebase. If you’re a human, the
Quickstart is friendlier.
Rules
- Check the AI SDK version first and pick the matching path (step 2):
wrap()fromfoglamp/wrapon AI SDK v4–v6, orfog.integration(...)on v7. Both capture identical traces — never upgrade the app’s AI SDK just to instrument it. Steps 3–5 below (mapping, flush, verify) apply to both paths. - Never refactor working AI code to instrument it.
wrap()coversgenerateText/streamText/generateObject/streamObjectand theToolLoopAgent/Experimental_Agentclasses — wrap in place; do not rewrite agent classes intogenerateTextcalls or restructure pipelines. - Prefer the installed package’s types/README over memory. Don’t invent SDK APIs
or hand-wire ingest endpoints — only use
foglamp’s public API below. - The SDK is a silent no-op without
FOGLAMP_API_KEY— safe to add in every environment. Nothing throws and no spans are sent until the key is set. - Names are static string literals.
agentName,workflowName, andtraceNamemust be written as literal strings in the source — never template literals, concatenation, or variables. Anything dynamic (a slug, URL, id, date) goes inmetadata,workflowRunId, orsessionIdinstead. See the mapping rules. - Instrument one real entry point first, verify a trace appears, then expand.
1. Install & configure
Installfoglamp with the repo’s own package manager (check the lockfile —
don’t introduce a second one):
.env
2. Wire up Foglamp — pick the path for the installed version
Check the installedai version first (read the lockfile / package.json),
then follow the matching path. Both capture identical traces; only the wiring
differs, and steps 3–5 apply to both. Every traced call needs a traceName
or an agentName.
AI SDK v4, v5, or v6 — wrap()
Wrap the ai module once, then bind a context with fog.with(...); the
returned functions keep the AI SDK’s own, fully-typed signatures. wrap() also
covers generateObject/streamObject and the ToolLoopAgent /
Experimental_Agent classes — instrument them in place; do not rewrite agent
code into generateText calls.
fog.run(...) (ambient context) and
the per-call foglamp: {...} option.
AI SDK v7 — fog.integration()
Attach the integration to each generateText / streamText call via the
telemetry option.
3. Map the codebase to Foglamp’s model
This is the step that makes the dashboard useful, so spend real effort here: read the codebase and decide what its agents, workflows, and sessions actually are before writing any context. The full context surface:| Property | What it is | Good values |
|---|---|---|
agentName | The named, reusable LLM behavior responsible for the call | Stable, low-cardinality identifiers from the code’s own vocabulary: "support-triage", "summarizer". Never per-request values. |
workflowName + workflowRunId | A named multi-step process, and one execution of it | workflowName stable like an agent name ("ticket-pipeline"); workflowRunId an id the app already has for this execution — request id, job id, ticket id. |
traceName | Human label for a one-off call that isn’t an agent | The call’s purpose: "classify-email". |
sessionId | Ties traces in one conversation or user thread together, across workflows and agents | The app’s existing chat/conversation/thread id. Conversations only — a batch/cron/pipeline run id is a workflowRunId, not a session. |
metadata | Everything else, as string key/values | userId, tenant, environment, prompt version, A/B variant. |
- Every call needs
traceNameoragentName(both is fine — the trace is attributed to the agent and displays thetraceName). workflowNameandworkflowRunIdgo together — one without the other is an error. Calls sharing aworkflowRunIdare stitched into one run on the Workflows timeline, so the id must be shared by every call in the run but unique per execution.
-
Find the agents. A class, module, or function that owns a system prompt
and is invoked from more than one place is an agent →
agentName. Name it after what the code calls it. -
Find the pipelines. A request handler or job that makes several model
calls (or calls several agents) before producing its result is a workflow →
same
workflowName+workflowRunIdon every call in it, including calls made by nested agents. Usefog.run(context, fn)at the handler/job entry point — it sets the context ambiently for everything inside (however deeply nested), so you don’t thread a trace parameter through every function signature between the handler and the AI calls: -
Find the threads. If the app has conversations (a chat, a support thread),
pass its id as
sessionIdon every call serving that thread. A session is a conversation — a thread where a user goes back and forth. If no human is conversing, there is no session: a batch run, cron job, pipeline execution, billing period, or engagement cycle is not a session, even though its id would technically group traces. Group executions withworkflowName+workflowRunIdand put longer-lived business ids (campaign, cycle, tenant) inmetadata. When in doubt, omitsessionId— it is optional. -
Don’t overload the names. High-cardinality values (user ids, slugs,
URLs, dates, ticket numbers) belong in
workflowRunId,sessionId, ormetadata— never inagentName/workflowName/traceName, which should each have a small, stable set of values. The mechanical check: every name must be a string literal at the call site. If you catch yourself writing a template literal or passing a variable, the dynamic part is metadata:
fog.with({...}), a per-call foglamp: {...} key, or
fog.run({...}, fn) for run-scoped context — see wrap.
4. Flush in serverless
Long-running servers (Node, Bun) flush on an interval automatically. Serverless is auto-detected (VERCEL / AWS_LAMBDA_FUNCTION_NAME env vars) and
switches to per-call flushing — so check what the deployment target needs
before adding flush plumbing:
- Vercel: nothing to do — foglamp reads
waitUntilfrom the runtime’s request context automatically (no@vercel/functionsdependency needed) to keep the invocation alive while the batch sends. - Cloudflare Workers / other serverless: pass
waitUntilin the config (foglamp({ waitUntil: ctx.waitUntil })), orawait fog.flush()before each handler returns.
5. Optional — live HUD (dev only)
If the app has a React UI and a local dev server, offer to wire up the live HUD: a dev-only floating overlay that streams runs (steps, tool calls, tokens, cost) on top of the app as the user develops — a great first-run “wow”. It needs no API key and is a no-op in production / on edge / serverless, so it’s safe to leave in. Two lines:- Server: pass
hud: trueto the existingfoglamp({ ... })call. - Client: render
<FoglampHUD />fromfoglamp/hudonce near the root of the client app (e.g. the root layout).
foglamp({ hud: true }) must run on the
Node runtime (not edge). It needs nothing beyond foglamp + React. Skip
this step entirely if there’s no React frontend. Full reference:
Live HUD.

