bootstrap
Adom Hydrogen (Windows / WSL2)
Public Made by Adomby adom
The Windows (WSL2) platform layer for Hydrogen.
master
Colby Knox
Publish 0.3.30
ed6a0ea
name: hydrogen-editor-state description: >- Hydrogen's Editor State Machine: how to know the true state of the VS Code editor and its Claude conversations, and the hard rules before typing into one. Use before typing into a Claude tab, or when a prompt landed in the wrong conversation, a split panel is empty, or the state is unknown.
hydrogen-editor-state — the Editor State Machine
ONE authoritative read: GET /editor/state on Hydrogen'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: hydrogen-editor-state
description: >-
Hydrogen's Editor State Machine: how to know the true state of the VS Code
editor and its Claude conversations, and the hard rules before typing into
one. Use before typing into a Claude tab, or when a prompt landed in the wrong
conversation, a split panel is empty, or the state is unknown.
---
# hydrogen-editor-state — the Editor State Machine
ONE authoritative read: `GET /editor/state` on Hydrogen'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).