kelta CLI — Agent Guide
How an AI agent should drive the CLI: discovery, auth precedence, output contract, exit codes and gotchas.
CLI for the Kelta platform (multi-tenant, metadata-driven). Everything here is machine-friendly by design: JSON output when piped, stable error codes, a discoverable command catalog.
Discovery#
kelta manifest— full machine-readable catalog: every command with a JSON Schema of its input, dangerous/auth flags, positionals, options. Start here.kelta manifest --group records— one group only.kelta <group> --help/kelta <group> <command> --help— human help, ending with that command’s examples (also in the manifest asexamples).
Auth & profiles#
- Credentials live in profiles (
~/.kelta/). Resolution precedence: flags > env (KELTA_PROFILE,KELTA_URL,KELTA_TENANT,KELTA_TOKEN) > profile file. - For CI/agents, env-only works with no profile at all:
KELTA_URL=https://api.kelta.io KELTA_TENANT=acme KELTA_TOKEN=klt_… kelta collections list kelta auth status --output json→{"authenticated": true|false, …}.- Missing/expired auth → exit 3 with
{"error":{"code":"AUTH_REQUIRED",…}}.
Output contract#
- Global
--output table|json|yaml|csv|ndjson. Piped output defaults to JSON — never parse the table format, it has no stability guarantee. - JSON:API responses are flattened to
{ "id", ...attributes, "<toOneRel>": id }.--rawgives the unflattened envelope (links, meta, relationships). --quietprints ids only, one per line.- stdout = data ONLY. Diagnostics and progress always go to stderr.
Errors & exit codes#
- Non-table modes emit ONE line of JSON on stderr:
{"error":{"code":"VALIDATION_FAILED","status":400,"detail":"…","source":{"pointer":"/data/attributes/name"},"meta":{"requestId":"…"}},"errors":[…]} erroriserrors[0]flattened for convenience;errorsis the full JSON:API array — read it when a request can fail on more than one field (e.g.records createwith two invalid attributes) or when you need every entry’ssource.pointer/meta, not just the first.codeis the platform’s stable UPPER_SNAKE_CASE contract — branch on it, never ondetail.meta.requestIdcorrelates with server logs; reference errors additionally carrymeta.targetCollection.- Exit codes: 0 ok · 1 API error · 2 usage/confirmation · 3 auth · 4 not found · 5 conflict/rate-limit.
- Argument errors — a missing required argument, an unknown option or an
unknown command — are
INVALID_ARGUMENTS, exit 2, in the same envelope:{"error":{"code":"INVALID_ARGUMENTS","detail":"unknown option '--colour'"}}.--helpand--versionexit 0.
Destructive commands#
- Anything destructive (delete/remove/reset/bulk/…) requires
--yeswhen stdin is not a TTY; without it you get exit 2 and{"error":{"code":"CONFIRMATION_REQUIRED"}}.kelta manifestmarks these with"dangerous": true.
Query grammar (list commands)#
--filter field=value(op defaults to eq) or--filter field.op=value; repeatable, ANDed. Ops: eq, neq, gt, gte, lt, lte, isnull, contains, starts, ends, icontains, istarts, iends, ieq, in (also aliased as any).--sort -createdAt,name(leading-= descending)--fields a,b(sparse) ·--include rel1,rel2·--page N --size N(max 200)--allauto-paginates (client cap 10k, warning on stderr when hit).
Escape hatch#
kelta api GET '/api/collections?page[size]=5'— any endpoint, profile auth + tenant prefix applied automatically, response verbatim.--datatakes any JSON (inline, @file, or-for stdin);--header Name:valuerepeatable. Every non-GET method is dangerous by spec (needs--yesoff-TTY, DELETE included) — without it, exit 2 and{"error":{"code":"CONFIRMATION_REQUIRED"}}, unchanged.kelta manifestadvertises this via"dangerous": true.- On a non-2xx response,
kelta apisurfaces the full error envelope above (all oferrors[], not just the first) and exits per the status table.
Canonical examples#
kelta collections list --output json | jq '.[].name'
kelta records list invoices --filter status=open --filter amount.gte=100 --sort -createdAt
kelta records create invoices --data '{"amount": 120, "status": "open"}'
kelta records update invoices <id> --data @patch.json --yes
kelta fields add invoices --name due_date --type date --required
kelta validation-rules create invoices --name positive \
--formula 'amount <= 0' --message 'Amount must be positive' # TRUE = reject
kelta flows execute <flowId> --input '{"key":"value"}' --wait # flows read $.input.key
kelta records bulk --data @ops.json --yes # {"atomic:operations":[…]}, all-or-nothing
kelta records search "acme" --limit 5
kelta api GET '/api/governor-limits'
kelta menus get main --tree # nests ui-menu-items by parentId, client-side
kelta dashboards get <id> --components # widgets sorted by rowPosition/columnPosition
kelta pages publish /home # resolves ui-pages by path, sets published=true
Gotchas#
- Flow input is double-wrapped by the platform: pass
--input '{"k":"v"}', the flow reads$.input.k. - Validation rules are ERROR conditions: the formula evaluating TRUE rejects the write.
- A rule can test related records through a ROLLUP_SUMMARY field it names:
the rollup is computed from the child rows at write time, and a value sent
in the body is ignored. E.g. a COUNT rollup
openTasks(filter{"status":"open"}) plusAND(state = "closed", openTasks > 0). - A just-created collection can briefly 404 on other pods (cache refresh); the CLI retries name lookups, but chained scripts should tolerate one retry.
- Page size clamps at 200 server-side; the CLI rejects larger values up front.
- No color is ever emitted; NO_COLOR needs no special handling.
Generated from the CLI command registry —
view the source
and run npm run gen:docs in kelta-web to update.