Skip to content

The engine --json API

The Engine JSON API is the contract that makes one engine, many shells work. Every prevail command accepts --json and writes a single JSON value (or NDJSON for streams) to stdout — nothing else. The cockpit, the desktop app, and the channels gateway all drive the engine through it.

  • --json everywhere. With --json, a command writes a single JSON value (or NDJSON for streams) to stdout and nothing else. Human output appears only when --json is absent.
  • Exit codes. 0 success, non-zero failure. On failure with --json, the command writes an error envelope to stdout:
    { "ok": false, "error": "human-readable message", "code": "MACHINE_CODE" }
  • Timestamps. ISO-8601 strings for human-facing fields (created, computed_at); epoch milliseconds (number) for machine fields (stateMtime, audited_at, ts).
  • stdin. Commands that take input (manifest set, onboard recommend, onboard apply, chat) read a JSON document from stdin.
FlagMeaning
--vault <path>Vault root to operate on. Defaults to the configured vault.
--jsonEmit machine-readable JSON (this contract).
--local-onlyForbid all network/cloud engines & tools for this invocation. Overrides config. → Privacy
--budget <tokens>Hard token budget for any LLM work in this invocation.
CommandOutputCovered in
prevail domains --jsonDomain[]
prevail manifest get/set <domain> --jsonDomainManifestManifest
prevail score <domain> [--audit] --jsonContextScoreContext Score
prevail score --all --json{ lifeReadiness, domains[] }Context Score
prevail score history <domain> --json{ ts, score }[]Context Score
prevail onboard recommend --jsonOnboardingRecommendationOnboarding
prevail onboard apply --jsonDomain[]Onboarding
prevail vault backup [--domain X] --jsonBackupResultBackup & archive
prevail vault archive/restore <domain> --json{ ok: true }Backup & archive
prevail vault list-archived --jsonstring[]Backup & archive
prevail chat --domain X --jsonNDJSON ChatEvent streambelow
prevail heartbeat install/status --json{ ok, installed, … }Heartbeat

Chat is the one streaming command. With --json it emits NDJSON — one ChatEvent per line, flushed as it happens. Typical order: start → (delta*) → assistantusagedone; errors emit an error event. The finalized turn is appended to <domain>/_threads/<id>.jsonl (the JSONL leg of the storage rule).

{"type":"start","thread":"2026-06-06-wealth-01","domain":"wealth","engine":"claude:opus-4-8"}
{"type":"delta","thread":"2026-06-06-wealth-01","text":"Your net worth "}
{"type":"assistant","thread":"2026-06-06-wealth-01","role":"assistant","text":"Your net worth is up 4.2% …"}
{"type":"usage","thread":"2026-06-06-wealth-01","usage":{"input_tokens":1820,"output_tokens":240,"cost_usd":0.018}}
{"type":"done","thread":"2026-06-06-wealth-01"}

Because the contract is frozen and the fixtures are published, a shell can be built and tested before the engine ships the command — render against docs/fixtures/, then swap in the live --json call. That’s the whole point of freezing the contract.