The environment the wizard reads and writes
The variables the wizard itself reads, the .env and .env.example it leaves behind, what --embed appends instead of overwriting, and the guard that refuses to persist a token.
This page covers the environment the wizard reads and the file it leaves behind; the variables the app itself reads at build and run time are on Environment variables.
What the wizard reads
| Name | Where it is read | What it does |
|---|---|---|
CHATFUEL_TOKEN | The token step, first attempt. | Used instead of the prompt, and still checked against the API. Under --yes, or with no TTY, its absence — or its rejection — ends the run rather than falling through to a prompt nobody can answer. |
SUPABASE_ACCESS_TOKEN | The auth step, and again by the deploy step. | The Supabase Management API token, when --supabase-token is not given. The deploy step reads it a second time to add the deployed origin to the redirect allowlist. |
SUPABASE_SERVICE_ROLE_KEY | The auth step, manual path only. | Taken from the environment instead of being asked for a second time. |
ADMIN_PASSWORD | The admin step, when --admin-password is not given. | Used as-is; only when neither is present does the wizard generate one. |
INIT_CWD | Every path the wizard resolves. | Where you were standing when you started it. A package-manager run moves process.cwd(), so --dir ./app would otherwise land inside the wrong directory. |
npm_config_user_agent | Preflight. | Whether pnpm is even considered. pnpm is chosen only when pnpm launched the wizard and is really installed; otherwise npm, which ships with Node. |
https_proxy, http_proxy, all_proxy, no_proxy | Every outbound call the wizard makes, in lowercase and uppercase. | Node's built-in fetch ignores these, so the wizard reads them itself — otherwise every call behind a company proxy times out and the token check reports "could not reach the API", which reads as a bad token. doctor prints the one it can see. |
The file it writes
.env, at mode 0600, in the app the wizard has written. Its contents are the app's own two variables —
VITE_APP_NAME and VITE_APP_LOGO, which belong to the deployment rather than to any module —
followed by the union of the selected modules' declared variables, first declaration winning.
Each value is resolved in one order: a value a step already settled (the workspace, brand and auth
steps), then the Chatfuel token, then the manifest's default, then empty. A variable that is
declared optional and resolves to nothing is written as a commented # NAME= line, so the file
documents it without setting it.
.env.example sits beside it. That one is not generated: it travels with the app template and is
copied whole, which is why it carries a paragraph of reasoning above every name instead of a value.
The auth module also declares SUPABASE_PROJECT_REF, which the wizard fills in whenever it knows
the ref. Nothing reads it at runtime and no deploy pushes it — it is bookkeeping, so you can find
the project the app belongs to without opening the URL.
A set-but-empty variable reads as configured everywhere downstream, which is why the wizard
writes # NAME= rather than NAME= and why the deploy script skips both. Filling one of those
in with an empty value is how a deployment ends up half-gated.
npm start loads a .env sitting next to the app, and real environment variables win over it — so
the file the wizard wrote keeps working after a build, and a platform that sets real variables is
never overridden by it.
What --embed appends instead of overwriting
An embed lands in a project you already have, which may already have a .env. So the step appends
only the keys that file does not define, under a # Added by chatfuel-wizard comment, and never
edits a line that is already there.
| Case | What happens |
|---|---|
| The key is absent | Appended, and reported as added. |
| The key exists with a different value | Left untouched, and reported: .env already defines NAME with a different value. |
The key exists as a # NAME= placeholder the wizard wrote before | Skipped, so a re-run does not append it twice. |
| The file did not exist | Created, and only then set to mode 0600 — an existing file's permissions are the host's business. |
That tree, those .env keys, a .gitignore line, the skills and the agent's handoff files are the
whole footprint. No vite.config, no tsconfig and no CSS of yours is edited — the wiring is the
agent's job, guided by the playbooks in the installed skills. The one exception is the dependency
install, which you confirm and your own package manager performs.
The guard that refuses to persist a token
Before either mode writes anything to .env, the wizard checks that .gitignore has a line that
ignores it. Without one, it asks. Say no and it writes no environment file at all — the app is
still scaffolded, and the wizard prints the command that starts it with the token passed on the
command line instead.
Under --yes the line is appended without asking — there is nobody there to ask, and the
alternative is an unattended run that produces an app with no token in it.
One wrinkle in a packaged install: npm reads a nested .gitignore as ignore rules for its own
directory, so the template's copy would drop files from the published tarball. It travels as
_gitignore and the scaffold step renames it back — before the guard runs, which is what keeps
the guard from failing on a file that is there under another name.
What the wizard does, step by step
The wizard's step sequence in order — what each step asks, what it writes, when it is skipped, and which ones reach your Chatfuel account.
Scripts in the generated app
Every npm script the scaffolded app ships with — what it runs, when you reach for it, and what has to be true first.