JFrog CLI Control Manager


JFCM is a developer-first execution and observability layer for the JFrog CLI (jf). It makes CLI runs predictable and auditable across laptops and CI by controlling which binary is executed, validating behavior before rollout, and surfacing usage/performance insights.

What you get

  • Execution control: pin per project, enforce priority via a jf shim, run custom binaries safely
  • Safety before rollout: side-by-side CLI output comparison and performance benchmarking
  • Observability: usage history, stats, and replay for faster triage and support
  • Version convenience: simple installs, aliases, and latest when you need it

Key Features

  • One-command installs & switching
  • Automatic project pinning via a .jfrog-version file
  • Shell priority management with a jf shim
  • Power tools for diffing, benchmarking, and usage analytics

JFCM ensures the right jf version runs every time, locally and in CI.

Why the JFrog CLI Control Manager Exists

The JFrog CLI Control Manager (JFCM) exists primarily to simplify and centralize the challenging task of managing multiple versions of the JFrog CLI (the jf binary) across different projects and environments. Its core motivation is to solve the complexity of version control that often led to difficult, manual workarounds.

Key Reasons for JFCM's Existence

1. Eliminating manual control management challenges

JFCM was created specifically to end the need for "symlink hacking or hardcoded paths" when trying to switch between different JFrog CLI versions. It removes brittle configuration and provides a smooth jf shim for command redirection to the correct, active version, ensuring the correct binary is executed every time. This also avoids "works-on-my-machine" drift between developers and CI environments.

2. Facilitating seamless version switching and installation

Inspired by managers like nvm, sdkman, and volta, JFCM streamlines obtaining and activating versions:

  • Install any released version of the jf binary
  • Automatically fetch and use the latest version with jfcm use latest
  • Define named aliases (e.g., prod, dev) for specific versions
  • Link locally built jf binaries for testing

3. Enabling project-specific control

Different projects can rely on specific JFrog CLI versions. JFCM automatically switches the active version based on a .jfrog-version file in the current directory, ensuring the correct version is always used.

4. Supporting advanced development and DevOps workflows

Beyond basic switching, JFCM enables safer upgrades and visibility into usage:

  • Version testing and comparison: compare JFrog CLI command output between two versions with diff visualization
  • Performance benchmarking: run detailed benchmarks across multiple jf versions
  • Usage analytics: history/stats on which versions and commands are used most

5. Prioritizing and ensuring correct execution

JFCM manages shell integration and PATH priority so the managed jf has the highest precedence over system-installed versions (Homebrew or defaults), guaranteeing the active version is the one executed.

Why JFCM exists

Teams ship faster when the right binary runs, behaves as expected, and is measurable:

  • Kill manual hacks: no symlink juggling or PATH guesswork; the jf shim always points to the active build
  • Seamless switching: jfcm install <version> then jfcm use <version | alias | latest>
  • Predictable environments: auto-activate the version in .jfrog-version per repo
  • Safer upgrades: compare outputs and benchmark before adopting a new version in CI
  • Operational insight: history and stats expose adoption, hotspots, and regressions

Execution, Safety, and Observability for the JFrog CLI

jfcm is more than a version switcher: it's a versioned, observable, and safe execution layer for the JFrog CLI. It brings the rigor of nvm/pyenv/volta to DevOps workflows—tailored for artifact management and CI/CD.

Problem Landscape

  • Inconsistent jf versions across dev/staging/CI
  • Upgrade hesitancy due to fear of breaking changes
  • Performance regressions that go unnoticed
  • Hard-to-reproduce bugs in support/QA
  • Custom builds overwriting global tools
  • Manual PATH/config errors after switching

JFCM Solution

  • Version isolation per project/alias/workflow
  • Compare: command-level output diffs across versions
  • Benchmark: performance checks with stats and export
  • History: observability of versions/commands over time
  • Link: test custom/local binaries without touching global jf
  • Hooks: pre/post execution hooks for standardization

Outcome: predictable pipelines, safer upgrades, faster triage, confident feature adoption.

Value by Role

