Trajectory is an experimental Manifest V3 Chrome side-panel extension that turns one complete ChatGPT conversation into a concise, source-grounded retrospective.
- Arc reconstructs what happened chronologically.
- Findings identify patterns across multiple exchanges.
- Show in chat verifies a finding against the exact source passage.
Trajectory reads the active authenticated ChatGPT tab through its content script. The backend never fetches private ChatGPT URLs and never receives ChatGPT cookies or account credentials.
The repository includes a prepared, sanitized browser sandbox. From the checkout, run:
node scripts/serve-demo.mjsOpen http://127.0.0.1:4173. No dependency install, extension build, ChatGPT account, OpenAI key, or network analysis is required.
Suggested review flow:
- Expand phases in Arc.
- Open Findings and select a finding.
- Expand Supporting phases, Evidence, and Limits.
- Change Compact/Default/Large text size with
Aa. - Resize the browser to inspect the fixed side-panel layout.
The prepared sandbox demonstrates the complete Arc/Findings UI and reviewed
source evidence. Show in chat is simulated because the sandbox is deliberately
not attached to a private ChatGPT conversation. See
docs/judge-guide.md for the test scope and live-plugin
path.
Requirements: Node.js 20.19 or newer and npm.
npm install
npm run sampleOpen http://127.0.0.1:5173/responsive-fixture.html. This isolated preview uses reviewed sample messages and analysis. It does not open ChatGPT, call OpenAI, or install the Chrome extension.
The sample supports these query parameters:
?size=compact|default|large
?view=arc|findings
-
Install dependencies and create the server environment:
npm install cp .env.example .env
-
Set at least these values in the repository-root
.env:OPENAI_API_KEY=your-server-side-key OPENAI_MODEL=a-structured-outputs-compatible-model ALLOWED_ORIGINS=http://localhost:5173 VITE_ANALYSIS_API_URL=http://localhost:8787
Never prefix the OpenAI key with
VITE_. Vite variables are bundled into browser code; the API key must remain server-side. -
Start the extension watchers and local analysis server:
npm run dev:live
-
Open
chrome://extensions, enable Developer mode, choose Load unpacked, and select this repository'sdist/directory. -
Open a conversation at
https://chatgpt.com, open Trajectory from the extension action, and choose Analyze conversation. -
Reload the unpacked extension from
chrome://extensionsafter a rebuild.
npm run dev is an alias for npm run dev:live.
| Component | Supported |
|---|---|
| Chrome extension | Desktop Chrome 116+ on macOS, Windows, and Linux |
| Conversation source | Authenticated https://chatgpt.com conversations |
| Analysis server | Node.js 20.19+ on macOS, Windows, or Linux |
| Prepared judge demo | Current Chrome, Edge, Firefox, or Safari with Node.js 20.19+ available to serve static files |
The extension is not currently packaged for Firefox, Safari, mobile Chrome, the ChatGPT desktop app, or other conversation providers.
The source server, compiled server, smoke test, and live development launcher
all resolve .env from the repository root. To use another file, set
TRAJECTORY_ENV_FILE to its path.
| Variable | Required | Purpose |
|---|---|---|
OPENAI_API_KEY |
live | Server-only OpenAI credential |
OPENAI_MODEL |
live | Model used by the Responses API |
VITE_ANALYSIS_API_URL |
extension | Analysis service URL compiled into the extension |
ALLOWED_ORIGINS |
server | Comma-separated browser origins allowed by CORS |
ANALYSIS_PIPELINE_MODE |
no | fast (one model call) or thorough (two calls) |
OPENAI_REASONING_EFFORT |
no | Model reasoning effort when supported |
OPENAI_TEXT_VERBOSITY |
no | low, medium, or high |
PORT |
no | Server port; defaults to 8787 |
MAX_TRANSCRIPT_CHARS |
no | Maximum normalized transcript size |
MAX_REQUEST_BODY_BYTES |
no | Raw JSON request ceiling |
ANALYSIS_TIMEOUT_MS |
no | Analysis timeout |
RATE_LIMIT_WINDOW_MS |
no | In-memory rate-limit window |
RATE_LIMIT_MAX_REQUESTS |
no | Requests allowed per window |
See .env.example for defaults and safety notes.
| Command | What it does |
|---|---|
npm run demo:serve |
Serves the committed prepared demo without rebuilding |
npm run sample |
Serves the isolated sample UI |
npm run build:sample |
Regenerates the committed static demo for maintainers |
npm run dev:live |
Builds/watches the extension and starts the live API |
npm run dev:mock |
Runs deterministic extension fixture mode after a fixture is prepared |
npm run smoke:openai |
Makes a tiny structured OpenAI request using server configuration |
npm run evaluate:analysis |
Runs the offline golden quality evaluation |
npm run evaluate:analysis -- --live |
Intentionally evaluates the golden transcript with OpenAI |
npm run verify:demo |
Validates the bundled demo fixture |
npm test |
Runs unit and integration tests without live model calls |
npm run typecheck |
Checks extension, scripts, shared code, and server types |
npm run build |
Produces extension and server production builds |
npm run check |
Runs tests, type checks, and both production builds |
npm start |
Starts the already-built analysis server |
The repository contains two sanitized datasets:
fixtures/trajectoryGolden.tsis a 50-message regression fixture used by the sample page and analysis-quality checks.src/analysis/fixtures/trajectory-demo.analysis.jsonis a 16-message packaged extension fixture used by explicit mock mode.
The checked-in demo uses a non-routable sample conversation identifier. It is not tied to a private ChatGPT URL. To create a deterministic extension demo for a conversation you control, analyze it in live mode, export the verified fixture, and import it with:
npm run demo:import-fixture -- /path/to/trajectory-demo.fixture.json
npm run verify:demo
npm run dev:mockFixture mode is always labeled PREPARED DEMO. Production and live analysis
never silently fall back to sample data.
Active ChatGPT tab
-> content-script extraction and controlled full-thread traversal
-> background state scoped to the tab and conversation
-> side-panel fingerprint and local cache lookup
-> user-initiated POST /api/analyze
-> OpenAI Responses API with Structured Outputs
-> deterministic grounding and quality validation
-> Arc and Findings
-> optional exact source-range navigation
The analysis service exposes:
GET /api/health— service and schema health information.POST /api/analyze— complete normalized conversation analysis.
Validated analyses are cached in chrome.storage.local by conversation
identity, transcript fingerprint, analysis schema version, and pipeline
version. A changed transcript cannot reuse a stale analysis as current.
See docs/architecture.md for the extraction, analysis, grounding, caching, and source-navigation design.
GPT-5.6 and Codex served different roles:
- GPT-5.6 powered the live conversation analysis during submission
development. The server sends the complete normalized transcript through the
Responses API, asks for structured phases, findings, and exact source
references, then applies deterministic validation before rendering anything.
The model remains configurable through
OPENAI_MODEL; it is not bundled into the extension. - Codex accelerated implementation across the Chrome extension, shared schema, Node server, tests, diagnostics, and documentation. It was used to inspect the existing code before edits, implement bounded changes, reproduce errors from console output and screenshots, and run the full verification loop after each change.
The product direction remained human-led. The decisive changes—abandoning message scores, removing fixed lenses and correction controls, reducing the UI to Arc and Findings, and requiring exact source verification—came from explicit product critique and were then implemented and regression-tested with Codex.
See docs/ai-development.md for the decision history, specific acceleration points, and safeguards used to review AI-assisted work.
src/ Chrome side panel, background worker, content script
server/ Express analysis API and OpenAI orchestration
shared/ API types, validation, labels, and quality checks
fixtures/ Golden transcript and reviewed expected analysis
demo/ Prepared static judge sandbox (committed)
scripts/ Development, fixture, smoke, and evaluation tools
docs/ Architecture, development, privacy, and deployment notes
public/manifest.json Chrome extension manifest source
dist/ Generated unpacked extension (ignored)
server-dist/ Generated server build (ignored)
- Analysis is user initiated outside explicit fixture mode.
- OpenAI requests use
store: false. - The server logs counts, sizes, request IDs, latency, token usage, and status; it does not log conversation text, titles, URLs, model output, or credentials.
- The included rate limiter is process-local demo protection, not production authentication, billing control, or distributed abuse prevention.
- A publicly reachable endpoint can create material OpenAI cost. Add durable authentication, quotas, distributed rate limiting, monitoring, and budget controls before exposing it broadly.
See docs/privacy-and-deployment.md before deploying the server.
Before opening a change:
npm run checkAutomated tests never call OpenAI. Live smoke and quality evaluation commands must be invoked explicitly.
See docs/judge-guide.md for submission testing, CONTRIBUTING.md for the development workflow, and SECURITY.md for reporting security issues.
- ChatGPT's DOM, virtualization, and route structure are not public stable APIs.
- Rich text and code are normalized to plain text; images are not analyzed.
- Very long or actively streaming threads may not be verifiably complete.
- Exact source grounding prevents mismatched navigation but does not guarantee that every model interpretation is useful.
- There are no accounts, cloud sync, background monitoring, or cross-conversation projects.
This project intentionally ignores .env, generated builds, logs, coverage,
and evaluation artifacts. Before pushing a new repository:
git init
git status --ignored
npm run checkReview the staged diff and sample transcripts manually. Do not force-add
.env, dist/, server-dist/, artifacts/, private ChatGPT URLs, or real
conversation/project identifiers. Commit the generated demo/ directory so
judges can run the prepared sandbox without rebuilding it.
Trajectory is available under the MIT License.