npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@unknown-creatives/substrate

v1.3.0

Published

The distribution init CLI — `substrate init` wires Substrate's AI tooling (skills, the Bloom agent, instruction files) into a consuming project across the 14-platform wiring matrix (Claude Code, Cursor, Windsurf, Copilot, Gemini, Codex, …), and records se

Readme

@unknown-creatives/substrate

The distribution init CLI — substrate init wires Substrate's AI tooling (skills, the Bloom agent, instruction files) into a consuming project across the 14-platform wiring matrix (Claude Code, Cursor, Windsurf, Copilot, Gemini, Codex, …), and records selections in .substrate/state.yaml for --refresh. It also owns catalog entry scaffolding through substrate add, deterministic substrate upgrade engine swaps, and exact-byte local engine artifact assembly and verification through substrate artifact assemble. setup --apply and upgrade cross one delivery seam: both consume the signed engine bundle and share a single verification implementation (distribution architecture v2).

These commands sit inside a delivery flow: for the end-to-end supervised engagement path — handoff set, onboarding, client-side verification, and upgrades — see the engagement delivery runbook.

Running the CLI

This package is published to npm. The package is @unknown-creatives/substrate; a bare npx substrate still installs an unrelated third-party package — always use the scoped name:

npx @unknown-creatives/substrate init --platform claude-code

The bare substrate <cmd> spellings below assume that invocation. The published version always equals the engine release version (single-version coupling), so npx @unknown-creatives/substrate@<v> means "the CLI released alongside engine <v>".

CLI dependencies vs engine runtime dependencies: the published package is self-contained — it declares and installs its own dependencies (js-yaml, and esbuild for artifact assemble). The engine's runtime dependencies (tsx, yaml, semver, and the typescript-5 alias for migration/audit analysis, UCS-1105) are not CLI dependencies and are intentionally not in this package: generation runs from a Substrate checkout or a vendored engine, never from the CLI install. (Historical note: before publishing, the bin had to run from a checkout that had had npm ci, else it failed with ERR_MODULE_NOT_FOUND — the published package has no such requirement.)

Working on Substrate itself, run the bin from your checkout after npm ci:

node <substrate-checkout>/packages/cli/bin/substrate-init.js init --platform claude-code

A substrate install bootstrap that would perform the engine-vendoring copy itself remains deferred to the npm-engine packaging option (P4·h) (see docs/getting-started.md §0).

In the vendored client layout, substrate init exits non-zero when its client bootstrap hits blockers — a kernel/platforms/types content root it could not create because the vendored engine source is missing (missing-source) or the symlink and copy fallback both failed (copy-failed). It then prints Init completed with N blocker(s) instead of Done! Substrate is ready in this project., so scripted or CI onboarding can gate on the exit code. The contract binds only when the engine the bootstrap inspects is the engine init detected: the legacy layouts (npm install, clone-subdir) may print the same content-root warnings but keep their warning-only exit 0. Unresolvable engine runtime dependencies (tsx, js-yaml, yaml, semver, typescript-5) stay a non-blocking warning: running generation from the Substrate checkout is a supported layout that never resolves them in the client (getting-started §0). The printed install command spells typescript-5 in its npm alias form ("typescript-5@npm:typescript@^5") — it pins the TS 5.x compiler API the migration and current-state analyzers need regardless of the client's own TypeScript major.

Setup planning and transactional apply

substrate setup --plan is the non-mutating front door for self-serve setup. It inspects a supported Vite + React consumer through client-visible signals (package.json, one vite.config.*, index.html, the React application entry, the application tsconfig, and one lockfile family) and prints a canonical JSON plan to stdout:

substrate setup --plan \
  --engine-artifact ../substrate-engine-0.39.0.bundle \
  --brand acme \
  --component surface \
  --component button \
  --target css \
  --target swift \
  --target compose \
  > /tmp/substrate-setup-plan.json

substrate setup --apply /tmp/substrate-setup-plan.json \
  --signing-public-key \
  ../substrate-release-signing-public-key.pem

--dry-run is an alias for --plan. Both modes only read the consumer repository. Keep a serialized plan outside the consumer repository: the plan binds the repository's real path and exact file snapshot, so adding the plan itself inside that tree correctly makes the original snapshot stale.

Apply accepts only that plan and a trusted Ed25519 public key. It rechecks the repository snapshot, re-derives the complete plan, verifies the retained bundle bytes against their attestation, checksum, signature, and public key, and stages the engine plus ownership records before committing any consumer-visible resource. A stale, edited, or foreign plan fails without mutation. Pre-commit failure removes staging and leaves the consumer byte-equivalent to its starting state; an exact rerun reports retained without rewriting files.

