# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Overview This is a modular bash configuration directory (`~/.bash.d/`). Files here are sourced by `~/.bashrc` to set up the shell environment. Each file handles a specific concern (PATH additions, environment variables, shell completions). See `README.md` for a full description of the directory and its contents. ## File Naming Convention Files use numeric prefixes to control load order: - **00-** : Helper functions (loads first — used by other scripts) - **10-** : PATH configuration (foundational) - **20-** : Build tool settings (depends on paths) - **30-** : Shell/prompt setup - **50-** : Shell completions (named `50--completion`) - **99-** : Application config, credentials (loads last) ## Available Helpers (defined in `00-*`) Use these in all scripts — do not manipulate `PATH` or check permissions manually: - `path_append ` — add directory to end of `$PATH` (checks existence, prevents duplicates) - `path_prepend ` — add directory to start of `$PATH` - `require_private ` — warn if file is group/world-accessible; use in credential files - `cached_completion ` — cache completion output to `~/.cache/bash.d/`; regenerates when the tool binary is updated. Use this for all new completion scripts instead of `eval` or `. <()` ## Writing Scripts - Every file must start with `# shellcheck shell=bash` - Guard external tools with `command -v &>/dev/null` before using them - Guard directory-dependent exports with `[[ -d ]]` before exporting - Do not suppress stderr from external scripts — only redirect stdout when needed - Avoid `eval` when `. <(cmd)` (process substitution) works - For shell completions, use `cached_completion` instead of `eval` or `. <()` to avoid subprocess overhead on every shell start - For slow environment scripts, use lazy-loading (see `20-oneapi` for the wrapper-function pattern) - Prevent `LD_LIBRARY_PATH` duplicates with a `case` guard (see `20-oneapi` for example) ## Permissions - Directory `~/.bash.d/` itself: mode `700` - Regular scripts (`00-*` through `50-*`): mode `755` (executable is **required** for sourcing) - Credential files (`99-*` with secrets): mode `700` and must call `require_private "${BASH_SOURCE[0]}"` as the first functional line - Non-credential config files (e.g. `20-android`): mode `755` like regular scripts ## Validation Validate all shell scripts with shellcheck before committing: ```bash shellcheck # single file shellcheck [0-9][0-9]-* # all scripts at once ``` To test changes, open a new shell or source a single file: ```bash source ~/.bash.d/20-ninja # reload one file in the current shell ``` ## Security Credential files are **excluded from git** via `.gitignore`. Each has a tracked `.example` template with placeholder values. To set up a credential: 1. Copy the template: `cp 99-foo.example 99-foo` 2. Fill in your real secret 3. Restrict permissions: `chmod 700 99-foo` When adding new credential files: - Create a `.example` template (mode `644`) tracked in git - Add the real filename to `.gitignore` - Use mode `700` on the real file: `chmod 700 ` - Call `require_private "${BASH_SOURCE[0]}"` as the first functional line - **Never commit real secrets** - Be aware that `export`ed tokens are visible to all child processes