Skill v1.0.1
currentAutomated scan100/100+10 new
version: "1.0.1" name: zsh-writer description: Use when writing or modifying ZSH functions.
ZSH Writer
Overview
Write ZSH code that is consistent with my conventions.
Core Workflow
Step 1 — Place the file
Goal: Correct path and name.
Exit criterion: File exists at correct path with correct name.
- Autoloaded function:
tools/term/zsh/config/functions/autoload/{domain}/{subdomain?}/{name} - Name:
{domain}-{subdomain?}-{action}— e.g.git-branch-list,json-lint -rawsuffix → machine-readable▮-separated output, consumed by other scripts
Step 2 — TDD: Write a failing test
Goal: Ensure the bug/feature has a failing test first
Exit criterion: Test fails.
Write a failing test for the bug or missing feature you want to implement.
- Run
bats <test_filepath>to run the tests - See Testing for full examples and best practices
bats_load_library 'helper'setup() {bats_tmp_dir}@test "converts space-separated words to camelCase" {bats_run_zsh "my-new-function hello world"[[ "$status" -eq 0 ]][[ "$output" = "helloWorld" ]]}@test "passes result to clipboard" {pbcopy() { echo "$1" > "$BATS_TMP_DIR/clipboard.txt"; }bats_mock pbcopybats_run_zsh "my-new-function hello world"[[ "$(cat "$BATS_TMP_DIR/clipboard.txt")" = "helloWorld" ]]}
Step 3 — Make it work
Goal: Write the minimal code to make the failing test pass.
Exit criterion: Test is green.
Write the simplest code that makes the test pass. No patterns yet — just correct behavior.
- Run
bats <test_filepath>to run the tests
Step 4 — Refactor
Goal: Apply structural and style patterns without changing behavior.
Exit criterion: Tests still pass after refactor.
| Pattern | Rule | |
|---|---|---|
| Headers | Top of the file: what the script does, how to call it and error protection | |
| Args parsing | Use zparseopts to parse --named arguments | |
| Variables | local myVar="$(myCommand)" on one line | |
| Splitting | Use ▮ as separator and ${(@ps/▮/)line} to split | |
| Conditions | [[ simpleCondition ]] && state=value. No nested if/else, return early | |
| Calling Commands | Use existing helpers (git-branch-current), not raw calls. Use --long-form, not -l. |
# Show changed files with syntax-aware coloring# Usage:# $ git-diff-colorize # Unstaged changes# $ git-diff-colorize --staged # Staged only# $ git-diff-colorize --ext ts # Filter by extensionsetopt local_options err_returnMAX_RESULTS=50zparseopts -E -D \s=flagStaged \-staged=flagStaged \e:=flagExt \-ext:=flagExtlocal isStaged=${#flagStaged}local extFilter=${flagExt[2]}local helperArgs=()[[ $isStaged == 1 ]] && helperArgs+=(--staged)[[ "$extFilter" != "" ]] && helperArgs+=(--ext "$extFilter")local rawFiles="$(git-diff-list-raw "${helperArgs[@]}")"# Nothing to display if working tree is clean[[ "$rawFiles" == "" ]] && return 0local output=""for rawLine in ${(f)rawFiles}; dolocal fields=(${(@ps/▮/)rawLine})local name=$fields[1]local dir=$fields[2]local ext=$fields[3]local parentDir="${dir:t}" # zsh modifier: last path componentlocal color=$COLOR_DEFAULT[[ "$ext" == "ts" ]] && color=$COLOR_FILE_TS[[ "$ext" == "zsh" ]] && color=$COLOR_FILE_ZSHoutput+="$(colorize "$name" $color)▮$parentDir▮$ext\n"donetable $output
- Run
bats <test_filepath>to confirm tests still pass
Step 5 — Lint the file
Run zsh-lint --fix <file> on any modified .zsh files. Run bats-lint <test_file> on any modified .bats test files. Fix every violation, including pre-existing ones.
Common Rationalizations
| Rationalization | Reality | |
|---|---|---|
| "It's only two levels of if/else, it's ok." | No it's not. Return early, always. |
Checklist
- [ ] Quick documentation and usage at top of script
- [ ] Return early — no avoidable nesting
- [ ] Comments for each guard clause
- [ ] All function vars
local; script constants UPPER_CASE - [ ] External commands use long-form args, one per line
- [ ] Use existing helpers over porcelain (e.g.
git-branch-list-rawnotgit branch) - [ ] Use
zparseoptsfor --named arguments - [ ] Tests still pass after refactor
- [ ] Tests use the dedicated helpers