phi started as an npm-only behavioral scanner. It's becoming a supply-chain firewall that doesn't care which registry produced the bytes. This page is the overview; per-version release notes live in CHANGELOG.md.
shipped released, on GitHub
Releases, runnable today
in progress actively being worked
on
next up committed direction, queued
behind the in-progress item
horizon direction we're going, not
committed to dates
out of scope explicit boundary —
phi will not become this
optionalDependencies are now resolved by default
with platform-aware filtering. Modern dev tooling that ships
native binaries this way — vite,
rollup, esbuild,
swc, lightningcss,
sharp — finally installs cleanly. The
resolver reads each package's os and cpu
fields and silently drops platform mismatches the same way
npm does; a packument failure on an optional entry is also
silent. --omit=optional becomes meaningful and
reinstates the previous strict behavior.
The install flow now runs in two phases:
safe packages extract immediately after the scan, then the
review prompt fires with the full per-detection breakdown
inline — severity badge, detector, the why:
description, the matched evidence:, and the
file: path. No more scrolling up to remember
what you're approving. Review-approved packages and any
safes that were deferred because their closure touched a
pending review then extract in a second pass.
Detector tightening, round 3: pdfjs-dist
cleared to SAFE; next@16.2.6's
@vercel/og TrueType font embed
(String.fromCharCode(0, 1, 0, 0, …)) and
node-html-parser's character-class boundary
table both stopped firing. The eval bundler-recovery
whitelist was rewritten exact-match plus
__dirname-anchored to close a real security
bypass — the previous "contains require(" rule accepted
eval("require('child_process').exec('rm -rf /')").
Four attack shapes are now pinned in regression tests.
phi watch backend gains a /api/stats endpoint
for the live headline package count, accepts
$DATABASE_URL as the Postgres DSN
(Railway / Fly Postgres plugin auto-wires), and the
Dockerfile drops the VOLUME directive that
Railway's Metal builder rejects.
The detector pipeline was tuned to clear false positives on
popular bundled CLIs and packages with embedded binary data.
prisma (score 100 → 35) and
pdfjs-dist (90 → 20) no longer land in the
BLOCKED tier: their hex-escape charset tables, embedded
OpenType / TrueType fonts, bundler
eval("__dirname") recovery shims, and
.npmrc reads by legitimate native-binary
installers all stopped tripping detectors without weakening
coverage of real attacks. Six new regression tests pin the
contract.
phi install gains
--strict-closure /
PHI_STRICT_CLOSURE: a CI gate that bails
before writing phi.lock when any
package would be pruned due to incomplete dep closure.
Without the flag, partial-prune installs now exit non-zero
so CI pipelines notice the incompleteness without re-reading
the per-package warnings.
phi watch v0.1.0 ships as a public feed: a
24/7 poller scanning a curated watchlist, with anonymous
package submission. The phi view <pkg>
hint is now the suggested next step whenever an install is
blocked — the per-detection evidence is one command away.
phi install now iteratively prunes packages
whose transitive dependency closure is incomplete —
typically when a parent in the resolved tree has a dep that
itself failed scan, was excluded by --omit, or
has no available tarball. The previous behavior would
install the parent with dangling refs, leaving
node_modules in a state where requires could
fail at runtime.
A fixed-point algorithm walks until no further pruning is needed, records each skip reason (blocked transitive, missing tarball, removed from tree), and surfaces the list of affected direct deps in the install report so the user knows exactly what to address.
npm installs are now best-effort: phi installs resolved SAFE
packages first, reports unresolved packages after extraction, skips
BLOCKED packages unless --force is used, and queues
REVIEW packages for an explicit approval step.
Accepted REVIEW packages are remembered in phi.lock, so
repeated installs do not ask again for the same accepted package
version. CLI flags such as --yes and
--no-advisories are parsed as installer flags instead of
package names.
New phi check / phi verify validates
package.json, phi.lock, installed package
directories, cached tarball integrity, and installed files when a
cached tarball is available. Registry fetches also gained retries,
a longer default timeout plus PHI_REGISTRY_TIMEOUT,
PHI_REGISTRY_ATTEMPTS, and
PHI_REGISTRY_RETRY_DELAY for slow networks.
phi becomes a polyglot supply chain firewall. Auto-detects
Go modules (go.mod, go.work) and
routes to the new hybrid replace pipeline: shells
out to go mod download into a phi-controlled
staging dir, scans every fetched zip with the analyzer + OSV,
then atomically materializes approved bytes into
$GOMODCACHE. BLOCKED modules never reach Go's
cache without an explicit override.
Full command surface: phi install,
install <mod>@<v>,
update, remove,
audit, audit fix,
outdated, upgrade-interactive,
view, why, ls,
build / test / run /
vet / fmt, doc,
replace / unreplace,
init --go. Plus Go-toolchain aliases
(phi mod tidy = phi install,
phi get = phi install,
phi mod verify = phi audit, etc.)
and the universal phi go <anything>
escape hatch.
Go workspaces (go.work) — multi-module
monorepos walk every use directive with a
per-member phi.lock and an aggregate verdict
summary. Binary install (phi install
<tool>@latest outside a project) gates global
Go tools through the same scan pipeline before
go install writes to $GOBIN.
Vendor via phi mod vendor.
Cross-compile sugar
(phi build --cross linux/arm64).
Replace /unreplace wrappers with
cross-org-fork detection.
Six new Go-specific detectors: go-init-network,
go-init-fs-write, go-cgo-shellexec,
go-build-tag-gated,
go-go-generate-curl, go-unsafe-import.
Plus the project-level go-replace-with-fork.
Schema-v3 phi.lock with a tagged
source.type union covers npm and Go in one
file. Verdict cache (h1-keyed, content-addressed) cuts
warm-cache install time ~50%. .phi-allow
persistent project allowlist. Retraction + deprecation
warnings surfaced on install. sum.golang.org transparency
status in audit footer.
phi view scans by default; live spinners
2026-05-16
phi view <pkg> now runs the detector
pipeline + OSV check on the resolved tarball and prints a
security: block (score, verdict, detections,
advisories with fix versions) alongside the standard
metadata. Same engine phi install and
phi audit use — so you get the same verdict you
would get if you installed the package, before you add it.
--no-scan opts out for scripting; field-targeted
queries (phi view react license) auto-skip.
Spinners now cover phi view,
phi outdated, and
phi upgrade-interactive so long-running phases
never look stuck. phi help rewritten and grouped
by lifecycle.
The biggest single drop of CLI ergonomics so far. Tier 1
features: phi ls (npm-style ASCII trees),
workspace: protocol (workspace:*,
workspace:^1.0.0, path-relative form),
phi link / phi unlink (Windows
junctions, no admin), and phi do --filter
(pnpm-style selectors). Tier 2:
phi view packument inspector,
phi config with secret redaction,
phi pkg dot-path editing, and
phi upgrade-interactive. Plus
--omit=dev,optional,peer, env var equivalents
(PHI_OMIT, PHI_CI, …), and
phi cache clean --runs /
--all-caches for stage cache eviction.
Registry failures now surface with the right shape: a
non-existent package gets a clear
not found · check the spelling or whether it's
private instead of a raw 404 Not Found
string. phi audit no longer dies on the first
registry failure — transient or missing packages are
recorded in phi-report.json's new
skipped array and the rest of the tree is
scanned. Registry fetches retry up to 3× with exponential
backoff (500ms / 1s / 2s) + ±25% jitter on network errors,
429 rate-limits, and 5xx; Retry-After honored.
The spinner now shows
resolving... (retrying X · N total) so flaky
networks are visible instead of looking like a hang.
phi ci for production installs
2026-05-11
phi ci is the canonical one-line install for
non-interactive environments (Docker builds, GitHub Actions) — sugar
for phi install --frozen-lockfile --yes. The frozen
lockfile is the audit record: anything in phi.lock was
already reviewed and approved by the developer during their local
install, so prod can auto-approve review verdicts without a prompt.
Blocked verdicts still abort unless --force. Plus two
composable primitives: -y/--yes
(auto-approve reviews on any install/update) and
--omit=dev (skip devDependencies, npm
parity).
phi x, scan-and-run like npx
2026-05-10
phi x <pkg> now mirrors npx: if the
bin isn't already in node_modules/.bin, phi resolves
the providing package, runs the full scanner + advisory pipeline
over the transitive tree, then runs the bin from a per-version cache
without polluting your node_modules. A scan-passed
marker means repeat invocations skip straight to running. Pinned
versions, scoped packages, bin-name-≠-package-name (phi x -p typescript tsc), and the -- separator all work the npx way.
Lifecycle scripts stay off — phi-stricter than npx by design. Plus
an animated resolver spinner with the first frame drawn immediately
— no more silence between banner and progress.
Mid-install interruption can no longer corrupt your
package.json. Bad packages can no longer crash a scan
run. Friendlier first-run experience on Windows.
phi audit fix [--apply | --force] — proposes safe fixes
for typosquats, vulnerable versions, and deprecated packages.
Preview by default; you opt in to applying. Scan progress now
renders consistently across every shell we ship to.
Two new behavioral detectors targeting recent threat patterns (credential exfiltration flow + Linux system tampering), plus deprecation guidance for packages with safer successors.
phi self-update brings phi current with one command.
Verifies the new binary against published checksums before swapping.
phi create bootstraps React, Next, Express, Fastify, or
Nest projects — with the scaffolder itself audited first.
--force escape hatch for packages you know you trust
despite a flagged verdict.
The install-time interception pipeline: 19 detectors (npm + Go), OSV vulnerability layer, lifecycle scripts off by default, lockfile + audit report, cross-platform binaries.
Cleans up the install experience on first run. Same binary, signed.
Continue tightening npm compatibility where it helps daily workflows:
script shorthands such as phi check <file> when a
project defines a check script, stricter/faster install
modes, and clearer policy output for skipped, REVIEW, and BLOCKED
packages.
Directional, not committed to dates. Order is rough priority.
Live scan as you edit your manifest.
First-class GitHub Action, GitLab CI templates, drop-in for the major platforms.
Opt-in per package; results feed the same risk score.
Strict trust model — signed plugins only.
phi will not become these things. Listing them here so the boundary is explicit.
phi is install-time only. Once code is in
node_modules/ and your app runs it, that's the
application's concern — use container limits, gVisor, or an EDR for
that.
phi.lock is a complete, integrity-verified lockfile —
phi can be your only package manager, in CI, in Docker, in
production. But if you'd rather keep
package-lock.json / yarn.lock /
pnpm-lock.yaml alongside for tooling that expects them,
phi leaves them alone. Drop-in, not rip-out.
No daemon. No phone-home. Ever. Decisions happen on your machine, with your data, full stop.
phi stays free and open-source. Commercial offerings would be separate products built on top — never behind a paywall on the install path itself.