RoleWhat JFCM Enables
DevelopersProject-pinned versions; quick alias switching; safe testing of local builds.
DevOps/PlatformVersion-safe CI/CD, drift-free runners, data-driven upgrades (compare/benchmark).
QA/TestSystematic cross-version validation; regression detection before rollout.
Support/SREReproduce issues with history, diff behavior with compare, cut MTTR.
Security/ComplianceEnforce allowed versions via repo policy; audit usage via history --stats.
Enterprise AdminsOrg-wide standardization, visibility, and controlled rollouts.
R&D/Plugin DevsSandbox experimental builds with link; trace behavior over runs.

JFCM Features (Full Details)

1. Version Management

JFCM provides seamless handling and organization of JFrog CLI versions, making it easy to install, switch, and maintain different binaries:

  • Installation: Installs any released jf binary version from JFrog's public release server (e.g., jfcm install <version>)
  • Activation/Switching (use): Activates a specified version or alias (e.g., jfcm use <version or alias>). Use jfcm use latest to fetch and activate the most recent version automatically
  • Project-Specific Defaults: Automatic switching based on a .jfrog-version file in the current directory ensures consistency
  • Aliasing: Define custom aliases for specific versions (e.g., prod, dev)
  • Local Linking: Link a locally built jf binary for use via JFCM
  • Removal and Listing: jfcm remove <version>, jfcm clear, and jfcm list

2. Shell Integration and Priority Management

JFCM automatically configures your shell to ensure that managed jf binaries have the highest priority over system-installed versions. This is achieved by:

  • Creating a shim (at ~/.jfcm/shim/jf) that redirects commands to the currently active version
  • Updating the PATH environment variable to prioritize the JFCM shim directory
  • Adding a shell function for enhanced priority handling (similar to the nvm approach)

3. Advanced Comparison and Benchmarking Features

Power tools highly beneficial for development and DevOps teams:

  • Parallel Command Comparison (jfcm compare cli): Compare JFrog CLI command output between two versions simultaneously, with git-like diff visualization (side-by-side or unified), colored output, and comparison of execution timing, exit codes, and error output
  • Changelog Comparison (jfcm compare changelog): Compare release notes and changelogs between two versions
  • Performance Benchmarking (jfcm benchmark): Run detailed performance benchmarks across multiple JFrog CLI versions; configurable iterations; stats (min, max, average); exports (table, JSON, CSV)

4. Usage Analytics and Health Checks

  • Usage History (jfcm history): Tracks version usage patterns, including command timing, usage trends, most-used versions and commands. History replay allows re-executing previous commands using !\{id\}
  • Health Check (jfcm health-check): Comprehensive check covering environment, PATH, network connectivity, performance checks, and security checks. Includes --fix to address common issues

Installation

macOS (Homebrew)

brew tap jfrog/homebrew-jfrog-cli-vm
brew install jfcm

If the formula isn't immediately found:

brew search jfcm
brew install https://raw.githubusercontent.com/jfrog/homebrew-jfrog-cli-vm/main/Formula/jfcm.rb

Build from Source (macOS/Linux)

git clone https://github.com/jfrog/jfrog-cli-vm.git
cd jfrog-cli-vm
make build
make install

Requirements: Go toolchain. The make install command copies the jfcm executable to ~/.jfcm/shim. You can also run make bootstrap to ensure ~/.jfcm/shim is added to your shell's PATH.

Post-Installation and Verification

After installation, the shim directory ($HOME/.jfcm/shim) must be prioritized at the beginning of your $PATH to ensure JFCM-managed jf versions take precedence.

Verify PATH:

echo $PATH

It should start with ~/.jfcm/shim.

Verify Installation:

jfcm --help
jfcm list

Upgrade and Uninstall

Upgrade JFCM

brew upgrade jfcm  # if installed via Homebrew

Uninstall JFCM

brew uninstall jfcm  # if installed via Homebrew

Complete removal:

rm -rf ~/.jfcm

This removes all installed jf versions, shim, config, and aliases.

Managing and Upgrading the JFrog CLI (jf) Versions

