Configuring Org Policy
Org policy lives at /policy/npm (redirected from /policy) and controls
how every install for your org is evaluated.
Evaluation order
Section titled “Evaluation order”pkgPlease checks, in this order:
- Security blocks — malware, an unavailable malware provider (we fail
closed), and any block pack whose class is
security. - Policy blocks — your own thresholds, such as the threat ceiling and the minimum package age.
- Steer — a package you have not endorsed when you have endorsed an interchangeable one.
- Needs approval — an endorsed package at a version outside the endorsed range.
- Endorsement — a soft allow, deliberately below every check above.
- Thresholds — the warn tiers.
An endorsement is not an escape hatch from a security block. Overriding one is possible, and it is a deliberate, recorded act — see Overrides below. A live endorsement authored specifically to override a given block pack satisfies that block for a human; an agent can never satisfy a block itself — it can only file a request through the approvals queue.
Thresholds
Section titled “Thresholds”- Block threshold (
block_threat) — threat score at or above this blocks the install outright. - Warn threshold (
warn_threat) — threat score at or above this (but below the block threshold) warns instead of blocking. - Warn trust (
warn_trust) — trust score below this warns. - Completeness floor (
completeness_floor) — minimum scoring confidence required before trust/threat are trusted at all. A score computed without the vulnerability/malware provider (for example, an early fast-path score written while the full scan is still queued) reports zero threat-completeness — it is never treated as “fully complete” just because no provider was asked in the first place — and fails closed rather than allowing the install. - Minimum package age (
min_package_age_days) — set to0to disable. Note: an unpinned install (no exact version requested) always resolves to the newest version that clears this floor, regardless of the action setting below. Defaults to 7 days for an org with no configured value. - Package age action (
min_package_age_action) —block,warn, orallowfor a version younger than the floor. An org created after the minimum-package-age feature shipped (2026-09-03) defaults toblock(secure by default). An org that existed before then keepswarn— the behavior this check had before the action setting existed — until it is changed here.
Click Save thresholds to apply changes.
New-package trust cap
Section titled “New-package trust cap”Separately from the configurable thresholds above, pkgPlease automatically
caps trust for packages under 30 days old — this cap is not adjustable via
org policy. It only applies when the package’s age is known. If npm’s
metadata for a package couldn’t be fetched (a transient registry error or
timeout), its age is unknown rather than assumed to be zero, and the cap does
not apply — an unscoreable age is reflected instead through the abstained
package_age trust signal and the completeness floor above. This distinction
matters most for agent-token installs, where a warn from the org policy
escalates to a block: a package should never be blocked as “brand new” just
because pkgPlease couldn’t reach npm.
Your org’s packs
Section titled “Your org’s packs”Every org gets two packs of its own: org-blocks, for packages this org has decided to block outright, and org-endorsements, for packages this org has endorsed.
Endorsements
Section titled “Endorsements”An endorsement names a package, an optional semver range (omitted
or unset means all versions), and a reason. The range is what absorbs an
ordinary bump — endorse left-pad at ^1.0.0 once, and every 1.x release
satisfies it without a new entry. The reason is where the specifics belong:
“9.x is ESM-only” is a reason, not a range — the range says which versions
are endorsed, the reason says why, and that distinction is what keeps a
coding agent from reading a version constraint as a compatibility note (or
the reverse). The next person or agent that hits the same package reads the
decision instead of re-litigating it.
Add an entry with POST /api/v1/policy/{registry_type}/packs/{slug}/entries
— a package name, an optional semver range, and a reason.
From the app, the fastest way to write one is the “Endorse”/“Block” popup on
a package’s own detail page (or the same popup from the ⋯ menu on the
packages list) — it pre-fills the package and version, and offers quick-pick
range helpers (“this version or newer, same major/minor”, “any version”) so
you don’t have to hand-write a semver range. The /policy/{registry}
Endorsements tab (?tab=endorsements) covers the same write with bare
text inputs, useful when you already know the exact range you want; Blocks
(?tab=blocks) is the equivalent tab for org-blocks.
Overlapping ranges
Section titled “Overlapping ranges”A range that overlaps an existing entry for the same package is rejected
at write time with a 409, rather than silently creating an ambiguous
double match — two live entries for the same package would leave no
deterministic answer for which reason applies to a given version. Widen the
existing entry instead of adding a second one: delete it and re-add it with
the broader range, or approve the out-of-range version from the
Approvals queue, which performs that widening for you.
Overrides
Section titled “Overrides”Every block is overridable by a person, and never by an agent — an agent that hits a block can only file a request through the approvals queue. The ceremony a person goes through depends on what’s being overridden:
- A policy block (your own thresholds) is satisfied by an ordinary endorsement, or by an ordinary approval in the queue.
- A security block (malware, or a block pack whose class is
security) requires more: a permitting role, a written reason, and a mandatory expiry. The expiry is not incidental — an override with no expiry becomes a permanent hole in exactly the place a security block exists to close, silently outliving the incident it was written for. Setoverride_of_pack_id(naming the block pack being overridden) andexpires_aton the entry to perform one.
Pack-level escape hatch
Section titled “Pack-level escape hatch”Two ways exist to stop enforcing a managed pack, and both are recorded in the audit log:
- Disable it wholesale —
PUT /api/v1/policy/{registry_type}/packs/{slug}with{"enabled": false}turns a managed pack off for your org entirely, recorded aspolicy.pack.toggled. - Fork one rule — leave the managed pack enabled and write your own
override entry (
override_of_pack_id) against the specific rule you disagree with. The managed pack keeps evaluating everything else; only the named rule is superseded, recorded aspolicy.pack.entry.added.
Approving a request in the Approvals queue writes
into org-endorsements through this same path automatically — endorsements
compound (an approval widens an existing entry’s range rather than piling
up a second one), where the old one-off exceptions only accumulated.
Rule Sets
Section titled “Rule Sets”pkgPlease maintains curated Package Rules and Signal Rules packs,
shown under the /policy/{registry} Rule Sets tab (?tab=ruleSets).
Each pack has a name, a severity (block or warn), a description, and an
entry count — toggle a pack on or off wholesale instead of adding its
entries one at a time.
Seeing policy in action
Section titled “Seeing policy in action”Use the Approvals queue to review anything your policy blocked, or the Audit Log to see every decision your policy has made.