Umbrella project that manages multiple subdomain sites under *.binaryage.com as git submodules.
For detailed technical documentation, AI agent guidelines, and advanced workflows, see CLAUDE.md
- mise - Version manager for Ruby and Node.js
- Ruby 3.4.7
- Node.js 22.21.1
- nginx - Proxy server for local development
- npm - Node.js package manager (ships with Node.js)
git clone git@github.com:binaryage/site.git
cd site
mise install # Install Ruby & Node.js versions
rake init # Initialize submodules, install dependenciesFor the best developer experience, enable automatic mise activation so Ruby and Node.js are available without manual intervention:
Option 1: Shell Integration (Recommended)
Add mise activation to your shell profile:
# For Zsh (add to ~/.zshrc)
eval "$(mise activate zsh)"
# For Bash (add to ~/.bashrc or ~/.bash_profile)
eval "$(mise activate bash)"
# For Fish (add to ~/.config/fish/config.fish)
mise activate fish | sourceAfter adding this, restart your shell or run source ~/.zshrc (or your shell's config file).
Option 2: direnv Integration
If you prefer direnv, mise can integrate with it:
# 1. Install direnv (if not already installed)
brew install direnv
# 2. Add direnv hook to your shell
# For Zsh (add to ~/.zshrc)
eval "$(direnv hook zsh)"
# For Bash (add to ~/.bashrc)
eval "$(direnv hook bash)"
# 3. Create .envrc in the project (already exists)
# mise will automatically work with direnv via .mise.toml
# 4. Allow direnv for this directory
direnv allowVerification:
After setup, verify automatic activation works:
cd /path/to/site
ruby --version # Should show 3.4.7 automatically
node --version # Should show 22.21.1 automaticallyWithout activation, you'd need to manually run mise exec -- command for every command.
# Terminal 1: Start nginx proxy (requires sudo for port 80)
rake proxy
# Terminal 2: Start Jekyll development server with live reload
rake serve # Serve all sites (default)
rake serve what=www,blog # Serve only specific sitesMake sure /etc/hosts is configured first: rake hosts
Access sites at:
rake build # Build all sites for production
rake build what=www,blog # Build specific sites
rake test:smoke # Run automated smoke testsrake status # Check git submodule status
rake pin # Fix detached HEAD - checkout branch tips after git pull/submodule update
rake shared:sync # Sync shared resources across all sites
rake remotes:list # Show git remote URLs for all sites
rake remotes:ssh # Convert all remotes to SSH format
rake screenshot:create name=X # Create screenshot baseline
rake screenshot:diff name=X # Compare screenshotsUse the /commit-site command for intelligent submodule commits:
/commit-site # Interactive picker - auto-detects sites with changes
/commit-site www # Commit changes in specific site
/commit-site www blog # Commit multiple sites
/commit-site all # Commit all sites with changesThis command intelligently handles both shared pointer updates and regular file changes, generating appropriate commit messages automatically. See CLAUDE.md for details.
- www - Main binaryage.com site
- blog - Blog subdomain
- support - Support site (redirects to discuss.binaryage.com)
- Products: totalfinder-web, totalspaces-web, totalterminal-web, asepsis-web, visor
- Tools: firequery, firerainbow, firelogger, xrefresh
Each site is a separate git repository tracked as a submodule.
shared/ directories across all submodules point to the SAME git repository (binaryage/shared).
This means:
- Single source of truth: One repository contains all shared layouts, CSS, and JavaScript
- Edit once: Changes to shared resources only need to be made in ONE place
- Sync across sites: Use
rake shared:syncto propagate commits to all sites
Shared repository contains:
layouts/- Jekyll layout filesincludes/- Includes for layoutscss/- Shared CSS (plain CSS with modern features, bundled via Lightning CSS)js/- Shared JavaScript (concatenated and minified)img/- Shared images
Typical workflow:
# 1. Make changes in any shared directory (typically www/shared)
cd www/shared
# ... edit files ...
git commit -m "Update layout"
# 2. Sync to all other sites
cd ../..
rake shared:sync
# 3. (Optional) Push shared changes when ready
cd www/shared
git push origin masterLevel 1 - Root-level submodules (www, blog, totalfinder-web, etc.):
- ❌ DO NOT manually commit pointer updates in the main
siterepository - The
hookgundeployment hook automatically updates these - Ignore "modified: www (new commits)" messages in git status
Level 2 - Shared submodule (shared/ inside each website):
- ✅ DO manually commit pointer updates in each website repository
- Each website tracks which version of shared it uses
- After updating shared:
git add shared && git commit -m "Update shared"
rake status # Check all submodules (shows issues only)
rake status verbose=1 # Full details for all submodules
rake pin # Pin all submodules to latest branch tips
rake shared:sync # Sync shared commits across all sites
rake remotes:list # Show remote URLs for all sites
rake remotes:ssh # Convert all remotes to SSH format
rake hooks:install # Install pre-push hooks (auto-installed during rake init)
rake hooks:status # Check hook installation statusThe repository includes a pre-push git hook that prevents accidentally pushing website changes with unpushed shared submodule commits. The hook:
- Automatically installed during
rake init - Only checks when pushing to
webbranch - Auto-fetches to verify shared commits are on GitHub
- Shows clear error messages with guidance
- Can be bypassed with
git push --no-verifyif needed
See CLAUDE.md for detailed documentation.
Standard deployment flow:
- Make changes in a subsite repository
- Push to the
webbranch - The
hookgunhook automatically builds and deploys to GitHub Pages - Root-level submodule pointer automatically updated
hookgun is maintained outside this repository (BinaryAge's deployment infrastructure). If you need to audit or adjust it, coordinate with the infrastructure team—the scripts are not stored in site/.
Important: When modifying shared resources, always push shared changes before pushing website changes.
If commands fail with Ruby/Node version errors:
First, verify mise is working:
mise --version # Verify mise is installed
mise install # Install Ruby & Node.js
mise current # Check active versionsRecommended: Set up automated mise activation (see "Automated mise Activation" section above) to avoid needing mise exec -- prefixes.
Without activation, you must explicitly use mise:
mise exec -- ruby --version # Should show 3.4.7
mise exec -- node --version # Should show 22.21.1
mise exec -- bundle exec rake build # Correct way to run rake tasksWith activation (shell integration or direnv), commands work directly:
ruby --version # Should show 3.4.7 automatically
node --version # Should show 22.21.1 automatically
rake build # Just worksgem install bundler
bundle installNever use sudo - mise installs gems in user space.
Tip: macOS ships Bundler 1.x by default. Run all Ruby commands through mise (e.g.
mise exec -- bundle exec rake -T) so Bundler 2 from your managed toolchain is used and you avoid the "You must use Bundler 2" error.
sudo rake proxy # nginx requires sudo for port 80
rake hosts # Show required /etc/hosts entrieslsof -i :80 # Check nginx port
lsof -i :4101 # Check Jekyll portsIn rare cases where you need to completely reset your workspace to match remote state (e.g., corrupted git state), use manual git commands instead of an automated task for safety:
Reset a single site:
cd www # Navigate to the site
git checkout -f web # Force checkout web branch
git reset --hard origin/web # Hard reset to remote state
git clean -f -f -d # Remove untracked files
git pull origin web # Pull latest changes
# Also reset the shared submodule if needed:
cd shared
git checkout -f master
git reset --hard origin/master
git clean -f -f -d
git pull origin masterReset all sites (if you're absolutely sure):
# Reset all site submodules using git submodule foreach
git submodule foreach '
echo "Resetting $(basename $PWD)..." &&
git checkout -f web &&
git reset --hard origin/web &&
git clean -f -f -d &&
git pull origin web &&
if [ -d shared ]; then
cd shared &&
git checkout -f master &&
git reset --hard origin/master &&
git clean -f -f -d &&
git pull origin master
fi
'Less destructive alternatives:
Before resorting to a full reset, consider these safer options:
rake pin- Fix detached HEAD without losing changesgit reset --hard origin/web- Reset just one sitegit stash- Save changes temporarily before resetting- Manual
git checkout- Discard changes to specific files only
Automated browser tests verify all sites load correctly:
rake build
rake serve:build # Start static server on port 8080
rake test:smoke # Run testsVisual regression testing with full-page screenshots:
rake screenshot:create name=baseline desc="Before changes"
# ... make changes ...
rake build
rake screenshot:diff name=baseline open=1Snapshot system verifies build output hasn't changed unexpectedly:
rake snapshot:create name=baseline desc="Before refactoring"
# ... make changes ...
rake build
rake snapshot:diff name=baselineFor comprehensive documentation including:
- AI agent guidelines
- All rake tasks with examples
- Configuration files reference
- IDE setup (RubyMine, WebStorm)
- Advanced workflows
- Detailed architecture
- Complete troubleshooting guide
See CLAUDE.md
- Jekyll - Static site generator
- Lightning CSS - CSS bundling, nesting transformation, and minification
- Terser - JavaScript minification
- Playwright - Browser automation & testing
- ODiff - Visual diff for screenshots
- mise - Version management
- nginx - Development proxy server
Individual sites have their own licenses. Check each submodule repository.