claude-evolve 1.3.14 → 1.3.16

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.
package/README.md CHANGED
@@ -12,7 +12,7 @@ Think of it like **genetic algorithms for code** - it handles the mutations and
12
12
 
13
13
  The system operates with specialized phases working together:
14
14
 
15
- - 🧠 **Ideation Phase**: Generates creative algorithm variations using Claude Opus
15
+ - 🧠 **Ideation Phase**: Generates creative algorithm variations using codex o3-pro (if available) or Claude Opus
16
16
  - 🔬 **Development Phase**: Implements mutations using Claude Sonnet (with periodic Opus "megathinking")
17
17
  - 📊 **Evaluation Phase**: Tests performance against your custom evaluator
18
18
  - 📈 **Analysis Phase**: Tracks evolution progress and identifies top performers
@@ -180,6 +180,7 @@ Evolution experiments can fail for various reasons. The system tracks these fail
180
180
  - [Claude CLI](https://docs.anthropic.com/en/docs/claude-code) (`claude` command)
181
181
 
182
182
  ### Optional (but recommended)
183
+ - [Codex CLI](https://github.com/aboutgaurav/codex) (`codex` command) - Uses o3-pro model for superior ideation when available
183
184
  - Scientific Python libraries (numpy, scipy, etc.) depending on your algorithms
184
185
  - Plotting libraries (matplotlib, plotly) for analyzing results
185
186
 
@@ -292,16 +292,18 @@ if command -v gnuplot >/dev/null 2>&1 && [[ $valid_performance_count -gt 0 ]]; t
292
292
  echo "# Row ID Performance Generation" >"$data_file"
293
293
  echo "# Generation AvgPerformance Color" >"$gen_avg_file"
294
294
 
295
- # Get color by generation number (rotates through 5 colors)
295
+ # Get color by generation number (rotates through 7 colors)
296
296
  get_gen_color() {
297
297
  local gen_num="$1"
298
- local color_index=$(( (gen_num - 1) % 5 + 1 ))
298
+ local color_index=$(( gen_num % 7 ))
299
299
  case $color_index in
300
- 1) echo "#1f77b4" ;; # blue
301
- 2) echo "#ff7f0e" ;; # orange
302
- 3) echo "#2ca02c" ;; # green
303
- 4) echo "#d62728" ;; # red
304
- 5) echo "#9467bd" ;; # purple
300
+ 0) echo "#1f77b4" ;; # blue
301
+ 1) echo "#ff7f0e" ;; # orange
302
+ 2) echo "#2ca02c" ;; # green
303
+ 3) echo "#d62728" ;; # red
304
+ 4) echo "#9467bd" ;; # purple
305
+ 5) echo "#8c564b" ;; # brown
306
+ 6) echo "#e377c2" ;; # pink
305
307
  esac
306
308
  }
307
309
 
@@ -314,76 +316,101 @@ if command -v gnuplot >/dev/null 2>&1 && [[ $valid_performance_count -gt 0 ]]; t
314
316
  max_row=0
315
317
  max_id=""
316
318
 
