This document gives any coding agent the context it needs to contribute safely and effectively to the Sage project. It covers the problem Sage solves, the current implementation, tooling constraints, and the operational guardrails you must respect when extending the system.
- Problem Statement: Developers rely on Claude Code as their primary assistant, but they often want an automated second opinion. Manually copying conversations into another LLM breaks flow and loses repo context. Sage steps in as a passive reviewer: it mirrors a Claude session, reads the same repo, and produces critique cards without user intervention.
- End Goal (v0): Let the user run
sage, pick a Claude session, and receive a Codex-powered critique of that session's latest turn. Reviews must be read-only, grounded in the repo, and require zero extra commands in the developer workflow. Hooks are auto-configured on first run. - Future direction: Continuous hooks (streaming reviews as new turns arrive), richer follow-up conversations with Sage, and smarter resume handling across session forks.
| Area | Status |
|---|---|
| Session Discovery | Lists sessions from hook-emitted metadata in ~/.sage/{project-path}/runtime/sessions/. Automatically filters warmup-only stubs. |
| UI | Ink TUI (src/ui/App.tsx) with structured critique cards, queue display, and real-time status. Shows project name in header. |
| Export | Claude hooks write per-session metadata and review signals into ~/.sage/{project-path}/runtime/ (no external CLI required). |
| Review Engine | src/lib/codex.ts uses Codex SDK with JSON schema for structured output. src/lib/jsonl.ts parses Claude JSONL logs (primary turns only). Returns typed CritiqueResponse objects (verdict, why, alternatives, and optional message_for_agent for non-approved verdicts). |
| Continuous Mode | After initial review, Sage watches ~/.sage/{project-path}/runtime/needs-review/ for hook signals and enqueues reviews (FIFO). |
| UI Components | src/ui/CritiqueCard.tsx renders structured critiques with symbols (✓ ⚠ ✗) and color-coded verdicts. Reviews stack vertically for scrollback. |
| Artifacts | Prompts and context are archived under ~/.sage/{project}/debug/ for inspection. All reviews generate artifacts regardless of operation mode. |
┌─ Initial Setup ─────────────────────────────────────────┐
│ Hook installer (src/scripts/configureHooks.ts) │
│ └ registers SessionStart/Stop/UserPromptSubmit │
│ │
│ Hook shim (src/hooks/sageHook.ts) │
│ └ writes ~/.sage/{project-path}/runtime/sessions/*.json │
│ │
│ Session picker (src/ui/App.tsx) │
│ └ user selects session │
│ │
│ Initial review (src/lib/review.ts + jsonl.ts) │
│ └ loads transcript JSONL + runs Codex review │
└──────────────────────────────────────────────────────────┘
┌─ Continuous Mode (after initial review) ────────────────┐
│ User prompts Claude → Stop hook fires │
│ ↓ │
│ Hook shim writes ~/.sage/{project-path}/runtime/needs-review/{sessionId} │
│ ↓ │
│ App.tsx watcher notices new signal │
│ ↓ │
│ extractTurns(jsonl) for new assistant response │
│ ↓ │
│ Enqueue review job (FIFO queue in App.tsx) │
│ ↓ │
│ Incremental review (src/lib/review.ts) │
│ └ reuses existing Codex thread │
│ ↓ │
│ Codex SDK (src/lib/codex.ts) │
│ └ structured JSON output via schema │
│ ↓ │
│ CritiqueCard component (src/ui/CritiqueCard.tsx) │
│ └ renders structured critique with symbols │
└──────────────────────────────────────────────────────────┘
Key modules and responsibilities:
src/hooks/sageHook.ts— Receives Claude Code hook payloads (SessionStart/Stop/UserPromptSubmit). Writes per-session metadata to~/.sage/{project-path}/runtime/sessions/and queues review signals in~/.sage/{project-path}/runtime/needs-review/. Note: SessionEnd hook was removed due to unreliability.src/scripts/configureHooks.ts— Hook configuration module that auto-installs Sage hooks on startup. Also available as CLI helper (npm run configure-hooks). Uses absolute paths to Sage's compiled hook script (dist/hooks/sageHook.js) to work correctly when Sage is installed globally via npm.src/lib/jsonl.ts— Streams Claude JSONL transcripts, filters warmups/compactions, and extracts user⇄assistant turns.src/lib/review.ts— Review orchestration layer. Handles initial and incremental critiques, stores thread metadata, and generates artifacts.src/lib/codex.ts— Codex SDK wrapper with JSON schema for structured output. Builds initial and follow-up prompts, manages thread lifecycle.src/ui/App.tsx— Main TUI orchestrator. Manages session picker, signal watcher (chokidar), FIFO queue, continuous review state, and chat threads.src/ui/CritiqueCard.tsx— Structured critique renderer with symbol-coded verdicts and color-coded sections.
- Claude Code 2.0.24+ — Required so delegated agent work is written to
agent-*.jsonlfiles (modern log format Sage expects). - OpenAI Codex SDK (
@openai/codex-sdk) handles review generation. It talks to the local Codex agent; no API key is set in this repo. - Ink / React render the TUI. Components rely on Node 18+.
- Claude JSONL logging retains fields like
type,sessionId,message.{role,content},summary, and optional prompt caching warmups.
- Claude injects
Warmupuser turns to prime prompt caching. These appear as sidechain user entries with no follow-up. Sage treats any session whose only main user prompt is “Warmup” (case-insensitive) as a warmup stub (isWarmup === true) and hides it from the picker. - Resuming a session (
claude --resume) clones the prior transcript into a new JSONL with a newsessionId, then appends fresh turns. Turn signatures (assistant UUIDs) are reused, so Sage relies on cachedlastTurnSignaturevalues to skip already-reviewed history.
- Ensure Claude Code and the Codex agent are running locally.
- From any project directory, run
sage(if installed globally) ornpm startfrom the Sage repo. - First run: Sage automatically configures Claude hooks in
.claude/settings.local.json. You'll see "✓ Hooks configured" in the session list. If auto-configuration fails, a warning appears with manual setup instructions. - Sage shows an Ink TUI with session picker:
- Arrow keys to navigate sessions.
Enterto select a session for review.Rto refresh session list (re-read~/.sage/{project-path}/runtime/sessions/metadata).
- After selection, Sage performs initial review and enters continuous mode:
- Status line shows
⏵ Running initial review...during setup - Confirms Claude hooks are writing metadata to
~/.sage/{project-path}/runtime/ - Starts watching
~/.sage/{project-path}/runtime/needs-review/for new signals
- Status line shows
- As you continue with Claude Code, Sage automatically reviews new turns:
- New turns are queued (FIFO) and displayed with prompt previews
- Status shows
⏵ Reviewing "..."with queue count - Completed critiques stack vertically (scroll terminal to see history)
- Each critique card displays:
- Symbol-coded verdict: ✓ Approved | ⚠ Concerns | ✗ Critical Issues
- WHY section (color-coded: green/yellow/red)
- ALTERNATIVES section (if applicable)
- QUESTIONS section (if applicable)
- MESSAGE FOR CLAUDE CODE AGENT section (only for Concerns/Critical Issues verdicts, when Sage has specific guidance for Claude)
- Keyboard controls in continuous mode:
Mto rescan signal files (useful if a hook ran while Sage was closed)Bto exit and return to session pickerCtrl+Oto toggle the Codex activity stream overlay
Do this:
- Keep Sage read-only. Don't add write or execute permissions to Codex threads.
- Maintain prompt clarity: any new Codex prompts must emphasize repo inspection, correctness, and admitting uncertainty.
- Use structured output schemas for Codex responses. All fields must be in the
requiredarray (OpenAI constraint). Instruct Codex to return empty strings for optional sections. - Respect the warmup filter—don't reintroduce warmup-only sessions into the picker unless you add an explicit toggle.
- Preserve sidechain filtering in
extractTurns()—only primary Claude/developer turns should enqueue reviews or reach Codex. - Capture plan-mode answers:
extractTurns()now threadstool_resultpayloads (e.g., “User answered Claude’s question…”) back into the assistant turn so Sage sees the full context. If Claude changes the schema for those results, update the parser rather than re-implementing the logic elsewhere. - When touching session parsing, account for resume forks and unusual content; tolerant parsers prevent crashing on new Claude schema changes.
- Update docs (
what-is-sage.md,agents.md, troubleshooting notes) whenever behavior or CLI flags change.
Avoid this:
- Don’t mutate
process.cwd()or assume Codex will operate in a specific directory unless you pass the right context (future enhancement). - Avoid duplicating Claude JSONL parsing—extend
src/lib/jsonl.tsif you need additional metadata. - Don’t silently swallow errors from Codex or hooks; surface meaningful messages in the UI.
- Resume chains: Sage relies on cached assistant UUIDs to skip duplicated turns when Claude creates a new transcript on resume. More robust cross-file stitching is still future work.
- Thread persistence: ✅ Sage now saves Codex thread metadata to
~/.sage/{project-path}/threads/and automatically resumes threads when re-selecting sessions. TheisFreshCritiqueflag prevents duplicate critiques when resuming unchanged threads. This enables context preservation across Sage restarts and faster incremental reviews. Seedocumentation/thread-persistence.mdfor details. - Partial responses: Sage now records “partial” critiques when you press
Mduring Claude’s response. These show a yellow banner and keep the existing canonical turn signature untouched so a second, definitive review runs automatically once Claude finishes. Use manual sync freely—partial and final critiques both remain in the scrollback, so developers can see what changed. - Critique history navigation: Reviews stack vertically for scrollback but no arrow-key navigation within the UI. Users scroll their terminal to see previous reviews.
- Read-only enforcement: Codex threads currently rely on context instructions; explicit permission settings (if supported by the SDK) would enhance safety.
- Comprehensive logging: Minimal debug output goes to the console; consider writing a log file for diagnosing hook or Codex failures.
| Task | Command / File |
|---|---|
| Start Sage TUI | npm start or tsx src/index.tsx |
| TypeScript build check | npm run build |
| Session discovery & listing | src/lib/jsonl.ts |
| Hook auto-configuration | src/scripts/configureHooks.ts (runs automatically on startup) |
| Manual hook setup | npm run configure-hooks |
| Codex prompt builder & schemas | src/lib/codex.ts |
| Review orchestration | src/lib/review.ts |
| Critique card component | src/ui/CritiqueCard.tsx |
| Hook shim | src/hooks/sageHook.ts |
- Artifacts (Always Created): Sage writes prompt instructions plus the raw conversation/context to
~/.sage/{project}/debug/review-<prompt>.txtfor every review. Filenames are sanitized and deduplicated. Each review card displays the artifact path underneath "Review #x • ..." so you can always inspect what was sent to Codex. - Purpose: Allows developers to inspect exactly what prompt and context were sent to Codex during each review. Useful for understanding how Sage formulates critiques and debugging unexpected review results.
- File Format: Artifacts include headers with session ID and review type, followed by the INSTRUCTIONS section (system prompt sent to Codex) and CONTEXT section (formatted conversation turns).
- Cleanup: Remove the
~/.sage/{project}/debug/folder or individual files when you no longer need them. They can accumulate quickly during rapid iteration.
Keep this guide up to date as the architecture evolves—future contributors (human or agent) should be able to read it and immediately understand the system’s intent, boundaries, and extension points. Happy reviewing! 🎩