<< All versions

Skill v1.0.1

currentAutomated scan100/100
pixelastic/oroshi/zsh-writer

+10 new

──Details
PublishedAugust 21, 2026 at 10:16 AM
Content Hashsha256:1f69c05be1594cd8...
Git SHA79692245fa39
Bump Typepatch
Compare with v1.0.0
──Files
Files (1 file, 4.4 KB)
SKILL.md4.4 KBactive
SKILL.md · 158 lines · 4.4 KB

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
  • -raw suffix → 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
bash
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 pbcopy
bats_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.

PatternRule
HeadersTop of the file: what the script does, how to call it and error protection
Args parsingUse zparseopts to parse --named arguments
Variableslocal myVar="$(myCommand)" on one line
SplittingUse ▮ as separator and ${(@ps/▮/)line} to split
Conditions[[ simpleCondition ]] && state=value. No nested if/else, return early
Calling CommandsUse existing helpers (git-branch-current), not raw calls. Use --long-form, not -l.
zsh
# 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 extension
setopt local_options err_return
MAX_RESULTS=50
zparseopts -E -D \
s=flagStaged \
-staged=flagStaged \
e:=flagExt \
-ext:=flagExt
local 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 0
local output=""
for rawLine in ${(f)rawFiles}; do
local fields=(${(@ps/▮/)rawLine})
local name=$fields[1]
local dir=$fields[2]
local ext=$fields[3]
local parentDir="${dir:t}" # zsh modifier: last path component
local color=$COLOR_DEFAULT
[[ "$ext" == "ts" ]] && color=$COLOR_FILE_TS
[[ "$ext" == "zsh" ]] && color=$COLOR_FILE_ZSH
output+="$(colorize "$name" $color)▮$parentDir▮$ext\n"
done
table $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

RationalizationReality
"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-raw not git branch)
  • [ ] Use zparseopts for --named arguments
  • [ ] Tests still pass after refactor
  • [ ] Tests use the dedicated helpers
← v1.0.0All versions