This document describes the internal architecture and design decisions of gh-account-guard.
gh-account-guard/
├── gh-account-guard # Main entry point
├── install # Installation script
├── lib/
│ ├── commands/ # Individual command implementations
│ │ ├── setup.sh
│ │ ├── init.sh
│ │ ├── status.sh
│ │ ├── fix.sh
│ │ ├── switch.sh
│ │ └── ...
│ ├── helpers/ # Reusable helper modules
│ │ ├── yaml.sh # YAML parsing utilities
│ │ ├── git.sh # Git operations
│ │ ├── gh_auth.sh # GitHub CLI auth operations
│ │ └── profile.sh # Profile matching logic
│ ├── commands.sh # Command loader
│ ├── config.sh # Configuration management
│ ├── directory.sh # Directory/file browser utilities
│ ├── ui.sh # UI/UX functions (gum/fzf integration)
│ └── utils.sh # General utilities
├── test/ # Test suite (bats)
└── docs/ # Documentation
The main script that:
- Sources all modules in dependency order
- Parses command-line arguments
- Routes to appropriate command handlers
- Provides usage information
Each command is implemented as a separate file:
cmd_<command_name>()function convention- Commands are sourced by
lib/commands.sh - Commands can use helper functions from
lib/helpers/
Reusable functionality extracted into focused modules:
-
yaml.sh: Pure bash YAML parsing (zero dependencies)- Reading values from config
- Writing/updating config
- YAML structure manipulation
- No external tools required
-
git.sh: Git operations- Setting git config
- Reading git config
- Git repository detection
- Remote URL validation
-
gh_auth.sh: GitHub CLI operations- Account switching
- Auth status checking
- Account validation
-
profile.sh: Profile matching logic- Path-based matching
- Longest match algorithm
- Profile validation
Handles:
- Config file location (
~/.config/gh/account-guard.yml) - Default directory settings
- Profile CRUD operations
- Config file validation
Provides:
- Detection of optional tools (
gum,fzf,bat) - Fallback to basic prompts when tools unavailable
- Interactive menus and prompts
- Consistent user experience
File browser functionality:
- Interactive directory selection
- Path validation
- File system operations
Current Directory
↓
lib/helpers/profile.sh::match_profile()
↓
lib/helpers/yaml.sh::yaml_get() (reads config)
↓
Returns matching profile index
↓
Command uses profile data
User Input (via setup/edit)
↓
lib/config.sh::add_profile() / update_profile()
↓
lib/helpers/yaml.sh::yaml_set() / yaml_add()
↓
Writes to ~/.config/gh/account-guard.yml
gh account-guard fix
↓
lib/helpers/profile.sh::match_profile()
↓
lib/helpers/git.sh::apply_profile_to_repo()
↓
git config --local user.name/email/signingkey
- Each command is self-contained
- Helper functions are reusable
- Clear separation of concerns
- Works without optional tools (
gum,fzf,bat) - Falls back to basic prompts
- No hard dependencies on optional tools
- Longest matching path wins
- Supports
~expansion - Simple and predictable
- Uses
git config --local(repo-specific) - Doesn't modify global git config
- Each repo maintains its own identity
- Shell hooks fail silently if no profile matches
- Doesn't interrupt workflow
- Only warns on actual issues
The config file uses YAML:
default_directory: "~/work" # Optional: default for file browser
profiles:
- name: work
path: ~/work/company/ # Can be string or array
gh_username: work-user
git:
name: "Name"
email: "email@example.com"
signingkey: "ssh-ed25519 ..."
gpgsign: true
gpgformat: ssh
remote_match: "github.com/Org/" # Optional validation- Create
lib/commands/new_command.sh - Implement
cmd_new_command()function - Add to
lib/commands.shloader - Add to
gh-account-guardusage and routing
- Create
lib/helpers/new_helper.sh - Implement helper functions
- Source in dependent modules
- Document usage
- Detect new tools in
lib/ui.sh - Add fallback logic
- Use in commands via UI functions
Tests are located in test/ and use bats:
test_utils.sh- Utility function teststest_config.sh- Configuration and profile matching teststest_commands.sh- Command implementation tests
Run tests with:
make test
# or
./test/run_tests.sh- bash - Shell interpreter (standard on Unix systems)
- git - Git operations (required for the tool's core functionality)
- gh - GitHub CLI (required for GitHub CLI extensions)
Zero external dependencies! All YAML parsing is done in pure bash.
- gum - Enhanced UI prompts (has fallback to basic prompts)
- fzf - Interactive selection (has fallback to basic menu)
- bat - Syntax highlighting (has fallback to
cat)
- Profile matching is O(n) where n = number of profiles
- YAML parsing uses pure bash (no external processes)
- Git operations are minimal (config reads/writes)
- Shell hooks run asynchronously to avoid blocking
- No credentials stored in code
- Config file contains user-provided data only
- Git config is local to repositories
- GitHub auth handled by
ghCLI
Potential areas for enhancement:
- Caching profile matches for performance
- Profile templates for common setups
- Migration tools for existing git configs
- Integration with git credential helpers
- Support for more git config options
- Contributing Guide - Development guidelines
- Quick Start - Getting started
- Troubleshooting - Common issues