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

create-kywi-app

v0.24.0

Published

Scaffold a new Kywi CMS project — npx create-kywi-app my-site

Readme

create-kywi-app

Scaffold a new Kywi CMS project.

npx create-kywi-app my-site

Dependency-free by design (bin/create-kywi-app.mjs uses only Node built-ins), so npx create-kywi-app runs with nothing pre-installed. The file contents it writes live in lib/templates.mjs (buildFileSet(answers)), unit-tested independently of the CLI's prompting/arg-parsing.

Usage

npx create-kywi-app [project-name] [options]     # scaffold a new project (default)
npx create-kywi-app agents [--force]             # add/refresh agent guidance in an
                                                 # existing project (run from its root)

Options:
  --yes, -y            Use defaults, skip prompts
  --mode <mode>        coupled | headless | decoupled   (default: coupled)
  --db <provider>      postgresql | mysql               (default: postgresql)
  --auth <list>        comma-separated: credentials,google,github  (default: credentials)
  --force, -f          agents: overwrite existing guidance files (default: skip them)
  --help, -h           Show this help

With no flags and a TTY, it prompts interactively (project name, DB provider, auth providers, deployment mode). Pass --yes (or run non-interactively, e.g. in CI) to skip straight to defaults + flags.

npx create-kywi-app my-site --yes
npx create-kywi-app blog --mode headless --auth credentials,google

Deployment modes

Set via --mode (and written into the generated kywi.config.ts's mode field):

  • coupled — the app renders the public site AND serves the API + admin. GET / renders content from the DB-backed scope.
  • headless — API + admin only. GET / returns 404.
  • decoupled — API + admin serve here; a separate frontend consumes @kywi-software/sdk against this app's /api/v1. GET / returns 404.

What gets generated

A generated project boots and works with zero manual edits: pnpm install && pnpm migrate && pnpm seed && pnpm dev gives you a working /admin — the full Kywi admin (dashboard, site tree, media, users, forms, audiences, settings, and every other core surface, sign in and create + publish a page) — and, in coupled mode, a public site that renders published pages at their slug.

buildFileSet() writes (lib/templates.mjs):

package.json                       scripts (dev/build/start/migrate/seed) + deps incl. drizzle-kit + tsx
kywi.config.ts                     defineKywiConfig/Site/Theme + a default "Page" content type
tsconfig.json
next.config.mjs                    the FULL config to consume core (transpilePackages, extensionAlias,
                                   serverExternalPackages) — every line is load-bearing
.env.example                       DATABASE_URL + AUTH_SECRET
.gitignore
README.md                          project-specific quick start (createdb, migrate, seed, dev, /admin, admin.features)
AGENTS.md                          guidance for AI agents working on this site: an app-specific
                                   header (where things live, the /admin URL, the CLI, the three
                                   scaffolded Claude Code skills) + Kywi's official building
                                   patterns (docs/agents/AGENT-PATTERNS.md, verbatim)
CLAUDE.md                          thin pointer that sends a Claude Code session to AGENTS.md first,
                                   plus a nudge toward the kywi-content-model skill (and the other
                                   two scaffolded skills)
.claude/skills/kywi-content-model/SKILL.md  Claude Code project skill: design a CONTENT-MODEL.md and get
                                   owner sign-off before creating types or entering content — loaded
                                   automatically by Claude Code, a pre-build checklist for other agents
.claude/skills/kywi-collections/SKILL.md  Claude Code project skill: build any collection (testimonials,
                                   logos, posts, products, …) as folder + feed + Feed Display — loaded
                                   automatically when adding a collection
.claude/skills/kywi-personalization/SKILL.md  Claude Code project skill: confirm the use case, then
                                   build audiences, page variants, or A/B experiments — loaded
                                   automatically when the owner wants personalization or A/B testing
lib/kywi.ts                        the ONE wiring point: kywi.config.ts → core's render path (stamped)
kywi.layers.ts                     GENERATED layer registry: imports every site/theme layer so core can
                                   resolve overrides theme → site → core at build time (never edit; upgrade regenerates) (stamped)
sites/default/index.ts             this site's layer: re-exports lib/modules.tsx as `modules` (add `templates` to override)
sites/default/themes/default/index.tsx  the default theme's layer: `templates.nav` → components/site-nav.tsx (coupled only)
middleware.ts                      re-exports core's middleware (auth gate, session refresh, cookie→bearer bridge) (stamped)
app/api/v1/[...kywi]/route.ts      the versioned API — a thin delegate to core's `createApiRoute` (cookie lifting lives in core) (stamped)
app/llms.txt/route.ts etc.        the root AX routes — thin delegates to core's `createAxRoute` (stamped: all 4 of
                                   llms.txt, llms-full.txt, sitemap.xml, robots.txt)
