Skip to content

Continue in Claude: one-click web→MCP part handoff - #315

Merged
ecto merged 7 commits into
mainfrom
claude/vigorous-driscoll-13c71c
Jun 23, 2026
Merged

ecto merged 7 commits into
mainfrom
claude/vigorous-driscoll-13c71c

Conversation

@ecto

@ecto ecto commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Continue in Claude

A signed-in user looking at their part on vcad.io clicks File → Continue in Claude… and lands in Claude (or ChatGPT, or their editor) with their exact geometry already loaded and being edited — no blank slate, no copy-paste. The install is plumbing; the part teleports.

The geometry never rides the URL: the link carries a short share token, and a new continue_document MCP tool resolves it server-side and materializes the geometry.

What's in here (7 commits)

V1 — the core

  • continue_document MCP tool: resolves a share token via the get_shared_document RPC, materializes raw CRDT content through the kernel engine (WasmDocumentEngine.load().get_document_json() — the engine render_view already boots), opens a live session that renders inline + persists to the user's account.
  • continue-links.ts: the verified per-host deep-link matrix — Claude Desktop claude://claude.ai/new?q= (prefill), ChatGPT chatgpt.com/?q=, Cursor/VS Code one-click MCP install, Claude Code one-liner. (claude.ai web ?q= was removed Oct 2025, so it's open-and-copy.)
  • ContinueDialog + File-menu item: mints/reuses a share token (no public profile publish → no username picker), host picker, remembers last host.

V2 — reach + readiness

  • Accountless inline handoff: compresses live IR into the seed (encodeDocForSeed, length-guarded), falling back to a sign-in nudge for large parts.
  • continue_handoff telemetry; continue_document MCP tool annotations for Anthropic Directory readiness.

V3 — alive in both surfaces

  • Idempotent cont_<token> rendezvous key: re-clicks reattach to the same session (Living Viewport accretes in place, edits survive), and it's the durable row key the tab can watch.
  • Live reflection: migration 031 publishes documents to Realtime; the dialog shows a "Live in Claude" pill that pulses as the model edits (owner-RLS scopes it to the user's own row).

Verification

  • MCP: continue_document 11 tests + full suite 306 pass; typecheck clean.
  • App: 13 continue-links tests; whole-app tsc -b clean; app boots with no errors.
  • Migration 031: supabase db push --dry-run OK (not applied — see below).

⚠️ Before merge / deploy

  1. Migration 031 publishes the whole documents table to Supabase Realtime — a deliberate prod fan-out decision. RLS still scopes every event to its owner. Apply with supabase db push when ready.
  2. Manual end-to-end pass (can't be driven headless): from a signed-in vcad.io session, Continue → Claude Desktop, confirm the part loads and the "Live in Claude" pill pulses as you edit. Confirm the exact claude://claude.ai/new?q= scheme.

🤖 Generated with Claude Code

ecto and others added 7 commits June 23, 2026 12:11
… handoff

The server side of the web app's "Continue in Claude" handoff. The browser
mints a public share token for the part the user is looking at and hands it to
the model in the seed prompt; continue_document resolves it server-side via the
get_shared_document RPC and opens it as a live MCP session — the geometry never
rides the URL, only the opaque token does.

Web docs store canonical CRDT state, so the tool materializes content to IR via
the kernel engine's WasmDocumentEngine.load() (the same engine render_view
boots); raw-IR/legacy content passes through. The opened session is a fresh
mcp:-keyed session seeded from the geometry, so it renders inline (UI_META) and
persists to the user's account (SWITCH_DOC_WRITERS) like any MCP-authored doc.

- resolveShareToken() in session-store.ts (service-role get_shared_document RPC)
- continue-doc.ts tool + registration + dispatch case
- unit tests: token parsing, uuid guard, unknown-token hint, IR passthrough

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pure builders for the "Continue in Claude" host matrix. Encodes each host's
real, verified mechanism: claude:// prefill for Claude Desktop, copy-to-paste
for claude.ai web (the ?q= prefill was removed Oct 2025), chatgpt.com/?q= for
ChatGPT, and the one-click MCP install deep links for Cursor (base64 config) and
VS Code (url-encoded JSON, name inline) plus a claude-mcp-add one-liner for
Claude Code. The seed carries only the share token + the continue_document tool
name — never the geometry. 9 unit tests pin every encoder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the user-facing entry point for the handoff. A sign-in-gated "Continue in
Claude…" item in the File menu opens ContinueDialog, which mints (or reuses) a
share token for the current cloud doc — token only, no public /@user/slug
publish, so there's no username picker — and presents the host matrix from
continue-links: open Claude Desktop / ChatGPT with the part prefilled, install +
copy-to-paste for Cursor / VS Code / claude.ai web, and a copyable command for
Claude Code. Remembers the last-used host. The model resolves the token with
continue_document and renders the user's exact part.

Also folds in a noUncheckedIndexedAccess fix in the continue-links encoder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ry hints

- Anon escape hatch: continue_document now accepts an inline `doc` (gzip +
  base64url IR) in addition to a share token, and the dialog compresses the
  live geometry into the seed for users without an account — length-guarded
  (MAX_INLINE_BLOB), falling back to a sign-in nudge for parts too big to ride a
  host URL. The File-menu item is no longer sign-in-gated.
- Telemetry: continue_handoff event (host + token/inline mode) via the app
  analytics pipeline; continue_document tool calls are already captured server-side.
- Directory readiness: continue_document carries MCP tool annotations
  (title, readOnlyHint, openWorldHint).

Tests: inline-doc round-trip (app encoder <-> mcp decoder), oversize guard,
corrupt-blob hint, inline seed shape. app 12 + mcp continue-doc 9, full mcp 302.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ation)

continue_document now keys a token handoff to a deterministic session id
(cont_<token>) instead of a random one, and reuses an already-open or durably
persisted session before re-materializing from the share snapshot. Effects:

- Idempotent: re-clicking "Continue" (or a cold-instance re-open) reattaches to
  the SAME session — the Living Viewport accretes in place and in-progress edits
  survive, matching the shipped accret-on-document_id behavior.
- Rendezvous key: because the id derives from the token the web app minted, the
  vcad.io tab knows the session's durable row (mcp:cont_<token>) in advance —
  the primitive a future live-reflection panel subscribes to. The token is an
  unguessable UUID, so the derived id stays capability-safe.
- Success payload nudges the verify loop (render_view -> verify_part/build_receipt).

Inline (accountless) handoffs keep a fresh random id (no stable key). Tests:
warm-cache reuse (one fetch), durable cold-instance rehydrate. mcp 306 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "alive in both surfaces" beat. After a signed-in token handoff, the dialog
shows a "Live in Claude" pill that pulses as the model edits the part: the
continued session persists to the user's own documents row (mcp:cont_<token>),
and the tab subscribes to Realtime changes on exactly that row.

- migration 031: publish `documents` to supabase_realtime (idempotent, guarded).
  Owner RLS already scopes rows to the user, and Realtime enforces RLS per
  subscriber, so a user only ever receives their OWN document changes.
- continueSessionRowKey(token): the shared mcp:cont_<token> contract between the
  server's keying and the tab's subscription (unit-tested rendezvous).
- useClaudeLiveStatus(token): subscribes/cleans up the channel, counts edits.
- ContinueDialog: the live pill, shown once a token host is launched.

VERIFY: end-to-end (a real Claude session morphing the pill) needs a manual pass
with the migration applied — it can't be driven headless. Pure parts (rowkey)
and types are covered; app tsc -b clean, 13 link tests pass, migration dry-run OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

4 Skipped Deployments
Project Deployment Actions Updated (UTC)
mecheval Ignored Ignored Jun 23, 2026 4:53pm
vcad Ignored Ignored Jun 23, 2026 4:53pm
vcad-docs Ignored Ignored Jun 23, 2026 4:53pm
vcad-mcp Ignored Ignored Jun 23, 2026 4:53pm

Request Review

@ecto
ecto merged commit 803647c into main Jun 23, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant