---
title: "The wf CLI"
section: "CLI"
framework: WebFluid
package: webfluid
version: "1.0.0b3"
stage: "beta"
released: "August 17, 2026"
canonical: "https://docs.webfluid.dev/latest/cli/wf.md"
html: "https://docs.webfluid.dev/latest/cli/wf"
audience: ai-agent
format: markdown
---

# The wf CLI


`wf` is the entry point for everything: scaffolding, running, migrating, translating, packaging. It
is a Typer app with five built-in command groups plus one per installed extension.


## The command tree

```text
wf
├── create      Scaffold projects, apps and additives
│   ├── project <name> [-sd] [-sf] [-bf]
│   ├── app <name> [-sl N]
│   └── additive <id>
├── ocean       Search, install and publish Ocean packages
│   ├── login / logout
│   ├── search [query] [-a|-e|-b] [--oss-only|--paid-only]
│   ├── install [-a id[==version]] [-e id] [-b bundle_id]
│   │           [--alpha|--beta|--rc] [-p|--pre] [-ps|--prefer-stable]
│   └── publish
├── run <app> [-h host] [-p port] [-l level] [-d] [-i]
├── node        Forward a command to the bundled Node runtime
├── tailwind    Forward a command to the Tailwind CLI
├── migrate     (extension) Alembic wrapper
│   ├── init <app>
│   ├── revision <app> [-a] [-m msg]
│   ├── upgrade <app>
│   └── downgrade <app> [-r rev]
└── babel       (extension) Translation catalogs
    ├── extract
    └── compile
```

The first five are core. `migrate` and `babel` are **extension CLIs**: on every invocation the CLI
walks `entry_points(group="webfluid.extensions")` and calls `cls.cli_entry(app, ep.name)`, which
mounts each extension's `_cli` Typer app under its entry-point name.

That is the same mechanism your own extension uses — see [`ext/base.md`](/latest/ext/base.md). An
entry point whose target is not a `FluidExtension` subclass is skipped with a yellow warning.

## Where each command runs

| Command                       | Working directory it expects | What it touches                                  |
|-------------------------------|------------------------------|--------------------------------------------------|
| `wf create project <name>`    | Anywhere                     | Creates `<name>/`                                |
| `wf create app <name>`        | Project root                 | Writes `app_configs/<name>.ini`                  |
| `wf create additive <id>`     | Project root                 | Writes `additives/<id>/`                         |
| `wf run <app>`                | Project root                 | Needs `main.py` **and** `app_configs/<app>.ini`  |
| `wf migrate …`                | Project root                 | Reads `app_configs/<app>.ini`, writes `migrate/` |
| `wf babel …`                  | Project root                 | Writes `messages.pot`, `translations/`           |
| `wf ocean install`            | Project root                 | Writes `additives/`, `extensions/`               |
| `wf ocean publish`            | The package directory        | Reads `manifest.json` or `pyproject.toml`        |
| `wf node …` / `wf tailwind …` | Anywhere                     | Forwards through                                 |

> **RULE** — Every command except wf create project and wf ocean publish expects the project root — the directory containing main.py, fluid/ and app_configs/. cd there first.

## Passthrough commands

```bash
wf node node --version
wf node npm --version
wf node npm install
wf node npm run build --workspaces

wf tailwind -- --help
```

Both forward the underlying tool's output verbatim. `wf node` uses the bundled standalone Node
(downloaded on first use, cached in `webfluid/surface/dist`) or a system Node when one is present.
`wf tailwind` needs the `--` separator so Typer stops parsing the following flags.

> **RULE** — In a WebFluid project, run npm through wf node npm rather than a global npm. It guarantees the same runtime the framework will use at boot, and it works on machines that have no Node installed at all.

## Exit behaviour

Commands raise `typer.Exit(1)` on a precondition failure with a red message — a missing app config,
a missing `main.py`, a non-empty target directory, debug mode on port 5173. `wf migrate` shells out
to Alembic with `check=True`, so a failed migration exits non-zero.

## Agent checklist

Reasonable defaults when driving the CLI non-interactively:

