SCAL-P is not a daemon, not a proxy, and not a plugin. It is a CLI tool that wraps npm and pnpm. Every invocation is stateless: load policy, resolve, evaluate, act, log, exit. This page describes the internal architecture for contributors and advanced users who want to understand how the pieces fit together — from the moment you runDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/CarlosEduJs/SCAL-P/llms.txt
Use this file to discover all available pages before exploring further.
scalp install --guarded to the final line written to .scalp/audit.log.
Data flow: guarded install
The following diagram shows the full data flow forscalp install --guarded. Each step maps to a specific internal package.
10-step guarded install flow
Load policy
SCAL-P reads
.scalp/policy.json and deserializes it into a Policy struct (internal/policy/). If the file does not exist, safe defaults are used: warn enforcement, audit-only mode. No file means no hard blocks.Resolve
The package manager adapter is called with the lockfile-only flag (
npm install --package-lock-only or pnpm install --lockfile-only). This produces or refreshes the lockfile without installing anything into node_modules.Parse lockfile
The adapter’s
ParseLockfile(ctx) method reads the lockfile produced in step 2 and returns a flat list of PackageNode structs — one per dependency, direct or transitive.Evaluate policy
policy.Evaluate(pol, nodes) checks every node against the allowlist, denylist, and transitive.max_depth setting. Violations are collected into a []Violation slice.Evaluate trust score
scorer.Evaluate(pol, nodes, lockfile) runs the four-factor trust score for each package: hash verification (30 pts), version maturity (15 pts), weekly download count (0–20 pts), and CVE status (15 pts). The cache at .scalp/cache/trust.json is consulted first; the npm API is used as a fallback. Additional violations are appended to the slice from step 4.Enforce
ApplyEnforcement(mode, violations) applies the configured enforcement mode. block exits 1 immediately. warn prints violations and continues. log records them silently and continues. All violations are written as audit events regardless of mode.Install
If enforcement did not halt execution, the package manager installs dependencies. In CI and fork contexts,
--ignore-scripts is passed to prevent lifecycle scripts from running.Get dependency tree
The adapter calls
GetTree(ctx), which runs npm ls --all --json or pnpm ls --json --depth Infinity. The result is a structured DependencyTree that maps package names to their on-disk locations.Hash sync
SyncWithTree(ctx, lf, tree, pm) walks every package in the tree, calls hash.Dir() on each directory to compute a SHA-512 hash of all files within it, and writes the results to .scalp/lockfile.json. This file is the baseline for all future audit checks.Component diagram
Package manager adapter pattern
Every supported package manager implements the samePackageManager interface defined in internal/pkgmanager/:
internal/pkgmanager/registry.go maps package manager names to their constructors. cli.init() calls the registry to select the adapter based on --pm. Currently implemented adapters are npm and pnpm.
To add support for a new package manager, implement the
PackageManager interface in a new package and register it in the registry. No changes to the CLI or evaluation engine are required.Trust score pipeline
The trust score engine ininternal/trust/ runs a four-factor evaluation for each package:
SCAL-P is offline-first. When the npm API is unreachable, download and CVE scores fall back to half-points rather than zero. A network failure degrades score accuracy but does not block evaluation or produce false violations.
.scalp/cache/trust.json has a TTL of 7 days. Entries older than 7 days are re-fetched on the next run.
CI command flow
scalp ci runs a variation of the guarded install flow optimized for pipeline use. It always blocks on violation, always writes a report, and never accepts passthrough arguments to the package manager:
File layout
The.scalp/ directory holds all SCAL-P state for a project:
Check in
policy.json and policy.schema.json. Do not commit lockfile.json, cache/, or audit.log — these are local runtime state.Internal package layout
Design constraints
Four constraints shape every decision in SCAL-P’s implementation:Zero external Go dependencies. SCAL-P uses the Go standard library only — no framework, no SDK, no ORM. This keeps the supply chain for the tool itself minimal and auditable.
No daemon. Every invocation is stateless. SCAL-P starts, does its work, and exits. There is no background process, no socket, and no persistent state beyond the files in
.scalp/.Offline-first. The npm API is consulted only when the local cache is stale. Network failure degrades score accuracy but never prevents SCAL-P from running. All evaluation inputs are available locally.
Deterministic. Given the same policy file, lockfile, and cache state, SCAL-P produces the same output every time. There are no random seeds, no timestamps in scoring, and no environment-dependent branching in the evaluation engine.