app/layout.tsx                     root <html>/<body>
app/icon.svg                       favicon
app/admin/[[...admin]]/page.tsx    mounts the FULL core admin (KywiAdminApp, every surface) at /admin (stamped)

coupled additionally gets app/(site)/layout.tsx + app/(site)/[[...slug]]/page.tsx (the public site — renders "/" and every published page at its slug, both stamped), plus app/(site)/site.css and components/site-nav.tsx (project-owned, unstamped). headless and decoupled instead get app/page.tsx (returns 404 — no public rendering, unstamped).

All eleven of the files marked (stamped) above are thin, version-stamped delegates: the two app/(site) route files, middleware.ts, lib/kywi.ts, kywi.layers.ts, the API route, the four AX root routes and the admin catch-all page. Each opens with a // kywi-render v2 (create-kywi-app <version>) sha256:<12 hex> comment — the hash is over the file's own body, so create-kywi-app upgrade (see below) can tell an untouched generated file (safe to replace) from one you've edited (refused) without a diff against every historical emission. The public render path itself — content and locale resolution, SEO metadata, JSON-LD, feed and nav hydration, personalization, A/B assignment and the front-of-site editor — is shipped as @kywi-software/core/next, so pnpm up @kywi-software/core upgrades it. Before this, ~1,370 lines of it were copied into every project, where no upgrade could ever reach them again. What a project owns: kywi.config.ts, app/(site)/site.css, lib/modules.tsx, components/site-nav.tsx and the layer files under sites/**.

The layer chain. Every named artifact core renders — a module renderer, the nav, the front-edit overlay, the personalization runtime, the /kywi.js loader — is resolved per request as theme → site → core, first hit wins, from the registry kywi.layers.ts imports. To override one, export it by name from sites/<site>/index.ts (modules or templates) or from sites/<site>/themes/<theme>/index.tsx; never edit core or the generated files. Core validates the registry at startup and fails loudly when a configured site or theme is missing from it, when two themes of one site disagree on region names, or when a layer overrides a module name neither core nor kywi.config.ts defines.

Note what's not in this list: there is no components/admin-shell.tsx, no per-route app/admin/content/**, no lib/admin-auth.ts. Since 0.2.0 the whole admin is one component (KywiAdminApp) shipped by @kywi-software/core — the generated project mounts it with the single catch-all page above instead of hand-rolling admin pages. See docs/hosting.md §3 for exactly what that mount does, and docs/admin-configuration.md for disabling surfaces you don't want (per deployment via admin.features in kywi.config.ts, or per site at runtime via the superAdmin "Admin Features" surface — no redeploy).

The security-critical session plumbing (JWT verify, the httpOnly cookie contract, the cookie→bearer bridge) is NOT copied into every project. It lives once in @kywi-software/core/host (+ /host-client); the generated middleware.ts and API route are thin framework wiring over those primitives, so a kywi upgrade ships session fixes without the app hand-maintaining crypto. See docs/hosting.md for the full host-app contract.

The generated project's own README.md walks through createdb, copying .env.example → .env, pnpm migrate, pnpm seed, and pnpm dev. For a decoupled deployment it also shows the @kywi-software/sdk usage snippet (see packages/sdk/README.md in this monorepo for the current, verified SDK API).

Adding (or refreshing) agent guidance in an existing project

New scaffolds get the agent-guidance files above automatically. To add them to a project that already exists — or to pull the latest guidance into one that has older copies — run the agents subcommand from the project's root:

npx create-kywi-app@latest agents           # add any missing guidance files
npx create-kywi-app@latest agents --force    # overwrite them with the latest

