claude-evolve 1.8.17 → 1.8.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,7 @@ OPTIONS:
35
35
  SELECTORS:
36
36
  gen01, gen02, etc. Target specific generation
37
37
  all Target all generations
38
+ winner Target the candidate with highest performance score
38
39
  failed Target all candidates with failed status (includes retries)
39
40
  complete Target all candidates with complete status
40
41
  pending Target all candidates with pending status
@@ -56,6 +57,7 @@ ACTIONS:
56
57
 
57
58
  EXAMPLES:
58
59
  claude-evolve edit gen03 failed # Mark all gen03 as failed
60
+ claude-evolve edit winner pending # Reset the winner to pending (recalculate)
59
61
  claude-evolve edit failed pending # Reset all failed candidates to pending
60
62
  claude-evolve edit pending skipped # Skip all pending candidates
61
63
  claude-evolve edit --recent-generations=15 failed pending # Reset only recent 15 gen failures
@@ -116,8 +118,8 @@ if ! validate_config; then
116
118
  fi
117
119
 
118
120
  # Validate selector format
119
- if [[ "$SELECTOR" != "all" && ! "$SELECTOR" =~ ^gen[0-9]+$ && "$SELECTOR" != "failed" && "$SELECTOR" != "complete" && "$SELECTOR" != "pending" && "$SELECTOR" != "running" && "$SELECTOR" != "skipped" && "$SELECTOR" != "0perf" ]]; then
120
- echo "[ERROR] Selector must be 'all', 'genXX' (e.g., gen01), or status ('failed', 'complete', 'pending', 'running', 'skipped', '0perf')" >&2
121
+ if [[ "$SELECTOR" != "all" && "$SELECTOR" != "winner" && ! "$SELECTOR" =~ ^gen[0-9]+$ && "$SELECTOR" != "failed" && "$SELECTOR" != "complete" && "$SELECTOR" != "pending" && "$SELECTOR" != "running" && "$SELECTOR" != "skipped" && "$SELECTOR" != "0perf" ]]; then
122
+ echo "[ERROR] Selector must be 'all', 'winner', 'genXX' (e.g., gen01), or status ('failed', 'complete', 'pending', 'running', 'skipped', '0perf')" >&2
121
123
  exit 1
122
124
  fi
123
125
 
@@ -201,19 +203,45 @@ try:
201
203
  recent_gen_set = set(sorted_generations[:n_recent])
202
204
  print(f'[INFO] Filtering to recent generations: {sorted(recent_gen_set)}', file=sys.stderr)
203
205
 
206
+ # For 'winner' selector, find the candidate with highest performance
207
+ winner_candidate_id = None
208
+ if selector == 'winner':
209
+ max_performance = None
210
+ for i in range(1, len(rows)):
211
+ row = rows[i]
212
+ if len(row) < 4:
213
+ continue
214
+ try:
215
+ perf_str = row[3].strip()
216
+ if perf_str and perf_str != '':
217
+ performance = float(perf_str)
218
+ if max_performance is None or performance > max_performance:
219
+ max_performance = performance
220
+ winner_candidate_id = row[0]
221
+ except (ValueError, IndexError):
222
+ continue
223
+
224
+ if winner_candidate_id:
225
+ print(f'[INFO] Winner candidate: {winner_candidate_id} with performance: {max_performance}', file=sys.stderr)
226
+ else:
227
+ print('[WARN] No winner found (no valid performance scores)', file=sys.stderr)
228
+
204
229
  # Update matching rows
205
230
  for i in range(1, len(rows)):
206
231
  row = rows[i]
207
232
  if len(row) < 1:
208
233
  continue
209
-
234
+
210
235
  candidate_id = row[0]
211
236
  current_status = row[4] if len(row) > 4 else ''
212
-
237
+
213
238
  # Check if this row matches selector
214
239
  matches = False
215
240
  if selector == 'all':
216
241
  matches = True
242
+ elif selector == 'winner':
243
+ # Match only the winner candidate
244
+ matches = (candidate_id == winner_candidate_id)
217
245
  elif selector.startswith('gen') and '-' in candidate_id:
218
246
  # Generation selector (e.g., gen01, gen02)
219
247
  matches = candidate_id.startswith(selector + '-')
@@ -335,41 +363,60 @@ try:
335
363
 
336
364
  # Skip header if present
337
365
  start_idx = 1 if rows and rows[0] and rows[0][0].lower() == 'id' else 0
338
-
366
+
339
367
  # Determine recent generations if filtering is requested
340
368
  recent_gen_set = set()
341
369
  if recent_generations and recent_generations.isdigit():
342
370
  n_recent = int(recent_generations)
343
-
371
+
344
372
  # Find all generation numbers from candidate IDs
345
373
  all_generations = set()
346
374
  for row in rows[start_idx:]:
347
375
  if len(row) < 1:
348
376
  continue
349
377
  candidate_id = row[0]
350
-
378
+
351
379
  # Extract generation number from candidate_id (e.g., gen01-001 -> 1)
352
380
  match = re.match(r'^gen(\d+)-', candidate_id)
353
381
  if match:
354
382
  gen_num = int(match.group(1))
355
383
  all_generations.add(gen_num)
356
-
384
+
357
385
  # Get the most recent N generations
358
386
  if all_generations:
359
387
  sorted_generations = sorted(all_generations, reverse=True)
360
388
  recent_gen_set = set(sorted_generations[:n_recent])
