Skip to content

feat: Codex adversarial reviewers, spec sharing, and Console improvements#123

Merged
maxritter merged 2 commits intomainfrom
dev
Mar 31, 2026
Merged

feat: Codex adversarial reviewers, spec sharing, and Console improvements#123
maxritter merged 2 commits intomainfrom
dev

Conversation

@maxritter
Copy link
Copy Markdown
Owner

@maxritter maxritter commented Mar 31, 2026

Codex Adversarial Reviewers

  • Rename review agents: plan-reviewerspec-review, spec-reviewerchanges-review across 30+ files
  • Add optional Codex adversarial review for spec planning and code verification — provides an independent second opinion powered by OpenAI Codex
  • Codex reviewers disabled by default, configurable via Console Settings → Spec Workflow → Codex Reviewers
  • Auto-detect Codex plugin at launcher startup, inject env vars (PILOT_CODEX_AVAILABLE, PILOT_CODEX_SPEC_REVIEW_ENABLED, PILOT_CODEX_CHANGES_REVIEW_ENABLED)
  • Crash/timeout handling: graceful skip on Codex job failure (waitTimedOut, cancelled, non-zero exit)
  • Use --scope working-tree for changes review (works with unstaged files)
  • Config migration v7: rename reviewer keys, add codexReviewers section
  • Fix agent [1m] bug: sub-agents no longer get extended context suffix
  • Fix stale command names in Settings (sync/learnsetup-rules/create-skill)
  • Add Codex to README prerequisites, docusaurus docs, installer post-install, and launcher banner
  • Faster reviewer polling (sleep 2 instead of sleep 10)

Spec Sharing

  • E2E encrypted spec sharing with collaborative annotation feedback
  • Public sharing via website for users without Pilot Shell installed

Console & Settings Improvements

  • Remove statusline spec config flags ([plan-rev spec-rev wt])
  • Extended Context description: line break + wording update ("not included in Max subscription anymore")
  • Update reviewer cards UI: 2x2 grid for Claude + Codex reviewers (Codex cards grayed when plugin absent)
  • Dashboard, extensions, and usage screenshot updates

Test Results

  • Python: 1280 passed (launcher, installer, hooks)
  • Console: 1264 passed, typecheck clean
  • Build: Console artifacts rebuilt successfully

Summary by CodeRabbit

  • New Features

    • Optional Codex plugin for adversarial second-opinion reviews during /spec
    • Feedback & annotation UI: inline annotations, toolbar, feedback sidebar, and a Shared page for secure spec viewing
    • Secure spec sharing: client-side compression, encryption, and share/feedback URL generation
  • Settings / UX

    • Added Codex reviewer toggles and an Extended Context (1M) toggle; renamed reviewer labels to “Spec Review” and “Changes Review”
  • Documentation

    • Updated getting-started, workflow, routing, hooks, and status-line docs to reflect above changes

…ovements

Codex Integration:
- Rename review agents: plan-reviewer → spec-review, spec-reviewer → changes-review
- Add optional Codex adversarial review for spec planning and code verification
- Codex reviewers disabled by default, configurable via Console Settings
- Auto-detect Codex plugin at startup, inject env vars for commands
- Crash/timeout handling for Codex jobs (graceful skip on failure)
- Use --scope working-tree for changes review (works with unstaged files)
- Config migration v7: rename keys, add codexReviewers section
- Fix agent [1m] bug: sub-agents no longer get extended context suffix
- Fix stale command names in Settings (sync/learn → setup-rules/create-skill)
- Add Codex to README prerequisites, docusaurus docs, installer, and launcher banner

Spec Sharing:
- E2E encrypted spec sharing with collaborative annotation feedback
- Public sharing via website for users without Pilot Shell

Console & Settings:
- Remove statusline spec config flags (plan-rev/spec-rev/wt)
- Extended Context description line break and wording update
- Update reviewer cards UI with 2x2 grid for Claude + Codex reviewers
- Faster reviewer polling (sleep 2 instead of sleep 10)
- Dashboard, extensions, and usage screenshot updates
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
pilot-shell Ignored Ignored Preview Mar 31, 2026 11:19am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3a83cca-aa50-470e-939a-965e92b4e7bc

📥 Commits

Reviewing files that changed from the base of the PR and between 2d7a032 and 77f5c2d.

📒 Files selected for processing (5)
  • docs/site/src/lib/sharing/sharing.ts
  • docs/site/src/pages/Shared.tsx
  • installer/steps/config_migration.py
  • installer/steps/finalize.py
  • installer/tests/unit/steps/test_finalize.py

Walkthrough

Renames reviewer agent keys and UI text to Spec/Changes Review, adds optional Codex adversarial reviewers, reduces hook count to 15, adds an annotation UI and secure share/feedback flow to the docs site, and implements config migration to version 7 plus installer adjustments.

Changes

Cohort / File(s) Summary
Docs — Reviewer & Console
docs/docusaurus/docs/features/console.md, docs/docusaurus/docs/workflows/spec.md, docs/docusaurus/docs/features/model-routing.md
Renamed review phases (plan → spec, code → changes), updated config keys (planReviewer/plan-reviewerspecReview/spec-review, specReviewer/spec-reviewerchangesReview/changes-review), and added codexReviewers documentation and toggles.
Docs — Feature Surface
docs/docusaurus/docs/features/hooks.md, docs/docusaurus/docs/intro.md, docs/docusaurus/docs/features/context-optimization.md, docs/docusaurus/docs/features/statusline.md
Reduced hook count (18 → 15), adjusted hook tables/descriptions; clarified 1M extended context availability and constraints; updated status-line fields and formats.
Docs — Getting Started & README/FAQ
README.md, docs/docusaurus/docs/getting-started/prerequisites.md, docs/docusaurus/docs/getting-started/installation.md, docs/site/src/components/FAQSection.tsx
Added Codex plugin install/setup guidance, documented auto-detection and opt-in/OpenAI API behavior, updated uninstall/version headings and FAQ messaging.
Annotation UI — Types/Parser/Hook
docs/site/src/lib/annotation/types.ts, docs/site/src/lib/annotation/parser.ts, docs/site/src/lib/annotation/useAnnotation.ts, docs/site/src/lib/annotation/index.ts
Added annotation types, markdown→blocks parser, a useAnnotation hook with selection handling and reducer, and a barrel export.
Annotation UI — Components
docs/site/src/components/feedback/BlockRenderer.tsx, docs/site/src/components/feedback/AnnotationToolbar.tsx, docs/site/src/components/feedback/FeedbackSidebar.tsx, docs/site/src/components/feedback/index.ts
Added BlockRenderer, AnnotationToolbar, FeedbackSidebar components and re-exports to render blocks, capture inline annotations, and manage/send feedback.
Secure Sharing — Crypto/Compress/Sharing
docs/site/src/lib/sharing/types.ts, docs/site/src/lib/sharing/compress.ts, docs/site/src/lib/sharing/crypto.ts, docs/site/src/lib/sharing/sharing.ts, docs/site/src/lib/sharing/index.ts
Implemented compress/decompress utilities, AES-GCM encrypt/decrypt (base64url), share/feedback URL generation and parsing, payload size guard, and shared types for share/feedback payloads.
Shared Viewer Page & Routing
docs/site/src/pages/Shared.tsx, docs/site/src/App.tsx
New /shared route and Shared page that parses hash fragments, decrypts/decompresses payloads, renders blocks with annotations, supports creating annotations and generating encrypted feedback URLs.
Installer — Migration & Finalize
installer/steps/config_migration.py, installer/tests/unit/steps/test_config_migration.py, installer/steps/finalize.py, installer/tests/unit/steps/test_finalize.py, installer/steps/dependencies.py
Bumped config version to 7; added _migration_v7 to rename reviewer keys and inject codexReviewers defaults; updated tests; changed stale-worker kill to two-phase termination; minor comment cleanups.
TS Config
docs/site/tsconfig.app.json
Added esnext to compiler lib for newer globals/types.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Browser as Browser/App
    participant Parser
    participant Renderer as BlockRenderer
    participant Annotations
    participant Compress
    participant Crypto
    participant Share as Sharing

    User->>Browser: Load shared URL / paste hash
    Browser->>Browser: parseHashFragment(hash) → {data, key}
    Browser->>Crypto: decrypt(data, key)
    Crypto-->>Browser: compressed bytes (plaintext)
    Browser->>Compress: decompress(bytes)
    Compress-->>Browser: JSON payload (SharePayload/FeedbackPayload)
    Browser->>Parser: parseMarkdownToBlocks(specContent)
    Parser-->>Browser: Block[]
    Browser->>Renderer: render Block[] + sharer annotations
    Renderer-->>Browser: interactive UI

    User->>Browser: select text
    Browser->>Annotations: handleMouseUp -> pendingSelection
    Annotations-->>Browser: show AnnotationToolbar
    User->>Browser: submit annotation
    Browser->>Annotations: createAnnotation -> update state
    Annotations-->>Renderer: re-render with new annotation

    User->>Browser: send feedback
    Browser->>Share: generateWebFeedbackUrl(feedbackPayload)
    Share->>Compress: compress(JSON)
    Compress-->>Share: compressed
    Share->>Crypto: encrypt(compressed)
    Crypto-->>Share: {ciphertext, key}
    Share-->>Browser: {url, key} (copied/shared)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

released

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.60% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main changes: Codex adversarial reviewers, spec sharing feature, and Console improvements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown

claude bot commented Mar 31, 2026

Claude finished @maxritter's task in 3m 4s —— View job


Code Review — feat: Codex adversarial reviewers, spec sharing, and Console improvements

  • Gather context and read CLAUDE.md
  • Review installer changes (config_migration.py, dependencies.py, finalize.py, tests)
  • Review docs/site sharing & annotation library
  • Review docs/site UI components (feedback/, pages/Shared.tsx)
  • Review documentation updates (docs/docusaurus/, README.md)
  • Post final review

Overall this is a well-structured PR with a clean migration path, good test coverage for migrations, and a solid E2E-encrypted sharing implementation. A few issues worth addressing below.


installer/steps/config_migration.py

Dead-code if modified: guard (line 77)

raw["_configVersion"] = CURRENT_CONFIG_VERSION
modified = True           # always True here

if modified:              # always executes — condition is dead code
    _write_atomic(config_path, raw)

modified is unconditionally set to True on line 75, so the if modified: guard on line 77 never prevents the write. The intent is presumably "only write if something changed," but modified = True overrides any earlier False. The file is always written whenever migrations ran (which is correct), but the guard is misleading. Fix this →


docs/site/src/lib/sharing/sharing.ts

DRY violation: generateWebShareUrl and generateWebFeedbackUrl are identical

Both functions have the exact same body — compress, encrypt, size-check, and return the URL. The only difference is the input type (SharePayload vs FeedbackPayload). Consider consolidating into one generic helper, or at minimum extracting the shared body to reduce the maintenance surface. Fix this →


docs/site/src/pages/Shared.tsx

extractFromPastedUrl — both branches are identical

function extractFromPastedUrl(input: string): { data: string; key: string } | null {
  const trimmed = input.trim();
  if (!trimmed) return null;
  if (trimmed.startsWith("#")) return parseHashFragment(trimmed); // same as below
  return parseHashFragment(trimmed);                               // same as above
}

The if (trimmed.startsWith("#")) branch is unreachable dead code — parseHashFragment already handles #-prefixed inputs correctly. The function reduces to two lines. Fix this →

Hardcoded production URL in handleSendFeedback

const baseUrl = "https://pilot-shell.com/shared";

This is buried inside a useCallback. If the domain ever changes, this won't be caught by TypeScript — consider hoisting it to a module-level constant alongside MAX_INLINE_BYTES.

onSelectAnnotation no-op in the spec viewer

onSelectAnnotation={() => {}}

Clicking annotation badges in the viewer silently does nothing. If annotation selection is not yet wired to the sidebar in read-only mode, a // TODO or disabling the button entirely would be clearer than a silent no-op.


docs/site/src/components/feedback/BlockRenderer.tsx

allAnnotations passed to every BlockItem for index lookup

globalIndex is computed via allAnnotations.findIndex() per-badge, which is O(n) for each annotation badge rendered. For any reasonable spec size this is fine, but worth noting since the full list is passed to every block. A pre-computed index map passed down would be more efficient.


installer/steps/finalize.py

kill -9 without SIGTERM first

subprocess.run(["kill", "-9", pid.strip()], ...)

SIGKILL prevents the worker from flushing state or releasing file locks. Sending SIGTERM first (with a short wait) would be more graceful. Fix this →


docs/site/src/lib/annotation/parser.ts

Module-level mutable counter

let blockIdCounter = 0;
// ...
export function parseMarkdownToBlocks(markdown: string): Block[] {
  blockIdCounter = 0;  // reset on each call

This works correctly in a single-threaded browser context but is fragile in test environments where multiple concurrent calls could occur. No change required unless test reliability issues emerge, just worth being aware of.


Crypto/Sharing — Good Practices Observed

  • AES-256-GCM with a random 96-bit IV per encryption: correct
  • Key exported to raw bytes and embedded in the URL fragment (never sent to server): correct
  • checkBrowserSupport() computed at module load for stable error handling: good
  • Compression before encryption (not after) is the correct order for size reduction: good
  • Fragment-based URL format (#ciphertext?key=k) is correctly parsed by parseHashFragment: verified

Migration v7 — Well Structured

The migration chain is clean and the test coverage for v7 is thorough. The key rename logic correctly handles all cases: keys present, missing, or already renamed.


Minor Nits

  • docs/docusaurus/docs/getting-started/prerequisites.md: claude plugin install @openai/codex — worth confirming this is the final published package name before merging
  • docs/site/src/lib/sharing/compress.ts: Browser support comment accurately calls out the Uint8Array.toBase64 minimum versions — the runtime check in Shared.tsx covers this correctly

@maxritter maxritter self-assigned this Mar 31, 2026
- config_migration.py: fix dead modified=True guard, only set when version changes
- sharing.ts: extract shared buildEncryptedUrl helper (DRY)
- Shared.tsx: remove dead branch in extractFromPastedUrl, hoist URL constant
- finalize.py: send SIGTERM before SIGKILL for graceful worker shutdown
- Update finalize test for SIGTERM-first behavior
@claude
Copy link
Copy Markdown

claude bot commented Mar 31, 2026

Claude finished @maxritter's task in 1m 38s —— View job


Incremental Code Review — Push Delta

  • Gather context
  • Review installer/steps/config_migration.py
  • Review installer/steps/finalize.py + test_finalize.py
  • Review docs/site/src/lib/sharing/sharing.ts
  • Review docs/site/src/pages/Shared.tsx
  • Post final review

✅ Resolved from prior review

All five flagged issues are fixed in this push:

  • config_migration.py dead-code guardmodified = True is now conditional on the version actually needing a bump (if raw.get("_configVersion") != CURRENT_CONFIG_VERSION:), making the if modified: write guard meaningful again.
  • sharing.ts DRY violationgenerateWebShareUrl and generateWebFeedbackUrl now both delegate to a private buildEncryptedUrl(payload, baseUrl) helper. Clean extraction.
  • Shared.tsx dead branch in extractFromPastedUrl — simplified to return parseHashFragment(trimmed) after the null guard.
  • Shared.tsx hardcoded production URL in handleSendFeedback — removed; now uses the module-level SHARE_BASE_URL constant.
  • finalize.py kill -9 without SIGTERM — now sends SIGTERM (kill <pid>), sleeps 1s, checks liveness with kill -0, and only sends SIGKILL if the process is still alive. Test coverage for both the SIGTERM-only and SIGTERM+SIGKILL paths is solid.

New observations

sharing.tsdecryptSharePayload / decryptFeedbackPayload still have identical bodies

With the new decryptHashPayload (which handles auto-detection), the two individual typed decrypt functions now have duplicate implementations:

// Both have exactly the same body — only the cast differs
const compressed = await decrypt(data, key);
return JSON.parse(await decompress(compressed)) as SharePayload; // or FeedbackPayload

These were not flagged in the prior review, but since decryptHashPayload was added in this push, the duplication is newly visible. If callers need typed decryption, consider having them call decryptHashPayload and narrow on .type, or extract a private _decryptRaw helper the typed functions delegate to. Not blocking.

Shared.tsx line 19 — Vite define self-reference pattern

const SHARE_BASE_URL = SHARE_BASE_URL;

This relies on Vite's define plugin replacing the RHS with a string literal before the TypeScript compiler sees it. It works, but it's fragile — if the define is ever missing from vite.config.ts, this becomes a ReferenceError at runtime with no compile-time warning. The prior version with an inline hardcoded string was easier to diagnose when misconfigured. Consider at minimum adding a declare const SHARE_BASE_URL: string; ambient declaration so TypeScript catches a missing define at build time.


Still open (unchanged from prior review)

  • onSelectAnnotation={() => {}} no-op on BlockRenderer (Shared.tsx:341) — annotation badge clicks silently do nothing in read-only view; a // TODO or disabled state would be clearer.

@maxritter maxritter merged commit 55055d9 into main Mar 31, 2026
12 checks passed
@maxritter maxritter deleted the dev branch March 31, 2026 09:11
github-actions bot pushed a commit that referenced this pull request Mar 31, 2026
# [7.10.0](v7.9.0...v7.10.0) (2026-03-31)

### Bug Fixes

* improve Codex CLI invocation and reviewer agent prompting ([#124](#124)) ([d0c8494](d0c8494))
* security audit hardening across console, launcher, and installer ([822c513](822c513))

### Features

* Codex adversarial reviewers, spec sharing, and Console improvements ([#123](#123)) ([55055d9](55055d9))
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 7.10.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant