Run
The very first thing you did in this guide was wf run app. Now that you've seen
the whole stack, here's what that command actually arranges — and the few flags that
change how your app comes up.
What run does
wf run <app> takes the name of an app config, reads
app_configs/<app>.ini into the environment, sets a handful of runtime
variables (the app name, host, port, log level) and launches your main.py as a
child process. It streams the app's output to your console while the app itself writes a plain
copy into a timestamped log file under logs/<app>/. Both an app config and a
main.py have to exist, otherwise it tells you to create them first.
It also hands the child the things a terminal application needs to know about the terminal it
is not attached to: the console width and height, and your console encoding. That is why a
progress bar inside your app — the startup phase bars, a tqdm loop of your
own — comes out the right width and redraws in place instead of scrolling one line per
frame. Redirect the output to a file and the bars degrade to plain ASCII rather than failing
to encode.
Two conveniences happen while the config is read in. Any key ending in _FILE is
treated as a path: the file is read and its contents are exposed under the key without the
suffix — handy for Docker style secrets. And a [dev] section is only applied
when you pass -d, so development-only overrides never leak into a normal run.
The flags
--host/-h— bind host. Default 127.0.0.1.--port/-p— bind port. Default 8000.--loglevel/-l— log verbosity (passed through to the log session). Default info.--debug/-d— run in debug mode.--interactive/-i— run with the interactive control menu.
# Plain run on a custom port
wf run app -p 9000
# Debug mode with verbose logging
wf run app -d -l debug
Debug mode
The -d flag is what lights up the frontend developer experience. In debug mode
the framework starts the Vite dev server, proxies it for hot module replacement, and rewrites
your pages to pull assets from it — everything we described in the Frontend chapters.
It also relaxes the secure session cookie (so the session survives plain http) and swaps the
generic error page for a detailed debug traceback.
Debug mode is not compatible with port 5173 — that one is reserved for the Vite dev server it manages for you. Pick any other port and you're fine.
Interactive mode
With -i, instead of streaming straight to your terminal, run drops
you into a small control menu — restart, stop, start, join the live log (leave it again
with ESC), clear the log folder, clear the console. It asks for host, port and
debug up front if you didn't pass them. It's handy for babysitting a long-lived process during
development, and it behaves the same on Windows as on POSIX systems.
The application's output is read continuously whether or not you are watching it, so muting the stream by returning to the menu never blocks the app on a full pipe, and joining the log again picks up from wherever it is. When you stop the app, the reader is drained before the closing message — so the shutdown hooks you wrote in the Lifecycle chapter print where they happened, not after the goodbye.
A plain (non-interactive) run forwards SIGINT and SIGTERM for you, so a clean Ctrl+C triggers the graceful shutdown sequence from the Lifecycle chapter: in-flight request finishes, shutdown hooks run, process exits.
That's the tour
From a single main.py to a fullstack runtime with batteries, modules and a
managed frontend — and a CLI that scaffolds and runs the lot. You now have the whole
map. For the precise surface of every class and function, the Reference is next.
Continue reading
From here you can continue straight with Ocean.