317
- # Use Python to generate chart data and capture output
318
- python_output=$("$PYTHON_CMD" -c "
319
+ # Use Python to generate chart data
320
+ "$PYTHON_CMD" -c "
319
321
  import csv
320
322
  import re
321
323
 
322
- row_num = 0
323
- max_perf = 0
324
- max_row = 0
325
- max_id = ''
326
-
327
324
  with open('$csv_file', 'r') as f:
328
325
  reader = csv.reader(f)
329
326
  next(reader) # Skip header
330
327
 
331
- data_lines = []
332
- gen_temp_lines = []
328
+ completed_order = 0 # Track order of completion
329
+
330
+ with open('$data_file', 'w') as data_f:
331
+ data_f.write('# Order ID Performance Generation\\n')
332
+
333
+ with open('$gen_data_temp', 'w') as gen_f:
334
+ pass # Clear file
335
+
336
+ max_perf = 0
337
+ max_id = ''
338
+ max_order = 0
333
339
 
334
340
  for row in reader:
335
341
  if len(row) < 5:
336
342
  continue
337
343
 
338
- row_num += 1
339
344
  id, _, desc, perf, status = row[:5]
340
345
 
341
346
  # Extract generation from ID
342
347
  gen = 'gen01' # default
343
- match = re.match(r'^(gen[0-9]+)-', id)
348
+ gen_num = 1
349
+ match = re.match(r'^gen([0-9]+)-', id)
344
350
  if match:
345
- gen = match.group(1)
351
+ gen = f'gen{match.group(1)}'
352
+ gen_num = int(match.group(1))
346
353
 
347
354
  # Only include completed algorithms with non-zero performance
348
355
  if perf and perf != '' and status in ['complete', 'completed']:
349
356
  try:
350
357
  perf_val = float(perf)
351
358
  if perf_val > 0:
352
- # Assign generation number for coloring (1-based)
353
- gen_num = 1
354
- match = re.match(r'^gen([0-9]+)-', id)
355
- if match:
356
- gen_num = int(match.group(1))
359
+ completed_order += 1
360
+
361
+ # Write to data file
362
+ with open('$data_file', 'a') as f:
363
+ f.write(f'{completed_order} \"{id}\" {perf} {gen_num}\\n')
357
364
 
358
- data_lines.append(f'{row_num} \\\"{id}\\\" {perf} {gen_num}')
359
- gen_temp_lines.append(f'{gen} {perf}')
365
+ # Write to gen temp file
366
+ with open('$gen_data_temp', 'a') as f:
367
+ f.write(f'{gen} {perf}\\n')
360
368
 
361
369
  # Track the winner
362
370
  if perf_val > max_perf:
363
371
  max_perf = perf_val
364
- max_row = row_num
372
+ max_order = completed_order
365
373
  max_id = id
366
374
  except ValueError:
367
375
  pass
368
376
 
369
- # Write data file
370
- with open('$data_file', 'a') as f:
371
- for line in data_lines:
372
- f.write(line + '\\\\n')
373
-
374
- # Write gen temp file
375
- with open('$gen_data_temp', 'a') as f:
376
- for line in gen_temp_lines:
377
- f.write(line + '\\\\n')
378
-
379
377
  # Output max values for shell
380
378
  print(f'max_perf={max_perf}')
381
- print(f'max_row={max_row}')
382
- print(f'max_id=\\\"{max_id}\\\"')
383
- ")
379
+ print(f'max_row={max_order}')
380
+ print(f'max_id=\"{max_id}\"')
381
+ "
384
382
 
385
- # Evaluate the Python output
386
- eval "$python_output"
383
+ # Capture the output properly
384
+ eval "$("$PYTHON_CMD" -c "
385
+ import csv
386
+ import re
387
+
388
+ with open('$csv_file', 'r') as f:
389
+ reader = csv.reader(f)
390
+ next(reader)
391
+
392
+ max_perf = 0
393
+ max_id = ''
394
+ max_order = 0
395
+ completed_order = 0
396
+
397
+ for row in reader:
398
+ if len(row) >= 5 and row[3] and row[4] in ['complete', 'completed']:
399
+ try:
400
+ perf_val = float(row[3])
401
+ if perf_val > 0:
402
+ completed_order += 1
403
+ if perf_val > max_perf:
404
+ max_perf = perf_val
405
+ max_order = completed_order
406
+ max_id = row[0]
407
+ except ValueError:
408
+ pass
409
+
410
+ print(f'max_perf={max_perf}')
411
+ print(f'max_row={max_order}')
412
+ print(f'max_id=\"{max_id}\"')
413
+ ")"
387
414
 
388
415
  # Create generation averages file and track max generation
389
416
  gen_index=1
@@ -397,11 +424,11 @@ print(f'max_id=\\\"{max_id}\\\"')
397
424
  avg=$(echo "scale=4; $sum / $count" | bc -l 2>/dev/null || echo "0")
398
425
  gen_num=$(echo "$gen" | sed 's/gen0*//')
399
426
  # Track max generation number
400
- if [[ $gen_num -gt $max_gen_num ]]; then
427
+ if [[ $gen_num =~ ^[0-9]+$ ]] && [[ $gen_num -gt $max_gen_num ]]; then
401
428
  max_gen_num=$gen_num
402
429
  fi
403
430
  color=$(get_gen_color "$gen_num")
404
- echo "$gen_index \"$gen\" $avg \"$color\"" >>"$gen_avg_file"
431
+ echo "$gen_index \"Gen$gen_num\" $avg \"$color\"" >>"$gen_avg_file"
405
432
  ((gen_index++))
406
433
  fi
407
434
  fi
@@ -417,26 +444,58 @@ print(f'max_id=\\\"{max_id}\\\"')
417
444
 
418
445
  # Generate dual plot
419
446
  if [[ -s "$data_file" ]]; then
420
- # Build dynamic plot command for generations
447
+ # Debug: show data file content
448
+ # echo "DEBUG: Data file content:"
449
+ # cat "$data_file"
450
+ # echo "DEBUG: max_gen_num=$max_gen_num"
451
+
452
+ # Plot all algorithms in order of completion, colored by generation
421
453
  plot_cmd=""
422
- for ((i=1; i<=max_gen_num; i++)); do
423
- color=$(get_gen_color "$i")
424
- if [[ -n $plot_cmd ]]; then
425
- plot_cmd="$plot_cmd, \\"$'\n'
454
+ gen_plots_added=0
455
+
456
+ # Find all generations that have data
457
+ generations=($(awk '{if(NR>1) print $4}' "$data_file" | sort -n | uniq))
458
+
459
+ for gen_num in "${generations[@]}"; do
460
+ if [[ -n $gen_num ]]; then
461
+ color=$(get_gen_color "$gen_num")
462
+ if [[ $gen_plots_added -gt 0 ]]; then
463
+ plot_cmd="$plot_cmd, \\"$'\n'
464
+ fi
465
+ plot_cmd="${plot_cmd} \"$data_file\" using (\$4==$gen_num?\$1:1/0):3 with linespoints linewidth 2 linecolor rgb \"$color\" pointsize 1.2 title \"Gen $gen_num\""
466
+ ((gen_plots_added++))
426
467
  fi
427
- plot_cmd="${plot_cmd} \"$data_file\" using (\$4==$i?\$1:1/0):3 with linespoints linewidth 2 linecolor rgb \"$color\" pointsize 0.8 title \"Gen $i\""
428
468
  done
469
+
429
470
  # Add winner point
430
- plot_cmd="$plot_cmd, \\"$'\n'
431
- plot_cmd="${plot_cmd} \"$winner_file\" using 1:3 with points pointtype 7 pointsize 2 linecolor rgb \"#0066cc\" title \"Winner\""
471
+ if [[ -n $max_id && -s "$winner_file" ]]; then
472
+ if [[ $gen_plots_added -gt 0 ]]; then
473
+ plot_cmd="$plot_cmd, \\"$'\n'
474
+ fi
475
+ plot_cmd="${plot_cmd} \"$winner_file\" using 1:3 with points pointtype 7 pointsize 3 linecolor rgb \"gold\" title \"Best ($max_id)\""
476
+ fi
432
477
 
433
- # Build x-axis labels for generation chart
478
+ # Fallback if no generation-specific plots
479
+ if [[ $gen_plots_added -eq 0 ]]; then
480
+ plot_cmd="\"$data_file\" using 1:3 with linespoints linewidth 2 linecolor rgb \"#1f77b4\" pointsize 1.2 title \"Evolution Progress\""
481
+ if [[ -n $max_id && -s "$winner_file" ]]; then
482
+ plot_cmd="$plot_cmd, \\"$'\n'
483
+ plot_cmd="${plot_cmd} \"$winner_file\" using 1:3 with points pointtype 7 pointsize 3 linecolor rgb \"gold\" title \"Best ($max_id)\""
484
+ fi
485
+ fi
486
+
487
+ # Build x-axis labels for generation chart (include all generations from data)
434
488
  xtics_labels=""
435
- for ((i=1; i<=max_gen_num; i++)); do
436
- if [[ -n $xtics_labels ]]; then
437
- xtics_labels="$xtics_labels, "
489
+ label_index=1
490
+ for gen in $(cut -d' ' -f1 "$gen_data_temp" | sort -u); do
491
+ if [[ -n $gen ]]; then
492
+ gen_display=$(echo "$gen" | sed 's/gen0*//')
493
+ if [[ -n $xtics_labels ]]; then
494
+ xtics_labels="$xtics_labels, "
495
+ fi
496
+ xtics_labels="${xtics_labels}\"Gen$gen_display\" $label_index"
497
+ ((label_index++))
438
498
  fi
439
- xtics_labels="${xtics_labels}\"Gen$i\" $i"
440
499
  done
441
500
 
442
501
  gnuplot <<EOF
@@ -448,11 +507,12 @@ set multiplot layout 2,1 margins 0.08,0.82,0.15,0.95 spacing 0.1,0.15
448
507
 
449
508
  #=================== TOP PLOT: Performance Over Time ===================
450
509
  set title "Algorithm Evolution Performance Over Time" font ",14"
451
- set xlabel "Evolution Run"
510
+ set xlabel "Completion Order (Algorithm #)"
452
511
  set ylabel "Performance Score"
453
512
  set grid
454
513
  set key outside right
455
- set xtics auto
514
+ set xtics 1
515
+ set autoscale y
456
516
 
457
517
  # Define colors for generations
458
518
  plot $plot_cmd
@@ -14,14 +14,34 @@ else
14
14
  load_config
15
15
  fi
16
16
 
17
- # Helper function to call Claude with usage limit detection
18
- call_claude_with_limit_check() {
17
+ # Helper function to call AI model (codex o3-pro if available, else Claude)
18
+ call_ai_with_limit_check() {
19
19
  local prompt="$1"
20
- local model="${2:-opus}"
20
+ local fallback_model="${2:-opus}"
21
+
22
+ # Check if codex is available
23
+ if command -v codex >/dev/null 2>&1; then
24
+ echo "[INFO] Using codex o3-pro for ideation (smartest available model)" >&2
25
+
26
+ # Call codex with o3-pro model
27
+ local ai_output
28
+ ai_output=$(echo "$prompt" | codex -m o3-pro 2>&1)
29
+ local ai_exit_code=$?
30
+
31
+ if [[ $ai_exit_code -eq 0 ]]; then
32
+ echo "$ai_output"
33
+ return 0
34
+ else
35
+ echo "[WARN] Codex failed, falling back to Claude" >&2
36
+ fi
37
+ fi
38
+
39
+ # Fall back to Claude
40
+ echo "[INFO] Using Claude $fallback_model for ideation" >&2
21
41
 
22
42
  # Call Claude and capture output
23
43
  local claude_output
24
- claude_output=$(echo "$prompt" | claude --dangerously-skip-permissions --model "$model" -p 2>&1)
44
+ claude_output=$(echo "$prompt" | claude --dangerously-skip-permissions --model "$fallback_model" -p 2>&1)
25
45
  local claude_exit_code=$?
26
46
 
27
47
  # Check for usage limit
@@ -51,6 +71,11 @@ call_claude_with_limit_check() {
51
71
  return $claude_exit_code
52
72
  }
53
73
 
74
+ # Backward compatibility alias
75
+ call_claude_with_limit_check() {
76
+ call_ai_with_limit_check "$@"
77
+ }
78
+
54
79
  # Parse arguments
55
80
  use_strategies=true
56
81
  no_ai=false
@@ -253,9 +278,9 @@ ideate_manual() {
253
278
 
254
279
  # Generate ideas using AI with multi-strategy approach
255
280
  ideate_ai_strategies() {
256
- # Check for claude CLI
257
- if ! command -v claude >/dev/null 2>&1; then
258
- echo "[WARN] Claude CLI not found. Falling back to manual entry."
281
+ # Check for AI CLI (codex or claude)
282
+ if ! command -v codex >/dev/null 2>&1 && ! command -v claude >/dev/null 2>&1; then
283
+ echo "[WARN] No AI CLI found (codex or claude). Falling back to manual entry."
259
284
  return 1
260
285
  fi
261
286
 
@@ -329,9 +354,9 @@ Example descriptions:
329
354
 
330
355
  Add exactly $count rows to the CSV file now."
331
356
 
332
- echo "[INFO] Calling Claude Opus to generate $count novel exploration ideas..."
333
- if ! call_claude_with_limit_check "$prompt" "opus"; then
334
- echo "[WARN] Claude failed to generate novel ideas" >&2
357
+ echo "[INFO] Generating $count novel exploration ideas..."
358
+ if ! call_ai_with_limit_check "$prompt" "opus"; then
359
+ echo "[WARN] AI failed to generate novel ideas" >&2
335
360
  return 1
336
361
  fi
337
362
  echo "[INFO] Novel exploration ideas generated"
@@ -382,9 +407,9 @@ Example descriptions:
382
407
 
383
408
  Add exactly $count parameter tuning rows to the CSV file now."
384
409
 
385
- echo "[INFO] Calling Claude Opus to generate $count hill climbing ideas..."
386
- if ! call_claude_with_limit_check "$prompt" "opus"; then
387
- echo "[WARN] Claude failed to generate hill climbing ideas" >&2
410
+ echo "[INFO] Generating $count hill climbing ideas..."
411
+ if ! call_ai_with_limit_check "$prompt" "opus"; then
412
+ echo "[WARN] AI failed to generate hill climbing ideas" >&2
388
413
  return 1
389
414
  fi
390
415
  echo "[INFO] Hill climbing ideas generated"
@@ -435,9 +460,9 @@ Example descriptions:
435
460
 
436
461
  Add exactly $count structural modification rows to the CSV file now."
437
462
 
438
- echo "[INFO] Calling Claude Opus to generate $count structural mutation ideas..."
439
- if ! call_claude_with_limit_check "$prompt" "opus"; then
440
- echo "[WARN] Claude failed to generate structural mutation ideas" >&2
463
+ echo "[INFO] Generating $count structural mutation ideas..."
464
+ if ! call_ai_with_limit_check "$prompt" "opus"; then
465
+ echo "[WARN] AI failed to generate structural mutation ideas" >&2
441
466
  return 1
442
467
  fi
443
468
  echo "[INFO] Structural mutation ideas generated"
@@ -488,9 +513,9 @@ Example descriptions:
488
513
 
489
514
  Add exactly $count hybrid combination rows to the CSV file now."
490
515
 
491
- echo "[INFO] Calling Claude Opus to generate $count crossover hybrid ideas..."
492
- if ! call_claude_with_limit_check "$prompt" "opus"; then
493
- echo "[WARN] Claude failed to generate crossover ideas" >&2
516
+ echo "[INFO] Generating $count crossover hybrid ideas..."
517
+ if ! call_ai_with_limit_check "$prompt" "opus"; then
518
+ echo "[WARN] AI failed to generate crossover ideas" >&2
494
519
  return 1
495
520
  fi
496
521
  echo "[INFO] Crossover hybrid ideas generated"
@@ -498,9 +523,9 @@ Add exactly $count hybrid combination rows to the CSV file now."
498
523
 
499
524
  # Legacy AI generation mode (for backward compatibility)
500
525
  ideate_ai_legacy() {
501
- # Check for claude CLI
502
- if ! command -v claude >/dev/null 2>&1; then
503
- echo "[WARN] Claude CLI not found. Falling back to manual entry."
526
+ # Check for AI CLI (codex or claude)
527
+ if ! command -v codex >/dev/null 2>&1 && ! command -v claude >/dev/null 2>&1; then
528
+ echo "[WARN] No AI CLI found (codex or claude). Falling back to manual entry."
504
529
  return 1
505
530
  fi
506
531
 
@@ -553,9 +578,9 @@ Requirements for new CSV rows:
553
578
 
554
579
  Add exactly $TOTAL_IDEAS algorithm variation rows to the CSV file now."
555
580
 
556
- echo "[INFO] Calling Claude Opus to generate $TOTAL_IDEAS ideas (legacy mode)..."
557
- if ! call_claude_with_limit_check "$prompt" "opus"; then
558
- echo "[WARN] Claude failed to generate ideas" >&2
581
+ echo "[INFO] Generating $TOTAL_IDEAS ideas (legacy mode)..."
582
+ if ! call_ai_with_limit_check "$prompt" "opus"; then
583
+ echo "[WARN] AI failed to generate ideas" >&2
559
584
  return 1
560
585
  fi
561
586
  echo "[INFO] Legacy ideas generated"
@@ -71,7 +71,10 @@ reader = csv.reader(sys.stdin)
71
71
  next(reader) # Skip header
72
72
  count = 0
73
73
  for row in reader:
74
- if len(row) >= 5 and (row[4] == 'pending' or row[4] == ''):
74
+ # If row has fewer than 5 fields, treat as pending
75
+ if len(row) < 5:
76
+ count += 1
77
+ elif len(row) >= 5 and (row[4] == 'pending' or row[4] == ''):
75
78
  count += 1
76
79
  print(count)
77
80
  "
package/lib/csv-lock.sh CHANGED
@@ -162,7 +162,15 @@ with open('$csv_file', 'r') as f:
162
162
  # Find first pending candidate
163
163
  candidate_id = None
164
164
  for i in range(1, len(rows)):
165
- if len(rows[i]) >= 5 and (rows[i][4] == 'pending' or rows[i][4] == ''):
165
+ # If row has fewer than 5 fields, it's pending
166
+ if len(rows[i]) < 5:
167
+ candidate_id = rows[i][0]
168
+ # Ensure row has 5 fields before setting status
169
+ while len(rows[i]) < 5:
170
+ rows[i].append('')
171
+ rows[i][4] = 'running' # Update status
172
+ break
173
+ elif len(rows[i]) >= 5 and (rows[i][4] == 'pending' or rows[i][4] == ''):
166
174
  candidate_id = rows[i][0]
167
175
  rows[i][4] = 'running' # Update status
168
176
  break
package/lib/csv_helper.py CHANGED
@@ -12,7 +12,11 @@ def find_pending_row(csv_path):
12
12
  reader = csv.reader(f)
13
13
  next(reader) # Skip header
14
14
  for row_num, row in enumerate(reader, start=2):
15
- # Ensure row has at least 5 fields
15
+ # If row has fewer than 5 fields, it's pending
16
+ if len(row) < 5:
17
+ return row_num
18
+
19
+ # Ensure row has at least 5 fields for status check
16
20
  while len(row) < 5:
17
21
  row.append('')
18
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.3.14",
3
+ "version": "1.3.16",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",