Research workflows

Run and continue remote Codex tasks

Start a bounded CLI agent task, retain its continuation identifier, inspect sessions, and interrupt a selected task.

Review research files with a remote Codex session

Run a bounded review in a CoCalc project, retain its session identity, ask a follow-up, and inspect or interrupt a running turn. The CLI runs the agent in the selected project without requiring an open browser tab. Save the completed responses locally using the commands below.

You need the CLI quickstart, a project you can use, and a configured Codex authentication/payment source. Run the Bash commands below on your own computer using your account profile. Do not save your personal account login in a shared project.

Check access and prepare a bounded input

export CLI_PROFILE=cocalc-ai
export PROJECT_ID='REPLACE_WITH_FULL_PROJECT_ID'
export CODEX_DIR='/home/user/research-codex-demo'

cocalc --profile "$CLI_PROFILE" --json auth status --check
cocalc --profile "$CLI_PROFILE" project get --project "$PROJECT_ID"
cocalc --profile "$CLI_PROFILE" --json project codex auth status \
  --project "$PROJECT_ID"
cocalc project codex exec --help

LOCAL_CODEX=$(mktemp -d)
cd "$LOCAL_CODEX"
cat > analysis-note.md <<'MARKDOWN'
# Analysis for review

Input measurements: 2, 4, 6, 8.
Claim: their arithmetic mean is 5.
Reproducibility note: record the input checksum and Python version.
MARKDOWN

cocalc --profile "$CLI_PROFILE" project file put --project "$PROJECT_ID" \
  analysis-note.md "$CODEX_DIR/analysis-note.md"

Adjust /home/user for your project and use a previously unused scratch path. The Codex authentication result includes data.payment_source, data.has_subscription, and indicators for configured account, project, or site API keys. CLI account authentication and Codex authentication are separate: a successful auth status --check does not establish a usable Codex source. If the source is none, configure the intended source before running a turn. For an account using a ChatGPT subscription, the CLI provides the interactive project codex auth subscription login --project "$PROJECT_ID" flow. Complete its displayed device authorization yourself, then check status again. Never put an API key or authentication JSON into a prompt or research file.

Run a read-only first turn

cocalc --profile "$CLI_PROFILE" --timeout 10m --json project codex exec \
  --project "$PROJECT_ID" --workdir "$CODEX_DIR" --session-mode read-only \
  'Read only analysis-note.md in this directory. Check the arithmetic and identify one missing reproducibility detail. Do not edit files.' \
  > codex-turn-1.json

python3 - <<'PYTHON'
import json
from pathlib import Path
response = json.loads(Path("codex-turn-1.json").read_text())
assert response["ok"], response
result = response["data"]
assert result["thread_id"], "No returned thread ID; inspect the response"
Path("codex-session-id.txt").write_text(result["thread_id"] + "\n")
print(result["final_response"])
print("Saved session ID:", result["thread_id"])
PYTHON

export CODEX_SESSION_ID=$(cat codex-session-id.txt)

The expected outcome is an explanation that the mean is 5 and a reproducibility suggestion. The agent's wording varies; independently check its conclusions. --workdir is the working directory inside the project. --session-mode read-only requests a read-only session; use synthetic inputs when learning the workflow and review the selected project before granting write access.

Use data.thread_id from the completed first turn as the continuation ID. data.session_id echoes the ID you supplied and is null when the first command omits --session-id. These fields are not interchangeable on that first result. The JSON result also includes final_response, usage when available, and stream counters; it is not a transcript of every event.

Continue the same session

cocalc --profile "$CLI_PROFILE" --timeout 10m --json project codex exec \
  --project "$PROJECT_ID" --workdir "$CODEX_DIR" --session-mode read-only \
  --session-id "$CODEX_SESSION_ID" \
  'Based on that review, propose a two-item verification checklist. Do not edit files.' \
  > codex-turn-2.json

python3 - <<'PYTHON'
import json
from pathlib import Path
response = json.loads(Path("codex-turn-2.json").read_text())
assert response["ok"], response
print(response["data"]["final_response"])
PYTHON

Keep the same project and save each completed response. Reusing the ID asks CoCalc to resume the Codex session; it does not mean every file remains unchanged between turns. If resuming fails, inspect the error and existing session before choosing to start a new session without that ID. Starting anew loses the prior conversation context.

Choose one output format

Flags on project codex exec What is written
No output flags Final response in human-readable output.
--stream Progress on stderr while the turn runs, then the normal result.
Global --json without streaming One result envelope on stdout; parse data.
--jsonl without global --json Raw stream-message JSON objects, one per line on stdout; no final result object.
Global --json with --stream Stream messages followed by the final result envelope on stdout; not one JSON document.

For scripts like the examples above, use plain --json and wait for the result. For interactive progress, use --stream. If you choose JSONL, handle each message by its type; a summary message carries threadId and finalResponse. Do not feed a streaming output file directly to json.load() as though it were one result. Avoid combining --jsonl with global JSON output in these recipes.

Inspect or interrupt a running turn

Open a second local terminal while a turn is running. Set the same profile and project ID, then inspect your own recent sessions:

export CLI_PROFILE=cocalc-ai
export PROJECT_ID='REPLACE_WITH_FULL_PROJECT_ID'

cocalc --profile "$CLI_PROFILE" --json codex sessions \
  --active --project "$PROJECT_ID"
cocalc --profile "$CLI_PROFILE" --json codex sessions \
  --recent --project "$PROJECT_ID" --limit 20

The JSON data is a list of session records. Match the full project ID and session ID, and inspect state, terminal, updated_at, error, and session_key. Human output groups turns and shortens IDs, so use JSON to select an exact target. Listing sessions provides status and identifiers, not their full conversation transcripts.

To stop one specific active record, copy its full session_key and run:

export SESSION_KEY='REPLACE_WITH_EXACT_SESSION_KEY_FROM_THE_LIST'
cocalc --profile "$CLI_PROFILE" --json codex interrupt "$SESSION_KEY" \
  --note 'Stopping the scratch research review'

Alternatively, the interrupt command accepts session:<session_id> or op:<op_id>. Do not pass an unprefixed session ID when you intend the session-ID form: an unprefixed value is interpreted as a session key. This command is cocalc codex interrupt, not cocalc project codex interrupt.

Inspect both the outer ok and the returned data.ok, data.state, data.terminal, and data.message. Run the session listing again to verify whether the turn has reached a terminal state. An interrupt request can return an uncertain result; it is not evidence that all work has already stopped. Avoid interrupt-all when your goal is to stop only this exercise.

Handle failures and finish

Retain the session ID and local result files with your research notes. After confirming no scratch turn remains active, delete the scratch input directory through Files if it is no longer useful. The session-control commands above do not delete conversation history or undo file changes.