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
| OS | Config 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:
- System: machine-wide defaults
- User:
~/.beekeeper/config.json(or%APPDATA%\beekeeper\config.json) - Project: a
.beekeeper/config.jsondiscovered by walking up from the working directory - 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 dependencypostinstallthat writes one) containing{"fail_mode":"open"}converts every fail-closed safety net into fail-open for that working tree. Treat the project.beekeeper/config.jsonas 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(defaulttrue) controls whether the installed schedule runs.interval(default2h) 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(defaultfalse) starts the sidecar.beekeeper llamafirewall enableanddisableflip this for you.sample_rate(default1.0) is the fraction of tool calls forwarded to the scanner, from0.0to1.0.fail_mode(defaultclosed) governs sidecar-crash behavior independently of the top-levelfail_mode:closedblocks,openallows,warnallows with a surfaced warning.codeshield(defaulttruewhen enabled) toggles the CodeShield unsafe-code scanner;codeshield_actioniswarn(default) orblock.python_path(defaultpython3) 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.directoriesis an optional list of extra extension directories forbeekeeper watchand the scan layer to monitor, in addition to the auto-detected editor paths.beekeeper initregisters detected editor directories here for you.{ "watch": { "directories": ["/path/to/extensions"] } } -
redact_patternsis 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(defaultfalse) is the opt-in gate. A fresh install never quarantines anything automatically.dry_run(defaulttrue) controls whether a threshold hit produces a real quarantine move or only an audit record. Set bothenabled: trueanddry_run: falseto activate live moves.threshold(default2, 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 default2, not the floor1. An out-of-range value (for example5) 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(defaultfalse) 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(default30) 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 reachesenforceweight.scope(defaultorg_only) is the record scope.community_shareableis 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.jsonbeekeeper policy test ~/.beekeeper/policies/my-policy.json --tool-call ./call.jsonbeekeeper policy listA 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.
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.envand.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
| Rule | Key | Default | Fires when |
|---|---|---|---|
| Release age | release-age | warn | The package's first publish is younger than 24 hours. An unknown publish time warns (fail soft). |
| Lifecycle scripts | lifecycle | warn | The install would run a pre or post-install lifecycle script. |
| Git / remote-URL dependency | git-remote | warn | A 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> --oncebeekeeper 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 --blockbeekeeper posture enforce release-age --warnposture 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.