Skip to content

CLI reference

npx wawesome fetches the CLI each time you name it, so there is nothing to install and nothing to keep up to date. Node 22.13 or newer is the whole requirement.

Most commands read wawesome-function.json in the current directory to find the App and the Function they act on. logs, invoke and cron take a Function name as an argument. Those three and domains take --app <slug> to reach another App. Most commands take -v, which prints the gateway they are talking to and the App and Function they resolved.

When a command fails, what it prints is the gateway’s own error. Errors lists every reason one carries and what to do about each.

Command What it does
npx wawesome login Opens your browser at the wawesome sign-in page and writes ~/.wawesome/credentials.json
npx wawesome logout Ends the session on the platform and clears those credentials
npx wawesome whoami Prints who you are, the workspace, and the gateway your token belongs to

Everything you choose happens on that page. You sign in there. If you belong to one workspace, that is the whole of it: the tab finishes by itself and your terminal is signed in, with nothing to press. If you belong to more than one, you pick which one this terminal acts in. If you belong to none yet, you make your first one on the same page: it asks what to call it and what address it should answer at, offering the name in address form, and it takes your acceptance of the terms. Leave the address empty and one is made up for you. Whichever of the three you are, one run of login is enough.

login opens a tab and waits for it on localhost:9999. The listener is on loopback only, so no other machine on your network can reach it, and it answers one browser: the tab login opened. Anything else that arrives is turned away, your terminal says so, and the login keeps waiting. If something else is already holding port 9999, login says which port and stops. A sign-in is good for ten minutes and is finished once, so a tab you walked away from means running login again. If many sign-ins start from one address at once, which an office behind one connection can do, the platform asks you to wait a minute and try again. Nothing is wrong with your account when that happens.

Your session outlives the token it is built on. The token a command sends is worth half an hour; when one runs out mid-command, the CLI renews it against the platform and the command carries on. Nothing is printed about it, and a logs --follow running for hours keeps its stream. Two commands running at the same time both keep working when they meet the same expiry.

A session nobody renews for ninety days is over, and the next command asks you to run login again. Using the CLI renews it, so this only happens to a terminal you stopped using. The same happens at once if somebody signs you out of the workspace.

logout ends the session on the platform first, then deletes the file. A copy of ~/.wawesome/credentials.json taken before you signed out is worth nothing afterwards. If the platform cannot be reached, the file stays where it is and logout says so. That file holds the only copy of the token that can end the session, so run logout again when you are back online.

A token is only valid at the gateway that issued it, so login records which gateway it used and every later command goes there. To reach a local or self-hosted one, pass npx wawesome login --gateway http://localhost:3000, set WAWESOME_GATEWAY_URL, or put {"gateway_url": "..."} in ~/.wawesome/settings.json. login reads only those three. A bare npx wawesome login always goes to https://api.wawesome.io.

Command What it does
npx wawesome workspace The workspace name, its address, and when the address can next change
npx wawesome workspace show The same thing, spelled out
npx wawesome workspace list Every workspace you belong to, with the one you are in marked
npx wawesome workspace switch <name> Moves this terminal to another workspace you belong to
npx wawesome workspace rename <name> Changes the public address. After your first deploy, once every 30 days

The address is the first half of the hostname every Function you deploy answers on. You choose it when you sign up, and rename changes it. Only the workspace owner can rename.

Before your first deploy, a rename is free. The address you leave stops working at once and goes back on offer for anyone to take.

After your first deploy, live URLs carry the address. You can still rename, once every 30 days. The old address answers 308 for 90 days and sends every request to the same path under the new one. Preview links under the old address stop working. After the 90 days the old address stops answering, and we hold it for 90 more days so nobody else can take it. Until those 180 days are over you can rename back to it, which counts as a rename like any other. Every owner and admin of the workspace gets an email with the old and the new address.

A rename after your first deploy says what it will do and asks you to type the new address again. --yes skips that. Without a terminal, for example in CI, the rename is refused unless you pass --yes. Inside the 30 days, rename is refused before anything is sent, and it names the date the next rename is allowed.

If you belong to more than one workspace, this terminal is in one of them at a time, and list shows which. switch moves it, and no browser opens: your session belongs to you rather than to one workspace. Name the one you want by its address or by its name. The move sticks: every later command goes there, whoami says so, and a session that renews hours later stays put. A workspace you are not a member of is refused, and the refusal lists the ones you are in.

Command What it does
npx wawesome templates Lists the template catalogue. No login needed
npx wawesome templates list The same list
npx wawesome init Scaffolds a project in the current directory
npx wawesome init --template <name> Scaffolds from a template, asks for what it needs, and deploys
npx wawesome init --root Scaffolds a root Function, which answers at the App’s own address
npx wawesome init --no-install Scaffolds without running your package manager

init asks for the Function name and the App slug, and both default to the directory name. Both go into the public URL, so both have to be legal hostname labels: lowercase letters, numbers, and single hyphens between them, no hyphen at either end, 63 characters at most. Answer My Client and the CLI shows you the my-client it would have to use, then asks again. It does not rewrite what you typed.

