Layouts¶
Layout schema¶
The schema lives in stackops.utils.schemas.layouts.layout_types.
Core types¶
| Type | Fields |
|---|---|
TabConfig |
tabName, startDir, command, optional tabWeight |
LayoutConfig |
layoutName, layoutTabs |
LayoutsFile |
version, layouts |
Helper behavior¶
serialize_layouts_to_file(layouts, version, path, write_mode="replace_file")writes a layout file with"$schema": "https://bit.ly/cfglayout"and replaces any existing file content.serialize_layouts_to_file(layouts, version, path, write_mode="merge_by_layout_name")preserves existing layouts, replaces layouts that share the samelayoutName, and appends new layout names.substitute_home(tabs)expands~and$HOMEand rewrites shorthand command prefixes:f ...->~/.config/stackops/scripts/wrap_stackops fire ...t ...->~/.config/stackops/scripts/wrap_stackops terminal ...s ...->~/.config/stackops/scripts/wrap_stackops seek ...
The current schema key is layoutTabs. There is no alternate tabs field in the typed definitions.
Building layouts from Python functions¶
stackops.cluster.sessions_managers.utils.maker converts Python functions into TabConfig entries.
Main helpers¶
| Helper | Purpose |
|---|---|
get_fire_tab_using_uv() |
Generates Python source from a function, writes a temporary script under ~/tmp_results/tmp_scripts/python/, and returns the tab config plus the generated file path |
get_fire_tab_using_fire() |
Builds a wrap_stackops fire ... command for a function file under the user's home directory |
make_layout_from_functions() |
Builds a LayoutConfig from functions plus any extra tabs you want to append |
make_layout_from_functions() accepts both launch styles through method:
"script"to execute generated Python throughuv"fire"to use thewrap_stackops fireentrypoint
Its flags parameter is passed through to the selected launch mode as either uv_run_flags or fire_flags.
Set max_stagger to add a random startup delay of up to that many seconds to each generated function tab. The extra delay is applied after the helper returns the tab command, so get_fire_tab_using_uv() and get_fire_tab_using_fire() keep their direct command behavior unchanged. Negative values raise ValueError.
Example¶
from stackops.cluster.sessions_managers.tmux.tmux_local import run_tmux_layout
from stackops.cluster.sessions_managers.utils.maker import make_layout_from_functions
def ingest() -> None:
print("ingest")
def train() -> None:
print("train")
layout = make_layout_from_functions(
functions=[ingest, train],
functions_weights=[1, 2],
import_module=True,
tab_configs=[],
layout_name="ml-workflow",
method="script",
uv_with=["stackops"],
uv_project_dir=None,
flags="",
start_dir="~/code/my-project",
max_stagger=10.0,
)
run_tmux_layout(layout_config=layout, on_conflict="rename")
If functions_weights is None, each function is treated as weight 1.
Controlling layout size¶
stackops.cluster.sessions_managers.utils.load_balancer provides two controls.
limit_tab_num()¶
limit_tab_num(
layout_configs=layouts,
max_thresh=8,
threshold_type="number",
breaking_method="moreLayouts",
)
Supported threshold_type values:
"number"for raw tab count"weight"for summedtabWeight
Supported breaking_method values:
"moreLayouts""combineTabs"
limit_tab_weight()¶
limit_tab_weight(layout_configs, max_weight, command_splitter) rewrites overweight tabs by calling your command_splitter(command, to=max_weight) function and replacing the original tab with ..._part1, ..._part2, and so on.
Convenience launcher¶
- starts all sessions with a 2-second poll window
- runs the monitoring routine at 2-second intervals
- kills all managed sessions when monitoring finishes
Backend-specific layout generators¶
The same LayoutConfig can be handed to the tmux backend:
run_tmux_layout(layout_config, on_conflict)usingexit_mode="backToShell"
The generator class is:
TmuxLayoutGenerator
That class is responsible for rendering backend-specific layout artifacts:
- tmux shell scripts
API reference¶
Layout schema¶
layout_types
¶
Type definitions for the standardized layout configuration schema. This module defines the data structures that match the layout.json schema.
Layout builders¶
maker
¶
Layout load balancer¶
load_balancer
¶
Load balancer helper¶
load_balancer_helper
¶
split_tabs_by_weight
¶
Split tabs into chunks where each chunk's total weight <= max_weight.
combine_tabs_into_super_tabs
¶
Combine tabs into num_super_tabs super tabs with combined commands.
combine_tabs_by_weight_into_super_tabs
¶
Combine tabs into super tabs where each super tab has weight <= max_weight.
restrict_num_tabs_helper1
¶
restrict_num_tabs_helper1(
layout_configs: list[LayoutConfig],
max_thresh: int,
threshold_type: Literal["number"],
breaking_method: Literal["moreLayouts"],
) -> list[LayoutConfig]
When threshold is exceeded, create more layouts with max_thresh tabs each.
restrict_num_tabs_helper2
¶
restrict_num_tabs_helper2(
layout_configs: list[LayoutConfig],
max_thresh: int,
threshold_type: Literal["number"],
breaking_method: Literal["combineTabs"],
) -> list[LayoutConfig]
When threshold is exceeded, combine tabs into super tabs to reduce count to max_thresh.
restrict_num_tabs_helper3
¶
restrict_num_tabs_helper3(
layout_configs: list[LayoutConfig],
max_thresh: int,
threshold_type: Literal["weight"],
breaking_method: Literal["moreLayouts"],
) -> list[LayoutConfig]
When threshold is exceeded, create more layouts with max_thresh total weight each.
restrict_num_tabs_helper4
¶
restrict_num_tabs_helper4(
layout_configs: list[LayoutConfig],
max_thresh: int,
threshold_type: Literal["weight"],
breaking_method: Literal["combineTabs"],
) -> list[LayoutConfig]
When threshold is exceeded, combine tabs into super tabs with weight <= max_thresh.
options:
show_root_heading: true
show_source: false
members_order: source
options:
show_root_heading: true
show_source: false
members_order: source
options:
show_root_heading: true
show_source: false
members_order: source
options:
show_root_heading: true
show_source: false
members_order: source
options:
show_root_heading: true
show_source: false
members_order: source
options:
show_root_heading: true
show_source: false
members_order: source