TMUX-ing
Written with the help of LMStudio + Qwen3 4B Thinking 2507.
Ever since I started working back in 2023, I’ve struggled to understand how to manage multiple client platforms, different repositories, and now different AWS configurations. I knew people were using tmux, but it never stuck for me.
I recently started working on a new client, and the question arose again: how do I manage multiple clients while keeping my workflow clean? The solution was tmuxinator!
Why and Goals #
- Never accidentally run a command against the wrong client’s AWS account.
- One command to drop into a fully set up session for any client.
- Copy/paste that just works (mouse selection → clipboard, no extra keys).
- Each new client: copy a template, fill in a few values, and you’re done.
Folder structure #
First I had to clean my ~/Developer structure:
~/Developer/
├── clients/
│ ├── client-y/ ← git repos live here
│ │ ├── .aws/config ← client-scoped AWS config (SSO session + profile)
│ │ └── .envrc ← direnv: sets AWS_CONFIG_FILE / AWS_PROFILE
│ └── <other-clients>/
│ └── ... same pattern
├── personal/
├── tooling/
│ ├── scripts/
│ └── ansible/
This is obviously an example, but you get the idea.
Each client gets its own .aws/config and .envrc rather than one shared ~/.aws/config — keeps clients fully isolated, and nothing sensitive to that client leaks if the folder is ever archived or shared.
2. AWS access — aws-vault + SSO, scoped per client #
Install vault stuffs:
brew install aws-vault
(This pulls from the actively maintained ByteNess/aws-vault fork — the original 99designs/aws-vault is abandoned!!!! Do not use it! Homebrew already points to the maintained one.)
Per-client config - ~/Developer/clients/<client>/.aws/config:
[sso-session <client>-sso]
sso_start_url = https://<client-org>.awsapps.com/start
sso_region = eu-west-1
sso_registration_scopes = sso:account:access
[profile <client>]
sso_session = <client>-sso
sso_account_id = <account-id>
sso_role_name = <role-name>
region = eu-west-1
output = json
Per-client .envrc (direnv), in ~/Developer/clients/<client>/.envrc:
export AWS_CONFIG_FILE="$PWD/.aws/config"
export AWS_PROFILE=<client>
Run direnv allow once inside that folder after creating/editing it.
You might not have envrc installed, install it using brew:
brew install direnv
Prerequisite for direnv to work at all — confirm this line exists in ~/.zshrc (without it, .envrc files never load, silently):
eval "$(direnv hook zsh)"
Gitignore — if the client folder (or subfolders) is a git repo, add:
.aws/
3. tmuxinator — per-client session templates #
Each client gets a YAML file in ~/.tmuxinator/<client>.yml describing the
windows/panes to open automatically.
Standard template (editor / git / aws / shell):
name: <client>
root: ~/Developer/clients/<client>/repos
windows:
- editor:
layout: main-vertical
panes:
- command1
- command2
- command3
Each command will open in its own window inside tmux, if you want to have an empty windows add this line:
- # This is an empty windows, you can use for whatever you want.
One-off / task-specific templates are also fine — e.g. XXX-ansible-.yml
uses a main-horizontal layout (one large pane on top, others in a row below)
for a specific repo, with panes running watch "git status" and a diff check,
no AWS window needed.
Start a session:
tmuxinator start <client>
5. Shell shortcuts — ~/.zshrc #
# Start (or attach to) a tmuxinator project by name
tm() {
tmuxinator start "$@"
}
# Tab completion: `tm <TAB>` lists all tmuxinator project names
_tm() {
local -a projects
projects=(${(f)"$(tmuxinator list -n 2>/dev/null)"})
compadd -a projects
}
compdef _tm tm
# Run a command with the current directory's AWS profile via aws-vault
awsx() {
aws-vault exec "${AWS_PROFILE:?AWS_PROFILE not set}" -- "$@"
}
Usage: tm client-y, tm client-y, tab-completion works out of the box
once ~/.zshrc is reloaded (source ~/.zshrc).