# Invocation & Envelope How a call is built, and what comes back. One grammar covers every platform action; one output contract covers every result. Everything on this page also rides every [discovery](https://omnicli.io/docs/discovery-contract.md) response as the `invocation`, `envelope`, and `pagination` scaffolding. ## The grammar ``` omni-cli [--flag value ...] [--json] ``` Every action parameter binds as a long flag `--`. There are no positional arguments and no short flags, and all values are passed as strings — a param's `type` in discovery is a semantic and validation hint, not a shell type. The action's `argv` field gives the exact ` ` triple; never guess flag spelling — read the action's tier-3 discovery entry. ## Global flags | Flag | Type | What it does | | --- | --- | --- | | `--context` | string | `work`, `personal`, or `both`. Omit to auto-resolve when exactly one context is logged in — agents should pass it explicitly. | | `--json` | bool | Machine-readable JSON output. Agents should always set it. | | `--verbose` | bool | Diagnostic logging to stderr (never secrets). | ## Hosts Platforms with `host_required` (a self-hosted server URL, or a Jira site including `/rest/api/3`) need a host. The host is saved at login and applied automatically to every action — omit `--host` on action commands; an explicit value overrides the saved host for that single call (exceptional). Omit host entirely for hosted platforms. ## The output contract **Success** — exit 0, and stdout carries the *bare* platform payload, projected to the action's `output_schema`. It is *not* wrapped in an `{ok, data}` envelope; if the platform returns an array, stdout is an array. **Failure** — non-zero exit, and the error goes to stderr: a structured JSON object when `--json` is set, human-readable text otherwise. ```json { "ok": false, "error": "rate_limited", "platform": "github", "context": "work", "message": "GitHub rejected the request: rate limit exceeded", "remedy": "wait and re-issue; the request was rejected before applying", "upstream": { "http_status": 429, "action": "github:issue.list", "mutating": false, "idempotent": true, "retry_after_seconds": 30 } } ``` `upstream` is present only when a platform request actually failed (never on local, usage, or auth errors): `http_status` (0 for a transport failure with no response), `action` (`:`), `mutating`, `idempotent`, and `retry_after_seconds` (0 unless the server sent a `Retry-After`). It exists so the caller can decide whether re-issuing is safe. ## Control flow Branch on the process exit code — never parse stdout's shape to detect failure. Exit 0: parse stdout against `output_schema`. Non-zero: read the error object from stderr; the code-to-meaning table is in [Exit Codes](https://omnicli.io/docs/exit-codes.md) (and ships in the CLI as `omni-cli errors`). ## Execute-once: retries are yours The CLI executes each action **exactly once and never retries — not even reads**. There is no backoff, no `Retry-After` sleep, and deliberately no `retryable` field: retry-safety is a judgment about side effects, and the caller owns it. The rule: - A `rate_limited` (12) or `upstream_error` (9) on an idempotent action (`upstream.idempotent` true) is safe to re-issue, optionally after `upstream.retry_after_seconds`. - Never blindly re-issue a non-idempotent action (`upstream.idempotent` false) after an indeterminate failure — a create or append may already have applied. ## Pagination The CLI returns a **single page and never auto-paginates** — paging is the caller's job. An action with a `pagination` block in its discovery entry pages; one without returns a complete set. To advance, re-call the action passing the prior response's next-page value via the param named by `pagination.cursor_param`; stop when that value is empty or absent. Where the next-page value lives depends on `pagination.next.from`: - `header` — the cursor is lifted from a response header into a top-level `next_cursor`: an array body is wrapped as `{items, next_cursor}`, an object body gets a `next_cursor` sibling. An empty `next_cursor` means last page. - `body` — the cursor is already in the named response field. - `body_total` — page by number until the named total field is reached. - `body_empty` — page by number until the named array field comes back empty. ``` omni-cli github issue list --repo octo/hello --json # → { "items": [ ... ], "next_cursor": "2" } omni-cli github issue list --repo octo/hello --page 2 --json # → { "items": [ ... ], "next_cursor": "" } # empty: last page ```