libtmux for Perl workspace
# LibTmux-Workspace
LibTmux-Workspace validates, plans, and loads JSON workspaces through public [LibTmux core APIs](https://github.com/libtmux/libtmux-perl/tree/master/packages/core). Describe sessions, windows, pane commands, layout, working directories, and environment; inspect the plan before applying it. [CLI example](#validate-plan-and-load-a-workspace) · [Perl example](#load-and-inspect-from-perl) · [Guide](https://libtmux.org/en/perl/latest/workspace/source-guide/) · [API reference](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace/) ## Install from source Install core first. From the workspace distribution directory: ```console $ cpm install \ --global \ . ``` Requires Perl 5.44, the versioned core distribution, and its Linux x86_64 LP64 and tmux 3.3a–3.8 environment. It adds no non-core runtime dependency and does not require async. This development distribution is not published on CPAN. Read the [source installation guide](https://github.com/libtmux/libtmux-perl/blob/master/docs/installation.md) for interpreter and installer setup. ## Validate, plan, and load a workspace The packaged [examples/workspace.json](examples/workspace.json) creates two windows and three panes. Its commands run Perl directly: ```json { "schema": "libtmux.workspace/v1", "environment": {"PROJECT": "api"}, "sessions": [{ "name": "perl-workspace", "windows": [{ "name": "editor", "layout": "even-horizontal", "panes": [ {"command": ["perl", "-e", "while () { print }"]}, {"command": ["perl", "-e", "while () { print }"], "horizontal": true} ] }, { "name": "logs", "panes": [{"command": ["perl", "-e", "while () { print }" ]}] }] }] } ``` From this distribution directory, validate the file and inspect its plan: ```console $ libtmux-workspace validate examples/workspace.json ``` ```console $ libtmux-workspace plan examples/workspace.json ``` Load it on an explicit socket. An unused path starts a new server: ```console $ libtmux-workspace load examples/workspace.json \ --socket-path "${TMPDIR:-/tmp}/libtmux-perl-workspace-$$.sock" \ --existing skip ``` Validation and planning perform no tmux I/O. Loading leaves the workspace running. Repeating the command with the same socket and `skip` preserves the entire existing session. The default policy reports a conflict; it never silently replaces another session. ## Load and inspect from Perl Run [examples/load.pl](examples/load.pl) to plan, load, inspect the graph, repeat with `skip`, and remove the session it created: ```console $ perl examples/load.pl "${TMPDIR:-/tmp}/libtmux-perl-workspace-$$.sock" ``` ```perl use v5.44; use FindBin; use LibTmux::Server; use LibTmux::Workspace; my $socket = shift @ARGV // die "Usage: $0 SOCKET_PATH [TMUX]\n"; my $tmux = shift @ARGV // 'tmux'; my $server = LibTmux::Server->new( socket_path => $socket, executable => $tmux, config_file => '/dev/null', ); # example: begin plan open my $in, '<:raw', "$FindBin::Bin/workspace.json" or die $!; my $json = do { local $/; <$in> }; close $in or die $!; my $workspace = LibTmux::Workspace->from_json($json); my $plan = $workspace->plan; say 'planned sessions: ', scalar $plan->{sessions}->@*; die 'plan must not mutate' if $plan->{mutates}; # example: end plan my ($session, $failure); try { # example: begin load my $report = $workspace->load(server => $server); my $snapshot = $server->snapshot; $session = $snapshot->sessions->one({name => 'perl-workspace'}); my $windows = $session->window_links; say 'loaded windows: ', $windows->count; my $editor = $windows->one({window => {-is => {name => 'editor'}}})->window; say 'editor panes: ', $editor->panes->count; # example: end load die 'workspace structure differs' unless $windows->count == 2 && $editor->panes->count == 2; # example: begin repeat my $again = $workspace->load(server => $server, existing => 'skip'); say 'skipped existing sessions: ', scalar $again->{skipped}->@*; # example: end repeat die 'repeat did not skip' unless $again->{skipped}->@* == 1; die 'environment was not inherited' unless $server->get_environment(session => $session, name => 'PROJECT') eq 'api'; } catch ($error) { $failure = $error } if ($session) { try { $server->kill_session(session => $session) } catch ($cleanup) { warn "session cleanup failed: $cleanup\n"; $failure //= $cleanup; } } die $failure if defined $failure; say 'workspace plan, load, repeat: ok'; ``` The program reports one planned session, two loaded windows, two editor panes, and one skipped session. It uses installed modules and its adjacent JSON file; it needs no Python or author fixture. ## Handle conflicts and partial effects The [`Workspace`](https://libtmux.org/en/perl/latest/workspace/reference/libtmux-workspace/) library checks all session-name conflicts before creating anything. `skip` preserves whole existing sessions; it does not reconcile their pane count or layout. Working directories and environment inherit through the configured levels, and layout is applied after splitting. A failed load records completed steps, the failed step, dispatch uncertainty, and the original typed cause. Rollback can affect only sessions proven created by that load. `report` preserves typed cleanup failures with target identities; `report_data` makes a detached JSON-safe diagnostic export. The CLI exits with 0 for success, 2 for usage/configuration, 3 for load failure, and 4 for conflict. Pane commands use literal `command` arrays or an explicit `shell_command`. The versioned `libtmux.workspace/v1` format is not tmuxp's schema; tmuxp catalog import is separate work. Read the [workspace guide](https://libtmux.org/en/perl/latest/workspace/source-guide/) and installed `perldoc LibTmux::Workspace` documentation. Each native archive includes this README, its logo assets, and the complete examples.