Guide

An HTML codes generator where the backend is already wired before the first line of HTML gets written.

Most tools that call themselves an HTML codes generator hand you a string to copy-paste. mk0r does something different. The moment you start a session, a Neon Postgres project, a Resend sending key, a PostHog app ID, and a private GitHub repo are provisioned in parallel and the credentials are written to /app/.env before the agent sends its first tool call. So the HTML you generate can persist to a database, send mail, fire analytics, and commit itself to git, without you signing up for anything.

M
Matthew Diakonov
11 min
4.8from 10K+ creators
Neon, Resend, PostHog, GitHub on boot
12 env vars in /app/.env before prompt 1
Promise.allSettled, partial failures OK

What every other page on this topic leaves out

Open the pages you reach by typing this guide's title into a search bar. You get snippet catalogs (hero, navbar, card, form, table), block libraries, and one-shot generators that emit a single self-contained HTML file. All useful if the job is a static landing-page mockup. All useless the moment the generated HTML needs to save data, send email, or be shared as a real URL.

None of them mention that the generator they are describing provisions a live database, a transactional email key, an analytics project, or a git remote for you. Because none of them do. mk0r does all four on every session boot. The next sections walk through exactly where that happens in the source.

0Services provisioned per session
0Env vars written to /app/.env
0Provisioning calls in parallel
0Signups required, any vendor

The four services, named and scoped per session

Each service gets its own resource under the mk0r umbrella account, named from the session key. Nothing is shared across sessions except the PostHog ingestion project, which uses a group property for isolation instead of a new project per app.

Neon Postgres

Brand new project named mk0r-<slug>, Postgres 17, aws-us-east-2. connection_uris[0] becomes DATABASE_URL. Use Drizzle plus @neondatabase/serverless right out of the gate.

Resend

A fresh audience plus a scoped API key (sending_access only) created in two sequential calls. audience ID and key land in the env as RESEND_AUDIENCE_ID and RESEND_API_KEY.

PostHog

Shared ingestion project, per-app group ID shaped mk0r-<slug>. Client-side vars (VITE_POSTHOG_KEY, VITE_POSTHOG_HOST, VITE_POSTHOG_APP_ID) are exposed to Vite.

GitHub

Private repo created under m13v, init_auto off. The VM boot script initializes /app as a local repo, points the remote at this URL, and pushes on every chat turn.

The orchestrator, in order

PostHog runs synchronously first (no API call, just a project key plus a generated app ID). Resend, Neon, and GitHub run in parallel via Promise.allSettled, so a failure in one does not block the other two. The wall-clock of the whole call is whichever remote is slowest on the day, not the sum.

src/core/service-provisioning.ts

The deliberate choice of allSettled over Promise.all is the interesting bit. An HTML codes generator that aborts the whole session because GitHub rate-limited the repo create is a bad experience. The orchestrator catches each rejection, logs it, and pushes forward with whatever did land. If your session has DATABASE_URL but no RESEND_API_KEY, the agent still writes HTML that persists data; it just skips the email path.

Inputs, hub, outputs

A session key goes in, four provisioning calls run against their respective APIs, and a bundle of env vars falls out the other side. Those env vars are what the agent sees when it opens /app/.env on its first tool call.

One session boot, four services provisioned

Session key
App name
Provisioning tokens
provisionServices()
Neon project
Resend key + audience
PostHog app group
GitHub private repo

Naming the resources so they stay isolated

There is no multi-tenancy trick here. Every per-app resource is given a unique name derived from the session key by this three-line helper. Two different sessions cannot collide on a resource name because the session keys differ.

src/core/service-provisioning.ts

The twelve-character slug becomes the Neon project name, the Resend audience name (suffixed " Users"), the Resend API key name, the GitHub repo name, and the PostHog group ID. A single grep of mk0r-<slug> across four provider dashboards tells you which resources belong to which session.

What the env file actually looks like

After the orchestrator finishes, the envVars record is flattened by buildEnvFileContent into a newline-delimited .env and written into the VM at /app/.env. Here are the exact keys the code sets, grouped by service.

src/core/service-provisioning.ts

Twelve vars when everything lands. Fewer when a service rejected. Note the Vite convention: the PostHog keys are prefixed VITE_ so they get exposed to client-side code via import.meta.env. The Neon and Resend keys are server-side only, so they are read as process.env inside a Node script or a build-time route.

How the agent learns these exist

Provisioning the vars is half the trick. The other half is telling the generator to check for them before asking you for API keys or trying to sign up for a free-tier Postgres. That instruction lives verbatim at step 2 of the Workflow block in the VM's global CLAUDE.md.