It writes the same five files (AGENTS.md, CLAUDE.md, and the three .claude/skills/<slug>/SKILL.md). What it does:

  • Detects the project — requires a kywi.config.ts in the current directory (otherwise it exits with an error), reads the project name from package.json (falling back to the directory name) and the deployment mode from the config.
  • Writes the real AGENTS.md header — the "where things live" section is generated from the landmarks it actually finds on disk (e.g. lib/modules.tsx, the public app/(site)/[[...slug]]/page.tsx, and a lib/site.ts — which only a project scaffolded before the layered render path still has), so a hand-built or older app gets an honest header rather than one that asserts files it doesn't have, or claims a thin delegate where it holds its own copy.
  • Never clobbers by default — existing files are skipped (a customized AGENTS.md is left untouched); pass --force to overwrite. It prints a created/updated/skipped summary either way.

Use @latest so an existing project picks up the newest guidance regardless of which create-kywi-app version originally scaffolded it.

Upgrading a project

Every generated render-path file is version-stamped (see the eleven (stamped) files above), so create-kywi-app upgrade can prove which ones are still exactly what it emitted and safe to replace, versus which ones carry your own edits and must not be touched. Run it from the project's root:

npx create-kywi-app@latest upgrade --dry-run   # see the full report, write nothing
npx create-kywi-app@latest upgrade             # apply it

