npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hyperdrive.bot/airlock-cli

v0.1.25

Published

Airlock CLI — multi-tenant secrets vault with a just-in-time access broker for AI agents

Readme

@hyperdrive.bot/airlock-cli

airlock — the CLI for Airlock, a multi-tenant secrets vault with a just-in-time access broker for AI agents.

Part of the @hyperdrive.bot product family. Backend + CLI design: docs/architecture/AIRLOCK-BACKEND-CLI-ARCHITECTURE.md.

Two planes

Airlock has two user planes, and the CLI auto-detects which one you're on by the token class (not by a flag or by CI):

| Plane | Trigger | Auth | Plaintext access | |---|---|---|---| | Human | default | Cognito OAuth PKCE → SigV4 (auth login) | direct reveal (policy-gated, audited) | | Agent | AIRLOCK_TOKEN starts with alk_agt_ | Bearer token | only via an approved, single-use grant |

A human running in CI with a Cognito session is still on the human plane; an agent on a laptop with an alk_agt_ token is still on the agent plane.

Install

npm install -g @hyperdrive.bot/airlock-cli
airlock auth login --domain <your-tenant-domain>   # e.g. acme.airlock.it.com

--domain is not optional in practice. The CLI resolves its bootstrap URL in this order: AIRLOCK_BOOTSTRAP_URL~/.airlock/config.json → the tenant domain you pass → a baked-in default. That baked-in default points at dev/us-east-1, so a bare airlock auth login against a live tenant talks to the wrong environment. Passing --domain is what makes the third rule fire, and it is the only step a new install needs.

If you would rather pin it once instead of passing the flag every time:

airlock auth init --bootstrap-url https://<your-tenant-domain>/tenant/bootstrap

Human workflow

airlock auth login --domain <your-tenant-domain>   # Cognito PKCE (opens a browser)
airlock credentials set prod/stripe --value sk_live_…
airlock credentials list
airlock get prod/stripe                  # direct reveal (audited)
airlock credentials rotate prod/stripe --value sk_live_new…

Approve / deny agent requests:

airlock approve req_01H… --otp 123456
airlock deny req_01H…

Manage agent tokens:

airlock agent issue --name ci-bot --scope "prod/*"   # raw token shown ONCE
airlock agent list
airlock agent revoke agt_01H…

Bulk-import from 1Password (via the op CLI):

op signin                                                          # a 1Password session is required
airlock credentials import --vault Engineering --dry-run           # preview the plan (values masked)
airlock credentials import --vault Engineering --prefix prod --yes # create them

Each 1Password item maps to a credential: name ← item title, path[prefix/]<slug(title)>, value ← the item's password/credential field (auto-detected, or pick one with --field <id>), tags ← the item's 1Password tags, policyTier--tier (default always-approve). Use --filter-tag to import only tagged items. Secret values are never printed, logged, or written to disk.

Agent workflow: airlock run (the agent never sees the secret)

An agent uses airlock run. It must never call airlock get.

get reveals plaintext to whoever ran it. That is fine for a human at a terminal; for an agent it means the secret enters the process, the logs and the transcript. run exists so it does not have to: the broker starts a local injecting proxy, the child process is handed a localhost base URL, and the real credential is attached only on the proxy→upstream leg.

export AIRLOCK_TOKEN=alk_agt_…
airlock run stripe-charge --arg amount=4200 --reason "refund #1234"
# → creates an access request, notifies a human approver, waits for approval,
#   then runs the verb's command with the secret injected ON THE WIRE.
#   The child gets a localhost URL, never the bytes. No standing access.

The command itself lives in the verb, not on your command line: the verb's command[] is templated with {{base}} (the proxy URL) and {{yourArg}} placeholders, which --arg key=value fills in. That is deliberate. If the caller could supply an arbitrary command, the caller could choose where the credential goes.

The secret is never in the child's environment, argv, or stdout. That is enforced, not aspirational: npm run test:smoke asserts it on every change.

Verbs are authored by a human, on the server

A verb binds secretRef → upstream → injection. It is registered human-plane and stored server-side, and a hash of the binding is frozen into the single-use grant. The proxy injects from that pin, so an agent cannot repoint a verb at its own collector and have a real secret sent there. Tampering fails closed.

airlock verb add stripe-charge --preset stripe --secret prod/stripe   # human
airlock verb ls                                                       # read-only
airlock verb add --list-presets   # anthropic, github, gitlab, openai, sendgrid, slack, stripe

Injection modes cover more than bearer headers: query params, JSON body fields, HMAC request signing, env vars, secret-as-file, mTLS client identity, and an ssh-agent broker where the child can sign but never read the key.

Transparent mode: let the hook do it

You do not have to type airlock run at all. Install the Claude Code hook and matching commands are routed through the broker automatically:

airlock hook install            # --dry-run to preview, --uninstall to remove

It rewrites a command only when exactly one verb is pinned to the host that command targets. No match, several hosts, or two verbs claiming the same host all leave the command untouched, on purpose: an unwrapped command fails loudly and recoverably, whereas a wrongly wrapped one sends a live secret somewhere nobody chose. The install is idempotent, backs up your settings first, and appends alongside any hook you already have rather than replacing it.

A /airlock skill ships in the package too, stating the invariant an agent has to respect: use run, never get, and on denial report and stop.

airlock get (human plane only)

airlock get prod/stripe                  # direct reveal, audited

Proving it yourself

The claim is that a credential can be used without ever being seen. Three automated proofs assert it on every change, against a real proxy and a real child process:

npm run test:smoke     # no-leak (verb path) + daemon + no-leak (passthrough)

Those use a sentinel, so they never touch a real vault. To prove the whole chain against live infrastructure, including the reveal and the grant:

airlock auth login --domain <your-tenant>

# from a clone of this repo:
node scripts/live-proof.mjs <credential-path-or-credId>

# or straight from the installed package:
node "$(npm root -g)/@hyperdrive.bot/airlock-cli/scripts/live-proof.mjs" <credential-path-or-credId>

It registers a throwaway verb pinned to a local upstream, runs a real command through the broker, and asserts the credential reached the upstream and appears in none of the captured stdout, stderr, argv or environment. The upstream receives the value and performs that check itself, printing only booleans, so running the proof cannot leak what it is proving.

Worth knowing why it exists: the sentinel proofs construct the secret locally, so they all passed while a verb whose secretRef was a credential path 404'd on every real run. Only the live proof caught that.

Commands from plugins (do not hand-write)

auth login/logout/status/refresh, init, config get/set/show, and domain current/list/switch come from @hyperdrive.bot/auth-plugin. Generic vault verbs are also reachable as dynamic manifest commands via @hyperdrive.bot/cli-api-plugin.

Environment

| Var | Purpose | |---|---| | AIRLOCK_TOKEN | Agent token (alk_agt_…). Presence + prefix selects the agent plane. | | AIRLOCK_API_URL | Override the API base URL (agent plane + human plane). | | AIRLOCK_AWS_REGION | Override the AWS region for SigV4 signing. |

Build

npm install
npm run build        # tsc -b + oclif manifest
./bin/run.js --help