---
name: config-setup
system: true
description: |
  Configure octo's global settings through guided conversation — set up AI model endpoints
  (providers, API keys, models), adjust agent defaults (reasoning effort, permission mode,
  coauthor, workspace directory), and manage the default/lite model assignments.
  Trigger on: "configure model", "add provider", "setup endpoint", "add API key",
  "change default model", "switch model", "set reasoning", "change permission mode",
  "config setup", "配置模型", "添加模型", "配置 API", "切换模型", "修改设置".
---

# Configure octo

Your job is to turn "I need my agent to use model X" or "change setting Y" into a
working configuration through octo's REST API. Not every user knows where
settings live — briefly explain when needed.

## Two categories of configuration

```
Agent Defaults                    Endpoints & Models
─────────────────                 ───────────────────
reasoning_effort                  provider selection
permission_mode                   API key
show_reasoning                    base URL (advanced)
coauthor                          model names
workspace_dir                     default / lite model
```

All of these live in `~/.octo/config.yml` and are editable through the REST API
on the running octo server at `http://localhost:<port>` (use `curl` via the `terminal` tool — do NOT use `web_fetch`, localhost is blocked by SSRF).

## Reaching the server

The server listens on `127.0.0.1:8088` by default (the desktop app's built-in
server uses the same port). Loopback requests need no access key.

1. **Try the default first**: `curl -s http://127.0.0.1:8088/api/config`.
   JSON back = you're connected; skip the rest of this section.
2. **Connection refused?** The server may be on a custom port:
   - Started as a daemon (`octo serve -d`): `cat ~/.octo/serve.pid` for the PID,
     then find its listen port — macOS/Linux:
     `lsof -iTCP -sTCP:LISTEN -P -n -a -p <PID>`; Windows (PowerShell):
     `Get-NetTCPConnection -State Listen -OwningProcess <PID>`.
   - A foreground `octo serve` writes no pid file — ask the user which port they
     started it on (it's also in the web UI's address bar).
3. **No server running at all?** Don't stop — fall back to editing
   `~/.octo/config.yml` directly (it is the same file every API call below
   mutates). Read the file first, apply the smallest edit that matches the
   structure you see, then validate with `octo doctor`. Changes are picked up
   by new CLI sessions and by the server next time it starts.

---

## Agent Defaults

These are global settings that govern how the Default Agent behaves.
All are individual `PUT` endpoints returning 200 on success, 400 on invalid input.

### Reasoning Effort

```
PUT /api/config/reasoning_effort
{"reasoning_effort": "off"|"low"|"medium"|"high"|"xhigh"|"max"}
```

| Value | Effect |
|-------|--------|
| `off` | No extended thinking (server default) |
| `low` | Fast, surface-level thinking |
| `medium` | Balanced |
| `high` | Deeper reasoning, slower |
| `xhigh` | Very thorough |
| `max` | Maximum depth |

### Permission Mode

```
PUT /api/config/permission_mode
{"permission_mode": "interactive"|"auto"|"strict"}
```

| Value | Effect |
|-------|--------|
| `interactive` | Ask before dangerous operations (default) |
| `auto` | Auto-approve all tools |
| `strict` | Deny all potentially dangerous tools |

### Show Reasoning

```
PUT /api/config/show_reasoning
{"show_reasoning": true|false}
```

When enabled, the agent's thinking process is visible in the chat.

### Coauthor

```
PUT /api/config/coauthor
{"coauthor": true|false}
```

When enabled, appends a `Co-authored-by: octo-agent` trailer to git commits.

### Workspace Directory

```
PUT /api/config/workspace_dir
{"workspace_dir": "/absolute/path"|"auto"}
```

Sets the default working directory for new sessions. Use `"auto"` to let octo
detect the project directory automatically. Only absolute paths are accepted
(no `~` — expand it to the full path first).

### Read Current Defaults

```
GET /api/config
```

Returns the full current config including all defaults. Use this to show the
user their current settings before making changes.

---

## Endpoints & Models