What it does, one line per file in this order — landmarks, then layer files, then retired pre-0.19 glue:

  • created — a landmark file the project is missing, or a layer file (sites/<id>/index.ts, sites/<id>/themes/<theme>/index.tsx) a site declared in kywi.config.ts has none of yet.
  • replaced — a stamped landmark whose hash proves it is still untouched; swapped for the current emission.
  • current — a stamped landmark that already matches the current emission byte for byte.
  • kept — a layer file under sites/** that already exists. Layer files are created once and never compared or overwritten again — from the moment they exist they are the project's.
  • REFUSED (edited) / REFUSED (unstamped) — a landmark whose hash doesn't match (someone's work is in it) or that carries no stamp at all (predates the layered render path, or was hand-written). The exception: a project scaffolded by 0.19.0 has six landmarks (the API route, the four AX root routes, the admin catch-all page) that 0.19.0 emitted with no stamp at all — upgrade recognises those six by their exact 0.19.0 bytes and replaces them like any other untouched file, so a 0.19.0 project upgrades with a plain upgrade, no --force needed.
  • REFUSED (legacy) — one of the six retired pre-0.19 files (lib/site.ts, lib/config.ts, lib/kywi-js-loader.ts, components/kywi-js-loader.tsx, components/personalization-runtime.tsx, app/(site)/kywi-front-edit.tsx) is still present; their contents now live in @kywi-software/core/next, and leaving a stale copy shadows the real thing. --force turns this into removed instead.
  • backed up: <path> → .kywi-upgrade/<timestamp>/<path> — printed above any replaced/removed line that --force produced from a refusal: the original is copied there before it's touched.
  • warn: <path> was ejected from @kywi-software/core <v>; installed is <v> — advisory only, for a file create-kywi-app eject (below) put under sites/** whose stamped core version no longer matches the installed one.
  • note: … — advisory hints: stale AGENTS.md guidance (create-kywi-app agents --force refreshes it), or an installed @kywi-software/core older than the generated files target.

Without --force, an edited or unstamped file (and the six retired files) is refused, not touched — the command reports it and leaves it exactly as it is. Re-run with --force to replace/remove refused files too; each one is backed up under .kywi-upgrade/<timestamp>/ first, so nothing is discarded. --dry-run runs the identical plan and prints the identical report, but writes nothing.

Exit codes: 0 — nothing was refused (with --force, every refusable file was replaced/removed instead). 2 — one or more files are still refused because --force wasn't passed — a CI job should treat this as "the project isn't caught up yet." 1 — no kywi.config.ts here, or it couldn't be scanned (the layer registry is generated from it, so the command would rather refuse to write anything than emit one that fails assertLayerContracts at boot).

What it never touches: kywi.config.ts, package.json, lib/modules.tsx, components/site-nav.tsx, app/(site)/site.css, app/layout.tsx, and any sites/** file that already exists.

Where your edits belong now, once a file is refused or you're migrating off a pre-0.19 project:

  • module renderers → sites/<site>/index.ts
  • nav / front-edit / personalization runtime / JS loader → create-kywi-app eject <artifact> (below)
  • styles → app/(site)/site.css

Ejecting a core artifact

Four of core's render-path client components ship as readable .tsx sources inside @kywi-software/core's eject/ folder, one per name:

| artifact | source file | | -------------------------- | ------------------------------- | | nav | site-nav.tsx | | frontEdit | front-edit.tsx | | personalizationRuntime | personalization-runtime.tsx | | jsLoader | kywi-js-loader.tsx |

npx create-kywi-app@latest eject <artifact> [--site <id>] [--theme <name>] [--layer site|theme] [--force]

It copies the named artifact into the project as a layer override you own — sites/<site>/themes/<theme>/<file>.tsx by default (--layer theme; --site defaults to the first site kywi.config.ts declares, --theme to that site's own configured theme), or sites/<site>/<file>.tsx with --layer site (--theme is meaningless there — a site layer isn't per-theme). The copy opens with two stamp lines: 'use client' first (a directive after any other line is inert, so this has to stay first), then // kywi-eject <artifact> (@kywi-software/core <version>) — the provenance create-kywi-app upgrade reads to warn when core's copy has since moved on.

When the target layer's index file still has the shape create-kywi-app generates, eject also wires the copy into that layer's templates export automatically (dropping any import that pointed the same entry at its previous component, so a re-eject with --force doesn't stack imports). When the index has been hand-edited into some other shape, it refuses to touch that file and prints the two lines to add by hand instead — an import line and a <artifact>: <ExportName>, entry for inside templates.

--force here means something different than in upgrade: it overwrites an existing ejected file at the target path (without it, eject refuses to clobber one). Needs node_modules installed, and an installed @kywi-software/core >= 0.20.0 (the first release that ships eject/).

Ejecting is a deliberate, one-artifact opt-out of core upgrades: from that moment the file is the project's own, pnpm up @kywi-software/core can no longer reach it, and create-kywi-app upgrade only warns — via the warn: line above — when the installed core has moved past the version it was copied from. Reach for it when you need to change the behaviour of one of these four components; everything else (module renderers, styles) has a lighter-weight home — see "Where your edits belong now" above.

Installing the generated packages

All @kywi-software/* packages (core, cli, sdk, mcp, js) are published to npm at the same version as create-kywi-app. The package.json this tool writes pins "@kywi-software/core" and "@kywi-software/cli" to ^<that version> (see buildFileSet() in lib/templates.mjs), so a plain

cd my-site && pnpm install   # (or npm install / yarn)

resolves them straight from the registry — no local build, packing, or override step required.

Working against a local monorepo checkout instead

If you're developing @kywi-software/* itself and want a scaffolded app to pick up unreleased local changes rather than the published npm packages, build and pack the packages you changed, then repoint those two deps at the tarballs in the generated package.json (mirrors a real npm install — dist-only, deduped React — better than a file: link to the source directory, which risks a duplicate React copy):

pnpm --filter @kywi-software/core --filter @kywi-software/cli build
( cd packages/core && pnpm pack --pack-destination /tmp/kywi-pkgs )
( cd packages/cli  && pnpm pack --pack-destination /tmp/kywi-pkgs )
node packages/create-kywi-app/bin/create-kywi-app.mjs my-site --yes
cd my-site
#   Repoint "@kywi-software/core"/"@kywi-software/cli" in package.json at
#   file:/tmp/kywi-pkgs/kywi-software-{core,cli}-<version>.tgz, then:
pnpm install && createdb my_site && cp .env.example .env
#   (set DATABASE_URL + AUTH_SECRET in .env)
pnpm migrate && pnpm seed && pnpm dev

Re-pack after any change to core/cli and re-run pnpm install.

Testing

pnpm --filter create-kywi-app test

__tests__/templates.test.mjs asserts on buildFileSet()'s output directly — no filesystem or network access required.