How the Open Code Review Session Viewer Interface Works: Architecture, Security, and Data Flow

The Session Viewer is a lightweight, browser-based UI in open-code-review that lets you browse, replay, and analyze past code review sessions through a three-layer HTTP server architecture with built-in host-guard security.

The alibaba/open-code-review project ships with a built-in Session Viewer that transforms locally stored JSONL transcripts into an interactive web interface. This component allows developers to inspect LLM-generated review outputs, replay reasoning timelines, and filter results by severity—all without sending sensitive code to external services. Understanding how the session viewer interface works reveals a thoughtfully designed balance between usability and security.

Three-Layer Architecture of the Session Viewer

The Session Viewer implementation in internal/viewer/ follows a clear separation of concerns across three layers: HTTP server setup, request routing with data handling, and template-based presentation.

HTTP Server Layer

The entry point is internal/viewer/server.go, where the StartServer function creates a hardened HTTP server:

// Simplified view of server.go responsibilities
mux := http.NewServeMux()
// Static assets mounted at /static/
// Routes registered for /, /r/{repo}, /r/{repo}/{sessionID}
// Wrapped with host-allowlist guard and security-header middleware

The server:

  • Resolves the sessions directory (SessionsRoot, typically ~/.ocr/sessions/)
  • Registers static asset handlers
  • Applies host-guard middleware (from hostguard.go) to prevent DNS-rebind attacks
  • Injects security headers via securityHeaders.go (Content-Security-Policy, X-Content-Type-Options, etc.)

Routing and Handler Layer

internal/viewer/handler.go implements three core handlers:

Route Handler Function Purpose
/ handleRepos Lists all repositories with stored sessions
/r/{repo} handleSessions Lists sessions for a specific repository
/r/{repo}/{sessionID} handleSession Renders detailed view of a single session

These handlers:

  • Call into internal/viewer/store.go to locate and read JSONL transcript files
  • Unmarshal spans into Go structs (Session, ReviewComment, etc.)
  • Compute aggregates: severity counts, task cards, comments grouped by file
  • Pass structured data to HTML templates

Presentation Layer

The UI renders through:

  • HTML templates in templates/*.html (repo list, session list, session detail)
  • Static assets: static/style.css for styling, static/session.js for client-side interactivity

Template parsing uses parseTemplate with a template.FuncMap providing helpers:

  • formatDuration – humanizes time spans
  • severityCounts – aggregates issue severity
  • groupCommentsByFile – organizes review output by affected file

Security Measures Protecting Session Data

The session viewer implements two critical defenses against local data exposure:

Host-Guard Protection

In hostguard.go, requests are filtered by Host header against an allow-list derived from:

  • The OCR_VIEWER_ALLOWED_HOSTS environment variable, or
  • The server's bind address

This prevents DNS-rebind attacks that could trick a browser into exposing session transcripts to malicious websites.

Security-Header Middleware

securityHeaders.go injects hardening headers on every response:

  • Content-Security-Policy – restricts resource loading
  • X-Content-Type-Options: nosniff – prevents MIME-type sniffing
  • Additional headers for clickjacking and XSS protection

Data Flow: From Review to Browser

The complete lifecycle of session data:

  1. Generation: When ocr review finishes, the CLI writes a JSONL transcript (one line per telemetry span) to ~/.ocr/sessions/<repo>/<sessionID>.jsonl

  2. Loading: The Viewer calls store.go utilities to:

    • Discover available repositories and sessions
    • Stream-read JSONL files
    • Decode into Go structs
  3. Aggregation: Handlers compute derived data structures for the UI:

    • Hierarchical navigation (repos → sessions → timeline)
    • Task cards for plan, main, relocation, and memory-compression phases
    • Filterable comment lists with severity badges
  4. Rendering: Templates receive pre-computed data and generate HTML with Content-Type: text/html

Launching the Session Viewer

Start the interface from your terminal:

ocr viewer                    # Default: 127.0.0.1:8080

ocr viewer --addr :3000       # Custom port

# Or via environment variable:

OCR_VIEWER_ADDR=0.0.0.0:8080 ocr viewer

The CLI command lives in cmd/opencodereview/viewer_cmd.go, which parses flags and delegates to viewer.StartServer(addr).

Enable external access only when needed (the host-guard will still enforce allow-list validation):

OCR_VIEWER_ALLOWED_HOSTS="localhost,myhost.example.com" ocr viewer --addr 0.0.0.0:8080

Key Implementation Files

File Purpose
cmd/opencodereview/viewer_cmd.go CLI entry point, flag parsing
internal/viewer/server.go HTTP server setup, middleware wrapping
internal/viewer/handler.go Request handlers for three route patterns
internal/viewer/store.go Session directory resolution, JSONL loading
internal/viewer/hostguard.go Host-allowlist security filter
internal/viewer/securityHeaders.go Response header hardening
internal/viewer/templates/*.html Go HTML templates
internal/viewer/static/style.css UI styling
internal/viewer/static/session.js Timeline interactivity, filtering

Summary

  • The Session Viewer provides browser-based access to locally stored review transcripts without external dependencies
  • Three-layer architecture separates server setup (server.go), data handling (handler.go), and presentation (templates/static assets)
  • Host-guard middleware and security headers protect against DNS-rebind and injection attacks
  • JSONL transcripts are read on-demand and aggregated into filterable, hierarchical views
  • Launch with ocr viewer—bind address and allow-list configurable via flags or environment

Frequently Asked Questions

How do I access the Session Viewer from another machine?

Set OCR_VIEWER_ADDR=0.0.0.0:8080 and add your hostname to OCR_VIEWER_ALLOWED_HOSTS. The host-guard will reject requests from unlisted Host headers even when bound to all interfaces.

Where are session files stored?

Transcripts live in ~/.ocr/sessions/<repo>/<sessionID>.jsonl. The store.go utilities resolve this path and stream-read the JSONL format—one JSON object per line representing telemetry spans.

Can I customize the viewer's appearance?

The templates in internal/viewer/templates/ and styles in internal/viewer/static/style.css can be modified before rebuilding. The Go template system uses a FuncMap with helpers like formatDuration for consistent rendering.

What data structures power the session detail page?

The handleSession function in handler.go unmarshals spans into Session and ReviewComment structs, then computes aggregates: severity counts, task-phase cards, and file-grouped comments. These pre-computed structures drive the timeline and filtering UI.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →