Skip to content

Map: v1.0 is a bridge over every Session the user starts #67

Closed
24 of 24 issues completed
Closed

Description

@Simon-AI-coding

Destination

v1.0 is a bridge: through the user's own claude / codex commands it covers every main Session the user starts on this Mac under his main account — the default config directory (~/.claude, Codex's default); the second config directory this machine runs, ~/.claude-b, is out of scope (Simon, 2026-08-26) — and lets the user — from the Live Call, the Companion Channel (Telegram) and the menu-bar Control Panel — know each Session's state and progress, Relay words into it, and be called when it stops needing a decision or an approval. Launching and closing Sessions are not on this map. Reached when the real-environment automated acceptance (docs/acceptance-design.md, reshaped for this journey) runs green on Simon's machine against the installed bundle. Like #58 and #49, this map carries execution.

Reached 2026-08-30. The exit ran green — v1.0 exit: real-environment acceptance run of record at 093c7be (a-account environment), run 20260829T233015Z, 19/19 PASS on the installed bundle — and Simon declared the exit the same day. No ticket remains open on this map, and Not yet specified is empty, so nothing graduates: the way to the destination is walked, not merely clear.

Supersedes Map: v1.0 launch with legacy as the behaviour spec, whose destination (repair the launch-centred v1.0 to legacy parity) was redrawn on 2026-08-25 after Simon cut scope.

Notes

Why this map exists (2026-08-25, Simon's call, grilled in the session that closed #58). Simon reduced v1.0 to its core: the bridge over all of his running Sessions — voice-launched or hand-launched, he does not distinguish — with launch/close set aside for a later map ("打磨开/关 Session 的交互"). Fact found on the way: Survey the open-source Claude Code / Codex session monitors: how do they discover running Sessions, and can one be our base or our discovery route? changed the initial upstream premise. Claude Code 2.1.241 now offers launch-independent live enumeration through claude agents --json; Codex 0.149.1 offers two-way control for threads owned by its shared app-server. Neither offers universal control of every already-running, unprepared Session. Legacy's command takeover remains a fallback to prototype for unresolved Claude foreground control and pre-existing Codex Embedded Sessions, not the assumed architecture.

Superseding fact (2026-08-25, #70 follow-up, verified against the official docs): the take-over is not needed on the Claude lane either. Claude reach is the Session's built-in inbox socket (Claude Code ≥ 2.1.224, on by default; idle → new turn, busy → queued) plus a user-scope PermissionRequest hook, both hot-applied to already-running Sessions; the Engine learns each Session's socket from a user-scope SessionStart hook (CLAUDE_CODE_MESSAGING_SOCKET/_TOKEN are exported before it runs) — legacy's hook-client registration model without its wrapper. Codex reach is the shared daemon. The bridge owns no transport of its own; #71 proved the combined route end to end on 2.1.245, so ADR 0006 and ADR 0007 are superseded — 0007 by ADR 0011. Every caveat that ticket carried is answered on it: peer-message authority is why the approval half has to exist at all, bypass-mode holding and the undocumented wire frame are met by honest receipts and no version pin, and the install boundary is ADR 0011.

Proven on the way (2026-08-25, Prototype the Claude lane, live on Claude Code 2.1.245). Relay into a hand-started bare claude works with no wrapper, no plugin and no channel — the bridge's central claim holds. Three facts from that run bind the rest of this map. (1) Coverage is per CLAUDE_CONFIG_DIR. This machine runs ~/.claude and ~/.claude-b; they are disjoint universes — neither lists the other's Sessions and neither can authenticate to the other. The fact stands; the inference it first carried does not. Simon scoped v1.0 to the main account on 2026-08-26, so "every Session the user starts" means every Session in the default config directory, one universe, and the acceptance carries no multi-directory case. What the fact still binds: discovery and installation are both scoped to that one directory by construction, and a Session started under any other CLAUDE_CONFIG_DIR is simply not a Session v1.0 covers. (2) Delivery is never inferred from a socket write. DELIVERED has exactly two honest sources: the held → delivered receipt, and the target's transcript entry whose origin.from is our own socket address. Held messages also expire after five minutes by default, which the receipt seam must report rather than imply delivery. (3) The approval half has no socket route at all, so ADR 0006/0007 are superseded for Relay only. Simon's call, same day: build on the socket route knowingly, on undocumented surface, with no version pin — when upstream breaks it, fix it then; the safeguard is honest receipts, not a pin.

Proven on the way (2026-08-25, the approval half of #71, live on 2.1.245). A permission dialog in a bare, hand-started claude was routed to an external engine and answered by it, with no wrapper, no --plugin-dir and no channel — so the bridge's second claim holds too. Three facts bind the rest of this map. (1) The install mechanism is a fingerprinted block in <config dir>/settings.json, not a plugin (ADR 0011, superseding ADR 0007). A plugin is cold: installed while a Session runs it never reaches that Session, only ones started later. The settings block is hot in both directions on a running Session, and an install that asks the user to restart every open terminal is not a bridge over the Sessions they already started. Both mechanisms uninstall byte-for-byte clean; legacy's merge (legacy@1d32845:bridge/hookconfig.py:68-125) is what keeps every foreign hook, proven against the two already in that file. (2) The registration hook earns its place on one field. SessionStart carries transcript_path, which Claude Code's own registry does not and which cannot be derived without guessing; it is one of the two honest sources of DELIVERED. (3) Scope stops being structural. A user-scope hook fires for every Session in its config directory, so ADR 0007's "no phantom events" guarantee is now two soft lines — the hook prints nothing when no engine holds that Session, and the engine refuses what it does not hold. Cost to a Session the bridge does not hold: ~33 ms, no socket, no writes. Untested and a real exposure in ~/.claude: concurrent writers of settings.json.

What the product is made of — three layers, each with a proven source:

  1. Session-side brain — registration of Sessions, reading what a Session stopped on (question / permission / tool summary / progress) from its transcript or rollout, delivery with a receipt, naming, the child-process rule, Duty bookkeeping. Source: legacy (bridge/hook.py, hookconfig.py, transcript.py, claude.py, codex.py, labels.py, parts of daemon.py). Simon: the effect is what he wants; the code is not.
  2. User-side surfaces — realtime Live Call, Telegram, menu-bar Control Panel, bridgectl control plane, switches. Source: v1.0, proven by the Build the real-environment acceptance harness before any further repair #60 acceptance run.
  3. Skeleton — seams, Bridge Core as the one decision-maker, adapter layering, no tmux binding, no big files. Source: v1.0 (ADR 0001) — the three things Simon rewrote for. Not up for revision.

Standing rules for this map:

  1. Legacy is the behaviour spec (ADR 0010, CLAUDE.md) — unchanged. Every brief cites file:line.
  2. "Port" means: understand the legacy code, then rebuild it inside the skeleton in the simplest form that keeps the effect, optimising what is found on the way (Simon, 2026-08-25). Never a verbatim copy; never a fresh invention where legacy already proved the behaviour. Legacy's durable ledgers (store.py), the ChatGPT-app driver (host.py), tmux launching (terminal.py) and its 33k-line test file are the parts to leave behind.
  3. The code-level port table comes before any build ticket. Parity audit: legacy as the behaviour spec — the gap table that scopes the repair #61 was a behaviour-level parity audit under the old "Session = what we launched" definition; this map's audit maps each wanted behaviour's legacy implementation to its landing point in the skeleton with port / adapt / simplify. Build tickets graduate from that table.
  4. The real-environment acceptance is the exit — green on Simon's machine, reshaped so the harness starts Sessions through the ordinary installed claude / codex path in a pty, not through bridgectl launch.
  5. The gen-1 remnants stay on disk until the port table and its tickets are done (carried from Map: v1.0 launch with legacy as the behaviour spec #58; ticket Dispose of the gen-1 bridge remnants #54 moves under this map).
  6. The published tree carries only what a user needs (carried from Map: v1.0 launch with legacy as the behaviour spec #58): process documents are local-only, decisions live on tickets.
  7. Launch/close code is parked, not deleted, and the parking ticket records where it returns: a voice launch runs the same installed command path a hand launch does, so both walk one path.

Decisions from the grilling that are settled, not re-derived here: v1.0 is for GitHub power users, one-command install and configure (Q1); voice and text loops both required, text first as the subset (Q2); every main Session regardless of launcher, child processes (crews, reviewers) visible in the roster but never conversed with and their stops never announced (Q3, Q13); menu-bar roster is view-only in v1.0 (Q12); both lanes equal (Q6); exit is acceptance green, no usage period (Q15); notice semantics, progress content and naming follow legacy — the port table decides their shape (Q10, Q11, Q14); Simon's budget: whatever it takes (Q7).

Inherited, still binding: ADR 0001–0008, 0010; the Telegram-token decision (#53 → #55); #41's RETIRE of the Notice Relay; merged repairs on main. ADR 0009 (a launch carries its Opening Instruction) is superseded by ticket "Redraw the domain". Open bug tickets #38, #39, #47, #55 are re-scoped by the port table; #39's launch half is parked with the launcher.

Tests/lint only via the project venv: .venv/bin/python -m pytest -q, .venv/bin/ruff check src tests. Skills: mattpocock-skills:grilling + mattpocock-skills:domain-modeling for grilling tickets; mattpocock-skills:research for research tickets; mattpocock-skills:diagnosing-bugs for disputed reproductions. Simon's standing rules (global CLAUDE.md) override everyone. Report to Simon in Chinese; artifacts in English.

Decisions so far

Not yet specified

Out of scope

Activity

  1. 28 remaining items

  2. Simon-AI-coding commented on Aug 28, 2026

    @Simon-AI-coding
    OwnerAuthor

    Exit attempt 1 (advisor, 2026-08-28): #135 run 20260828T074856Z at 197b1d8 — claude lane 9/9 + realtime probe green; codex lane refused at engine start. Cause measured: the engine's own codex app-server socket is born 0755 under the inherited umask and chmodded to 0600 by codex a moment later; the engine verifies at first sight and _spawn sets no umask — the bind→chmod window #116 closed for our own listeners, still open for the one we do not bind. Filed #136 (ready-for-agent, umask=0o077 on the spawn, guard unchanged; legacy had neither umask nor guard — new, not ported). #135 re-runs in full after #136 lands. Wording defect recorded, not scheduled: the codex degradation line "a Session started by this CLI will not join that daemon" appeared on the green run of record too, and #105 measured the opposite. Also being investigated: the installed app on Simon's machine currently runs no engine (shell up, engine log last written 2026-08-24).

  3. Simon-AI-coding commented on Aug 28, 2026

    @Simon-AI-coding
    OwnerAuthor

    Found on the way (advisor, 2026-08-28): the installed product on Simon's machine has not run an engine since 2026-08-24. Two causes, in order, both measured: (1) engine/config.toml still carried [adapters.settings.session_launcher], which #72 (1a62bcc) removed from the schema — the engine refused it at every launch, the shell burned its five attempts in 18 s and showed a bare red "stopped" (removed by hand today, backup beside the file); (2) with that gone, the engine refuses on $GPTVOICECODING_TELEGRAM_TOKEN absent from its environment — #55's defect verbatim: the token lived in launchctl setenv, which a reboot cleared, and re-setting it there no longer reaches an app launched through LaunchServices (variable set, absent from the shell's environment). Simon's calls today: #55 into v1.0 (Routing added, ready-for-agent); #137 filed and into v1.0 — the panel shows the engine's own refusal sentence instead of a failure count, legacy's fail-loud (terminal.py:893-915) ported, plus the config-migration line #72 never wrote. Two facts recorded, not scheduled: installation status run from a dev venv reports claude-hooks: stale because the render embeds sys.executable — the bundle's own interpreter reports current; and the seven channel.mjs processes on the machine are the hands-free-channel plugin's per-session children, not gen-1 remnants. Chain to exit: #136 → #137 → #55 → #135 full re-run.

  4. Simon-AI-coding commented on Aug 30, 2026

    @Simon-AI-coding
    OwnerAuthor

    Exit declared — 2026-08-30, Simon. The map's destination is reached.

    The destination was one sentence with one test in it: v1.0 is a bridge over every main Session the user starts under his main account, reached when the real-environment automated acceptance runs green on Simon's machine against the installed bundle. On 2026-08-30 it did — v1.0 exit: real-environment acceptance run of record at 093c7be (a-account environment), run 20260829T233015Z, 19/19 PASS, both lanes 9/9 plus the 0b realtime probe, against /Applications/GPT-VoiceCoding.app certified byte-identical to 093c7be, git status clean before and after, nothing arranged by hand to make a step pass.

    What the map turned out to be about. It opened on a premise that did not survive contact: legacy's command takeover as the assumed architecture. Survey the open-source Claude Code / Codex session monitors and then Prototype the Claude lane replaced it: the bridge owns no transport of its own, reaches a hand-started bare claude with no wrapper, no plugin and no channel, and installs as a hot fingerprinted block in settings.json rather than a cold plugin — ADR 0011, superseding 0006/0007 — because a bridge that asks the user to restart every open terminal is not a bridge over the Sessions they already started. That single fact is why the product exists in the shape it does.

    Two scoping acts closed the frontier rather than advancing it: ~/.claude-b ruled out on 2026-08-26 (coverage is per config directory, so scoping to one directory scopes to one whole universe — a clean cut, not a gap), and launch/close parked at parked/launch-close as reference material, not a resumption point.

    Three fog patches were answered by measurement in the exit run itself, not by a decision — all three indexed in Decisions so far and detailed on #143: 0b is green where 2026-08-26 re-confirmed it dead (an upstream-side change; nothing in 093c7be touches it); a Codex approval can be raised in a trusted workspace, measured out of codex's own turn_context; and a Claude subagent is visible from outside, listed under its parent and refused for Relay as a Child Process.

    Three were not, and they are recorded as out of scope rather than as debt on a closed map — Live Call auto-end on long silence, the Control Panel roster's Swift rendering, and whether #38/#47 close on verification alone. The acceptance ran green without all three, and that is precisely what puts them past this destination. They do not graduate; the frontier stops at the destination. #38 and #47 stay open on the tracker as ordinary bugs.

    Not yet specified is now empty and every child ticket is closed. Closing the map. The next map is the parked one: launching and closing Sessions, and the interaction polish around them — a fresh effort, not a resumption of this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions