1. Three layers of fact
- Provider = an OpenAI-compatible Base URL plus an API key. The key lives in the system
keychain (macOS Keychain, service
ai.cosk.coskey) — never in a config file, never in logs. - Upstream model = a factual record under that provider: the
modelfield sent upstream and which protocol it speaks. The context window is not set here; it lives on the “Model mapping” page. - App model (mapping) = the entry that appears in the ChatGPT.app picker, maintained on the “Model mapping” page.
Upstream models land in the catalogue by default and never appear in the ChatGPT.app picker on their own. To get them there, create a mapping — see Mappings and context windows.
2. Add a provider
Open the Providers page and click “New provider”. The row of icons at the top of the form
(DeepSeek, 千问, 智谱, Kimi, MiniMax) fills in the first three fields — id,
display name and Base URL — in one click, leaving only the API key; “Custom” at the front
clears the form again (the API key you already typed goes too). Using something else, such as a
self-hosted gateway? Just fill in all four fields by hand:

| Field | Notes |
|---|---|
| Provider id | Letters, digits, - and _ only; it becomes the namespace of mapping ids |
| Display name (optional) | The card title and the prefix of generated display names |
| Base URL | The OpenAI-compatible endpoint, exactly as the provider documents it (whether it includes /v1 varies) |
| API key | Not echoed; written to the system keychain on save |
“More…” at the end of that row pulls a fresh preset list from a remote source and merges it by id + version, appending anything new to the row (the note says where it came from and how many entries were added or updated). The list is cached for 24 hours, so repeated clicks do not re-download. It is only a preset list — nothing is written to your config, the keychain is untouched, and you still choose and save a provider yourself:

The card appears as soon as you save, with a keychain check mark next to its title and a small provider icon chosen from the Base URL:

The icon matches the full endpoint first and falls back to the host, so
https://api.deepseek.com and the /v1 form both draw the DeepSeek icon; endpoints outside
the preset list stay blank.
3. Import models from the upstream list
Click “Import models…”. Coskey pulls the upstream /models list once with that provider’s
key and shows the models that are not in the catalogue yet:

- The search box filters by name; searching only affects what is displayed and never drops your selection;
- Select all results ticks everything in the current search;
- Press “Import N”.
Each model is probed for /responses while importing, and the verdict is stored with it:

- Native = the upstream supports
/v1/responses, so requests pass through (tool definitions and system instructions included); - Translated = the upstream only offers chat/completions, so the local translation layer converts responses ⇄ chat both ways, streaming and tool calls included;
- The “used by” column holds a single “+ Use model” button: clicking it creates a mapping for that upstream model in place (the dialog is the Model mapping form with the target prefilled). Until a mapping exists, the model is in the catalogue but not yet in the ChatGPT.app picker.
Models missing from the upstream list (common with self-hosted gateways) can be added by hand with “+ Add model”: enter the upstream
modelfield and the protocol is detected the same way. It adds one model at a time — the form collapses on save and the verdict appears under the new row.
4. Other controls on the card
| Control | Purpose |
|---|---|
| Provider navigation | The pill row above the list scrolls to a provider’s card on click; press and drag left/right to reorder providers (saved on release; coskey provider list follows the same order) |
| Import models… | Pull the upstream /models list, search and multi-select (the recommended route) |
| + Add model | Enter a single model by hand (one per save) |
| Time the Base URL | Check that the address responds and how long a round trip takes |
| Copy Base URL / API key | The two copy icons on the card: one copies the endpoint, the other reads the key from the system keychain to the clipboard (plaintext is never shown) |
| Test connection | Send one minimal request using the model’s protocol: native models report two timings (“no reasoning” and “with reasoning”), translated models report a time to first byte |
| Probe protocol | Re-probe /responses for a single model row; the verdict appears under that row |
| Edit / delete | Deleting a provider also removes its models, picker entries and keychain item (with a confirmation) |
| + Use model | Under the “used by” column of each model row: create a mapping for it in place, and the name appears in that column as soon as you save |
| “Used by” column | Shows the name this upstream model appears under in the ChatGPT.app picker; the # in the header switches the column between display names and model ids |
Providers, upstream models and mappings take effect immediately: the running wrapper hot-reloads its configuration, so the next request uses the new values without restarting the app; the ChatGPT.app picker list refreshes within about 5 minutes (restarting is faster).
Next: Mappings and context windows.