shtick
shell-agnostic-shell-configuration-generation
(noun) : something cl[ever]
(see also) : pedantic
what is this?
this is a tool I use to manage groups of shell configurations (aliases, env vars, functions). It started out written in C for a presentation on unix shells to a group of TAs. I asked an LLM to help me port it to python because I got sick of remembering about memory and waking up in cold sweats over a presentation to a bunch of 20 y/o's, and chap and I got carried away. That's the disclaimer - AI helped. But this tool is for me and I use it actively, if you think it could help you too, continue on.
It's useful if you use multiple shells regularly and would like a single source of truth for your shell ..config (...within reason).
- Define aliases, env vars, and shell functions in one place (~/.config/shtick/config.toml)
- Manage persistent aliases, env vars, shell functions
- Define toggleable groups of aliases, e.g. dev, personal
- Create, rename, and remove groups
- Backup and restore configurations
- Configurable behavior through settings
Shell Integration
Shtick generates shell-specific files in ~/.config/shtick/. To make them available in new shell sessions, add this to your shell config:
# ~/.bashrc or ~/.zshrc
source ~/.config/shtick/load_active.bash
# ~/.config/fish/config.fish or whatever shell you use
source ~/.config/shtick/load_active.fish
Supported Shells
bash, zsh, fish, ksh, mksh, yash, dash, csh, tcsh, xonsh, elvish, nushell, powershell, rc, es, oil
- Run
shtick shellsto see the complete list.
Installation
If you decide you want to use this yourself, do all the usual cloning, then from your local clone run make install and the shtick package will be installed in your environment.
Commands reference
Core
# Add persistent items (always active)
shtick alias <key>=<value> # Add persistent alias
shtick env <key>=<value> # Add persistent env var
shtick function <key>=<value> # Add persistent function
# Add to specific groups
shtick add <type> <group> <key>=<value> # Add to specific group
shtick remove <type> <group> <key> # Remove from group
# Group activation
shtick activate <group> # Activate group
shtick deactivate <group> # Deactivate group
# Information
shtick status # Show status
shtick list [-l] # List items (use -l for detailed view)
shtick shells [-l] # List supported shells
Group management
# Create, rename, and remove groups
shtick group create <name> [-d <description>] # Create new group
shtick group rename <old> <new> # Rename group
shtick group remove <name> [-f] # Remove group (-f to skip confirmation)
Backup & restore
# Backup management
shtick backup create [-n <name>] # Create backup (optional custom name)
shtick backup list # List available backups
shtick backup restore <name> # Restore from backup
Settings management
# Configure shtick behavior
shtick settings init # Create default settings file
shtick settings show # Show current settings
shtick settings set <key> <value> # Change a setting
# Available settings:
# generation.shells = [] # List of shells to generate for (empty = auto-detect)
# generation.parallel = false # Enable parallel generation
# behavior.auto_source_prompt = true # Prompt to source after changes
# behavior.check_conflicts = true # Warn about conflicts
# behavior.backup_on_save = false # Auto-backup before saving
Other commands
shtick generate [--terse] # Regenerate shell files
shtick source [--shell <shell>] # Output source command for eval
Usage Examples
Basic Workflow
# Add some aliases
shtick alias ll='ls -la'
shtick alias gs='git status'
shtick alias gd='git diff'
Add environment variables
shtick env EDITOR='vim'
shtick env PAGER='less'
Add functions
shtick function mkcd='mkdir -p "$1" && cd "$1"'
shtick function backup='cp "$1" "$1.backup.$(date +%Y%m%d)"'
Load changes in current shell
eval "$(shtick source)"
Working with Groups
Create a work group
shtick group create work -d "Work-related configurations"
Add items to the work group
shtick add alias work deploy='./scripts/deploy.sh'
shtick add env work NODE_ENV='development'
shtick add function work vpn='sudo openvpn /etc/vpn/work.conf'
Create a personal group
shtick group create personal
Add items to personal group
shtick add alias personal myip='curl ifconfig.me'
shtick add function personal note='echo "$(date): $*" >> $HOME/notes.txt'
Activate work group
shtick activate work
Switch to personal
shtick deactivate work
shtick activate personal
Or have both active
shtick activate work
shtick activate personal
Backup and Restore
# Create a backup before major changes
shtick backup create -n "before_refactor"
Make your changes...
shtick group remove old_stuff -f
Oops, need to restore
shtick backup restore before_refactor
Settings Customization
Initialize settings file
shtick settings init
Disable auto-source prompt
shtick settings set behavior.auto_source_prompt false
Generate for specific shells only
shtick settings set generation.shells '["bash", "zsh"]'
Enable auto-backup
shtick settings set behavior.backup_on_save true
Sample Configuration
Shtick looks for ~/.config/shtick/config.toml. Here's a sample. See also sample
# Persistent items - always active in every shell session
[persistent.aliases]
pls = "sudo !!"
bk = "- || cd -"
wttr = "curl wttr.in"
refresh = "source ${HOME}/.zshrc"
goclass = "cd ${HOME}/Documents/Class/"
goproj = "cd ${HOME}/Documents/Project/"
goorg = "cd ${HOME}/Documents/GithubOrgs/"
gad = "git add"
gall = "git add --all"
gputt = "git push origin trunk"
gcamm = "git commit --all --message"
glogg = "git log --oneline --graph --decorate --all"
[persistent.env_vars]
PAGER = "less"
EDITOR = "micro"
BROWSER = "firefox"
[persistent.functions]
backup = "cp \"$1\" \"$1.backup.$(date +%Y%m%d_%H%M%S)\""
# Development group
[dev.aliases]
mk = "make"
mkr = "make run"
mki = "make install"
gfort = "gfortran"
ni = "npm install"
serve = "python manage.py runserver"
pyserve = "python3 -m http.server 8000"
brewup = "brew update && brew upgrade && brew cleanup"
[dev.env_vars]
DEBUG = "1"
NODE_ENV = "development"
[dev.functions]
newproject = "mkdir -p \"$HOME/projects/$1\" && cd \"$HOME/projects/$1\" && git init"
# Personal group
[personal.aliases]
myip = "curl ifconfig.me"
[personal.env_vars]
PERSONAL_NOTES = "$HOME/Documents/notes"
[personal.functions]
note = "echo \"$(date): $*\" >> $HOME/notes.txt"
todo = "echo \"[ ] $*\" >> $HOME/todo.txt"
# Work group (activate during work hours)
[work.aliases]
deploy = "./scripts/deploy.sh"
staging = "ssh staging.company.com"
prod = "ssh prod.company.com"
[work.env_vars]
AWS_PROFILE = "work"
KUBECONFIG = "$HOME/.kube/work-config"
[work.functions]
vpn = "sudo openvpn /etc/vpn/work.conf"
standup = "open https://meet.company.com/daily-standup"
Tips n. Trinkets
"Instant" sourcing alias: Add this for convenience:
shtick alias ss='eval "$(shtick source)"'
# Now you can just run 'ss' after any shtick command
Check for conflicts: Shtick warns you about duplicate items across groups:
$ shtick add alias dev ll='ls -la'
Warning: Item 'll' exists in groups: ['persistent']
Fuzzy removal: Remove items with partial matching:
shtick remove alias persistent brew # Matches 'brewup' and offers selection
Quick status check: See what's active at a glance:
Persistent (always active): 15 items
Available Groups:
dev: 8 items (ACTIVE)
personal: 5 items (inactive)
work: 12 items (ACTIVE)
Backup before removing groups:
shtick backup create -n "safe_point" && shtick group remove old_configs -f
View source
| 1 | # shtick |
| 2 | #### shell-agnostic-shell-configuration-generation |
| 3 | (noun) : something cl[ever] |
| 4 | (see also) : pedantic |
| 5 | |
| 6 | ### what is this? |
| 7 | this is a tool I use to manage groups of shell configurations (aliases, env vars, functions). It started out written in C for a presentation on unix shells to a group of TAs. I asked an LLM to help me port it to python because I got sick of remembering about memory and waking up in cold sweats over a presentation to a bunch of 20 y/o's, and chap and I got carried away. That's the disclaimer - AI helped. But this tool is for me and I use it actively, if you think it could help you too, continue on. |
| 8 | |
| 9 | It's useful if you use multiple shells regularly and would like a single source of truth for your shell ..config (...within reason). |
| 10 | |
| 11 | - Define aliases, env vars, and shell functions in one place (~/.config/shtick/config.toml) |
| 12 | - Manage persistent aliases, env vars, shell functions |
| 13 | - Define toggleable groups of aliases, e.g. dev, personal |
| 14 | - Create, rename, and remove groups |
| 15 | - Backup and restore configurations |
| 16 | - Configurable behavior through settings |
| 17 | |
| 18 | ### Shell Integration |
| 19 | Shtick generates shell-specific files in `~/.config/shtick/`. To make them available in new shell sessions, add this to your shell config: |
| 20 | |
| 21 | ``` |
| 22 | # ~/.bashrc or ~/.zshrc |
| 23 | source ~/.config/shtick/load_active.bash |
| 24 | |
| 25 | # ~/.config/fish/config.fish or whatever shell you use |
| 26 | source ~/.config/shtick/load_active.fish |
| 27 | ``` |
| 28 | |
| 29 | ### Supported Shells |
| 30 | `bash`, `zsh`, `fish`, `ksh`, `mksh`, `yash`, `dash`, `csh`, `tcsh`, `xonsh`, `elvish`, `nushell`, `powershell`, `rc`, `es`, `oil` |
| 31 | - Run `shtick shells` to see the complete list. |
| 32 | |
| 33 | ### Installation |
| 34 | |
| 35 | If you decide you want to use this yourself, do all the usual cloning, then from your local clone run `make install` and the `shtick` package will be installed in your environment. |
| 36 | |
| 37 | ## Commands reference |
| 38 | |
| 39 | #### Core |
| 40 | ``` |
| 41 | # Add persistent items (always active) |
| 42 | shtick alias <key>=<value> # Add persistent alias |
| 43 | shtick env <key>=<value> # Add persistent env var |
| 44 | shtick function <key>=<value> # Add persistent function |
| 45 | |
| 46 | # Add to specific groups |
| 47 | shtick add <type> <group> <key>=<value> # Add to specific group |
| 48 | shtick remove <type> <group> <key> # Remove from group |
| 49 | |
| 50 | # Group activation |
| 51 | shtick activate <group> # Activate group |
| 52 | shtick deactivate <group> # Deactivate group |
| 53 | |
| 54 | # Information |
| 55 | shtick status # Show status |
| 56 | shtick list [-l] # List items (use -l for detailed view) |
| 57 | shtick shells [-l] # List supported shells |
| 58 | ``` |
| 59 | |
| 60 | #### Group management |
| 61 | ``` |
| 62 | # Create, rename, and remove groups |
| 63 | shtick group create <name> [-d <description>] # Create new group |
| 64 | shtick group rename <old> <new> # Rename group |
| 65 | shtick group remove <name> [-f] # Remove group (-f to skip confirmation) |
| 66 | ``` |
| 67 | |
| 68 | #### Backup & restore |
| 69 | ``` |
| 70 | # Backup management |
| 71 | shtick backup create [-n <name>] # Create backup (optional custom name) |
| 72 | shtick backup list # List available backups |
| 73 | shtick backup restore <name> # Restore from backup |
| 74 | ``` |
| 75 | |
| 76 | #### Settings management |
| 77 | ``` |
| 78 | # Configure shtick behavior |
| 79 | shtick settings init # Create default settings file |
| 80 | shtick settings show # Show current settings |
| 81 | shtick settings set <key> <value> # Change a setting |
| 82 | |
| 83 | # Available settings: |
| 84 | # generation.shells = [] # List of shells to generate for (empty = auto-detect) |
| 85 | # generation.parallel = false # Enable parallel generation |
| 86 | # behavior.auto_source_prompt = true # Prompt to source after changes |
| 87 | # behavior.check_conflicts = true # Warn about conflicts |
| 88 | # behavior.backup_on_save = false # Auto-backup before saving |
| 89 | ``` |
| 90 | |
| 91 | #### Other commands |
| 92 | ``` |
| 93 | shtick generate [--terse] # Regenerate shell files |
| 94 | shtick source [--shell <shell>] # Output source command for eval |
| 95 | ``` |
| 96 | |
| 97 | |
| 98 | ### Usage Examples |
| 99 | #### Basic Workflow |
| 100 | ``` |
| 101 | # Add some aliases |
| 102 | shtick alias ll='ls -la' |
| 103 | shtick alias gs='git status' |
| 104 | shtick alias gd='git diff' |
| 105 | ``` |
| 106 | |
| 107 | #### Add environment variables |
| 108 | ``` |
| 109 | shtick env EDITOR='vim' |
| 110 | shtick env PAGER='less' |
| 111 | ``` |
| 112 | |
| 113 | #### Add functions |
| 114 | ``` |
| 115 | shtick function mkcd='mkdir -p "$1" && cd "$1"' |
| 116 | shtick function backup='cp "$1" "$1.backup.$(date +%Y%m%d)"' |
| 117 | ``` |
| 118 | |
| 119 | #### Load changes in current shell |
| 120 | `eval "$(shtick source)"` |
| 121 | |
| 122 | ### Working with Groups |
| 123 | #### Create a work group |
| 124 | `shtick group create work -d "Work-related configurations"` |
| 125 | |
| 126 | #### Add items to the work group |
| 127 | ``` |
| 128 | shtick add alias work deploy='./scripts/deploy.sh' |
| 129 | shtick add env work NODE_ENV='development' |
| 130 | shtick add function work vpn='sudo openvpn /etc/vpn/work.conf' |
| 131 | ``` |
| 132 | |
| 133 | #### Create a personal group |
| 134 | `shtick group create personal` |
| 135 | |
| 136 | #### Add items to personal group |
| 137 | ``` |
| 138 | shtick add alias personal myip='curl ifconfig.me' |
| 139 | shtick add function personal note='echo "$(date): $*" >> $HOME/notes.txt' |
| 140 | ``` |
| 141 | |
| 142 | #### Activate work group |
| 143 | `shtick activate work` |
| 144 | |
| 145 | #### Switch to personal |
| 146 | ``` |
| 147 | shtick deactivate work |
| 148 | shtick activate personal |
| 149 | ``` |
| 150 | |
| 151 | #### Or have both active |
| 152 | ``` |
| 153 | shtick activate work |
| 154 | shtick activate personal |
| 155 | Backup and Restore |
| 156 | |
| 157 | # Create a backup before major changes |
| 158 | shtick backup create -n "before_refactor" |
| 159 | ``` |
| 160 | |
| 161 | #### Make your changes... |
| 162 | `shtick group remove old_stuff -f` |
| 163 | |
| 164 | #### Oops, need to restore |
| 165 | `shtick backup restore before_refactor` |
| 166 | |
| 167 | ### Settings Customization |
| 168 | #### Initialize settings file |
| 169 | `shtick settings init` |
| 170 | |
| 171 | #### Disable auto-source prompt |
| 172 | `shtick settings set behavior.auto_source_prompt false` |
| 173 | |
| 174 | #### Generate for specific shells only |
| 175 | `shtick settings set generation.shells '["bash", "zsh"]'` |
| 176 | |
| 177 | #### Enable auto-backup |
| 178 | `shtick settings set behavior.backup_on_save true` |
| 179 | |
| 180 | ## Sample Configuration |
| 181 | Shtick looks for `~/.config/shtick/config.toml`. Here's a sample. See also [sample](/config.sample.toml) |
| 182 | |
| 183 | ``` |
| 184 | # Persistent items - always active in every shell session |
| 185 | [persistent.aliases] |
| 186 | pls = "sudo !!" |
| 187 | bk = "- || cd -" |
| 188 | wttr = "curl wttr.in" |
| 189 | refresh = "source ${HOME}/.zshrc" |
| 190 | goclass = "cd ${HOME}/Documents/Class/" |
| 191 | goproj = "cd ${HOME}/Documents/Project/" |
| 192 | goorg = "cd ${HOME}/Documents/GithubOrgs/" |
| 193 | gad = "git add" |
| 194 | gall = "git add --all" |
| 195 | gputt = "git push origin trunk" |
| 196 | gcamm = "git commit --all --message" |
| 197 | glogg = "git log --oneline --graph --decorate --all" |
| 198 | |
| 199 | [persistent.env_vars] |
| 200 | PAGER = "less" |
| 201 | EDITOR = "micro" |
| 202 | BROWSER = "firefox" |
| 203 | |
| 204 | [persistent.functions] |
| 205 | backup = "cp \"$1\" \"$1.backup.$(date +%Y%m%d_%H%M%S)\"" |
| 206 | |
| 207 | # Development group |
| 208 | [dev.aliases] |
| 209 | mk = "make" |
| 210 | mkr = "make run" |
| 211 | mki = "make install" |
| 212 | gfort = "gfortran" |
| 213 | ni = "npm install" |
| 214 | serve = "python manage.py runserver" |
| 215 | pyserve = "python3 -m http.server 8000" |
| 216 | brewup = "brew update && brew upgrade && brew cleanup" |
| 217 | |
| 218 | [dev.env_vars] |
| 219 | DEBUG = "1" |
| 220 | NODE_ENV = "development" |
| 221 | |
| 222 | [dev.functions] |
| 223 | newproject = "mkdir -p \"$HOME/projects/$1\" && cd \"$HOME/projects/$1\" && git init" |
| 224 | |
| 225 | # Personal group |
| 226 | [personal.aliases] |
| 227 | myip = "curl ifconfig.me" |
| 228 | |
| 229 | [personal.env_vars] |
| 230 | PERSONAL_NOTES = "$HOME/Documents/notes" |
| 231 | |
| 232 | [personal.functions] |
| 233 | note = "echo \"$(date): $*\" >> $HOME/notes.txt" |
| 234 | todo = "echo \"[ ] $*\" >> $HOME/todo.txt" |
| 235 | |
| 236 | # Work group (activate during work hours) |
| 237 | [work.aliases] |
| 238 | deploy = "./scripts/deploy.sh" |
| 239 | staging = "ssh staging.company.com" |
| 240 | prod = "ssh prod.company.com" |
| 241 | |
| 242 | [work.env_vars] |
| 243 | AWS_PROFILE = "work" |
| 244 | KUBECONFIG = "$HOME/.kube/work-config" |
| 245 | |
| 246 | [work.functions] |
| 247 | vpn = "sudo openvpn /etc/vpn/work.conf" |
| 248 | standup = "open https://meet.company.com/daily-standup" |
| 249 | ``` |
| 250 | |
| 251 | ### Tips n. Trinkets |
| 252 | |
| 253 | |
| 254 | #### "Instant" sourcing alias: Add this for convenience: |
| 255 | ``` |
| 256 | shtick alias ss='eval "$(shtick source)"' |
| 257 | # Now you can just run 'ss' after any shtick command |
| 258 | ``` |
| 259 | |
| 260 | #### Check for conflicts: Shtick warns you about duplicate items across groups: |
| 261 | ``` |
| 262 | $ shtick add alias dev ll='ls -la' |
| 263 | Warning: Item 'll' exists in groups: ['persistent'] |
| 264 | ``` |
| 265 | |
| 266 | #### Fuzzy removal: Remove items with partial matching: |
| 267 | ``` |
| 268 | shtick remove alias persistent brew # Matches 'brewup' and offers selection |
| 269 | ``` |
| 270 | |
| 271 | #### Quick status check: See what's active at a glance: |
| 272 | ```$ shtick status |
| 273 | Persistent (always active): 15 items |
| 274 | Available Groups: |
| 275 | dev: 8 items (ACTIVE) |
| 276 | personal: 5 items (inactive) |
| 277 | work: 12 items (ACTIVE) |
| 278 | ``` |
| 279 | #### Backup before removing groups: |
| 280 | ``` |
| 281 | shtick backup create -n "safe_point" && shtick group remove old_configs -f |
| 282 | ``` |