Skip to main content

Forge your shell configuration from modular pieces with dependency resolution

Project description

gzh-cli-shellforge

Forge your shell configuration from modular pieces with dependency resolution

A build tool that transforms modular shell scripts into a unified .zshrc/.bashrc with automatic dependency ordering and OS-specific filtering.

What it does

  • Reads shell modules from your config directory
  • Resolves dependencies automatically
  • Filters by OS (Mac/Linux)
  • Generates optimized .zshrc/.bashrc
  • Validates configuration integrity
  • Automatic backup and version control (new in v0.2.0)

Problem

Managing shell configurations across multiple machines and operating systems is challenging:

  • Manual concatenation is error-prone
  • Dependency ordering is hard to maintain
  • OS-specific logic scattered everywhere
  • No validation before deployment

Solution

Shellforge uses a declarative manifest to define your shell modules and their dependencies, then builds the final configuration file with correct ordering and OS filtering.

Installation

# With uv (recommended)
uv pip install shellforge

# Or with pip
pip install shellforge

Quick Start

Option A: Auto-generate from existing shellrc (Recommended)

If you have an existing shell configuration in init.d/, rc_pre.d/, rc_post.d/ structure:

# 1. Auto-generate manifest from existing config
shellforge init -c ~/devenv/config/shellrc -o manifest.yaml

# 2. Review and edit the generated manifest
vim manifest.yaml

# 3. Validate
shellforge validate -c ~/devenv/config/shellrc -m manifest.yaml

# 4. Build
shellforge build -c ~/devenv/config/shellrc -m manifest.yaml --auto-output

Option B: Manual manifest creation

# manifest.yaml
modules:
  - name: brew-path
    file: init.d/brew.sh
    requires: []
    os: [Mac]
    description: Homebrew PATH initialization

  - name: conda
    file: rc_pre.d/conda.sh
    requires: [brew-path]
    os: [Mac, Linux]
    description: Conda environment

Then build:

shellforge build \
  --config-dir ~/devenv/config/shellrc \
  --manifest manifest.yaml \
  --output ~/.zshrc

New in v0.2.0: Deployment with Backup

Deploy with automatic backup and version control:

shellforge build \
  -c shellforge-modules/modules \
  -m shellforge-modules/manifest.yaml \
  --auto-output \
  --deploy

This will:

  1. Build to tmp/shellforge-build/ first
  2. Create timestamped snapshot in ~/.backup/shellforge/snapshots/
  3. Commit to git in ~/.backup/shellforge/
  4. Deploy to actual location (e.g., ~/.zshrc)

Dual Protection:

  • Git history for full version control
  • Timestamped snapshots for quick rollback

Restore from Backup

Rollback to a previous version:

# List available snapshots
shellforge restore -t ~/.zshrc --list

# Restore interactively (shows recent snapshots)
shellforge restore -t ~/.zshrc

# Restore specific snapshot
shellforge restore -t ~/.zshrc -s ~/.backup/shellforge/snapshots/zshrc/2025-11-23_10-29-15

Cleanup Old Snapshots

Manage snapshot retention:

# Keep only last 10 snapshots
shellforge clean-snapshots -t ~/.zshrc --keep-count 10

# Keep snapshots from last 30 days
shellforge clean-snapshots -t ~/.zshrc --keep-days 30

# Preview what would be deleted
shellforge clean-snapshots -t ~/.zshrc --keep-count 10 --dry-run

See Deployment Guide for details.

Self-Documenting CLI (v0.3.0+)

Shellforge provides contextual guidance to help you navigate workflows without constantly consulting documentation:

Quick Start Guide

Run shellforge --help to see common workflows organized by use case:

  • First-time setup: Migrate existing config or start from scratch
  • Daily workflow: Validate → Build → Diff → Deploy cycle
  • Recovery: Restore from backups

Smart Statistics

Commands show helpful statistics after execution:

$ shellforge validate -c modules -m manifest.yaml

✓ Validation passed

📊 Validation Statistics:
   Total modules: 27
   Mac modules: 27
   Linux modules: 22
   Total dependencies: 18

💡 Next steps:
  Preview:  shellforge build -c modules -m manifest.yaml --dry-run
  Compare:  shellforge diff -c modules -m manifest.yaml --auto-detect-existing

Next Steps Suggestions

