---
type: research
title: Modo ChatGPT, Submodo Work — Protocolo
description: As duas formas de iniciar o submodo work (direto pela aba e via handoff), execution target local_executor, e o que muda no payload
tags: [openai, chatgpt, work-submode, handoff, local-executor, protocol]
timestamp: 2026-08-24
---

# Modo ChatGPT, Submodo Work — Protocolo

Part of [openai-research](openai-research.md). Fixed nomenclature: see the hub glossary.

## The two ways to start

1. **Direct (Work tab at the top of ChatGPT mode)**: o composer mode é persistido por conversa (`home-composer-mode`, enum interno `['chat', 'work', 'codex']`) com resolver de gating (`workOnlyModeEnabled`, `workModeAllowed`, denied → work). Com a aba work ativa, `isEverydayWorkMode = true`.
2. **Via handoff (from the chat submode)**: o modelo do chat chama a tool `handoff(prompt, reason)` → cria o thread/work. (O caso "crie uma task no modo work…" — ver [voice-and-tasks](voice-and-tasks.md).)

## What changes in the payload (`/f/conversation`)

- `local_function_signatures: [{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'}]` — with the **full server-provided description** ("Redirect the user's request from ChatGPT to Work mode when Work mode is the better execution environment…" — verbatim text in [flow-a-tool-protocol](flow-a-tool-protocol.md) and [flow-a-manual-step-by-step](flow-a-manual-step-by-step.md)). **Always offered in the ChatGPT mode** (chat submode included — the handoff is the bridge from chat to work); the model calls it only when the task needs execution
- `conversation_execution_target`:

```json
{
  "kind": "local_executor",
  "cwd": "<diretório da conversa>",
  "installation_id": "<app installation id>",
  "mcp_servers": {},
  "selected_capability_roots": []
}
```

- O target **persiste na `metadata.conversation_execution_target` da primeira user message** — os turns seguintes derivam dele (`jVr` lê da última user message)
- `model`/`thinking_effort`: defaults do submodo (ex.: "5.5 High")

## Execution

When the model calls `handoff`, the app executes the agent **locally** via the embedded app-server (`Resources/codex`) — the UI "Full access" is this executor scope (cwd, capability roots, local MCP servers, up to 256). Codex threads: `codex://threads/{id}`; thread compact via `/responses/compact` (see [codex-flow-protocol](codex-flow-protocol.md)).

## Execution location: local vs cloud (the sidebar label)

The thread hover card shows **`execution-location`**: `local` ("**Runs on your computer**", `sidebar.thread.hoverCard.executionLocation.local`) vs `cloud` ("**Runs in the cloud**"). Feature flags gate each: `workLocalAccess`, `workCloudAccess`, `codexLocalAccess` (plus `localBackend`). Observed: a **Codex mode thread** (started in the Codex tab, `thread_source: user`) is listed in the ChatGPT mode as "Work — Runs on your computer" — the modes share the **same local thread store** (`state_5.threads`); the sidebar differentiates conversations by `conversation_origin` (`tpp` = tasks vs `non-tpp`) and the label by execution location. "Work cloud/remote" = the site-side equivalent (needs `workCloudAccess`; not exercised in this research).

## Tasks (origin `tpp`)

`conversation_origin: 'tpp'` marca as **tasks** do Work — o filtro da sidebar (`chats` = origin ≠ tpp; `tasks` = origin === tpp) e `Pqr()`: origin tpp → backend `codex`. Creation via `POST /wham/tasks` with `prior_conversation` when it comes from the chat (see [voice-and-tasks](voice-and-tasks.md)).

## TypeScript types (payloads of the work submode)

```ts
// ── handoff (the local function signature that starts work) ──────────────
export interface HandoffParams {
  prompt: string          // required — brief instruction for Work
  reason: string          // required — user-facing reason
}
export type HandoffSignature = import('./flow-a-tool-protocol').LocalFunctionSignature & {
  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' } },
  ]
}

// ── the execution target (persisted in the first user message metadata) ──
export interface LocalExecutionTarget {
  kind: 'local_executor'
  cwd: string
  installation_id: string
  mcp_servers: Record<string, unknown>   // {} observed for the plain chat handoff
  selected_capability_roots: unknown[]
}
export interface RemoteExecutionTarget {
  kind: 'remote'           // the site-side equivalent (workCloudAccess) — not exercised
  [key: string]: unknown
}
export type ExecutionTarget = LocalExecutionTarget | RemoteExecutionTarget

// ── persistence + labels ─────────────────────────────────────────────────
export interface FirstUserMessageMetadata {
  conversation_execution_target: ExecutionTarget
}
export type ConversationOrigin = 'tpp' | 'non-tpp' | string     // 'tpp' = Work tasks (sidebar)
export type ExecutionLocationLabel = 'local' | 'cloud'
export interface ExecutionLocationFlags {
  workLocalAccess: boolean
  workCloudAccess: boolean
  codexLocalAccess: boolean
  localBackend: boolean
}
```

## Cross-references

- Chat submode (the focus): [chat-submode-protocol](chat-submode-protocol.md)
- Shared codex backend: [codex-flow-protocol](codex-flow-protocol.md)
- Architecture: [chatgpt-desktop-architecture](chatgpt-desktop-architecture.md)
- Live full-loop evidence: [work-runtime-trace](work-runtime-trace.md)
- The tool contract (the handoff is the canonical client-executed tool): [flow-a-tool-protocol](flow-a-tool-protocol.md)
- Flow definitions: [flow-definitions](flow-definitions.md) (work is not a flow — it is a surface; the flows A/B describe attestation/PoW)
