Understand your prompting habits and get specific insights to improve how you work with AI coding agents. Session Intelligence helps individuals and teams see where prompts lack context, why sessions need repeated corrections, what went well, and where time or tokens were wasted. It also flags exposed secrets and personal data. Bring your own LLM; no Session Intelligence SaaS or account is required.
Choose your path:
Analyze your own sessions: collect a transcript, run the analysis, and use the findings to improve your next session.
Embed in your product: use the Go API, supply your own model, or process a backlog with Postgres.
The workflow is collect → analyze → review → improve. Pair this engine with Agent Desk to browse your local sessions and use its local-session-extractor package to extract them into a common format. Agent Desk collects and displays sessions; Session Intelligence analyzes them.
Quick start
For analysis you need Go 1.25 or newer, Docker, and a Gemini API key. To collect local transcripts with the companion extractor, you also need macOS and Node 24 or newer. If you already have a transcript in the engine's format, skip step 2. You can also try the sample offline without a key or Docker.
1. Get the engine
git clone https://github.com/tetriz-ai/session-intelligence.git
cd session-intelligence
2. Find and extract your transcript
You do not need to find each tool's hidden session files yourself. Once Agent Desk's local-session-extractor v0.1.0 release is published with its local-session-extractor-0.1.0.tgz asset, install that release tarball, scan, and list the sessions it found. The commands below require that release asset to be available; if it is not yet published, use the offline sample or supply an existing transcript in the engine's format.
npm install --prefix /tmp/session-intelligence-extractor "https://github.com/tetriz-ai/agent-desk/releases/download/local-session-extractor-v0.1.0/local-session-extractor-0.1.0.tgz"
/tmp/session-intelligence-extractor/node_modules/.bin/local-session-extractor scan
/tmp/session-intelligence-extractor/node_modules/.bin/local-session-extractor list
If Agent Desk is private, sign in with gh auth login using an account with repository access, then download and install the release asset locally:
Pick a source and session ID from the list. For example, replace YOUR_SESSION_ID with a Codex session ID:
/tmp/session-intelligence-extractor/node_modules/.bin/local-session-extractor show codex -- YOUR_SESSION_ID > extracted-session.json
No conversion needed. The engine reads the extractor's record as it is — what local-session-extractor show prints, one line of its export, or one of its store rows — and keeps every message with its metadata, the session metadata, and the session events and their coverage. Pass the extracted file straight to the analysis CLI with no adapter step. A multi-session export --out sessions.jsonl has one record per line; pass one line at a time, not the whole JSONL file.
For Claude Code, use show claude-code -- YOUR_SESSION_ID; the -- also handles IDs starting with a dash. Other source names are cursor, copilot, kiro and antigravity. To browse visually, install Agent Desk. The commands here use the standalone extractor and its own store, so they work without the desktop app.
Already have a transcript? Use examples/transcript.sample.json as the input template, with ordered user and assistant messages from your real session. Save it as transcript.json. Native Claude/Codex JSONL files, Cursor databases, and plain-text chat exports need conversion first.
3. Start the analysis service with your key
The bundled reference-llm service uses Gemini. Replace your-gemini-api-key with your own key:
GEMINI_API_KEY=your-gemini-api-key docker compose up -d --build --wait
The Go CLI sends the transcript to your local service, which sends it to Gemini for analysis. Using your own key does not make Gemini inference offline. To use another model, see Use a different model.
The Compose stack also starts Postgres, although the single-session CLI does not use it. If host port 5432 or 8000 is already in use, remap it with a docker-compose.override.yml.
4. Analyze and save the result
go run ./cmd/analyze-real --url http://localhost:8000 extracted-session.json > analysis.json
Open analysis.json to read the verdict, turn and phase judgments, measured usage, and security flags. To check the setup with the bundled sample instead:
go run ./cmd/analyze-real --url http://localhost:8000 examples/transcript.sample.json > sample-analysis.json
Run docker compose down when you are done. Each analysis makes calls using your key and incurs your provider's usage charges.
What a result looks like
The output is a single analyze.Analysis JSON object. A trimmed example — a session verdict, one phase with a went_wrong and a friction_cause, one judged turn, and one security flag — is in examples/analysis.sample.json:
{
"session_id": "sample-session",
"ide_type": "CLAUDE_CODE",
"disposition": "PRODUCED",
"verdict": {
"underlying_goal": "Configure and wire payments client to provider API using environment secrets and preserved backoff retries.",
"goal_is_coding_work": true,
"goal_achieved": "SOMEWHAT",
"smoothness": "ROUGH",
"friction_cause": "PROMPT",
"score_overall": 3,
"score_clarity": 4
},
"phases": [
{
"ordinal": 0,
"theme": "CREATION",
"objective_met": "PARTIALLY_MET",
"friction_cause": "PROMPT",
"went_well": ["Agent asked clarifying questions when info was missing"],
"went_wrong": ["Prompt 1 leaked live API credentials directly in chat", "Agent hardcoded credentials and broke existing backoff logic, needing a correction round-trip"]
}
],
"turns": [
{
"prompt_index": 1,
"prompt_type": "CREATION",
"security_issues": [
{ "type": "api-key-leak", "severity": "CRITICAL", "note": "Live API key pasted directly into prompt." }
]
}
],
"security_flags": [
{ "type": "api-key-leak", "severity": "critical", "occurrences": ["Live API key pasted directly into prompt."] }
]
}
Enum-valued fields render as their short upper-snake names (an unresolved signal is the empty string); the sample file carries the full field set.
Supported tools and versions
The engine analyzes the normalized Conversation format, rather than reading vendor files directly. Source support comes from Agent Desk v0.1.0 / local-session-extractor v0.1.0, on macOS:
Tool (extractor reader version)
CLI / IDE / desktop surfaces read by the companion extractor
Formats covered
Codex (v2)
CLI, VS Code extension, Codex desktop app
Shared .codex rollout JSONL and state_5.sqlite; the reader documents the v0.118+ rollout shape and skips legacy files without a type envelope
Claude (v1)
Claude Code CLI, VS Code and desktop entry points; Claude desktop Cowork agent mode
.claude/projects JSONL and Cowork audit.jsonl stores
Kiro (v1)
CLI and IDE/desktop
CLI session.json + messages.jsonl, current IDE session format, and legacy desktop JSON history
Cursor (v2)
Desktop IDE and cursor-agent CLI
IDE conversation databases/transcripts and CLI ~/.cursor/chatsstore.db + meta.json
GitHub Copilot (v2)
CLI, VS Code / VS Code Insiders, JetBrains IDEs
CLI events.jsonl, VS Code JSONL and legacy JSON chat sessions, JetBrains Nitrite/H2 chat databases
Antigravity (v1)
Desktop IDE
Local session artifacts; full conversations depend on the running local server
Vendor release ranges are not certified. Except for the Codex format observation above, the companion project does not publish minimum/maximum supported vendor releases. The version beside each tool is the extractor's own reader code version, not a vendor app version. These readers cover the listed file layouts; a newer vendor release can change them. Ordinary Claude desktop chat is not the Cowork/Claude Code agent transcript covered here.
Check the installed extractor with local-session-extractor capabilities. For source locations, see its reference; the source readers define the formats covered. This engine does not require you to install or run the originating IDE once you have a normalized transcript.
Understand your results
Use the analysis to choose a concrete change for your next session:
Whether the session reached its goal and how much effort it took
Compare similar tasks over time to see whether your changes help
security_flags and per-turn security_issues
Exposed API keys, database credentials or personal data
Locate the affected exchange and address the exposure
The CLI returns structured JSON; it does not provide a dashboard or automatically track habits across sessions. Review several analyses to spot recurring patterns. Scores are model judgments, and usage metrics depend on what the transcript contains. Optional round-trip fault scoring requires a custom detector; the bundled placeholder is off by default. See Limitations for the exact boundaries.
No key yet? Try it offline
One example analyzes a built-in session with a fake model, so it needs no key and no Docker:
go run ./examples/analyze-raw-session
session: example-session (CLAUDE_CODE)
goal: Add retry with backoff and a unit test
coding work: true
scores: overall 8, clarity 7
turns: 2 judged, phases: 1
security flags: 0
To compile everything and run the offline suite:
go build ./... # compile every package
go test ./... # unit suites run offline; DAO/e2e tests skip without POSTGRES_TEST_DSN
This uses a fake model to demonstrate the output; it does not evaluate your own prompting. Every runnable example is listed in examples/README.md.
Embed in your product
Use this path when you want structured session analysis in your own application. The packages accept your model and storage dependencies explicitly.
Choosing an entry point
To embed Session Intelligence in your own product, pick the entry point that matches what you have.
You have
Use
Example
one transcript and your own key, and want its analysis
Every entry point is package-level Go, and each dependency is passed in as an interface. Importing the engine has no global side effects: it logs through a no-op logger until you call analyze.SetLogger, and registers no Prometheus metrics until you call analyze.RegisterMetrics.
Packages
These are the supported public import paths — the API contract:
Import path
What it gives you
github.com/tetriz-ai/session-intelligence/analyze
the main entry: AnalyzeSession, ParseConversation, the Provider and RoundTripDetector interfaces, and the Err* sentinels
the generated Conversation proto and its companions
Everything under github.com/tetriz-ai/session-intelligence/internal/ is implementation detail — not part of the API contract, and may change without notice. Do not import it.
Analyze one session with your own key
When: you have a single transcript and want its structured analysis without standing up Postgres or the batch pipeline. AnalyzeSession runs the spine, then the read, evidence and discard passes, over one in-memory Conversation, and returns a clean Analysis. It does no database or S3 access, so the only I/O is your Provider's LLM calls.
conv, err := analyze.ParseConversation(transcriptJSON) // or build *analyze.Conversation directly
if err != nil { /* ... */ }
analysis, err := analyze.AnalyzeSession(ctx, conv, analyze.Options{
Provider: analyze.NewReferenceLLMProvider("http://localhost:8000"), // or your own Provider
})
if err != nil { /* ... */ }
fmt.Println(analysis.Verdict.UnderlyingGoal, len(analysis.Turns), len(analysis.SecurityFlags))
Remember: the call is all-or-nothing, so a failed evidence or discard pass fails the whole call rather than returning a partial verdict. See Reference for the inputs it rejects before any provider call.
Use a different model
The engine is not tied to Gemini. The bundled reference service calls Gemini through the google-genai SDK, in reference-llm/app/llm/providers/gemini.py. You can run against any provider in one of two ways.
In Go, in process. Implement analyze.Provider — one GenerateContent method — and pass it in Options. The engine then calls your model directly, with no reference-llm at all.
When: a pass found security-layer issues on a record and you want the open flags for it. The complete program is in reconcile-security-flags, and runs offline:
Remember: a non-security slug is ignored rather than flagged, and each excerpt is masked as a backstop, not as redaction.
Plug your own round-trip detector
When: you want your own round-trip scoring in place of the bundled placeholder. The complete program is in custom-pair-detector: it implements analyze.RoundTripDetector and passes it through Options. It runs offline:
Remember: return a non-nil empty result when no pairs are supplied, and set Truncated when the pairs overflow the ceiling.
Running the full pipeline
The full engine reads raw records and persists analyses, so it needs Postgres. Two runs exercise it. The first is the CI acceptance gate and needs no key or Docker: it feeds a recorded fixture through a fake LLMProducer and a placeholder detector, and asserts it persists the session analysis with its turn, phase and state rows plus any security_flags.
createdb session_intelligence_test
psql -d session_intelligence_test -f migrations/latest.sql
# Or, against the docker-compose Postgres:
# POSTGRES_TEST_DSN="postgres://postgres:postgres@localhost:5432/session_intelligence"
POSTGRES_TEST_DSN="host=localhost port=5432 dbname=session_intelligence_test sslmode=disable" \
go test ./... -run TestFullStackSessionAnalysisE2E -count=1
The second runs the same pipeline with real LLM calls, against Postgres and the bundled reference reference-llm brought up by docker-compose. The provider key is read only from the environment.
Under the hood it runs a deterministic spine over the transcript, then a three-pass LLM pipeline — a read pass, an evidence pass and a discard pass.
flowchart LR
CONV[Conversation<br/>one transcript] --> SPINE
subgraph ENGINE["analyze.AnalyzeSession"]
direction LR
SPINE[Spine<br/>parse · telemetry<br/>· round-trip pairs<br/>· phases] --> R[R — read<br/>turns + phases]
R --> E[E — evidence]
E --> D[D — discard]
D --> OUT[Analysis]
end
R -.->|Provider| LLM[[your LLM<br/>or reference-llm]]
E -.->|Provider| LLM
D -.->|Provider| LLM
SPINE -.->|RoundTripDetector| PD[[round-trip detector<br/>optional]]
What it does not do
No multi-tenant row-level security, seat scoping or plan gating. This engine is single-tenant by design.
No dashboard-serving aggregate tier. The dao package carries the batch pipeline's persistence and reference readers, with nothing aggregating on top.
No corpus-fitted round-trip model. Only a transparent placeholder ships, and the detector defaults off.
No provider key ships. The real path reads GEMINI_API_KEY from the environment at run time.
Reference
AnalyzeSession
One session, one call. It sends the whole rendered transcript to the read pass in a single request rather than windowing it the way the batch path does.
Bounded input. A transcript past the single-call size ceiling returns analyze.ErrTranscriptTooLarge, and an empty or assistant-only one returns analyze.ErrNoTaggableTurns, both before any provider call.
Reconciled flags, masked.Analysis.SecurityFlags are reconciled to one flag per type at the highest severity, each excerpt masked. The per-turn Turns[].SecurityIssues are the raw readout, redacted but not deduped.
ProcessFlat
Processes every record and person. The seat and data-window gates fail open by default.
Returns the count and an error. It never panics on a missing or failing producer.
Abstains on unrecognized vendor tokens. An unknown enum token maps to the nil value, never a plausible default.
ReconcileOpenFlags
Three recognized types. Only api-key-leak, db-credential-leak and pii-injection become flags. Any other slug is ignored.
One flag per type. Repeats collapse to a single flag at the highest severity seen.
Unspecified severity defaults to "medium". A finding is never dropped for lacking a severity.
Evidence gate. Evidence-pass issues publish only when publishEvidence is true.
Empty is non-nil. With no pairs, Detect returns an empty, non-nil result.
Ceiling overflow is visible.Truncated is true when the pairs overflow the ceiling.
Glossary
Plain definitions of the terms this README uses.
Term
What it means
Session (transcript)
One coding-agent conversation — an ordered list of the person's and the agent's messages. It is the engine's unit of analysis, encoded as a Conversation.
Spine
The deterministic first pass. Before any LLM call it parses the transcript, computes telemetry, finds round-trip pairs and segments phases.
Turn
One judged exchange — a prompt and the agent's response — scored for things like whether its objective was met and how helpful the agent was.
Phase
A group of turns that make up one stage of the work.
Verdict
The session-level judgment: the underlying goal, whether it was coding work, quality scores, and outcome signals like smoothness and speed.
Outcome
Whether the session reached its goal.
Round-trip
A back-and-forth where the person had to re-engage the agent on the same thing — a correction or a repeat, which signals rework.
Round-trip detector
The optional seam (analyze.RoundTripDetector) that scores round-trip pairs. A transparent placeholder ships, off by default.
Security flag
Sensitive data that leaked into the session: a leaked API key, a database credential, or personal data (PII). One of three types, each with a severity from low to critical.
Read / Evidence / Discard
The three LLM passes after the spine. Read judges the turns, phases and verdict. Evidence judges artifacts and round-trip fault. Discard judges wasted effort.
Provider
The seam that makes the LLM calls (analyze.Provider). The bundled reference uses Gemini, and you can supply your own.
Disposition
Whether the analysis is complete (PRODUCED) or partial (PARTIAL).
Before you rely on it
Check these before you run the engine on data that matters. Each is pinned by a test.
Security flags
A raw secret can be persisted if an upstream finding left one in a note (can leak). This layer masks only well-known secret shapes as a backstop, pinned by TestReconcileMasksKnownSecretShapesInExcerpt. Sanitizing a finding is the finding's author's job, and a novel secret shape in a note will still be stored. Do not rely on this layer for redaction.
A detected finding always reaches an open flag. A security-layer issue is mapped to security_flags, never silently dropped, and an unspecified severity is published at "medium". Pinned by security/reconcile_test.go.
Flags more than it should (harmless). A non-security slug is ignored rather than flagged. Pinned by security/reconcile_test.go.
Round-trip detector
Misses (placeholder only). The bundled classifier is an uncalibrated placeholder, so the detector defaults off (ML_MODEL_INFERENCE__DETECTOR_ENABLED=false). With it on, the scores are not fitted, and the corpus-fitted model is not distributed.
Flags too much. None known.
Tenancy
Processes everything (gates fail open). The seat, plan and data-window gates default to unlimited — no seat cap, no window cutoff — so every record and person reaches the pipeline, and no row-level security is applied. This engine is single-tenant by design, with no scoping to install. Pinned by the DAO tests, which load a schema with no row-level security.
Project
Versioning and compatibility
This is v0.1.0, a pre-1.0 release: the public API and the proto package path may change before v1.0. The project follows semantic versioning, and a change to an exported signature is breaking. The toolchain floor is Go 1.25.0.
Tests
go test ./... runs the unit suites offline. The DAO and pipeline end-to-end tests need Postgres and skip without POSTGRES_TEST_DSN. CONTRIBUTING.md shows the setup. Every example runs in CI through scripts/run-examples.sh.
Contributing, security and license
Read CONTRIBUTING.md to build, test and lint. Every pull request needs a test.
Report a security vulnerability privately, following SECURITY.md. Do not open a public issue for it.
The code is MIT-licensed, in LICENSE. Copyright 2026 Workloom Solutions Private Limited. Contributors are listed in CONTRIBUTORS.md.
Package analyze is the single-session public front door to the session-intelligence engine: bring one coding-agent transcript and your own LLM provider, and get the same structured analysis the batch pipeline produces — a session verdict, judged turns, phases, outcome signals and security flags — with no database, no S3 and no per-org configuration.
Package analyze is the single-session public front door to the session-intelligence engine: bring one coding-agent transcript and your own LLM provider, and get the same structured analysis the batch pipeline produces — a session verdict, judged turns, phases, outcome signals and security flags — with no database, no S3 and no per-org configuration.
Command analyze-raw-session runs the public single-session front door — analyze.AnalyzeSession — over a raw session transcript (the JSON a coding-agent session is captured as) and prints the structured analysis: the session verdict, input-quality scores, and the judged turn and phase counts.
Command analyze-raw-session runs the public single-session front door — analyze.AnalyzeSession — over a raw session transcript (the JSON a coding-agent session is captured as) and prints the structured analysis: the session verdict, input-quality scores, and the judged turn and phase counts.
Command reconcile-security-flags shows the security detector's reconcile half: it maps the security-layer issues a producer found (an exposed API key, a leaked DB credential) to open security flags for a record, collapsing repeats to one flag per type at the highest severity seen.
Command reconcile-security-flags shows the security detector's reconcile half: it maps the security-layer issues a producer found (an exposed API key, a leaked DB credential) to open security flags for a record, collapsing repeats to one flag per type at the highest severity seen.
Package lineage defines the session-lineage metadata contract shared across the session pipeline — the flat raw_records.metadata keys the desktop sets on a child conversation, and the values the processor reads to fold children onto their parent.
Package lineage defines the session-lineage metadata contract shared across the session pipeline — the flat raw_records.metadata keys the desktop sets on a child conversation, and the values the processor reads to fold children onto their parent.
Package sessionanalysis is the session-analysis engine: the deterministic spine, the read/evidence/discard producers, commit, and round-trip detection.
Package sessionanalysis is the session-analysis engine: the deterministic spine, the read/evidence/discard producers, commit, and round-trip detection.
Package sessionintelligence holds the conversation parsing, pricing and metrics helpers the engine reads to turn a raw session transcript into structured input.
Package sessionintelligence holds the conversation parsing, pricing and metrics helpers the engine reads to turn a raw session transcript into structured input.