CLI
ff is a single binary. Run it with no arguments to print the built-in usage summary; ff -h, ff --help, and ff help print the same.
Errors & exit codes
ff renders its own diagnostics in a fixed shape:
erroris printed in red andhintin dim when stderr is a TTY. Color is auto-disabled when output is piped or redirected, or whenNO_COLORis set (to any value).- Progress, success, and detail lines use a small glyph vocabulary:
→for a step in progress,✓for a completed step, and•for secondary detail. The glyphs are plain UTF-8; only color is TTY-gated. - Every command exits
0on success and1on failure. This includes usage errors (missing arguments, unknown options), a missing or invalidff.json, network/registry failures, integrity mismatches, and failed tests. Several failure paths that used to print a message but exit0—ff upgradeon a network error,ff start/--watch startwith noff.json,ff imprintorff severwith a malformed manifest, TLS setup errors inff start— now exit1. - An unknown option prints
error: unknown option '--x'and a hint to runff --help; a missing argument prints the sameerror:plus the command's one-lineUsage:. - JavaScript exceptions are not part of this shape: they keep their own
Error: …output from the runtime and REPL.
Quick look
Run a file
Runs the given JS file — or .ffbc bytecode (the loader detects the magic). The process exits when the event loop drains.
--ca trusts an extra CA bundle for that run's outbound fetch / WSS. It is accepted only by ff <file> and ff -e — not by ff start (use FF_CA_FILE there).
--allow-ffi unlocks the ffi global (ffi.dlopen) for that run. Native code bypasses every sandbox guarantee, so without the flag ffi.dlopen throws and ffi.allowed is false. Accepted by ff <file>, ff -e, ff test, and ff start. See FFI for the full API and security contract.
Evaluate inline code
Runs the string as a classic script — no top-level await (it's a
SyntaxError; wrap in an async IIFE when you need await). Accepts
--ca like ff <file>. Handy for smoke tests:
Scaffold a project
Prompts (Enter accepts each default), skipped entirely with -y / --yes:
Writes ff.json plus the entry file (console.log("Hello from fairyfly!")). Optional [<dir>] scaffolds inside a new directory.
Caution:
ff initalways overwritesff.jsonand the entry file. Back them up first if you customized them.
Serve a project
Reads main from ff.json and runs it as a module (max 10MB). Missing or invalid manifest prints an error and exits.
When the entry starts an HTTP server, ff prints the step and the bound URL:
With TLS (--cert/--key or http.serve({ tls })) the URL uses https://.
Both must be given together. On success the same port serves HTTPS/WSS too, and the cert path is trusted by the runtime's own outbound fetch / WebSocket — convenient for self-signed dev setups.
The port comes only from http.serve({ port }) (default 3000). There is no --port and no FF_PORT.
Install packages
Only ESM-compatible packages pass the pure-ESM gate.
Direct sources also accept https://github.com/owner/repo[#ref] and
https://codeberg.org/owner/repo[#ref]; omit #ref to use HEAD. The archive
root must contain package.json. Private repositories, authentication,
monorepo subdirectories, and build scripts are not supported. The lock pins the
archive URL and a computed SHA-512 integrity hash; a moved branch fails the
integrity check instead of installing different code.
Remove packages
Names are scope-aware: ff sever @scope/pkg@1.0 strips to @scope/pkg.
Run the test suite
Runs every test/*.test.js through the runtime (same convention as test/run.sh — see the Testing guide). The optional filter is a substring match on the filename. Each file evaluates to success with no FAIL lines; exits 1 if any test fails. Files larger than 10MB are not loaded. Pass --allow-ffi to run the FFI contract (test/ffi.test.js); without it the FFI tests skip.
Interactive REPL
Line buffer is 8192 bytes. Async work runs after each line via microtasks + event loop.
Compile to bytecode
Compiles an ES module to QuickJS bytecode with source and debug info stripped. Default output replaces the extension with .ffbc. Input cap: 20MB.
Format code
Delegates to npx --yes prettier (needs network, or a global prettier). Without files it prints usage; exit code is non-zero when prettier fails.
Self-update
Queries GitHub Releases for AbdElMajidOuhamane/ff (needs curl), compares semver against ff --version:
Note: Releases are published at github.com/AbdElMajidOuhamane/ff/releases —
v0.2.0-betais the first. With a release available,ff upgradereports up-to-date for current builds, downloads when you're behind, and only takes the failure row on network errors or a missing release asset.
Print the version
Proxy environment
Outbound fetch / WebSocket requests in every command honor the standard
proxy environment variables. They are read once at process start:
Proxy URLs may carry credentials (http://user:pass@proxy:8080). SOCKS is
not supported. See fetch Proxies for matching
details and examples.
