feat: route teleport through disponent local backend#185
Merged
Conversation
When PM_LOCAL_BACKEND=disponent, teleport now rides disponent's local tmux backend instead of pm's legacy pm-owned worktree code — using the two per-dispatch fields on current disponent main: fetchRemote (#74, fetch gitRef off the clone's origin) and agentCmd (#33, a startup run verbatim with no brief appended). Previously the backend gate excluded teleport (!opts.fetchRemote && !opts.startup), because the disponent local backend couldn't fetch a remote branch or run a bespoke startup. Both capabilities are on disponent main now, so teleport's two needs — fetch the cloud worker's pushed branch, and resume the run via `claude --teleport <id>` — map straight onto them. How: - worktree.ts: loosen the gate to `viaDisponent = localDisponentEnabled()`; thread opts.fetchRemote / opts.startup through startLocalViaDisponent. - local-disponent.ts: LocalProvisionArgs gains fetchRemote? / startup?, mapped onto the dispatch spec's fetchRemote / agentCmd. A plain start-local leaves both unset, so its spec is byte-identical to before. - The teleport session is just another disponent-local session, so the descriptor-driven browser terminal attach from #184 covers its terminal — no extra wiring. Still opt-in behind PM_LOCAL_BACKEND=disponent; the legacy startLocalViaWorktree path and the default are untouched (a later stage flips the default and retires the legacy code). Builds on #184. Part of pm#152. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018L3HzzZcSFo8PmygtQZT3M
zmaril
marked this pull request as ready for review
July 21, 2026 21:03
zmaril
enabled auto-merge
July 21, 2026 21:03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second pm piece of the disponent migration (pm#152). Stacked on #184 (base =
feat/attach-disponent-terminal), so this diff shows only the teleport change. Builds against current disponent main (d77a34e), which has both fields merged: #33agentCmd(per-dispatch verbatim startup, brief-suppressed) and #74fetchRemote(fetchgitRefoff the clone's origin).What & why
When
PM_LOCAL_BACKEND=disponent, teleport now rides disponent's local tmux backend instead of pm's legacy pm-owned worktree code. Until now the backend gate excluded teleport (!opts.fetchRemote && !opts.startup), because the disponent local backend couldn't fetch a remote branch or run a bespoke startup. Both capabilities are on disponent main now, so teleport's two needs — fetch the cloud worker's pushed branch, and resume the run viaclaude --teleport <id>— map straight onto them.Still opt-in; the default
PM_LOCAL_BACKENDand the legacy path are untouched (a later stage flips the default + retires the legacy code — not this PR).Before / After
claude --teleport.origin, cuts the worktree at its pushed tip, and runsclaude --teleport <id>verbatim in its owndsp-<uid>tmux. The browser terminal (the descriptor-driven attach from feat: attach browser terminal to disponent's transport-neutral terminal #184) attaches straight to that session — no pm-owned worktree/PTY.How
worktree.ts— gate loosened toviaDisponent = localDisponentEnabled();startLocalViaDisponentnow takesoptsand threadsopts.fetchRemote/opts.startupthrough.local-disponent.ts—LocalProvisionArgsgainsfetchRemote?/startup?, mapped onto the dispatch spec'sfetchRemote(chore(db): upgrade PGlite 0.2.17 → 0.5.4 #74) /agentCmd(Stop must not un-merge completed tasks on a multi-task session #33). A plain start-local leaves both unset, so its spec is byte-identical to before.resolveDisponentAttach+dsp-<uid>browser attach.Verify
bun run check,bun run typecheck, fullbun test— green, except the one known pre-existingdispatch.test.tsgithub-proxy env failure, unrelated to this diff.tests/local-disponent.test.ts): teleport-shaped opts route through disponent andfetchRemote+startupland on the dispatch spec asfetchRemote/agentCmd/gitRef(spied on the engine'sdispatch); a plain start-local leaves both unset.Rendered proof — honest scope
A true cloud teleport is not reproducible in-container (no real
session_…id, no authedclaude --teleport <id>resume). So the proof uses an honest substitute: a REAL local tmux dispatch driven through the actualstartLocalSessionteleport path, with a bare "origin" repo holding a distinctive commit onpm/task-1-demo(reachable only via fetch) and a marker startup standing in forclaude --teleport <id>.What it proves: the loosened gate routes teleport through disponent;
fetchRemotechecks the worktree out at the fetched remote tip (worktree HEAD6c2e4e4== the pushed commit, distinctive remote file present, not localmain);agentCmdruns the startup verbatim (capture-paneshowsTELEPORT_V2_9f3a); and the browser terminal attaches to thedsp-<uid>session (screenshot: panel shows the marker, tmux status linedsp-019f80:sleep— disponent's session, notpm-session-1).What it does not prove: the real cloud
claude --teleport <id>conversation resume — that needs a live cloud session and is exercised end-to-end only outside the container.DISPONENT_REF stays at
d77a34e(from #184; both fields are on that main).🤖 Generated with Claude Code
https://claude.ai/code/session_018L3HzzZcSFo8PmygtQZT3M
Generated by Claude Code