src/core/vm-claude-md.ts

That single bold line shifts the agent's default behavior. Ask for "a signup form that stores submissions in a database" and the agent, instead of asking you to connect a Supabase project, opens /app/.env, sees DATABASE_URL, installs @neondatabase/serverless, and writes the Drizzle schema. The HTML code that came out is actually wired up.

Watch the provisioning happen in the server log

Every step emits a structured log line via the plog helper. Here is a compressed trace of a single session boot on a good day, reassembled from the events the orchestrator emits.

provisionServices() on a healthy session

What the agent does with those vars

The backend-services skill at /root/.claude/skills/backend-services/SKILL.md teaches the agent how to wire each service into a Vite project. Here is the shape of a typical turn, taken from the skill's integration patterns.

From a prompt to HTML that actually runs

1

You type: 'signup form that stores emails'

A one-line user prompt. No mention of a database, no request for keys.

2

Agent opens /app/.env

Step 2 of the Workflow block. It finds DATABASE_URL, RESEND_API_KEY, VITE_POSTHOG_APP_ID. It does not prompt you for them.

3

Installs only what is needed

npm install drizzle-orm @neondatabase/serverless. No Supabase signup, no free-tier Mongo.

4

Writes the Drizzle schema and handler

Real schema file in src/db/schema.ts, a form component in src/components/SignupForm.tsx, an App.tsx import, a small server handler.

5

Runs drizzle-kit push against the real Postgres

The migration hits the Neon project created at session boot. The emails table exists in a real database before you see the page.

6

Chat returns a preview URL

Vite serves the form at port 5173 of the VM, which maps to <vmId>.mk0r.com. Submissions land in your Neon Postgres immediately.

7

Turn commits to the GitHub repo

commitTurn runs git add -A, git commit, git push against the private repo provisioned at boot. The HTML code is versioned from the first turn.

How this compares with what else comes up on this topic

No tool wins on every axis. Snippet catalogs are faster if you just need a navbar to paste into an existing site. Visual builders beat a chat UI if you want to drag a hero around. But if the question is "what happens when the generated HTML needs a backend," the comparison is stark.

FeatureTypical HTML codes generatormk0r
Database available to the generated HTMLNo, bring your ownYes, Neon Postgres provisioned at boot, DATABASE_URL in /app/.env
Transactional email available to the generated HTMLNo, bring your ownYes, Resend API key plus a per-app audience
Analytics available to the generated HTMLNo, paste a Google Analytics snippetYes, PostHog key plus a per-app group ID for isolation
Version control for the generated HTMLNo, clipboard is the storage mediumYes, private GitHub repo plus a commit per chat turn
Signup required on your endVaries, often an email at minimumNone, provisioning runs under the mk0r umbrella
What you get after one promptA string in your clipboardA running app at <vmId>.mk0r.com with real services wired
Partial-failure behaviorN/APromise.allSettled, one dead service does not kill the session
Inspectable provisioning logicClosed, or non-existentsrc/core/service-provisioning.ts, public repo

What gets wired, at a glance

The usual list of "things a code generator can emit" is fine. The more useful list is "things a generator can emit that will actually function without any extra work from you".

/app/.env with DATABASE_URLResend audience pre-createdPostHog group ID mk0r-<slug>Private GitHub repoDrizzle-ready PostgresScoped sending-only keyVite plus React plus Tailwind v4Playwright MCP attachedCommit per chat turn

By the numbers

The thing that makes this work without a signup is counted, not claimed. Here are the exact integers.

0
Services provisioned
0
Env vars on boot
0
Char app slug
0
Vendor signups

When this is overbuilt

If all you need is a snippet for an email signature or a static table to paste into a CMS, the provisioning pipeline is doing nothing useful for you. Use a snippet catalog and move on. The whole point of wiring Neon, Resend, PostHog, and GitHub on boot is that the moment a prompt says "save," "send," "track," or "share," the agent can just do it without asking you for anything.

A useful rule of thumb: if the HTML has a form or a button that should do something, this tool is designed for that. If it is purely decorative, almost anything will generate it.

Want a walkthrough of the provisioning pipeline?

Fifteen minutes. I will show you the four services landing in /app/.env on a real session boot and answer any build questions.

Book a call

Frequently asked questions

What does 'HTML codes generator' mean inside mk0r specifically?

A chat UI on mk0r.com that boots a fresh E2B sandbox, provisions four external services into /app/.env, and hands an agent a Vite + React + TypeScript project at /app. The agent writes components, Vite renders real HTML on port 5173, and you see the output in the preview iframe. Unlike snippet catalogs that hand you a string, every 'code' the agent generates lands in a live project that already has a database connection string, a transactional email key, analytics credentials, and a private git remote.

