Configuration
Two files decide how the CLI treats a project: vsa.json, which every
project has, and .env, where the identity credential lives.
vsa.json
It sits at the project root, and it is how vsa recognises a project at all.
{
"name": "Acme HR",
"cli": ">=1.0.0",
"devPort": 8093,
"modules": { "kind": "code", "allowFalse": true },
"xauth": { "project": "ACME-HR", "app": "hr" },
"env": {
"required": { "SUBS_ID": "the subscription this install serves" },
"services": { "SIGNAL_URL": "live updates" },
"liveSideEffects": [{ "keys": "^PLASGATE_", "why": "sends REAL, billed SMS" }]
},
"knownIssues": [
{ "check": "dom-scope", "file": "public/js/pages/main/Old.js", "why": "rewrite planned" }
]
}
| Key | Meaning |
|---|---|
name | The product name, used by make:app titles and vsa help |
cli | The CLI version this project needs (>=x.y.z or ^x.y). An older CLI refuses to run here |
devPort | The port vsa serve uses |
modules | How app files name a page's XAuth module: kind code (ref codes, the default — xauth:sync creates them) or id for legacy numeric ids. allowFalse lets false mark a non-routable page |
env.required | .env keys doctor treats as an error when missing, on top of the defaults (APP_KEY, APP_URL, DB_*, COOKIE_NAME, XAUTH_*). A key set to null is removed |
env.services | Keys reported as a warning instead, where the value is the feature that stops working without them |
env.liveSideEffects | Keys (as a regex) that make a development checkout act on the real world. doctor warns — this is what stops a local run from sending billed SMS |
knownIssues | Errors check downgrades to warnings while a decision is pending. Keep it empty when you can |
xauth.console | The development console. setup writes it into a new .env, serve always passes it to the app, doctor probes it |
xauth.project | The project's code in the console, matched case-insensitively and kept UPPER-CASE — DMS, PRM. Every xauth:* command matches on it, and xauth:register creates a project under it when the console has none, so it must be the code the console already uses for this product |
xauth.app | The entry application, the one XAUTH_APP_ID names. Under a project credential it is a name rather than a key — but the mirror pull will not run without it |
template | Only in the template’s own vsa.json: the paths it owns and the ones it merges. vsa upgrade reads nothing else when deciding what it may touch. A project records the template commit it was taken from, so a later upgrade knows what changed |
quickSkip | Checks the pre-commit hook and vsa serve skip. Defaults to cdn-fresh, the only rule that needs the network |
config/vsa.php
The runtime half: plain data, read by the app and by vsa without
booting Laravel — so no env() on a key the CLI reads, no closures,
no function calls.
| Key | Meaning |
|---|---|
asset_epoch | Appended to the ?v= of every bundle the shell loads — the one reliable way to make every browser fetch fresh JS and CSS. Change it with vsa cache:bust, and commit it: vsa check fails a bump that was only edited |
assets | auto (built when public/dist/manifest.json exists, raw otherwise), raw, or built — where a missing manifest is a visible error rather than a silent fall back to raw files on a production deploy |
lazy_pages | Load a page's script and markup the first time it is opened instead of putting every page in the document at boot. Once per app lifecycle, not per navigation, and hovering a menu item prefetches. Off by default, because it changes when a page's script runs |
tenant_domain, tenant_transport | Which transports name the subscriber — see Routes & tenancy |
dev_subs_code | Local only, and blanked in config outside APP_ENV=local so config:cache on a real host bakes an empty value even if the key is copied there by mistake |
The XAuth credential in .env
A deployed host authenticates as its project, not as one
application. doctor and serve read the same module for
this, so they never describe a checkout differently.
| Key | Role |
|---|---|
XAUTH_PROJECT_IDXAUTH_PROJECT_SECRET |
The credential, covering every application of the project. Issued on the console's Projects screen — xauth:register cannot issue it, because the provisioner only ever issues application secrets |
XAUTH_APP_ID |
Names the entry application in X-App-Id. It has no secret of its own under a project credential, but it is not optional: the mirror pull refuses to run without it, and the app-specific APIs address it |
XAUTH_APP_SECRET |
The older per-application credential. Still valid, and still right for a single app deployed alone on its host. Never read once a project credential is set |
What doctor reports
- Error — no credential at all, or a half-filled project pair. A project pair does not fall back to the application pair: the client treats it as configured only when both keys are set, so one empty key is a dead sign-in.
- Warning — a project credential with no
XAUTH_APP_ID. Sign-in still works, so it is not an error: a host that only signs people in does not need it, and.envdoes not say which kind of host this is. - Info —
XAUTH_APP_SECRETset alongside a project credential, where nothing reads it, and which of the two modes the checkout is in. - Warning — the same key assigned twice. phpdotenv keeps the last one while
xauth:syncwrites to the first, so a credential written there can look applied and do nothing.
vsa check does not read .env at all. It
reads the code the browser downloads. Its only credential-related rule is
secrets, which is value-shaped and so already covers a project
secret pasted into client code.