---
type: research
title: Flow A Manual — Step-by-Step (executable by a fresh agent)
description: The validated end-to-end sequence of flow A1 (session-keeper) with exact headers, bodies and the live token acquisition — reproducible request by request via the bezetacil harness
tags: [openai, flow-a, manual, step-by-step, protocol, bezetacil, headers, bodies]
timestamp: 2026-08-27
---

# Flow A Manual — Step-by-Step (A1)

Part of [openai-research](openai-research.md). This is the **validated** sequence (2026-08-27; multiple successful runs: tool call, client return, multi-turn continuation). Every step is one action; every HTTP request goes through the **bezetacil trigger `conv`** (the main process `electron.net` — the same transport and pool as the app).

## 0. Environment

- bezetacil running (`http://127.0.0.1:9228`), the ChatGPT desktop app **logged in** (the app-server holds the session).
- Installation constants (this Mac, 2026-08-27): `oai-did = a05f9cdd-ca51-4a91-9da1-9c374dfe0536` (live from the renderer — verified `at` step 2), `ChatGPT-Account-Id = aa06cafc-774a-432f-b104-89d45ad24d81`, `User-Agent = Codex Desktop/26.820.60940 (Mac OS; arm64)`, `originator = Codex Desktop`, `OAI-Language = en-US`, timezone `America/Sao_Paulo`, `timezone_offset_min = 180`.

## 1. Live access token (getAuthStatus with includeToken)

Write `/tmp/standalone-a-rpc.json`:
```json
{"method": "getAuthStatus", "params": {"includeToken": true, "refreshToken": false}}
```
`POST http://127.0.0.1:9228/run/rpc` → response:
```json
{"id": "<uuid>", "result": {"authMethod": "chatgpt", "authToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6…", "requiresOpenaiAuth": true}}
```
Use `authToken`. (The live app-server session token; the static `~/.codex/auth.json` may be stale after an app-server refresh — using the stale file produced 403s on 2026-08-27 16:19+ until the live token was used.)

## 2. Live did

`POST http://127.0.0.1:9228/run/did-runtime` → (real response observed 2026-08-27 — the targets list varies with the open webContents; the important field is `did`):
```json
{"targets": [{"id": 3, "url": "https://chatgpt.com/?source=codex-embedded-checkout#pricing"},
              {"id": 2, "url": "app://-/index.html?initialRoute=%2Favatar-overlay"}],
 "did": "a05f9cdd-ca51-4a91-9da1-9c374dfe0536", "error": null}
```.
**Never regenerate** (the did is the persisted installation identity in the renderer localStorage key `codex.chatgpt-conversations.device-id`; a fresh uuid → 403 both at challenge and conversation).

## 3. DeviceCheck token

