@cultured_computer/sight
v0.6.0
Published
A standard format for agent experience data: every step your production AI takes and what comes back, in one published, versioned record. Behavioural measurements on top, no evals. Ships a CLI for pulling your own data out.
Downloads
1,589
Maintainers
Readme
Sight
Sight records what your production assistant is being. Not traces of what the model produced: the interaction itself, captured as a coupled record. Each turn holds what the situation was, what your agent did, how the user responded, and what it led to. Both actors, one record. Behavior lives in the coupling, not in the transcript: a reply only means something next to what happened after it.
The record also carries an environment channel: tool outcomes, world signals, stimulus events with their timing. Behavior reads against what the world actually did, not just against text.
The SDK captures out of band; responses are never modified or delayed. From the record, the dashboard shows the worst conversations first (opened on the transcript), joins outcomes back to the conversation that caused them even when they arrive days later, and computes behavioural measurements on top: the situations your deployment handles, voice consistency, uptake, breaks, return behaviour. Every interpreted number stays preliminary until it agrees with your own labels on your own traffic.
The SDK is in beta. The record format is versioned and stable; the surfaces around it are still moving.
Install
npm install @cultured_computer/sightNode 18 or later. TypeScript types ship with the package.
Quickstart
import { Sight } from '@cultured_computer/sight'
Sight.init({
apiKey: process.env.SIGHT_API_KEY!,
deployment: 'my-assistant',
})
Sight.startSession({
externalId: conversationId,
externalUserId: userId,
})Notes:
apiKeyis a project ingest key. Create a project in the dashboard and copy its key (shown once) intoSIGHT_API_KEY. That is the only required setup; the ingest endpoint defaults to production; override it withendpointonly for self-hosting or staging.initruns once at startup.deploymentidentifies the configuration this traffic belongs to; all measurement is per deployment.externalIdkeys the session (one conversation).externalUserIdis a stable, pseudonymous user id you supply. Return metrics key on the user id; sessions without it still capture, but return behaviour is not computable.
Pull your own data out: the CLI, from your terminal
The sight CLI also carries out data from projects you own, with no
dashboard click-through and no session cookie to juggle. Sign the terminal in
once against the browser session you already hold, then export any deployment
you own as RLDS JSONL:
# one-time: sign this terminal in (prints a code, opens your browser to approve)
npx @cultured_computer/sight auth login
# then pull a deployment's full record
npx @cultured_computer/sight export --project <slug> --deployment <slug> --out data.jsonl
# or pull the readings: the per-turn judge labels (closure, backward-pass, ...)
npx @cultured_computer/sight export --project <slug> --deployment <slug> --readings --out readings.jsonl
# sign out when you're done
npx @cultured_computer/sight auth logoutauth loginprints a short code and opens your browser to the/deviceapproval page (RFC 8628 device authorization). You approve as yourself on a browser you are already signed into: same identity, same role, same rules as your dashboard session. The token is stored at~/.config/sight/credentials.json(mode0600).exportstreams the deployment's sessions and turns as RLDS JSONL, the same Tier-2 redacted shape the dashboard produces. It is owner-only: the token is your session, so the carry-out gate is exactly the dashboard's. Members read in-product; owners carry the dataset out.--readingspulls the graded reads instead of the record: one line per per-turn judge label (closure, backward-pass, and the rest), with the rubric version and judge-model pin. These are the re-computable evidence layer over the record, not part of the versioned record schema.--out <file>writes to a file; omit it to stream to stdout.
One more CLI door, for a different shape: sight connect attaches Sight to a
buzz community you don't serve as a read-only observer (invite-code
authorization, no account needed up front). A side lane, not the install —
the walkthrough lives at
Connect your buzz community.
What lands automatically
OpenAI: wrap your client. This is the reliable autocapture path and the one to use in every new integration:
import OpenAI from 'openai'; import { Sight, wrapOpenAI } from '@cultured_computer/sight'; const openai = wrapOpenAI(new OpenAI()); // Every chat.completions.create and responses.create call on this // client is now captured, streaming included. Wrap before or after // Sight.init(); order does not matter.Module-level autocapture (no wrap call) also exists but has hard limits: it attaches only under CommonJS, only when
openailoads afterinit, and only for openai v4 (the underlying instrumentation does not support v5+). When it cannot attach, the SDK now prints a warning namingwrapOpenAIinstead of failing silently. If you run ESM or openai v5+, wrap the client.Module-level autocapture is on from
initfor calls made through the Anthropic SDK, Vercel AI SDK, LangChain, and LangGraph in the process, with the same CommonJS and load-order caveats. Each adapter no-ops if its target library is not installed. Mercury-2 reached through the OpenAI SDK with a baseURL override is captured and tagged by provider;wrapOpenAIapplies there too.Plumbing fields populate with no further configuration: model, tokens, latency, cost, tool calls, finish reason.
Turns are grouped into sessions by the ids you supply; sessions are created lazily on first capture.
Capture never blocks your LLM path. Send failures log in debug mode and are otherwise swallowed.
Attach outcomes
Call these wherever the outcome becomes known; they join back by session id, even hours later, from a webhook or CRM callback.
// A user reporting a persona break.
await Sight.flagPersonaBreak({
sessionExternalId: sessionId,
note: 'sounded robotic',
})
// Your own downstream outcome: a resolved ticket, a rating, a conversion.
await Sight.emitOutcomeEvent({
sessionExternalId: sessionId,
kind: 'ticket_resolved',
detail: { ticketId: 'ZD-88213' },
})Capture environment events
Deployments that run alongside a non-dialogue channel (a stimulus feed, a game state stream, an editor buffer) can record that channel's events against the conversation:
await Sight.captureEnvironmentEvents(events, {
clock_source: 'my-event-clock',
skew_bound_ms: 25,
rule_version: 'v1',
})The envelope is generalized: source_type and event are free strings whose
meaning is defined per deployment. The instrument attaches events to turns by
time (the next turn's state corner, plus the causing turn's outcome corner
when the event carries a causeProvenance turn reference) and never
interprets them.
Capture spans
Deployments that keep their own sub-turn structure (tool calls, retrieval steps, per-call model usage inside a single turn) can ship it as spans:
await Sight.captureSpans(
[
{
deploymentSlug: 'my-agent',
sessionExternalId: sessionId,
turnIndex: 3,
spanType: 'tool_call',
name: 'lookup_order',
startedAt: '2026-07-22T00:00:01.200Z',
durationMs: 180,
attributes: { toolName: 'lookup_order', argKeys: ['orderId'] },
},
],
{ clock_source: 'my-agent-clock', skew_bound_ms: 25, rule_version: 'v1' },
)A span lands on the turn you name, or on the session's latest turn at/under
its startedAt when turnIndex is omitted. Parent structure rides the
batch: give a span a caller-local spanId and reference it from a sibling's
parentSpanId. attributes are metadata only: tool names and argument
shapes, never free-text conversation content. Sight.captureSpan(span) is
the single-span form.
Scope
Sight is a measurement system: it reports what a deployment did. It does not modify responses, and it does not estimate what a different response would have produced. Counterfactual evaluation requires logged propensities or a live experiment.
The record schema
Everything Sight captures exports in one published, versioned shape:
schema/sight-record-v1.schema.json, shipped in this package
(@cultured_computer/sight/schema/record-v1). One JSON line per
session; each turn carries the fixed four-field envelope: the
situation, the assistant's move, how the person took it, and what
followed, on both sides of the exchange, with provenance and
redaction built into the shape. A CI test keeps the schema and the
export bytes in lockstep. Formats that standardize the agent log stop
at the assistant's half; this one records the exchange and its
consequences. See Data format.
Docs
- Get started: install, initialise, verify capture.
- Cookbook: runnable snippets, each with what it lands in the record.
- SDK reference: the full method surface.
- Status: what is available now versus in beta.
Legal
Privacy Policy and Terms of Service.
License
MIT (c) Cultured Computer
