mateclaw/mateclaw-server/src/main/resources/docs/en/config.md
mikemikimike 576eb8055a
fix(auth): require secure JWT configuration and persist desktop secret (#666)
Require explicitly configured secure JWT secrets for server deployments and persist a random per-installation desktop secret across restarts. Preserve explicit environment overrides for strict server validation. Fixes #665.
2026-10-19 04:26:06 -05:00

397 lines
14 KiB
Markdown

# Configuration
**Three places to configure MateClaw: `application.yml`, environment variables, and the database.**
Most settings live in `application.yml` (Spring Boot's default config file), with sensitive values overridden by environment variables. Anything you want to change at runtime — model providers, search keys, feature toggles — lives in the `mate_system_setting` table and is edited through the Settings page.
Deep-dive topics have their own pages — Tool Guard rules in [Security & Approval](./security), model providers in [Models](./models), memory tuning in [Memory](./memory).
---
## Profiles
| Profile | Database | Activated by |
|---------|----------|--------------|
| `default` | H2 file at `./data/mateclaw` | No action needed |
| `mysql` | MySQL 8.0+ | `spring.profiles.active=mysql` or `SPRING_PROFILES_ACTIVE=mysql` |
| `postgres` | PostgreSQL 16+ | `SPRING_PROFILES_ACTIVE=postgres` |
| `kingbase` | KingbaseES | `SPRING_PROFILES_ACTIVE=kingbase` (opt-in driver required) |
The public Docker Compose stack activates `postgres`. Desktop builds use `default`; the `mysql` profile remains supported for existing or self-managed deployments.
---
## Core `application.yml` sections
### Server
```yaml
server:
port: 18088 # HTTP port
servlet:
context-path: /
```
### Database — H2 (development)
```yaml
spring:
datasource:
url: jdbc:h2:file:./data/mateclaw;MODE=MYSQL
username: sa
password:
driver-class-name: org.h2.Driver
h2:
console:
enabled: true # Available at /h2-console (disable in production)
```
### Database — MySQL (supported self-managed deployment)
```yaml
spring:
profiles:
active: mysql
datasource:
url: jdbc:mysql://localhost:3306/mateclaw?useSSL=false&serverTimezone=UTC
username: root
password: ${DB_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
```
### AI model — managed in the UI, not YAML
::: tip
**Model configuration is 100% UI-driven.** Don't put `spring.ai.*` blocks in `application.yml` — every provider, key, and model config lives in `Settings → Models`, backed by the `mate_model_provider` and `mate_model_config` tables.
:::
**Provider, key, and model rows in the database are the primary configuration.** On a fresh install, log in and add the first provider under `Settings → Models → Add Provider`. `DASHSCOPE_API_KEY` remains a compatibility fallback for DashScope auto-configuration, but it does not replace the provider row; do not assume equivalent environment variables are read for other providers. Full reference in [Models](./models).
### Virtual threads (JDK 21)
```yaml
spring:
threads:
virtual:
enabled: true
```
Enabled by default. Tomcat request threads, `@Scheduled` tasks, and `@Async` methods all run on virtual threads. SSE long-connections no longer hold platform threads, and I/O-bound async tasks (memory extraction, auditing, skill install, etc.) no longer queue behind a 16-thread pool.
### Spring AI Observability
```yaml
spring:
ai:
chat:
observations:
log-prompt: false # don't write prompt content into spans (security)
log-completion: false # don't write completion content into spans
```
When enabled, `/actuator/metrics/gen_ai.client.operation` and `/actuator/metrics/gen_ai.client.token.usage` automatically record latency and token usage for every LLM call. Requires `spring-boot-starter-actuator` (already included).
### Context window
```yaml
mate:
agent:
conversation:
window:
default-max-input-tokens: 128000
compact-trigger-ratio: 0.75
preserve-recent-pairs: 2
summary-max-tokens: 300
```
Details in [Memory](./memory).
### Memory extraction and consolidation
```yaml
mate:
memory:
auto-summarize-enabled: true
min-messages-for-summarize: 4
min-user-message-length: 10
skip-cron-conversations: true
summary-max-tokens: 1000
max-transcript-messages: 30
cooldown-minutes: 5
emergence-enabled: true
emergence-day-range: 7
```
### LLM Wiki
```yaml
mate:
wiki:
enabled: true
max-chunk-size: 30000
max-context-chars: 10000
max-pages-per-raw: 15
max-parallel-raw-materials: 3
max-parallel-phase-b-pages: 3
auto-process-on-upload: true
upload-dir: ./data/wiki-uploads
```
Details in [LLM Wiki](./wiki).
### Tool Guard (rule-based)
Tool Guard's global switch, default policy, and rules are **not configured in application.yml** — they live in the database (`mate_tool_guard_config` / `mate_tool_guard_rule`) and are edited from the admin **Security** page or via REST:
| Method | Path | What it does |
|---|---|---|
| `GET` / `PUT` | `/api/v1/security/guard/config` | Global switch + default policy (`allow` / `deny` / `require_approval`) |
| `GET` | `/api/v1/security/guard/rules/builtin` | Built-in rules |
| `GET` / `POST` | `/api/v1/security/guard/rules` | List / create custom rules |
| `PUT` | `/api/v1/security/guard/rules/{ruleId}` | Update a rule |
| `PUT` | `/api/v1/security/guard/rules/{ruleId}/toggle` | Enable/disable a single rule |
Each rule matches on tool name + argument pattern and yields an `allow` / `deny` / `require_approval` action, ordered by priority. Details in [Security & Approval](./security).
### File Guard
File Guard has two layers:
1. **Allowed / denied path rules** — like Tool Guard, stored in the database and edited from the admin **Security** page; REST is `GET` / `PUT /api/v1/security/guard/config/file-guard`. **Not in application.yml.**
2. **Global fallback sandbox root** — the only piece that lives in application.yml. When a conversation has no per-workspace base path configured, file/shell tools are confined to this root (fail-closed default):
```yaml
mateclaw:
workspace:
sandbox:
enabled: true # set false to restore the legacy unconstrained behaviour
root: ${user.dir}/data/workspace # fallback sandbox root, created at startup
```
Environment overrides: `MATECLAW_WORKSPACE_SANDBOX_ENABLED` / `MATECLAW_WORKSPACE_SANDBOX_ROOT`.
### JWT authentication
```yaml
mateclaw:
jwt:
secret: ${JWT_SECRET:}
expiration: 86400000
```
::: warning
`JWT_SECRET` is required at startup in every environment. Set a unique random value of at least 32 UTF-8 bytes; generate one with `openssl rand -base64 48`. Never commit it. Rotating it invalidates existing tokens.
:::
### Skill workspace
```yaml
mateclaw:
skill:
workspace:
root: ${user.home}/.mateclaw/skills
auto-init: true
delete-policy: archive
bundled-skills-path: skills
```
### Multimodal default providers
```yaml
mate:
image:
default-provider: dashscope
video:
default-provider: dashscope
tts:
default-provider: cosyvoice
stt:
default-provider: paraformer
music:
default-provider: dashscope
```
Details in [Multimodal](./multimodal).
---
## Environment variables
::: warning Manage LLM keys in the console
Provider, key, and model rows in `Settings → Models` are primary. `DASHSCOPE_API_KEY` remains only as a compatibility fallback for DashScope auto-configuration; do not assume equivalent environment variables are read for other providers.
:::
| Variable | Required | Purpose |
|----------|----------|---------|
| `SERPER_API_KEY` | — | Google Serper search key (search tools not yet UI-managed) |
| `TAVILY_API_KEY` | — | Tavily search key (same as above) |
| `JWT_SECRET` | Yes | JWT signing secret |
| `MATECLAW_CORS_ALLOWED_ORIGINS` | — | CORS allowlist (recommended in production) |
| `DB_PASSWORD` / `DB_ADMIN_PASSWORD` | Docker | PostgreSQL application / bootstrap-admin passwords (must differ) |
| `DB_USERNAME` / `DB_ADMIN_USERNAME` | — | PostgreSQL application / bootstrap-admin usernames |
| `DB_HOST` / `DB_PORT` / `DB_NAME` | — | Database address, port, and name |
| `SPRING_PROFILES_ACTIVE` | — | Docker Compose sets `postgres`; self-managed deployments may use `mysql` / `kingbase` |
### Setting them
**Linux / macOS:**
```bash
export JWT_SECRET="$(openssl rand -base64 48)"
export SERPER_API_KEY=your-serper-key # optional
```
**Windows (PowerShell):**
```powershell
$env:JWT_SECRET = openssl rand -base64 48
```
**Docker (`.env` file):**
```properties
DB_PASSWORD=secure-password-here
DB_ADMIN_PASSWORD=different-secure-password-here
# Generate with: openssl rand -base64 48
JWT_SECRET=replace-with-generated-value
```
After startup, open `http://localhost:18080`, sign in as `admin / admin123`, and add your first LLM provider under `Settings → Models → Add Provider`.
---
## Database schema init
MateClaw uses **Flyway** for schema migrations:
1. `db/migration/h2/V*__*.sql` — H2-dialect migration scripts
2. `db/migration/mysql/V*__*.sql` — MySQL-dialect migration scripts
3. After migrations, seed data is loaded from `db/data-*.sql` — idempotent
Flyway selects the migration dialect from the active Spring profile. Startup runs `migrate` with checksum validation enabled by default in all bundled profiles. Applied migration files must not be edited: checksum drift or a failed migration stops startup rather than silently changing the schema history.
**Desktop upgrade compatibility:** an existing desktop database whose applied scripts differ from the new release can now fail to start. A new database and an unchanged migration history need no repair. Keep a backup that can be opened with the previous application version; do not delete the database to clear a validation error.
If validation fails:
1. Stop the application and back up the database. Keep the exact previous and target release artifacts, and inspect the failing migration and schema history.
2. Compare the old and new SQL with the actual schema/data. Prefer restoring the expected migration file or a maintainer-provided forward migration. `repair` changes migration metadata; it does **not** execute changed DDL, undo partial DDL/data changes, or prove the schema is correct. Resolve any partial migration effects before proceeding.
3. Only after confirming that history repair is appropriate, set `mateclaw.flyway.auto-repair=true` (environment variable `MATECLAW_FLYWAY_AUTOREPAIR=true`) for one controlled startup. Repair uses the configured migration locations and is followed by normal migration. Keep validation enabled.
4. Remove the opt-in immediately afterwards, restart normally, and verify validation and application behavior before allowing writes. If recovery fails, restore the backup with its matching application version.
The opt-in defaults to `false`, including Desktop. It is not an unattended upgrade policy. `spring.flyway.validate-on-migrate` remains externally configurable, but setting it to `false` bypasses the validation guard and is not a repair procedure.
### Table conventions
- All tables prefixed `mate_`
- `snake_case` columns, `camelCase` Java fields (auto-mapped by MyBatis Plus)
- Every table has `create_time`, `update_time`, `deleted`
- Logical delete: `deleted = 0` active, `deleted = 1` soft-deleted
### H2 console in dev
[http://localhost:18088/h2-console](http://localhost:18088/h2-console):
| Field | Value |
|-------|-------|
| JDBC URL | `jdbc:h2:file:./data/mateclaw` |
| Username | `sa` |
| Password | *(empty)* |
### Switching to MySQL
```sql
CREATE DATABASE mateclaw CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
```bash
export SPRING_PROFILES_ACTIVE=mysql
export DB_PASSWORD=your-password
mvn spring-boot:run
```
---
## Runtime settings (`mate_system_setting`)
Things you want to change without restarting:
| Key | Type | Purpose |
|-----|------|---------|
| `default_agent_id` | Long | Agent used when none specified |
| `default_model_config_id` | Long | Default model configuration |
| `max_conversation_turns` | Integer | Max turns per conversation |
| `enable_memory` | Boolean | Enable memory extraction |
| `search_enabled` | Boolean | Global web search toggle |
| `search_provider` | String | `serper` / `tavily` / `duckduckgo` / `searxng` |
| `search_fallback_enabled` | Boolean | Fall through to next provider on failure |
| `serper_api_key` | String | Serper key (masked in UI) |
| `tavily_api_key` | String | Tavily key (masked in UI) |
| `language` | String | `zh-CN` / `en-US` default UI language |
| `stream_enabled` | Boolean | SSE streaming output |
| `debug_mode` | Boolean | Show extra debug info in UI |
All editable from `Settings → System`. Changes take effect immediately.
### Search service configuration
Web search config has been migrated from `application.yml` to the **System Settings** page. Changes take effect immediately without restart.
::: tip
API keys are displayed masked. When saving, keys are only overwritten when a new value is entered. Blank input means "keep existing key".
:::
---
## Logging
```yaml
logging:
level:
vip.mate: INFO
vip.mate.agent: DEBUG
vip.mate.agent.graph: DEBUG
org.springframework.ai: INFO
root: INFO
```
For deep debugging, set `vip.mate: TRACE`. Log volume is high — don't leave it on in production.
---
## CORS
Development: Vite's dev server handles CORS via its proxy. Production: frontend is embedded in the JAR, no CORS needed.
If you deploy the frontend separately:
```yaml
mateclaw:
cors:
allowed-origins:
- http://localhost:5173
- https://your-domain.com
```
---
## Configuration precedence
Settings resolve in this order (highest priority first):
1. **Environment variables**
2. **Command-line arguments** (`--server.port=9090`)
3. **`application-{profile}.yml`**
4. **`application.yml`**
5. **Database `mate_system_setting`** (for runtime-configurable values)
---
## Next
- [Models](./models) — provider and model config in detail
- [Security & Approval](./security) — JWT, Tool Guard, File Guard, audit log
- [Memory](./memory) — memory tuning parameters
- [LLM Wiki](./wiki) — `mate.wiki` block explained
- [Channels](./channels) — channel-specific configuration