`POST http://127.0.0.1:9228/run/devicecheck` → `{"ok": true, "result": {"supported": true, "token": "AgAA…", "len": 2980}}` (generated in the MAIN process — the app bundle context — same as the app's own flow).

## 4. Per-turn cycle

Run 4.1 → 4.2 → 4.3 for **each** turn (user message, tool return, continuation). Write each input to `/tmp/standalone-a-input.json`, then `POST http://127.0.0.1:9228/run/conv`.

### 4.1 attestation challenge

Input:
```json
{"url": "/ios/attestation_challenge", "method": "GET",
 "headers": {
   "OAI-Language": "en-US",
   "oai-did": "a05f9cdd-ca51-4a91-9da1-9c374dfe0536",
   "originator": "Codex Desktop",
   "User-Agent": "Codex Desktop/26.820.60940 (Mac OS; arm64)",
   "Authorization": "Bearer <authToken from step 1>",
   "ChatGPT-Account-Id": "aa06cafc-774a-432f-b104-89d45ad24d81",
   "x-sentinel-dc": "{\"token\": \"<devicecheck token from step 3>\"}"}}
```
→ `{"ok": true, "result": {"status": 200, "text": "{\"attestation_challenge\": \"gAAAAABqkGYnoU…\", …}"}}`.
The challenge is **one-time** — never reuse it for a second request.

### 4.2 prepare

Input:
```json
{"url": "/f/conversation/prepare", "method": "POST",
 "headers": {
   "OAI-Language": "en-US",
   "oai-did": "a05f9cdd-ca51-4a91-9da1-9c374dfe0536",
   "originator": "Codex Desktop",
   "User-Agent": "Codex Desktop/26.820.60940 (Mac OS; arm64)",
   "Authorization": "Bearer <authToken>",
   "ChatGPT-Account-Id": "aa06cafc-774a-432f-b104-89d45ad24d81",
   "Content-Type": "application/json",
   "x-conduit-token": "no-token"},
 "body": {
   "action": "next",
   "client_prepare_state": "sent",
   "model": "gpt-5-6-thinking",
   "thinking_effort": "extended",
   "timezone": "America/Sao_Paulo",
   "timezone_offset_min": 180}}
```
→ `{"status": 200, "text": "{\"status\":\"ok\",\"conduit_token\":\"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9…\"}"}`.

### 4.3 conversation

Input (first turn of a new conversation — omit `conversation_id` and `parent_message_id`; every following turn includes both):
```json
{"url": "/f/conversation", "method": "POST",
 "headers": {
   "OAI-Language": "en-US",
   "oai-did": "a05f9cdd-ca51-4a91-9da1-9c374dfe0536",
   "originator": "Codex Desktop",
   "User-Agent": "Codex Desktop/26.820.60940 (Mac OS; arm64)",
   "Authorization": "Bearer <authToken>",
   "ChatGPT-Account-Id": "aa06cafc-774a-432f-b104-89d45ad24d81",
   "Content-Type": "application/json"},
 "body": {
   "action": "next",
   "local_function_signatures": [
     {"description": "Redirect the user's request from ChatGPT to Work mode when Work mode is the better execution environment.\n\nYou MUST call this tool before doing any work when the request involves:\n- Browser use or computer-use automation\n- Building apps, local coding, repository edits, command execution, or file inspection\n- Opening, updating, reviewing, or otherwise working with PRs\n- Creating, editing, converting, inspecting or delivering files or artifacts, including implicit requests for downloadable or editable deliverables such as slide decks, `.pptx`, spreadsheets, `.xlsx`, workbooks, documents, `.docx`, or PDFs,\n- Complex analysis such as financial modeling\n\nPrefer answering directly in ChatGPT for:\n- Email, message, or prose drafting\n- Brainstorming, planning, or explanation\n- Code snippets or examples that fit naturally in chat\n\nIf the user rejected the suggestion, don't call this tool again.",
      "name": "handoff",
      "params": [
        {"name": "prompt", "required": true, "type": {"description": "A brief instruction describing what Work mode should do for the user.", "type": "string"}},
        {"name": "reason", "required": true, "type": {"description": "A short user-facing reason why continuing in Work mode would help.", "type": "string"}}],
      "type": "kwargs"}],
   "messages": [
     {"author": {"metadata": {}, "name": null, "role": "user"},
      "channel": null,
      "content": {"content_type": "text", "parts": ["<the user text>"]},
      "create_time": <unix seconds as a float>,
      "end_turn": null,
      "id": "<new uuid>",
      "metadata": {},
      "recipient": "all",
      "status": "finished_successfully",
      "update_time": null,
      "weight": 1}],
   "model": "gpt-5-6-thinking",
   "supported_encodings": ["v1"],
   "thinking_effort": "extended",
   "timezone": "America/Sao_Paulo",
   "timezone_offset_min": 180,
   "client_prepare_state": "success",
   "app_attest_challenge": "<challenge from 4.1>",
   "conversation_id": "<id of the existing conversation — omitted on the first turn>",
   "parent_message_id": "<id of the last message — omitted on the first turn>"}}
```
→ **`200`** with the SSE (delta v1: `add`/`append`/`patch`; `message_marker` events `cot_token`, `user_visible_token`, `final_channel_token`; streams end with `message_stream_complete` + `conversation_detail_metadata` + `title_generation`).

**Invariants that are now facts** (each verified):
- No `x-conduit-token` header on `/f/conversation` (the app's own winning request has none; the conduit is prepare-only).
- The first turn of a conversation omits `conversation_id`/`parent_message_id`; **every** following turn includes both (omitting them on a continuation → 403; the app always sends them in follow-up payloads).
- The `local_function_signatures` must contain the `handoff` signature in normal turns (a turn with only a custom tool and no handoff → 403).
- The whole cycle (challenge, prepare, conversation) stays on the **same transport** (the main/trigger path).

## 5. Multi-turn continuation (same conversation)

For the next user message: run 4.1 (fresh challenge), 4.2 (fresh prepare), 4.3 with `conversation_id` and `parent_message_id` = the **last assistant `message.id`** (from the previous SSE — or from the conversation tree via `GET /conversation/<id>`), messages = the new user record. Validated: `200` → "De nada.".

## 6. TypeScript types (the A1 surface)

```ts
// ── app-server RPC (via the bezetacil rpc trigger) ───────────────────────
export type AuthMode =
  | 'apiKey'                 // Codex-managed API key
  | 'chatgpt'                // managed ChatGPT OAuth (tokens persisted/refreshed by Codex)
  | 'chatgptAuthTokens'      // EXTERNAL-host-provided tokens, memory-only (this is our A1 state:
                             //   authToken obtained AS-IS from getAuthStatus {includeToken:true})
  | 'amazonBedrock'          // Managed Bedrock
// source: codex-rs/app-server-protocol/src/protocol/common.rs line 24 (enum AuthMode)

export interface GetAuthStatusParams {
  includeToken: boolean      // false = no token returned (the app's own calls use false)
  refreshToken: boolean      // false = never refresh as a side effect
}
export interface GetAuthStatusResponse {
  authMethod: AuthMode
  authToken?: string         // present only when includeToken: true (the LIVE session token)
  requiresOpenaiAuth: boolean
}

// ── triggers (bezetacil) ─────────────────────────────────────────────────
export interface DidRuntimeResult {          // POST :9228/run/did-runtime
  targets: Array<{ id: number; url: string }>
  did: string | null                         // the renderer localStorage value
  error: string | null
}
export interface DeviceCheckTriggerResult {   // POST :9228/run/devicecheck
  supported: boolean
  token: string                               // base64 App-Attest token (2980 chars)
  len: number
}

// ── attestation challenge ────────────────────────────────────────────────
export interface ChallengeHeadersToken {     // x-sentinel-dc value
  token: string
}
export interface AttestationChallengeResponse {
  attestation_challenge: string               // 'gAAAAAB…' — one-time per use
}

// ── prepare ──────────────────────────────────────────────────────────────
export interface PrepareHeaders {
  'OAI-Language': 'en-US'
  'oai-did': string
  originator: 'Codex Desktop'
  'User-Agent': `Codex Desktop/${string} (Mac OS; arm64)`
  Authorization: `Bearer ${string}`
  'ChatGPT-Account-Id': string
  'Content-Type': 'application/json'
  'x-conduit-token': 'no-token'
}
export interface PrepareResponseBody {       // decoded from the trigger text
  status: 'ok'
  conduit_token: string                       // JWT ES256 — see Jet claims below
}
/** The conduit JWT payload (decoded from real tokens). */
export interface ConduitTokenClaims {
  conduit_uuid: string
  conduit_location: string                    // '10.130.x.x:830x' (internal cluster coord)
  cluster: string                             // 'unified-83' / 'unified-84' — the routing pin
  iat: number
  exp: number                                 // iat + 60 (1-minute lifetime)
  turn_topic_id: string | null
}

// ── conversation request headers ─────────────────────────────────────────
export interface ConversationHeaders extends Omit<PrepareHeaders, 'x-conduit-token' | 'Content-Type'> {
  'Content-Type': 'application/json'
  // NO x-conduit-token on /f/conversation (verified)
}

// ── conversation request body / response ─────────────────────────────────
export type ConversationRequestBodyV1 =
  import('./flow-a-tool-protocol').ConversationRequestBody   // the shared type from the tool protocol page
export interface ConversationResponseStream {
  /** SSE text of /f/conversation (see [response-sse-real](response-sse-real.md) for the event types). */
  // events: delta_encoding 'v1'; data-only; delta {c,o,p,v}; message_marker; title_generation;
  //         message_stream_complete; conversation_detail_metadata; server_ste_metadata
}
```

## Cross-references

- [flow-a-tool-protocol](flow-a-tool-protocol.md) — the tool contract (call_id, end_turn, recipient, channel)
- [flow-a-403-cases](flow-a-403-cases.md) — what fails and why
- [flow-definitions](flow-definitions.md) — A / A0 / A1 / B
- [bezetacil](../bezetacil/bezetacil.md) — the harness (triggers rpc / conv / devicecheck / did-runtime / cookie-check)
