Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

15 Commits

Folders and files

Repository files navigation

chatgpt-session-cli

cgs is a small CLI for inspecting and continuing your own ChatGPT web sessions from the terminal.

It deliberately separates read-only browsing from account-side writes:

Command Boundary What it does
cgs doctor read-only Checks auth metadata, a tiny backend read probe, command aliases, and Chromium CDP health without printing secrets.
cgs list read-only Lists ChatGPT conversations through the web backend.
cgs show <conversation_id> read-only Prints one conversation as text or JSON.
cgs export read-only Writes raw conversation JSON files for a private, append-preserving archive.
cgs chat write Sends one prompt to a new ChatGPT web conversation, or continues an existing one when --conversation-id is provided.

This project uses ChatGPT's unofficial web backend APIs, not the OpenAI Platform API. cgs export is a read-only local snapshot helper; it does not upload, delete, or mutate ChatGPT conversations.

Quick start

cd /path/to/chatgpt-session-cli
uv run cgs --help
uv run cgs doctor --skip-read-probe --skip-cdp

If you want the command globally:

cd /path/to/chatgpt-session-cli
uv tool install -e . --force
cgs --help

cgs is the recommended short command. cgpts, cgpt-session, and chatgpt-session-cli are equivalent aliases. In an uninstalled checkout, prefix the examples below with uv run, for example uv run cgs list.

Full usage guide: docs/usage.md

Authentication for read-only session browsing

The simplest read-only flow is to save your ChatGPT session JSON locally.

  1. Open this while logged in to ChatGPT:

    https://chatgpt.com/api/auth/session
    
  2. Copy the full JSON response.

  3. Save it as the default auth file. On macOS, after copying the response:

    mkdir -p ~/.config/chatgpt-session-cli
    pbpaste > ~/.config/chatgpt-session-cli/auth.json
    chmod 600 ~/.config/chatgpt-session-cli/auth.json

    On other operating systems, paste the JSON into that same path with a local editor, then restrict the file to the current user when the platform supports it.

  4. Verify the read-only setup, then browse conversations:

    cgs doctor --skip-cdp
    cgs list

The file should look roughly like this:

{
  "user": {
    "email": "you@example.com"
  },
  "accessToken": "...",
  "sessionToken": "...",
  "expires": "..."
}

accessToken is required for read-only backend calls. sessionToken is optional for list / show, but enables the experimental chat write-path to inject a logged-in ChatGPT browser cookie into the connected Chromium context. Keep both values local and treat them as account-equivalent secrets.

Do not commit auth files. .gitignore also protects an accidental repo-local file:

/auth.json

By default, cgs reads CHATGPT_SESSION_AUTH_FILE when set, then ~/.config/chatgpt-session-cli/auth.json. It never searches the caller's current directory or the source checkout, so the same local auth file works from any repository.

To use a different file explicitly:

cgs --auth-file ~/some/local/auth.json list

Or set it once in your shell:

export CHATGPT_SESSION_AUTH_FILE="$HOME/some/local/auth.json"
cgs list

Do not paste session JSON, session cookies, access tokens, or SSE stream bodies into chat logs. Keep them local.

Local diagnostics and auth refresh

Health check without printing secrets:

# Full local diagnostic: auth metadata, tiny read probe, aliases, and Chromium CDP health
cgs doctor

# Machine-readable diagnostic output
cgs doctor --json

Refresh auth.json from a logged-in Chromium page connected over CDP without pasting tokens into chat or argv:

# Attach to the local CDP endpoint, or launch the default browser if it is not running
cgs login --from-cdp

# If you need to sign in manually, open a ChatGPT tab first, then poll while you finish login
cgs login --from-cdp --wait-seconds 300

This flow fetches /api/auth/session inside the browser context, validates the returned access token against /backend-api/models, and writes only the local auth file. If it reports backend_token_invalid, sign in again in that same Chromium profile.

Read-only commands

Session browsing:

# List active conversations, newest first
cgs list

# Show one conversation. Long output opens in a pager when needed.
cgs show <conversation_id>

# Force pager. show starts at the bottom when less is used.
cgs show <conversation_id> --pager always

# More rows
cgs list --limit 200

