Grounded SDK
The Grounded SDK is a server-side TypeScript interface to the existing Grounded /api surface.
It is not a monolithic browser analytics package. It is two packages with one brand:
| Package | Purpose | Auth | Main Routes |
|---|---|---|---|
@grounded/client | Control-plane automation for agents, connectors, sessions, snapshots, jobs, evals, and datasets | Secret key grd_sk_... | /api/agents, /api/connectors, /api/sessions, /api/snapshots, /api/jobs, /api/job-loops, /api/evals |
@grounded/tracing | Direct trace, span, score, and identity ingestion from your app runtime | Publishable key grd_pk_... | /api/traces/batch, /api/traces/:id, /api/traces/:id/spans, /api/traces/:id/scores |
What The SDK Actually Does
Grounded has two different kinds of work:
- Control plane work. You create or inspect Grounded resources such as connectors, snapshots, jobs, evals, and datasets.
- Data plane work. You send your application's traces into Grounded so they can be inspected directly and, when tied to an agent, normalized into sessions that power insights and optimization workflows.
That split is why the SDK is two packages instead of one.
@grounded/client
Use the client package when you want to automate Grounded itself:
- create and inspect agents
- create, update, connect, disconnect, and sync connectors
- list sessions and session stats
- read insights
- fork snapshots, update drafts, run analysis, activate or reject snapshots
- create and poll jobs
- manage job loops
- create evals, run evals, and inspect eval runs
- create datasets and list dataset rows
The client intentionally smooths over the current backend response differences. Some existing routes return raw arrays, some return { data: [...] }, and some return paginated objects. The SDK normalizes those into consistent return shapes.
@grounded/tracing
Use the tracing package when your app already has the data and you want to send it straight to Grounded:
- start a trace for a request, conversation, or background task
- create spans for LLM calls, tools, retrieval, or app logic
- record trace- or span-level events
- attach scores such as
resolved=trueorgroundedness=0.91 - tag traces with
environment,release,agentId, andsnapshotId - optionally wrap OpenAI calls so spans are created automatically
- batch and flush completed traces efficiently
This package sends completed traces, not partial streaming span updates. Each completed trace is posted to /api/traces/batch.
How It Fits Into Grounded
If you send traces with a valid resource.agentId, Grounded stores the raw trace and then tries to normalize it into the same session model used by connector-ingested data.
That means a directly ingested trace can become:
- a session in the session explorer
- input for insight mining
- input for snapshot analysis and optimization
- input for eval workflows
To make that work in practice:
resource.agentIdis required for trace ingestionresource.snapshotIdis optional, but if provided it must belong to that agent- if
resource.snapshotIdis omitted, Grounded uses the latest snapshot for that agent - if the agent has no snapshot yet, the trace is stored but will not normalize into a session
Auth Model
The SDK reuses the current Grounded /api and adds API-key auth alongside dashboard session auth.
- secret keys:
grd_sk_...- used by
@grounded/client - can be tenant-scoped or agent-scoped
- carry explicit scopes such as
connectors:write,jobs:read, orsnapshots:write
- used by
- publishable keys:
grd_pk_...- used by
@grounded/tracing - must be agent-scoped
- can only carry trace scopes such as
traces:write
- used by
Key issuance currently happens through internal, session-authenticated routes:
GET /api/api-keysPOST /api/api-keysPOST /api/api-keys/:keyId/revoke
Current Distribution
The SDK is implemented in the Grounded monorepo today:
@grounded/client@grounded/tracing
The public npm publish is not live yet, so the docs below show the final package names and the current monorepo-first workflow.
First Example
import { Grounded } from '@grounded/client';
import { GroundedTracing } from '@grounded/tracing';
const grounded = new Grounded({
apiKey: process.env.GROUNDED_SECRET_KEY!,
baseUrl: process.env.GROUNDED_BASE_URL ?? 'http://localhost:3001',
});
const tracing = new GroundedTracing({
publishableKey: process.env.GROUNDED_PUBLISHABLE_KEY!,
baseUrl: process.env.GROUNDED_BASE_URL ?? 'http://localhost:3001',
environment: 'production',
release: 'api-2026-03-06',
});
const connector = await grounded.connectors.create({
agentId: 'agt_123',
name: 'LangSmith prod',
category: 'llm-tracing',
config: {
apiKey: process.env.LANGSMITH_API_KEY!,
projectName: 'support-prod',
},
});
await grounded.connectors.connect(connector.id);
const syncJob = await grounded.connectors.sync(connector.id);
await grounded.jobs.wait(syncJob.id);
const trace = tracing.startTrace({
traceId: 'chat_123',
sessionId: 'chat_123',
userId: 'user_123',
name: 'support.reply',
resource: { agentId: 'agt_123' },
input: { message: 'where is my refund?' },
});
const span = trace.startSpan({
name: 'policy.lookup',
kind: 'retrieval',
input: { source: 'faq' },
});
span.end({
status: 'ok',
output: { articleId: 'refund-policy-v3' },
});
trace.score({
name: 'resolved',
value: true,
dataType: 'boolean',
});
await trace.end({
status: 'ok',
output: { text: 'your refund is processing' },
});
await tracing.flush();