361
-
389
+
390
+ # For 'winner' selector, find the candidate with highest performance
391
+ winner_candidate_id = None
392
+ if selector == 'winner':
393
+ max_performance = None
394
+ for row in rows[start_idx:]:
395
+ if len(row) < 4:
396
+ continue
397
+ try:
398
+ perf_str = row[3].strip()
399
+ if perf_str and perf_str != '':
400
+ performance = float(perf_str)
401
+ if max_performance is None or performance > max_performance:
402
+ max_performance = performance
403
+ winner_candidate_id = row[0]
404
+ except (ValueError, IndexError):
405
+ continue
406
+
362
407
  candidates = []
363
408
  for row in rows[start_idx:]:
364
409
  if len(row) < 1:
365
410
  continue
366
-
411
+
367
412
  candidate_id = row[0]
368
413
  current_status = row[4] if len(row) > 4 else ''
369
-
414
+
370
415
  # Check if matches status selector
371
416
  matches = False
372
- if selector == 'pending':
417
+ if selector == 'winner':
418
+ matches = (candidate_id == winner_candidate_id)
419
+ elif selector == 'pending':
373
420
  matches = current_status == '' or current_status == 'pending'
374
421
  elif selector == 'failed':
375
422
  matches = current_status.startswith('failed')
@@ -478,17 +525,36 @@ with EvolutionCSV('$FULL_CSV_PATH') as csv:
478
525
  if all_generations:
479
526
  sorted_generations = sorted(all_generations, reverse=True)
480
527
  recent_gen_set = set(sorted_generations[:n_recent])
481
-
528
+
529
+ # For 'winner' selector, find the candidate with highest performance
530
+ winner_candidate_id = None
531
+ if selector == 'winner':
532
+ max_performance = None
533
+ for row in rows[start_idx:]:
534
+ if not row or len(row) < 4:
535
+ continue
536
+ try:
537
+ perf_str = row[3].strip()
538
+ if perf_str and perf_str != '':
539
+ performance = float(perf_str)
540
+ if max_performance is None or performance > max_performance:
541
+ max_performance = performance
542
+ winner_candidate_id = row[0].strip()
543
+ except (ValueError, IndexError):
544
+ continue
545
+
482
546
  for row in rows[start_idx:]:
483
547
  if not row or not row[0].strip():
484
548
  continue
485
-
549
+
486
550
  candidate_id = row[0].strip()
487
551
  current_status = row[4].strip() if len(row) > 4 else ''
488
-
552
+
489
553
  matches = False
490
554
  if selector == 'all':
491
555
  matches = True
556
+ elif selector == 'winner':
557
+ matches = (candidate_id == winner_candidate_id)
492
558
  elif selector.startswith('gen') and re.match(r'^gen\\d+$', selector):
493
559
  # Generation selector (e.g., gen01, gen02)
494
560
  gen_pattern = f'^{selector}-'
package/lib/ai-cli.sh CHANGED
@@ -118,7 +118,7 @@ $prompt"
118
118
  ai_output=$(timeout 600 opencode -m openrouter/anthropic/claude-opus-4.1 run "$prompt" 2>&1)
119
119
  local ai_exit_code=$?
120
120
  ;;
121
- moonshot-kimi-k2)
121
+ kimi-k2-think-moonshot)
122
122
  local ai_output
123
123
  ai_output=$(timeout 600 opencode -m moonshotai/kimi-k2-thinking run "$prompt" 2>&1)
124
124
  local ai_exit_code=$?
@@ -129,12 +129,6 @@ $prompt"
129
129
  ai_output=$(timeout 2400 codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss "$prompt" 2>&1)
130
130
  local ai_exit_code=$?
131
131
  ;;
132
- kimi-k2-llamacloud)
133
- # Kimi K2 via Codex CLI with Ollama cloud backend
134
- local ai_output
135
- ai_output=$(timeout 600 codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss -m kimi-k2:1t-cloud "$prompt" 2>&1)
136
- local ai_exit_code=$?
137
- ;;
138
132
  deepseek-v3-llamacloud)
139
133
  # Deepseek via Codex CLI with Ollama cloud backend
140
134
  local ai_output
package/lib/config.sh CHANGED
@@ -60,7 +60,7 @@ DEFAULT_WORKER_MAX_CANDIDATES=3
60
60
  # Default LLM CLI configuration
61
61
  DEFAULT_LLM_RUN="glm-zai glm-zai glm-zai glm-zai glm-zai codex-oss-local gemini-flash haiku"
62
62
  # Ideate: Commercial models for idea generation + local fallback
63
- DEFAULT_LLM_IDEATE="opus-openrouter moonshot-kimi-k2 gemini-pro sonnet-think gpt5high grok-4-openrouter deepseek-openrouter glm-zai"
63
+ DEFAULT_LLM_IDEATE="opus-openrouter kimi-k2-think-moonshot gemini-pro sonnet-think gpt5high grok-4-openrouter deepseek-openrouter glm-zai"
64
64
 
65
65
  # Load configuration from a YAML file and update variables
66
66
  _load_yaml_config() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.8.17",
3
+ "version": "1.8.19",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",
@@ -80,7 +80,7 @@ llm_cli:
80
80
  # Default configuration: 100% local code generation, commercial ideation + local fallback
81
81
  # Commented out because these change over time; uncomment to override
82
82
  #run: codex-qwen3
83
- #ideate: opus-openrouter moonshot-kimi-k2 gemini-pro sonnet-think gpt5high grok-4-openrouter deepseek-openrouter glm-zai
83
+ #ideate: opus-openrouter kimi-k2-think-moonshot gemini-pro sonnet-think gpt5high grok-4-openrouter deepseek-openrouter glm-zai
84
84
 
85
85
  # Available models:
86
86
  # - sonnet: Claude 3.5 Sonnet via Claude CLI
@@ -97,6 +97,6 @@ llm_cli:
97
97
  # - grok-code-fast: Grok Code Fast 1 via OpenRouter
98
98
  # - grok-4: Grok 4 via OpenRouter
99
99
  # - opus-openrouter: Claude Opus 4.1 via OpenRouter
100
- # - moonshot-kimi-k2: Kimi K2 Thinking via Moonshot
100
+ # - kimi-k2-think-moonshot: Kimi K2 Thinking via Moonshot
101
101
  # - codex-qwen3: Qwen3-Coder via Codex + Ollama (local, free, RECOMMENDED)
102
102
  # - aider-qwen3: Qwen3-Coder via Aider + Ollama (local, free, experimental)
package/lib/config.sh.new DELETED
@@ -1,327 +0,0 @@
1
- #!/bin/bash
2
- # Configuration loader for claude-evolve
3
-
4
- # Default configuration values
5
- DEFAULT_EVOLUTION_DIR="evolution"
6
- DEFAULT_ALGORITHM_FILE="algorithm.py"
7
- DEFAULT_EVALUATOR_FILE="evaluator.py"
8
- DEFAULT_BRIEF_FILE="BRIEF.md"
9
- DEFAULT_EVOLUTION_CSV="evolution.csv"
10
- DEFAULT_OUTPUT_DIR=""
11
- DEFAULT_PARENT_SELECTION="best"
12
- # Detect Python command based on platform
13
- detect_python_cmd() {
14
- # Try python3 first (macOS, Linux)
15
- if command -v python3 >/dev/null 2>&1; then
16
- echo "python3"
17
- # Try python (Windows, some Linux)
18
- elif command -v python >/dev/null 2>&1; then
19
- # Verify it's Python 3
20
- if python -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
21
- echo "python"
22
- else
23
- echo "python3" # Fallback
24
- fi
25
- else
26
- echo "python3" # Default fallback
27
- fi
28
- }
29
-
30
- DEFAULT_PYTHON_CMD="$(detect_python_cmd)"
31
-
32
- # Default ideation strategy values
33
- DEFAULT_TOTAL_IDEAS=15
34
- DEFAULT_NOVEL_EXPLORATION=3
35
- DEFAULT_HILL_CLIMBING=5
36
- DEFAULT_STRUCTURAL_MUTATION=3
37
- DEFAULT_CROSSOVER_HYBRID=4
38
- DEFAULT_NUM_ELITES=3
39
- DEFAULT_NUM_REVOLUTION=2 # Number of top novel candidates to include
40
-
41
- # Default parallel execution values
42
- DEFAULT_PARALLEL_ENABLED=false
43
- DEFAULT_MAX_WORKERS=4
44
- DEFAULT_LOCK_TIMEOUT=10
45
-
46
- # Default auto ideation value
47
- DEFAULT_AUTO_IDEATE=true
48
-
49
- # Default retry value
50
- DEFAULT_MAX_RETRIES=3
51
-
52
- # Default memory limit (in MB, 0 means no limit)
53
- # Set to reasonable limit for ML workloads - about half of available system RAM
54
- DEFAULT_MEMORY_LIMIT_MB=12288
55
-
56
- # Default LLM CLI configuration - use simple variables instead of arrays
57
- # Run: 100% local with qwen3 via Codex+Ollama (more reliable than aider)
58
- DEFAULT_LLM_RUN="codex-qwen3 codex-oss gemini-flash"
59
- # Ideate: Commercial models for idea generation + local fallback
60
- DEFAULT_LLM_IDEATE="gemini sonnet-think gpt5high glm grok-4 codex-qwen3 codex-oss"
61
-
62
- # Load configuration from a YAML file and update variables
63
- _load_yaml_config() {
64
- local config_file="$1"
65
- if [[ ! -f "$config_file" ]]; then
66
- return 0 # File does not exist, nothing to load
67
- fi
68
-
69
-
70
- local in_ideation_section=false
71
- local in_parallel_section=false
72
- local in_llm_cli_section=false
73
- local llm_cli_subsection=""
74
-
75
- while IFS='' read -r line; do
76
- [[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
77
-
78
- if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
79
- continue
80
- fi
81
- local key="${BASH_REMATCH[1]}"
82
- local value="${BASH_REMATCH[2]}"
83
-
84
- local is_indented=false
85
- [[ $key =~ ^[[:space:]]+ ]] && is_indented=true
86
-
87
- key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
88
- value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
89
-
90
- if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
91
- echo "[CONFIG DEBUG] Before comment removal: key='$key' value='$value'" >&2
92
- fi
93
-
94
- value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
95
- value=$(echo "$value" | sed 's/^"//;s/"$//')
96
-
97
- if [[ $key == "ideation_strategies" ]]; then
98
- in_ideation_section=true
99
- in_parallel_section=false
100
- in_llm_cli_section=false
101
- continue
102
- elif [[ $key == "parallel" ]]; then
103
- in_parallel_section=true
104
- in_ideation_section=false
105
- in_llm_cli_section=false
106
- continue
107
- elif [[ $key == "llm_cli" ]]; then
108
- in_llm_cli_section=true
109
- in_ideation_section=false
110
- in_parallel_section=false
111
- llm_cli_subsection=""
112
- continue
113
- elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true || $in_llm_cli_section == true ]]; then
114
- in_ideation_section=false
115
- in_parallel_section=false
116
- in_llm_cli_section=false
117
- llm_cli_subsection=""
118
- fi
119
-
120
- if [[ $in_ideation_section == true ]]; then
121
- case $key in
122
- total_ideas) TOTAL_IDEAS="$value" ;;
123
- novel_exploration) NOVEL_EXPLORATION="$value" ;;
124
- hill_climbing) HILL_CLIMBING="$value" ;;
125
- structural_mutation) STRUCTURAL_MUTATION="$value" ;;
126
- crossover_hybrid) CROSSOVER_HYBRID="$value" ;;
127
- num_elites) NUM_ELITES="$value" ;;
128
- num_revolution) NUM_REVOLUTION="$value" ;;
129
- esac
130
- elif [[ $in_parallel_section == true ]]; then
131
- case $key in
132
- enabled) PARALLEL_ENABLED="$value" ;;
133
- max_workers) MAX_WORKERS="$value" ;;
134
- lock_timeout) LOCK_TIMEOUT="$value" ;;
135
- esac
136
- elif [[ $in_llm_cli_section == true ]]; then
137
- if [[ $key == "run" || $key == "ideate" ]]; then
138
- case $key in
139
- run) LLM_RUN="$value" ;;
140
- ideate) LLM_IDEATE="$value" ;;
141
- esac
142
- else
143
- value=$(echo "$value" | sed "s/^'//;s/'$//")
144
- local var_key=$(echo "$key" | sed 's/-/_/g')
145
- if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
146
- echo "[CONFIG DEBUG] Setting LLM_CLI_${var_key} = '$value'" >&2
147
- fi
148
- eval "LLM_CLI_${var_key}=\"$value\""
149
- fi
150
- else
151
- case $key in
152
- algorithm_file) ALGORITHM_FILE="$value" ;;
153
- evaluator_file) EVALUATOR_FILE="$value" ;;
154
- brief_file) BRIEF_FILE="$value" ;;
155
- evolution_csv) EVOLUTION_CSV="$value" ;;
156
- output_dir) OUTPUT_DIR="$value" ;;
157
- parent_selection) PARENT_SELECTION="$value" ;;
158
- python_cmd) PYTHON_CMD="$value" ;;
159
- auto_ideate) AUTO_IDEATE="$value" ;;
160
- max_retries) MAX_RETRIES="$value" ;;
161
- memory_limit_mb) MEMORY_LIMIT_MB="$value" ;;
162
- evolution_dir):
163
- echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
164
- ;;
165
- esac
166
- fi
167
- done < "$config_file"
168
- # Keep track of the last config file loaded to infer evolution_dir
169
- LAST_CONFIG_FILE_LOADED="$config_file"
170
- }
171
-
172
- load_config() {
173
- # Set defaults first
174
- EVOLUTION_DIR="$DEFAULT_EVOLUTION_DIR" # Initialize with default
175
- ALGORITHM_FILE="$DEFAULT_ALGORITHM_FILE"
176
- EVALUATOR_FILE="$DEFAULT_EVALUATOR_FILE"
177
- BRIEF_FILE="$DEFAULT_BRIEF_FILE"
178
- EVOLUTION_CSV="$DEFAULT_EVOLUTION_CSV"
179
- OUTPUT_DIR="$DEFAULT_OUTPUT_DIR"
180
- PARENT_SELECTION="$DEFAULT_PARENT_SELECTION"
181
- PYTHON_CMD="$DEFAULT_PYTHON_CMD"
182
-
183
- # Determine EVOLUTION_DIR based on specified logic, overriding default if found
184
- if [[ -n "$CLAUDE_EVOLVE_WORKING_DIR" ]]; then
185
- EVOLUTION_DIR="$CLAUDE_EVOLVE_WORKING_DIR"
186
- elif [[ -f "evolution/evolution.csv" ]]; then
187
- EVOLUTION_DIR="evolution"
188
- elif [[ -f "./evolution.csv" ]]; then
189
- EVOLUTION_DIR="."
190
- else
191
- fi
192
-
193
- TOTAL_IDEAS="$DEFAULT_TOTAL_IDEAS"
194
- NOVEL_EXPLORATION="$DEFAULT_NOVEL_EXPLORATION"
195
- HILL_CLIMBING="$DEFAULT_HILL_CLIMBING"
196
- STRUCTURAL_MUTATION="$DEFAULT_STRUCTURAL_MUTATION"
197
- CROSSOVER_HYBRID="$DEFAULT_CROSSOVER_HYBRID"
198
- NUM_ELITES="$DEFAULT_NUM_ELITES"
199
- NUM_REVOLUTION="$DEFAULT_NUM_REVOLUTION"
200
-
201
- PARALLEL_ENABLED="$DEFAULT_PARALLEL_ENABLED"
202
- MAX_WORKERS="$DEFAULT_MAX_WORKERS"
203
- LOCK_TIMEOUT="$DEFAULT_LOCK_TIMEOUT"
204
-
205
- AUTO_IDEATE="$DEFAULT_AUTO_IDEATE"
206
- MAX_RETRIES="$DEFAULT_MAX_RETRIES"
207
- MEMORY_LIMIT_MB="$DEFAULT_MEMORY_LIMIT_MB"
208
-
209
- LLM_CLI_gpt5high='codex exec --profile gpt5high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
210
- LLM_CLI_o3high='codex exec --profile o3high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
211
- LLM_CLI_codex='codex exec --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
212
- LLM_CLI_gemini='gemini -y -p "{{PROMPT}}"'
213
- LLM_CLI_gemini_flash='gemini -y -p "{{PROMPT}}" --model gemini-2.5-flash'
214
- LLM_CLI_opus='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "{{PROMPT}}"'
215
- LLM_CLI_opus_think='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "ultrathink\n\n{{PROMPT}}"'
216
- LLM_CLI_sonnet='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "{{PROMPT}}"'
217
- LLM_CLI_sonnet_think='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "ultrathink\n\n{{PROMPT}}"'
218
- LLM_CLI_cursor_sonnet='cursor-agent sonnet -p "{{PROMPT}}"'
219
- LLM_CLI_cursor_opus='cursor-agent opus -p "{{PROMPT}}"'
220
- LLM_CLI_glm='opencode -m openrouter/z-ai/glm-4.6 run "{{PROMPT}}"'
221
- LLM_CLI_deepseek='opencode -m openrouter/deepseek/deepseek-v3.1-terminus run "{{PROMPT}}"'
222
- LLM_CLI_ollama-cloud-gpt-oss='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model gpt-oss:20b-cloud "{{PROMPT}}"' LLM_CLI_ollama-cloud-kimi-k2='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model kimi-k2:1t-cloud "{{PROMPT}}"' LLM_RUN="$DEFAULT_LLM_RUN"
223
- LLM_IDEATE="$DEFAULT_LLM_IDEATE"
224
-
225
- # Determine local config file path relative to EVOLUTION_DIR
226
- local local_config_file="$EVOLUTION_DIR/config.yaml"
227
-
228
- # Load local config
229
- _load_yaml_config "$local_config_file"
230
-
231
- # Load global config (overrides local config)
232
- local global_config_file="$HOME/.config/claude-evolve/config.yaml"
233
- _load_yaml_config "$global_config_file"
234
-
235
-
236
- # Create full paths - ALL paths are relative to EVOLUTION_DIR
237
- # Make EVOLUTION_DIR absolute if it\'s relative
238
- if [[ "$EVOLUTION_DIR" = /* ]]; then
239
- FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
240
- else
241
- FULL_EVOLUTION_DIR="$(cd "$EVOLUTION_DIR" 2>/dev/null && pwd)" || FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
242
- fi
243
-
244
- FULL_ALGORITHM_PATH="$FULL_EVOLUTION_DIR/$ALGORITHM_FILE"
245
- FULL_EVALUATOR_PATH="$FULL_EVOLUTION_DIR/$EVALUATOR_FILE"
246
- FULL_BRIEF_PATH="$FULL_EVOLUTION_DIR/$BRIEF_FILE"
247
- FULL_CSV_PATH="$FULL_EVOLUTION_DIR/$EVOLUTION_CSV"
248
-
249
- if [[ -n $OUTPUT_DIR ]]; then
250
- FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR/$OUTPUT_DIR"
251
- else
252
- FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR"
253
- fi
254
- }
255
-
256
- # Validate configuration
257
- validate_config() {
258
- local errors=0
259
-
260
- if [[ ! -d "$FULL_EVOLUTION_DIR" ]]; then
261
- echo "[ERROR] Evolution directory not found: $FULL_EVOLUTION_DIR" >&2
262
- ((errors++))
263
- fi
264
-
265
- if [[ ! -f "$FULL_ALGORITHM_PATH" ]]; then
266
- echo "[ERROR] Algorithm file not found: $FULL_ALGORITHM_PATH" >&2
267
- ((errors++))
268
- fi
269
-
270
- if [[ ! -f "$FULL_EVALUATOR_PATH" ]]; then
271
- echo "[ERROR] Evaluator file not found: $FULL_EVALUATOR_PATH" >&2
272
- ((errors++))
273
- fi
274
-
275
- if [[ ! -f "$FULL_BRIEF_PATH" ]]; then
276
- echo "[ERROR] Brief file not found: $FULL_BRIEF_PATH" >&2
277
- ((errors++))
278
- fi
279
-
280
- if ! command -v "$PYTHON_CMD" >/dev/null 2>&1; then
281
- echo "[ERROR] Python command not found: $PYTHON_CMD" >&2
282
- echo "[ERROR] Please install Python 3.x or set python_cmd in config.yaml" >&2
283
- echo "[ERROR] Examples: python_cmd: \"python\" or python_cmd: \"C:\\Python39\\python.exe\"" >&2
284
- ((errors++))
285
- else
286
- # Verify Python version is 3.x
287
- if ! "$PYTHON_CMD" -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
288
- echo "[ERROR] Python 3.x required, but $PYTHON_CMD appears to be Python 2" >&2
289
- echo "[ERROR] Please set python_cmd in config.yaml to point to Python 3" >&2
290
- ((errors++))
291
- fi
292
- fi
293
-
294
- return $errors
295
- }
296
-
297
- # Show current configuration
298
- show_config() {
299
- echo "Current claude-evolve configuration:"
300
- echo " Evolution directory: $FULL_EVOLUTION_DIR"
301
- echo " Algorithm file: $FULL_ALGORITHM_PATH"
302
- echo " Evaluator file: $FULL_EVALUATOR_PATH"
303
- echo " Brief file: $FULL_BRIEF_PATH"
304
- echo " CSV file: $FULL_CSV_PATH"
305
- echo " Output directory: $FULL_OUTPUT_DIR"
306
- echo " Parent selection: $PARENT_SELECTION"
307
- echo " Python command: $PYTHON_CMD"
308
- echo " Parallel enabled: $PARALLEL_ENABLED"
309
- echo " Max workers: $MAX_WORKERS"
310
- echo " Lock timeout: $LOCK_TIMEOUT"
311
- echo " Auto ideate: $AUTO_IDEATE"
312
- echo " Max retries: $MAX_RETRIES"
313
- echo " Memory limit: ${MEMORY_LIMIT_MB}MB"
314
- echo " LLM configuration:"
315
- # Show LLM configurations using dynamic variable names
316
- for model in gpt5high o3high codex gemini opus opus_think sonnet sonnet_think cursor_sonnet cursor_opus glm deepseek; do
317
- var_name="LLM_CLI_${model}"
318
- var_value=$(eval echo "\$$var_name")
319
- if [[ -n "$var_value" ]]; then
320
- # Convert underscore back to dash for display
321
- display_name=$(echo "$model" | sed 's/_/-/g')
322
- echo " $display_name: $var_value"
323
- fi
324
- done
325
- echo " LLM for run: $LLM_RUN"
326
- echo " LLM for ideate: $LLM_IDEATE"
327
- }
@@ -1,327 +0,0 @@
1
- #!/bin/bash
2
- # Configuration loader for claude-evolve
3
-
4
- # Default configuration values
5
- DEFAULT_EVOLUTION_DIR="evolution"
6
- DEFAULT_ALGORITHM_FILE="algorithm.py"
7
- DEFAULT_EVALUATOR_FILE="evaluator.py"
8
- DEFAULT_BRIEF_FILE="BRIEF.md"
9
- DEFAULT_EVOLUTION_CSV="evolution.csv"
10
- DEFAULT_OUTPUT_DIR=""
11
- DEFAULT_PARENT_SELECTION="best"
12
- # Detect Python command based on platform
13
- detect_python_cmd() {
14
- # Try python3 first (macOS, Linux)
15
- if command -v python3 >/dev/null 2>&1; then
16
- echo "python3"
17
- # Try python (Windows, some Linux)
18
- elif command -v python >/dev/null 2>&1; then
19
- # Verify it's Python 3
20
- if python -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
21
- echo "python"
22
- else
23
- echo "python3" # Fallback
24
- fi
25
- else
26
- echo "python3" # Default fallback
27
- fi
28
- }
29
-
30
- DEFAULT_PYTHON_CMD="$(detect_python_cmd)"
31
-
32
- # Default ideation strategy values
33
- DEFAULT_TOTAL_IDEAS=15
34
- DEFAULT_NOVEL_EXPLORATION=3
35
- DEFAULT_HILL_CLIMBING=5
36
- DEFAULT_STRUCTURAL_MUTATION=3
37
- DEFAULT_CROSSOVER_HYBRID=4
38
- DEFAULT_NUM_ELITES=3
39
- DEFAULT_NUM_REVOLUTION=2 # Number of top novel candidates to include
40
-
41
- # Default parallel execution values
42
- DEFAULT_PARALLEL_ENABLED=false
43
- DEFAULT_MAX_WORKERS=4
44
- DEFAULT_LOCK_TIMEOUT=10
45
-
46
- # Default auto ideation value
47
- DEFAULT_AUTO_IDEATE=true
48
-
49
- # Default retry value
50
- DEFAULT_MAX_RETRIES=3
51
-
52
- # Default memory limit (in MB, 0 means no limit)
53
- # Set to reasonable limit for ML workloads - about half of available system RAM
54
- DEFAULT_MEMORY_LIMIT_MB=12288
55
-
56
- # Default LLM CLI configuration - use simple variables instead of arrays
57
- # Run: 100% local with qwen3 via Codex+Ollama (more reliable than aider)
58
- DEFAULT_LLM_RUN="codex-qwen3 codex-oss gemini-flash"
59
- # Ideate: Commercial models for idea generation + local fallback
60
- DEFAULT_LLM_IDEATE="gemini sonnet-think gpt5high glm grok-4 codex-qwen3 codex-oss"
61
-
62
- # Load configuration from a YAML file and update variables
63
- _load_yaml_config() {
64
- local config_file="$1"
65
- if [[ ! -f "$config_file" ]]; then
66
- return 0 # File does not exist, nothing to load
67
- fi
68
-
69
-
70
- local in_ideation_section=false
71
- local in_parallel_section=false
72
- local in_llm_cli_section=false
73
- local llm_cli_subsection=""
74
-
75
- while IFS='' read -r line; do
76
- [[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
77
-
78
- if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
79
- continue
80
- fi
81
- local key="${BASH_REMATCH[1]}"
82
- local value="${BASH_REMATCH[2]}"
83
-
84
- local is_indented=false
85
- [[ $key =~ ^[[:space:]]+ ]] && is_indented=true
86
-
87
- key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
88
- value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
89
-
90
- if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
91
- echo "[CONFIG DEBUG] Before comment removal: key='$key' value='$value'" >&2
92
- fi
93
-
94
- value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
95
- value=$(echo "$value" | sed 's/^"//;s/"$//')
96
-
97
- if [[ $key == "ideation_strategies" ]]; then
98
- in_ideation_section=true
99
- in_parallel_section=false
100
- in_llm_cli_section=false
101
- continue
102
- elif [[ $key == "parallel" ]]; then
103
- in_parallel_section=true
104
- in_ideation_section=false
105
- in_llm_cli_section=false
106
- continue
107
- elif [[ $key == "llm_cli" ]]; then
108
- in_llm_cli_section=true
109
- in_ideation_section=false
110
- in_parallel_section=false
111
- llm_cli_subsection=""
112
- continue
113
- elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true || $in_llm_cli_section == true ]]; then
114
- in_ideation_section=false
115
- in_parallel_section=false
116
- in_llm_cli_section=false
117
- llm_cli_subsection=""
118
- fi
119
-
120
- if [[ $in_ideation_section == true ]]; then
121
- case $key in
122
- total_ideas) TOTAL_IDEAS="$value" ;;
123
- novel_exploration) NOVEL_EXPLORATION="$value" ;;
124
- hill_climbing) HILL_CLIMBING="$value" ;;
125
- structural_mutation) STRUCTURAL_MUTATION="$value" ;;
126
- crossover_hybrid) CROSSOVER_HYBRID="$value" ;;
127
- num_elites) NUM_ELITES="$value" ;;
128
- num_revolution) NUM_REVOLUTION="$value" ;;
129
- esac
130
- elif [[ $in_parallel_section == true ]]; then
131
- case $key in
132
- enabled) PARALLEL_ENABLED="$value" ;;
133
- max_workers) MAX_WORKERS="$value" ;;
134
- lock_timeout) LOCK_TIMEOUT="$value" ;;
135
- esac
136
- elif [[ $in_llm_cli_section == true ]]; then
137
- if [[ $key == "run" || $key == "ideate" ]]; then
138
- case $key in
139
- run) LLM_RUN="$value" ;;
140
- ideate) LLM_IDEATE="$value" ;;
141
- esac
142
- else
143
- value=$(echo "$value" | sed "s/^'//;s/'$//")
144
- local var_key=$(echo "$key" | sed 's/-/_/g')
145
- if [[ "${DEBUG_CONFIG:-}" == "true" ]]; then
146
- echo "[CONFIG DEBUG] Setting LLM_CLI_${var_key} = '$value'" >&2
147
- fi
148
- eval "LLM_CLI_${var_key}=\"$value\""
149
- fi
150
- else
151
- case $key in
152
- algorithm_file) ALGORITHM_FILE="$value" ;;
153
- evaluator_file) EVALUATOR_FILE="$value" ;;
154
- brief_file) BRIEF_FILE="$value" ;;
155
- evolution_csv) EVOLUTION_CSV="$value" ;;
156
- output_dir) OUTPUT_DIR="$value" ;;
157
- parent_selection) PARENT_SELECTION="$value" ;;
158
- python_cmd) PYTHON_CMD="$value" ;;
159
- auto_ideate) AUTO_IDEATE="$value" ;;
160
- max_retries) MAX_RETRIES="$value" ;;
161
- memory_limit_mb) MEMORY_LIMIT_MB="$value" ;;
162
- evolution_dir):
163
- echo "[WARN] evolution_dir in config is ignored - automatically inferred from config file location" >&2
164
- ;;
165
- esac
166
- fi
167
- done < "$config_file"
168
- # Keep track of the last config file loaded to infer evolution_dir
169
- LAST_CONFIG_FILE_LOADED="$config_file"
170
- }
171
-
172
- load_config() {
173
- # Set defaults first
174
- EVOLUTION_DIR="$DEFAULT_EVOLUTION_DIR" # Initialize with default
175
- ALGORITHM_FILE="$DEFAULT_ALGORITHM_FILE"
176
- EVALUATOR_FILE="$DEFAULT_EVALUATOR_FILE"
177
- BRIEF_FILE="$DEFAULT_BRIEF_FILE"
178
- EVOLUTION_CSV="$DEFAULT_EVOLUTION_CSV"
179
- OUTPUT_DIR="$DEFAULT_OUTPUT_DIR"
180
- PARENT_SELECTION="$DEFAULT_PARENT_SELECTION"
181
- PYTHON_CMD="$DEFAULT_PYTHON_CMD"
182
-
183
- # Determine EVOLUTION_DIR based on specified logic, overriding default if found
184
- if [[ -n "$CLAUDE_EVOLVE_WORKING_DIR" ]]; then
185
- EVOLUTION_DIR="$CLAUDE_EVOLVE_WORKING_DIR"
186
- elif [[ -f "evolution/evolution.csv" ]]; then
187
- EVOLUTION_DIR="evolution"
188
- elif [[ -f "./evolution.csv" ]]; then
189
- EVOLUTION_DIR="."
190
- else
191
- fi
192
-
193
- TOTAL_IDEAS="$DEFAULT_TOTAL_IDEAS"
194
- NOVEL_EXPLORATION="$DEFAULT_NOVEL_EXPLORATION"
195
- HILL_CLIMBING="$DEFAULT_HILL_CLIMBING"
196
- STRUCTURAL_MUTATION="$DEFAULT_STRUCTURAL_MUTATION"
197
- CROSSOVER_HYBRID="$DEFAULT_CROSSOVER_HYBRID"
198
- NUM_ELITES="$DEFAULT_NUM_ELITES"
199
- NUM_REVOLUTION="$DEFAULT_NUM_REVOLUTION"
200
-
201
- PARALLEL_ENABLED="$DEFAULT_PARALLEL_ENABLED"
202
- MAX_WORKERS="$DEFAULT_MAX_WORKERS"
203
- LOCK_TIMEOUT="$DEFAULT_LOCK_TIMEOUT"
204
-
205
- AUTO_IDEATE="$DEFAULT_AUTO_IDEATE"
206
- MAX_RETRIES="$DEFAULT_MAX_RETRIES"
207
- MEMORY_LIMIT_MB="$DEFAULT_MEMORY_LIMIT_MB"
208
-
209
- LLM_CLI_gpt5high='codex exec --profile gpt5high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
210
- LLM_CLI_o3high='codex exec --profile o3high --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
211
- LLM_CLI_codex='codex exec --dangerously-bypass-approvals-and-sandbox "{{PROMPT}}"'
212
- LLM_CLI_gemini='gemini -y -p "{{PROMPT}}"'
213
- LLM_CLI_gemini_flash='gemini -y -p "{{PROMPT}}" --model gemini-2.5-flash'
214
- LLM_CLI_opus='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "{{PROMPT}}"'
215
- LLM_CLI_opus_think='claude --dangerously-skip-permissions --mcp-config "" --model opus -p "ultrathink\n\n{{PROMPT}}"'
216
- LLM_CLI_sonnet='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "{{PROMPT}}"'
217
- LLM_CLI_sonnet_think='claude --dangerously-skip-permissions --mcp-config "" --model sonnet -p "ultrathink\n\n{{PROMPT}}"'
218
- LLM_CLI_cursor_sonnet='cursor-agent sonnet -p "{{PROMPT}}"'
219
- LLM_CLI_cursor_opus='cursor-agent opus -p "{{PROMPT}}"'
220
- LLM_CLI_glm='opencode -m openrouter/z-ai/glm-4.6 run "{{PROMPT}}"'
221
- LLM_CLI_deepseek='opencode -m openrouter/deepseek/deepseek-v3.1-terminus run "{{PROMPT}}"'
222
- LLM_CLI_ollama-cloud-gpt-oss='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model gpt-oss:20b-cloud "{{PROMPT}}"' LLM_CLI_ollama-cloud-kimi-k2='codex exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --oss --model kimi-k2:1t-cloud "{{PROMPT}}"' LLM_RUN="$DEFAULT_LLM_RUN"
223
- LLM_IDEATE="$DEFAULT_LLM_IDEATE"
224
-
225
- # Determine local config file path relative to EVOLUTION_DIR
226
- local local_config_file="$EVOLUTION_DIR/config.yaml"
227
-
228
- # Load local config
229
- _load_yaml_config "$local_config_file"
230
-
231
- # Load global config (overrides local config)
232
- local global_config_file="$HOME/.config/claude-evolve/config.yaml"
233
- _load_yaml_config "$global_config_file"
234
-
235
-
236
- # Create full paths - ALL paths are relative to EVOLUTION_DIR
237
- # Make EVOLUTION_DIR absolute if it\'s relative
238
- if [[ "$EVOLUTION_DIR" = /* ]]; then
239
- FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
240
- else
241
- FULL_EVOLUTION_DIR="$(cd "$EVOLUTION_DIR" 2>/dev/null && pwd)" || FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
242
- fi
243
-
244
- FULL_ALGORITHM_PATH="$FULL_EVOLUTION_DIR/$ALGORITHM_FILE"
245
- FULL_EVALUATOR_PATH="$FULL_EVOLUTION_DIR/$EVALUATOR_FILE"
246
- FULL_BRIEF_PATH="$FULL_EVOLUTION_DIR/$BRIEF_FILE"
247
- FULL_CSV_PATH="$FULL_EVOLUTION_DIR/$EVOLUTION_CSV"
248
-
249
- if [[ -n $OUTPUT_DIR ]]; then
250
- FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR/$OUTPUT_DIR"
251
- else
252
- FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR"
253
- fi
254
- }
255
-
256
- # Validate configuration
257
- validate_config() {
258
- local errors=0
259
-
260
- if [[ ! -d "$FULL_EVOLUTION_DIR" ]]; then
261
- echo "[ERROR] Evolution directory not found: $FULL_EVOLUTION_DIR" >&2
262
- ((errors++))
263
- fi
264
-
265
- if [[ ! -f "$FULL_ALGORITHM_PATH" ]]; then
266
- echo "[ERROR] Algorithm file not found: $FULL_ALGORITHM_PATH" >&2
267
- ((errors++))
268
- fi
269
-
270
- if [[ ! -f "$FULL_EVALUATOR_PATH" ]]; then
271
- echo "[ERROR] Evaluator file not found: $FULL_EVALUATOR_PATH" >&2
272
- ((errors++))
273
- fi
274
-
275
- if [[ ! -f "$FULL_BRIEF_PATH" ]]; then
276
- echo "[ERROR] Brief file not found: $FULL_BRIEF_PATH" >&2
277
- ((errors++))
278
- fi
279
-
280
- if ! command -v "$PYTHON_CMD" >/dev/null 2>&1; then
281
- echo "[ERROR] Python command not found: $PYTHON_CMD" >&2
282
- echo "[ERROR] Please install Python 3.x or set python_cmd in config.yaml" >&2
283
- echo "[ERROR] Examples: python_cmd: \"python\" or python_cmd: \"C:\\Python39\\python.exe\"" >&2
284
- ((errors++))
285
- else
286
- # Verify Python version is 3.x
287
- if ! "$PYTHON_CMD" -c "import sys; sys.exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then
288
- echo "[ERROR] Python 3.x required, but $PYTHON_CMD appears to be Python 2" >&2
289
- echo "[ERROR] Please set python_cmd in config.yaml to point to Python 3" >&2
290
- ((errors++))
291
- fi
292
- fi
293
-
294
- return $errors
295
- }
296
-
297
- # Show current configuration
298
- show_config() {
299
- echo "Current claude-evolve configuration:"
300
- echo " Evolution directory: $FULL_EVOLUTION_DIR"
301
- echo " Algorithm file: $FULL_ALGORITHM_PATH"
302
- echo " Evaluator file: $FULL_EVALUATOR_PATH"
303
- echo " Brief file: $FULL_BRIEF_PATH"
304
- echo " CSV file: $FULL_CSV_PATH"
305
- echo " Output directory: $FULL_OUTPUT_DIR"
306
- echo " Parent selection: $PARENT_SELECTION"
307
- echo " Python command: $PYTHON_CMD"
308
- echo " Parallel enabled: $PARALLEL_ENABLED"
309
- echo " Max workers: $MAX_WORKERS"
310
- echo " Lock timeout: $LOCK_TIMEOUT"
311
- echo " Auto ideate: $AUTO_IDEATE"
312
- echo " Max retries: $MAX_RETRIES"
313
- echo " Memory limit: ${MEMORY_LIMIT_MB}MB"
314
- echo " LLM configuration:"
315
- # Show LLM configurations using dynamic variable names
316
- for model in gpt5high o3high codex gemini opus opus_think sonnet sonnet_think cursor_sonnet cursor_opus glm deepseek; do
317
- var_name="LLM_CLI_${model}"
318
- var_value=$(eval echo "\$$var_name")
319
- if [[ -n "$var_value" ]]; then
320
- # Convert underscore back to dash for display
321
- display_name=$(echo "$model" | sed 's/_/-/g')
322
- echo " $display_name: $var_value"
323
- fi
324
- done
325
- echo " LLM for run: $LLM_RUN"
326
- echo " LLM for ideate: $LLM_IDEATE"
327
- }