Run it in an empty directory. If any file would be overwritten, nothing is written at all and the CLI names the collision.

--template goes from nothing to a deployed Function in one command. The template is downloaded over plain HTTP, so git is not required. The CLI asks for each environment variable the template declares, enables the outbound providers it calls, installs your dependencies, and deploys. Leave a value blank if it does not exist yet and the CLI prints the env set command to run once it does.

Command What it does
npx wawesome build [entry] Bundles the entry point to dist/index.js
npx wawesome build -o <path> Writes the bundle somewhere else
npx wawesome deploy [entry] Builds, uploads, and promotes a new version to production
npx wawesome deploy --skip-build Uploads the bundle already on disk
npx wawesome deploy -m "<text>" Records one line about what this deploy carries
npx wawesome deploy --publish Confirms putting a private Function back on its public address
npx wawesome deploy --drop-assets Confirms a deploy carrying no static files where the live version serves some

deploy prints the address the Function answers on, the version it made, and its visibility. Every path beneath that address reaches the same Function.

If the code and files are byte for byte the version that’s live, deploy makes no new version. It says so and exits 0, so a CI job that deploys on every push stays green when only a README changed. The -m text doesn’t count as a change. If they match an older version that isn’t live, deploy exits 1 and names the version switch that puts it back.

-m writes one line about what you are shipping, and the version keeps it. version list shows it under the version number, so a list of numbers becomes a list you can read. Keep it to one line and 200 characters. A longer one turns the deploy down instead of cutting it, so nothing you wrote goes missing quietly. -m "" deploys with no message, which is what every deploy did before the flag existed.

--publish and --drop-assets exist because a deleted line should never make either change on its own. Deleting "visibility": "private" puts a job back on the open internet. Dropping "assets" takes every file on a site down at once. Each is turned down until you type the flag.

What "assets" points at, and where each file it carries answers, is in documents. So is "files", the directory of private files no address serves.

Command What it does
npx wawesome version list Every version of this Function, and which one is live
npx wawesome versions The same list
npx wawesome version switch <version> Puts a version the Function already has back on its address
npx wawesome switch <version> The same switch

Switching builds nothing and uploads nothing. It points the Function’s public address at a version we already hold, and the next request arrives on it. Requests already running finish on the version they started on. The version you switched away from is still there, so switching back is the same command with the other number.

A version carries the code and the static files that one deploy declared. Nothing is inherited from the version before it, so a rollback takes the pages back along with the handler. What a Version is, and why a deploy makes one, is in concepts.

version list prints the message each deploy stated under its version, cut to the width of your terminal. Switching takes no message of its own. The message belongs to the version, so switching back to v13 shows you what v13 was deployed with.

All four take -e <environment>, which defaults to production.

Command What it does
npx wawesome env list Every variable on this App
npx wawesome env set <key> <value> Sets one, or overwrites it
npx wawesome env set <key> <value> --secret Sets one write-only
npx wawesome env rm <key> Deletes one

Variables belong to the App rather than to any one Function inside it, so every Function in the App reads the same set. A variable set --secret is never read back, by you or by anything else. env list shows that it is set and not what it says.

Command What it does
npx wawesome logs Recent invocations of the Function in this directory
npx wawesome logs <function> Recent invocations of a Function you name
npx wawesome logs <invocation-id> The stdout and stderr one run captured
npx wawesome logs --invocation <id> The same body, with the id behind a flag
npx wawesome logs <function> --follow Streams output as it runs, and waits for the next run if nothing is going
npx wawesome logs <function> --error Failed runs only. --success, --timeout, --running and --status <status> filter the same way
npx wawesome invoke Fires a run of this Function now and follows its output
npx wawesome invoke <function> Fires a run of a Function you name
npx wawesome invoke -m POST -d '{"event":"audit"}' Sends a method and a body with the run
npx wawesome invoke --no-follow Fires the run and exits

An invocation id is what a response carries back in x-wawesome-invocation-id, so a caller who saw a failure can hand you the exact run to read.

--follow reconnects with back-off on a dropped connection or a 5xx, three times. It does not retry a 401 or a 404, since neither improves by being asked again. You hold one live tail per credential.

Command What it does
npx wawesome cron Schedules for this Function, with their expression, state and next run in UTC
npx wawesome cron list <function> Schedules for a Function you name. --app <slug> lists a whole App
npx wawesome cron pause <schedule> Stops a schedule. -r "<reason>" records why
npx wawesome cron resume <schedule> Starts it again, counting from now
npx wawesome cron history Runs that already happened: when each was due, when it started, how it ended
npx wawesome cron history <function> --state failed The same history, filtered by state
npx wawesome schedules Another name for cron

You declare schedules in wawesome-function.json, and a deploy applies them. Pausing is not in the file, and it survives every later deploy. When a job runs is code. Whether it is running is not. Resuming counts the next run from now and backfills nothing.

