docs/cli-provider-settings-descriptor.md
CLI provider settings descriptor
Status: Proposed, not shipped. The last full contract verification used the
checksum-verified official Linux CLI 0.56.2 on 2026-09-01. It rejects
config providers --descriptors and has no generic config set or config action.
See the pinned audit. The scoped
0.57.0 probes
confirm descriptor absence and the unchanged generic-command gap.
Track settings delivery and
onboarding actions in TODO.
All command examples and payloads below describe the proposed contract.
This document defines the CLI contract Plasma needs before it can render real provider settings or onboarding flows without duplicating macOS Swift logic in QML.
The Plasma widget consumes this contract when the upstream codexbar CLI
exposes it. If a descriptor is absent or unsupported, Plasma keeps enable/disable,
supported single-key setup, docs/dashboard/login links, redacted diagnostics, and
CLI command hints available.
Command
| 1 | codexbar config providers --descriptors --format json --json-only |
The command returns the normal provider list plus a provider-specific descriptor. The descriptor is declarative: it names fields and actions, but the CLI remains the only component that knows how to read, validate, write, import, or redact provider settings.
Descriptor writes use local CLI commands such as
codexbar config set --provider amp --field sourceMode --value api --json-only.
Descriptor actions use local CLI commands such as
codexbar config action --provider openai --action openDashboard --json-only.
Top-level shape
| 1 | [ |
| 2 | { |
| 3 | "provider": "openrouter", |
| 4 | "displayName": "OpenRouter", |
| 5 | "enabled": true, |
| 6 | "descriptor": { |
| 7 | "schemaVersion": 1, |
| 8 | "fields": [], |
| 9 | "actions": [] |
| 10 | } |
| 11 | } |
| 12 | ] |
schemaVersion must be incremented for incompatible changes. Plasma should
ignore descriptors with an unknown major schema and keep showing CLI command
hints.
Fields
Fields are settings the frontend can display or edit. Field order is display order.
| 1 | { |
| 2 | "id": "apiKey", |
| 3 | "kind": "secret", |
| 4 | "title": "API key", |
| 5 | "description": "Stored by codexbar. Paste your OpenRouter API key.", |
| 6 | "redactedValue": "sk-...abcd", |
| 7 | "required": true, |
| 8 | "writeCommand": [ |
| 9 | "codexbar", |
| 10 | "config", |
| 11 | "set", |
| 12 | "--provider", |
| 13 | "openrouter", |
| 14 | "--field", |
| 15 | "apiKey", |
| 16 | "--stdin", |
| 17 | "--format", |
| 18 | "json", |
| 19 | "--json-only" |
| 20 | ] |
| 21 | } |
Supported field kinds:
"kind": "text": short non-secret string, such as a base URL or workspace id."kind": "secret": secret input, always written through stdin."kind": "enum": one of a stable option list."kind": "boolean": checkbox/toggle."kind": "number": bounded numeric setting.
Command-like behavior belongs in the descriptor's actions array, not in
fields; every field is editable and must provide an allowed writeCommand.
Enum fields include options:
| 1 | { |
| 2 | "id": "sourceMode", |
| 3 | "kind": "enum", |
| 4 | "title": "Source", |
| 5 | "value": "auto", |
| 6 | "options": [ |
| 7 | { "id": "auto", "title": "Automatic" }, |
| 8 | { "id": "api", "title": "API key" }, |
| 9 | { "id": "web", "title": "Browser cookies" } |
| 10 | ], |
| 11 | "writeCommand": [ |
| 12 | "codexbar", |
| 13 | "config", |
| 14 | "set", |
| 15 | "--provider", |
| 16 | "amp", |
| 17 | "--field", |
| 18 | "sourceMode", |
| 19 | "--value", |
| 20 | "{value}", |
| 21 | "--format", |
| 22 | "json", |
| 23 | "--json-only" |
| 24 | ] |
| 25 | } |
The CLI must validate {value}. Plasma must not infer valid enum values from
provider names or config files.
Field, action, and option IDs are machine identifiers. They must match
[A-Za-z0-9][A-Za-z0-9._-]* and be no longer than 128 characters. Consumers
reject invalid IDs instead of trimming, truncating, or otherwise rewriting
them.
Actions
Actions are provider setup flows the CLI knows how to perform.
| 1 | { |
| 2 | "id": "refreshCookies", |
| 3 | "kind": "command", |
| 4 | "title": "Refresh browser cookies", |
| 5 | "description": "Import browser cookies for the selected provider.", |
| 6 | "command": [ |
| 7 | "codexbar", |
| 8 | "config", |
| 9 | "action", |
| 10 | "--provider", |
| 11 | "codex", |
| 12 | "--action", |
| 13 | "refreshCookies", |
| 14 | "--format", |
| 15 | "json", |
| 16 | "--json-only" |
| 17 | ] |
| 18 | } |
Useful action categories:
- browser-cookie import
- manual cookie save
- API key save or clear
- OAuth/device-flow handoff
- local app/session probe
- token-account add/edit/remove
- provider diagnostics refresh
- open docs/dashboard/login URL
Actions must report structured JSON with status, optional message, and
optional refreshed descriptor. status is ok after a completed action,
error after a failed action, or cancelled when the user abandons an
interactive flow. A failed action may still exit with code zero, so consumers
must inspect the structured status before reporting success.
URL-opening actions should still be local CLI actions. For example,
codexbar config action --provider openai --action openDashboard --json-only
can return { "status": "ok", "url": "https://..." }; Plasma opens the URL
only after the CLI reports it.
Redaction and safety
Do not expose raw secrets.
Rules for the CLI:
- Secret fields must return only
redactedValue, never raw values. - Writes for secrets must use stdin, not command-line arguments.
- Descriptors must not include browser cookie values, bearer tokens, API keys, account IDs that are not already user-visible, or raw diagnostic responses.
- Error messages should be bounded and safe to store in user config.
- Commands must be local
codexbarcommands, not remote shell snippets.
Rules for Plasma:
- Treat descriptor JSON as a contract, not as raw config.
- Render only supported field kinds.
- Use
writeCommandand actioncommandexactly as arrays of argv-like tokens; quote each token when using Plasma's executable data source. - Reject descriptor commands unless they start with
codexbar configand use an allowed local subcommand:set/set-api-keyfor fields,actionfor actions. - Open descriptor-returned URLs only when they are HTTPS URLs.
- Keep secret fields write-only except for
redactedValue. - Fall back to current CLI command hints when a descriptor is missing, unsupported, or invalid.
- Bound rendering work even for malformed descriptors. Plasma inspects at most 32 fields and 32 actions per provider, 64 options per field, and 64 command tokens of at most 2048 characters each. Fields with text values longer than 2048 characters are ignored instead of binding or rewriting the value.
Plasma renderer rules
The first Plasma implementation should be deliberately small:
- Render fields in the Providers page below the redacted diagnostics summary.
- Use native controls: text field, password field, checkbox, combo box, spin box, and buttons.
- Disable controls while their command is in flight.
- After a successful write/action, reload
codexbar config providers --descriptors --format json --json-only. - Keep existing provider enable/disable behavior separate from descriptor fields.
- Do not add provider-specific QML branches for individual settings.
Example descriptor
| 1 | { |
| 2 | "provider": "amp", |
| 3 | "displayName": "Amp", |
| 4 | "enabled": true, |
| 5 | "descriptor": { |
| 6 | "schemaVersion": 1, |
| 7 | "fields": [ |
| 8 | { |
| 9 | "id": "sourceMode", |
| 10 | "kind": "enum", |
| 11 | "title": "Source", |
| 12 | "value": "auto", |
| 13 | "options": [ |
| 14 | { "id": "auto", "title": "Automatic" }, |
| 15 | { "id": "api", "title": "API key" }, |
| 16 | { "id": "web", "title": "Browser cookies" } |
| 17 | ], |
| 18 | "writeCommand": [ |
| 19 | "codexbar", |
| 20 | "config", |
| 21 | "set", |
| 22 | "--provider", |
| 23 | "amp", |
| 24 | "--field", |
| 25 | "sourceMode", |
| 26 | "--value", |
| 27 | "{value}", |
| 28 | "--format", |
| 29 | "json", |
| 30 | "--json-only" |
| 31 | ] |
| 32 | }, |
| 33 | { |
| 34 | "id": "apiKey", |
| 35 | "kind": "secret", |
| 36 | "title": "API key", |
| 37 | "redactedValue": "amp_...7890", |
| 38 | "writeCommand": [ |
| 39 | "codexbar", |
| 40 | "config", |
| 41 | "set", |
| 42 | "--provider", |
| 43 | "amp", |
| 44 | "--field", |
| 45 | "apiKey", |
| 46 | "--stdin", |
| 47 | "--format", |
| 48 | "json", |
| 49 | "--json-only" |
| 50 | ] |
| 51 | } |
| 52 | ], |
| 53 | "actions": [ |
| 54 | { |
| 55 | "id": "refreshCookies", |
| 56 | "kind": "command", |
| 57 | "title": "Refresh browser cookies", |
| 58 | "command": [ |
| 59 | "codexbar", |
| 60 | "config", |
| 61 | "action", |
| 62 | "--provider", |
| 63 | "amp", |
| 64 | "--action", |
| 65 | "refreshCookies", |
| 66 | "--format", |
| 67 | "json", |
| 68 | "--json-only" |
| 69 | ] |
| 70 | } |
| 71 | ] |
| 72 | } |
| 73 | } |