.kensa/traces/ that your coding agent can mine into evals.
.kensa/traces/ is local evidence, not an observability backend. Kensa imports bounded exports to build CI regression tests; it does not stream or store your production telemetry.Importing from a provider
Langfuse is supported as a live connection. Connect once, then import.kensa connect saves connection metadata to .kensa/connections/<provider>.json. API keys are read from environment variables (or a configured dotenv) at run time and are never written to that file. By default connect verifies access before saving; pass --configure-only to skip the check.
Kensa automatically chooses between the legacy traces API and observations v2. Use
--langfuse-mode legacy_traces or --langfuse-mode observations_v2 only when you need to force one path.
See the CLI reference for every connect and import flag.
Importing from a file
You do not need a live connection.kensa import reads bounded export files in several formats:
Imports are normalized to Kensa’s TraceView schema and written to
.kensa/traces/imports/<provider>-<timestamp>.jsonl, with a .manifest.json recording provenance and redaction, and a latest.json pointer.
Evidence minimization and redaction
Import has two privacy boundaries:- Kensa projects provider payloads into a minimal TraceView. It retains trace and span relationships, names and kinds, tool names, timing and status, input and output, and model usage. Arbitrary provider metadata is dropped.
- Kensa scans retained values with deterministic recognizers, detect-secrets, Presidio, and spaCy NER. PII and secrets become typed placeholders such as
[PERSON_1]before the artifact is written.
kensa init installs kensa[redaction] and prepares the small English model by default. Select the larger model when recall matters more than download size:
[tool.kensa].redaction_model selects the model. Kensa verifies the wheel checksum on download
and validates the cache before use. It writes no readiness file.
Capturing traces locally
If you do not have an observability provider, instrument your agent and let Kensa record spans directly. The recording helpers are exported from the top-level package:result= when the result already exists before the context:
kensa.tool.args and kensa.tool.result span attributes, so later caller
mutation cannot change the evidence. set_result(...) records at most one result. Supplying
result= and then calling set_result(...), or calling set_result(...) twice, raises
RuntimeError.
If the tool body raises before recording a result, the original exception and traceback escape
unchanged. The tool call remains observable with status == "error" and
result_recorded is False.
During kensa eval, these context managers preserve the current operation when a trial times out.
Set KENSA_TRACE_DIR so spans are written to disk, then import them like any other JSONL source:
OTLP HTTP export
Opt in withotlp_endpoint= or KENSA_OTLP_ENDPOINT. Local JSONL capture stays on, so each span
lands both locally and at the endpoint:
OTEL_EXPORTER_OTLP_* variables never enable export, so instrument() stays a no-op in a
process that only configures OpenTelemetry for its own exporter. Credentials come from
otlp_headers= or KENSA_OTLP_HEADERS only; your application’s OTEL_EXPORTER_OTLP_HEADERS is
never sent to a Kensa endpoint. Timeout, compression, and certificate settings still read the
standard variables.
Without a local directory, spans also go to .kensa/traces/spans.jsonl. An unreachable endpoint is
logged and does not discard the local span or raise. Requests default to a two-second timeout,
overridable with otlp_timeout_s or the standard timeout variables, which the Python exporter reads
in seconds. Both exporters ship the same spans, so expect duplicates if your application already
exports to the same collector.
Inside an eval, the same helpers feed the live result.trace accessor on successful runs. The
case-aware agent returned by kensa_run(case) wraps real tool and model calls with
record_tool_call / record_llm_call. Kensa adds one source-attributed outer response span for every
attempted agent or simulator response, while the existing trace totals include activity from both
sources. See Pytest plugin.
Attaching evidence from a target-owned agent
Keep the deployed agent in its own repository or service and translate its native result intoAgentRunEvidence inside your adapter. Kensa records the supplied data but never imports, invokes,
or connects to the target agent.
attach_agent_run() after the target finishes and before respond() returns. With no active
Kensa runtime it is a no-op, so the same adapter works in application tests. If a Kensa runtime
exists, attachment before case.run(), after the operation returns, or from a late background task
raises KensaCaseError. Each run_id is immutable: an equal duplicate is ignored and conflicting
evidence is rejected.
Attachment lifecycle errors and conflicting run_id evidence are KensaCaseError values. Even
when the conversation boundary wraps them, Kensa records them as harness/case_contract, not as
agent execution failures.
Invalid AgentRunEvidence model construction originates inside the target adapter and is therefore
an agent/execution error by default when it escapes through respond(). If the adapter knows that
invalid evidence is its own contract defect, translate it explicitly:
Evidence reference
Event
kind is one of llm, tool, handoff, retrieval, action, state, or span.
Event status is completed, failed, or cancelled. Completeness is complete, pending,
partial, or unavailable; any value other than complete requires an incomplete_reason.
Trajectory and state completeness are independent.
Effect policies are target-supplied facts:
Attaching
effects="live" does not make a network call or approve, reject, authorize, sandbox, or
roll back an effect. Point adapters at test or sandbox environments unless live effects are
deliberately part of the evaluation policy.
Trajectory events become normalized spans in result.trace. Tool events appear in
result.trace.tools, and LLM events count toward result.trace.llm_turns. A finite nonnegative
kensa.cost_usd event attribute contributes to known cost. If any local or external LLM event has
no valid cost, known_cost_usd still sums priced events while cost_available is false and
cost_usd is unavailable.
StateObservation contains actual state read from the target-owned environment and stays under
result.trace.agent_runs[*].state. It never becomes a span or trial outcome. An
AgentEvent(kind="state") is only a reported trajectory transition, not proof of actual state.
From traces to evals
Once evidence is imported, your coding agent turns it into evals. Thekensa-inspect skill reads the redacted evidence and proposes reviewable eval ideas as a YAML queue under .kensa/inspect/, which the CLI can read and validate:
status: pending to status: approved), then the kensa-generate skill materializes them as tests/evals/test_<id>.py. No traces yet? Capture a local run (below), or let the skill seed a first eval from one realistic prompt.
OpenTelemetry compatibility
Spans are standard OpenTelemetry. Kensa annotates them withkensa.span.kind, kensa.tool.name, and kensa.llm.provider / kensa.llm.model attributes.
record_llm_call also emits standard GenAI attributes. operation_name defaults to chat and
accepts embeddings, generate_content, or text_completion; use
span_kind=SpanKind.INTERNAL for an in-process model. Anything that emits OTLP can be imported with
--from otlp.