Gemkeeper

This project is an opinionated wrapper around Gem in a Box for managing private gem dependencies in an offline development environment.

Installation

Via RubyGems

gem install gemkeeper

Via Homebrew (MacOS)

brew tap danhorst/tap
brew install danhorst/tap/gemkeeper

Forumla: danhorst/homebrew-tap

Workstation Setup

If you cannot reach your organization's private gem server, follow these steps to use gemkeeper as a local proxy.

Prerequisites: You must have HTTPS access to the internal gem repositories on GitHub. Configure GitHub credentials before step 4 — see GitHub authentication docs.

  1. Install gemkeeper:
gem install gemkeeper
  1. Install your org's gem manifest:

Your organization should provide a command or file that writes ~/.config/gemkeeper/manifest.yml. This manifest lists the internal gems and their GitHub URLs, and may include the private gem source URL used in step 6.

  1. Generate a gemkeeper.yml for your project:
gemkeeper setup path/to/Gemfile.lock

This reads the lockfile, cross-references the manifest, and writes a gemkeeper.yml in the current directory. It also prints the bundle config command you will need in step 6.

  1. Build and cache the internal gems:
gemkeeper sync
  1. Start the local gem server:
gemkeeper server start
  1. Point Bundler at the local server using the command printed by step 3:
bundle config set --local mirror.<your-private-gem-source-url> http://localhost:9292

Replace <your-private-gem-source-url> with the gem source URL declared in your Gemfile (the one that requires VPN or private credentials). The mirror approach redirects gem resolution to your local Geminabox without modifying the committed Gemfile or Gemfile.lock. Public gems are proxied from RubyGems.org automatically.

Quick Start

  1. Create a configuration file at ~/.config/gemkeeper/config.yml:
port: 9292
gems:
  - repo: https://github.com/company/internal-gem
    version: latest
  1. Start the server:
gemkeeper server start
  1. Configure your Rails app to use the local gem server:
# Gemfile
source "http://localhost:9292" do
  gem "internal-gem"
end
  1. Sync your gems:
gemkeeper sync

Configuration

Gemkeeper looks for configuration files in these locations (in order):

  1. ./gemkeeper.yml (current directory)
  2. ~/.config/gemkeeper/config.yml
  3. ~/.gemkeeper.yml
  4. /usr/local/etc/gemkeeper.yml (Homebrew on Intel)
  5. /opt/homebrew/etc/gemkeeper.yml (Homebrew on Apple Silicon)

Configuration Options

# Port for the Geminabox server (default: 9292)
port: 9292

# Where to clone gem repositories (default: ./cache/repos)
repos_path: ./cache/repos

# Where to store built gems (default: ./cache/gems)
gems_path: ./cache/gems

# PID file location (default: ./cache/gemkeeper.pid)
pid_file: ./cache/gemkeeper.pid

# List of gems to manage
gems:
  # HTTPS is recommended — works without SSH key setup (alternative: git@github.com:company/gem-one.git)
  - repo: https://github.com/company/gem-one
    version: latest    # Use the latest commit on main/master; cached by resolved gemspec version

  - repo: https://github.com/company/gem-two
    version: v1.2.3    # Use a specific tag; both v-prefixed and bare semver accepted

  - repo: https://github.com/company/gem-two
    version: from_lockfile    # Read version from the nearest Gemfile.lock

  - repo: https://github.com/company/ruby-gem-three
    name: gem-three    # Override the gem name (strips "ruby-" prefix by default)

CLI Commands

Server Management

# Start the server (daemonized)
gemkeeper server start

# Start in foreground (for services/debugging)
gemkeeper server start --foreground
gemkeeper server start -f

# Start on a specific port
gemkeeper server start --port 8080

# Stop the server
gemkeeper server stop

# Check server status
gemkeeper server status

Project Setup

# Generate gemkeeper.yml from a Gemfile.lock and org manifest
gemkeeper setup path/to/Gemfile.lock

# Use a custom manifest path
gemkeeper setup path/to/Gemfile.lock --manifest ~/.config/myorg/manifest.yml

# Overwrite existing gemkeeper.yml entirely
gemkeeper setup path/to/Gemfile.lock --force

Gem Synchronization

# Sync all configured gems
gemkeeper sync

# Sync a specific gem
gemkeeper sync internal-gem

Other Commands

# List cached gems
gemkeeper list

# Show version
gemkeeper version

Global Options

All commands support:

--config PATH    # Use a specific config file

Running as a Service

Homebrew Services (macOS)

If installed via Homebrew:

# Start and enable at login
brew services start gemkeeper

# Stop the service
brew services stop gemkeeper

# Check status
brew services info gemkeeper

Manual Background Mode

# Start daemonized
gemkeeper server start

# Check if running
gemkeeper server status

# Stop
gemkeeper server stop

How It Works

  1. Clone/Pull: Gemkeeper clones (or pulls) gem repositories to a local cache.
  2. Build: Builds .gem files from the source at the specified version/tag.
  3. Upload: Uploads built gems to a local Geminabox server.
  4. Proxy: Geminabox proxies public gems from RubyGems.org, so you only need one gem source.

This lets you use a combination of public and private gems from a single gem source.

Development

bundle install
bundle exec rake test    # Run tests
bundle exec rubocop      # Run linter