Once JFCM is installed, the following commands are used to manage the versions of the jf binary:

Installing Specific Versions

To install a specific jf binary from JFrog's public release server:

jfcm install <version>

# Example:
jfcm install 2.74.0

Switching to and Activating a Version (Effectively Upgrading)

The jfcm use command is crucial for activating a version and is the primary way to "upgrade" your active jf:

# Specific version or alias
jfcm use <version or alias>   # e.g., jfcm use 2.74.0

# Latest:
jfcm use latest               # fetches/installs if necessary, and activates

Handling Project-Specific Versions

To ensure project-based version control:

# In your repo
echo "2.74.0" > .jfrog-version
# Then simply:
jfcm use

JFCM will automatically use the version specified in that file.

Health Check and Troubleshooting

To troubleshoot installation or version switching issues:

jfcm health-check --fix

This verifies the setup (including PATH configuration) and attempts to resolve common issues.

Core Commands

These commands handle installation, removal, switching, and aliasing of JFrog CLI versions.

CommandSyntax & ExampleWhat it Does & How it WorksWhen to Use It
installjfcm install <version>
(e.g., jfcm install 2.74.0)
Installs the specified version of the JFrog CLI (jf). It downloads the binary from JFrog's public release server.When you need a specific version of jf that isn't installed.
usejfcm use <version or alias>
(e.g., jfcm use 2.74.0, jfcm use latest, jfcm use prod)
Activates the given version or alias, making it the active jf binary; sets up PATH priority so JFCM-managed jf takes precedence over system versions.Switch versions; jfcm use latest auto-fetches and activates the newest (downloading if needed). If no argument is passed, it uses the version in .jfrog-version.
listjfcm listShows all installed versions of jf and indicates which one is active.Review managed versions on your system.
removejfcm remove <version>
(e.g., jfcm remove 2.72.1)
Removes a specific installed jf version.Clean up old or unused versions.
clearjfcm clearRemoves all installed versions of jf.Complete cleanup of all JFCM-managed binaries.
aliasjfcm alias <n> <version>
(e.g., jfcm alias dev 2.74.0)
Defines a named alias for a specific version.Friendly names (e.g., prod, dev) for jfcm use.
linkjfcm link --from <path> --name <n>
(e.g., jfcm link --from /Users/Jfrog/go/bin/jf --name local-dev)
Links a locally built jf so it can be used and managed via JFCM; then jfcm use <n> to activate.Developing or testing local/unreleased builds.
health-checkjfcm health-check [options]
(e.g., --fix, --verbose, --performance, --security)
Performs a comprehensive health check: install status, shim setup, PATH, network connectivity, binary execution, basic perf/security. --fix auto-resolves common issues.Initial setup verification; troubleshooting PATH/priority issues.

Advanced Features Commands

JFCM leverages multiple versions simultaneously for comparison, benchmarking, and analytics.

Compare Behavior Between Two Versions

Run the same jf command twice and diff the outputs.

jfcm compare cli <v1> <v2> -- <jf command>

# Examples:
jfcm compare cli 2.74.0 2.73.0 -- --version
jfcm compare cli prod dev -- rt ping

Features:

  • Git-like diff visualization (side-by-side or unified)
  • Colored output; compares execution timing, exit codes, and stderr
  • When to use it: version testing before upgrade; config diffs (e.g., config show); feature verification

Changelog Comparison

jfcm compare changelog <v1> <v2>

# Example:
jfcm compare changelog v2.75.1 v2.76.0

Compares release notes/changelogs between two JFrog CLI versions.

Performance Benchmarking

Run performance tests across multiple versions:

jfcm benchmark <versions> -- <command> [options]

# Examples:
jfcm benchmark 2.74.0,2.73.0,2.72.0 -- rt search "*.jar" --format csv
jfcm benchmark prod,dev -- rt upload test.txt my-repo/ --iterations 5 --detailed

Features:

  • Parallel execution; configurable iterations
  • Stats (min, max, average), performance ranking
  • Export results as table, JSON, CSV

Usage Analytics (jfcm history)

Track and analyze historical usage of jf versions.