Apply is also the reconciliation boundary for an existing declaration. It copies the current generated root into staging, runs the complete declared project generation there, hash-validates every generated path declared by the new manifest.gen.json, and compares that manifest with the previous generated ownership record. Unmanifested passthrough files are checked separately and must remain byte-identical. A removed brand, component, or target deletes every path owned by the previous manifest, including a locally edited copy; unmanifested files are copied through unchanged, and a newly generated path that would collide with an unowned file fails the transaction. Generation or pre-commit failure cannot publish a partial prune or advance ownership.

The apply JSON reports generated artifacts separately from committed transaction resources. artifacts.targets.css, .swift, and .compose each list created, updated, removed, and unchanged client-relative paths; the ownership-manifest report independently identifies whether manifest.gen.json was created, updated, or unchanged. Repeating the same declaration or contraction therefore produces an all-unchanged artifact report and no committed resource changes.

The local engine input is the substrate-engine-<version>.bundle file emitted by substrate artifact assemble, together with its .attestation.json, .bundle.sha256, and .bundle.sig sidecars. Planning reads the bundle's declared member metadata to enumerate future destinations, but labels those declarations unverified: provider verification of the retained bundle bytes is mandatory before apply can extract anything. It never accepts an unpacked directory as a second delivery format.

The JSON identifies the vite-react host adapter, operational root remaps and integration points, inferred or existing substrate/project.yaml, detected AI hosts, and the future acquisition, ownership, projection, host-integration, generation, and verification phases. Every planned resource includes its future operation and reason. Generated target projections carry only target-neutral brand/component/target selections; engine adapters own their concrete output topology and the generation phase owns manifest.gen.json.

The client-owned declaration has four keys:

version: 1
brands:
  - acme
components:
  - button
  - surface
targets:
  - css
  - swift
  - compose

Targets are output selections, not AI hosts. AI-host detection remains a separate operational concern destined for .substrate/state.yaml; delivery provenance remains in .substrate/manifest.yaml; generated topology and freshness remain in substrate/generated/manifest.gen.json.

The installed engine resolves this declaration into one platform-neutral declared project graph before target descriptor construction. CSS, Swift, and Compose consume target selections from the same graph, so brand identity, component dependency closure, system inputs, and provenance resolve once while adapter syntax remains separate.

When substrate/project.yaml already exists, plan mode reads and validates it instead of accepting selection flags as a second authority. Unsupported or ambiguous host shapes fail with a resolution before any edit. The supported Vite seam directly imports defineConfig from vite, exports one object literal through that binding, and declares exactly one top-level plugins array. Transactional apply verifies and stages the sealed engine, durable project state, generated CSS projection, and deterministic Vite/TypeScript/ React integration before committing them. It then runs the consumer-owned scripts.build, whose supported contract performs both the TypeScript check and Vite production build; setup reports success only when that command passes. Repeated setup retains the managed integration byte-for-byte. Unsupported, ambiguous, or symlinked host layouts fail before any client file is edited. The plan never schedules the existing client-owned project declaration for rewrite, and apply preserves its exact bytes. An engine root whose exact file set and hashes match the unverified bundle declaration is retained only when its delivery manifest also owns the same engine root, version, and member hash set; any unowned or divergent engine root is rejected with a direction to use substrate upgrade. Verification is mandatory before apply relies on either case.

Onboarding P0 release gate

Run the complete release-level onboarding acceptance gate from the Substrate repository root:

npm run verify:onboarding:p0

The gate requires Node 22, npm registry access for disposable installs, a real swiftc, and a Java-backed kotlinc. Missing native toolchains are blocking failures; there is no local or CI skip mode.

The command packs and installs @unknown-creatives/substrate, assembles the allowlisted engine bundle through that installed public command, and invokes onboarding only through the documented substrate setup --plan / --apply interface. Disposable consumers have registry-installed Vite, React, and TypeScript dependencies and no source-checkout aliases or links. The gate builds the real Vite application, compiles minimal Swift and Kotlin consumers against the shipped kernels and projected output, proves an unchanged rerun, and contracts brands, components, and targets from generated-manifest ownership while preserving an unmanifested client file. It also proves byte restoration and no success output for artifact tampering, invalid declaration, generation, Swift/Compose compilation, and consumer-build failures.

The pull-request checks job and the release workflow run this exact command. P0 is not green, and a release cannot be cut, unless every black-box contract passes with all three CSS, Swift, and Compose targets enabled.

Toolchain aliases

substrate init also sets up the supported @substrate/* import aliases for the project's toolchain (UCS-703). The alias list is sourced at runtime from the src/aliases.ts policy SSOT (UCS-702) — the CLI never hardcodes a second list, so a contract change can't drift from what init writes.

  • Auto-write (default): the two public aliases (@substrate/engine, @substrate/generated/*) are written into tsconfig.json compilerOptions.paths (the safe structured surface). The write is idempotent and preserves existing options and unrelated paths. baseUrl is never added — TypeScript 7 removed the option (TS5102), and the ./-prefixed targets resolve relative to the tsconfig without it.
  • Report for bundlers: Vite, Vitest, Webpack, and Next configs are code and unsafe to rewrite, so when one is detected init prints the exact alias block to add by hand instead of editing it.
  • Report-only (--report-aliases): print every alias block (tsconfig + detected bundlers) without writing anything.

--dry-run previews the alias step without writing. Targets resolve against any roots: remapping in .substrate/state.yaml.

Catalog add

substrate add is the P4·c v0 catalog path. It resolves a path-derived entry id from a local catalog, validates the author-facing entry.yaml, copies scaffoldable files into the client content root with provenance headers, records the fetch in .substrate/manifest.yaml, and runs the caller-provided generate command. V0 deliberately has no customer permission, tier, or delivery-token model.

substrate add components/button \
  --catalog ./catalog-staging \
  --generate-command "npm run generate"

Inside the Substrate repo, the same public command scaffolds entries from catalog-staging/ into a client-shaped target for dogfooding.

Local engine artifact assembly

substrate artifact assemble is the P0 local engine delivery path. It compiles the generator and its runtime packages into a standalone Node compiler entrypoint, independently bundles the browser-safe runtime entrypoint, adds only sealed engine data from the explicit allowlist, and writes one deterministic artifact bundle plus verification metadata:

substrate artifact assemble \
  --source-root . \
  --output-directory dist/local-engine \
  --version 0.39.0 \
  --signing-private-key env:SUBSTRATE_RELEASE_SIGNING_PRIVATE_KEY

For version 0.39.0, the output set is:

  • substrate-engine-0.39.0.bundle — the exact bytes delivered and consumed
  • substrate-engine-0.39.0.attestation.json — version, byte length, checksum, signature, member hashes, and compiler/browser-runtime input provenance
  • substrate-engine-0.39.0.bundle.sha256
  • substrate-engine-0.39.0.bundle.sig

The final-member allowlist contains compiler.mjs, the browser runtime.mjs plus its public TypeScript declarations, a minimal artifact package.json, sealed system/property YAML, the chart and text-role defaults required by client CSS projection, the public alias policy, and static web cascade CSS. It also contains the exact Swift/Kotlin kernel sources and SwiftUI/Compose API stubs required to compile generated native projections during client setup. Those native validation inputs have their own canonical provenance list and must match bundle members byte-for-byte. The runtime is compiled separately from the Node compiler so the disposable application imports one browser-safe public entrypoint rather than engine source internals.

generated/, src/brands/, src/components/, and client-owned substrate.config.yaml are not members. Compiler source and package inputs are also enumerated by exact path in checked-in compiler and browser-runtime allowlists; both exact path sets are recorded in artifact provenance. Assembly fails if either build graph reaches a newly imported test, demo, generated registry, source, or package file until that input is explicitly reviewed and added.

Setup can use the local provider seam without trusting a mutable path:

import {
  createLocalEngineArtifactProvider,
  inspectEngineArtifact,
} from '@unknown-creatives/substrate/engine-artifact';

const declaration = inspectEngineArtifact({
  artifactPath: './incoming/substrate-engine-0.39.0.bundle',
  attestationPath: './incoming/substrate-engine-0.39.0.attestation.json',
});
// declaration.verification === 'unverified'
// declaration exposes version, entrypoint, and immutable memberPaths for planning.

const provider = createLocalEngineArtifactProvider({
  artifactPath: './incoming/substrate-engine-0.39.0.bundle',
  attestationPath: './incoming/substrate-engine-0.39.0.attestation.json',
  checksumPath: './incoming/substrate-engine-0.39.0.bundle.sha256',
  signaturePath: './incoming/substrate-engine-0.39.0.bundle.sig',
  publicKey,
});
const artifact = await provider.acquire();
// artifact.verification === 'verified'
artifact.extractTo(stagingDirectory);

inspectEngineArtifact() and provider.inspect() parse only declared, read-only planning metadata and never extract or confer trust. Setup may use their immutable member paths to build a plan, but it must not mutate a client from an unverified declaration. acquire() reads the bundle once, then verifies the byte length, SHA-256 checksum sidecar, Ed25519 signature sidecar, matching attestation, version, attested provenance, member set, member hashes, and safe paths. readBytes() returns a copy of those retained verified bytes and extractTo() materializes from the retained bundle, so replacing the local file after verification cannot change what gets staged. Extraction requires an empty staging directory. The artifact test executes the extracted compiler.mjs against client-owned brand intent, then asserts that the compiler plans and emits a generated registry without node_modules or a source checkout. The release workflow uses this same exact-byte assembler for engine delivery. Both substrate setup --apply and substrate upgrade acquire the engine through this one provider, so the artifact that onboards a client is the artifact that upgrades them (UCS-1118). The existing directory-based catalog signer remains separate.

Deterministic engine upgrade

substrate upgrade is the P3·d updater v1: no git merge, no semantic merge, and no silent overwrite of manifest-tracked engine edits.

Upgrade takes the same signed .bundle and sidecars that setup --apply consumes — one delivery contract across onboarding and updates. Verification is not reimplemented here: upgrade calls createLocalEngineArtifactProvider().acquire(), the single implementation described above, so byte length, checksum, signature, attestation, member hashes, and safe member paths are checked identically on both paths. The engine is then extracted from the retained verified bytes, never copied from a mutable directory. The command:

  1. Acquires and verifies the signed engine bundle through the shared provider before touching the current engine, and refuses a bundle whose declared version disagrees with --engine-version.
  2. Confirms the current engine.files hash set in .substrate/manifest.yaml still matches the vendored engine on disk. If it does not, the command stops before swapping and requires an explicit three-door decision.
  3. Replaces the resolved engine root wholesale with the verified artifact.
  4. Runs versioned config-schema codemods from the new engine registry.
  5. Runs caller-provided regenerate and verify commands, then refreshes the manifest engine version/hash set while preserving catalog fetch records.
  6. Writes Markdown and JSON reports under .substrate/reports/ and prints the same renderer's summary to the terminal.
substrate upgrade \
  --engine-artifact ./incoming/substrate-engine-0.37.0.bundle \
  --signing-public-key ./uc-release-public-key.pem \
  --engine-version 0.37.0 \
  --regenerate-command "npm run generate" \
  --verify-command "npm run generate:check && npm run test:e2e:engine" \
  --modified-engine refuse \
  --report-id 2026-06-13-client-upgrade

The .attestation.json, .bundle.sha256, and .bundle.sig sidecars are resolved next to the bundle, exactly as setup resolves them, so a client passes the release handoff files unchanged.

Migrating from the directory contract

--engine-artifact no longer accepts an unpacked engine directory; passing one fails with a migration message before any engine mutation. --artifact-sha256 and --artifact-signature are likewise retired — the bundle carries its own checksum and signature sidecars, verified against the attestation, so those values are no longer passed by hand. If you only have a source checkout, produce a bundle with substrate artifact assemble and pass that.

The signature payload is deterministic and covers artifact kind, target version, and checksum:

substrate-artifact-signature-v1
kind=engine
version=0.37.0
sha256=<sha256>

--signing-public-key accepts a PEM string, a file path, or env:NAME. The release workflow assembles the signed engine bundle through the exact-byte path above and signs catalog attestations with SUBSTRATE_RELEASE_SIGNING_PRIVATE_KEY; clients receive the public key through the engagement handoff and the updater refuses unsigned or tampered artifacts before the engine swap.

Release signing public key

The current release signing public key is recorded in docs/release/substrate-release-signing-public-key.pem and distributed with signed release assets as substrate-release-signing-public-key.pem. Its SHA-256 fingerprint over the SPKI DER public key is:

b61d2c945cd9fad091d9ec2fbd1c5e4ec1fa6097e294b00803744aa472363a6e

Release handoffs should include the public key, this fingerprint, and the matching *.attestation.json, *.sha256, and *.sig files for the delivered engine or catalog artifact. The private key remains only in owner-controlled storage and the GitHub Actions secret named SUBSTRATE_RELEASE_SIGNING_PRIVATE_KEY; it must never be committed, attached to a release, or pasted into handoff notes. If the key is rotated, publish the new public key and fingerprint before signing the first release with it, then call out the rotation in release notes and engagement handoff material.

When the current engine has local edits, --modified-engine refuse (the default) prints the modified paths and the three available doors without touching disk: discard replaces the edited engine with the new artifact, freeze exits successfully while staying on the current version, and engage-uc exits successfully with an upstream/white-glove handoff prompt. Only discard may overwrite engine edits, and it must be selected explicitly.

Engine artifacts may ship upgrade codemods in codemods/registry.yaml. This framework is specific to deterministic engine upgrades and is deliberately separate from the guided src/migration/ domain. Entries run in target-version order during the post-swap-pre-regenerate phase:

version: 1
codemods:
  - id: config-schema-002
    from: 0.1.0
    to: 0.2.0
    phase: post-swap-pre-regenerate
    command: node substrate/engine/codemods/config-schema-002.js

Codemod commands run from the client project root with SUBSTRATE_PROJECT_ROOT, SUBSTRATE_ENGINE_ROOT, SUBSTRATE_CONTENT_ROOT, SUBSTRATE_GENERATED_ROOT, and SUBSTRATE_CODEMOD_* environment variables. The phase field defaults to post-swap-pre-regenerate; the explicit field is kept so a future post-regenerate phase can be added without changing the registry shape.

The report lists refreshed pristine engine files, modified delivered catalog files, path-collision counts, and knowledge/reference overlay conflicts. Overlay conflicts cover same-path overlays plus conservative semantic duplicates: Markdown/frontmatter titles provide the semantic key, token overlap provides a deterministic confidence score, and each finding carries a stable id plus a cleanup recommendation for Bloom. Its JSON sidecar is the durable input for the later substrate adopt flow (P3·f).

Bloom reconciliation

substrate adopt consumes an upgrade report JSON sidecar and turns flagged findings into stable, per-finding actions. Listing mode never mutates disk:

substrate adopt --report .substrate/reports/upgrade-2026-06-13-client-upgrade.json

Apply mode requires one explicit finding id. The first implementation only performs deterministic file-level moves: file path collisions copy the engine file into the client path, while exact byte-identical knowledge/reference overlays are removed because the engine now carries the same content. Shadow overlays, semantic duplicates, directory collisions, and modified delivered catalog files remain manual/Bloom-reconciliation plans.

substrate adopt \
  --report .substrate/reports/upgrade-2026-06-13-client-upgrade.json \
  --finding path-collision:0 \
  --apply

Every applied finding writes a rollback record under .substrate/adopt/ before changing files and prints the rollback id:

substrate adopt --rollback adopt-2026-06-13t18.20.00.000z-12345-path-collision-0

A wrong merge is any applied finding that fails validation or user review after adoption. The rollback record restores the exact previous file bytes (or absence) for that finding, giving the client a reversible default while larger semantic choices stay in manual Bloom review.

Substrate location detection

detectSubstrate() (bin/lib/detect.js) probes in priority order; the resolved path is always the directory containing skills/ and agents/:

| Probe | Model | Path | |---|---|---| | $SUBSTRATE_PATH set | manual | env var value (must stay inside the project) | | substrate/engine/skills/substrate-config/ | client | substrate/engine | | engine/skills/substrate-config/ | client | engine (substrate root remapped onto the repo root) | | node_modules/@unknown-ui/substrate/skills/substrate-config/ | install (legacy) | node_modules/@unknown-ui/substrate | | substrate/skills/substrate-config/ | clone-subdir (legacy) | substrate | | skills/substrate-config/ | clone-root | . |

The client model is the v2 client layout (spec §4): a vendored engine at {substrate root}/engine/, the sealed unit UC replaces wholesale. It is probed before every legacy model so a v2 client repo is never misdetected as clone-subdir and a leftover npm install never shadows the vendored engine.

The npm install model is superseded

The npm-symlink install model (npm install @unknown-ui/substrate + symlinks into node_modules/) is formally superseded by vendored delivery — decision D10 of the 2026-06-12 distribution architecture v2 (§10). Detection of node_modules/@unknown-ui/substrate stays so existing installs keep working, but no new capability targets it.

To be precise about what is and isn't published: what was superseded is engine-in-node_modules; what is published today is the CLI only (@unknown-creatives/substrate — the bin/ + assets/ surface of this package). The engine is never published; it arrives through the signed bundle (supervised engagement) or a vendored checkout, and P4·h's engine-packaging question is unchanged by CLI publishing.

The packaging research behind it (npm files manifest, symlink-through- node_modules resolution, update flow) is preserved in the 2026-05-18 companion spec and re-enters as the npm-engine packaging option (P4·h) if self-serve productization wants it. That trigger — not general demand — is what would revive the model.