Jhol
A fast, offline-friendly package manager that plays nice with your existing package.json. It caches everything it can and runs without Node, Bun, or npm for install, doctor, and audit by default.
See also: CHANGELOG.md for latest release notes.
Why use Jhol?
- No Node/Bun/npm required – Install, lockfile-only, doctor, and audit use the npm registry and OSV API directly. Use
--fallback-backendto fall back to Bun/npm if needed. - Fast installs – Once a package is in the cache, repeat installs skip the network. Same lockfile? You’re basically done.
- Offline-friendly – No internet? No problem. If it’s cached, you can install it.
- Fallback optional – Pass
--fallback-backendto use Bun or npm when native install fails. - Doctor –
jhol doctorshows what’s outdated;jhol doctor --fixupdates those packages. - Audit & SBOM –
jhol auditchecks for known vulnerabilities;jhol sbomspits out a software bill of materials for your project. - Workspaces – Use
--all-workspacesand it’ll run install, doctor, or audit across all your workspace packages in one go.
Installation
From crates.io:
From source:
Prebuilt binaries (Linux & Windows):
Grab jhol-linux or jhol-windows.exe from Releases.
On Linux: chmod +x jhol-linux and optionally move it into your PATH.
On Windows: run it or add its folder to your PATH.
Put jhol on your PATH (any install method):
Quick start
Commands (the important ones)
| What you want | Command |
|---|---|
| Install packages | jhol install <pkg> [pkgs...] or just jhol install (from package.json) |
| Ignore cache and fetch fresh | jhol install --no-cache <pkg> |
| Only update the lockfile | jhol install --lockfile-only |
| Offline only (fail if not cached) | jhol install --offline or set JHOL_OFFLINE=1 |
| Strict lockfile (fail if out of sync) | jhol install --frozen |
| CI strict install | jhol ci |
| Use Bun/npm when native fails | jhol install --fallback-backend |
| Script policy for fallback backend | jhol install --no-scripts (default) or jhol install --scripts |
| Check outdated deps | jhol doctor |
| Update outdated deps | jhol doctor --fix |
| Run in all workspaces | jhol install --all-workspaces, jhol doctor --all-workspaces, jhol audit --all-workspaces |
| Security audit | jhol audit / jhol audit --fix |
| CI vulnerability gate | jhol audit --gate |
| Generate SBOM | jhol sbom or jhol sbom -o sbom.json |
| List cache | jhol cache list |
| Cache size | jhol cache size |
| Prune old cache | jhol cache prune or jhol cache prune --keep 50 |
| Export deps for offline | jhol cache export ./my-bundle |
| Import from bundle | jhol cache import ./my-bundle |
| Wipe cache | jhol cache clean |
| Lockfile hash (for CI cache key) | jhol cache key |
| Prefetch deps into cache (no node_modules) | jhol prefetch then jhol install --offline |
| Install the binary to PATH | jhol global-install |
Use -q or --quiet when you want less noise. Use --json on install, doctor, or audit if you need machine-readable output.
Configuration
| Env / file | What it does |
|---|---|
JHOL_CACHE_DIR |
Where to put the cache (default: ~/.jhol-cache on Unix, %USERPROFILE%\.jhol-cache on Windows) |
JHOL_LOG=quiet or -q |
Less logging |
JHOL_OFFLINE=1 or --offline |
Only use cache; fail if something isn’t there |
JHOL_SCRIPT_ALLOWLIST=a,b,c |
If --scripts is used, only allow scripts for these packages |
.jholrc (JSON in project or home) |
Optional: set backend ("bun" or "npm"), cacheDir, offline, frozen so you don’t have to pass flags every time |
CI tip: Run jhol cache key to get a hash of your lockfile (bun.lock or package-lock.json). Same lockfile → same key. Use that as your CI cache key so you can reuse the Jhol store between runs.
Deterministic installs (CI)
With a lockfile and jhol install --frozen (or jhol ci), Jhol does no resolution and no packument requests: it only downloads missing tarballs (from lockfile URLs) and links or extracts from the store. Recommended for CI. Use jhol cache key as your cache key so the same lockfile reuses the same store.
--json responses for install, doctor, audit, and ci now include a stable shape with schemaVersion, command, and status.
How it fits together
The repo is a Cargo workspace: the jhol binary lives at the root and talks to jhol-core in crates/jhol-core. The core does the real work (cache, install, doctor, registry, lockfile, audit, workspaces); the CLI just parses args and calls in. You can depend on jhol-core from other tools (e.g. a script or a future LSP) without pulling in the CLI.
Performance benchmarking
Jhol includes a simple benchmark harness at scripts/benchmark.py to measure install performance.
What it measures
jhol_cold_install: empty cache + installjhol_warm_install: cached installjhol_offline_install: cached install in--offlinemode- Optional:
npm_cold_install/npm_warm_installwith--compare-npm
Run it
Optional npm comparison:
Tip: use exact versions in --packages for stable and repeatable results.
Regression check against baseline
Use the baseline in benchmarks/baseline.json and fail if a metric regresses beyond threshold:
--threshold 0.25 means up to 25% slowdown is allowed before failing.
Compatibility & current limitations
What is stable today
- Native install flow with npm registry metadata + tarball extraction
- Cache-first and offline workflows (
prefetch,install --offline) - Lockfile-aware deterministic installs (
--frozen) - Workspace traversal for install/doctor/audit/run
Known limitations (to improve next)
- Dependency resolution is currently a greedy strategy (single version preference) and may differ from npm behavior on complex trees.
- Some advanced npm ecosystem edge cases (complex peer dependency graphs, rare postinstall assumptions) are not fully parity-tested yet.
- Benchmarking is available and automated in CI with a threshold gate, but baseline tuning per environment/project profile is still evolving.
If you hit an issue, please open one with the failing package graph and lockfile for fastest debugging.
Links
- Crate: crates.io/crates/jhol
- Releases: GitHub Releases
License
Jhol is licensed under the Jhol License (personal and non-commercial use). For other use, contact bhuvanstark6@gmail.com.