Each command suggests what to do next based on the operation result:

  • After validate: Suggests preview, compare, or deploy
  • After build: Suggests compare or deploy (context-aware)
  • After diff: Suggests deploy or backup strategies

Verbose Mode for Details

Use -v or --verbose flag for detailed information:

# See dependency resolution details
shellforge validate -c modules -m manifest.yaml -v

# See module load order during build
shellforge build -c modules -m manifest.yaml -o output.zsh -v

# See detailed change analysis
shellforge diff -c modules -m manifest.yaml --auto-detect-existing -v

Error-Specific Help

Errors include specific troubleshooting steps:

$ shellforge validate -c wrong -m manifest.yaml

✗ Validation failed:
   Circular dependency detected: asdf-core -> nvm -> asdf-core

  💡 Fix circular dependency:
     Edit manifest.yaml and review the 'requires' fields
     Remove one dependency from the circular chain

Common error scenarios covered:

  • Circular dependencies: Shows which dependencies to review
  • Missing files: Guides path verification
  • YAML syntax errors: Links to example manifests
  • Permission errors: Provides chmod examples

Usage

Init

Generate manifest from existing shell configuration:

# Auto-generate manifest from existing shellrc directory
shellforge init -c config/shellrc -o manifest.yaml

# Preview without writing file
shellforge init -c config/shellrc --dry-run

# Custom output location
shellforge init -c ~/dotfiles/shellrc -o ~/dotfiles/manifest.yaml

What it does:

  • Scans init.d/, rc_pre.d/, rc_post.d/ directories
  • Auto-detects module dependencies:
    • $MACHINE usage → depends on os-detection
    • brew commands → depends on brew-path
    • Module-specific (e.g., asdf-flutterasdf-core)
  • Detects OS support from case $MACHINE statements
  • Extracts descriptions from comments or generates defaults
  • Generates YAML manifest with helpful category comments

Example output:

# Shellforge Manifest
# Auto-generated from existing shell configuration

modules:
  # System Initialization (init.d)
  - name: os-detection
    file: init.d/00_check_os.sh
    requires: []
    os: [Mac, Linux]
    description: Detect operating system and set MACHINE variable

  # Pre-RC Configuration (rc_pre.d)
  - name: conda
    file: rc_pre.d/conda.sh
    requires: [os-detection, brew-path]
    os: [Mac, Linux]
    description: Conda environment initialization

Build

Generate shell configuration file:

# Auto-detect OS and use recommended output file
shellforge build -c config/shellrc -m manifest.yaml --auto-output

# Specify OS, shell, and session type
shellforge build -c config/shellrc -m manifest.yaml \
  --os macos --shell zsh --session interactive \
  --auto-output

# Manual output file
shellforge build -c config/shellrc -m manifest.yaml -o ~/.zshrc

# Build for different session types
# Login shell (.zprofile for zsh, .bash_profile for bash)
shellforge build -c config/shellrc -m manifest.yaml \
  --session login --auto-output

# Interactive shell (.zshrc for zsh, .bashrc for bash)
shellforge build -c config/shellrc -m manifest.yaml \
  --session interactive --auto-output

# Always sourced (.zshenv for zsh)
shellforge build -c config/shellrc -m manifest.yaml \
  --shell zsh --session always --auto-output

# Fish shell (always use --session always for fish)
shellforge build -c config/shellrc -m manifest.yaml \
  --shell fish --session always --auto-output

# Dry run (preview output)
shellforge build -c config/shellrc -m manifest.yaml --auto-output --dry-run

# Verbose output
shellforge build -c config/shellrc -m manifest.yaml --auto-output -v

Template

Generate new modules from common patterns:

# List available templates
shellforge template list

# Generate PATH module
shellforge template generate path my-custom-bin \
  -f path_dir=/opt/myapp/bin \
  -f description="My custom application binaries"

# Generate environment variable
shellforge template generate env EDITOR \
  -f var_name=EDITOR \
  -f var_value=vim \
  -f description="Set default editor"

# Generate aliases
shellforge template generate alias git-shortcuts \
  -f description="Git command shortcuts" \
  -f aliases="alias gs='git status'
alias gp='git push'
alias gl='git pull'"

# Generate tool initialization with dependencies
shellforge template generate tool-init nvm \
  -f tool_name=nvm \
  -f tool_command=nvm \
  -f init_command='eval "$(nvm init -)"' \
  -f description="Node Version Manager" \
  -r brew-path

