@zero2webmaster/starter-kit
v0.27.0
Published
Node CLI to scaffold new Z2W projects from canonical Templates + AGENTS.md.
Maintainers
Readme
z2w-starter-kit
Version: 0.27.0 | Framework: 2.19.0
Node CLI to scaffold new Z2W projects from canonical Templates + AGENTS.md.
Brand: Zero2Webmaster
Overview
z2w-starter-kit is a command-line scaffolder for Zero2Webmaster projects. It reads canonical content from the master Templates folder — the AGENTS body is discovered by glob (AGENTS_v*.md for general projects, AGENTS_WP_v*.md for WordPress) plus the matching SETUP_GUIDE_* and Resources/*, so an upstream framework-version bump flows through with no code change. It parses a pasted project brief OR walks an 8-question fallback wizard, applies brand presets, layers the current Z2W standards block (portable-stack, Fathom analytics, Uptime Kuma, Neon-careful, Agent Coordination, SEO baseline, email-service, moderation, text-size), substitutes placeholders, and writes a complete project skeleton atomically into the target path.
It is the Node/npm sibling of the instantiate-z2w-project Claude Code skill — the same orchestration logic, packaged so any developer can run it without Claude Code installed. When standards drift, both must be updated together.
npx @zero2webmaster/starter-kit initQuick start
# Run without installing
npx @zero2webmaster/starter-kit init
# Or install globally
npm install -g @zero2webmaster/starter-kit
z2w-starter-kit init
# Or run from a local clone during development
git clone https://github.com/zero2webmaster/z2w-starter-kit
cd z2w-starter-kit
npm install
npm run build
node dist/cli.js initThe CLI's primary surface is brief-first: paste a project-instantiation brief, the CLI parses it deterministically, shows a numbered confirmation screen with per-line edit, then scaffolds. Type skip at the brief prompt or pass --wizard to fall back to the 8-question sequential wizard.
Project types supported: wp-plugin, cf-worker, cf-pages, nextjs, python-service, library, protocol-repo.
Brand presets: save-the-frogs, bansuri-bliss, zero2webmaster, custom.
CLI flags
| Flag | Purpose |
|---|---|
| --wizard | Skip brief-first mode; go straight to the 8-question fallback wizard |
| --input <source> | Non-interactive mode. --input <path> reads ScaffoldInputs JSON from a file; --input - reads from stdin. Bypasses brief / confirm / wizard entirely. For CI use |
| --dry-run | Print the file list + contents that would be written, without touching disk |
| --target-path <path> | Override the target path from inputs |
| --templates-path <path> | Point at a Templates folder other than ~/Desktop/Zero2Webmaster/AI/Templates/. Strict — only that exact folder is consulted |
| --promote-standards | Run the interactive (a) inline / (b) promote-into-Templates dialog per applicable standard. Promoted standards are captured in STANDARDS_PROMOTIONS.md alongside the scaffold (the Templates-folder write itself is a v0.3.x concern) |
| --allow-non-empty | Write into a non-empty target directory. Off by default — the CLI refuses to scaffold over existing content unless explicitly opted in |
| --no-color | Suppress ANSI color in the final summary output. Honored regardless of terminal capability, per POSIX NO_COLOR convention |
Architecture
This is a pure CLI tool. No web UI, no database, no scheduled jobs, no deployment target. Side-effectful commands (git init, gh repo create, npm install, composer install, symlink setup) are surfaced as next-actions in the final summary block — the CLI does NOT run them on the user's behalf in v0.1.x.
- Layer 1 (Directive): SOPs in
directives/(system architecture, scaffolder contracts, brand presets) - Layer 2 (Orchestration): Node CLI (
src/cli.ts) parses args, parses the brief or runs the wizard, decides what to write - Layer 3 (Execution): Filesystem operations via
fs-extra(atomic per-file writes via.tmp+ rename); git/ghshell-outs run by the user post-scaffold, not by this CLI
For non-WP web apps (nextjs, cf-pages with hasWebUi), the CLI emits the full 7-item SEO baseline at instantiation: SSR/SSG via the framework's Metadata API, per-page metadata, one <h1> + semantic HTML, sitemap + robots with preview-noindex gating, OG image placeholder, Organization JSON-LD, Fathom Analytics wiring via the canonical env var (NEXT_PUBLIC_FATHOM_SITE_ID for Next.js, PUBLIC_FATHOM_SITE_ID for Vite/SvelteKit/Astro, inline <script> for cf-pages static), and a SEO-CHECKLIST.md pre-launch audit.
Templates resolution
The CLI resolves canonical template content (AGENTS bodies + Resources/) from the local Templates folder only:
--templates-path <path>if set — strict use of that exact location.- Local Templates folder at
~/Desktop/Zero2Webmaster/AI/Templates/. - Otherwise, hard fail with a clear
--templates-path <path>hint.
The CLI reads the folder fresh on every run (nothing is cached or embedded), so an upstream Templates edit is picked up the next time you run init.
Note: the v0.2.0 hosted-mirror fallback (
templates.z2w.us+ a 24h local cache) was retired 2026-06-23 to protect the framework IP — the public mirror was taken down. The CLI is therefore back to requiring a local Templates folder (or--templates-path), the same as v0.1.x. No license-gated content channel is planned — the framework stays in-house rather than being licensed out (decided 2026-07-30).
Relationship to the Claude Code skill
The Claude Code skill at ~/.claude/skills/instantiate-z2w-project/SKILL.md and this CLI share a contract: same inputs, same outputs, same brand presets, same standards block. The skill is the in-Claude-Code path; this CLI is the standalone path. The canonical Templates folder remains the source for AGENTS file bodies and Resources/ boilerplate — both the skill and this CLI read Templates files fresh on every run; neither embeds copies.
Status
- v0.27.0 (current) answers
org-hq's two scaffold defects, ten days after they were filed. The headline:app/robots.tswas asking the wrong question. Its gate required a production deployment AND a real custom domain — and an internal admin console satisfies both while still being wrong to index, soorg-hqservedAllow: /on a branded public subdomain for a month with every check it had passing, because none of them asked. Indexability now takes a third condition,hasPublicSurface, baked in at scaffold time rather than read from the environment, because it is a fact about what an app IS and not about where a copy of it is running. It fails CLOSED — omitted reads as "no public surface" — which is the opposite default from every other optional input here and is deliberate: a public site wrongly withheld is one field and a redeploy with nothing having escaped, while an internal console wrongly published is silent, slow to undo, and has already happened by the time anyone notices. The wizard and brief-first flows ask, and the CLI's final summary now states the posture out loud in both directions, since a silent default is how the original defect survived.cf-pagesis fixed in the same release — it publishedAllow: /unconditionally — because shipping the fix only in the type that was reported would have left its sibling quietly broken. The second defect: the*.vercel.appalias redirect now excludes/api/*, whose SEO rationale never applied and whose 308 breaks every server-to-server caller that does not follow redirects. And re-measuring the report changed it: the companion claim — that adding the exclusion would silently stop redirecting/, because a:pathparam cannot match the empty string — did not reproduce. On Next.js 15.5.23 a CUSTOM param pattern supplies its own.*, which matches empty, so the wildcard alone still redirected the root; the explicit root rule ships anyway as insurance against a path-to-regexp detail that is not a documented guarantee, described as insurance rather than as a repair. Verified per tier 1 on two real scaffolds from the builtdist/—npm install, a realnext build, andcurlwith forgedHostheaders against both the shipped form and a control build with the root rule removed. 1241 of 1241 passing. - v0.26.0 releases two things. First, the per-service Uptime Kuma health keyword, built on 2026-08-21 but never released or written down until now: every deploy target's health document serves
{"status":"ok","service":"<slug>","keyword":"<slug>-health-ok"}, and the emitted standards block tells the reader to match the full keyword. The old portfolio-wide"status":"ok"was worthless as a check — byte-identical across every Z2W service, so a monitor with a mistyped URL, one copied from a sibling project, or one left pointing at a decommissioned host still went green, which is the exact failure a keyword exists to catch; a portfolio audit found 12 of 23 monitors keyed on it. The value is DERIVED from the slug viahealthKeyword(), which is the load-bearing half — a shared constant would rebuild the same trap with extra steps. Second, a fix inrollup-integrations.mjs: a comma in an author's prose is not an edge separator. Stripping parentheticals before splitting handled the(why…)note form and did nothing for the canonical form's— whynote, which runs to end of line, so- consumes: contact-registry — people, tags, entitlements.was about to writetagsinto the Project Registry as a dependency ofcommerce-engine, andaudit-engine's trailing sentence was about to writelive-status. Both had been PRINTED on every run underⓘ not registry slugs (external, or prose noise — check)— a line that reports and does not filter, so a reported artifact that is still written is not a caught one. A comma-part is now an edge only when it is a known registry slug or carries a:qualifier, with the first part exempt because that is where the author names the edge and the only position a legitimate non-registry backend occupies. The same work uncovered the inverse defect — a MISS: prose left attached to the last inline item swallowed its slug, soz2w-observability-bridge's section yielded onlyVercel, an external its own sentence had just disclaimed, while its real edge went unread. 1233 of 1233 passing. - v0.25.0 adds
scripts/reconcile-production-url.mjs, which reconciles the Project Registry'sproduction_urlcolumn against the Vercel API — and measuring the real API showed the 2026-08-17 design sketch was wrong in three separate ways. The sketch said "readdomains[], filter out*.vercel.app, never takedomains[0]." Measured across all 23 Zero2Webmaster Vercel projects: position carries no information at all (z2w-social's correct domain is the first survivor,org-hq's is the second), so no positional rule can exist; filtering the aliases out blanks five Live rows whose only public surface is a.vercel.appalias, so aliases are a lower-priority tier rather than noise; and multiple custom domains are the common case, not an edge — 6 of 19 resolvable projects have more than one,file-serverhas four. The reconciler therefore returns a verdict object rather than a URL, so "there is one" and "I picked one of four" cannot print the same way, and it writes only into a NULL — a recorded value that disagrees is reported as drift and never overwritten, because it may be a human's deliberate choice. It found a real one on its first live run: the registry'sz2w-socialURL 308-redirects tofrogspace.savethefrogs.com. Live redirect evidence is used only to eliminate a candidate that points at another candidate — bothleaderboarddomains 307 to/bansuri, a tenant path, so "follow redirects and take the final URL" would have written a tenant-scoped URL as a project's production URL. A coverage ledger accounts for every row asserting a public surface, and a completeness check makes an unexplained row loud instead of absent. Also re-syncs the canonical Agent Coordination block to v0.1.27, which brings the previously-red conformance test back to green — 1199 of 1199 passing. - v0.24.0 makes contrast a measured property of a PAIR rather than a taste call about a swatch. Every
nextjsscaffold now emitslib/a11y/contrast.tsandtest/contrast.test.ts, a table of SURFACE x TEXT-ROLE x THRESHOLD rows measured against the stylesheet the project actually ships — thirteen pairs across six surfaces, with--brand-inkmeasured four separate times because it is painted on four different backgrounds. The candidate came fromstatic-sitesand its lesson is one line: contrast is per-surface, not per-palette — a validator that checks each swatch against white passes cleanly while shipping unreadable text, because the swatch is rendered on the tint panel three components down. Writing that check found two real defects in this scaffold's own CSS, both invisible to every brand preset. The keyboard focus ring was painted in--brand-primary, which measures 2.03:1 on white in Z2W green and 1.40:1 in Z2W gold — so focusing a field made its boundary less visible than at rest, in Zero2Webmaster's and Save The Frogs' own colors. AndreadableInkOn()picked the better of near-black and white without checking that the winner cleared anything, which put a 4.41:1 glyph on any mid-tone brand fill. Fixed with a derived--brand-focus(same hue, darkened only as far as 3:1 requires) and an escalation to pure black, which provably clears 4.5:1 on every possible background. Verified by running the scaffold's own vitest, plus four canaries that each reproduce a defect on demand — including the one that matters most: an ink that stays green on white and fails at 4.06:1 on the code tint. - v0.23.0 makes every scaffolded web app defend its own head.
audit-enginemeasured 26 reachable Z2W surfaces on 2026-08-20: 22 carried none of the five baseline security headers, whileleaderboardcarried five of five — so this was a lift from a passing in-house implementation rather than a design exercise. Everynextjsscaffold now emitslib/security-headers.mjs, applied to every route by a newasync headers()in bothnext.config.mjsvariants, andcf-pagesgoes from two of five to five of five. The CSP is assembled from the origins the scaffold actually loads, each gated on the input that ships the feature: Fathom unconditionally, Turnstile inscript-srcandframe-srcwhen the project takes cards (the widget is an iframe, so allowing only the script leaves an uncompletable card path), Sentry inconnect-srcalone when observability is on. It ships enforcing rather than Report-Only — a considered deviation from the retrofit-oriented rule, reasoned in the emitted comments, because a scaffold has no live traffic to break and a header that blocks nothing is just a note asking someone to finish later. Alongside it,lib/json-ld.tscloses theJSON.stringify-into-a-<script>sink: not because the scaffold's own JSON-LD was exploitable (it holds a brand name and an env URL) but because the Pro-SEO extension's documented example fed a post title — database content — straight into it, which is the exact stored XSS found live inz2w-social. A scaffold's examples are copied more often than its code is read. Verified on the artifact: realnext build, all six headerscurl-confirmed on a home page, a child page and an API route, and headless Chrome reporting zero CSP violations — with a positive control proving the detector fires. - v0.22.0 reshapes every emitted
.env.example/.env.localso the line you came to fill in is the one you see. Kerry, 2026-08-16: the# ── Database (Neon Postgres) ─────…ruler "is usually too long and therefore doesn't look like anything useful", and eighteen lines of explanation sat between the header andDATABASE_URL=. Headers are now a plain# Database (Neon Postgres), and each block leads with its assignments and carries its prose directly underneath. Per block rather than per file, which was Kerry's call between two readings of his own note — collecting every variable at the top of the file would put the pooled-connection warning a screen away from the person about to paste the wrong connection string, and that warning only works where it is read. Not a trim: every explanatory sentence survives, reworded and moved, and there is a control test that unwraps the comment prose and asserts the load-bearing warnings are all still present, because a layout change is exactly where a paragraph goes missing unnoticed. Verified by loading the emitted file with Node's real dotenv parser — all 13 variables read back — not by grepping the template. - v0.21.0 makes the external audience gate say what actually went wrong. Its refusal named exactly one cause — "a heading was probably renamed upstream" — for a state that has two, and
project-creator, the only consumer that resolves Templates from a version-pinned package rather than from Kerry's disk, hits the other one every time: at AGENTS v2.15.0 the## Keeping This Framework Currentsection simply did not exist yet, so every outside-brand scaffold refused in their production while they hunted a rename that never happened. Each gated section now declares the Templates version that first shipped it, the gate derives a minimum from those declarations, and the error distinguishes version skew (upgrade Templates) from unexplained (fix the section list). The throw is deliberately not softened. Same release: the standards decision log is now gate-aware — a standard whose whole section the gate removed reportsremoved-by-audience-gateinstead ofinserted-inline, because the old log let a preview UI tell an outside customer it had "Skill Vault awareness" in a file that no longer mentioned it; and a newprivateReferencesfinding separates a surviving line that instructs the reader into the private Skill Vault from one that merely points at a missing section — one hit at Templates v2.18.0 and zero at v2.19.0, which removed that sentence upstream during the same session, demoting the finding into the milder dangling-reference class rather than making the check inert. No emitted file changes by a byte. - v0.20.0 emits
lib/csv-export.tsand an enforcingtest/csv-export.test.tsinto every Next.js scaffold, with no capability flag. A CSV cell beginning=,+,-or@is evaluated as a formula by Excel and Google Sheets, so an unguarded export is code execution on the machine of whoever opens it — arriving through a file the app itself told them to download. A survey of 53 Z2W repos found 1 pass and 12 fail, and all 12 grew their export months after the project was scaffolded, which is why this one ships unconditionally rather than behind a flag: "this app will export CSV" is not knowable at scaffold time the way "this app takes cards" is. The emitted test greps for any file servingtext/csvthat skips the helper, so the guard survives the next person who adds an export. Same release:scripts/rollup-integrations.mjsnow reads markdown tables and**We CONSUME:**headings, recovering 18 real dependency edges the ecosystem map had been missing, with none lost. - v0.19.1 emits a
:disabledrule for buttons inapp/globals.css, so a disabled button still looks disabled after the author gives buttons a brand fill. The scaffold ships no button styling of its own, so today the browser's grey rendering still applies — the trap opens on the author's firstbackground/color, which overrides that grey and leaves:disableda state with no appearance: the button looks pressable, the click does nothing, and the user concludes the app is broken. A sibling Z2W app shipped exactly that across ~50 screens behind a clean typecheck, a green build and 1,051 passing tests, because it is a rendered-pixel property no unit test holds. Includes the:hovercancel people forget — afilter: brightness()hover happily re-brightens a dimmed button at the moment the user is deciding to click. Verified on real pixels via CDP with:hoverforced, and canary-verified by stripping the rule from a live scaffold. - v0.19.0 emits the PWA baseline for
nextjsprojects with a web UI —public/manifest.json,public/icon.svg,public/sw.jsandcomponents/ServiceWorker.tsx, wired intoapp/layout.tsx— so a scaffolded app installs on a phone. Three decisions run against the original design note and are documented in place:app/icon.svgis NOT emitted (a static icon file in that segment would silently retire the generatedapp/icon.tsxfavicon),theme_colorcomes from the brand primary so it agrees with the layout'sviewport.themeColor, and the glyph is a path rather than text because no font is guaranteed where the OS rasterises an icon. The service worker is network-first, never caches/api/, and evicts only its own cache prefix — that last clause fixed a real defect found by executing the emitted worker in tests rather than grepping it: an origin-wide sweep meant one Z2W app's deploy wiped a neighbouring app's offline cache under/pathrouting. - v0.18.4 points the writer's cross-cutting placeholder check at EVERY emitted file. It had run against
CLAUDE.mdalone since Step 6 — one of the ~42 files a Next.js scaffold emits — sosentry.shared.tsshipped a literal{{project_name}}, a key that has never existed in the substitution map. Found by dogfooding a real scaffold, not by the suite. A per-project-type sweep now covers all eight types. - v0.18.3 makes every emitted
.gitignorerefuse a downloaded cloud service-account key. The Google Cloud console names a private key<project-id>-<12 hex>.json, which matched nothing in the scaffolded ignore file and, unlike a stray.env.production, carries no hint in its filename that it is a credential. Found when a live Gmail delegation key for two SAVE THE FROGS! mailboxes landed in a repo this CLI had emitted. - v0.18.2 bumps the emitted Agent Coordination fingerprint to v0.1.26, matching what
z2w-agent-coordinationcurrently publishes. Every scaffold emitted while the constant saidv0.1.25carries a stale fingerprint, which is precisely the drift the fingerprint exists to detect. - v0.18.1 returns the audience gate's findings as data (
ScaffoldResult.audienceGate) rather than only printing them. v0.18.0 wrote its dangling-reference warning to the terminal, butpreviewScaffold()discards its output stream by design — and that is the entry point a web UI uses — so the report had no receiver on the one path where an external audience actually occurs. No emitted file changes by a byte. - v0.18.0 implements Kerry's 2026-08-14 ruling — Option A: "ship the artifact, not the doctrine." A new
audienceinput (internal|external, defaulting tointernal) gates what an outside customer's scaffold contains. The emitted code is untouched — that is the value a customer is buying — but the ~40 KB prose corpus explaining which internal rulings produced it is not emitted:Standards block,Z2W Portfolio Standards,Capture Learnings,Keeping This Framework Current,Common Name & Terminology GlossaryandAgent Coordinationare dropped as whole##sections, and surviving[[skill]]Vault pointers are unwrapped to plain text. Measured on a real customer scaffold: CLAUDE.md 85,702 → 44,848 B, a 47.7% reduction, 0 Vault pointers, 0 bulletin-repo mentions; the internal control is byte-for-byte unchanged. Whole sections, never edited sentences — omitting a fingerprinted block makes no identity claim, whereas editing one ships a modified body under an unmodified fingerprint and an emitter mints that lie forever. The gate refuses to emit when a section it must drop cannot be found (a renamed heading would otherwise re-leak it silently), and reports surviving back-references to dropped sections rather than editing the canonical body to fix them. Also fixes a defect that was wrong under every option and had nothing to do with the ruling:buildCustomBrandSpec()hardcodedauthor: DEFAULT_AUTHORandCustomBrandInputshad no author field, so every outside-customer scaffold emitted© 2026 Dr. Kerry Krigerinto the customer's ownREADME.mdand page footer — the inverse of an IP leak, a false ownership claim on someone else's repo, live on theproject-creatorpath. A custom brand now supplies its ownauthor/authorUrland falls back to its own brand name, the README's hardcoded, Zero2Webmasteris empty for custom brands, and the typography rule no longer cites a "Z2W standing organization instruction" at somebody else's organisation. Themarketing.md/BACKUPS.mdinstructions to mirror status into the private Project Registry are omitted for external audiences. Tests 983 → 1,009. - v0.17.2 closes the gap v0.17.1 left open and stated: the file selection behind that denominator was still an inline chain of filters in
main(), so nothing could execute it without a live database and a full run — the same untestable-inline shape v0.16.2 had just fixed for--strict, in the same file, for a second decision.selectBulletinFiles()anddescribeSelection()are now pure exported functions with 13 tests, canary-verified by replanting the v0.17.0 bug. Two things came out of the extraction: the selection now partitions its input (four disjoint buckets that always sum to the entry count, so a file cannot leave the denominator without changing a number somebody prints), which surfaced two exclusion classes the report had never mentioned; andmain()now refuses a run that selected zero files instead of printingscanned: 0 / rows that WOULD change: 0— a summary byte-identical to a healthy, fully-in-sync run. That is this script's own founding failure, relocated one layer up from the parse into the file selection. Real-corpus figure unchanged at 52, so the refactor is behaviour-preserving. - v0.17.1 stops
scripts/rollup-integrations.mjscounting its own*-archive.mdspill files in the "Bulletin files scanned" denominator (72 -> 52), and STATES the exclusion rather than silently shrinking the number. - v0.17.0 makes the Cloud-Run-vs-Fly.io host choice a standard for
python-service/node-servicescaffolds, so a long-running service's platform is decided by one test — does it need a persistent volume? — rather than per project by whoever is in the chair. Cloud Run for stateless request/response that scales to zero with the database elsewhere; Fly.io for stateful always-on needing a disk that survives a restart, which Cloud Run structurally cannot hold. It is a ruling rather than a preference becausez2w-multi-lingual-apicosted it on a live service (~13 req/hr inside a $2/month budget, because Cloud Run genuinely idles at zero), and it carries the half a new project would not think to ask for: do not re-litigate this as a migration — every real incident there traced to Neon's CU-hour cap or to secret hygiene, both external to both platforms. Deliberately NOT inserted forcf-worker/cf-pages/nextjs, whose host the project type already settles. - v0.16.2 fixes
--strictso it judges only what the invocation actually reconciled, unblockingz2w-agent-coordination's Project Registry reconciler cron. - v0.15.1 ships
scripts/rollup-integrations.mjsin the npm tarball, which is the one thing standing between the Project Registry reconciler and a schedule.z2w-agent-coordinationaccepted this project's proposal to host it on a cron and built the workflow, then found neither delivery route worked: a checkout of this private repo needs a PAT that could read every private repo in the org, and although the package is published, the tarball shipped noscripts/at all —fileslisteddist/**+ README + LICENSE and the reconciler matched none of those globs. "It is published" and "the script is reachable" were two different facts. A runner can nownpm i @zero2webmaster/starter-kit@latestand get it with zero credentials. Guarded bysrc/package-contents.test.ts, which runsnpm pack --dry-run --jsonand asserts on the artifact rather than the glob — nothing here could previously tell a shipped file from an unshipped one. - v0.15.0 deletes the embedded Agent Coordination block in favour of a pointer, because this CLI is an emitter and a stale copy here is minted into every new Z2W project.
z2w-agent-coordinationmeasured currency across the ecosystem on 2026-08-07 and found 0 of 37 files at canonical — 34 stale, 3 frozen paraphrases — and named "delete the copy, keep a pointer" its preferred remedy; the block had grown 4,274 B → 34,515 B in ten weeks, so every bump re-asked ~21 projects for a bigger paste. ScaffoldedCLAUDE.mdfiles now carry heading + fingerprint + session-start steps 1 and 1b (read the live block; it wins) + the Hard rules, and drop ~24 KB of auto-loaded context each. The Hard rules stay embedded on purpose — a leaked secret or an overwritten neighbour is irreversible, so those must hold even when the clone is unreachable. The old byte-diff guard was replaced rather than dropped (pointer conformance + an anti-regrowth byte ceiling, both canary-verified), and a real defect in it was fixed: it read a local bulletin checkout without ever checking that the checkout was current, and that clone was 215 commits behind, so it compared against stale canon while reporting a shrinking gap. - v0.14.0 makes card-path bot protection a scaffold standard, and fixes a defect that made every Next.js scaffold's server modules impossible to unit-test. A new
acceptsCardsinput inserts a standard pointing at [[stripe-elements-confirm-path]] §8 for every project type that has a runtime request surface, and — for Next.js — emits the protected endpoint shape rather than a bare one: a Turnstile verifier whose verdict is five-valued and fails open, an abuse policy sized for card entry (30 per 10 minutes per source, no global cap) rather than copied from order submission, the browser widget withappearance: "interaction-only"and every failure callback wired, and an emitted test that greps the consuming project's ownapp/and fails the next card path added bare. The enumeration grep ships with the standard, because a rule that says "protect the card path" without saying how to enumerate card paths passes review and misses a route. Separately:import "server-only"is a build-time poison pill that made every server module in every scaffold fail to LOAD under vitest — whilenext build,tsc --noEmitand the emitted suite all passed — so scaffolds now emit aserver-onlytest stub plus the@/*alias that mirrorstsconfig.json. - v0.9.5 gives the Project Registry a write path for the events it describes.
z2w-agent-command-centerreported two staleproduction_statusrows and asked for a writer; investigating found two different causes wearing one face.site-control's row would have been fixed by the reconciler that already exists — nothing ever ran it.email-engine's row could not be fixed, becausescripts/rollup-integrations.mjsallowed a backtick before the status value but not an asterisk, so every project that bolded its Live status parsed as null and vanished from the report — indistinguishable from a row already in sync. That was 3 of the 15 sections declaring a status (20%), two of which said LIVE. The parser now reads the forms agents actually write, and reports declared-but-unreadable separately from never-declared, at zero as well as non-zero. Six rows reconciled. Also: thecommand_centerrole (scoped to the two approval columns), a CHECK that makessummary_state = 'approved'unreachable without them, andstatus_qualifierfor the projects that kept writing a sixth value into a five-value enum. - v0.9.4 corrects a privacy understatement in the emitted Sentry standard. It had told every scaffolded web app to set
sendDefaultPii: trueand described the consequence as "user IP + request headers". Verified against@sentry/core10.69.0's owndefaultPiiToCollectionOptions(), that flag resolves ten axes on — includinghttpBodiesin all four directions,databaseQueryData,stackFrameVariables(local variable values), andgenAI: { inputs: true, outputs: true }, which is the user's prompt and the model's completion. The standard now prescribes one completedataCollectionblock, carries both counter-intuitive traps (a partial block flips the baseline to all-on;stackFrameVariablesis on in both branches sosendDefaultPii: falsecannot reach it), and makes the resolver the binding check rather than any list in a doc. Also retires the registry'sproject_typecolumn in favour ofstack+audience. - v0.9.3 fixes a scaffold-corrupting splice bug and the "GitHub org" wording. The canonical Agent Coordination block contains the anchor
(`^## Current focus$`), whose$and closing backtick form$`— aString.replace()special pattern meaning "everything before the match". Because the block was passed as a replacement string, every scaffold emitted since 2026-07-30 pasted its own entire document head into the middle of that sentence. All four canonical-body splices now use a replacer function, whose return value is never pattern-interpreted. Separately, the brand block now reads- **GitHub owner:**and states the account type:zero2webmasteris a GitHub User, not an Organization, so/organizations/...URLs 404 — wording that had sent two agents to those 404s. - v0.9.2 re-syncs the emitted Capture Learnings block to canonical v1.1.0 (the
AGENTS.md/GEMINI.mdmirror is now conditional). v0.9.1 republishes v0.9.0 with the corrected LICENSE + README. The 0.9.0 tarball shipped the old text by accident — see CHANGELOG. v0.9.0 gives every Next.js scaffold accessible form primitives —components/FormBits.tsx(<Field>/<Required>/<InfoHint>), theapp/globals.cssthey need, a vitest runner, and an emittedtest/form-standards.test.tsthat fails on the next hand-rolled form which labels a field "(optional)", hides help text in a placeholder, or marks required with a bare*. - v0.8.0 (published) emits the canonical Capture Learnings block into every scaffolded
CLAUDE.md, so the session-end "should this become a skill?" step actually reaches the agent working in the new project. - v0.7.0 added
lib/seo/page-metadata.ts— apageMetadata()helper that returns a completeopenGraph+twitterobject every time. Next.js merges metadata shallowly per top-level key, so a page that hand-writes a partialopenGraphsilently dropsog:type,og:site_nameandog:imageand downgrades its Twitter card. - v0.6.0 shipped the magic-link
CANONICAL_HOSTSseam, a sharedlib/seo/canonical-host.mjssorobots.tsand the Vercel alias redirect cannot disagree, and a404-on-unmapped-Host guard for Host-routed multi-tenant apps. - Automatic GitHub repo creation is a free default: after a scaffold the CLI runs
git init+ first commit +gh repo create --private+ push, with--no-repoto opt out. It is skipped for--dry-runand for the non-interactive--inputCI path, and it warns rather than failing ifghis unavailable. - The monetization question is settled: the IP stays in-house (Kerry, 2026-07-30). Zero2Webmaster does not sell licences to this tool or to the framework it encodes; what gets monetized is the work built with it. The paid-subscription language that earlier releases carried in
LICENSEand in this README has been withdrawn. Thelicensesubcommands and the--with-pro-seogate are now dormant machinery pending a removal decision — they are built and tested but have nothing to validate against.
Note on the hosted Templates mirror: earlier releases (v0.2.0 / v0.2.1) shipped a hosted mirror at
templates.z2w.usthat let the CLI run without a local Templates folder. That mirror was retired on 2026-06-23 and the CLI now reads canonical content from the local Templates folder only — see Templates resolution above.
License
Proprietary. All rights reserved. No license is granted, and this tool is not for sale.
© 2026 Dr. Kerry Kriger, Zero2Webmaster.
This package is published to npm for the operational convenience of Zero2Webmaster's own machines. Publication to a public registry is not a license, an offer, or a grant of any kind — see LICENSE for the full terms.
This is an internal build tool, not a product. Earlier releases of this package invited the public to evaluate it and buy a subscription; that invitation was withdrawn on 2026-07-30 to protect the framework encoded in this tool and in the templates it emits.
This says nothing about Zero2Webmaster's products. Zero2Webmaster licenses its software to customers and clients under separate terms — this notice concerns this internal tool alone.
Inquiries: [email protected].
Scaffolded 2026-05-28 via the [[instantiate-z2w-project]] Claude Code skill v1; reconciled against the consolidated skill v1.1.0 (brief-first + Agent Coordination block) on 2026-05-29. Version: 0.27.0 | Last Updated: 2026-08-25
