# 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.

Page: https://sdk.chatfuel.com/docs/reference/environment
Markdown: https://sdk.chatfuel.com/docs/reference/environment.md

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](/docs/deploy/environments).

## What the wizard reads [#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 [#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.

<Callout type="warn">
  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.
</Callout>

`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 [#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 [#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.
