Skip to main content
Beekeeper Docs

Configuration

Layered config, fail mode, policy-as-code, sensitive paths, install posture, auto-quarantine, and the local corpus.

Beekeeper reads a layered JSON config and declarative policy files. This page covers each layer, the fail-closed posture, sensitive-path enforcement, and install posture.

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 the agent-cloned repository Beekeeper exists to police. Beekeeper honors it for most settings, with one hardening exception: install-posture overrides from the project (or environment) layer are tighten-only. An untrusted repo can raise a posture rule from warn to block, but it can never lower a rule back to warn or add a posture allow exemption, so it cannot silently loosen 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 runs 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.

The hourly heartbeat is not the fetch rate

The installed schedule wakes Beekeeper every hour, but Beekeeper does not fetch every hour. The hourly job is a heartbeat. Each run checks an interval gate first: if interval has not elapsed since the last successful sync, the run prints sync skipped: not due and exits. With the default 2h you fetch at most once every two hours, and the wake-ups in between do nothing.

The heartbeat stays hourly on purpose. It keeps the worst-case lag low without rewriting the operating system schedule each time you change interval. Change the cadence here or in the dashboard, and the same heartbeat honors it.

Install the schedule with beekeeper catalogs daemon install (a systemd user timer, a macOS LaunchAgent, or a Windows current-user scheduled task, all unprivileged). The scheduled run uses catalogs sync --background, which hides the console on Windows and writes every run to a rotating <state>/logs/sync.log. Sync uses conditional ETag requests, so an unchanged feed is nearly free. Check the last result with beekeeper catalogs status.

Like install posture, 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.

Catalog source settings

Two optional blocks tune the threat-intel sources.

Socket source token. Socket is one of the three corroboration sources, but it stays disabled until you supply an API token. Register at socket.dev, then:

{
  "socket": {
    "api_token": "sk_..."
  }
}

An empty or absent token disables the Socket source gracefully (it is not an error); Beekeeper runs with the remaining sources. Without it you have two corroboration sources, not three. Set it if you rely on the two-source block threshold.

beekeeper-self feed overrides. The self_catalog block overrides the compiled-in beekeeper-self compromise feed (see Security). Both fields are optional; leave them empty to use the defaults baked into the binary.

{
  "self_catalog": {
    "url": "https://...",
    "pub_key": "<base64 ed25519 public key>"
  }
}

pub_key overrides the Ed25519 key used to verify the feed signature.

LlamaFirewall

The opt-in prompt-injection sidecar (see Security and the CLI Reference) reads its tunables from the llamafirewall block:

{
  "llamafirewall": {
    "enabled": false,
    "sample_rate": 1.0,
    "fail_mode": "closed",
    "codeshield": true,
    "codeshield_action": "warn",
    "python_path": "python3"
  }
}
  • enabled (default false) starts the sidecar. beekeeper llamafirewall enable and disable flip this for you.
  • sample_rate (default 1.0) is the fraction of tool calls forwarded to the scanner, from 0.0 to 1.0.
  • fail_mode (default closed) governs sidecar-crash behavior independently of the top-level fail_mode: closed blocks, open allows, warn allows with a surfaced warning.
  • codeshield (default true when enabled) toggles the CodeShield unsafe-code scanner; codeshield_action is warn (default) or block.
  • python_path (default python3) selects the interpreter used to launch the sidecar.

There is no beekeeper config set command for these keys: edit config.json and confirm it loads cleanly with beekeeper diag.

Other settings

  • watch.directories is an optional list of extra extension directories for beekeeper watch and the scan layer to monitor, in addition to the auto-detected editor paths. beekeeper init registers detected editor directories here for you.

    {
      "watch": {
        "directories": ["/path/to/extensions"]
      }
    }
  • redact_patterns is accepted in the schema for future custom audit-redaction rules but is not yet applied in this release. The built-in redaction patterns (Bearer tokens, JWTs, and common API-key prefixes) always run regardless of this field.

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, but you do not have to hand-edit JSON: open beekeeper dashboard --admin, press s for the first-responder settings panel, and toggle enabled / dry_run or adjust threshold there. The panel validates the change and writes config.json for you (an out-of-range threshold is rejected before it is saved). You can still edit config.json directly if you prefer, then confirm it 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. The two knobs you are likely to change, enabled and downstream_clean_days, are editable from the same first-responder settings panel (beekeeper dashboard --admin, then s), which validates and writes config.json for you. path and scope stay file-only: path is an advanced override, and scope's only functional value is org_only (community_shareable is reserved and has no effect this release). 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.

Install posture

Beekeeper enforces a default install posture at the agent pre-exec hook. Three rules evaluate every package install an agent runs: release age (a package first published less than 24 hours ago warns), lifecycle scripts (an install that would run pre or post-install scripts warns), and git or remote-URL dependencies (a dependency pulled from a git ref or arbitrary URL instead of a registry warns). All three warn by default and fail soft: an unknown answer (a registry timeout, a missing publish timestamp) warns rather than blocks, so a slow or offline check never stops an agent. The checks are tool agnostic: they apply at the hook regardless of which package manager the agent reaches for.

npm v12 blocks install lifecycle scripts by default, so the old steer-to-pnpm-or-Bun nudge is no longer the headline win. Install posture is the tool-agnostic successor: it applies the same structural checks to every package manager, at the hook. The package-manager nudge was removed in v1.1.0.

The three rules

RuleKeyDefaultFires when
Release agerelease-agewarnThe package's first publish is younger than 24 hours. An unknown publish time warns (fail soft).
Lifecycle scriptslifecyclewarnThe install would run a pre or post-install lifecycle script.
Git / remote-URL dependencygit-remotewarnA dependency resolves from a git ref or arbitrary URL instead of a registry.

A definite violation of a rule that has been opted up to block (see below) is blocked. The unknown / fail-soft path always warns regardless, so a registry outage never blocks an install even under block.

Scoped overrides and per-rule opt-up

Posture overrides are made with the beekeeper posture CLI, not config set (there are no settable posture keys; the overrides are stored in the posture block and written through audited commands). The two surfaces:

beekeeper posture allow <package> --once
beekeeper posture allow <package> --always --reason "internal mirror"

posture allow is posture-scoped: it silences a posture warn for the named package but never downgrades a catalog or corroboration malware block for the same package. It appends to the posture allow list, not the general package_allowlist. You can scope an allow to one rule (--rule release-age | lifecycle | git-remote) or one ecosystem (--ecosystem npm).

beekeeper posture enforce release-age --block
beekeeper posture enforce release-age --warn

posture enforce --block opts a single rule up from the default warn to block; --warn lowers it back. Per-rule opt-up is tighten-only from untrusted layers: a project or environment layer may raise a rule to block but never lower it, and the unknown / fail-soft path stays warn even under block. Each override writes a distinct posture_override audit record (see Audit log).

Enforcement boundary

Install posture is enforced pre-execution at the agent hook, inheriting each harness tier's caveats. For harnesses with no pre-exec hook, and for installs a person runs directly in a terminal, the Sentry layer observes and audits the install rather than preventing it. See Security for the full enforcement boundary, including the experimental package-manager shim.

See the CLI Reference for the full beekeeper posture surface.

On this page