Skip to content

Architecture

Optra Prism is three stacked measurement layers and one parallel intelligence pipeline. Layers are numbered bottom-up by data flow — signals rise from Layer 0 through Layer 1 into Layer 2 — and each layer holds exactly one kind of thing.

flowchart LR
    L0["Layer 0 — Telemetry<br/>OpenTelemetry from Claude Code"] --> L1["Layer 1 — Facts<br/>goal_complete · rework · tokens · prompt_grade"]
    L1 --> L2["Layer 2 — Scores<br/>Prompt Score (APG) · Completion rate"]
    L1 -.-> PIQ["Prompt Rubric Agent<br/>7 booleans × 8 intents"]
    PIQ -.-> L1

    style L0 fill:#22c55e,stroke:#16a34a,color:#fff
    style L1 fill:#f59e0b,stroke:#d97706,color:#fff
    style L2 fill:#8b5cf6,stroke:#7c3aed,color:#fff
    style PIQ fill:#a855f7,stroke:#9333ea,color:#fff

The single source of truth. Claude Code emits cost, tokens, events, links, and labels via OpenTelemetry. No git webhook, no repo scanner, no CI integration.

Three flags need to be set for full functionality:

Terminal window
CLAUDE_CODE_ENABLE_TELEMETRY=1
OTEL_LOG_USER_PROMPTS=1
OTEL_LOG_TOOL_DETAILS=1

Without OTEL_LOG_USER_PROMPTS, the prompt rubric, goal_complete, and rework LLM judges all run in degraded mode — the prompt text isn’t available to the agents. Pure-counter metrics (tokens, turns, active time) are unaffected, but sub-sessions affected by this fall back to “unscored” rather than getting an inaccurate Prompt Score. Without OTEL_LOG_TOOL_DETAILS, file-path extraction breaks; sub-session boundary reconciliation still runs on timestamps, topic shifts, and /clear events.

The /prism:setup flow wires these flags up automatically.

For each sub-session, the API extracts the four atomic facts that determine its outcome:

  • goal_complete — Boolean. Did the developer reach the sub-session’s stated goal? LLM-judged from the session’s telemetry.
  • rework — Boolean. Did the goal then have to be redone? Detected from later-session telemetry (correction turns and follow-up work), not from git.
  • token_sum — Integer with model breakdown. From OTel: tokens.input, tokens.output, tokens.cache_read, tokens.cache_write.
  • prompt_grade — Letter A+→F. Rolled up from the prompt rubric (7 booleans × 8 intent classes); see the Prompt Rubric Agent below.

A sub-session is crushed when it passed the substance floor, goal_complete is true, and rework is not. That feeds the supporting Completion rate at Layer 2.

Developer-facing numbers, derived from Layer 1 by pure arithmetic — no LLM judgment at this layer.

ScoreFormulaRange
Prompt Score (headline)Average Prompt Grade (APG) — mean of per-prompt prompt_grade0–100 + letter grade
Completion rate (supporting)crushed sub-sessions ÷ scored sub-sessions0–100%

The headline is the Prompt Score — the average prompt grade, shown with a letter grade at the top of the dashboard. The Completion rate (share of scored sub-sessions that crushed) is a supporting outcome metric. The same arithmetic computes both personal and team views; team scores are team-aggregate, never the average of per-developer scores. The developer-facing view rests on three supporting metrics — Speed (CSPW), Skill (Skill Index), and Token Usage (Crush Weight) — plus a Skill tier (Novice → Elite). See the Prompt Score section for each, and The scoring model for how the numbers fit together.

Prompt Rubric Agent — intelligence pipeline

Section titled “Prompt Rubric Agent — intelligence pipeline”

The rubric agent runs alongside the layers, not above them. It turns raw prompts into the per-prompt letter grade that feeds prompt_grade:

  1. Language detection + intent classification — classifies each prompt into one of eight intent classes (Question, Investigation, Review, Plan/Spec, Small change, Bug fix, Feature, Refactor), with confidence.
  2. Rubric scoring — judges the prompt against seven booleans: goal_explicit, scope_bounded, references_concrete, context_sufficient, verification_requested (double-weighted), root_cause_oriented, plan_first. Applicability of each boolean depends on the intent class.
  3. Letter grade — the applicable-and-passed booleans roll up into a 0–100 numeric score, which maps to a letter grade via the v3 rubric bands (A+ ≥ 90, B ≥ 50 baseline, down to F below 12).
  4. Aggregation — per-prompt grades aggregate into the sub-session’s prompt_grade fact.

Everything the rubric agent produces is auditable end-to-end: each boolean’s pass/fail and the intent class are logged so a human can see why a prompt scored the way it did.

sequenceDiagram
    participant Dev as You
    participant Plugin as Prism Plugin
    participant Ingest as Ingest Service
    participant Worker as Prism Worker
    participant API as Prism API
    participant Dash as Dashboard

    Dev->>Plugin: Write a prompt
    Plugin->>Ingest: Send OTLP + prompt text
    Ingest->>Worker: NATS publish
    Worker->>Worker: Parquet write → boundary reconciler → facts + rubric → trend aggregator
    Dev->>Dash: Open /prism
    Dash->>API: Query scored product data
    Dash-->>Dev: Prompt Score + letter grade + 3 supporting metrics

Everything the dashboard shows is recomputable from S3 Parquet + Postgres — no scores live only in memory.

All communication uses your Prism API key. Prism issues and stores it for you; the Connect panel in the dashboard header shows the setup command with the key already in it. New keys are prism_* (legacy gck_* keys are still accepted).

  • The plugin includes your key on every request to Ingest
  • Ingest validates the key and associates data with your organization
  • Dashboard access uses Supabase login (email/password or OAuth)

Your key is stored locally in ~/.prism/config.json with restricted file permissions.

The Plugin key is stored locally in ~/.prism/config.json. It authenticates your Claude Code traffic when it is redirected through the legacy Optra gateway — the key you set with /prism:setup.