# Claude Conversation Management — and taking a conversation to claude.ai / your phone

Hydrogen Desktop runs Claude Code as **conversation tabs** inside the editor. HD exposes a
**first-class API** to manage those conversations — list them, open and close them, switch
between them, read each one's full state, type into a specific one, and **turn on Remote
Control so you can continue the same conversation on claude.ai or the Claude mobile app**.

Everything here works for **you**, for the **AI inside your workspace**, and for HD's own
setup steps — they all call the same endpoints. It all runs in the background: no window
focus, no stolen keystrokes.

![Multiple Claude conversations as tabs in Hydrogen Desktop](screenshots/claude-conversations.png)

## Why this matters

- **Run several conversations at once** and drive each independently — one mapping your
  design stack, one wiring up pricing, one answering a quick question — all
  scriptable.
- **Keep going on your phone.** Turn on Remote Control and HD hands you a `claude.ai` URL.
  Open it in any browser or the Claude mobile app and you're looking at — and controlling —
  the *same* conversation in the cloud. Start at your desk in HD, continue from the couch on
  your phone.
- **Nothing gets lost.** Every conversation is stored as a local log you can read, and HD
  can hand you its session id automatically.

## The model: every conversation has a stable id

Each conversation is addressed by a stable **`context_id`**. That's how you reliably target
one — not its tab position (tabs come and go) and not its title (untitled until you send a
message). Ask HD for the list, then act on a conversation by its id.

> The control API runs on a dynamic local port — find it in the HD log or via port
> discovery. Examples below use `$HD` for `http://127.0.0.1:<port>`.

## See what's open

```bash
curl -s $HD/claude/conversations
```
```jsonc
{
  "count": 2,
  "conversations": [
    { "ordinal": 3, "active": true, "loaded": true, "context_id": 7,
      "title": "Calculate 10 times 10", "tab_label": "Calculate 10 times 10",
      "compose_text": "", "msg_count": 16,
      "session_id": "566cec21-d84f-4600-a119-e31f88683ff3",
      "rc_active": false, "remote_control_url": null },
    { "ordinal": 1, "active": false, "loaded": false, "context_id": null,
      "title": "Find the capital of France", "tab_label": "Find the capital of Fran…",
      "compose_text": null, "msg_count": null,
      "session_id": "b352055b-471f-46dc-b412-a4450642e831",
      "rc_active": null, "remote_control_url": null }
  ]
}
```
- The list **merges three sources** so you see everything: the tab bar (every conversation +
  which is `active`), the live webviews (rich data for `loaded` tabs), and the on-disk logs (GUIDs).
- `loaded:false` means VS Code disposed that background tab's webview — its `context_id`,
  `compose_text`, `msg_count`, and `rc_active` read `null` until you activate it. Its `session_id`
  still resolves when the title matches the log.
- `title` is the name Claude gives the conversation after its first message (before that it's
  `Untitled`); `rc_active` shows whether Remote Control is on.

## Open, close, switch

```bash
curl -s -X POST $HD/claude/new-conversation       # open a new conversation tab
curl -s -X POST $HD/claude/tabs/close-all          # close them all (and clean the blank panel)
curl -s -X POST $HD/claude/tabs/activate -d '{"label":"Eiffel"}'   # switch by title
curl -s -X POST $HD/claude/tabs/close-empty-groups # remove a stale empty split panel
```
HD keeps your editor tidy: it removes leftover **empty** editor panels automatically on
launch, while **preserving** an intentional two-group (left/right) layout if you use one.

## Type a message into a specific conversation

```bash
# Instant (fast):
curl -s -X POST $HD/claude/inject \
  -d '{"text":"summarize this repo","context_index":16,"typed":false,"submit":true}'

# With the human typing animation, then send:
curl -s -X POST $HD/claude/inject \
  -d '{"text":"hello","context_index":16,"typed":true,"delay_ms":50,"submit":true}'
```
- `typed`: `true` = animated character-by-character; `false` = instant paste.
- `submit`: `true` = press Enter; `false` = leave it in the compose box as a draft.
- It lands in **exactly** that conversation, even with many open and even when it's not the
  one on screen.

## ⭐ Remote Control: continue on claude.ai / your phone

```bash
curl -s -X POST $HD/claude/remote-control -d '{"context_index":7}'
```
```jsonc
{
  "ok": true,
  "rc_active": true,
  "context_id": 7,
  "remote_control_url": "https://claude.ai/code/session_014koKPJxmjYpnX2SjRRqrD3"
}
```
Open that `remote_control_url` on **claude.ai** (in your browser or the **Claude mobile
app**) and you can see and drive that exact conversation from anywhere. This is the bridge
from "a conversation locked inside my desktop app" to "my conversation, in the cloud, on any
device."

Remote Control is a **toggle**, so this endpoint detects the current state first: re-calling it
on an already-on conversation just returns the existing URL (it won't switch it off), and
`{enable:false}` turns it off. Each conversation's state shows up as `rc_active` in
`/claude/conversations`.

## How HD knows which on-disk log is which conversation

Claude stores each conversation as `~/.claude/projects/<project>/<uuid>.jsonl` (with its
`sessionId`, generated title, and every message). The conversation's webview doesn't expose
that GUID, so HD matches a live conversation to its log by the **first user message** — exact
and unique — then fills in the `session_id` and the authoritative title for you. So you never
have to hunt through log files by hand; `GET /claude/conversations` gives you the id directly.

Read a full transcript anytime:
```bash
cat ~/.claude/projects/*/<session_id>.jsonl
```

## For the AI in your workspace

Your in-workspace AI can do all of the above. The bundled **`hd-claude-management`** skill
documents every endpoint with examples, so you can ask things like *"open three conversations
and ask each a different question"* or *"turn on remote control for this conversation and give
me the link for my phone."*

## Endpoint reference

| Endpoint | Method | What it does |
|---|---|---|
| `/claude/conversations` | GET | Full per-conversation data incl. `session_id` |
| `/claude/contexts` | GET | Light list: `context_id` + `compose_text` |
| `/claude/tabs` | GET | Raw editor tabs |
| `/claude/new-conversation` | POST | Open a new conversation tab |
| `/claude/tabs/close-all` | POST | Close all tabs + remove the empty panel |
| `/claude/tabs/activate` | POST | Switch visible tab by `{index}` or `{label}` |
| `/claude/tabs/close-empty-groups` | POST | Remove empty editor groups (keeps populated) |
| `/claude/inject` | POST | Type into `{context_index}` (`typed`,`submit`,`delay_ms`) |
| `/claude/remote-control` | POST | Turn on RC → returns the `claude.ai` cloud URL |
