This file serves as the complete AI context and history for all AI interactions with this project. It contains:
- Full conversation history - All AI sessions and their accomplishments
- AI-specific rules - Behavior, autonomy, workflow requirements
- Project context - Current state, patterns, conventions
- Lessons learned - Solutions, workarounds, best practices discovered
- Future reference - Historical context for understanding decisions
Status: ✅ ALWAYS KEEP IN SYNC - Update after every AI session
- ✅ Execute autonomously when instructions are clear
- ✅ Ask when uncertain or ambiguous
- ✅ Never ask permission for routine tasks (read files, run tests, check status)
- ✅ Always ask when unsure or before destructive operations
- ✅ Question mark (?) = User asking a question, NOT giving instructions
- ✅ No question mark = User giving instructions, act on them
- ✅ Multiple tasks = Create AI.TODO.md immediately (see below)
- ❌ "Should I read this file?" (just do it)
- ❌ "Can I run this command?" (just run it)
- ❌ "Would you like me to test?" (always test)
- ❌ "Permission to check status?" (always check)
- ✅ "This will delete 100 files, confirm?"
- ✅ "Ambiguous requirement, did you mean X or Y?"
- ✅ "This could break production, proceed?"
- ✅ "Multiple approaches possible, which do you prefer?"
ALWAYS create when:
- ✅ More than 2 instructions given at once
- ✅ More than 2 tasks to complete
- ✅ Complex multi-step workflow
- ✅ Multiple files to modify
# AI TODO
## Current Session Tasks
- [ ] Task 1: Description with details
- [ ] Task 2: Description with details
- [ ] Task 3: Description with details
## Completed
- [x] Completed task 1
- [x] Completed task 2- User gives 3+ tasks → Create AI.TODO.md immediately
- Work on first task
- Update AI.TODO.md (move to Completed section)
- Work on next task
- Update AI.TODO.md
- When all done → Delete AI.TODO.md
- Update AI.md with session summary
- Create COMMIT_MESS with all changes
- ✅ Keeps AI organized and focused
- ✅ User can see progress at any time
- ✅ Prevents tasks from being forgotten
- ✅ Maintains clear workflow
- ✅ Easy to resume if interrupted
- ✅ Always in sync with actual work
-
✅ Full access to read-only git commands
git status,git diff,git log,git show,git branch, etc.gitcommit status,gitcommit log,gitcommit log show,gitcommit diff, etc.
-
❌ NEVER run commit commands
git commit- User handles all commits with GPG signinggitcommit(no args) - Triggers commitgitcommit all- Commits all changesgitcommit push- Pushes changes- Any command that actually commits changes
ALWAYS create/update .git/COMMIT_MESS after making changes:
# Find git root
git_root=$(git rev-parse --show-toplevel)
# File location
${git_root}/.git/COMMIT_MESSFormat:
🔧 Short commit message with emojis (max 72 chars) 🔧
Detailed description of changes with multiple paragraphs if needed.
**Changes:**
- `file1` - Description of changes
- `file2` - Description of changes
**Testing:**
✅ Syntax validated
✅ Functionality tested
✅ Follows project standards
Short Message Rules (CRITICAL):
- ✅ Maximum 72 characters (including emojis)
- ✅ Format:
🔧 Short summary 🔧 - ✅ Start with emoji (no text before)
- ✅ End with same emoji (no text after)
- ✅ NO period at end
- ✅ NO "..." truncation
- ✅ Capitalize first word after emoji
Common Emojis:
- 🐛 Bug fix
- ✨ New feature
- 📝 Documentation
- 🚀 Release
- ♻️ Refactor
- 🗃️ General changes
- 🔧 Configuration
User Workflow:
- AI makes changes
- AI creates/updates
.git/COMMIT_MESS - User runs
gitcommit(or./bin/gitcommit) - Script parses file, commits with GPG signing
- Script cleans up
.git/COMMIT_MESS
- ✅ Functions: Prefix with
__(internal functions) - ✅ Variables: Prefix with
{SCRIPTNAME}_(uppercase script name) - ✅ Comments: Always above code (NEVER inline at end of line)
- ✅ Control flow: Use
if/elseorif/elif/elseinstead of&&/||chains - ✅ Newlines: Always add newline at end of files (except where not supported)
- ✅ Headers: Update script headers when making changes
- Update
@@Versionto current date-time (YYYYMMDDHHMM-git) - Update
@@Changelogwith brief description - Update other fields as appropriate
- Update
Rule: Prefer bash built-ins over forked subprocesses. Never use Useless Use of Cat (UUOC).
Every $(...), pipe, and external command spawns a subprocess. In scripts
that run frequently or in tight loops, these forks add up. Use bash native
features wherever possible.
File reading:
# BAD
contents="$(cat file)"
cat file | grep pattern
cat file | jq '.key'
cat file | curl --data-urlencode text@-
# GOOD
contents="$(< file)"
grep pattern file
jq '.key' file
curl --data-urlencode text@filePath manipulation — use parameter expansion, not basename/dirname:
# BAD
name="$(basename -- "$path")"
dir="$(dirname -- "$path")"
stem="$(basename "$path" .ext)"
# GOOD
name="${path##*/}" # basename
dir="${path%/*}" # dirname
stem="${name%.ext}" # strip extension
ext="${name##*.}" # extension onlyString matching — use [[ ]], not echo | grep:
# BAD
if echo "$var" | grep -q "pattern"; then ...
if echo "$line" | grep -q '^#'; then ...
# GOOD
if [[ "$var" == *"pattern"* ]]; then ...
if [[ "$line" == "#"* ]]; then ...Regex — use =~ and BASH_REMATCH, not echo | grep -E:
# BAD
protocol="$(echo "$url" | grep -oE '^https?')"
# GOOD
if [[ "$url" =~ ^(https?):// ]]; then
protocol="${BASH_REMATCH[1]}"
fiSplitting — use parameter expansion, not echo | cut:
# BAD
major="$(echo "$version" | cut -d. -f1)"
user="$(echo "$path" | cut -d/ -f1)"
# GOOD
major="${version%%.*}" # everything before first .
user="${path%%/*}" # everything before first /
tail="${path#*/}" # everything after first /Parsing — use read, not awk/cut when bash suffices:
# BAD
load1="$(cat /proc/loadavg | awk '{print $1}')"
load5="$(cat /proc/loadavg | awk '{print $2}')"
# GOOD (single read, zero forks)
read -r load1 load5 load15 _ _ < /proc/loadavgStdin — let programs read it directly, don't cat | into them:
# BAD
cat - | yad --text-info
cat - | sed 's/x/y/'
# GOOD
yad --text-info # reads stdin by default
sed 's/x/y/' # reads stdin by defaultWhen forking IS acceptable:
- Tool genuinely needs a subshell (
$(...)capturing output that can't be inlined) - Complex text processing where
awk/sedis clearly the right tool - External data sources (APIs, databases) — no bash equivalent
- Readability wins over a micro-optimization in a non-hot-path
Rule of thumb: if you're writing echo "$var" |, cat file |, or
$(basename "$x"), stop — there's almost always a bash built-in.
- ✅ Docker-first (preferred)
docker build -t local-scripts-test . docker run --rm -it local-scripts-test bash -n /path/to/script docker run --rm -it local-scripts-test /path/to/script --help - ✅ Local testing (fallback)
bash -n bin/scriptname shellcheck bin/scriptname ./bin/scriptname --help
- ❌ No
curl | shpatterns - ✅ Proper sudo handling with
sudo teeinstead of redirects - ✅ Input validation and sanitization
- ✅ Secure credential storage
- amd64 (x86_64)
- arm64 (aarch64)
- arm (armv7l)
- Scripts:
bin/ - Functions:
functions/ - Completions:
completions/_{scriptname}_completions - Man pages:
man/{scriptname}.1 - Helpers:
helpers/ - Templates:
templates/ - Tests:
tests/
- User configs:
~/.config/myscripts/scriptname/ - System configs:
/etc/scriptname/ - Logs:
~/.local/log/scriptname/ - Temp files:
~/.local/tmp/claude/{reponame}/
SCRIPTNAME_CONFIG_DIR # Configuration directory
SCRIPTNAME_LOG_DIR # Log directory
SCRIPTNAME_CACHE_DIR # Cache directoryObjective: Improve gitcommit and gen-changelog functionality, establish AI workflow rules
Tasks Completed:
-
Enhanced
gitcommitAI error handling- Added comprehensive error handling for all AI tools
- Capture and display API errors (rate limits, auth, network)
- Improved user feedback with helpful error messages
- Function:
__generate_ai_commit_message()
-
Fixed
__git_logfunction in gitcommit- Added optional limit parameter:
gitcommit log [N] - Fixed shortcut handling for
gitcommit l [N] - Preserved color output with grep filtering
- Always exclude "Version bump" commits
- Enhanced with
--color=alwaysandgrep --color=always
- Added optional limit parameter:
-
Added commit detail viewing
- New:
gitcommit log show- Show most recent commit (excluding version bumps) - New:
gitcommit log show <sha>- Show specific commit - Full commit details with diff output
- Configurable exclusions
- New:
-
Enhanced
gen-changelogscript- New:
gen-changelog --create- Generate full CHANGELOG.md - Function:
__create_new_changelog() - Full commit details with date, author, SHA, body
- Excludes "Version bump" commits automatically
- Proper markdown formatting with sections
- New:
-
Synced changes to
gitadmin- Updated
__git_logfunction to match gitcommit - Same filtering, color preservation, and limit support
- Updated
-
Updated completions and man pages
- Updated
_gitcommit_completionswith new commands - Updated
_gen-changelog_completionswith --create flag - Updated man pages for both scripts
- Updated
-
Code quality improvements
- Moved all inline comments above code (project standard)
- Added comment style rule to CLAUDE.md
- Consistent formatting across all changes
-
Established AI workflow rules in CLAUDE.md
- Added "AI Behavior & Autonomy" section
- Added "AI TODO Management" workflow
- Added AI/Claude Access rules for git commands
- Clarified COMMIT_MESS workflow with git root path
- Added short commit message format requirements
-
Created AI.md master context file
- Complete AI conversation history
- All AI-specific rules and workflows
- Project context and conventions
- Always kept in sync with project
Files Modified:
bin/gitcommit- Error handling, log enhancements, commit viewingbin/gitadmin- Log function sync with gitcommitbin/gen-changelog- Added --create flag and full changelog generationcompletions/_gitcommit_completions- New commandscompletions/_gen-changelog_completions- New --create flagman/gitcommit.1- Documentation updatesman/gen-changelog.1- Documentation updatesCLAUDE.md- AI workflow rules, autonomy guidelines, TODO managementAI.md- Created master AI context file
Testing:
- ✅ Syntax validation:
bash -non all modified scripts - ✅ Functionality:
gitcommit log,gitcommit log 10,gitcommit log show - ✅ gen-changelog:
gen-changelog --createproduces proper CHANGELOG.md - ✅ Color output preserved with grep filtering
- ✅ Exclusions working correctly
- ✅ Error handling tested with various AI tools
Lessons Learned:
-
grep and color preservation
- Use
--color=alwayson both git and grep - grep preserves ANSI color codes when using
--color=always - Pipe works correctly:
git log --color=always | grep --color=always -v "pattern"
- Use
-
AI.TODO.md workflow
- Essential for managing multiple tasks
- Should have been created at session start
- Helps keep AI organized and user informed
- Example: This session had 8+ tasks, should have used AI.TODO.md
-
Comment placement
- Project standard: Comments ALWAYS above code
- NEVER inline at end of line
- Improves readability and consistency
-
Git root path handling
- Use
git rev-parse --show-toplevelto find git root - COMMIT_MESS location:
<git_root>/.git/COMMIT_MESS - Important for submodules and nested repos
- Use
-
AI autonomy expectations
- Act autonomously when clear
- Ask when uncertain
- Question mark (?) = question, not instruction
- User expects AI to just do routine tasks
Patterns Established:
-
Error handling for AI tools
error_output=$(command 2>&1) exit_code=$? if [ $exit_code -ne 0 ]; then printf_red "Error: $error_output" return 1 fi
-
Git log with filtering and color
local exclude_pattern="Version bump" git log --color=always --oneline --no-decorate ${limit_flag} | \ grep --color=always -viE "$exclude_pattern"
-
Changelog generation
git log --format="%H|%ad|%an|%s" --date=format:"%Y-%m-%d" | \ while IFS='|' read -r sha date author subject; do # Format with full details including body done
Next Session TODO:
- ✅ AI.md created and synced
- ✅ All rules documented
- ✅ Ready for future development
Before Starting:
- Read AI.md for full context
- Check for AI.TODO.md (resume existing tasks)
- Understand current project state
During Work:
- If >2 tasks → Create AI.TODO.md immediately
- Update AI.TODO.md after each task
- Follow code standards (functions:
__, variables:SCRIPTNAME_) - Comments above code (never inline)
- Test changes (Docker-first, then local)
After Completion:
- Delete AI.TODO.md (if all tasks done)
- Create/update
.git/COMMIT_MESSwith proper format - Update AI.md with session summary
- Verify all files synced and tested
Common Commands:
# Find git root
git rev-parse --show-toplevel
# Test syntax
bash -n bin/scriptname
# Docker test
docker build -t local-scripts-test .
docker run --rm -it local-scripts-test bash -n /path/to/script
# Check status
git status
gitcommit status
gitcommit log 10
gitcommit diff- AI.md - This file, always in sync, master context
- AI.TODO.md - Temporary task tracker, created when needed, deleted when done
- CLAUDE.md - Development notes and project standards (reference)
- TODO.md - User's general project TODO (not AI-specific)
- .git/COMMIT_MESS - Commit message staging, created by AI, cleaned by gitcommit
This AI.md file should be updated:
- ✅ After every AI session (add to Session History)
- ✅ When new patterns are established
- ✅ When lessons are learned
- ✅ When rules are added or changed
- ✅ When project structure changes
When starting a new AI session:
- Read AI.md first - Get full context and history
- Check AI.TODO.md - Resume incomplete tasks if exists
- Read CLAUDE.md - Review development standards
- Check git status - Understand current state
- Proceed with task - Follow established patterns
- Enhanced AI error handling patterns
- Additional changelog formatting options
- More git workflow automation
- Extended testing frameworks
- AI API rate limiting strategies
- Error recovery mechanisms
- User feedback improvements
- Automation opportunities
Last Updated: 2026-04-19 Status: ✅ In Sync Next Update: After next AI session
✅ Analyzed setupmgr script (9715 lines) architecture and installation functions ✅ Fixed critical bug in __install_from_binary function ✅ Converted act tool to use unified __install_from_archive function ✅ Converted incus tool to use unified __install_from_binary function ✅ Tested both tools for install and update scenarios
Bug Fixed: __install_from_binary argument passing
- Function expected 2 args:
(url, destination) - Was being called with 3 args:
(url, name, destination) - After
shift 1in function,$1wasnameinstead ofdestination - Fixed by removing
$nameparameter from __download_and_move call - Changed:
__download_and_move "$download_url" "$name" "$binFile" - To:
__download_and_move "$download_url" "$binFile"
Pattern Matching Insights
- Auto-generated patterns from
__build_asset_patternwork correctly - Pattern is case-insensitive via
grep -iE - Handles OS variations: linux, gnu, darwin, macos, etc.
- Handles arch variations: x86_64, amd64, x64, aarch64, arm64, etc.
- For unusual naming (like incus: bin.linux.incus.x86_64), use custom arch-specific pattern
Unified Function Architecture
__install_from_binary()- For direct binary downloads (no extraction)__install_from_archive()- For archived binaries (tar.gz, zip, etc.)- Both functions:
- Auto-detect architecture and OS
- Build appropriate asset patterns
- Find latest release from GitHub/GitLab/Gitea/etc.
- Validate binary architecture before installation
- Display version after installation
- Handle system/user installation paths
Tool Conversion Pattern
# Old pattern (40+ lines):
__setup_tool() {
local exitCode=0
local name="tool"
local arch="$(uname -m)"
local binFile="$SETUPMGR_DEFAULT_BIN_DIR/$name"
local release_url="https://api.github.com/repos/owner/repo/releases/latest"
# ... manual version fetching
# ... manual URL construction
# ... manual download/extract
# ... manual error handling
return $exitCode
}
# New pattern (3 lines for archives, 1 line for binaries):
__setup_tool() {
__install_from_archive "tool" "owner/repo" "$SETUPMGR_DEFAULT_BIN_DIR"
}
# Or for direct binaries:
__setup_tool() {
__install_from_binary "tool" "owner/repo" "$SETUPMGR_DEFAULT_BIN_DIR"
}
# Or with custom pattern:
__setup_tool() {
__install_from_binary "tool" "owner/repo" "$SETUPMGR_DEFAULT_BIN_DIR" "custom-pattern"
}Architecture-Specific Pattern Building For tools with non-standard naming (like incus), build arch-specific patterns:
local arch="$(__get_system_arch)"
local arch_pattern=""
case "$arch" in
amd64) arch_pattern="x86_64" ;;
arm64) arch_pattern="aarch64" ;;
esac
__install_from_binary "tool" "owner/repo" "$dir" "pattern\\.${arch_pattern}\$"Custom Pattern Format
- Use regex format:
"pattern\\.to\\.match\\.${variable}\\$" - Escape dots with double backslash:
\\. - Use
\$for end-of-string anchor - Pattern will be used with
grep -iE(case-insensitive extended regex)
- Reduced act from 40 lines → 3 lines (93% reduction)
- Reduced incus from 30 lines → 13 lines (57% reduction)
- Eliminated redundant code (version fetching, URL construction, error handling)
- Standardized output messages across all tools
- Consistent architecture validation
- Better error messages with context
# act - Fresh install
./bin/setupmgr act
# Output: Installing act (latest release)
# act installed to /usr/local/bin/act: 0.2.84
# act - Update/reinstall
./bin/setupmgr act
# Output: Updating act to latest release
# act installed to /usr/local/bin/act: 0.2.84
# incus - Fresh install
./bin/setupmgr incus
# Output: Updating incus to latest release
# incus installed: 6.18
# incus - Update/reinstall
./bin/setupmgr incus
# Output: Updating incus to latest release
# incus installed: 6.18- 132 more tool functions to convert to unified system
- Need systematic approach to convert in batches
- Identify which tools need archive vs binary extraction
- Test converted tools for edge cases
- Update documentation
bin/setupmgr- Fixed __install_from_binary, converted act and incus.git/COMMIT_MESS- Created commit messageAI.TODO.md- Created task tracker
- Continue batch conversion of remaining tool functions
- Prioritize commonly used tools (ripgrep, shellcheck, shfmt, yq, fd, bat, delta)
- Test each batch after conversion
- Update man pages and completions if needed
- Systematically tested all 95 converted tools
- 89 tools working correctly (93.7%)
- Identified 6 tools with no binaries for removal
- Fixed critical issues: zoxide strip-components, tokei release fallback
-
Archive Extraction Bug: Tools with binaries at root level fail with
--strip-components=1- Solution: Added
do_not_strip_componentsflag support - Fixed: zoxide
- Solution: Added
-
Latest Release Empty: Some projects don't upload binaries to latest release
- Solution:
__find_release_asset()now falls back to scanning recent releases - Fixed: tokei
- Solution:
-
Missing Case Entries: 31 converted tools had no case statement entries
- Added explicit
tool)cases for all - Added
--debugwarning for unmapped tools
- Added explicit
- broot - Canop/broot
- btop - aristocratos/btop
- mc - minio/mc
- ncdu - rofl0r/ncdu
- httpie - httpie/cli (Python package)
- trivy - aquasecurity/trivy
- mise - installation fails
- skaffold - installation fails
- tilt - installation fails
- All case statement entries (need to re-add)
- Debug warning in wildcard case (need to re-add)
- This is expected, continuing...
- Re-apply case entries for all 31 tools
- Re-add debug warning
- Remove 6 tools with no binaries
- Fix mise/skaffold/tilt
- Final testing
- Documentation sync
dockermgr manifest was broken — confirmed from logs in ~/.local/log/dockermgr/:
'docker manifest create' requires at least 2 arguments(wireguard, almalinux)'docker buildx build' requires 1 argument(vault)
-
Wrong platform names (
x86_64→amd64) Docker uses GOARCH names (amd64, arm64) not uname names (x86_64, aarch64). This caused all docker builds to fail silently, leaving$amendempty. -
Empty
$amendguard — when builds fail,docker manifest create $tag(no images) fails with "requires at least 2 arguments". Added guard to skip with clear error. -
--amendflag misused — was--amend img1 --amend img2(per-image) instead ofdocker manifest create --amend TAG img1 img2(command-level flag). -
$oci_labelsword-splitting bug — label values with spaces (e.g."Docker image for vault") were split when$oci_labelsstring was unquoted in the command, consuming the-stdin context arg. Fixed by convertingoci_labelsfrom a string to a bash array. -
BuildKit stdin compatibility —
docker build ... -→docker build ... -f - .Docker 25+ with BuildKit requires explicit-f -for stdin Dockerfile; the old-alone no longer works as a raw Dockerfile context in BuildKit mode.
When accumulating shell flags that may have values with spaces, ALWAYS use an array:
# WRONG (word-splits on spaces in values):
local flags=""
flags+="--label key=\"value with spaces\" "
docker build $flags -
# CORRECT:
local flags=()
flags+=("--label" "key=value with spaces")
docker build "${flags[@]}" -f - .bin/dockermgr— Fixed__create_manifest(): platforms, oci_labels array, --amend flag, guard, BuildKit stdin
Refactor all 222 scripts in bin/ to remove Useless Use of Cat (UUOC)
anti-patterns and replace forked subprocess calls with bash built-ins.
Add a permanent rule to AI.md so future work follows the same standard.
APPNAME="$(basename -- "$0" 2>/dev/null)"→APPNAME="${0##*/}"(220 scripts)[ "$(basename -- "$SUDO" 2>/dev/null)" = "sudo" ]→[ "${SUDO##*/}" = "sudo" ](208 scripts)__is_an_option()rewritten to use[[ "$ARRAY" == *"x"* ]]instead ofecho | grep -q(210 scripts)
sysusage— 3 ×cat /proc/loadavg | awkcollapsed into a singleread -r ... < /proc/loadavg(zero forks)reqpkgs—cat /etc/*release | grep→grep /etc/*release(10 sites)proxmox-cli—cat file | jq→jq file;echo | cut -d. -f1→${ver%%.*}pastebin—cat "$file" | curl --data-urlencode text@-→curl --data-urlencode text@"$file"buildx— nestedbasename $(dirname $(realpath))→ pure parameter expansionshortenurl,gitignore—echo | grep -q→[[ == *"x"* ]]gen-nginx—echo | grep -qE→[[ =~ regex ]]withBASH_REMATCHcalendar— 6 consecutivegrepcalls fused into singlegrep -Evdictionary— 7 ×cat file.out | jq→jq ... file.outnotifications— one-time file read instead of triplecaturbandict,wikipedia,earthquakes,duckdns— droppedcat -|before stdin-capable tools
- All 222 scripts pass
bash -n(0 syntax errors) git diff --stat: 222 files changed, 1091 insertions(+), 1012 deletions(-)- Single remaining
cat | cmdpattern in repo is commented-out code
New "Bash Performance: No UUOC, Minimize Forks" section under Project-Specific Rules → Code Standards. Documents:
- File reading (
$(< file), direct file arg) - Parameter expansion (
${var##*/}notbasename) - Pattern match with
[[ == *"x"* ]]notecho | grep - Regex with
=~+BASH_REMATCHnotecho | grep -E - Split with
${var%%.*}notecho | cut - Parse with
readnotcat | awk - Let tools read stdin directly (no
cat -|)
- Sed delimiter conflict — when replacement contains
|, switch delimiter toXor#:sed -i 'sXpatternXreplacementXg'. replace_allrisk — doingreplace_allofcat file | jq→jqdropped the filename; had to re-addfileas explicit arg to eachjq. Always preview replace_all on at least one site first.- Verify with diff, not just grep — confirmed via
grep -cand final scan that only commented-outcat |remained.
AI.md— Added "Bash Performance: No UUOC, Minimize Forks" rule + this session entrybin/*— 222 scripts refactored.git/COMMIT_MESS— Commit message staged for user
Apply the same UUOC/fork-reduction refactor to templates/ — but only to
files whose shebang indicates bash. Templates drive script generation, so
fixing them prevents the patterns from re-appearing in newly created scripts.
Parameter expansion (${var##*/}), [[ =~ ]], and [[ == *"x"* ]] are
bashisms. They don't exist in POSIX sh, fish, or zsh. Before touching
any template:
- Check the file with
file <path>orhead -1 <path> - Only apply fixes when shebang is
#!/usr/bin/env bash(or#!/bin/bash) - Skip sh/fish/zsh templates entirely — they need different (or no) fixes
- 37 bash templates (
#!/usr/bin/env bash) — eligible - 15
.tmpl.shheredoc generators — eligible (they produce bash) - 3 non-bash (
templates/scripts/shell/{sh,fish,zsh}) — skipped
Core bash templates (templates/scripts/bash/*) — these are the source
that gen-script copies from to produce the scripts in bin/:
user,system,terminal,simple,mgr-script.user.sh,mgr-script.system.sh— universal APPNAME, SUDO basename,__is_an_optionfixes;echo | awk '{print $1}'→${VAR%% *}
Installers (templates/scripts/installers/*.sh):
dfmgr.sh,systemmgr.sh,devenvmgr.sh,hakmgr.sh,desktopmgr.sh—basenamefixesdockermgr.sh— manyecho | grep -q→[[ == *"x"* ]]/[[ =~ ]],cat file | grep→grep file,cat file | tee→tee < file, complex pipeline simplifications (TYPE extraction, CONTAINER_HOSTNAME)
OS bootstrap (templates/scripts/os/*.sh):
centos.sh— 6-branchecho | grep -qE '^pattern'chain →[[ == pat* ]]arch.sh— basename fix
Shared scripts (templates/scripts/other/, templates/scripts/functions/,
templates/scripts/shell/):
other/build,other/docker-entrypoint,other/start-service,functions/docker-entrypoint,shell/bash— basename/grep/sed fixes;cat /dev/urandom | tr→tr < /dev/urandom;$(basename "$x")→"${x##*/}"(8 sites in functions/docker-entrypoint)
gen-script heredoc generators (templates/gen-script/):
script/user.tmpl.sh,script/system.tmpl.sh,header/raw.tmpl.sh— escaped\$(basename -- "\$0")→\${0##*/}. This ensures every NEW script generated viagen-scriptstarts with the correct pattern.
templates/scripts/installers/dockermgr.sh:1009-1011 has a pre-existing
bug where DOCKER_HUB_IMAGE_URL is stripped of its tag first, then field 2
is extracted from the (now tag-less) URL — so DOCKER_HUB_IMAGE_TAG is
always empty. Did NOT fix this — behavior preservation was the contract.
Flagged in commit message only so the user can see it on the next pass.
"$(dirname "$path")" → "${path%/*}" has divergent behavior when the path
has no /: dirname returns ., parameter expansion returns the string
unchanged. Left these 5–6 sites alone — not worth a subtle behavior change.
- 37 bash templates:
bash -npasses (0 failures) - 15 tmpl.sh generators:
bash -npasses (they're heredocs, so syntax check is partial but confirms no quoting regressions) - 23 files changed, 86 insertions, 86 deletions
- Templates drive generated code — fixing templates is how you stop a
pattern from coming back. The 200+
APPNAME=$(basename...)inbin/existed becausegen-script/script/*.tmpl.shemitted them. Fixed the tmpl.sh files too so future generations start clean. - Shebang is the contract — checked shebang before every fix. 3 shell templates (sh/fish/zsh) untouched. This is a permanent rule: always scope bash-only rewrites to files with a bash shebang.
dirnamehas subtle semantics — don't blindly convert to${x%/*}; they diverge when the path has no/.- Sed delimiter with
/— when the replacement text contains/(like${0##*/}), use a different delimiter (X,#) or escape. Thefor-file-with-sedone-liner approach broke on the first/inEXEC_CMD_BIN.
AI.md— This session entrytemplates/scripts/bash/*— 6 core templatestemplates/scripts/installers/*.sh— 6 installerstemplates/scripts/os/{arch,centos}.sh— 2 OS bootstrapstemplates/scripts/other/{build,docker-entrypoint,start-service}— 3 scriptstemplates/scripts/functions/docker-entrypoint— shared functionstemplates/scripts/shell/bash— shell templatetemplates/gen-script/{script,header}/*.tmpl.sh— 3 heredoc generators.git/COMMIT_MESS— Amended with template fixes