An "endpoint" groups a provider with its API key, then lists the models available
through it. The two-level structure:

```
Endpoint "anthropic"                  Endpoint "relay-a"
  provider: anthropic                   provider: custom
  api_key: sk-ant-…                     api_key: sk-…
  models:                               models:
    - claude-sonnet-5                     - gpt-4o
    - claude-haiku-4-5                    - deepseek-flash
```

Two top-level composite ids pick across endpoints: `default` (e.g.
`anthropic::claude-sonnet-5`) is what the agent uses for normal turns, and `lite`
(e.g. `anthropic::claude-haiku-4-5`) is used for lightweight tasks (title
generation, compaction summaries). An empty `lite` means those run on the
primary model — nothing cheaper is inferred.

### List Endpoints

```
GET /api/config/endpoints
```

Returns all configured endpoints with their models, including which is default/lite.

### List Available Providers

```
GET /api/providers
```

Returns the built-in provider registry — each entry has a `name`, `base_url`,
and `models` (suggested model names). Use this to help the user pick a provider.

### Create an Endpoint

```
POST /api/config/endpoints
{
  "id": "my-relay",
  "name": "My Relay",
  "provider": "custom",
  "api_key": "sk-…",
  "base_url": "https://api.example.com",
  "protocol": "openai",
  "models": [{"model": "gpt-4o", "vision": false}]
}
```

| Field | Required | Notes |
|-------|----------|-------|
| `id` | yes | Unique slug, `[a-zA-Z0-9_-]+`, e.g. `anthropic`, `my-openai` |
| `name` | no | Display name |
| `provider` | yes | Must match a known provider id from GET /api/providers, or `"custom"` |
| `api_key` | no | The API key (never echo it back to the user after saving) |
| `base_url` | no | Override for API base URL; only for `"custom"` provider — named providers use their registry URL |
| `protocol` | no | `"anthropic"` or `"openai"` — only needed for `"custom"` provider |
| `models` | no | Initial models to register — array of `{"model": "...", "vision": bool}`, **not** plain strings |

### Update an Endpoint

```
PATCH /api/config/endpoints/{id}
{
  "new_id": "new-name",     // rename (optional)
  "name": "New display",    // new display name (optional)
  "provider": "openai",     // change provider (optional)
  "api_key": "sk-…",        // update key (optional)
  "base_url": "https://…",  // change URL (optional)
  "protocol": "openai"      // change protocol (optional)
}
```

All fields are optional — only include what's changing. To rename, set `new_id`.

### Delete an Endpoint

```
DELETE /api/config/endpoints/{id}
```

Returns 204. **Destructive** — deletes the endpoint and all its models.
Confirm with the user before calling.

### Add a Model to an Endpoint

```
POST /api/config/endpoints/{id}/models
{"model": "gpt-4o", "vision": true}
```

`vision` (optional, default false): whether this model supports image input.

### Delete a Model from an Endpoint

```
DELETE /api/config/endpoints/{id}/models/{model}
```

The model name must be URL-encoded when it contains special characters — this
matters for slash-style names like `deepseek/deepseek-chat`, which becomes
`deepseek%2Fdeepseek-chat` in the path.

### Set Default / Lite Model

```
POST /api/config/endpoints/{id}/default?model=gpt-4o
POST /api/config/endpoints/{id}/lite?model=claude-haiku
DELETE /api/config/endpoints/{id}/lite   // clear lite designation
```

The model is passed as a **query parameter** (`?model=…`), not in the request body.
Omit `?model` to use the endpoint's first model as a fallback.

**Important**: This changes the **server-wide default** that seeds new sessions.
It does **not** switch the model of any session that is already running or already
bound to a specific model. For those, see [Switching the Current Session's Model](#switching-the-current-sessions-model).

### Switching the Current Session's Model

A session is bound to the global default model only at creation time. Once it has
a turn, it keeps that model until you explicitly switch it. This applies to
Web, TUI, CLI one-shot, and IM sessions.

- **Web UI**: Click the model chip in the Composer status bar (the row showing the
current model name, e.g. `K3`), then pick the desired model from the dropdown.
- **IM (Weixin/Feishu/DingTalk/WeCom/Discord/Telegram)**: Send `/model` to list
configured models and see the current one, then `/model <endpoint>::<model>` to
bind the session to that endpoint's model, or `/model default` to make it follow
the server-wide default again. You cannot switch while a turn is running.
- **REST API**:

```
PATCH /api/sessions/{id}/model
{"model_id": "Kimi::k3-256k"}
```

Use `default` as the `model_id` to unbind the session from a specific endpoint
and make it follow the global default on subsequent turns. Unknown or bare model
strings are treated as raw model names on the default sender.

**Restart behavior**: You do **not** need to restart `octo serve` after changing
the global default or a session's model. Both take effect on the next turn. The
only exception is a session that was already bound to a model before the change —
it will not switch unless you use one of the methods above.

---

## Workflow

### Configuring Agent Defaults

1. **Read current state** via `GET /api/config`.
2. **Ask what they want to change.** Show current values and let the user pick.
3. **Call the PUT endpoint** for the changed setting.
4. **Confirm the change** — re-read the setting and report back.

Keep it brief: one question at a time, one change per response.

### Adding a new endpoint

1. **Understand the goal.** "I want to use GPT-4o" → OpenAI provider. "I have a
   relay at company.com" → custom provider. If the user names a specific
   provider, skip to step 3.

2. **Check existing endpoints** via `GET /api/config/endpoints`. If an endpoint
   for this provider already exists, ask if they want to add models to it instead.

3. **Collect the API key.** Ask for it once, never echo it back. If the user
   doesn't have one, point them to the provider's website (use the `website_url`
   from `GET /api/providers`).

4. **Pick models.** Named providers have a suggested model list (from
   `GET /api/providers`). For custom providers, ask what model names the relay
   accepts. Suggest sensible defaults — one powerful model for main turns,
   one fast/cheap model for lite tasks.

5. **Confirm and create** via `POST /api/config/endpoints`. Show a summary
   (provider, models, which is default/lite) before calling.

6. **Verify** via `GET /api/config/endpoints` — confirm the new endpoint
   appears with the right models.

7. **Tell the user** the endpoint is ready. New sessions will use it immediately.
   Existing sessions keep their current model binding unless manually switched.

### Editing an existing endpoint

1. **Fetch current state** via `GET /api/config/endpoints`.
2. **Show the user** the endpoint's current config.
3. **Apply the smallest change** via `PATCH /api/config/endpoints/{id}`.
4. **Verify** the change took effect.
5. **Point out** that updating an endpoint (key, URL, provider, protocol) does not
   automatically switch any bound session to a different model; it only changes
   how the already-bound model is reached. If the user wants a running session to
   use a different model, use the per-session switch.

### Setting default / lite model

1. **List endpoints** to show the user what's available.
2. **Confirm** which model should be default (normal turns) and which lite
   (lightweight tasks).
3. **Call** `POST /api/config/endpoints/{id}/default` etc.
4. **Confirm** the assignment.
5. **Clarify the scope**: this only affects **new** sessions and any session that
   is currently unbound. Sessions already in progress or already switched to a
   specific model continue on that model. Tell the user how to switch the current
   session if they expected it to change immediately (Web UI model chip, IM `/model`,
   or `PATCH /api/sessions/{id}/model`).

---

## Rules

- **Never echo API keys back to the user** after they're saved.
- **Always confirm before destructive operations** (delete endpoint, delete model).
- **Show current state before modifying** — never guess the user's setup.
- **One change at a time** — don't batch unrelated config changes.
- **Provider names must match** the registry from `GET /api/providers`. An
  invalid provider returns 400; list the available ones for the user.
- **Model names are free-form** for custom endpoints — don't validate them,
  just pass through what the user gives you.
- **workspace_dir must be absolute** — expand `~` to the full home path before
  calling the API.
