-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.example.toml
More file actions
950 lines (887 loc) · 57.5 KB
/
Copy pathconfig.example.toml
File metadata and controls
950 lines (887 loc) · 57.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
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ CodeSmith Configuration ║
# ║ ║
# ║ Terminal coding agent for open-weight models. ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
# 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 volcengine`, `--provider xiaomi-mimo`, `--provider fireworks`,
# `--provider siliconflow`, `/provider moonshot`, `/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 | volcengine | openrouter | xiaomi-mimo | novita | fireworks | siliconflow | moonshot | 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" }
# Escape hatch (ROADMAP §D2): for an OpenAI-compatible gateway that doesn't fit a
# built-in `[providers.*]` table, register a `[[providers.custom]]` entry (see the
# bottom of the providers section) and select it by id here. When `custom_provider`
# is set it takes precedence over `provider` above.
# custom_provider = "acme" # must match a [[providers.custom]] id below
# ─────────────────────────────────────────────────────────────────────────────────
# 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
# deepseek/deepseek-v4-pro — default OpenRouter DeepSeek model ID
# arcee-ai/trinity-large-thinking — OpenRouter Arcee Trinity Large Thinking
# qwen/qwen3.7-max — OpenRouter Qwen 3.7 Max
# xiaomi/mimo-v2.5-pro — OpenRouter Xiaomi MiMo 2.5 Pro
# xiaomi/mimo-v2.5 — OpenRouter Xiaomi MiMo 2.5
# gpt-5 — default generic OpenAI-compatible model ID
# deepseek-ai/deepseek-v4-flash — default AtlasCloud model ID
# deepseek-reasoner — default Wanjie Ark model ID
# mimo-v2.5-pro — default Xiaomi MiMo model ID
# accounts/fireworks/models/deepseek-v4-pro — Fireworks AI Pro model ID
# deepseek-ai/DeepSeek-V4-Pro — SiliconFlow hosted Pro model ID
# deepseek-ai/DeepSeek-V4-Flash — SiliconFlow hosted Flash 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
# ─────────────────────────────────────────────────────────────────────────────────
# Startup update check
# ─────────────────────────────────────────────────────────────────────────────────
# The TUI checks for newer CodeSmith releases in the background at startup.
# Set check_for_updates = false in managed or air-gapped environments.
# update_uri may point at a GitHub-compatible latest-release JSON endpoint.
[update]
check_for_updates = true
# update_uri = "https://internal.mirror.example/codesmith/releases/latest"
# ─────────────────────────────────────────────────────────────────────────────────
# Paths
# ─────────────────────────────────────────────────────────────────────────────────
# New installs write product state under ~/.codesmith/. Existing ~/.codesmith/
# files are still read as compatibility fallbacks when the .codesmith file is
# absent.
skills_dir = "~/.codesmith/skills"
mcp_config_path = "~/.codesmith/mcp.json"
notes_path = "~/.codesmith/notes.txt"
memory_path = "~/.codesmith/memory.md"
# instructions = ["./AGENTS.md", "~/.codesmith/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 (.codesmith/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.
# personality = "calm"
#
# Voice-and-tone overlay for the system prompt: "calm" (default) or
# "playful". Presentation-only — it changes how the agent speaks, never
# what it does. Case-insensitive; anything else fails startup validation.
# Overridable from project-level config.
# append_system_prompt = ["~/.codesmith/extra-prompt.md"]
#
# Additional prompt sections appended after the assembled system prompt,
# in declared order. Entries are file paths expanded so `~` and env vars
# work; unreadable files are skipped with a warning.
#
# For a full override there are also (left commented — they discard the
# built-in constitution, tool taxonomy, and mode layers):
#
# system_prompt = "You are a release engineering assistant..."
# system_prompt_file = "~/.codesmith/prompt.md"
#
# Inline system_prompt wins over system_prompt_file; append sections still
# render after the override. Prefer instructions + append_system_prompt.
# Run /system in the TUI to inspect the final assembled prompt.
# ─────────────────────────────────────────────────────────────────────────────────
# User memory (#489) — default ON. 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. Opt out with
# enabled = false or CODESMITH_DISABLE_AUTO_MEMORY=1 (bare/simple and
# storage-less remote sessions also disable it automatically).
# ─────────────────────────────────────────────────────────────────────────────────
[memory]
# enabled = true # default ON; set false to opt out entirely
# Override the env-var equivalent: `CODESMITH_MEMORY=on`
# kod_enabled = false # directory-based Knowledge On Demand memory
# # (frontmatter .md files + MEMORY.md entrypoint);
# # requires enabled = true and the knowledge_on_demand
# # feature flag
# directory = "~/.codesmith/memory" # defaults to the parent of memory_path
# # with /memory/ appended
# excludes = [] # paths excluded from the four-tier CLAUDE.md memory
# # merge (Plan 03 / finding F1); resolved into
# # CODESMITH_MEMORY_EXCLUDES at engine startup
# Parsed but currently unused (reserved for future versions):
# tools_file = "./tools.json"
# Native tool catalog controls (#2076). By default only the core tool surface
# is loaded into the model context; less common native tools are discoverable
# through ToolSearch and loaded on first use.
# [tools]
# always_load = ["git_show", "notify"]
# ─────────────────────────────────────────────────────────────────────────────────
# 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:
# CODESMITH_SANDBOX_BACKEND → sandbox_backend
# CODESMITH_SANDBOX_URL → sandbox_url
# CODESMITH_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.
# ─────────────────────────────────────────────────────────────────────────────────
# Bubblewrap (Linux only, additional filesystem isolation)
# ─────────────────────────────────────────────────────────────────────────────────
# When set to true and `/usr/bin/bwrap` is present, exec_shell commands are
# routed through bubblewrap instead of relying solely on Landlock. Bubblewrap
# creates a read-only view of the root filesystem with write access limited to
# the working directory. Install separately:
#
# Ubuntu/Debian: apt install bubblewrap
# Fedora: dnf install bubblewrap
# Arch: pacman -S bubblewrap
#
# prefer_bwrap = false # default — use Landlock only
#
# Env override: CODESMITH_PREFER_BWRAP=true
# 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 (0/unset = 120)
# inherit_full_registry = false # false (default) = child tool surface is a
# # subset of the parent's effective tools
# # (restrictToSubset); true restores the legacy
# # v0.6.6 full-inheritance behavior.
# Per-role/per-type model defaults; explicit `model` values on agent_open win:
# default_model = "deepseek-v4-pro"
# worker_model = "deepseek-v4-pro"
# explorer_model = "deepseek-v4-flash"
# awaiter_model = "deepseek-v4-flash"
# review_model = "deepseek-v4-pro"
# custom_model = "deepseek-v4-pro"
# [subagents.models] # free-form role/type keys
# worker = "deepseek-v4-pro"
# explore = "deepseek-v4-flash"
# Optional managed policy paths (defaults to /etc/codesmith/*.toml on unix):
# managed_config_path = "/etc/codesmith/managed_config.toml"
# requirements_path = "/etc/codesmith/requirements.toml"
# ─────────────────────────────────────────────────────────────────────────────────
# Structured sandbox controls ([sandbox] + [sandbox.filesystem] / [sandbox.network])
# ─────────────────────────────────────────────────────────────────────────────────
# Every key is optional; these tables layer on top of the flat
# sandbox_mode / prefer_bwrap keys above. See docs/SANDBOX.md for platform
# details (macOS Seatbelt, Linux Landlock + seccomp, Windows Job Object,
# bubblewrap) and denial metadata.
#
# [sandbox]
# enabled = true # master switch for OS-level sandboxing
# fail_if_unavailable = false # true = fail closed instead of unsandboxed fallback
# enabled_platforms = ["macos", "linux"]
# excluded_commands = [] # program names or command prefixes never sandboxed
# auto_allow_bash_if_sandboxed = true # skip the approval prompt for shell calls
# # that ran inside the sandbox
# prefer_bwrap = false # same as the top-level flat key
#
# [sandbox.filesystem] # path-level read/write policy
# mode = "workspace-write" # read-only | workspace-write | danger-full-access | external-sandbox
# writable_roots = [] # extra writable paths (added to the mode default)
# allow_read = []
# deny_read = [] # deny always wins over allow
# allow_write = []
# deny_write = []
# exclude_tmpdir = true # keep $TMPDIR writable for build tools
# exclude_slash_tmp = false # keep /tmp writable
#
# [sandbox.network]
# enabled = true # network blocking inside the sandbox
# allow_managed_domains_only = false # local OS sandboxes cannot enforce host allow-lists
# allow = []
# deny = []
# ─────────────────────────────────────────────────────────────────────────────────
# 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 volcengine` / `/provider fireworks` /
# `--provider siliconflow` / `/provider moonshot`
# switches between them without having to re-enter keys. Env vars override anything set here:
# DeepSeek: DEEPSEEK_API_KEY, CODESMITH_BASE_URL, CODESMITH_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
# Volcengine Ark: VOLCENGINE_API_KEY (or VOLCENGINE_ARK_API_KEY / ARK_API_KEY), VOLCENGINE_BASE_URL, VOLCENGINE_MODEL
# OpenRouter: OPENROUTER_API_KEY, OPENROUTER_BASE_URL, OPENROUTER_MODEL
# Xiaomi MiMo: XIAOMI_MIMO_API_KEY (or XIAOMI_API_KEY / MIMO_API_KEY), XIAOMI_MIMO_BASE_URL, XIAOMI_MIMO_MODEL
# Novita: NOVITA_API_KEY, NOVITA_BASE_URL, NOVITA_MODEL
# Fireworks: FIREWORKS_API_KEY, FIREWORKS_BASE_URL
# SiliconFlow: SILICONFLOW_API_KEY, SILICONFLOW_BASE_URL, SILICONFLOW_MODEL
# Moonshot/Kimi: MOONSHOT_API_KEY (or KIMI_API_KEY), MOONSHOT_BASE_URL, MOONSHOT_MODEL
# 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
#
# Custom DeepSeek-compatible APIs usually do not need a new provider table:
# set `provider = "deepseek"` and override [providers.deepseek].base_url/model.
# For generic OpenAI-compatible gateways, use `provider = "openai"` and the
# [providers.openai] table below. Keep provider/api_key/base_url in user config
# or environment variables; project overlays are not allowed to set them.
# 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"
# Custom DeepSeek-compatible example:
# base_url = "https://your-provider.example/v1"
# model = "deepseek-ai/DeepSeek-V4-Pro"
# http_headers = { "X-Model-Provider-Id" = "your-model-provider" } # optional custom request headers
# Vision capability (product-polish §1). Every [providers.*] table (and each
# [[providers.custom]] entry) accepts an optional `vision = true|false`.
# Unset -> static model-name matrix (deepseek-vl*, Qwen-VL, GLM-V, gpt-4o+,
# claude-*, mimo-v2.5 ... are vision-capable; text-only families are not).
# Set `true` when a gateway fronts a vision model the matrix cannot see, or
# `false` to force the text-reference fallback on a vision-capable model.
# When true, `/attach` + Ctrl+V images are sent as native image content
# blocks; when false they degrade to path references + image_analyze/read_file.
# 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. Only use
# non-local http:// gateways on a trusted network.
[providers.openai]
# api_key = "YOUR_OPENAI_COMPATIBLE_API_KEY"
# base_url = "https://api.openai.com/v1"
# model = "gpt-5"
# Gateway example (a custom base_url requires an explicit model — startup
# fails fast without one):
# base_url = "https://gateway.example/v1"
# model = "your-deepseek-compatible-model"
# vision = true # gateway fronts a vision model -> send inline image blocks
# 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
# Volcengine / Volcano Engine Ark Coding API
[providers.volcengine]
# api_key = "YOUR_VOLCENGINE_API_KEY"
# base_url = "https://ark.cn-beijing.volces.com/api/coding/v3"
# model = "DeepSeek-V4-Pro" # or DeepSeek-V4-Flash
# 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"
# Recent large model IDs also accepted here include arcee-ai/trinity-large-thinking,
# qwen/qwen3.7-max, xiaomi/mimo-v2.5-pro, qwen/qwen3.6-35b-a3b,
# google/gemma-4-31b-it, z-ai/glm-5.1, moonshotai/kimi-k2.6, and
# nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free.
# Xiaomi MiMo OpenAI-compatible endpoint (https://platform.xiaomimimo.com)
[providers.xiaomi_mimo]
# api_key = "YOUR_XIAOMI_KEY"
# base_url = "https://api.xiaomimimo.com/v1"
# model = "mimo-v2.5-pro"
# 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"
# SiliconFlow-hosted DeepSeek V4 (https://siliconflow.com)
[providers.siliconflow]
# api_key = "YOUR_SILICONFLOW_API_KEY"
# base_url = "https://api.siliconflow.com/v1"
# model = "deepseek-ai/DeepSeek-V4-Pro" # or deepseek-ai/DeepSeek-V4-Flash
# 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
# ─────────────────────────────────────────────────────────────────────────────────
# Custom providers (escape hatch — `[[providers.custom]]`, ROADMAP §D2)
# ─────────────────────────────────────────────────────────────────────────────────
# For OpenAI-compatible gateways that don't fit a built-in provider table, register
# one or more custom providers here and select one with the top-level
# `custom_provider = "<id>"` field (see the top of this file). Each entry needs a
# unique `id`; the remaining fields mirror the built-in `[providers.*]` tables.
# When `custom_provider` is set it takes precedence over `provider`.
#
# `[[providers.custom]]` is an array of tables, so multiple entries are allowed.
# It is read-only via `config set` (edit this file by hand) and is treated as
# sensitive: `api_key` values are masked in `config list`. Project overlays cannot
# set `custom_provider` or `[[providers.custom]]` — credentials, endpoints, and
# provider selection must live in user config or environment variables.
#
# Note (v1): a custom provider reuses the DeepSeek capability matrix (context
# window / max_output / thinking budget) for diagnostics; request shaping is
# unaffected (the rig adapter keys by provider name, not capability metadata).
#
# [[providers.custom]]
# id = "acme"
# api_key = "YOUR_ACME_API_KEY"
# base_url = "https://gateway.acme.example/v1"
# model = "acme-flagship"
# # http_headers = { "X-Org" = "acme" } # optional custom request headers
#
# [[providers.custom]]
# id = "internal"
# base_url = "http://localhost:8080/v1" # localhost: no api_key needed
# model = "internal-dev"
#
# Then activate one (uncomment the top-level selector):
# custom_provider = "acme"
# ─────────────────────────────────────────────────────────────────────────────────
# Web Search Provider
# ─────────────────────────────────────────────────────────────────────────────────
# Choose which backend `web_search` uses. Default is DuckDuckGo HTML scraping
# with Bing fallback — no API key needed. Bing remains selectable for users who
# explicitly prefer it. Switch to Tavily, Bocha, Metaso, or Baidu for
# API-backed search.
#
# [search]
# provider = "duckduckgo" # duckduckgo | bing | tavily | bocha | metaso | baidu | volcengine
# # duckduckgo: HTML scrape with Bing fallback
# # bing: HTML scrape, no API key
# # tavily: https://tavily.com — AI search, needs api_key
# # bocha: https://bochaai.com — 博查AI搜索,国内友好,需api_key
# # metaso: https://metaso.cn — 秘塔AI搜索,每天 100 次免费
# # 设置 METASO_API_KEY 或 [search] api_key 可提升额度
# # baidu: 百度 AI Search via qianfan.baidubce.com,需 api_key
# # volcengine: 火山引擎 Ark web_search (免费 2 万次/月), 需 api_key
# # 也回退到 VOLCENGINE_API_KEY / VOLCENGINE_ARK_API_KEY / ARK_API_KEY 环境变量
# api_key = "YOUR_SEARCH_KEY" # required for tavily, bocha, and baidu; optional for metaso
# # WARNING: treat config.toml like a secret file when
# # storing API keys. Prefer env vars for local smoke tests.
#
# Env-var overrides:
# CODESMITH_SEARCH_PROVIDER → search.provider
# CODESMITH_SEARCH_API_KEY → search.api_key
# METASO_API_KEY → metaso key fallback
# BAIDU_SEARCH_API_KEY → baidu key fallback
# ─────────────────────────────────────────────────────────────────────────────────
# Persistent code index (docs/INDEX.md). Enables `symbol_search` /
# `find_references`: indexed symbol navigation that beats grep_files on
# large repositories. Index data lives under ~/.codesmith/index/<workspace>/,
# refreshed lazily and incrementally on every query (mtime+size diff, no
# file watcher). Everything below is optional — absent table = enabled with
# the built-in `tree-sitter` backend for rust/python/js/ts/go.
#
# [index]
# enabled = true # master switch (CODESMITH_INDEX_ENABLED)
# refresh_budget_ms = 2000 # per-query incremental refresh budget
#
# [index.files] # file inventory cache (list_files surface)
# enabled = true
#
# [index.symbols] # symbol index capability
# enabled = true
# backend = "tree-sitter" # registry id (CODESMITH_INDEX_SYMBOLS_BACKEND)
# [index.symbols.languages] # per-language switches, absent = enabled
# rust = true
# python = true
# typescript = true
# javascript = true
# go = true
#
# [index.semantic] # reserved: embedding-based search. No built-in
# enabled = false # backend yet; enabling with backend = "none"
# backend = "none" # fails validation with guidance.
# ─────────────────────────────────────────────────────────────────────────────────
# 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 = []
# proxy = [] # hostnames whose DNS may resolve to fake-IP/private
# # proxy ranges in an explicitly trusted proxy setup
# # (literal IP URLs remain blocked)
# audit = true # one line per call to ~/.codesmith/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/camilesing/codesmith-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 | zh-Hans | zh-Hant | hi | es-419
# # "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
# file_freshness = true # read-before-edit validation: edit_file/write_file/fim_edit/apply_patch
# # reject files never read in this session or changed on disk since
# # their last read. Correctness guard (not a security control);
# # applies in all modes including Yolo.
# ─────────────────────────────────────────────────────────────────────────────────
# 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
#
# Xiaomi MiMo image understanding can be configured through the same tool:
# model = "mimo-v2.5"
# api_key = "YOUR_XIAOMI_KEY"
# base_url = "https://api.xiaomimo.com/v1"
# ─────────────────────────────────────────────────────────────────────────────────
# Utility Model Configuration (optional)
# ─────────────────────────────────────────────────────────────────────────────────
# A cheap/fast secondary LLM used for background assists so the main model's
# budget is spent on the actual conversation:
# - workshop large-output synthesis (#548): tool results above the
# `large_output_threshold_tokens` threshold are condensed by this model;
# only the synthesis enters the parent context (the raw output is kept in
# the workshop variable `last_tool_result`)
# - auto-route classification (`/model auto` + sub-agent routing)
# - Flash seams (`[context] seam_model` default)
#
# When this table is absent every assist falls back to the main model and
# behaviour is unchanged. api_key / base_url / provider inherit from the main
# config when omitted (same-provider setups reuse the main client with a
# per-request model override); a different `provider` builds a dedicated second
# client (e.g. main = anthropic, utility = deepseek) and then needs its own
# api_key — one vendor's key is never sent to another.
# The model id can also be set via CODESMITH_UTILITY_MODEL (legacy alias:
# CODESMITH_UTILITY_MODEL).
#
# [utility_model]
# model = "deepseek-v4-flash" # Required: enables the utility model
# provider = "deepseek" # Optional: defaults to the main provider
# api_key = "YOUR_API_KEY" # Optional: defaults to main api_key
# base_url = "https://api.deepseek.com/beta" # Optional: defaults to main base_url
# ─────────────────────────────────────────────────────────────────────────────────
# 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
# Defaults to the [utility_model] model id when configured, else Flash.
seam_model = "deepseek-v4-flash"
# Exact token counting: path to a HuggingFace tokenizer.json (BPE/Unigram).
# When set (and loadable), compaction / capacity / truncation budgets use
# real counts instead of the chars÷3 heuristic. Obtain one with e.g.
# huggingface-cli download deepseek-ai/DeepSeek-V3 tokenizer.json \
# --local-dir ~/.codesmith/tokenizers
# tokenizer_path = "~/.codesmith/tokenizers/tokenizer.json"
# ─────────────────────────────────────────────────────────────────────────────────
# Workshop / Large-Output Routing (#548)
# ─────────────────────────────────────────────────────────────────────────────────
# Tool outputs exceeding `large_output_threshold_tokens` are routed through a
# synthesis sub-agent powered by [utility_model] (main model when unconfigured).
# 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 `CODESMITH_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:
#
# ~/.codesmith/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
# # codesmith 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
# java → jdtls
# vue → vue-language-server --stdio
# c, cpp → clangd
#
# Java support uses Eclipse JDT LS via the `jdtls` command. IntelliJ IDEA is
# not required, and installing IntelliJ IDEA alone does not install `jdtls`.
#
# 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"]
# java = ["jdtls"]
# vue = ["vue-language-server", "--stdio"]
# ─────────────────────────────────────────────────────────────────────────────────
# 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 (alias: pre_tool_use), tool_call_after (alias: post_tool_use),
# mode_change, on_error, shell_env, task_created, task_completed, pre_compact.
#
# `message_submit` is the only mutable hook: it receives JSON on stdin and
# can replace or block the submitted text (see docs/HOOKS.md). `pre_compact`
# stdout is merged into the compaction summary as preserved context.
#
# `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 `~/.codesmith/audit.log` so each session can be
# reconciled later. Hook failure / timeout simply contributes no vars —
# it does not abort the shell call.
#
# Full schema, conditions, and I/O contracts: docs/HOOKS.md
#
# [hooks]
# enabled = true
# default_timeout_secs = 30
# working_dir = "~/work" # default: the active workspace
#
# [[hooks.hooks]]
# event = "session_start"
# command = "echo 'CodeSmith 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 (`codesmith 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
# `CODESMITH_CORS_ORIGINS=url1,url2` resolve to the same merged list.
#
# [runtime_api]
# cors_origins = ["http://localhost:5173", "http://127.0.0.1:5173"]
# ─────────────────────────────────────────────────────────────────────────────────
# Tool Overrides & Plugins ([tools])
# ─────────────────────────────────────────────────────────────────────────────────
# The `[tools]` table lets you replace any built-in tool with a custom
# implementation (script or command) or disable it entirely — without
# forking or recompiling the binary.
#
# Plugin scripts dropped in the plugin directory are auto-discovered and
# registered as model-visible tools alongside the built-in ones.
#
# Scripts receive the tool's JSON input on **stdin** and must return a
# JSON `ToolResult` (`{"content": "...", "success": true}`) on **stdout**.
#
# [tools]
# # Custom plugin directory (defaults to `~/.codesmith/tools/`)
# plugin_dir = "~/.codesmith/tools"
#
# [tools.overrides]
# # Disable a tool entirely — removes it from the model-visible catalog.
# "code_execution" = { type = "disabled" }
#
# # Replace a tool with a script. Relative paths resolve against plugin_dir.
# "exec_shell" = { type = "script", path = "audit-exec-shell.sh" }
#
# # Replace a tool with a command (binary on PATH or absolute path).
# "read_file" = { type = "command", command = "bat", args = ["--paging=never"] }
#
# # Scripts can also accept static arguments before the JSON input:
# "fetch_url" = { type = "script", path = "cached-fetch.sh", args = ["--ttl", "300"] }
# ──────────── Enterprise example: audit-logging exec_shell wrapper ──────────────
# Drop `audit-exec-shell.sh` in `~/.codesmith/tools/` and enable with:
#
# [tools.overrides]
# "exec_shell" = { type = "script", path = "audit-exec-shell.sh" }
#
# The wrapper logs every request to `~/.codesmith/audit/exec_shell.log`, then
# delegates to your own approved shell executor. Do not pipe the raw JSON
# request into `sh -s`; parse the command field and enforce your policy first.
#
# ```sh
# #!/usr/bin/env sh
# # name: exec_shell
# # description: Audit-logging wrapper for exec_shell
# # approval: required
# LOGDIR="${HOME}/.codesmith/audit"
# mkdir -p "$LOGDIR"
# LOGFILE="$LOGDIR/exec_shell.log"
# input=$(cat)
# echo "[$(date -Iseconds)] $input" >> "$LOGFILE"
# printf '%s\n' '{"content":"audit wrapper placeholder: configure an executor","success":false}'
# ```
# ─────────────────────────────────────────────────────────────────────────────────
# Requirements (admin constraints) example file
# ─────────────────────────────────────────────────────────────────────────────────
# allowed_approval_policies = ["on-request", "untrusted", "never"]
# allowed_sandbox_modes = ["read-only", "workspace-write"]