Give your AI agents access to ChatGPT. Oracle is a CLI tool that lets AI agents (Claude, Codex, etc.) query ChatGPT Pro via browser automation — running in the background with zero focus stealing.
Early-stage software. This project works and is actively used, but it automates a browser against a third-party website — things can break when ChatGPT's UI changes, and browser automation on your machine is inherently somewhat invasive. Review the code before running it, and use at your own risk.
macOS only in its current version (uses AppleScript and macOS-specific Chrome management).
Built by AI. The vast majority of this codebase was written by Claude and Codex (OpenAI), with human direction and review by @seeekr. Treat accordingly — it's been tested and works well, but hasn't had extensive manual code review.
AI agents sometimes need to consult other AI models. Oracle makes this possible by automating a real Chrome browser session against ChatGPT, with:
- Zero focus steal — Oracle Chrome runs offscreen and never interrupts your work
- Personal Chrome isolation — uses a dedicated browser profile at
~/.oracle/chrome, completely separate from your personal Chrome - Long-running query support — built for queries that take minutes to tens of minutes (ChatGPT Pro extended thinking)
- Structured error handling — all errors include codes, messages, and recovery suggestions in JSON
- Conversation continuity — follow-up messages to existing conversations
- macOS (Ventura or later)
- Node.js 22+
- Google Chrome installed
- ChatGPT account with a Pro subscription (extended thinking requires Pro)
One-liner:
curl -fsSL https://raw.githubusercontent.com/productioneer/oracle/main/install.sh | bashOr manually:
git clone https://github.com/productioneer/oracle.git
cd oracle
npm install
npx playwright install chromium
npm run build
ln -s "$(pwd)/dist/cli.js" /usr/local/bin/oracleOn first use, open a visible browser window to log in:
oracle openThis opens Chrome with Oracle's dedicated profile. Log in to ChatGPT, then close the window. You only need to do this once — the session persists.
# Start a run (returns immediately with a run_id)
echo "What is the mass of the Sun?" | oracle run --json
# Wait for completion
oracle watch <run_id>
# Get the result
oracle result <run_id>echo "How does that compare to Jupiter?" | oracle run <run_id> --json
oracle watch <run_id>
oracle result <run_id>By default, Oracle uses ChatGPT's extended thinking mode — deep reasoning that typically takes 5-90 minutes. For faster responses when deep reasoning isn't needed:
echo "Quick question" | oracle run --effort standard --jsonOracle is designed to be used by AI agents. Copy the instructions below into your agent's system prompt or memory file (for instance, Claude Code's ~/.claude/CLAUDE.md):
Click to expand agent instructions
## Oracle CLI
Query ChatGPT Pro via browser automation. Runs asynchronously — start a run, wait for completion, get the result.
**Oracle is effectively a remote agent.** It has ONLY the information in your prompt and attached files — no repo access, no local filesystem, no knowledge of your project or conventions. Include all relevant context in the prompt and use `@file` references to attach files, but don't overshare irrelevant setup details.
### Standard Workflow (3 commands)
```bash
# 1. Start a run (returns run_id in JSON)
echo "your prompt" | oracle run --json
# 2. Wait for completion (blocks until done, prints status updates)
oracle watch <run_id>
# 3. Get the response text
oracle result <run_id>
```
### Important Notes
- **Always use `--json`** with `oracle run` to get structured output with the run_id.
- **`oracle watch` blocks** until the run completes — no need to poll manually.
- **`oracle result`** returns the response text on stdout. Use `--json` for structured metadata.
- **`--effort extended`** (default) uses deep reasoning — thorough but slow (5-90 min). Use `--effort standard` for faster responses when deep reasoning isn't needed.
- Runs are stored under `~/.oracle/runs/<run_id>/`.
### All Commands
| Command | Purpose |
| ------------------------------------------------ | ------------------------------------------------ |
| `oracle run "<prompt>" --json` | Start new run, get run_id |
| `echo "prompt" \| oracle run --json` | Start run via stdin |
| `oracle run --prompt-file prompt.txt --json` | Start run from file |
| `oracle run --effort standard "<prompt>" --json` | Start run with standard (faster) reasoning |
| `echo "follow-up" \| oracle run <run_id> --json` | Continue conversation |
| `oracle watch <run_id>` | Wait for completion |
| `oracle result <run_id>` | Get response text |
| `oracle result <run_id> --json` | Get response metadata (JSON) |
| `oracle status <run_id>` | Check current state |
| `oracle status <run_id> --json` | Check state (JSON output) |
| `oracle cancel <run_id>` | Cancel active run |
| `oracle cancel <run_id> --json` | Cancel (JSON output) |
| `oracle resume <run_id>` | Resume a paused run (after user logs in) |
| `oracle thinking <run_id>` | Get thinking output (incremental) |
| `oracle thinking <run_id> --full` | Get full thinking output |
| `oracle list` | List recent runs (newest first, default 20) |
| `oracle list --json` | List runs as JSON |
| `oracle list --state running` | Filter by state |
| `oracle list --search "topic"` | Search prompt text |
| `oracle list --limit 5` | Limit results (default: 20) |
| `oracle list --id "abc"` | Filter by run ID prefix |
| `oracle list --url "conv-id"` | Filter by conversation URL |
| `oracle health` | Production health (success rate, errors, Chrome) |
| `oracle health --json` | Health data as JSON |
| `oracle health --hours 48` | Look back N hours (default: 24) |
### Error Handling
All commands support `--json`. With `--json`, errors output structured JSON to stdout:
```json
{ "error": true, "code": "ERROR_CODE", "message": "...", "suggestion": "..." }
```
Common error codes:
- `PROMPT_REQUIRED` — no prompt provided
- `PROMPT_TEXT_EMPTY` — prompt has file attachments but no instruction text
- `RUN_NOT_FOUND` — invalid run_id or run was removed with `oracle prune`
- `RUN_TERMINAL` — run already completed/failed/canceled
- `RESULT_NOT_AVAILABLE` — result not ready yet (use `oracle watch` first)
- `STATUS_NOT_AVAILABLE` — status file not yet written (run may still be starting)
- `NEEDS_USER` — requires manual intervention (login, Cloudflare). Escalate to user.
### `oracle watch --json` terminal states
When `watch --json` completes, check the `state` field:
- `"state":"completed"` — success. Use `oracle result <run_id>` to get the response.
- `"state":"failed"` — browser-level failure. Report it.
- `"state":"canceled"` — the run was canceled.
A non-completed state sets exit code 1.
**Response text may contain ChatGPT errors** — even when state is "completed", inspect the result text. If it looks like a generic error rather than a real answer, report it as a ChatGPT error.
### Recovery
- If `oracle watch` reports `needs_user`, escalate to the user immediately. After the user logs in via `oracle open`, resume with `oracle resume <run_id> --json`.
- If `oracle watch --json` reports `"state":"failed"`, report the failure. Do not retry automatically.
- On persistent failures (same query fails >2 times), alert the human.
- Stale `needs_user` runs (waiting >30 min) can be canceled with `oracle cancel <run_id> --json`.
### @file References
Include file contents in prompts: `@path/to/file.ts` uploads as attachment, `@file.ts:23-90` inlines specific lines.| Command | Description |
|---|---|
oracle run |
Start a new run or continue a conversation |
oracle watch |
Watch a run until completion |
oracle status |
Check run status |
oracle result |
Get the response text |
oracle thinking |
Get thinking/reasoning output |
oracle resume |
Resume a paused run |
oracle cancel |
Cancel an active run |
oracle list |
List recent runs with status and prompt preview |
oracle health |
Show production health: success rate, failure patterns, Chrome status |
oracle prune |
Remove old completed runs (explicit cleanup) |
oracle open |
Open a visible browser for login/recovery |
All commands support --json for machine-readable output. Use oracle <command> --help for full options.
oracle runlaunches a detached Chrome worker process with Oracle's dedicated profile- The worker navigates to ChatGPT, submits your prompt, and waits for the response
- Chrome runs offscreen (
--window-position=-32000,-32000) with AppleScript hiding — it never steals focus - State is persisted to
~/.oracle/runs/<run_id>/as JSON files oracle watchpolls until completion;oracle resultextracts the response
Oracle uses Playwright for browser automation.
Oracle always uses a separate Chrome profile at ~/.oracle/chrome — your personal Chrome is never touched. When your personal Chrome is also running, Oracle takes extra care:
- Skips app-level hiding to avoid accidentally hiding your personal Chrome windows
- Oracle's Chrome window is parked offscreen instead
- Set
ORACLE_FORCE_APP_HIDE=1to force full hiding (may affect personal Chrome windows)
Oracle uses AppleScript to manage Chrome windows. On first run, macOS may prompt you to grant your terminal (Terminal.app, iTerm2, etc.) Accessibility and Automation permissions in System Settings > Privacy & Security. Allow these — without them, Oracle can't hide the Chrome window or prevent focus stealing.
If ChatGPT requires login or hits a Cloudflare challenge, the run enters a needs_user state. A macOS notification is sent automatically via Notification Center so you know intervention is needed. To resolve:
# Open a visible browser to log in
oracle open
# Then resume the run
oracle resume <run_id>If Chrome is stuck:
oracle resume <run_id> --allow-killAll run data is stored persistently at ~/.oracle/runs/<run_id>/. This means:
- Results survive process crashes, terminal closures, and system reboots. As long as the run completed on ChatGPT, the result is recoverable.
- Run IDs are the primary recovery key. Save the
run_idfromoracle run --json— it's all you need to retrieve results later.
If you lose a run_id, use oracle list to find it:
oracle list # recent runs (newest first)
oracle list --search "architecture" # filter by prompt content
oracle list --state completed # only completed runs
oracle list --id "abc123" # filter by run ID prefix
oracle list --url "conv-id" # filter by conversation URL
oracle list --json # machine-readable outputOracle runs can take 5-90 minutes. If your agent framework uses block/session transitions (for instance, Klaus harness), save the run_id to persistent state before transitioning. On the next block:
- Retrieve the saved run_id
- Check status:
oracle status <run_id> --json - If complete:
oracle result <run_id> - If still running:
oracle watch <run_id> - If run_id is lost:
oracle list --search "keywords from your prompt"
| Environment Variable | Description |
|---|---|
ORACLE_BASE_URL |
Override ChatGPT URL |
ORACLE_DEV |
Enable dev mode (exposes --timeout-ms, --browser, etc.) |
ORACLE_FORCE_APP_HIDE |
Force app-level Chrome hiding (bypasses personal Chrome safety — may hide your personal Chrome windows) |
ORACLE_FORCE_KILL |
Enable SIGKILL for stuck Chrome (use with --allow-kill) |
ORACLE_CAPTURE_HTML |
Save debug HTML/PNG snapshots |
ORACLE_MAX_ATTEMPTS |
Override default max retry attempts (default: 3) |
All Oracle data lives under ~/.oracle/:
| Path | Contents |
|---|---|
~/.oracle/chrome/ |
Dedicated Chrome profile (cookies, login sessions, local storage) |
~/.oracle/runs/ |
Run data (prompts, results, status files, debug snapshots) |
Oracle never reads or writes your personal Chrome profile. To manage Oracle data:
# Wipe session data (forces re-login on next run)
rm -rf ~/.oracle/chrome
# Wipe all run history
oracle prune # removes old completed runs
rm -rf ~/.oracle/runs # removes everything
# Wipe all Oracle data
rm -rf ~/.oracle# Run from source
npm run dev -- run "Hello"
# Run safe tests (no Chrome, no focus stealing)
npm test
# Run all tests including Chrome integration
npm run test:all
# Run agent evals (mock ChatGPT)
npm run eval:agentsSee docs/TESTING.md for testing details.
Oracle automates a real Chrome browser against ChatGPT. This means it interacts with your ChatGPT account and manages Chrome processes on your machine. While it uses a dedicated Chrome profile and takes care to not interfere with your personal browser, browser automation is inherently somewhat unpredictable — ChatGPT's UI can change without notice, and things may break.
Please also ensure your usage complies with OpenAI's Terms of Use.
Inspired by @steipete/oracle by Peter Steinberger — an API-based Oracle CLI. This project takes a different approach: browser automation instead of API calls, designed specifically for agents that need ChatGPT Pro's extended thinking capabilities via the web interface.