Profiles
Save a whole desk — tabs, pane layouts, commands, working directories, and environment values — and open it with koshi --profile.
A profile is a saved session layout. Load one by name:
koshi --profile devThat reads profile/dev.kdl instead of opening a single shell pane. The file
lives in a profile/ subdirectory of the
config directory.
If anything in the profile is wrong, the whole profile is dropped and koshi
starts one shell instead. A missing named profile falls back the same way.
koshi config check validates every saved profile.
Structure
A profile is one or more tab blocks, plus a required version.
| Node | Meaning | Since |
|---|---|---|
version <n> | Required schema version | ≥ 0.1.0 |
tab { … } | One tab; its children are the pane arrangement | ≥ 0.1.0 |
pane { … } | A terminal pane | ≥ 0.1.0 |
horizontal { … } | Split its children left to right | ≥ 0.1.0 |
vertical { … } | Split its children top to bottom | ≥ 0.1.0 |
stack { … } | Children share one rectangle; one is expanded | ≥ 0.1.0 |
Inside a pane
| Key | Value | Since |
|---|---|---|
command "prog" "arg"… | The program and its arguments. Omit for the default shell | ≥ 0.1.0 |
cwd "/path" | Working directory, used as written — absolute, and ~ is not expanded | ≥ 0.1.0 |
env "NAME" "VALUE" | One environment variable for this pane; repeatable | ≥ 0.1.0 |
focus | Start with this pane focused; one per tab | ≥ 0.1.0 |
Omitting cwd inherits the directory koshi was launched from. Launching from
/home/me/proj starts that pane there; an explicit cwd "/srv/app" still
wins.
Sizing
Sizing keys are only valid on a direct child of horizontal or vertical.
Without any, children share the space equally.
| Key | Value | Since |
|---|---|---|
size 40 / size "60%" | A fixed size in cells, or a percent of the split | ≥ 0.1.0 |
weight 2 | A relative share of the leftover space | ≥ 0.1.0 |
min 10 | Never shrink below this many cells | ≥ 0.1.0 |
preferred 30 | The size to aim for when there is room | ≥ 0.1.0 |
Stacks and focus
Inside a stack, expanded marks the one member shown open; the rest collapse
to a one-row header.
focus inside a pane marks the pane that starts focused — one per tab.
focus as a direct child of a tab marks the tab that starts active — one per
profile. Without either, the first pane of the first tab starts focused.
A profile using every feature
// profile/dev.kdl — a complete profile using every feature.
version 1
tab {
// a horizontal split: editor on the left (60%), a tools column (40%) right
horizontal {
pane {
command "nvim" "src/main.rs" // program + its arguments
cwd "/home/me/proj" // absolute path (~ is not expanded)
env "RUST_LOG" "debug" // one env var...
env "NO_COLOR" "1" // ...repeat for more
size "60%" // fixed share of the split
focus // this pane starts focused
}
vertical {
size "40%"
pane {
command "cargo" "watch" "-x" "test"
cwd "/home/me/proj"
weight 2 // twice the leftover share of...
min 5 // ...but never below 5 rows,
preferred 20 // ...aiming for 20 when there's room
}
pane {
cwd "/home/me/proj" // no command → the default shell
weight 1
}
}
}
}
tab {
focus // this tab starts active
// a stack: members share one rectangle; `expanded` is the open one
stack {
pane {
command "journalctl" "-f"
}
pane {
command "htop"
expanded // this member starts open
}
}
}