jfcm history                 # recent usage
jfcm history --stats         # aggregate stats
jfcm history --version 2.74.0
jfcm history '!5'            # replay the command with id 5

Features:

  • Tracks usage patterns (command, version, timestamps), capped at ~1000 entries
  • Detailed stats; filter by version; history replay via !\{id\}
  • Stored at ~/.jfcm/history.json

Shell Integration & Priority Management

The core goal of JFCM's shell integration is to ensure that when you run jf, the JFCM-managed version executes, not a system-installed binary (like Homebrew or OS defaults).

When you run jfcm use <version>, it:

  1. Creates a shim at ~/.jfcm/shim/jf that redirects to the active version
  2. Updates the PATH to prioritize the JFCM shim directory
  3. Adds a shell function for enhanced priority handling (similar to the nvm approach)

Profile Snippet (Auto-Priority)

# jfcm PATH configuration - ensures jfcm-managed jf takes highest priority
export PATH="$HOME/.jfcm/shim:$PATH"

# jfcm shell function for enhanced priority (similar to nvm approach)
jf() {
    # Check if jfcm shim exists and is executable
    if [ -x "$HOME/.jfcm/shim/jf" ]; then
        # Execute jfcm-managed jf with highest priority
        "$HOME/.jfcm/shim/jf" "$@"
    else
        # Fallback to system jf if jfcm shim not available
        command jf "$@"
    fi
}

Debug Mode

export jfcm_DEBUG=1
# Will show which version is being executed
jf --version

Troubleshooting PATH Issues

If jf is still using the system version instead of JFCM-managed version:

1. Run the health check command:

jfcm health-check --fix

This will verify all aspects of JFCM setup and attempt to fix issues.

2. Check which jf is being used:

which jf
# Should show: /Users/username/.jfcm/shim/jf

3. Verify PATH order:

echo $PATH
# ~/.jfcm/shim should appear before /usr/local/bin or /opt/homebrew/bin

4. Re-run use command:

jfcm use <version>
source ~/.zshrc  # or ~/.bashrc

5. Manual PATH fix:

Add this to your shell profile:

export PATH="$HOME/.jfcm/shim:$PATH"

6. Check for shell function conflicts:

type jf
# Should show the jfcm shell function, not a system binary

Advanced Examples

Comparing Configuration Changes

# Compare configuration differences between versions
jfcm compare cli 2.74.0 2.73.0 -- config show --format json

# Check if a specific feature works across versions
jfcm compare cli old new -- rt search "libs-release-local/*.jar" --limit 5

# Compare release notes and changelogs
jfcm compare changelog v2.75.1 v2.76.0

Performance Analysis

# Benchmark search performance across versions
jfcm benchmark 2.74.0,2.73.0,2.72.0 -- rt search "*" --limit 100 --iterations 3

# Test upload performance
jfcm benchmark prod,dev -- rt upload test.txt my-repo/ --iterations 5 --detailed

Usage Analytics

# See your most used JFrog CLI commands
jfcm history --stats

# Track version adoption over time
jfcm history --version 2.74.0

Automation and CI/CD

# Export benchmark results for CI analysis
jfcm benchmark $OLD_VERSION,$NEW_VERSION -- rt ping --format json > performance.json

# Compare outputs in automated testing
jfcm compare cli baseline canary --unified --no-color -- rt search "*.jar"

# Always use the latest version in CI/CD pipelines
jfcm use latest
jf --version

Advanced Configuration in JFCM

The JFCM tool manages configuration settings related to usage tracking, performance, and installation health, allowing users to fine-tune the tool's behavior and analyze its operations.

History Management

  • History is automatically tracked in ~/.jfcm/history.json
  • The history log is limited to ~1000 entries to prevent unlimited growth
  • Tracked data includes command execution timing and associated metadata
  • Usage history provides insights into most used versions and commands
  • Options: filter by version (--version 2.74.0), show detailed statistics (--stats), or replay using !\{id\} (e.g., jfcm history '!5')

Health Check Features

