wirl.json and the CLI
wirl.json#
wirl.json sits beside your project, where you run wirl deploy.
{
"app": "churn-dashboard",
"org": "acme",
"server": "dist/server.js",
"description": "Accounts at risk this month, from HubSpot and Stripe",
"accent": "sun",
"connections": [
"hubspot",
{ "slug": "stripe", "hosts": ["api.stripe.com"], "kind": "http_bearer" }
]
}
app— the app's slug. Combined with the org, it forms the app's address:<org>--<app>.wirl.run.org— which organisation to deploy to. Without it,wirlfalls back to your personal org, or asks which one if you belong to more than one.server— the module exporting{ fetch }. Without it, the bundle is served as static files.connections— what the app needs from the organisation. Each entry is a connection's name, or an object narrowing it:slug— the connection's name.hosts— hostnames the app may call through this connection. It can only narrow the connection's own allowed hosts, never widen them.kind— the shape of the credential:http_bearer(the default),http_header,basic,postgres,env, orwebhook_secret(one secret, no hosts — holds the signing secret apublic_pathsentry checks incoming requests against; the outbound broker refuses to use it).
description— shown under the app's name on its hub card. At most 160 characters.accent— the hub card's color: one ofblue,green,sun,purple,red,sky,orange,lime. Without one, the app gets a color chosen deterministically from its slug, and a redeploy that says nothing aboutdescriptionoraccentleaves whatever was set before alone.schedules— cron jobs wirl fires into the app. Each entry is an object:name— 1-40 lowercase letters, digits or dashes. Unique within the app.cron— a standard five-field cron expression.timezone— an IANA zone, e.g.America/Los_Angeles. Defaults toUTC.timeout— how long a fire may run before wirl gives up on it,"30s"to"15m". Defaults to"5m".retries— 0 to 3 more attempts after a failure. Defaults to0.overlap—"skip"(the default) leaves a still-running fire alone;"allow"starts another anyway.
See Schedules for what your app receives and how retries and overlap actually behave.
public_paths— paths the internet may call with no sign-in, checked before your app is. Each entry is an object:path— starts with/, and is either exact or ends in one trailing/*covering everything below it. No leading wildcard, no bare/*, and anything under/__wirlis reserved for wirl.verify—slack,stripe,github, ornone.connection— thewebhook_secretconnection holding the signing secret. Required unlessverifyisnone, and refused if given when it is.
At most 10 per app, service apps only. See Public paths for what your app receives, what each provider signs, and what a
nonepath costs you.
The CLI#
wirl login Sign in from this terminal (or --token wirl_...)
wirl init [dir] [--server] Create wirl.json, and a working server module with --server
wirl skill [dir] [--print] Write the skill file a coding agent reads (init does this too; --no-skill to skip)
wirl dev [dir] Run the app here, signed in as a stub user
wirl deploy [dir] Build, scan and deploy (creates the app if new)
wirl apps [--org <slug>] List apps you can open
wirl share <email> [--role viewer|editor]
wirl transfer <email> Hand the app to a new owner (you keep editor access)
wirl move --to <org> Move the app to another organisation you belong to
wirl orgs list | create <slug> Your organisations; make one for a team
wirl members list | add <email> --role | remove <email> The roster (--org)
wirl versions List deployments
wirl rollback <deployment-id>
wirl schedules List the app's schedules with their last and next run
wirl run <schedule> Run one now and wait for the outcome
wirl logs [--since 1h] [--errors] [--follow] [--limit n] [--cursor n] What the app printed, per request; --run, --ray, --search narrow it
wirl pull <app> [dir] [--force] Fetch a deployed app's source and keep building
wirl connections list Connections an admin has created in the org
wirl connections create <slug> --secret-file f.json [--name n] [--kind k] [--hosts a,b]
wirl connections rotate <slug> --secret-file f.json
wirl connections delete <slug>
wirl connections pending Apps waiting on an owner or admin
wirl connections grants Every app and what it uses (admins)
wirl connections show <app> What an app has been granted
wirl connections approve|revoke|request <app> <slug>
wirl whoami
A few of these are worth a sentence:
wirl share <email>shares the app with that person. Role defaults to viewer, so add--role editorwhen they should be able to deploy it too.wirl rollback <deployment-id>rolls back to one of the deployments listed by version.wirl run <schedule>fires a declared schedule now, outside its cron, and waits for the outcome — the fast way to check one works right after deploying it.wirl logsprints what the deployed app printed, one block per request, newest first, with the status and any exception.--errorskeeps only failures,--followkeeps watching,--ray <id>finds the request behind acf-rayheader someone copied from a broken page, and--cursor <n>reads the page before a "More before this" line. See Logs.wirl connections createreads the secret from a file,--secret-file, rather than a command-line argument.wirl connections rotatereads a replacement the same way.wirl connections approve|revoke|request <app> <slug>decides, or asks to decide, whether an app may use a connection.wirl whoamiprints who you are signed in as: your organisations and your token's scope.
Options#
--org <slug> Organisation. Defaults to wirl.json or your personal org.
--app <slug> App. Defaults to wirl.json or the directory name.
--no-create Fail instead of creating an app that does not exist yet.
--json Machine-readable output.