# Interactive mode (prompts for all fields)
shellforge template generate env MY_VAR -i

# Generate in specific directory
shellforge template generate path custom-bin \
  -c ~/dotfiles/shellrc \
  -f path_dir=/usr/local/mybin \
  -f description="Custom binaries"

Available templates:

  • path - Add directory to PATH (init.d/)
  • env - Set environment variable (rc_pre.d/)
  • alias - Define shell aliases (rc_post.d/)
  • conditional-source - Source file if it exists (rc_pre.d/)
  • tool-init - Initialize development tool (rc_pre.d/)
  • os-specific - OS-specific configuration (rc_pre.d/)

Info

Show shell configuration file information:

# macOS zsh interactive shell
shellforge info --os macos --shell zsh --session interactive

# Ubuntu bash login shell
shellforge info --os ubuntu --shell bash --session login

# Arch zsh (always sourced)
shellforge info --os arch --shell zsh --session always

# Fish shell (all platforms, session type is always 'always')
shellforge info --os macos --shell fish --session always
shellforge info --os ubuntu --shell fish --session always

Validate

Check manifest and module files:

shellforge validate -c config/shellrc -m manifest.yaml

Migrate

Convert traditional RC file to shellforge structure:

# Migrate existing .zshrc to shellforge modules
shellforge migrate -s ~/.zshrc -t config/shellrc

# Preview migration without writing files
shellforge migrate -s ~/.zshrc -t config/shellrc --dry-run

# Migrate without backup
shellforge migrate -s ~/.zshrc -t config/shellrc --no-backup

# Migrate without auto-generating manifest
shellforge migrate -s ~/.zshrc -t config/shellrc --no-manifest

What it does:

  • Analyzes your existing RC file and identifies logical sections
  • Automatically categorizes sections into init.d/, rc_pre.d/, or rc_post.d/
  • Creates modular shell scripts for each section
  • Creates backup of original file (default)
  • Auto-generates manifest.yaml (default)

Example workflow:

# 1. Migrate existing .zshrc
shellforge migrate -s ~/.zshrc -t ~/dotfiles/shellrc

