# ~/.bash.d — Modular Bash Configuration This directory contains modular shell configuration files that are automatically sourced by `~/.bashrc` on every new shell session. Instead of maintaining one monolithic `.bashrc`, each concern lives in its own file — making the setup easier to understand, maintain, and extend. ## How It Works Add the following to the end of your `~/.bashrc`: ```bash for file in $HOME/.bash.d/*; do [[ -x $file ]] && source $file done ``` This iterates over all files in `~/.bash.d/` and sources each one that has the **executable bit** set. Non-executable files are silently skipped, which provides a simple way to temporarily disable a configuration (just `chmod -x` the file). Files are sourced in **lexicographic order**, so numeric prefixes control the load sequence. This matters because later files may depend on functions or variables defined by earlier ones. ## File Naming Convention | Prefix | Purpose | Example | |--------|----------------------------------|---------------------------| | `00-` | Helper functions (loaded first) | `00-path-helper` | | `10-` | PATH configuration | `10-go-path`, `10-rust-path` | | `20-` | Build tool settings | `20-ninja` | | `30-` | Shell/prompt setup | `30-starship` | | `50-` | Shell completions | `50-claude-completion` | | `99-` | Credentials (last) | `99-gemini`, `99-huggingface` | Lower numbers load first, so foundational pieces like helper functions (`00-`) and PATH entries (`10-`) are available before anything that depends on them. ## Current Files ### Helpers (`00-`) - **`00-path-helper`** — Defines `path_append` and `path_prepend` functions that safely add directories to `$PATH` (checking the directory exists and avoiding duplicates). - **`00-credential-guard`** — Defines `require_private`, which warns at shell startup if a credential file has overly permissive permissions (anything beyond owner-only access). - **`00-completion-cache`** — Defines `cached_completion`, which caches shell completion scripts to `~/.cache/bash.d/` so they are only regenerated when the tool binary is updated. Used by all `50-*-completion` scripts. ### PATH (`10-`) - **`10-bun-path`** — Adds Bun (JavaScript runtime) binaries to PATH. - **`10-go-path`** — Sets `$GOPATH` and adds Go binaries to PATH. - **`10-rust-path`** — Sets `$CARGO_HOME` and adds Cargo binaries to PATH. ### Build Tools (`20-`) - **`20-android`** — Sets `$ANDROID_HOME`, `$JAVA_HOME`, and adds Android SDK tools to PATH (only when installed). - **`20-ninja`** — Configures Ninja as the default CMake generator and enables ccache for C/C++ builds (only when installed). - **`20-oneapi`** — Lazy-loads the Intel oneAPI environment. Because `setvars.sh` takes ~1.5 seconds, the full environment is deferred until an Intel tool (`icc`, `icx`, `ifort`, etc.) is first invoked. Call `_load_oneapi` to trigger it manually. ### Prompt (`30-`) - **`30-starship`** — Initialises the [Starship](https://starship.rs) cross-shell prompt, if installed. ### Completions (`50-`) All completions (except `50-claude-completion`) use `cached_completion` to avoid subprocess overhead on every shell start. Cache files live in `~/.cache/bash.d/` and are automatically regenerated when the tool binary is updated. - **`50-asdf-completion`** — Tab completion for the asdf version manager. - **`50-bun-completion`** — Tab completion for Bun (JavaScript runtime & package manager). - **`50-claude-completion`** — Tab completion for [Claude Code](https://claude.com/claude-code) CLI. - **`50-fj-completion`** — Tab completion for the Forgejo CLI (`fj`). - **`50-gh-completion`** — Tab completion for the GitHub CLI (`gh`). - **`50-podman-completion`** — Tab completion for Podman (rootless container engine). - **`50-tailscale-completion`** — Tab completion for Tailscale. - **`50-uv-completion`** — Tab completion for [uv](https://github.com/astral-sh/uv) (Python package manager). ### Credentials (`99-`) - **`99-claude.example`** — Template for Forgejo issue token for Claude Code integrations. - **`99-gemini.example`** — Template for Gemini API key. - **`99-google.example`** — Template for Google API key. - **`99-huggingface.example`** — Template for HuggingFace token (`$HF_TOKEN`). - **`99-replicate.example`** — Template for Replicate API token. ## Adding a New File 1. Create the file with the appropriate numeric prefix: ```bash vim ~/.bash.d/50-mytool-completion ``` 2. Start the file with the shellcheck directive: ```bash # shellcheck shell=bash ``` 3. Make it executable (required for it to be sourced): ```bash chmod +x ~/.bash.d/50-mytool-completion ``` 4. For credential files, create a `.example` template and the real file: ```bash # Create the template (tracked in git) cat > ~/.bash.d/99-mytool.example << 'EOF' # shellcheck shell=bash # Copy to 99-mytool and fill in your token, then: chmod 700 99-mytool require_private "${BASH_SOURCE[0]}" export MY_SECRET_TOKEN=your-token-here EOF # Create the real file from the template cp ~/.bash.d/99-mytool.example ~/.bash.d/99-mytool # Edit 99-mytool and fill in your real secret chmod 700 ~/.bash.d/99-mytool ``` Then add `99-mytool` to `.gitignore`. 5. Validate with shellcheck: ```bash shellcheck ~/.bash.d/50-mytool-completion ``` ## Security Credential files (`99-*`) are **excluded from git** via `.gitignore` and are never committed. Each credential has a tracked `.example` template with placeholder values. To set up credentials: 1. Copy the template: `cp 99-foo.example 99-foo` 2. Fill in your real secret 3. Restrict permissions: `chmod 700 99-foo` Additional protections: - **File permissions** — Credential files use mode `700` (owner-only). - **Runtime checks** — The `require_private` helper warns on shell startup if a credential file has been accidentally loosened. - **Never commit real secrets** — Only `.example` templates are tracked in git.