Which four services get provisioned, and where is that logic?

Neon Postgres (a brand new database project), Resend (a fresh audience plus a scoped sending API key), PostHog (a per-app group ID sharing the mk0r ingestion project), and GitHub (a private repo under the m13v account). The orchestrator is the provisionServices function in src/core/service-provisioning.ts, lines 277 to 362. The four services race in parallel via Promise.allSettled at line 297, so the slowest of the three async calls sets the wall-clock.

What exactly lands in /app/.env before the first prompt?

Twelve variables, written by buildEnvFileContent at line 367 of src/core/service-provisioning.ts. DATABASE_URL, NEON_HOST, NEON_DB_NAME, NEON_ROLE_NAME, NEON_ROLE_PASSWORD for the Postgres. RESEND_API_KEY and RESEND_AUDIENCE_ID for email. VITE_POSTHOG_KEY, VITE_POSTHOG_HOST, VITE_POSTHOG_APP_ID for analytics. GITHUB_REPO and GITHUB_REPO_URL for the remote. If a provider fails, its vars are simply absent (the agent is told to check before using any env var).

How is per-app isolation achieved without creating new accounts?

A tiny helper called appSlug at line 65 of service-provisioning.ts takes the session key, strips non-alphanumerics, slices the first twelve characters, and lowercases it. Every downstream resource name is prefixed mk0r-<slug>: the Neon project, the Resend audience and API key, the GitHub repo, and the PostHog group ID. So 'isolation' is per-resource name, not per-account. You never signed up for anything.

What happens if one of the three remote provisioning calls fails?

The orchestrator catches each rejection independently, logs it with plog, and records it on a ProvisioningResult.errors array. The other services still get wired up. The generated HTML can then use whatever services did land in /app/.env. If you see an app that has DATABASE_URL but no RESEND_API_KEY, it means the Resend call rejected and the pipeline kept going. That partial-failure behavior is why the orchestrator uses allSettled instead of Promise.all.

So the 'HTML code' the generator writes can actually write to a database?

Yes. The VM's CLAUDE.md tells the agent at line 69 to 'Check /app/.env for pre-provisioned services before creating new accounts or asking the user for API keys.' The backend-services skill at src/core/vm-claude-md.ts line 1196 shows it how to wire Drizzle plus @neondatabase/serverless against DATABASE_URL. Generate a sign-up form, and the agent knows a real Postgres already exists to take the submissions. No 'connect your database' modal.

Is the GitHub repo just for show, or does the generated HTML actually get pushed there?

It gets pushed. The VM init script initializes /app as a git repo, configures a user, sets the remote from GITHUB_REPO_URL, makes an initial empty commit, and force-pushes to main. After that, every chat turn becomes a real commit via commitTurn, which runs git add -A, git commit with the first line of your prompt as the message, and git push origin main. So the HTML codes that were generated during your chat session live in a real private GitHub repo you can clone.

What about PostHog, what does the 'app ID' actually do?

PostHog is shared across all mk0r apps under one project, so isolation is done at the group level. The appId is shaped 'mk0r-<slug>' and set as a group property on every event via posthog.group('app', appId). The Tracking events pattern in the backend-services skill uses this. You can filter any PostHog dashboard by the app group to see only your app's events, without provisioning a new PostHog project per session.

Can I turn the generated HTML into a static site, or is it locked to the VM?

Run npm run build inside the VM and ship /app/dist. That directory is plain HTML, hashed CSS, and hashed JS with no server requirement. But the DATABASE_URL, RESEND_API_KEY, and so on were injected into the runtime, so a static build only makes sense if your HTML doesn't need them. If it does, deploy the /app directory to any host that runs a Node server, or publish through mk0r and the preview URL becomes your public URL.

Do I need to sign up for Neon, Resend, or GitHub to get these?

No. mk0r uses its own provisioning tokens (NEON_PROVISIONING_KEY, RESEND_PROVISIONING_KEY, GITHUB_PROVISIONING_TOKEN) to create the per-app resources under its own umbrella accounts. You never see a signup screen for any of them. The resources are provisioned under mk0r's org and scoped to a sessionKey-derived name. If you later want to move them to your own accounts, you can export the Postgres via pg_dump, move the audience to your own Resend workspace, and transfer the repo to your personal GitHub.

Generate HTML against a real Neon Postgres, a real Resend key, a real PostHog app, and a real git remote. No signup, no card, no setup.

Try mk0r