# 2. Review migrated modules
ls ~/dotfiles/shellrc/*/

# 3. Validate
shellforge validate -c ~/dotfiles/shellrc -m ~/dotfiles/shellrc/manifest.yaml

# 4. Build and test
shellforge build -c ~/dotfiles/shellrc -m ~/dotfiles/shellrc/manifest.yaml --auto-output --dry-run

Diff

Compare generated configuration with existing RC file:

# Auto-detect existing RC file based on OS/shell
shellforge diff -c config/shellrc -m manifest.yaml --auto-detect-existing

# Compare with specific file
shellforge diff -c config/shellrc -m manifest.yaml -e ~/.zshrc

# Show detailed unified diff
shellforge diff -c config/shellrc -m manifest.yaml \
  --auto-detect-existing --format unified

# Context diff format
shellforge diff -c config/shellrc -m manifest.yaml \
  --auto-detect-existing --format context

# Summary only (default)
shellforge diff -c config/shellrc -m manifest.yaml \
  --auto-detect-existing --format summary

Output formats:

  • summary: Statistics about differences (default)
  • unified: Standard unified diff format
  • context: Context diff format

List Modules

Show modules in load order:

# Current OS
shellforge list-modules -c config/shellrc -m manifest.yaml

# Specific OS
shellforge list-modules -c config/shellrc -m manifest.yaml --os Linux

Manifest Format

modules:
  - name: module-name          # Unique identifier
    file: path/to/module.sh    # Relative to config-dir
    requires: [dep1, dep2]     # Dependencies (optional)
    os: [Mac, Linux]           # Supported OS (optional)
    description: What it does  # Description (optional)

Example Manifest

See examples/manifest.yaml for a complete example.

Project Structure

your-dotfiles/
├── config/
│   └── shellrc/
│       ├── init.d/
│       │   ├── 00-os-detection.sh
│       │   └── 05-brew-path.sh
│       ├── rc_pre.d/
│       │   ├── conda.sh
│       │   └── nvm.sh
│       └── rc_post.d/
│           └── aliases.sh
└── manifest.yaml

Features

Shell Configuration Metadata

Shellforge includes comprehensive metadata about shell configuration files for different operating systems and session types.

Supported Operating Systems:

  • macOS
  • Ubuntu
  • Debian
  • Arch Linux
  • Manjaro Linux

Supported Shells:

  • Zsh (~69% market share) - Default on macOS
  • Bash (~17% market share) - Most widely available
  • Fish (~6% market share) - Modern, user-friendly shell

Session Types:

  • login: Login shells (TTY, SSH, Terminal.app on macOS) - bash/zsh
  • interactive: Interactive non-login shells (most terminal emulators) - bash/zsh
  • always: Always sourced - zsh (via .zshenv) and fish (all invocations)
  • gui: GUI desktop environment startup

Note on Fish Shell: Fish does not distinguish between login/non-login or interactive/non-interactive shells. All fish shells load the same configuration files, so use --session always for fish.

The metadata includes:

  • Which files are loaded in which order
  • System-wide vs user-specific files
  • File alternatives (e.g., .bash_profile OR .bash_login OR .profile)
  • Recommended build targets for each environment

Use shellforge info to explore the metadata for your environment.

Automatic Dependency Resolution

Shellforge builds a dependency graph and uses topological sorting to ensure modules are loaded in the correct order.

modules:
  - name: gcloud
    requires: [brew-path]  # Will be loaded after brew-path

  - name: brew-path
    requires: []           # Loaded first

OS Filtering

Only include modules for the target OS:

modules:
  - name: brew-path
    os: [Mac]            # Only on macOS

  - name: pacman-setup
    os: [Linux]          # Only on Linux

  - name: common-aliases
    os: [Mac, Linux]     # Both

Circular Dependency Detection

Shellforge detects and reports circular dependencies:

$ shellforge validate -c config -m manifest.yaml
✗ Validation failed:
  - Circular dependency detected: 'module-a' -> 'module-b' -> 'module-a'

Development

Setup

# Clone repository
git clone git@github.com:Gizzahub/gzh-cli-shellforge.git
cd gzh-cli-shellforge

# Quick setup (creates venv and installs dependencies)
make dev-setup

# Or manual installation
uv pip install -e ".[dev]"

Available Make Commands

make help              # Show all available commands

# Installation
make install           # Install in development mode
make install-system    # Install system-wide
make install-dev       # Install with dev dependencies

# Testing
make test              # Run all tests
make test-coverage     # Run tests with coverage report

# Code Quality
make lint              # Check code style (no changes)
make lint-fix          # Auto-fix lint issues
make lint-strict-fix   # Strict lint with auto-fix

# Build
make build             # Build package
make clean             # Clean build artifacts

Run Tests

make test
# or directly
uv run pytest -v

Lint

make lint-fix
# or directly
uv run ruff check . --fix
uv run ruff format .

Integration with Chezmoi

You can use Shellforge with Chezmoi for multi-machine dotfile management:

# Build config
shellforge build -c config/shellrc -m manifest.yaml -o ~/.zshrc

# Add to Chezmoi
chezmoi add ~/.zshrc

# Apply to other machines
chezmoi apply

License

MIT

Contributing

Contributions welcome! Please open an issue or PR.

Documentation

Related Projects

Part of gzh-cli Series

Other tools in the gzh-cli series:

  • gzh-cli-shellforge - This project
  • More coming soon...

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gz_shellforge-0.3.2.tar.gz (108.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gz_shellforge-0.3.2-py3-none-any.whl (35.0 kB view details)

Uploaded Python 3

File details

Details for the file gz_shellforge-0.3.2.tar.gz.

File metadata

  • Download URL: gz_shellforge-0.3.2.tar.gz
  • Upload date:
  • Size: 108.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gz_shellforge-0.3.2.tar.gz
Algorithm Hash digest
SHA256 52937ae8843cdd99d30c11ed54f340ed7fa9ae31eb2cedc6c3750fb1b277366d
MD5 a707ae7e7a55d6ec8edc5e4013995c55
BLAKE2b-256 f2b7db46ac56f60015a8d56244051cbca8128d543f478a162c895b52fe8d5f04

See more details on using hashes here.

File details

Details for the file gz_shellforge-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: gz_shellforge-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 35.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gz_shellforge-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 77b3a15efccb69c99a5a6b904a19f18cc6e13e152c63f2f35aa8addda377a9a4
MD5 e16c65f44af3a167c659997474eb92f7
BLAKE2b-256 ee9e5e8eb8336d37b1a6025ef7b8387792c5f9370e1da73f793a8f32595cf52f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page