bootstrap
Hydrogen Desktop Bootstrap (apps + skills)
Public Made by Adomby adom
Layer Hydrogen Desktop's workspace onto a standard Adom workstation.
name: hd-editor-state description: The Editor State Machine (ESM) — HOW to know the true state of the VS Code editor and the Claude Code conversations inside Hydrogen Desktop, and the HARD typing invariants. Use BEFORE typing into a Claude conversation, driving setup-step threads, diagnosing "state unknown", empty split panels, tab spam, prompts landing in the wrong conversation, or any Claude tab/webview confusion. Trigger words — editor state, /editor/state, claude tab state, conversation state, which tab is active, empty editor group, split panel, double-type, typed into two boxes, prompt in wrong conversation, census, safe to type, stray text, disk verified, msg_count wrong, workbench unknown.
hd-editor-state — the Editor State Machine
ONE authoritative read: GET /editor/state on HD's control API. Everything below is what it
returns and the rules for acting on it. Full design: docs/EDITOR-STATE-MACHINE.md (hd repo).
The layered truth (never blend layers)
| Layer | Question | Source | Trust |
|---|---|---|---|
L0 lifecycle |
starting / editor-up / ready | port probes (7380, :8821, CDP) | absolute |
L1 layout+conversations |
groups, widths, empty panels, tab census, focused tab | workbench DOM + tab bar | high (VS Code chrome is stable) |
L2 extension |
what commands can I invoke | the extension's contributed-command registry + fingerprint | absolute (it IS the API) |
L3 conversations_disk |
turns, first prompt, generating, delivered | the jsonl transcripts | absolute — works for DISPOSED background tabs |
L4 census |
compose boxes + submit buttons visible NOW | DOM probes across ALL contexts | only under the invariants below |
The HARD invariants (John 2026-07-17 — non-negotiable)
- Never type unless
census.safe_to_type == true(exactly 1 visible input across ALL webview contexts — not just the focused one). - Freshness oracle is the TITLE:
title == 'Untitled'= never submitted. NEVER usemsg_countfor freshness — it counts welcome-screen DOM nodes (reads 5 on a pristine tab). - After a submit, run the stray-text audit:
POST /editor/audit-prompt {prefix}must returncontexts_containing: 0. 1+ = the prompt is ALSO sitting in another conversation's box (double-type) — clear it, fail loudly, never ignore. - Delivery is proven on DISK, not in the DOM: the prompt must be the first user turn of
exactly ONE
~/.claude/projects/*/*.jsonl. 0 = not delivered; 2+ = double-send. - Background tabs are unreadable (VS Code disposes their webviews):
loaded:false, null ctx/compose. To read one, activate it first (/claude/tabs/activate {index:<ordinal>}— by ORDINAL, never by label: every Claude tab is labeled 'Claude Code'). normalize_needed: true→POST /editor/normalizebefore showing the user anything (an empty split group steals 50% of their editor; populated 2-group layouts are preserved).- Prefer registered commands over DOM clicks:
extension.commandslists them (claude-vscode.newConversation, .focus, .editor.open, ...). Run via the in-distro:8821/commandAPI. Commands survive extension updates; selectors don't. - Extension drift:
extension.fingerprintchanges when Claude Code updates — re-verify your assumptions (anchors, commands) before trusting flows after a fingerprint change.
Quick recipes
- Am I safe to type?
GET /editor/state→census.safe_to_type. - Did my prompt double-type?
POST /editor/audit-prompt {"prefix":"<first words>"}→ want 0 after submit. - Which conversation is generating?
conversations_disk[*].generating(disk truth, any tab). - Fix a half-width Claude tab / dead empty panel?
POST /editor/normalize. - Bars:
layout.barsreports activity / primary sidebar / secondary (auxiliary) bar / bottom panel visibility. A Claude conversation living in the SECONDARY bar is a second compose box (census=2). Close bars deterministically:POST /editor/bars {"primary":"close","secondary":"close"}(read -> toggle-on-mismatch -> verify; never a blind toggle).
---
name: hd-editor-state
description: The Editor State Machine (ESM) — HOW to know the true state of the VS Code editor and the Claude Code conversations inside Hydrogen Desktop, and the HARD typing invariants. Use BEFORE typing into a Claude conversation, driving setup-step threads, diagnosing "state unknown", empty split panels, tab spam, prompts landing in the wrong conversation, or any Claude tab/webview confusion. Trigger words — editor state, /editor/state, claude tab state, conversation state, which tab is active, empty editor group, split panel, double-type, typed into two boxes, prompt in wrong conversation, census, safe to type, stray text, disk verified, msg_count wrong, workbench unknown.
---
# hd-editor-state — the Editor State Machine
ONE authoritative read: `GET /editor/state` on HD's control API. Everything below is what it
returns and the rules for acting on it. Full design: docs/EDITOR-STATE-MACHINE.md (hd repo).
## The layered truth (never blend layers)
| Layer | Question | Source | Trust |
|---|---|---|---|
| L0 `lifecycle` | starting / editor-up / ready | port probes (7380, :8821, CDP) | absolute |
| L1 `layout`+`conversations` | groups, widths, empty panels, tab census, focused tab | workbench DOM + tab bar | high (VS Code chrome is stable) |
| L2 `extension` | what commands can I invoke | the extension's contributed-command registry + fingerprint | absolute (it IS the API) |
| L3 `conversations_disk` | turns, first prompt, generating, delivered | the jsonl transcripts | absolute — works for DISPOSED background tabs |
| L4 `census` | compose boxes + submit buttons visible NOW | DOM probes across ALL contexts | only under the invariants below |
## The HARD invariants (John 2026-07-17 — non-negotiable)
1. **Never type unless `census.safe_to_type == true`** (exactly 1 visible input across ALL
webview contexts — not just the focused one).
2. **Freshness oracle is the TITLE**: `title == 'Untitled'` = never submitted. NEVER use
`msg_count` for freshness — it counts welcome-screen DOM nodes (reads 5 on a pristine tab).
3. **After a submit, run the stray-text audit**: `POST /editor/audit-prompt {prefix}` must
return `contexts_containing: 0`. 1+ = the prompt is ALSO sitting in another conversation's
box (double-type) — clear it, fail loudly, never ignore.
4. **Delivery is proven on DISK, not in the DOM**: the prompt must be the first user turn of
exactly ONE `~/.claude/projects/*/*.jsonl`. 0 = not delivered; 2+ = double-send.
5. **Background tabs are unreadable** (VS Code disposes their webviews): `loaded:false`,
null ctx/compose. To read one, activate it first (`/claude/tabs/activate {index:<ordinal>}`
— by ORDINAL, never by label: every Claude tab is labeled 'Claude Code').
6. **`normalize_needed: true` → `POST /editor/normalize`** before showing the user anything
(an empty split group steals 50% of their editor; populated 2-group layouts are preserved).
7. **Prefer registered commands over DOM clicks**: `extension.commands` lists them
(claude-vscode.newConversation, .focus, .editor.open, ...). Run via the in-distro
`:8821/command` API. Commands survive extension updates; selectors don't.
8. **Extension drift**: `extension.fingerprint` changes when Claude Code updates — re-verify
your assumptions (anchors, commands) before trusting flows after a fingerprint change.
## Quick recipes
- Am I safe to type? `GET /editor/state` → `census.safe_to_type`.
- Did my prompt double-type? `POST /editor/audit-prompt {"prefix":"<first words>"}` → want 0 after submit.
- Which conversation is generating? `conversations_disk[*].generating` (disk truth, any tab).
- Fix a half-width Claude tab / dead empty panel? `POST /editor/normalize`.
- Bars: `layout.bars` reports activity / primary sidebar / secondary (auxiliary) bar / bottom
panel visibility. A Claude conversation living in the SECONDARY bar is a second compose box
(census=2). Close bars deterministically: `POST /editor/bars {"primary":"close","secondary":"close"}`
(read -> toggle-on-mismatch -> verify; never a blind toggle).