Feature Category → Detailed Checks:

  • Installation Status: verifies JFCM directories, shim setup, PATH configuration
  • Priority Verification: ensures the managed jf has priority over system-installed versions
  • System Environment: checks OS compatibility, architecture, shell detection
  • Binary Execution: tests running both jfcm and jf
  • Network Connectivity: confirms reachability to GitHub API and JFrog releases infra
  • Performance & Security: includes performance checks and basic security checks (file permissions, suspicious file detection)
  • Advanced Output/Fixes: --fix auto-resolves common issues; supports JSON output for CI/CD

Performance Optimization

  • Commands are designed to run in parallel when possible to speed up comparisons and benchmarks
  • Supports configurable timeouts for long-running operations
  • Efficient diff algorithms are used when comparing large command results

Debugging and CI/CD Integration

  • Debug Mode: jfcm_DEBUG=1 reveals detailed shim execution information (which version is executed)
  • Automation: benchmark results can be exported as JSON/CSV; comparison output supports --unified and --no-color for reliable, deterministic diffs in CI

Note: The JFCM (JFrog CLI Control Manager) tool addresses the challenges of managing multiple JFrog CLI (jf) versions across projects/environments. It simplifies management, auto-installation, version switching, and analytics, drawing inspiration from nvm, sdkman, and volta.

CI/CD Tips (Quick)

Always Latest

jfcm use latest
jf --version

Baseline vs Canary

jfcm compare cli baseline canary --unified --no-color -- rt search "*.jar"

Export Performance Data

Use --format json|csv for dashboards and regression alarms.


Troubleshooting (Quick)

IssueSolution
jf resolves to system binaryEnsure ~/.jfcm/shim is first on PATH; run jfcm health-check --fix
Network or permissions issuesRerun with --verbose; verify proxy and file permissions
Local build not usedjfcm link --from /path/to/jf --name local-dev then jfcm use local-dev

Upgrade & Uninstall

Upgrade JFCM

brew upgrade jfcm

Uninstall JFCM (Homebrew)

brew uninstall jfcm

Manual Removal (Primary Method)

rm -rf ~/.jfcm

This removes:

  • All installed versions of the JFrog CLI (jf)
  • The JFCM shim (located at ~/.jfcm/shim/jf)
  • The history tracking file (~/.jfcm/history.json)
  • Config and aliases

FAQ

What is JFCM?

A version manager and, more importantly, an execution & observability layer for the JFrog CLI (jf) that installs, activates, and prioritizes specific versions.

What can JFCM do?

Auto-installation, version switching, performance benchmarking, parallel version comparison, usage analytics, safe custom binary linking, and health checks.

How do I install a specific version?

Use jfcm install <version> (for example: jfcm install 2.74.0).

How do I switch the active version?

Use jfcm use <version or alias> or jfcm use latest. With a .jfrog-version file present, jfcm use (no args) auto-activates it.

How does JFCM make sure the managed version runs?

It creates a lightweight shim at ~/.jfcm/shim/jf and updates your shell's PATH to ensure the managed version has the highest priority.

How can I see what versions are installed?

Use jfcm list to show all installed versions and the active one.

How do I remove an old version?

Use jfcm remove <version> (e.g., jfcm remove 2.72.1). To remove all installed versions, use jfcm clear.

Can I set a version for a specific project?

Yes. Add a .jfrog-version file to your repository containing the desired version number (e.g., 2.74.0), then run jfcm use.

How do I compare versions safely before upgrading?

Use jfcm compare cli <v1> <v2> -- <jf command> for behavior diffs; jfcm compare changelog to review release notes.

What is performance benchmarking used for?

jfcm benchmark runs performance tests across multiple JFrog CLI versions to detect regressions and analyze slow operations. Use --format json|csv for CI.

How do I check if my JFCM setup is working?

Run jfcm health-check. You can use the --fix option to automatically resolve common configuration issues.

How do I use a local/custom build?

jfcm link --from <path> --name local and then jfcm use local.

How do I uninstall JFCM completely?

Manually remove the installation directory using rm -rf ~/.jfcm. If installed via Homebrew, you can also use brew uninstall jfcm.