# Workspace guide

Source: https://libtmux.org/en/julia/latest/workspace/source-guide/

> Workspace guide: LibTmux documentation.

LibTmuxWorkspace reads a documented tmuxp-style YAML/JSON subset. Validation,
expansion and planning are pure. Applying a plan creates tmux resources and
can execute shell input. Keep those stages explicit when reviewing an
untrusted configuration.

From a consumer project directory, add the core and workspace package from the
same public Git tag:

```console
$ julia \
    --startup-file=no \
    -e 'using Pkg; Pkg.activate("."); repo="https://github.com/libtmux/libtmux-julia.git"; tag="v0.1.0-alpha.1"; Pkg.add([Pkg.PackageSpec(url=repo, rev=tag), Pkg.PackageSpec(url=repo, rev=tag, subdir="packages/LibTmuxWorkspace")])'
```

The following executable source example needs a checkout and its own consumer
environment. Clone the same tag, then enter the checkout:

```console
$ git clone \
    --branch v0.1.0-alpha.1 \
    --depth 1 \
    https://github.com/libtmux/libtmux-julia.git
```

```console
$ cd libtmux-julia
```

Create a local environment for the example:

```console
$ julia \
    --startup-file=no \
    -e 'using Pkg; Pkg.activate(".workspace-env"); repo="https://github.com/libtmux/libtmux-julia.git"; tag="v0.1.0-alpha.1"; Pkg.add([Pkg.PackageSpec(url=repo, rev=tag), Pkg.PackageSpec(url=repo, rev=tag, subdir="packages/LibTmuxWorkspace")])'
```

It loads two panes, checks their layout and focus, freezes the supported
reconstruction subset, and closes the private daemon:

```console
$ julia \
    --startup-file=no \
    --project=.workspace-env \
    packages/LibTmuxWorkspace/examples/owned_load.jl
```

The code below is included from that executable program:

```julia title="owned_load.jl"
using LibTmux, LibTmuxWorkspace

function main()
    endpoint = Ref{Server}()
    frozen = with_server(; tmux=get(ENV, "LIBTMUX_TEST_TMUX", "tmux")) do server
        endpoint[] = server
        config = validate(
            Dict(
                "session_name" => "workspace-example",
                "options" => Dict("default-shell" => "/bin/sh"),
                "windows" => [
                    Dict(
                        "window_name" => "editor",
                        "window_index" => 0,
                        "layout" => "even-horizontal",
                        "focus" => true,
                        "panes" => [
                            Dict(
                                "shell_command" => [
                                    Dict("cmd" => "printf ready", "enter" => false),
                                ],
                            ),
                            Dict("focus" => true),
                        ],
                    ),
                ],
            ),
        )
        prepared = plan(expand(config; base_directory=dirname(server.socket_path)))
        result = apply(server, prepared; rollback=:created)
        @assert result.status == :complete
        observed = snapshot(server)
        @assert length(panes(observed)) == 2
        link = only(windowlinks(observed))
        @assert link.index == 0 && link.active
        editor = window(link)
        editor_panes = sort(collect(panes(editor)); by=p -> p.index)
        @assert [p.active for p in editor_panes] == [false, true]
        @assert all(p -> p.height == editor.height, editor_panes)
        @assert sum(p.width for p in editor_panes) + 1 == editor.width
        @assert abs(editor_panes[1].width - editor_panes[2].width) <= 1
        document = freeze(server, result.session)
        @assert length(validate(document).windows[1].panes) == 2
        frozen_editor = only(validate(document).windows)
        @assert frozen_editor.name == "editor" && frozen_editor.focus
        @assert [p.focus for p in frozen_editor.panes] == [false, true]
        @assert all(
            p -> p.start_directory == realpath(dirname(server.socket_path)),
            frozen_editor.panes,
        )
        @assert frozen_editor.layout ==
                only(read_formats(server, editor.ref, FormatField("window_layout"))).value
        println("Loaded 1 window and 2 panes; frozen names, layout, paths and focus")
        document
    end
    @assert !ispath(dirname(endpoint[].socket_path))
    frozen
end

main()
```

## Install the command

The launcher binds to that environment and performs no package resolution at
startup:

```console
$ julia \
    --startup-file=no \
    --project=.workspace-env \
    -e 'using LibTmuxWorkspace; println(LibTmuxWorkspace.install_cli("bin"))'
```

Inspect the shipped configuration without contacting tmux:

```console
$ bin/libtmux-workspace plan packages/LibTmuxWorkspace/examples/workspace.yaml \
    --env PROJECT=example \
    --output json
```

`validate FILE` checks syntax and schema. `plan FILE` expands only explicitly
supplied environment/home values and produces inert ordered steps.
`load FILE` and `freeze SESSION` require exactly one explicit `--socket` or
`--socket-name`. Loading is detached by default; an existing session name
fails unless reuse is explicit. Interactive `--attach` requires a terminal
and remains outside automated attachment evidence.

Human progress goes to stderr. `--output json` writes one final result;
`--output ndjson` writes ordered progress and one terminal record. Nonzero
exit codes distinguish usage, backend failure, partial effects, cancellation
and deadline. A requested rollback removes only provably created resources.
Shell input, scripts and changes to borrowed resources cannot be rolled back.

The default POSIX shell readiness handshake uses directory notifications
and an exact owned marker. It does not poll cursor position or infer that
later commands finished. Custom interactive launchers require the explicit
readiness opt-out and caller-provided coordination.

Freeze preserves names, layouts, pane directories and focus. It cannot
reconstruct commands, history, environment or options. Reloading shared
windows creates independent windows. Snapshot acquisition is not atomic.

## Library reference

Browse the [LibTmuxWorkspace API reference](https://libtmux.org/en/julia/latest/workspace/reference/).
