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.goto 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.cssfor styling,static/session.jsfor client-side interactivity
Template parsing uses parseTemplate with a template.FuncMap providing helpers:
formatDuration– humanizes time spansseverityCounts– aggregates issue severitygroupCommentsByFile– 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_HOSTSenvironment 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 loadingX-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:
-
Generation: When
ocr reviewfinishes, the CLI writes a JSONL transcript (one line per telemetry span) to~/.ocr/sessions/<repo>/<sessionID>.jsonl -
Loading: The Viewer calls
store.goutilities to:- Discover available repositories and sessions
- Stream-read JSONL files
- Decode into Go structs
-
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
-
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →