Workspace ManagerconceptInternals

Choose documentation 3

latest

Current version

latest
English

Early release libtmux is released, and its APIs may still change between releases. This site's structure and URLs may change too.

Edit this page on GitHub

Go workspace builder examples

github.com/libtmux/libtmux-go/workspace · Source

Read a workspace file, create two windows and three panes, then stop the private tmux server. The /bin/cat commands keep panes open without another application or log file.

Prepare the project

Use Go 1.26 and tmux 3.3a or newer on Unix. Create an empty project:

Terminal window
$ mkdir go-workspace-example && cd go-workspace-example

Create the module file. It requires the published core and workspace modules at v0.1.0; the indirect YAML dependency is what go mod tidy resolves:

go.mod
module example.com/workspace
go 1.26.0
require (
github.com/libtmux/libtmux-go v0.1.0
github.com/libtmux/libtmux-go/workspace v0.1.0
)
require go.yaml.in/yaml/v3 v3.0.5 // indirect

Create the workspace file in the same directory:

workspace.yaml
session_name: workspace-example
windows:
- window_name: editor
layout: even-horizontal
panes: [/bin/cat, /bin/cat]
- window_name: logs
panes: [/bin/cat]

Build a session

Create the complete program below. It reads and validates the YAML before creating a private socket directory. Parse rejects unknown configuration fields; a misspelled key fails before the example starts tmux.

main.go
package main
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/libtmux/libtmux-go/tmux"
"github.com/libtmux/libtmux-go/workspace"
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() (err error) {
document, err := os.ReadFile("workspace.yaml")
if err != nil {
return err
}
described, err := workspace.Parse(document)
if err != nil {
return err
}
directory, err := os.MkdirTemp("/tmp", "libtmux-go-workspace-")
if err != nil {
return err
}
config := filepath.Join(directory, "tmux.conf")
if err = os.WriteFile(config, []byte("set -g default-shell /bin/sh\n"+
"set-environment -g ENV /dev/null\n"+
"set-environment -g BASH_ENV /dev/null\n"), 0600); err != nil {
return errors.Join(err, os.RemoveAll(directory))
}
socket := filepath.Join(directory, "s")
server, err := tmux.NewServer(tmux.ServerOptions{
SocketPath: socket,
ConfigFile: config,
})
if err != nil {
return errors.Join(err, os.RemoveAll(directory))
}
defer func() {
cleanup, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if cleanupErr := server.Kill(cleanup); cleanupErr != nil {
err = errors.Join(err, fmt.Errorf("stop private server at %s: %w", socket, cleanupErr))
return
}
err = errors.Join(err, os.RemoveAll(directory))
}()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
session, err := workspace.Build(ctx, server, described)
if err != nil {
return fmt.Errorf("build workspace: %w", err)
}
windows, err := session.SearchWindows(ctx, nil)
if err != nil {
return err
}
panes, err := server.Panes(ctx)
if err != nil {
return err
}
if len(windows) != 2 || len(panes) != 3 {
return fmt.Errorf("expected two windows and three panes, got %d and %d", len(windows), len(panes))
}
fmt.Printf("built: %d windows\npanes: %d\n", len(windows), len(panes))
return nil
}

Build opens a control connection for construction, closes it, and returns a session handle that can be used for later operations. Pane commands may still be running when the build returns. Check the application itself for readiness.

For an application that already owns a connection, use Workspace.InitialSessionRequest to create the initial session, then pass it to BuildInto. That function populates the supplied session and leaves connection ownership with the caller.

Verification

Resolve dependencies and run the program from the project directory:

Terminal window
$ go mod tidy
Terminal window
$ go run .

Expected output:

built: 2 windows
panes: 3

A failed build can leave part of the workspace in tmux. Cleanup is registered before Build and uses its own five-second deadline, so an expired build context does not skip server shutdown. If stopping tmux fails, the program keeps the socket directory and reports the cleanup error alongside any build error.

For a workspace that stays open, let your application retain its explicitly selected server and choose when to stop it.

Builder source; configuration source.

Esc

Type to search.

Reference previewOpen reference