forked from Hmbown/CodeWhale
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.example.toml
More file actions
583 lines (536 loc) · 36.5 KB
/
config.example.toml
File metadata and controls
583 lines (536 loc) · 36.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ CodeWhale Configuration ║
# ║ ║
# ║ Terminal coding agent for DeepSeek. ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
# See `docs/CONFIGURATION.md` for how config is loaded (profiles, env overrides, etc.).
# ─────────────────────────────────────────────────────────────────────────────────
# Active provider + DeepSeek defaults
# ─────────────────────────────────────────────────────────────────────────────────
# Choose which provider to use by default. Per-provider credentials live in the
# `[providers.*]` sections near the bottom of
# this file — keeping both stored at once means `/provider deepseek` and
# `/provider nvidia-nim` (or `--provider openai`, `--provider wanjie-ark`,
# `--provider fireworks`, `/provider sglang`, `/provider vllm`, `/provider ollama`)
# toggle without having to re-enter keys. Top-level `api_key` / `base_url` are
# still read as DeepSeek defaults when `[providers.deepseek]` is absent
# (backward compatibility).
provider = "deepseek" # deepseek | deepseek-cn | nvidia-nim | openai | atlascloud | wanjie-ark | openrouter | novita | fireworks | sglang | vllm | ollama
api_key = "YOUR_DEEPSEEK_API_KEY" # must be non-empty
base_url = "https://api.deepseek.com/beta"
# provider = "deepseek-cn" # legacy alias (official host is still https://api.deepseek.com)
# base_url = "https://api.deepseek.com" # opt out of DeepSeek beta features
# Optional custom model request headers for OpenAI-compatible gateways.
# Authorization and Content-Type are managed by the client and cannot be overridden here.
# http_headers = { "X-Model-Provider-Id" = "your-model-provider" }
# ─────────────────────────────────────────────────────────────────────────────────
# Default Models
# ─────────────────────────────────────────────────────────────────────────────────
# DeepSeek V4 family:
# deepseek-v4-pro — flagship reasoning model on DeepSeek Platform
# deepseek-v4-flash — fast, cost-efficient (legacy aliases: deepseek-chat, deepseek-reasoner)
# deepseek-ai/deepseek-v4-pro — NVIDIA NIM-hosted Pro model ID
# deepseek-ai/deepseek-v4-flash — NVIDIA NIM-hosted Flash model ID
# gpt-4.1 — default generic OpenAI-compatible model ID
# deepseek-ai/deepseek-v4-flash — default AtlasCloud model ID
# deepseek-reasoner — default Wanjie Ark model ID
# accounts/fireworks/models/deepseek-v4-pro — Fireworks AI Pro model ID
# deepseek-ai/DeepSeek-V4-Pro — SGLang self-hosted Pro model ID
# deepseek-ai/DeepSeek-V4-Flash — SGLang self-hosted Flash model ID
default_text_model = "deepseek-v4-pro"
# ─────────────────────────────────────────────────────────────────────────────────
# Thinking Mode (DeepSeek V4 reasoning effort)
# ─────────────────────────────────────────────────────────────────────────────────
# "off" — disables chain-of-thought (thinking.type = disabled)
# "low" — compat-maps to "high" server-side
# "medium" — compat-maps to "high" server-side
# "high" — reasoning_effort = high (DeepSeek default)
# "max" — reasoning_effort = max (deepest reasoning)
#
# Shift+Tab in the TUI cycles between off / high / max. The header shows the
# current tier as a ⚡ chip.
reasoning_effort = "max"
# ─────────────────────────────────────────────────────────────────────────────────
# Cost Display
# ─────────────────────────────────────────────────────────────────────────────────
# Display estimated usage in USD or CNY. Aliases `yuan` and `rmb` normalize to `cny`.
cost_currency = "usd" # usd | cny
# ─────────────────────────────────────────────────────────────────────────────────
# Paths
# ─────────────────────────────────────────────────────────────────────────────────
skills_dir = "~/.deepseek/skills"
mcp_config_path = "~/.deepseek/mcp.json"
notes_path = "~/.deepseek/notes.txt"
memory_path = "~/.deepseek/memory.md"
# instructions = ["./AGENTS.md", "~/.deepseek/global.md"]
#
# Optional list of additional instruction files concatenated into the
# system prompt in declared order (#454). Useful for layering
# repo-specific rules on top of a global preferences file. Each entry
# is expanded so `~` and env vars work; missing files are skipped with
# a tracing warning. Files are capped at 100 KiB per entry.
#
# Project-level config (.deepseek/config.toml in the workspace) replaces
# the user-level array wholesale rather than merging — list `~/global.md`
# inside the project array if you want both. An explicit empty array
# (`instructions = []`) clears the user list for the current repo.
# ─────────────────────────────────────────────────────────────────────────────────
# User memory (#489) — opt-in. When enabled, the TUI reads memory_path on
# startup and injects its contents into the system prompt as a
# <user_memory> block, intercepts `# foo` typed in the composer to append
# the line as a timestamped bullet, and registers a `remember` tool the
# model can call to add durable notes itself.
# ─────────────────────────────────────────────────────────────────────────────────
[memory]
# enabled = true # turn the feature on (default: false)
# Override the env-var equivalent: `DEEPSEEK_MEMORY=on`
# Parsed but currently unused (reserved for future versions):
# tools_file = "./tools.json"
# ─────────────────────────────────────────────────────────────────────────────────
# Security
# ─────────────────────────────────────────────────────────────────────────────────
allow_shell = true
approval_policy = "on-request" # on-request | untrusted | never
sandbox_mode = "workspace-write" # read-only | workspace-write | danger-full-access | external-sandbox
# ─────────────────────────────────────────────────────────────────────────────────
# External Sandbox Backend (pluggable remote execution)
# ─────────────────────────────────────────────────────────────────────────────────
# When sandbox_backend is set to "opensandbox", all exec_shell calls are
# routed through an external OpenSandbox-compatible HTTP API instead of
# spawning a local process. The backend sends `POST {sandbox_url}/v1/sandbox/run`
# with `{"cmd": "...", "env": {...}}` and expects
# `{"stdout": "...", "stderr": "...", "exit_code": 0}`.
#
# sandbox_backend = "none" # "none" (default) or "opensandbox"
# sandbox_url = "http://localhost:8080" # OpenSandbox-compatible API base URL
# sandbox_api_key = "YOUR_API_KEY" # Optional Bearer token sent with requests
#
# Env-var overrides:
# DEEPSEEK_SANDBOX_BACKEND → sandbox_backend
# DEEPSEEK_SANDBOX_URL → sandbox_url
# DEEPSEEK_SANDBOX_API_KEY → sandbox_api_key
#
# Example OpenSandbox setup:
#
# sandbox_backend = "opensandbox"
# sandbox_url = "http://localhost:8080"
# sandbox_api_key = "sk-opensandbox-secret"
#
# The backend uses a 30-second HTTP timeout. Background, interactive, and
# TTY modes are not supported with external backends — all commands run
# synchronously via HTTP.
# auto_allow entries match by command prefix, not raw string.
# See command_safety.rs for the prefix dictionary.
#
# Examples:
# auto_allow = ["git status"] # auto-approves: git status, git status -s, git status --porcelain
# # does NOT auto-approve: git push, git checkout
# auto_allow = ["cargo check", "npm run"]
#
# auto_allow = []
max_subagents = 10 # optional (1-20)
# Optional sub-agent tuning. max_concurrent overrides top-level max_subagents.
# [subagents]
# max_concurrent = 10
# api_timeout_secs = 120 # per-step API timeout, clamped to 1..=1800
# Optional managed policy paths (defaults to /etc/deepseek/*.toml on unix):
# managed_config_path = "/etc/deepseek/managed_config.toml"
# requirements_path = "/etc/deepseek/requirements.toml"
# ─────────────────────────────────────────────────────────────────────────────────
# Per-provider credentials (peer providers — NIM is first-class, not a flag)
# ─────────────────────────────────────────────────────────────────────────────────
# Providers can be stored at once; `provider = "..."` (top of file) or
# `/provider deepseek` / `/provider nvidia-nim` / `--provider openai` /
# `--provider wanjie-ark` / `/provider fireworks` switches between them without
# having to re-enter keys. Env vars override anything set here:
# DeepSeek: DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL
# NIM: NVIDIA_API_KEY (or NVIDIA_NIM_API_KEY), NIM_BASE_URL
# (or NVIDIA_NIM_BASE_URL / NVIDIA_BASE_URL), NVIDIA_NIM_MODEL
# OpenAI-compatible: OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL
# Wanjie Ark: WANJIE_ARK_API_KEY (or WANJIE_API_KEY), WANJIE_ARK_BASE_URL, WANJIE_ARK_MODEL
# OpenRouter: OPENROUTER_API_KEY, OPENROUTER_BASE_URL, OPENROUTER_MODEL
# Novita: NOVITA_API_KEY, NOVITA_BASE_URL, NOVITA_MODEL
# Fireworks: FIREWORKS_API_KEY, FIREWORKS_BASE_URL
# SGLang: SGLANG_BASE_URL, SGLANG_MODEL, optional SGLANG_API_KEY
# vLLM: VLLM_BASE_URL, VLLM_MODEL, optional VLLM_API_KEY
# Ollama: OLLAMA_BASE_URL, OLLAMA_MODEL, optional OLLAMA_API_KEY
# DeepSeek Platform (https://platform.deepseek.com)
[providers.deepseek]
# api_key = "YOUR_DEEPSEEK_API_KEY"
# base_url = "https://api.deepseek.com/beta"
# model = "deepseek-v4-pro"
# http_headers = { "X-Model-Provider-Id" = "your-model-provider" } # optional custom request headers
# NVIDIA NIM-hosted DeepSeek V4 (https://build.nvidia.com)
[providers.nvidia_nim]
# api_key = "YOUR_NVIDIA_API_KEY"
# base_url = "https://integrate.api.nvidia.com/v1"
# model = "deepseek-ai/deepseek-v4-pro" # or deepseek-ai/deepseek-v4-flash
# Generic OpenAI-compatible endpoint. Use the built-in `openai` provider for
# third-party gateways; do not invent a custom provider name. For non-local
# http:// gateways, launch with DEEPSEEK_ALLOW_INSECURE_HTTP=1 only on a
# trusted network.
[providers.openai]
# api_key = "YOUR_OPENAI_COMPATIBLE_API_KEY"
# base_url = "https://api.openai.com/v1"
# model = "gpt-4.1"
# AtlasCloud OpenAI-compatible endpoint (https://www.atlascloud.ai/docs/models/llm)
[providers.atlascloud]
# api_key = "YOUR_ATLASCLOUD_API_KEY"
# base_url = "https://api.atlascloud.ai/v1"
# model = "deepseek-ai/deepseek-v4-flash"
# Wanjie Ark / 万界方舟 OpenAI-compatible endpoint
[providers.wanjie_ark]
# api_key = "YOUR_WANJIE_API_KEY"
# base_url = "https://maas-openapi.wanjiedata.com/api/v1"
# model = "deepseek-reasoner" # or the exact model ID enabled on your Wanjie account
# OpenRouter — multi-provider gateway (https://openrouter.ai)
[providers.openrouter]
# api_key = "YOUR_OPENROUTER_API_KEY"
# base_url = "https://openrouter.ai/api/v1"
# model = "deepseek/deepseek-v4-pro" # or deepseek/deepseek-v4-flash
# Novita AI-hosted inference (https://novita.ai)
[providers.novita]
# api_key = "YOUR_NOVITA_API_KEY"
# base_url = "https://api.novita.ai/v1"
# model = "deepseek/deepseek-v4-pro" # or deepseek/deepseek-v4-flash
# Fireworks AI-hosted DeepSeek V4 (https://fireworks.ai)
[providers.fireworks]
# api_key = "YOUR_FIREWORKS_API_KEY"
# base_url = "https://api.fireworks.ai/inference/v1"
# model = "accounts/fireworks/models/deepseek-v4-pro"
# Self-hosted SGLang OpenAI-compatible server
[providers.sglang]
# api_key = "OPTIONAL_SGLANG_TOKEN"
# base_url = "http://localhost:30000/v1"
# model = "deepseek-ai/DeepSeek-V4-Pro" # or deepseek-ai/DeepSeek-V4-Flash
# Self-hosted vLLM OpenAI-compatible server
[providers.vllm]
# api_key = "OPTIONAL_VLLM_TOKEN"
# base_url = "http://localhost:8000/v1"
# model = "deepseek-ai/DeepSeek-V4-Pro" # or deepseek-ai/DeepSeek-V4-Flash
# Self-hosted Ollama OpenAI-compatible server
[providers.ollama]
# api_key = "OPTIONAL_OLLAMA_TOKEN"
# base_url = "http://localhost:11434/v1"
# model = "deepseek-coder:1.3b" # or any local Ollama tag
# ─────────────────────────────────────────────────────────────────────────────────
# Web Search Provider
# ─────────────────────────────────────────────────────────────────────────────────
# Choose which backend `web_search` uses. Default is Bing HTML scraping — no
# API key needed. DuckDuckGo remains selectable and still falls back to Bing
# when its HTML endpoint returns a bot challenge or no parseable results.
# Switch to Tavily or Bocha for reliable search in mainland China.
#
# [search]
# provider = "bing" # bing | duckduckgo | tavily | bocha
# # duckduckgo: HTML scrape with Bing fallback
# # tavily: https://tavily.com — AI search, needs api_key
# # bocha: https://bochaai.com — 博查AI搜索,国内友好,需api_key
# api_key = "tvly-YOUR_KEY" # required for tavily and bocha
# # WARNING: treat config.toml like a secret file when
# # storing API keys. Use env vars or `auth set` instead.
#
# Env-var overrides:
# DEEPSEEK_SEARCH_PROVIDER → search.provider
# DEEPSEEK_SEARCH_API_KEY → search.api_key
# ─────────────────────────────────────────────────────────────────────────────────
# Network Policy (#135)
# ─────────────────────────────────────────────────────────────────────────────────
# Per-domain allow/deny rules for outbound network calls made by the TUI's
# tools (`fetch_url`, `web_search`) and the MCP HTTP transport. Stdio MCP
# servers and direct LLM API calls are unaffected.
#
# Precedence: deny wins. A host listed in both `allow` and `deny` is denied.
#
# Host-matching rules:
# - Exact match: `api.deepseek.com` matches only `api.deepseek.com`.
# - Subdomain wildcard: an entry starting with `.` (e.g. `.example.com`)
# matches `api.example.com` and `a.b.example.com` but not the apex
# `example.com`. To cover both, list both. `*.example.com` is also accepted.
#
# Defaults are intentionally conservative: when this section is absent, no
# policy is enforced (mirrors pre-v0.7.0 behavior). To opt in:
#
# [network]
# default = "prompt" # allow | deny | prompt
# allow = ["api.deepseek.com", "github.com", ".githubusercontent.com"]
# deny = []
# audit = true # one line per call to ~/.deepseek/audit.log
# ─────────────────────────────────────────────────────────────────────────────────
# Skills (#140)
# ─────────────────────────────────────────────────────────────────────────────────
# Settings for the `/skill install <spec>` community-skill installer.
# * registry_url — curated index.json that resolves bare names to
# `github:owner/repo` specs. Override to point at
# a private fork or internal mirror.
# * max_install_size_bytes — per-skill uncompressed size cap. Tarballs that
# exceed this limit are rejected during validation.
# Default: 5 MiB.
#
# `/skill install` is gated by `[network]`. Make sure `github.com` and
# `raw.githubusercontent.com` are reachable (default `prompt` is fine — you'll
# be asked once and can persist) before running it.
#
# [skills]
# registry_url = "https://raw.githubusercontent.com/Hmbown/deepseek-skills/main/index.json"
# max_install_size_bytes = 5_242_880
# ─────────────────────────────────────────────────────────────────────────────────
# TUI
# ─────────────────────────────────────────────────────────────────────────────────
[tui]
alternate_screen = "auto" # auto/always use the TUI screen; never uses terminal scrollback
mouse_capture = true # true copies only transcript user/assistant text; false uses raw terminal selection/copy
terminal_probe_timeout_ms = 500 # optional startup terminal-mode timeout (100-5000ms)
osc8_links = true # emit OSC 8 escapes around URLs (Cmd+click in iTerm2/Ghostty/Kitty/WezTerm/Terminal.app 13+); set false for terminals that misrender
# notification_condition = "always" # always | never — overrides [notifications].threshold_secs.
# "always" = notify on every successful turn (no threshold);
# "never" = suppress all turn-completion notifications;
# unset = use [notifications] defaults (recommended).
# locale = "auto" # UI chrome language: auto | en | ja | zh-Hans | pt-BR
# # "auto" reads LC_ALL → LC_MESSAGES → LANG; falls back to English.
# # Override: `locale = "zh-Hans"` for Simplified Chinese regardless of OS locale.
# # Also settable at runtime: /config locale zh-Hans
# # Note: this only affects TUI labels/chrome — it does NOT change model output language.
# ─────────────────────────────────────────────────────────────────────────────────
# Feature Flags
# ─────────────────────────────────────────────────────────────────────────────────
[features]
shell_tool = true
subagents = true
web_search = true # enables canonical web.run plus the compatibility web_search alias
apply_patch = true
mcp = true
exec_policy = true
# vision_model = false # enable vision model for image_analyze tool
# ─────────────────────────────────────────────────────────────────────────────────
# Vision Model Configuration (optional)
# ─────────────────────────────────────────────────────────────────────────────────
# Uses an OpenAI-compatible vision model API for the `image_analyze` tool.
# api_key inherits from the main config if not specified.
#
# [vision_model]
# model = "gemini-3.1-flash-lite-preview" # Required: vision-capable model ID
# api_key = "YOUR_API_KEY" # Optional: defaults to main api_key
# base_url = "https://generativelanguage.googleapis.com/v1beta/openai/" # Optional
# ─────────────────────────────────────────────────────────────────────────────────
# Retry Configuration
# ─────────────────────────────────────────────────────────────────────────────────
[retry]
enabled = true
max_retries = 3
initial_delay = 1.0
max_delay = 60.0
exponential_base = 2.0
# ─────────────────────────────────────────────────────────────────────────────────
# Context Compaction
# ─────────────────────────────────────────────────────────────────────────────────
# Auto-compaction is a saved UI setting edited with `/config` (`auto_compact`).
# There is no config-file `[compaction]` table yet; detailed thresholds are
# chosen by the TUI from the active model/context budget.
# Append-only Flash seams are experimental and opt-in while the v0.7.5
# context/cache audit validates prefix-cache behavior.
[context]
enabled = false
verbatim_window_turns = 16
# Thresholds are based on the active request input estimate, not lifetime
# summed API usage.
l1_threshold = 192000
l2_threshold = 384000
l3_threshold = 576000
# Hard cycle reserves the normal 262144-token internal turn budget plus 1024
# safety tokens, separate from V4's official 384000 max-output metadata.
cycle_threshold = 768000
seam_model = "deepseek-v4-flash"
# ─────────────────────────────────────────────────────────────────────────────────
# Workshop / Large-Output Routing (#548)
# ─────────────────────────────────────────────────────────────────────────────────
# Tool outputs exceeding `large_output_threshold_tokens` are routed through a
# V4-Flash synthesis sub-agent. Only the synthesis reaches the parent context;
# the raw text is stored in the workshop variable `last_tool_result` so the
# parent can call `promote_to_context` later if it needs the full content.
#
# Per-tool overrides let high-volume tools (e.g. exec_shell) use tighter
# thresholds without changing the global default.
#
# Add `raw = true` to any tool call to bypass routing for that invocation.
#
# [workshop]
# large_output_threshold_tokens = 4096
# [workshop.per_tool_thresholds]
# exec_shell = 2048 # shell output synthesised aggressively
# grep_files = 2048
# web_search = 8192 # web results can be large; give them more room
# ─────────────────────────────────────────────────────────────────────────────────
# Capacity Controller (runtime pressure guardrails)
# ─────────────────────────────────────────────────────────────────────────────────
[capacity]
enabled = false
low_risk_max = 0.50
medium_risk_max = 0.62
severe_min_slack = -0.25
severe_violation_ratio = 0.40
refresh_cooldown_turns = 6
replan_cooldown_turns = 5
max_replay_per_turn = 1
min_turns_before_guardrail = 4
profile_window = 8
deepseek_v3_2_chat_prior = 3.9
deepseek_v3_2_reasoner_prior = 4.1
deepseek_v4_pro_prior = 3.5
deepseek_v4_flash_prior = 4.2
fallback_default_prior = 3.8
# ─────────────────────────────────────────────────────────────────────────────────
# Profile Example (for multiple environments)
# ─────────────────────────────────────────────────────────────────────────────────
# Select a profile with `deepseek --profile <name>` or `DEEPSEEK_PROFILE=<name>`.
[profiles.work]
api_key = "WORK_DEEPSEEK_API_KEY"
base_url = "https://api.deepseek.com/beta"
[profiles.dev]
api_key = "DEV_DEEPSEEK_API_KEY"
allow_shell = true
[profiles.nvidia-nim]
provider = "nvidia-nim"
api_key = "YOUR_NVIDIA_API_KEY"
base_url = "https://integrate.api.nvidia.com/v1"
default_text_model = "deepseek-ai/deepseek-v4-pro"
# ─────────────────────────────────────────────────────────────────────────────────
# Desktop Notifications (OSC 9 / BEL on long agent-turn completion)
# ─────────────────────────────────────────────────────────────────────────────────
# Emits an escape sequence to the terminal when a turn **completes successfully**
# and took longer than `threshold_secs`. Failed or cancelled turns are
# intentionally silent. Useful when you tab away from the TUI and want an alert
# for "your task is ready".
#
# method = "auto" # auto | osc9 | bel | off
# auto: OSC 9 for iTerm.app / Ghostty / WezTerm.
# On macOS / Linux, falls back to BEL.
# On Windows, falls back to "off" — BEL maps to the
# system error chime (SystemAsterisk / MB_OK), which
# sounds like an error popup. Set method = "bel"
# explicitly to opt back in (#583).
# osc9: \x1b]9;<msg>\x07 (iTerm2-style; shows macOS notification)
# bel: plain \x07 beep
# off: disable entirely
# threshold_secs = 30 # only notify when the turn took >= this many seconds
# include_summary = false # include elapsed time + cost in the notification body
[notifications]
# method = "auto"
# threshold_secs = 30
# include_summary = false
# ─────────────────────────────────────────────────────────────────────────────────
# Workspace Snapshots (#137)
# ─────────────────────────────────────────────────────────────────────────────────
# Each turn the TUI takes a `pre-turn:<seq>` and `post-turn:<seq>` snapshot of
# your workspace into a side-git repo at:
#
# ~/.deepseek/snapshots/<project_hash>/<worktree_hash>/.git
#
# Your own `.git` is never touched — `--git-dir` and `--work-tree` are always
# set together when shelling out to git. Use `/restore N` (slash command) or
# the `revert_turn` tool to roll the working tree back. Conversation history
# is unaffected.
#
# Disk footprint: ~1-2 GB worst case for a 100 MB workspace × 12 turns/day,
# typically far less thanks to git's content-addressed storage. The session
# boot prunes anything older than `max_age_days` (default 7).
#
# [snapshots]
# enabled = true # Snapshot workspace pre/post each turn for /restore
# max_age_days = 7 # Older snapshots pruned at session start
# max_workspace_gb = 2 # Snapshots self-disable on first init when the
# # non-excluded workspace exceeds this size in GB
# # (v0.8.32). Default 2 GB protects against running
# # codewhale in directories with hundreds of GB
# # of datasets / model weights / docker dumps where
# # `git add -A` would hang the TUI for hours. Set
# # to 0 to disable the cap (v0.8.31 behaviour);
# # raise to a higher number for legitimate large
# # monorepos.
# ─────────────────────────────────────────────────────────────────────────────────
# LSP Diagnostics (post-edit) (#136)
# ─────────────────────────────────────────────────────────────────────────────────
# After every successful file edit (`edit_file`, `apply_patch`, `write_file`),
# the engine asks an LSP server for diagnostics on the file and injects them
# as a synthetic system message before the next API call. This lets the agent
# see compile breaks immediately without round-tripping through the user.
#
# Enabled by default. Failure modes are non-blocking: a missing LSP binary,
# a crashed server, or a timeout simply skips the post-edit hook for that
# turn — the agent's work is never blocked.
#
# Built-in language → server defaults:
# rust → rust-analyzer
# go → gopls serve
# python → pyright-langserver --stdio
# typescript → typescript-language-server --stdio
# c, cpp → clangd
#
# Override the defaults via the `servers` table below.
[lsp]
# enabled = true
# poll_after_edit_ms = 5000
# max_diagnostics_per_file = 20
# include_warnings = false
# [lsp.servers]
# rust = ["rust-analyzer"]
# go = ["gopls", "serve"]
# ─────────────────────────────────────────────────────────────────────────────────
# Hooks (optional)
# ─────────────────────────────────────────────────────────────────────────────────
# Hooks run shell commands on lifecycle events (session start/end, tool calls, etc.).
# Configure as `[[hooks.hooks]]` under a `[hooks]` table.
#
# Available events: session_start, session_end, message_submit,
# tool_call_before, tool_call_after, mode_change, on_error, shell_env.
#
# `shell_env` (#456) is special: the hook runs immediately before each
# `exec_shell` invocation and its stdout is parsed as `KEY=VALUE\n` lines.
# Those vars are merged into the spawned process environment (later hooks
# override earlier ones). Use this for ephemeral credentials, per-skill
# PATH adjustments, or short-lived tokens. The resolved KEY names (NEVER
# values) are written to `~/.deepseek/audit.log` so each session can be
# reconciled later. Hook failure / timeout simply contributes no vars —
# it does not abort the shell call.
#
# [hooks]
# enabled = true
# default_timeout_secs = 30
#
# [[hooks.hooks]]
# event = "session_start"
# command = "echo 'CodeWhale session started'"
#
# # Inject ephemeral creds into every shell call. Output one
# # KEY=VALUE per line on stdout (export prefix optional).
# [[hooks.hooks]]
# name = "aws-creds"
# event = "shell_env"
# command = "aws-vault export my-profile --format=env"
# # Optionally limit to specific tool names / categories:
# # condition = { type = "tool_category", category = "shell" }
# ─────────────────────────────────────────────────────────────────────────────────
# Runtime API (`deepseek serve --http`) (#561)
# ─────────────────────────────────────────────────────────────────────────────────
# Tuning knobs for the local HTTP/SSE daemon. The server binds to 127.0.0.1
# by default and is intended for local UIs (whalescale-desktop, dashboards,
# automation scripts). Today this section only controls the CORS allow-list;
# host/port/workers stay on `--host`, `--port`, and `--workers` flags.
#
# Built-in defaults always include:
# http://localhost:3000 http://127.0.0.1:3000
# http://localhost:1420 http://127.0.0.1:1420
# tauri://localhost
#
# Use `cors_origins` to add extra dev origins (e.g. Vite's default `:5173`).
# User entries STACK on top of the defaults — they do not replace them. The
# CLI flag `--cors-origin URL` (repeatable) and env var
# `DEEPSEEK_CORS_ORIGINS=url1,url2` resolve to the same merged list.
#
# [runtime_api]
# cors_origins = ["http://localhost:5173", "http://127.0.0.1:5173"]
# ─────────────────────────────────────────────────────────────────────────────────
# Requirements (admin constraints) example file
# ─────────────────────────────────────────────────────────────────────────────────
# allowed_approval_policies = ["on-request", "untrusted", "never"]
# allowed_sandbox_modes = ["read-only", "workspace-write"]