The listing tells three off-states apart. paused was stopped by a person and cron resume starts it. not in this config file was removed from the config, and only declaring it again turns it back on. suspended was stopped by non-payment and resumes once the balance is settled.

Declaring one, the plan you need for one, and what each run state in the history means are in schedules.

Command What it does
npx wawesome domains The App’s domain, where it got to, when that was last checked, and the DNS records to add
npx wawesome domains adopt Writes the hostname the App answers at into wawesome-function.json
npx wawesome domains detach <hostname> Stops serving the App at a domain you attached

You attach a domain by declaring "domain" in wawesome-function.json and deploying. The dashboard attaches one too, and so does an agent. Both leave the file saying nothing about it, which is what adopt fixes. domains changes nothing, and a deploy credential carrying read:domains can run it, so a pipeline reads the same states you do.

Detaching is typed out in full because it takes a live site dark. Deleting the line from the file detaches nothing.

The records to add, what each state means for traffic, and the record that is in but proxied are in custom domains.

A deploy credential is what a CI pipeline or an agent authenticates with, where nobody is at a keyboard to log in. What each capability lets you do, and how to hand one to a pipeline, is in deploy credentials.

Command What it does
npx wawesome credentials Name, prefix, capabilities, Apps, last use and expiry. Never the secret
npx wawesome credentials list The same listing
npx wawesome credentials mint <name> Mints one and prints its secret, once
npx wawesome credentials regenerate <name-or-prefix> Replaces the secret, keeping the name and the grant
npx wawesome credentials revoke <name-or-prefix> Stops it working, immediately and for good
npx wawesome credentials delete <name-or-prefix> Removes a revoked or expired one, freeing its name

Minting, listing, regenerating, revoking and deleting all run on your own npx wawesome login session. They are closed to deploy credentials whatever those carry, so a leaked credential cannot mint another or renew its own expiry.

mint and regenerate print the secret on stdout alone and everything else on stderr, so npx wawesome credentials mint ci > secret.txt catches the secret and nothing besides.

Command What it does
npx wawesome export Asks for an archive of the whole workspace, waits, and prints the link
npx wawesome export --no-wait Asks for one and returns straight away
npx wawesome export status The latest export, with a new link if it is ready

Only the workspace owner can export, on their own login. The link works for an hour, and the archive is deleted after seven days. What is in it is in exporting a workspace.

Command What it does
npx wawesome --help Every command. npx wawesome <command> --help for one of them
npx wawesome --version The version of the CLI that just ran

Your Function does not run on Node. Every build scans the bundle it just produced against the globals we provide, and says nothing unless it finds something.

These are not provided: Intl, URLPattern, WebSocket, EventSource, BroadcastChannel, caches, FileReader, WebAssembly, XMLHttpRequest, navigator, localStorage, sessionStorage, indexedDB, setImmediate, reportError, Atomics and SharedArrayBuffer. Limits says what to reach for in place of each.

Where the bundle reaches one as it loads, in your own module scope or a dependency’s, the build is turned down before anything is uploaded. That bundle would not evaluate here. Where the reference sits inside a function that may never be called, behind a typeof check, or inside a try, you get a warning and the deploy goes ahead. A library that asks whether WebSocket is there before it uses one is that second case, and it deploys.

toLocaleString, toLocaleDateString, toLocaleTimeString, toLocaleLowerCase and toLocaleUpperCase ignore the locale you pass them. They run and return an unlocalised answer, so these warn rather than stop the build. (1234.5).toLocaleString('en-US') comes back as "1234.5", not "1,234.50".

Each message names the global, the file and the line in your own source, and what to do about it. The scan reads static references only, so a global reached through globalThis['Intl'] is invisible to it. No deploy is ever turned down on a guess. deploy --skip-build scans the bundle it found on disk before uploading it.

To silence the report, declare a polyfill in your package.json as you normally would, or install one on globalThis in the bundle itself. A dependency that provides Intl or URLPattern is left in place rather than stripped out from under you. The others have no polyfill to declare. What they need is a socket, a disk, a second thread or a browser, and none of those is in the sandbox for a polyfill to build on.

Node has Intl, and its toLocaleString honours the locale you pass. That is how a green test suite ships a Function that throws in production. Point your suite at the same globals we have instead:

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: { setupFiles: ["wawesome/vitest-setup"] },
});

Templates scaffolded with wawesome init --template ship this already. With it in place the globals above are gone, MessageChannel, MessagePort, MessageEvent, TextEncoderStream and TextDecoderStream are our implementations rather than Node’s, and the locale-sensitive methods throw with a message naming the fix. They throw rather than return the unlocalised answer. A wrong string that fails nowhere is what this is here to stop you shipping.

node:fs/promises reads your private files from your files folder, and every write rejects, as it does in production.

WebAssembly is the one exception. Node compiles its own HTTP parser from it the first time anything calls fetch, so taking it away would fail your suite somewhere you did not write. Your Function still has none, and the build still turns down a bundle that reaches for it.