# Pending prompts (/docs/api/gateway/prompts)

Ready-to-paste prompts that agents (or you) leave for a future chat — handoffs, dated follow-ups — with reminders and one-click launch on a device.

A pending prompt is a complete, self-contained prompt saved for later: the handoff an agent writes when a goal is done, a follow-up that should only start after a date, or an idea you want to pick up in a fresh chat. It is stored centrally, so the same list shows up on the desktop app, the phone and the hub.

Agents read the list through the MCP server tools `prompts_list` (`status`, `limit`) and `prompts_get` (`id`). Both are read-only: launching a prompt starts a paid run, so it stays in the hub, desktop and phone.

## Pending prompts: how agents leave prompts for later [#pending-prompts-how-agents-leave-prompts-for-later]

1. **Capture.** At the end of a goal the agent posts its "start a new chat with this" prompt to `POST /v1/prompts`. The Copilot Stop hook, the desktop handoff tool, the phone and the hub all use the same endpoint, with `source` saying which one.
2. **Dedupe and supersede.** The same text is stored once (a sha256 of the whitespace-normalised prompt), so two capture paths never create twins — the second call answers `200` with `created: false`. Pass a stable `goal_key` and every older **open** prompt with that key becomes `superseded`: only the latest handoff for a goal stays open.
3. **Wait.** Without `not_before` the prompt is due at once. With a date (`2026-10-01` means 07:00 UTC that day) or an ISO datetime it stays quiet until then.
4. **Remind.** When `not_before` passes you get a `prompt.due` notification in the [inbox](/docs/api/gateway/triggers) (plus a push) whose `url` is `codai://prompts/<id>`. With `auto_run: true` the prompt is also launched automatically on `target_device_id`, or on your freshest desktop/Android device.
5. **Act.** Open the prompt and copy it, snooze it (`PATCH` a new `not_before` — this re-arms the reminder), mark it `done` / `dismissed`, or `POST …/launch`: that opens a new shared session and sends the text to a device as a `send` control. The prompt moves to `launched` and keeps the `run_session_id`.

```ts
import { Codai } from 'codai-sdk';

const codai = new Codai({ apiKey: process.env.CODAI_API_KEY! });
const saved = await codai.prompts.create({
  prompt: 'Goal: finish the billing export…',
  source: 'agent',
  goal_key: 'billing-export',
  not_before: '2026-10-01',
});
const due = await codai.prompts.list({ status: 'due' });
await codai.prompts.launch(saved.id);
```

```python
from codai import Codai

codai = Codai(api_key="codai_...")
saved = codai.prompts.create({"prompt": "Goal: finish the billing export…", "goal_key": "billing-export"})
codai.prompts.update(saved["id"], {"not_before": "2026-10-03"})  # snooze
codai.prompts.launch(saved["id"])
```

Statuses: `open` → `launched` → `sent` → `answered` → `verified`, plus the closing states `done` / `dismissed` / `superseded`. `GET /v1/prompts` defaults to `open`; `status=active` returns everything still in flight (`open`, `launched`, `sent`, `answered`), `status=due` returns open prompts whose `not_before` is empty or already passed, `status=all` returns everything.

## Sent, answered, verified [#sent-answered-verified]

You do not have to mark a prompt by hand once you paste it into a chat:

- **Sent.** When a session reports a `turn_start` whose text matches an active prompt (same hash, same first 4 000 characters, or word overlap of at least 85 %), the gateway marks the prompt `sent` and stores `match_ref` (the session) and `match_turn_id`. Clients that see chats the gateway does not (the VS Code extension scans local Copilot Chat sessions) report the same thing with `POST /v1/prompts/{id}/match`. Matching never blocks or fails the turn.
- **Answered.** When that turn ends (`turn_end`), the prompt moves to `answered`.
- **Verified.** `POST /v1/prompts/{id}/verify` asks `codai-fast` whether the chat actually did what the prompt asked. It reads the session transcript, plus an optional `diff` (for example `git diff base_sha..HEAD`) and `files` from the client, and stores a `report` (`verdict` `done` / `partial` / `not_started`, `summary`, `changed`, `remaining`). A `done` verdict moves the prompt to `verified`; any other verdict leaves the status alone. `POST /v1/prompts/verify` does the same for every active prompt that has a session (or for the `ids` you pass). Every client has a **Verify all** button for this.

## Live updates [#live-updates]

`GET /v1/prompts/stream` is a server-sent event stream: one `prompt` event per create, update or delete of any of your prompts, so the desktop app, phone, hub and VS Code show the same state within a second or two. A backgrounded phone gets a push instead.

<OpenAPIPage document="./openapi/en/gateway.yaml" operations={[{path: '/v1/prompts',method: 'get'},{path: '/v1/prompts',method: 'post'},{path: '/v1/prompts/{id}',method: 'get'},{path: '/v1/prompts/{id}',method: 'patch'},{path: '/v1/prompts/{id}',method: 'delete'},{path: '/v1/prompts/{id}/launch',method: 'post'},{path: '/v1/prompts/{id}/match',method: 'post'},{path: '/v1/prompts/{id}/verify',method: 'post'},{path: '/v1/prompts/verify',method: 'post'},{path: '/v1/prompts/stream',method: 'get'}]} />