# No limit
cgs list --limit 0

# Archived only
cgs list --archived

# Active + archived
cgs list --all

# JSON for scripts
cgs list --json
cgs show <conversation_id> --json

# Export active conversations as raw API JSON for the private session archive
cgs export --output-dir ~/.config/chatgpt-session-cli/archive/conversations --limit 100

# Resume a partially completed backfill without refetching files already on disk
cgs export --output-dir ~/.config/chatgpt-session-cli/archive/conversations --limit 100 --skip-existing

# Include archived conversations too (one request mode at a time)
cgs export --all --output-dir ~/.config/chatgpt-session-cli/archive/conversations --limit 100

# Disable the inter-request delay only for a controlled local test
cgs export --request-delay-ms 0 --limit 1

# Disable pager explicitly
cgs show <conversation_id> --pager never

Other read-only auth flows

Interactive local login:

cgs login

This prints the ChatGPT session JSON URL (https://chatgpt.com/api/auth/session) and accepts the complete JSON response directly in the terminal, including long or pretty-printed responses. It writes the default auth file containing the access token, optional session/CSRF tokens, and user email. A raw session token is also accepted for compatibility.

Env-var based flows, useful when you already have a token locally and do not want it in shell history or process args:

# Save an access token from a local env var
CHATGPT_ACCESS_TOKEN=*** cgs login --access-token-from-env

# Save from a session token stored in a local env var
CHATGPT_SESSION_TOKEN=*** cgs login --session-token-from-env

# Use an access token for one read-only command without writing auth.json
CHATGPT_ACCESS_TOKEN=*** cgs list

Experimental chat write-path

Use this only when you explicitly want to mutate ChatGPT web conversation state. cgs chat sends one prompt through a Chromium page connected over CDP. When --conversation-id is omitted, it creates a new ChatGPT conversation. When --conversation-id is provided, it continues that existing conversation; --parent-message-id can pin a specific parent node.

The command attaches to http://127.0.0.1:9222 first. If the endpoint is unavailable, it launches the system-default Chromium-family browser with its existing profile when that browser is not already running. On macOS this follows the default browser app (including Dia); use --chromium-executable to override it. It never closes an already-running browser unless --relaunch-default-browser is explicitly passed. Pass --browser-profile-dir to use an isolated profile instead. If the auth file contains sessionToken or session_token, that value is injected as the __Secure-next-auth.session-token cookie before posting. No token value is accepted through argv or printed.

Important defaults:

Option Default Notes
--cdp-url http://127.0.0.1:9222 Loopback Chromium CDP endpoint.
--browser-profile-dir detected browser profile on macOS; otherwise ~/.config/chatgpt-session-cli/chromium-cdp-profile Override the profile used when cgs launches Chromium. Pass a new path for isolation.
--relaunch-default-browser off Explicitly allow cgs to close and restart the running default browser profile to enable CDP.
--request-delay-ms 1500 Waits between backend calls to avoid ChatGPT “Too many session requests”. Use 0 only for debugging.
--model ChatGPT account default, or gpt-5-5-thinking with --deep-research Validated against /backend-api/models before POST.
--think / --thinking-effort unset Must be supported by the selected model.
--deep-research-version standard Experimental metadata observed from ChatGPT's Deep Research App.

Deep Research is experimental. --deep-research now mirrors the observed ChatGPT web-app routing shape: it prefixes the user text with the Deep Research ecosystem mention, adds the connector:connector_openai_deep_research system_hints, includes deep_research_version=standard / venus_model_variant=standard plus the ecosystemMention serialization metadata, and sends the observed /backend-api/f/conversation/prepare connector-prepare call before the final conversation POST. It defaults the model to gpt-5-5-thinking unless --model is explicitly provided. Success is verified only from non-secret assistant/tool metadata such as Deep Research App_start, /connector_openai_deep_research/start, async_task_conversation_id, and venus_widget_state; user-turn metadata alone is not treated as activation.

Prerequisites:

  1. A Chromium-family browser can be connected over CDP at --cdp-url, or cgs can find an installed browser to launch.
  2. The connected page is logged into https://chatgpt.com/, or the selected auth file contains sessionToken / session_token for cookie injection.
  3. For continuation only: an existing conversation_id from cgs list or from ChatGPT's URL.

Some Chromium builds, including Chrome 136 and later, do not allow remote debugging with the ordinary default profile. Dia supports the default-profile flow. If the browser is already running without CDP, cgs refuses to close it by default; start it with CDP yourself, pass --relaunch-default-browser, or use an isolated --browser-profile-dir. Keep the CDP endpoint bound to 127.0.0.1 because it grants full control of the connected browser.

Help:

cgs chat --help

New conversation:

cgs chat \
  --prompt 'CLI POST connectivity test. Reply with exactly: ok'

Continue an existing conversation:

cgs chat \
  --conversation-id '<conversation-id>' \
  --prompt 'Continue from here'

Disable auth-file cookie import when you intentionally want to rely only on the existing Chromium CDP browser session:

cgs chat \
  --conversation-id '<conversation-id>' \
  --no-auth-inject

Optional JSON output:

cgs chat \
  --prompt 'Reply with exactly: ok' \
  --json

cgs chat returns explicit non-secret error codes for common write-path failures:

Code Meaning
no_access_token The connected Chromium page reached /api/auth/session, but ChatGPT did not expose an access token. Log into ChatGPT in that profile or refresh auth.json.
models_request_failed The account-visible model list could not be fetched, commonly because the access token is expired.
prepare_request_failed / finalize_request_failed Sentinel chat-requirements negotiation failed before posting.
post_request_failed The final /backend-api/conversation write failed.
verification_request_failed The write may have happened, but the follow-up conversation fetch failed, so the CLI did not verify it.

Start an experimental Deep Research request:

cgs chat \
  --deep-research \
  --request-delay-ms 3000 \
  --prompt 'Research HoudahSpot from a technical architecture perspective' \
  --json

For smoke tests, run it once and verify metadata rather than assistant prose:

deep_research.activation_detected
deep_research.async_task_conversation_id
deep_research.widget_status

Reuse an existing tab and parent node when you already know them:

cgs chat \
  --cdp-url http://127.0.0.1:9222 \
  --no-launch \
  --conversation-id '<conversation-id>' \
  --parent-message-id '<current-node-id>' \
  --prompt 'Continue from this exact parent'

Details and safety notes are in docs/usage.md and docs/cdp-post-poc.md.

What the CLI calls

Read-only browsing endpoints:

GET https://chatgpt.com/backend-api/conversations
GET https://chatgpt.com/backend-api/conversation/{conversation_id}
GET https://chatgpt.com/api/auth/session

Experimental cgs chat write-path flow inside Chromium browser context connected over CDP:

GET  https://chatgpt.com/api/auth/session
GET  https://chatgpt.com/backend-api/conversation/{conversation_id}   # continuation only
GET  https://chatgpt.com/backend-api/models
POST https://chatgpt.com/backend-api/sentinel/chat-requirements/prepare
POST https://chatgpt.com/backend-api/sentinel/chat-requirements/finalize
POST https://chatgpt.com/backend-api/conversation
GET  https://chatgpt.com/backend-api/conversation/{conversation_id}   # verification

For new conversations, the final verification id is parsed from the POST SSE stream. No PATCH, archive, delete, or bulk mutation endpoints are implemented.

Pager behavior

Text output uses --pager auto by default.

  • auto: open $PAGER/less only when stdout is an interactive TTY and output is taller than the terminal.
  • always: force pager.
  • never: print directly.
  • show starts at the bottom when paging through less, so the newest/end of the conversation is visible first.
  • JSON output is never paged.

Safety notes

  • This uses unofficial ChatGPT web APIs. Endpoints and response shapes may change without notice.
  • Auth files contain account-equivalent secrets. Treat them like passwords.
  • Secret values are not accepted as direct chat argument values, to avoid process-list and shell-history leaks.
  • chat prints only non-secret verification metadata or non-secret JSON summaries.
  • chat mutates ChatGPT conversation state and does not delete or roll back test messages.
  • Keep auth.json local and out of Git.

Development

Development checks:

uv run python -m unittest discover -s tests
uv run python -m compileall -q src tests scripts
uv run cgs chat --help

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages