GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Experimental: pure-chain ChainWorkspaceBuilder + `--builder=chain` by tony · Pull Request #1054 · tmux-python/tmuxp

Conversation

@tony

@tony tony commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

  • Add a ChainWorkspaceBuilder that constructs a workspace's entire session → window → pane tree from a single libtmux._experimental.chain.ForwardPlan, resolved over the minimum number of tmux invocations instead of one subprocess per new-window / split-window.
  • Add an opt-in --builder=chain flag to tmuxp load (Env: TMUXP_BUILDER); the default builder is unchanged.
  • Experimental: depends on libtmux's _experimental.chain API, pinned to a sibling worktree via [tool.uv.sources]. Not for merge — companion to the libtmux experiment.

Changes by area

src/tmuxp/workspace/chain_builder.py (new)

ChainWorkspaceBuilder, a subclass of WorkspaceBuilder, overriding build(): the session is created, then every window and pane is described in one ForwardPlan seeded from the session and resolved via ServerPlanRunner. Reuses the parent's helpers (_wait_for_pane_ready, config_after_window, focus handling, plugin hooks, before_script, session options).

src/tmuxp/cli/load.py

Adds --builder={default,chain} (Env TMUXP_BUILDER), threaded through command_load → load_workspace as builder_name, selecting the builder class. The rest of the load path is unchanged because the subclass mirrors the constructor, .session, and event hooks.

pyproject.toml

[tool.uv.sources] pins libtmux to the sibling ../libtmux worktree so the experimental chain API is importable.

Design decisions

  • Reuse the default window, don't orphan it. Seeding with ForwardPlan.from_session(session) and addressing window 1 through seed.initial_window / seed.initial_pane builds onto the session's default window instead of moving it aside and killing it (the move-to-99 + kill dance the classic builder performs).
  • send_keys_mode, default readiness. The chain batches split + send-keys without waiting for the new pane's shell prompt. readiness builds only the structure via the chain, then sends each pane's commands shell-ready (matching the classic builder, deterministic). batched folds send-keys into the plan for the fullest "all at once" — faster, but it can race an interactive prompt.
  • Sync, not async. tmuxp has no async today and a workspace build is causally serial (windows depend on the session; decorations depend on captured ids), so the chain's synchronous path (ServerPlanRunner / run_resolving) is the right fit.
  • Subclass, not fork. Extending WorkspaceBuilder keeps .session, find_current_attached_session, the on_* event hooks, and the plugin lifecycle identical, so load.py needs only to pick the class.

Test plan

  • Lint + format clean on the new builder, tests, and the CLI change
  • Type-check (mypy) clean
  • tests/workspace/test_chain_builder.py — two/three-pane structure, window + pane focus, readiness-mode commands landing, batched mode, and --builder flag parsing
  • Existing tests/workspace/test_builder.py and tests/cli/test_load.py still pass (the subclass leaves the default builder untouched)
  • Smoke: tmuxp load -d --builder=chain tests/fixtures/workspace/builder/two_pane.yaml builds editor (2 panes), logging, test, matching the default builder

Companion PR

Depends on the libtmux experimental chain API: tmux-python/libtmux#685.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
This was referenced Jun 27, 2026
Workspace builder roadmap: classic default, pluggable builders, readiness policy, and parallel loading #1058
Open
WorkspaceBuilder: define a public builder protocol and entry points #1060
Closed
WorkspaceBuilder: add an opt-in parallel builder #1062
Open
Docs: document custom workspace builders #1063
Closed
Experimental chain workspace builder (scaffold) #1068
Open
tony added a commit that referenced this pull request Jul 4, 2026
@tony
Builder(feat[chain]): scaffold chain builder
ac57cb0
why: Land the experimental ChainWorkspaceBuilder from #1054 on the new
builder package. It builds the window/pane tree via libtmux's chain API
(libtmux#685), which is unreleased and absent from published libtmux, so
the scaffold must import cleanly and fail with an actionable error rather
than crash on import.

what:
- Add src/tmuxp/workspace/builder/chain.py: ChainWorkspaceBuilder
  subclasses ClassicWorkspaceBuilder; guard the experimental import
  behind _HAVE_CHAIN so the module imports without the API
- build() raises exc.WorkspaceBuilderImportError when the chain API is
  absent; when present, port #1054's single-ForwardPlan build
- Register the `chain` entry point in tmuxp.workspace_builders
- Export ChainWorkspaceBuilder from the builder package
- Add tests: test_builder_chain.py importorskips the chain API; the new
  test_builder_chain_unavailable.py asserts selecting `chain` without the
  API resolves the class yet raises on build()
@tony
tony force-pushed the chainable-commands-experiment-00 branch from 0f297eb to 5b82f53 Compare July 4, 2026 14:20
@tony
tony force-pushed the master branch from 63172d2 to eeb6912 Compare July 25, 2026 17:00
tony added 3 commits October 24, 2026 04:48
@tony
py(deps[libtmux]) Pin to sibling chainable-commands worktree
675fbcd
why: Build the experimental ChainWorkspaceBuilder against the in-progress
libtmux._experimental.chain API on the sibling libtmux worktree.
what:
- Add [tool.uv.sources] libtmux = { path = "../libtmux", editable = true }
- Relock against the local editable checkout
@tony
workspace(feat[chain]): add ChainWorkspaceBuilder
55e6315
why: Showcase libtmux's experimental chain API downstream: build a whole
workspace's window/pane tree in the minimum tmux invocations instead of
one subprocess per new-window / split-window.

what:
- Add ChainWorkspaceBuilder (subclass of WorkspaceBuilder): one
  ForwardPlan seeded from the session builds every window and pane,
  reusing the session's default window as window 1 (no orphan) via
  initial_window / initial_pane
- send_keys_mode: readiness (default, classic per-pane shell-ready
  delivery) or batched (folded into the plan)
- Reuse parent helpers (_wait_for_pane_ready, config_after_window, focus,
  plugins, before_script, options)
- Tests: two/three-pane structure, focus, readiness commands land, batched
@tony
cli(load[builder]): --builder=chain flag
c3d3d6b
why: Make the experimental ChainWorkspaceBuilder selectable from the CLI
without replacing the default builder.

what:
- Add --builder={default,chain} to `tmuxp load` (Env: TMUXP_BUILDER),
  threaded through command_load -> load_workspace as builder_name
- Select ChainWorkspaceBuilder when chosen; default builder otherwise
- Test the flag parsing (smoke-verified `tmuxp load --builder=chain`
  builds the expected window/pane tree)
tony added a commit that referenced this pull request Oct 24, 2026
@tony
Builder(feat[chain]): scaffold chain builder
33c1228
why: Land the experimental ChainWorkspaceBuilder from #1054 on the new
builder package. It builds the window/pane tree via libtmux's chain API
(libtmux#685), which is unreleased and absent from published libtmux, so
the scaffold must import cleanly and fail with an actionable error rather
than crash on import.

what:
- Add src/tmuxp/workspace/builder/chain.py: ChainWorkspaceBuilder
  subclasses ClassicWorkspaceBuilder; guard the experimental import
  behind _HAVE_CHAIN so the module imports without the API
- build() raises exc.WorkspaceBuilderImportError when the chain API is
  absent; when present, port #1054's single-ForwardPlan build
- Register the `chain` entry point in tmuxp.workspace_builders
- Export ChainWorkspaceBuilder from the builder package
- Add tests: test_builder_chain.py importorskips the chain API; the new
  test_builder_chain_unavailable.py asserts selecting `chain` without the
  API resolves the class yet raises on build()
@tony
tony force-pushed the chainable-commands-experiment-00 branch from 5b82f53 to c3d3d6b Compare October 24, 2026 09:58

This branch has not been deployed

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

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@tony
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.