@cobuild/review-gpt
v0.5.147
Published
Bundle repo context, stage ChatGPT review drafts, and capture responses from a managed browser
Maintainers
Readme
@cobuild/review-gpt
@cobuild/review-gpt bundles your repo context, opens ChatGPT in a managed Chromium-family browser, and stages a draft with the right review context attached or selected.
It is designed to be installed in any repository that wants a repeatable review:gpt workflow. You keep prompts and presets in the consuming repo, while this package handles packaging, browser automation, response capture, and thread follow-up.
The CLI is implemented with incur, so it also ships with built-in shell completions plus agent-facing --llms, skills add, and mcp add integrations while preserving the existing cobuild-review-gpt command surface.
Skills
This repo also hosts installable Codex skills under skills/.
Current skill:
work-with-pro: work with a ChatGPT Pro thread for repo tasks. Preferwatch-onlywhen the user already has a prepared thread URL with repo context attached. Default to immediate polling withthread wake --delay 0s --poll-interval 1m, only use a later first check when the user explicitly asks for one, and do not nudge an existing thread unless the user explicitly authorizes that. Usesend-and-wakethroughreview-gpt, which owns repo-context packaging. Ifreview-gptis missing, stop with a clear setup instruction.
Install from the public repo with:
npx skills add https://github.com/cobuildwithus/review-gpt --skill work-with-proWhy Use It
- turns "open ChatGPT and attach the right repo context" into one command
- packages
codebase.zipfrom your curated repo manifest, can optionally derive a matching Repomix artifact, or can skip file attachments for connector-only review context - keeps project prompts local to each repo instead of centralizing them in the package
- defaults to draft-only staging, so nothing is sent unless you ask for
--sendor--wait - can capture the final assistant response to stdout or a file
- includes delayed send plus thread export, download, and delayed wake helpers for long-running ChatGPT work
Quick Start
Install it in the repo where you want to use it:
pnpm add -D @cobuild/review-gptAdd a repo-local script:
{
"scripts": {
"review:gpt": "cobuild-review-gpt --config scripts/review-gpt.config.sh"
}
}Create a shell config that registers the prompts your repo wants to expose:
#!/usr/bin/env bash
browser_binary_path="/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
review_gpt_register_preset "architecture" "scripts/prompts/architecture.md" \
"Architecture review with emphasis on boundaries and coupling."
review_gpt_register_preset "bugs" "scripts/prompts/bugs.md" \
"Behavioral regressions, edge cases, and missing tests." \
"regressions"
review_gpt_register_preset_group "full-review" "Run the main review passes." \
"architecture" "bugs"Then run it:
pnpm review:gpt --preset architectureOn first run with a fresh managed browser profile, use headful mode, sign in to ChatGPT in the opened window once, then rerun the command. The same persistent profile can run headless afterward.
How It Works
Each run can:
- resolve prompt content from repo-local presets plus optional inline
--prompttext or--prompt-file - build
codebase.zipfrom your repo context and, when explicitly enabled, deriverepo.repomix.ziporrepo.repomix.xmlfrom the same packaged manifest - skip artifact packaging entirely when
--no-artifacts,--no-zip, orattach_artifacts=0is used - open ChatGPT and stage a draft with the selected app connector plus any configured repo context URL and file attachments
- optionally auto-submit with
--send - optionally wait for the final response with
--wait - optionally switch into the dedicated Deep Research flow with
--deep-research
Normal reviews are kept on regular Chat so they do not consume or appear in ChatGPT Work. On the new-chat page, ReviewGPT switches the Chat/Work control to Chat before it stages anything. It refuses an existing Work conversation and checks the surface again before staging and immediately before auto-send. Deep Research uses its dedicated surface and is unchanged.
This package does not own project prompts. Presets, aliases, and preset groups live in the consuming repository, typically through scripts/review-gpt.config.sh.
Credential Safety
Review context is uploaded to ChatGPT, so every packaged ZIP is inspected before it is attached. A run fails with the offending paths listed when the ZIP contains dotenv files (.env, .env.local; .env.example and other *.example/*.sample/*.template/*.dist names are fine), SSH/AWS/GnuPG directories, .npmrc/.netrc/.envrc-style credential files, or private keys and certificates (.pem, .key, .p8, .p12, and similar). Runs also default COBUILD_AUDIT_CONTEXT_EXCLUDE_SENSITIVE=1 for the package script so the @cobuild/repo-tools packager filters the same shapes; set it explicitly to opt out.
Set REVIEW_GPT_ALLOW_SENSITIVE_ARTIFACTS=1 to downgrade the failure to a warning when a match is a false positive.
Common Commands
# Run a named preset
cobuild-review-gpt --config scripts/review-gpt.config.sh --preset architecture
# Schedule a named preset for later
cobuild-review-gpt delay --config scripts/review-gpt.config.sh --delay 50m --preset architecture
# Positional preset shorthand
cobuild-review-gpt architecture --config scripts/review-gpt.config.sh
# Add extra inline instructions
cobuild-review-gpt --config scripts/review-gpt.config.sh \
--preset bugs \
--prompt "Focus on auth edge cases and rollback behavior"
# Use a prompt file with the normal repo artifacts attached
cobuild-review-gpt --config scripts/review-gpt.config.sh \
--prompt-file prompts/release-review.md
# Auto-send and wait for a captured response
cobuild-review-gpt --config scripts/review-gpt.config.sh \
--wait \
--response-file review-output.md
# Include or exclude configured test paths
cobuild-review-gpt --config scripts/review-gpt.config.sh --with-tests --preset bugs
cobuild-review-gpt --config scripts/review-gpt.config.sh --no-tests --preset bugs
# Select a ChatGPT app connector before staging the draft
cobuild-review-gpt --config scripts/review-gpt.config.sh --app-connector github --preset architecture
# Use a connector-only review with no artifact files
cobuild-review-gpt --config scripts/review-gpt.config.sh --connector github --no-artifacts --preset architecture
# Deep Research mode
cobuild-review-gpt --config scripts/review-gpt.config.sh --deep-research --wait
# Re-open an existing thread
cobuild-review-gpt --config scripts/review-gpt.config.sh --chat 69a86c41-cca8-8327-975a-1716caa599cf
cobuild-review-gpt --config scripts/review-gpt.config.sh --chat-url https://chatgpt.com/c/69a86c41-cca8-8327-975a-1716caa599cfModel selection defaults to gpt-6-pro; --model pro also targets GPT-6 Pro. ReviewGPT verifies the explicit 6 Pro composer label. The picker's Latest row is only a navigation choice: its selection alone is not model proof. When Latest is selected at lower power, ReviewGPT moves the combined five-position Power control to Pro, then verifies the explicit 6 Pro label before sending. Older versions and a bare Pro effort label cannot satisfy a GPT-6 Pro request. Response-model metadata is checked when available; GPT-6 Pro accepts the gpt-6-pro response slug and rejects older Pro or Thinking slugs.
Explicit --model gpt-5.6-sol retains the previous Sol target, including its Advanced picker and response-slug aliases. Other versioned aliases such as gpt-5.5, gpt-5.5-thinking, and gpt-5.5-pro, plus the plain tier aliases instant and thinking, retain their existing picker behavior. Plain gpt-5.5 targets Instant. Non-Pro aliases do not match Pro rows, and obsolete Extended Pro labels are not accepted as Pro proof. Older model targets leave the separate Effort control and slider unchanged. If the requested model is disabled, rate-limited, or unavailable, the run fails instead of silently continuing on the current model. Thinking defaults to current and does not open an independent thinking menu. Explicit xhigh and legacy extended thinking targets remain unsupported. Deep Research uses its dedicated page and ignores normal model and thinking forcing.
App connector selection defaults to current, which keeps the current ChatGPT composer state. Use --app-connector github or its alias --connector github to open the composer add menu, enter More, and select the GitHub app connector before the prompt and files are staged. Deep Research mode uses its dedicated page and ignores app connector forcing.
Set repo_context_url="https://github.com/owner/repo" in config when connector-only runs should include a specific repository URL in the staged prompt.
Each run stages codebase.zip as the fidelity artifact. Set snapshot_attachment_name="review-gpt.repo-snapshot.zip" in your repo config when a consumer needs a different attachment name. The value must be a .zip filename, not a path.
Repomix is disabled by default. Set repomix_attachment_format="zip" to stage repo.repomix.zip or repomix_attachment_format="xml" to stage the raw XML. The compressed attachment contains repo.repomix.xml at the root of the archive.
Draft staging confirms attachments before placing the review prompt in the composer. Confirmation requires the expected filenames to be visible in the composer's own attachment tiles, matched tolerantly against the name(2).ext or name(YYYYMMDD-HHMMSS).ext forms ChatGPT gives uploaded files. Hidden file-input state and generic upload UI movement are not enough, because neither leaves the model with a readable artifact.
Auto-send also verifies those filenames on the exact user turn ChatGPT committed. If a staged ZIP disappears during submission, the run fails before the long response wait, retains every generated local attachment, records the accepted thread when it can prove it, and never resends automatically.
ReviewGPT keeps only one stable local copy of each generated attachment while staging. Non-wait auto-send removes generated attachments after the exact committed user turn confirms every expected filename; waited runs remove them after response capture finishes. Draft-only runs retain them: the draft has not been sent, and deleting a staged file while the browser is still reading it cancels the upload. Dry runs and failed or unconfirmed staging attempts also keep the local artifact for inspection. This cleanup applies only to files generated by ReviewGPT for that run; it never deletes arbitrary user-supplied attachments.
Set attach_artifacts=0, or pass --no-artifacts / --no-zip, to skip the codebase ZIP and any explicitly enabled Repomix artifact. In that mode review-gpt does not run the repo packager.
Repo Configuration
The config file is a sourced shell file that can override defaults, register preset mappings, and adjust path settings.
Optional config override:
snapshot_attachment_name="review-gpt.repo-snapshot.zip"
repomix_attachment_format="xml" # optional; default is "none"
app_connector="github" # optional; default is "current"
repo_context_url="https://github.com/owner/repo"
attach_artifacts=0 # optional; default is 1
idle_draft_timeout_ms="30m" # close hidden, inactive unsent drafts; use 0 to disable
minimum_marked_response_ms="5m" # positive trust threshold for marked concrete-model reviews
repomix_ignore_patterns=(
"dist/**"
"coverage/**"
)repomix_attachment_format and repomix_ignore_patterns are opt-in. ReviewGPT builds Repomix from the packaged manifest only when the format is zip or xml; add ignore patterns only when your consuming repo deliberately excludes a subset of those packaged files.
review-gpt packages repo context through its installed @cobuild/repo-tools dependency by default. Keep package_script only for an intentional repo-specific override.
Config helpers exposed by the package:
review_gpt_register_preset <name> <file> <description> [alias ...]review_gpt_register_dir_preset <name> <filename> <description> [alias ...]review_gpt_register_preset_group <name> <description> <preset ...>
Each consuming repo must register its own presets. If the config does not register any presets, --list-presets reports none configured and any --preset use fails.
Recommended repo entry point:
{
"scripts": {
"review:gpt": "cobuild-review-gpt --config scripts/review-gpt.config.sh"
}
}Use the package binary directly. Avoid repo-local wrapper scripts unless you have a concrete repo-specific need beyond passing --config.
The CLI still accepts preset shorthand tokens for the top-level command. cobuild-review-gpt architecture behaves like cobuild-review-gpt --preset architecture, while thread wake ... remains unchanged.
Runtime Extras
In addition to the review workflow, the incur runtime also exposes:
cobuild-review-gpt completions <bash|zsh|fish>cobuild-review-gpt --llmscobuild-review-gpt skills addcobuild-review-gpt mcp add
Browser Notes
browser_binary_pathis the preferred config knob for the browser executable.browser_chrome_pathremains supported for backward compatibility.- Chromium-family browsers are supported as long as the binary is Chromium-compatible. Chrome, Brave, Chromium, Edge, and Vivaldi all work with the managed-profile launch flow.
- The launcher also checks
CHROME_PATH,BROWSER_BINARY_PATH, and--browser-pathfor one-off browser overrides. - The managed browser profile defaults to
$HOME/.review-gpt/managed-chromium. If an older$HOME/.oracle/remote-chromeprofile already exists, the launcher reuses it automatically instead of forcing a new sign-in. - You can override the managed profile location with
managed_browser_user_data_dirand the profile name withmanaged_browser_profile. - Managed browsers default to
managed_browser_background_mode="balanced": Chromium keeps its normal background timer, renderer, and occluded-window scheduling. ReviewGPT pins only the target it is actively capturing. If a specific browser version still freezes background capture, setmanaged_browser_background_mode="unthrottled"to restore all three legacy backgrounding opt-outs. - Managed browsers default to
managed_browser_display_mode="headful". Setmanaged_browser_display_mode="headless"or pass--headlessto run the same persistent signed-in profile without visible browser UI. Headless mode keeps CDP bound to loopback and uses a desktop-sized viewport; it does not disable ChatGPT's renderer or page JavaScript and is not a low-resource guarantee, so benchmark it before making it the local default. - Managed headful browsers default to
managed_browser_launch_mode="foreground". Set it to"background"to start the browser without activating it on macOS. Model and connector selection use targeted CDP input with emulated page focus and never activate the browser window. Background startup clears restored tabs from the dedicated managed profile and keeps one ChatGPT home tab while reviews run. Use foreground mode once if the profile needs an interactive sign-in. - Managed browsers stay open by default. Set
managed_browser_close_after_wait="true"to close the browser after the last concurrent--waitresponse capture succeeds. Each process holds a short machine-local lease, so concurrent ReviewGPT runs share the browser safely and close it only after the final run releases it. ReviewGPT keeps the browser open after failures for exact-thread recovery, and also keeps it open when a page outside the managed home/startup set remains active. - Display mode is selected when the managed browser process starts. An already-running endpoint keeps its current mode until that exact managed browser instance exits normally.
- A newly started managed browser keeps one ChatGPT page available for first-run sign-in. If that profile is already locked while its debugging endpoint is unavailable, startup fails closed instead of forwarding another window into the existing browser process.
- Draft automation creates a fresh ChatGPT browser target for each run and does not foreground the page. If the browser debugging endpoint cannot create a new target, the command fails instead of reusing an existing ChatGPT tab.
- Before a send is accepted, direct runs close their exact owned target on handled failure and ordinary
SIGINT,SIGTERM, orSIGHUPinterruption. Once a send is accepted, ReviewGPT preserves that exact target for capture or wake recovery; successful waited capture closes it. Send-without-wait runs retain their target intentionally. Draft-only runs retain their target for 30 minutes by default, then a single lightweight coordinator per browser lane closes the exact target once it is both hidden and no longer generating. A visible or busy draft is deferred for another check. Override the grace period with--idle-draft-timeoutoridle_draft_timeout_ms; set either to0to keep unsent drafts indefinitely. - After auto-send, ReviewGPT reports a thread URL only after the same canonical
/c/<thread-id>location appears across separate polling cycles. Provisional browser routes such asWEB:<id>are ignored. - On first run with a fresh managed profile, use headful mode to sign in once before enabling headless mode.
- If the first authentication probe reports that the managed ChatGPT page is signed out, ReviewGPT hard-refreshes that page once with cache bypass and checks again before asking you to sign in. This covers transient unauthenticated startup state without hiding a persistently signed-out profile.
Response Capture
--waitimplies auto-send and waits up to120mfor the response by default. Browser setup keeps its separate10mdraft timeout (40min Deep Research mode), so a stalled setup still fails promptly without cutting off a healthy long-running review. Override response capture with--wait-timeoutand browser setup with--timeout.- When
--waitis enabled,review-gptstays attached until the assistant finishes or the wait timeout is hit. Deep Research runs can stay quiet for a long time before the final report arrives. - Waited runs retain their generated local attachment files until response capture ends, so a large upload cannot be invalidated by immediate post-send cleanup. If ChatGPT accepts the prompt but response capture later fails, ReviewGPT exits nonzero while preserving the canonical thread URL. Inspect or resume that thread before retrying so the same review is not sent twice.
- Every confirmed send reports the selected browser endpoint and a replayable
thread wakecommand containing that endpoint and exact thread URL. Send also atomically persists a private capture sidecar (beside--response-file, or in the run's temporary staging directory) with the accepted target and committed user-turn identity. Prior recovery metadata remains in place until a new send is accepted and its replacement sidecar is durable. A waited completion atomically upgrades it with the exact assistant turn, response digest, and artifact controls. Deep Research captures separately bind the parent assistant turn that owns artifacts and the final iframe report content, so wake can validate both sources before export. Content-derived prompt, response, artifact-label, artifact-href, parent-anchor, and iframe-report identities are stored only as hashes; raw text prefixes, data URL contents, and signed artifact routes are not retained. - A waited capture that loses its page websocket first reconnects to the originally accepted target ID. If that target no longer exists, ReviewGPT may create one replacement target at the exact canonical thread URL, but it never selects or navigates another existing tab. The replacement is accepted only after the stored thread and committed-turn identity validate, and recovery never resends or extends the original response deadline. If that identity cannot be proved, capture fails closed and the replayable wake command is the recovery path.
- A response is only captured after it stays unchanged across consecutive quiet polls (no busy status, no stop control) for several seconds, so interim assistant status messages emitted before long tool/connector work are not mistaken for the final reply.
- Waited concrete-model runs check ChatGPT response-model metadata when available. ReviewGPT does not ask the assistant to identify itself or require a
MODEL_CONFIRMATIONline. Missing metadata produces no model-verification evidence; a present incompatible model slug still fails. Thegpt-5.6-solalias acceptsgpt-5-6-pro,gpt-5-6-thinking, andgpt-5.6-sol-wmbackend slugs without reinterpreting an explicitly requested Thinking model. The response must belong to the exact user turn committed by this run. An ephemeral per-run nonce at the start of the sent prompt disambiguates concurrent lanes and prevents duplicate protocol insertion; it is never written to attestation evidence. A completed concrete-GPT capture with matching platform metadata emits a versionedREVIEW_GPT_MODEL_VERIFICATIONJSON record withrequestedModel,responseModelSlug, andresponseSha256; the digest covers the exact normalized UTF-8 response-file bytes. Elapsed time and assistant self-descriptions do not claim platform-model evidence. With--response-file, the mandatory response is written atomically with owner-only permissions before completion is emitted. The evidence sidecar is optional: a sidecar-only persistence failure produces a warning, omits the verification record, and never invalidates or repeats the completed response. Exact-target cleanup remains bounded; cleanup uncertainty after a completed capture is reported separately and does not turn that capture into a retryable model failure. A new waited response-file attempt removes only the derived sidecar before browser work, and partial or failed captures never create attestation evidence. - A visible “Capabilities reduced until…” notice is a rate limit even when ChatGPT keeps answering or Pro is unselectable. ReviewGPT checks before model selection, before sending, and during response capture and wake. It fails with
REVIEW_GPT_RATE_LIMITEDbefore accepting completion or model evidence. The reset time is included in the driver error. The calling agent should exclude that lane for the current retry sequence and start a fresh full review on another configured, signed-in browser lane with the same requested model and review context. Never move an existing conversation across lanes or accept a reduced-capability answer. Try each allowed lane at most once; if none is available, report the limit and wait for recovery. ReviewGPT itself operates one configured browser per invocation; lane selection belongs to the caller. --response-marker <text>makes capture contract-based instead of heuristic: the wait only accepts a response containing that exact text, so prompts that instruct the assistant to end its final message with the marker are immune to interim status messages even across minutes-long quiet gaps. A marked concrete-model response may complete before the trust threshold only when the same snapshot exposes compatible concrete platform-model metadata; otherwise the duration floor still applies. A too-fast unverified response fails closed, preserves the diagnostic response in--response-file, and emits no model-verification attestation. The threshold defaults to 5 minutes and can be raised or lowered with--minimum-marked-response-time <duration>orminimum_marked_response_ms; it must remain positive and cannot disable the fallback gate. If the marker never appears, capture fails after writing the best snapshot when one was configured.- Browsers throttle background tabs, which can freeze the DOM the capture reads mid-stream. The capture session pins focus emulation and an active page lifecycle only for its owned page over CDP, then releases emulated focus before retaining or closing the page. While generation is active, ReviewGPT samples the large live response DOM once per minute and hard-refreshes the exact accepted thread with cache bypassed every 10 minutes; after generation becomes quiet, it returns to short stability polls. This keeps capture reliable without forcing every profile tab to run unthrottled or continuously rescanning UI that no caller consumes.
- Deep Research auto-send gives the product up to 60 seconds to auto-start, then only falls back to the approval-card
Startaction if that gate is still present. - Captured assistant output is printed between
REVIEW_GPT_RESPONSE_BEGINandREVIEW_GPT_RESPONSE_ENDmarkers so callers can parse it reliably. --response-file <path>writes the captured assistant response to a file after the run finishes.
Delayed Runs
Use delay when you want the normal top-level review flow to start later without switching into the thread-wake follow-up workflow.
Examples:
# Schedule a delayed new send
cobuild-review-gpt delay \
--config scripts/review-gpt.config.sh \
--delay 50m \
--preset bugs
# Re-check an existing thread later with the built-in delayed follow-up prompt
cobuild-review-gpt delay \
--config scripts/review-gpt.config.sh \
--delay 50m \
--chat-url https://chatgpt.com/c/69a86c41-cca8-8327-975a-1716caa599cfNotes:
delaywaits before launching the normalreview-gptreview flow. It is for delayed sends or delayed same-thread follow-ups.- Existing-thread delayed follow-ups default to
--waitand to a response file insideoutput-packages/review-gpt-delay/...unless you override those flags. thread wakeis different: it revisits an existing thread later, exports the latest assistant text, downloads artifacts from the latest request when they exist, and can hand off into Codex.
Thread Follow-Up
Thread helpers ship through the main CLI:
cobuild-review-gpt thread export --chat-url <url> --capture-metadata <response.capture.json> --output <path>cobuild-review-gpt thread download --chat-url <url> --capture-metadata <response.capture.json> --artifact-index <n> --output-dir <dir>cobuild-review-gpt thread diagnose --chat-url <url> --log-file <path> [--receipt-path <path>]cobuild-review-gpt thread wake --delay 70m --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --detach --delay 0s --poll-interval 1m --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --delay 0s --no-poll-until-complete --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --delay 0s --poll-interval 1m --poll-jitter 1m --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --delay 0s --resume-prompt "<instructions>" --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --delay 0s --tab-lifecycle keep --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --delay 0s --recursive-depth 1 --recursive-prompt "<instructions>" --chat-url <url> --session-id <id>cobuild-review-gpt thread wake --delay 0s --poll-timeout 120m --recursive-depth 1 --chat-url <url> --session-id <id>
thread export, thread download, thread diagnose, and thread wake require a full ChatGPT conversation URL such as https://chatgpt.com/c/<thread-id>. The plain home URL is rejected before browser automation starts.
For long-running ChatGPT work, these commands read an existing conversation from the same managed Chromium session, retain the latest assistant text response for the latest user request, only accept patch and file artifacts that belong to that latest request, prefer the final assistant turn within that latest request, and can optionally hand off to a follow-up interactive Codex session later.
Examples:
cobuild-review-gpt thread export \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--output output-packages/thread.json
cobuild-review-gpt thread download \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--artifact-index 0 \
--output-dir output-packages/downloads
cobuild-review-gpt thread diagnose \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--log-file output-packages/chatgpt-watch/run/recursive-review-send.log \
--receipt-path output-packages/chatgpt-watch/run/recursive-followup.json
cobuild-review-gpt thread wake \
--delay 70m \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c
cobuild-review-gpt thread wake \
--delay 0s \
--poll-interval 1m \
--poll-jitter 1m \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c
cobuild-review-gpt thread wake \
--delay 0s \
--no-poll-until-complete \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c
cobuild-review-gpt thread wake \
--delay 0s \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c \
--tab-lifecycle keep
cobuild-review-gpt thread wake \
--delay 0s \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c \
--resume-prompt "After applying the returned patch, run pnpm review:gpt --send --chat-url {{chat_url}} and ask for final bug and simplification feedback."
cobuild-review-gpt thread wake \
--delay 0s \
--poll-interval 1m \
--poll-timeout 120m \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c \
--recursive-depth 1
cobuild-review-gpt thread wake \
--delay 0s \
--chat-url https://chatgpt.com/c/69c71d43-0e38-8330-9df8-c4e10f5bf536 \
--session-id 019d36e3-f6a2-7873-910a-2bdbd4f9748c \
--recursive-depth 1 \
--recursive-prompt "Wait for the thread response, then implement the returned plan as a clean long-term patch with tests and return a .patch attachment."Resume notes:
cobuild-review-gpt thread wakedoes not touch the managed browser until the configured--delayhas elapsed, so scheduling a 60m or 100m follow-up does not immediately reopen or navigate the ChatGPT tab.--detachlaunches the wake loop as its own background process, writeswake.logbesidestatus.json, and returns immediately with the detached PID plus output paths. Use it when the current shell, terminal, parent agent, or PTY may exit before the wake finishes.- Polling is enabled by default and has no implicit overall expiry. After the initial delay, an exact
--capture-metadatawake inspects the retained hydrated target before any reload so an in-memory replacement artifact remains recoverable. If that target disappeared, wake may create one replacement at the exact captured thread URL and bind it only after the stored thread and turn identity validate; it never substitutes a different existing tab. During continued polling, wake hard-refreshes that same exact tab with cache bypassed every 10 minutes and still fails closed if its stored thread or turn identity no longer validates; bounded stale-state detection can trigger an earlier one-time fallback reload. A wake without capture metadata retains the compatibility behavior of reloading before its first export. Wake keeps re-exporting until it sees a stable final state: assistant-owned artifacts end the wait immediately, while no-artifact replies must expose ChatGPT's completed-turn copy control or terminal status and stay unchanged across consecutive idle polls after busy status and stop controls disappear. Wake reuses the current same-thread tab when one already exists, keeps it available throughout export and artifact download, and closes that exact harvested target only after the final response and every requested artifact are persisted locally. A failed wake closes only ordinary targets it created; a validated replacement for a missing captured target, reused send target, or user tab stays available for recovery. Any artifact download error retains the tab and the replay commands for recovery. Use--tab-lifecycle keepto retain every target, or--tab-lifecycle close-createdto close only ordinary targets created during that wake.--poll-intervaldefaults to1m,--poll-jitterdefaults to1mso the normal retry cadence lands between 60 and 120 seconds, and polling also adds a small hidden startup spread before the first export so several simultaneous wake runs do not all hit ChatGPT at once.--poll-timeoutcan bound that wait, and--no-poll-until-completerestores the old one-shot behavior. - Wake treats ChatGPT's own visible assistant failure controls, such as
Thinking failedorStopped thinking, as terminal generation failures instead of retaining them as prose-only responses. - Every successful wake export writes
assistant-response.mdandassistant-response.meta.jsonbesidethread.json, even when artifacts are also downloaded. Prose-only replies can hand off to Codex from this retained response file without needing a.patchor.diffattachment. - When the final assistant response declares
Patch artifact: <filename>.patch, waited capture andthread wakerequire that exact assistant-owned downloadable filename. A different notes or support attachment cannot substitute for the declared patch; ReviewGPT preserves the response, records failure, and does not launch the Codex handoff. - Polling tolerates a few transient thread-export failures before the first successful snapshot, and after a good snapshot exists it keeps polling until the overall timeout instead of aborting immediately on a short flaky stretch.
- Wake records the last assistant preview, busy reason, retained text response paths, artifact labels, and download outcomes in
status.jsonfor debugging. thread wakereuses an existing tab only when it is already on the same/c/<thread-id>conversation, and treats same-thread URLs with extra query parameters as the same thread.- After the delay elapses, thread export inspects the current ChatGPT tab first, only navigates or reloads when needed, and still requires real conversation signals before capture so generic ChatGPT chrome does not masquerade as a ready thread. Thread download keeps the hydrated thread tab alive and activates the visible attachment control inside the page before falling back to a native browser click.
- Thread export and download scope artifact discovery to the conversation body, ignore ChatGPT conversation links that only look like attachments, and only consider assistant-owned downloadable controls that appear after the latest user message in the thread. Within that latest request, they prefer the final assistant turn, download every assistant-owned final-turn control by artifact index instead of gating on patch-shaped labels, and still carry forward human-readable artifact labels for wake/debug handoff when ChatGPT exposes them.
--capture-metadatareplaces latest-visible rediscovery with exact selection: export and download require the captured endpoint, thread, committed turn, assistant response digest, and artifact identity to resolve exactly once. A missing target may be rehydrated only at the exact captured thread URL and is rebound only after identity validation. That exact assistant identity remains authoritative even if a later user turn exists. Older-branch, ambiguous, or mismatched identities fail closed instead of downloading a same-named artifact from another response.- Thread export now preserves the full assistant turn text in saved snapshots instead of clipping assistant messages to a 20k-character preview.
thread downloadstill honors native browser downloads when ChatGPT emits them, but it also falls back to authenticated estuary fetches for inline assistant download controls such as combined patch buttons and native-download cases where the browser never materializes the file on disk. Every downloaded artifact must be a non-empty file; when one final assistant artifact is paired with one declared SHA-256 digest, download verifies that digest before success. Failed native-download attempts clean up zero-byte files they created, andthread wakeretries each artifact download once before failing nonzero without launching a child handoff.cobuild-review-gpt thread wakeresolves the localcodexexecutable itself, solaunchd,tmux,nohup, and similar runs do not depend on your interactive shellPATH.cobuild-review-gpt thread wakecaptures the current working directory and launches a freshcodex execchild with-Cset to that repo directory, seeded with the built-in wake prompt, the exported thread JSON, the retained assistant text response, and every downloaded assistant artifact from the latest request.- Wake now launches the follow-up through
codex exec --jsonwithCODEX_HOMEpinned to the resolved owner home, so the prompt is submitted directly without PTY keystroke injection. - Wake verifies launch from the child JSON event stream, then records
childSessionId,childSessionPersistence,childRolloutPath,launcherPid,eventsPath,resumeOutputPath, andstderrPathinstatus.jsonfor debugging. If launch evidence times out, ReviewGPT terminates and reaps the exact detached child process group it created before returning failure.childSessionPersistence: "pending"means the child already started but its canonical ID-bearing session-log filename was not visible yet. - Once that follow-up Codex session is verified and handed off successfully,
thread wakewritesstate: "succeeded"and exits instead of waiting for the spawned Codex run to finish. - The built-in wake prompt always includes the watched ChatGPT thread URL so the resumed Codex session can reuse it for follow-up
review:gpt --sendcommands. thread diagnosecaptures a structured failure bundle for same-thread send and wake problems: matching managed-browser tabs, which tab selection would currently win, a sanitized command log copy, an optional sanitized recursive receipt copy, and a fresh sanitized thread export underoutput-packages/review-gpt-diagnostics/.--recursive-depth <n>adds a built-in same-thread review loop on top of the normal wake handoff. Whenn > 0, wake now generatesrecursive-followup.shinside the wake output directory. The resumed child runs that helper after verification; it sends the built-in bug-and-simplification review with an explicit300stimeout, writesrecursive-followup.jsonplusrecursive-review-send.log, and, on success, arms one more detachedthread wakeon the same URL with the counter decremented. When the counter reaches0, the next child applies the returned review patch and stops.- Top-level auto-send on an existing conversation now auto-captures the same diagnostics bundle on managed-browser send failure, and recursive same-thread follow-up helpers do the same automatically before they exit non-zero. Recursive receipts now record the diagnostics output and status paths.
--recursive-promptoverrides that built-in same-thread review prompt. The same override is baked intorecursive-followup.shand forwarded to descendant recursive wakes so one custom recursive workflow can run across the whole chain.- Recursive wakes now use deterministic nested output directories such as
recursive-depth-0under the current wake directory instead of scattering timestamped descendant runs elsewhere.status.jsonrecords the generated recursive helper paths and the expected descendantstatus.jsonpath so second-hop debugging does not require filesystem scanning. - Wake also writes
wake-commands.shbesidethread.jsonandstatus.json; those directnode .../bin.mjs thread export|downloadcommands bypasspnpm exec, so a stale consumer workspace install does not block thread re-export or attachment re-download during follow-up debugging. --resume-promptappends extra instructions to the built-in Codex wake prompt instead of replacing the default export/download/apply guidance, and supports{{chat_url}}plus{{chat_id}}placeholders for the watched thread.- Auto-send now re-checks the final composer and thread state once more before declaring
commit-timeout, so ambiguous send confirmations do not break recursive wake chains when the message actually landed. - Wake uses explicit
--codex-homefirst, otherwise trusts the inheritedCODEX_HOMEcaptured by the detached process. Neither path reads historical session contents. - If neither home is available, wake falls back to filename and shell-snapshot metadata across conventional local Codex homes. It never opens session transcripts or history during ownership discovery; ambiguous or legacy layouts fail with an instruction to pass
--codex-home. - The supplied
--session-idrecords lineage and supports that metadata-only fallback. Wake starts a fresh interactive session in the selected home instead of mutating the original session ID. --full-autois now opt-in onthread wake; without it, the launched Codex session behaves like a normal manual interactive launch.- Wake stores the exported thread, all downloaded assistant artifacts,
wake-commands.sh, andstatus.jsonalongside the follow-up launch. --skip-resumestill exports the thread and downloads any assistant-owned artifacts, but it does not launch the follow-up Codex session.- If you do not use
--detach, keep long wake runs undernohup,tmux,screen,launchd, or another supervisor so the foreground wake process survives terminal exit.
Local Package Iteration
For local package iteration, prefer package-manager linking or a local file dependency rather than wrapper-script fallbacks:
pnpm add -D file:../review-gpt
# or
pnpm link --global ../review-gpt
pnpm link --global @cobuild/review-gptRelease
This package is published as @cobuild/review-gpt on npm.
Release ownership note: release, version-bump, and publish actions are user-operated by default. Agents should not run release flows unless explicitly instructed in the current chat turn.
pnpm run release:check
pnpm run release:dry-run
pnpm run release:patch
# or: pnpm run release:minor
# or: pnpm run release:major
# or: pnpm run release:alphaThe local release script:
- requires a clean git working tree on
main - verifies package scope
@cobuild/review-gpt - supports
check,pre*bumps with--preid, and strict exact semver input - uses
pnpmversioning sopnpm-lock.yamlstays authoritative andpackage-lock.jsonis not recreated - bumps version and updates
CHANGELOG.md - creates release commit
release: v<version>, tagsv<version>, and pushesmainplus tags - after push, waits for npm publish visibility and then attempts to update sibling repos under the configured sync root that depend directly on
@cobuild/review-gpt
Release helpers resolve @cobuild/repo-tools from the installed dependency in node_modules first and fall back to the sibling repo-tools checkout in this workspace when testing unreleased shared tooling before the next publish.
If downstream sync fails after a successful publish, the release command now warns and exits successfully so a completed publish is not misreported as a failed release. You can rerun the sync manually.
You can skip the post-release sibling sync with --no-sync-upstreams or REVIEW_GPT_SKIP_UPSTREAM_SYNC=1.
Manual sync command:
pnpm run sync:repos -- --version "$(node -p "require('./package.json').version")" --wait-for-publishPublishing is tag-driven in GitHub Actions at .github/workflows/release.yml:
- validates tag format and version match with
package.json - runs tests and checks, creates a tarball, and creates a GitHub Release with Codex-style notes
- publishes to npm via Trusted Publishing, including prerelease channel tags such as
alpha,beta, andrc
Before first automated publish, configure npm Trusted Publisher for @cobuild/review-gpt to allow cobuildwithus/review-gpt GitHub Actions to publish.
Changelog helpers:
pnpm run changelog:update -- 0.1.1
pnpm run release:notes -- 0.1.1 /tmp/release-notes.md