pithy env

Report every Worker’s environments — bindings, resolved ids, provisioned state, base URLs and Cloudflare dashboard links — reading everything and writing nothing.

Synopsis

pithy env [name] [--worker <name>] [--json]

Flags

FlagMeaning
[name] (positional, optional)Show only this environment, e.g. staging. Filters the human output only
--worker <name>Show only this Worker, by the name pithy worker list shows or its apps/<dir> basename. Default: every Worker
--jsonMachine-readable output. Default false

What it does

pithy env is an inventory, not a switch. It writes nothing, changes nothing and provisions nothing — pithy provision is what turns a not provisioned line into a real resource. Provisioning health and non-zero exits belong to pithy doctor; this command reports what is declared and what resolves, and a resource that does not exist is a line saying so rather than a failure.

Every Worker lives in apps/<name>/ with its own wrangler.jsonc, so the report is per Worker × per environment. A Worker’s top-level stanza is its dev environment; each env.<name> block is another. For each environment it lists every id-carrying binding — D1, KV, R2 and Durable Objects — with the id wrangler.jsonc declares, whether that id is real, and a link into the Cloudflare dashboard.

Provisioned means the id is present and is not a placeholder. An empty value, a <database_id> stub, or anything containing “placeholder” reads as not provisioned — which is exactly the state a freshly scaffolded project is in.

A local environment is not judged against a standard that cannot apply to it. The presence of a Cloudflare resource is not a property a local environment has: Miniflare serves D1 from the binding declaration alone, and pithy dev works precisely because no Cloudflare resource is involved. So a binding with no id reads local there, and not provisioned only in a deployed environment.

Deliberately different words. Sharing them made the real action item weaker and taught people to skim past red in the one command they read against production.

And local is not “nothing to provision”. The same top-level stanza is the one a bare pithy deploy ships — wrangler deploy with no --env, and the only deploy path with nothing in front of it refusing a binding that has no id. So a local environment holding an id-less binding carries one line under it saying so:

Miniflare needs no id. A bare pithy deploy ships this stanza, and nothing gates it on one.

Printed once per stanza, because it is a fact about the stanza rather than about each binding — and printed only where it is a fact. A local environment whose bindings all carry ids says nothing, and a deployed one already says not provisioned, which is the action item.

A link is either right or absent. A resource gets a deep link when its dashboard id is knowable, that product’s list page when it is not, and nothing at all with no account id or when the resource is not provisioned. A Durable Object binding names a class, and the dashboard addresses a DO by a namespace id wrangler.jsonc never carries, so DO rows show the class name and fall back to the list page. In a terminal an id renders as a clickable hyperlink; with hyperlinks off, piped, or under NO_COLOR, the URL is printed beside the id.

The environment set comes from wrangler.jsonc alone, so the inventory prints in a project whose dependencies are not installed. A Worker’s pithy.config.ts is read only for its domains declaration, and only opportunistically.

baseUrl is "local" for dev, because a local run has no public address. For every other environment it is resolved offline, in order, from the domains declaration, then the first route pattern, then a hand-set vars.BASE_URL — and null when the Worker declares no address at all.

The positional filter applies to the human output only. --json always carries every environment every selected Worker declares. Narrow it with --worker, or filter the array yourself.

--json

One line on stdout.

KeyTypeMeaning
commandstring"env"
accountIdstring or nullThe Cloudflare account id, or null — dashboard links are omitted when it is absent
workersobject[]Every selected Worker with a wrangler.jsonc, in discovery order
workers[].workerstringThe Worker’s name, as pithy worker list shows it
workers[].dirstringThe Worker’s directory, relative to the project root, e.g. apps/api
workers[].environmentsobject[]Every environment declared in that Worker’s wrangler.jsonc, dev first
workers[].environments[].namestring"dev" for the top-level stanza, otherwise the env.<name> key
workers[].environments[].localbooleanTrue for the top-level stanza — the environment that runs on your machine rather than in an account. Read it before judging any provisioned: false beneath it, and read it again before a bare pithy deploy
workers[].environments[].scriptNamestring or nullThe Worker script name this environment deploys under
workers[].environments[].baseUrlstring or null"local" for dev; the resolved public address otherwise; null when the Worker declares none
workers[].environments[].workerDashboardUrlstring or nullThe dashboard link for this environment’s Worker, or null with no account id or no script name
workers[].environments[].resourcesobject[]Every binding declared for this environment
…resources[].kindstring"d1", "kv", "r2" or "durable_object"
…resources[].bindingstringThe Worker binding name, e.g. DB or SESSIONS
…resources[].idstring or nullThe resolved id — a D1 uuid, a KV namespace id, an R2 bucket name, a DO class name — or null when absent
…resources[].provisionedbooleanTrue when the id is present, non-empty and not a placeholder. false under a local environment is a statement, not a deficiency
…resources[].dashboardUrlstring or nullThe resource’s own dashboard page when its id is knowable, else that product’s list page

Errors

The command exits 0 for every state it is meant to report, including a completely unprovisioned project. Two things still refuse:

  • No workers here. Nothing under apps/ carries a wrangler.jsonc. Run pithy init to start a project.
  • No worker named "<name>". --worker matched nothing. The refusal lists the Workers that do exist.

A Worker whose wrangler.jsonc vanished between discovery and reading is skipped rather than failing the inventory. A Worker whose config is present and will not open still refuses — a Worker silently missing from an inventory is the under-report this command exists to prevent.

Examples

pithy env
pithy env staging
pithy env --worker api --json
{"command":"env","accountId":"<account-id>","workers":[{"worker":"acme-api","dir":"apps/api","environments":[{"name":"dev","scriptName":"acme-api","baseUrl":"local","workerDashboardUrl":null,"resources":[{"kind":"d1","binding":"DB","id":"<database_id>","provisioned":false,"dashboardUrl":null}]},{"name":"prod","scriptName":"acme-prod-api","baseUrl":"https://api.example.com","workerDashboardUrl":"<dashboard-url>","resources":[{"kind":"d1","binding":"DB","id":"<database-id>","provisioned":true,"dashboardUrl":"<dashboard-url>"}]}]}]}

Nothing this command reads is a credential, and nothing it prints is one. An account id and a resource id are identifiers.

ESC