Skip to main content
Beekeeper Docs

Configuration

Layered config, fail mode, policy-as-code, sensitive paths, the package-manager nudge, auto-quarantine, and the local corpus.

Beekeeper is configured through a layered JSON config, declarative policy files, and a small set of beekeeper config set keys. This page covers each layer, the fail-closed posture, sensitive-path enforcement, and the package-manager nudge.

Config file location

OSConfig file
Linux / macOS~/.beekeeper/config.json
Windows%APPDATA%\beekeeper\config.json

Layered configuration

Config is merged from four layers, each overriding the one before it:

  1. System: machine-wide defaults
  2. User: ~/.beekeeper/config.json (or %APPDATA%\beekeeper\config.json)
  3. Project: a .beekeeper/config.json discovered by walking up from the working directory
  4. Environment: BEEKEEPER_* environment variables

The project layer is the lowest-trust file layer: it is exactly the agent-cloned repository Beekeeper exists to police. It is still honored for most settings, with one hardening exception: a project-layer attempt to disable the nudge ({"nudge":{"enabled":false}}) is refused, so an untrusted repo cannot silently turn off supply-chain enforcement. See the caveat below for the fail-mode risk that is not refused.

Fail mode

Beekeeper's default posture is fail-closed (fail_closed): any crash, timeout, oversized input, or missing/corrupt index in beekeeper check or the gateway results in a block, not an allow. Opting out (fail_mode: open, historically written fail_open) is explicit and reduces security:

{
  "fail_mode": "open"
}

Security-relevant caveat. Because the project layer is merged above user config, a project-local .beekeeper/config.json (or a dependency postinstall that writes one) containing {"fail_mode":"open"} converts every fail-closed safety net into fail-open for that working tree. Treat the project .beekeeper/config.json as security-relevant, and do not run agents in untrusted repositories with project-config discovery enabled if you rely on a fail-closed posture (see Security).

Background catalog sync

Threat-intel freshness can run on its own. Alongside the manual beekeeper catalogs sync, an unprivileged per-user daemon syncs on an interval. The default config block:

{
  "catalog_sync": {
    "enabled": true,
    "interval": "2h"
  }
}
  • enabled (default true) controls whether the installed schedule runs.
  • interval (default 2h) is clamped to a 2h to 24h range; an out-of-range or unparseable value is clamped fail-safe rather than disabling sync.

Install the schedule with beekeeper catalogs daemon install (a systemd user timer, a macOS LaunchAgent, or a Windows current-user scheduled task, all unprivileged). Sync uses conditional ETag requests, so an unchanged feed is nearly free.

Like the nudge, catalog_sync is self-defended against the project layer: an untrusted repository's .beekeeper/config.json cannot disable it or loosen the interval. Only tightening the cadence from a project layer is honored, so an agent cannot slow down or switch off threat-intel freshness from inside a repo.

Auto-quarantine (first-responder loop)

When the background sync produces a catalog delta, Beekeeper runs a read-only cross-reference of installed packages against the updated index. The auto_quarantine block controls what happens when a scan hit reaches the corroboration threshold:

{
  "auto_quarantine": {
    "enabled": false,
    "dry_run": true,
    "threshold": 2
  }
}
  • enabled (default false) is the opt-in gate. A fresh install never quarantines anything automatically.
  • dry_run (default true) controls whether a threshold hit produces a real quarantine move or only an audit record. Set both enabled: true and dry_run: false to activate live moves.
  • threshold (default 2, clamped to [1, 3]) is the minimum number of independent catalog sources required to trigger a quarantine move. A zero or absent value resolves to the default 2, not the floor 1. An out-of-range value (for example 5) is rejected at load time fail-closed, not silently clamped, so a misconfigured threshold never weakens the posture.

There is no beekeeper config set command for auto_quarantine keys. Edit config.json directly, then confirm the value loads cleanly with beekeeper diag.

What auto-quarantine does (and does not do)

When enabled and not in dry-run mode, and a scan hit reaches the threshold with a known on-disk path, Beekeeper moves the artifact to the quarantine directory as a reversible directory rename plus a restore manifest. It then writes an audit record and surfaces a TUI incident.

If the installed path cannot be resolved, a pending-quarantine record is written rather than guessing the path. No partial deletes happen on failure.

The destructive purge is never automatic. The TUI incident surfaces [P] purge (permanent) and [R] restore options. The CLI purge command requires a y/N confirmation. See Security for the full first-responder design, including the catalog-to-Sentry targeted trace that runs alongside the quarantine path.

Cross-reference with catalog_sync

The cross-reference only runs when a sync produces a delta. The catalog_sync interval (default 2h) is therefore the outer cadence. Tightening the sync interval tightens how quickly a newly-flagged installed package is noticed.

Corpus (local incident record)

The corpus block controls the local, append-only record of confirmed incidents that drives the first-responder feedback loop (see Security). It writes nothing off the machine.

{
  "corpus": {
    "enabled": false,
    "path": "",
    "downstream_clean_days": 30,
    "scope": "org_only"
  }
}
  • enabled (default false) turns the corpus store on. While off, no corpus file is written.
  • path (default empty) overrides the corpus file location. When empty, Beekeeper uses <state-dir>/corpus/beekeeper-corpus.ndjson, owner-only (0600).
  • downstream_clean_days (default 30) is the rolling window the adjudication engine waits before labelling an allowed package benign when no follow-on incident with the same cluster appears. It is the weakest benign signal and never reaches enforce weight.
  • scope (default org_only) is the record scope. community_shareable is reserved for a future milestone and has no effect in this release; promotion to it always returns an error.

Like auto_quarantine, there is no beekeeper config set command for corpus keys, so edit config.json directly. The corroboration threshold that gates the corpus-driven Sentry elevation is the same two-source bar used elsewhere; it is not a separate config key.

Policy-as-code

Declarative policy files live in ~/.beekeeper/policies/*.json (owner-only, 0600). Validate, dry-run, and list them:

beekeeper policy validate ~/.beekeeper/policies/my-policy.json
beekeeper policy test ~/.beekeeper/policies/my-policy.json --tool-call ./call.json
beekeeper policy list

A package_allowlist rule with "action":"allow" is an escape hatch: it can override a catalog-corroborated block for the exact listed package, useful for an internal package a fresh catalog source misflags. Every allowlist-override decision is recorded in the audit Reason field, so it is forensically visible. Treat ~/.beekeeper/policies/ as part of your security-relevant configuration.

Not enforced in this release: release_age, lifecycle_script_allowlist

Policy files may declare release_age (minimum package age) and lifecycle_script_allowlist rules, but these two rule types are not enforced by the policy overlay in this release; they require package-publication-age and lifecycle-script metadata that is not present in a pure tool call. They are accepted for documentation and beekeeper policy test dry-runs only, and must not be relied upon for live enforcement. The engine's built-in catalog-side release-age handling remains the enforcement path.

Sensitive paths

Beekeeper blocks agent reads (and shell-redirect writes) of credential and secret paths outside the project working directory. The default blocklist (DefaultSensitivePaths) covers:

  • ~/.ssh, ~/.aws, ~/.cargo/credentials
  • .env and .env.* globs
  • Editor MCP config directories (Cursor, Windsurf)

with normalization for Windows alternate data streams and trailing-dot tricks. Policy files can add sensitive_path rules; a sensitive-path block is merged most-restrictive-wins and can never be downgraded by a package_allowlist allow.

Package-manager nudge

The nudge steers agents away from npm / yarn toward pnpm (≥ 11) or bun (≥ 1.3), which ship structural supply-chain defenses npm does not. The default config block:

{
  "nudge": {
    "enabled": true,
    "mode": "soft",
    "require_hardened": false,
    "preferred": "pnpm",
    "check_socket_scanner": true,
    "major_drift_check": { "enabled": true, "interval": "168h" },
    "version_floors": { "pnpm": "11.0.0", "bun": "1.3.0", "node": "22.0.0" }
  }
}

Modes

nudge.mode accepts three values (any other value is rejected fail-closed by the config validator):

ModeBehavior
softDefault. Emit an advisory recommending pnpm/bun, then allow the original npm install to proceed (exit 0).
hardRewrite the command to its pnpm/bun equivalent and surface the rewrite to the agent (advisory: Beekeeper does not execute it).
blockDeny npm / yarn installs when a hardened PM is available, telling the agent to use pnpm/bun instead. Detection-independent supply-chain enforcement.

When you run beekeeper hooks install, Beekeeper enables mode: block on first install (installing the hook is an explicit "protect this machine" action). To opt down to advisory-only:

beekeeper config set nudge.mode soft

Settable keys

beekeeper config set is scoped to five nudge keys (each validated fail-closed, each change written to the audit log as a config_change record):

beekeeper config set nudge.enabled true
beekeeper config set nudge.mode hard
beekeeper config set nudge.require_hardened true
beekeeper config set nudge.preferred bun
beekeeper config set nudge.check_socket_scanner false

require_hardened: true is a separate blocking trigger from mode: block: it denies an npm install when no hardened package manager is installed at all (whereas mode: block denies npm/yarn when pnpm/bun is available and steers to it). Both default off in the shipped library; mode: block is turned on by the hook installer.

Package-manager detection is fail-open by design: a slow or missing pnpm/bun/node binary is treated as "not installed" so an advisory never blocks a legitimate install. mode: block enforcement, by contrast, is detection-independent and does not fail open.

See the CLI Reference for beekeeper nudge status / check / audit.

On this page