CANDIDATE tooling for the OpenAPI v4.0 "Suluk" candidate (NOT official OAS, NOT SIG-ratified). This doc is the design spine for
tooling/. The spec itself lives inspecification/candidate-v4/.
The user types the least possible contract surface:
Hono endpoints + Zod validations + Better Auth settings
…and the system derives the rest. The contracts are the single source of truth; every other artifact is a Derivation — a pure projection of the contracts. The OpenAPI v4 document is itself just one Derivation, never the source (this mirrors Suluk's own "the Document is a projection of the ledger" discipline).
Data floor Contracts Derivations (projections of the hub)
┌──────────────┐ ┌───────────────┐ ┌──────────────────────────────────────────────┐
│ Drizzle │ CRUD │ Hono routes │ │ v4 doc ─▶ 3.1 downgrade ─▶ Scalar / Swagger │
│ tables │ ─────▶ │ Zod schemas │ ─────▶ │ │ │
│ (system of │ │ Better Auth │ v4 │ ├──▶ Nano Stores client (state corner) │
│ record) │ │ settings │ hub │ ├──▶ shadcn forms / tables (UI corner) │
└──────────────┘ └───────────────┘ │ ├──▶ request-validation middleware │
│ ├──▶ auto-generated contract TESTS │
│ └──▶ documentation-coverage audit │
└──────────────────────────────────────────────┘
▲
┌────────────┴─────────────┐
│ suluk-vscode = the COCKPIT — every layer above is visible, navigable,
│ and actionable from one surface, re-projected per viewer + time.
└──────────────────────────────────────────────────────────────────────┘
The cycle is now declarative end to end: a Drizzle table is the system of record (@suluk/drizzle
emits its CRUD RouteContracts); the contract projects to the v4 hub; and from the hub fall the docs
(@suluk/scalar/swagger), the client state (@suluk/nano-stores), the UI (@suluk/shadcn),
the validation, the tests, and the audit. The developer authors the data + contract; everything else is
derived.
The pivotal requirement: the emitted documentation must be dynamic — it varies by who and when is asking. So the central Derivation is not a static document but a pure function:
render(contracts, principal, now) -> v4 Document
security requirements the principal
satisfies; redact or annotate the rest. A reader sees their API, plus their own facts (API keys,
rate-limit budget) injected as examples / x- extensions.now is an input, never Date.now() read ambiently — so a render is reproducible and
testable (you can ask "what did/will the doc look like at time T").A static export is just render(contracts, publicPrincipal, now). Nothing special-cases it.
| Package | Role | Status |
|---|---|---|
@suluk/core |
parse · validate(meta-schema) · resolve-by-name (own-property only) · signature · ADA · match | ✅ 20 tests |
@suluk/openapi-compat |
v4 ⇄ 3.1 (the Scalar/Swagger lever; ingest external 3.x via upgrade) |
✅ 12 tests |
@suluk/zod |
lossless Zod ⇄ v4 Schema Objects (fixpoint-proven) | ✅ 29 tests |
@suluk/scalar / @suluk/swagger |
render a v4 doc via the 3.1 downgrade | ✅ 5 + 6 tests |
@suluk/hono |
the derivation engine: render(routes, principal, now) -> v4; validation middleware; audit; contract-test generation |
✅ 14 tests |
@suluk/better-auth |
official Better-Auth-on-Hono: auth settings → securitySchemes/security; ingest its openAPI() output via compat.upgrade; session → principal; the fail-closed previewLoginHandler (role-preview) |
✅ 21 tests |
@suluk/drizzle |
data floor: Drizzle table → Zod (drizzle-zod) → v4 schemas + DB metadata + CRUD RouteContracts | ✅ 17 tests |
@suluk/nano-stores |
state corner: v4 contracts → typed @nanostores/query fetcher/mutator stores (Zod-guarded I/O) |
✅ 8 tests |
@suluk/shadcn |
UI corner: v4 Schema Objects → form/table specs + shadcn TSX (react-hook-form + zodResolver) | ✅ 20 tests |
@suluk/builder |
the builder: DSL; buildApp/toShadcnRegistry; modules (C021) — installModule (refuse-on-collision + requires + dangling-ref backstop + namespacing), curated + remote + signed registries, gradeModule/previewInstall, provider slots (swapProvider), composition (planComposition/composeModules + stack templates — the non-dev "compose a platform" flow) |
✅ 77 tests |
@suluk/deploy |
the capstone: swappable DeployProvider; Cloudflare (Workers + D1 + assets); a fail-closed preview variant (two locks + seed) |
✅ 12 tests |
@suluk/cockpit |
the pure cockpit core (10-layer cycle · builder · codegen+diagrams · deploy · drift · cross-cut · converge · D2 diagrams · component pixel-confidence · ship-readiness gates (L3) · role-preview · validate/audit/preview) — shared brain | ✅ 115 tests |
@suluk/admin |
the /superadmin web panel — the cockpit rendered as a Hono web UI, superadmin-gated | ✅ 7 tests |
@suluk/example-petshop |
runnable end-to-end demo — real Drizzle → live CRUD + Scalar + frontend + /superadmin + client round-trip | ✅ 10 tests |
@suluk/docs |
generate a GitHub-Pages docs site from source (Suluk documents itself); packageGraphD2 — the "how the tools compose" diagram on the Architecture page |
✅ 14 tests |
@suluk/cost |
cost as a contract facet — declare per-op cost (x-suluk-cost, bubbles) + meter actual per-user cost | ✅ 10 tests |
@suluk/stripe |
first-class Stripe behind a swappable PaymentProvider; bridges cost → metered billing |
✅ 9 tests |
@suluk/visual |
pixel-confidence by construction — verify each primitive's pixels once; confidence propagates via content-hash | ✅ 9 tests |
suluk-core (Rust) |
perf core: parse + signature + reverse-parse matcher; 2nd independent impl | ✅ 9 tests |
suluk-vscode |
the cockpit's editor face — a thin vscode shell over @suluk/cockpit (Cycle + Builder TreeViews, Environments axis: connect/drift/live-cost, "View as", codegen, install module, ship-readiness checklist, preview as role, deploy) |
✅ 6 tests (+ tsc + bundle) |
Total: 20 TS packages (432 tests) + a Rust core (9 tests) = 441 green. Shipped: npm (@suluk/*),
crates.io (suluk-core), VS Code Marketplace (MahmoodKhalil.suluk-vscode). Live demo: a full SaaS
(saasuluk) on Cloudflare Workers + D1 at saasuluk.saastemly.com — auth (Better Auth/D1), CRUD,
Scalar docs, the /superadmin cockpit, a durable cost ledger, and a static Astro frontend.
@suluk/visual)You shouldn't re-verify every pixel every time. Verify each UI primitive once (render it in isolation, screenshot it, approve it); the approval is recorded against the primitive's content hash. Thereafter any generated UI is pixel-confident without a new screenshot iff every primitive it uses is approved + unchanged — decided by hashing, not rendering. A primitive is re-verified only when its source changes (the hash drifts). Confidence propagates up the component → block → section → page tiers — the same verify-the-source- once discipline as the v4 ledger and the conformance grade.
The cockpit's logic lives once, in @suluk/cockpit (pure: buildCycle, buildBuilderModel, codegen,
deployPlan, validate/audit/preview — no host API). Two shells render it:
suluk-vscode — the editor face (TreeViews + commands + webviews).@suluk/admin — the /superadmin web face (Hono-served HTML, superadmin-gated). Mounted with
app.route("/", adminApp({ document, authorize })); the petshop demo mounts it live.
Because both consume the same core, the admin panel is the extension — it cannot drift from it.@suluk/hono — the derivation engine (design)@hono/zod-validator already declares the input schemas; we read them, so the contract stays
in the route definition (minimal extra typing).emitV4(registry, ctx?) -> { document, diagnostics }. Zod→v4 via @suluk/zod; assemble the v4
Document. ctx = { principal?, now?, servers? } enables the dynamic projection (filter by scope, set
servers by env, mark deprecations by now). No ctx ⇒ the full public doc.validator() middleware. Validate incoming requests against the same Zod schemas the doc is
built from — the doc and the runtime can never drift, because they are one source.audit(document) -> Finding[]. Documentation-coverage: flag operations missing
summary/description/response schema/examples. This is the ceiling side of the Conformance Grade
(an under-documented route indicts the producer). Optional autofill synthesizes sane defaults.generateContractTests(document) -> TestCase[]. The doc as an executable check: per operation,
assert valid example instances satisfy the request schema, invalid ones are rejected, the live
response matches the declared response schema, and ADA signatures don't collide (reuse
core.buildAda().collisions). Emit as bun:test cases.@suluk/better-auth — official Better Auth on Hono (design)securitySchemes (bearer / session-cookie / apiKey) + by-name security from the Better Auth
instance config.openAPI() plugin output (OpenAPI 3.x for /sign-in, /session, OAuth
callbacks, …) → compat.upgrade() → v4 → merge into the app doc, so the auth surface is documented
without re-typing it.principal extractor that feeds render(contracts, principal, now) — closing the loop on
per-viewer docs.@suluk/drizzle (data floor). A Drizzle table is the system of record. tableSchemas (drizzle-zod
select/insert/update) → tableToV4 (via @suluk/zod) → tableComponents; tableMetadata reads
pk/notNull/hasDefault/enum off the column descriptors; crudRoutes(table) emits list/get/create/update/
delete RouteContracts. emitV4(crudRoutes(table)) validates against the meta-schema — the floor reaches
the hub with no hand-written contract.@suluk/nano-stores (state corner). The same RouteContracts the server is built from project into a
typed @nanostores/query client: GET → fetcher stores, the rest → mutator stores, with the contract's Zod
guarding request and response edges (SchemaViolationError). One contract, two projections.@suluk/shadcn (UI corner). v4 Schema Object → formSpec/tableSpec descriptors → shadcn TSX
(renderFormTsx/renderTableTsx: react-hook-form + zodResolver). Codegen only — no runtime UI deps.suluk-vscode — the cockpit (the unifying surface)The extension is where the whole cycle becomes coherent: one v4 document is the hub, and every projection is visible, navigable, and actionable from one place.
buildCycle(doc, {principal?}) (pure, tested). An 8-layer model — data · contract · auth · document ·
docs · state · ui · tests — each layer a projection of the hub. It is a function of the viewer: pass
scopes and scope-gated operations the principal can't reach are filtered out (the per-WHO projection,
applied at the hub; the hidden count surfaced honestly). docChecks = the doc as an executable check.codegen (pure, tested). Actions that land files, each reusing a projection package: generateForm/
generateTable (shadcn TSX), generateStoresModule (the @suluk/nano-stores wiring + derived store
list), exportV4Json. The editor never reimplements a projection.@suluk/builder)Inspired by ~/apps/multivendorbuilder's page → section → block → component DSL, rebuilt with the Suluk
discipline. The load-bearing idea is contract-narrowing: a document's params is EXACTLY and ONLY what
the tier above may set. Each tier consumes the full contract below, hardcodes most of it, and re-publishes a
narrower params upward — the narrowing IS the safety surface (the same discipline as the per-viewer doc
projection, applied to composition). "The owner can't change the form's fields" isn't a rule — fields just
isn't in the section's params.
The Suluk twist binds the tiers to the cycle: lower tiers auto-generate from an entity schema (Form/Table
blocks, a CRUD section, the backend CRUD routes); a page composes sections. So buildApp(spec) emits
both ends from one spec — backend (routes → emitV4 → v4 doc) and frontend (shadcn components + page
TSX). Building a page builds the front and the back, because each entity carries data + contract + UI.
shadcn's registry isn't UI-only: a registry:file item carries arbitrary files to any target. So
toShadcnRegistry(builtApp) packages each slice as one installable unit (npx shadcn add <item>) bundling
its shadcn Form/Table and its backend routes module and its v4 schema. The registry becomes the
universal distribution format for every layer — managed from the cockpit. This is what makes the stack modular
and installable end to end.
The terminal stage: once a user logs into their Cloudflare account through the extension, everything deploys
to Cloudflare — Hono → Workers, the frontend → Pages, Drizzle(sqlite) → D1, plus observability /
compute. This is an adapter, not a rewrite: the stack is already Cloudflare-native by construction (Hono is
the canonical Workers framework; @suluk/drizzle targets sqlite-core, which is D1). Kept behind a
swappable target interface (@suluk/deploy) so Cloudflare is the first provider, not the only one — the
services are built on good standards we can swap later. Built as @suluk/deploy: cloudflare.generate()
emits wrangler.jsonc (D1 binding + static assets SPA-fallback + observability) + worker.ts
(export default app) + schema.sql (from the entities) + an ordered plan (login → d1 create → apply →
deploy). The extension's "Deploy to Cloudflare" command writes these + a DEPLOY.md and opens a terminal —
it never runs wrangler for you (deploys are consequential; OAuth login happens in your terminal).
Cost is just another facet of the contract. @suluk/cost lets an operation declare what it costs you
(per-call + metered third-party usage, in raw µ$); annotateCosts writes it as x-suluk-cost on the
operation, so it bubbles like everything else — through the 3.1 downgrade (the converter now passes x-*
through), into Scalar, into the cockpit's Cost layer, and into a coverage audit (which operations
declared nothing). At runtime, costMeter (Hono middleware) records what each request actually cost,
attributed all the way down: the frontend action (@suluk/nano-stores tags requests with
x-suluk-action) → the operation → each source. The ledger shows the raw per-user picture; you display it
as it is and build pricing on top.
@suluk/stripe is the reference PaymentProvider (swappable — other processors follow Stripe). It
models the modern usage-based stack (Billing Meters + meter events + metered prices, customers,
subscriptions, webhooks) as pure param-builders over a duck-typed client, and a bridge turns @suluk/cost
events into Stripe usage — one meter event per principal. You meter usage; the price + your markup = revenue.
compat collision diagnostics, zod lossy-effect
warnings, hono audit findings, drizzle/shadcn warnings. The pattern is uniform.hono.mount, better-auth.mountAuth, the vscode shell). That is why coverage is high and the host
bindings are trivial.Each package derives one facet from the single v4 contract; here is how they depend on each other — every
package pointing at its @suluk/* dependencies (rendered with d3).