| Goal                                           | Command                                                             |
|------------------------------------------------|---------------------------------------------------------------------|
| New project, no interactive frontend questions | `wf create project myapp --skip-frontend`                           |
| New project, full scaffold                     | `wf create project myapp` (asks about the frontend)                 |
| Run for development                            | `wf run app -d`                                                     |
| Run on another port                            | `wf run app -p 9000`                                                |
| Verbose run                                    | `wf run app -d -l debug`                                            |
| Migrate after a model change                   | `wf migrate revision app -a -m "..."` then `wf migrate upgrade app` |

> **WARNING** — wf create app and wf create additive are interactive — they prompt for extensions, features, database URIs, frontend type and more. There is no non-interactive flag. When you need a config file without a TTY, write the .ini yourself; the format is in config/app-config.md.

## Next

- [`cli/create.md`](/latest/cli/create.md) — the scaffolders in detail.
- [`cli/run.md`](/latest/cli/run.md) — what `wf run` arranges.
- [`cli/ocean.md`](/latest/cli/ocean.md) — the package hub.


---

## Navigation


- [Overview](/latest/.md) — what WebFluid is, how to navigate these docs, release state and known bugs
- [Getting Started](/latest/get-started.md) — install, minimal app, the layout the framework expects

**Configuration**
- [App configs](/latest/config/app-config.md) — `app_configs/<app>.ini`, switches, `*_FILE` secrets, `[dev]`
- [Config classes](/latest/config/config-class.md) — `register_config`, `DefaultConfig`, every framework key

**Extensions**
- [Introduction](/latest/ext/base.md) — `FluidExtension`, entry points, `expand_fluid`
- [Scheduling](/latest/ext/scheduling.md) — APScheduler `AsyncIOScheduler`
- [SQLAlchemy](/latest/ext/sqlalchemy.md) — `Model`, executors, binds, sessions
- [Migrate](/latest/ext/migrate.md) — Alembic wrapper, `prepare_fluid`, single/multi-db
- [Mail](/latest/ext/mailman.md) — SMTP, sync/async, batching, attachments
- [Babel](/latest/ext/babel.md) — gettext, domains, locale selection, formatters
- [Security](/latest/ext/security.md) — users, gates, CSRF, tokens, OAuth, bearer grants
- [Events](/latest/ext/events.md) — signals, events, queries, browser socket
- [Cache](/latest/ext/cache.md) — redis / legacy backends
- [JWTManager](/latest/ext/jwt.md) — encode/decode, rotation, revocation

**Frontend (surface)**
- [Introduction](/latest/surface/tooling.md) — feature switches, `fluid_base.html`, Tailwind, themes
- [Integration](/latest/surface/frontend.md) — `APP_FRONTEND`, htmx, Vite workspaces
- [Template resolution](/latest/surface/jinja.md) — loader order, namespaces, overriding

**Additives**
- [Introduction](/latest/additives/intro.md) — manifest, routers, enabling
- [Base Additives](/latest/additives/base.md) — `type: base`, `import_base`, extension semantics
- [Interaction between](/latest/additives/contract.md) — events/queries as contracts, requirements, packaging

**Framework utility**
- [Lifecycle](/latest/utils/lifecycle.md) — `mix()`, startup/shutdown hooks, graceful stop
- [Runtime](/latest/utils/runtime.md) — `FluidContext`, request hooks, themes, proxy, rate limits
- [Logging](/latest/utils/logging.md) — the log factory, levels, files, additive attribution

**CLI**
- [Introduction](/latest/cli/wf.md) — command tree, extension CLIs
- [Create](/latest/cli/create.md) — `wf create project/app/additive`
- [Run](/latest/cli/run.md) — `wf run`, flags, debug and interactive mode
- [Ocean](/latest/cli/ocean.md) — search, install, publish

**Reference**
- [Overview](/latest/ref.md) — package layout, stability contract
- [Core](/latest/ref/core.md) — `Fluid`, config, context, `core.ext`, constants
- [Extensions](/latest/ref/extensions.md) — the battery API surface
- [Surface](/latest/ref/surface.md) — `Frontend`, Node and Tailwind tooling
- [Additives](/latest/ref/additives.md) — `Additive`, `Router`, `Manifest`, registry helpers
- [Utils](/latest/ref/utils.md) — helpers, logging, exceptions