Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/EvoMap/evolver/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Evolver prevents autonomous agents from overwriting core evolver code and critical workspace files to avoid cascading failures. Location: src/gep/solidify.js:493-535

Why Self-Modification is Dangerous

When an evolver modifies its own source code, it can introduce bugs into:
  1. Prompt generation (src/gep/prompt.js) → malformed prompts → agent confusion
  2. Validation logic (src/gep/solidify.js) → broken safety checks → dangerous evolutions approved
  3. Selector logic (src/gep/selector.js) → wrong genes selected → unintended changes
  4. Rollback logic (src/gep/solidify.js) → failed rollback → data loss
Cascading failure scenario: Location: SKILL.md:65

Protected Skill Directories

These skill directories cannot be modified by default:
// src/gep/solidify.js:493-504
const CRITICAL_PROTECTED_PREFIXES = [
  'skills/feishu-evolver-wrapper/',
  'skills/feishu-common/',
  'skills/feishu-post/',
  'skills/feishu-card/',
  'skills/feishu-doc/',
  'skills/skill-tools/',
  'skills/clawhub/',
  'skills/clawhub-batch-undelete/',
  'skills/git-sync/',
  'skills/evolver/',  // Core evolver
];
Rationale:
  • skills/evolver/: Core evolution engine
  • skills/feishu-evolver-wrapper/: Platform integration layer
  • skills/feishu-common/: Shared Feishu utilities
  • skills/git-sync/: Critical workspace sync
  • skills/clawhub/: Package management
  • skills/skill-tools/: Skill infrastructure
Destroying any of these will crash the entire system.

Protected Workspace Files

These files at the workspace root cannot be modified:
// src/gep/solidify.js:507-520
const CRITICAL_PROTECTED_FILES = [
  'MEMORY.md',           // Agent's long-term memory
  'SOUL.md',             // Agent's personality definition
  'IDENTITY.md',         // Agent identity
  'AGENTS.md',           // Multi-agent coordination
  'USER.md',             // User preferences
  'HEARTBEAT.md',        // Health monitoring
  'RECENT_EVENTS.md',    // Event log
  'TOOLS.md',            // Tool registry
  'TROUBLESHOOTING.md',  // Debugging guide
  'openclaw.json',       // Agent config
  '.env',                // Environment secrets
  'package.json',        // Dependencies
];
Why these are critical:
  • MEMORY.md: Deleting this causes memory loss
  • .env: Contains secrets (API keys, tokens)
  • openclaw.json: Agent configuration; corruption breaks startup
  • package.json: Dependency definitions; corruption breaks npm

Enforcement

During solidify, all changed files are checked against protected paths:
// src/gep/solidify.js:306-319
for (const f of blast.all_changed_files || blast.changed_files || []) {
  if (isCriticalProtectedPath(f)) {
    var norm = normalizeRelPath(f);
    if (allowSelfModify && norm.startsWith('skills/evolver/') && gene && gene.category === 'repair') {
      // Self-modify opt-in: allow repair-only changes to evolver when explicitly enabled
      warnings.push('self_modify_evolver_repair: ' + norm + ' (EVOLVE_ALLOW_SELF_MODIFY=true)');
    } else {
      violations.push('critical_path_modified: ' + norm);
    }
  }
}
Result: If violations are found, solidify fails and rollback is triggered.

isCriticalProtectedPath

Implementation:
// src/gep/solidify.js:522-535
function isCriticalProtectedPath(relPath) {
  const rel = normalizeRelPath(relPath);
  if (!rel) return false;
  
  // Check protected prefixes (skill directories)
  for (const prefix of CRITICAL_PROTECTED_PREFIXES) {
    const p = prefix.replace(/\/+$/, '');
    if (rel === p || rel.startsWith(p + '/')) return true;
  }
  
  // Check protected root files
  for (const f of CRITICAL_PROTECTED_FILES) {
    if (rel === f) return true;
  }
  
  return false;
}
Examples:
isCriticalProtectedPath('skills/evolver/src/evolve.js')  // true
isCriticalProtectedPath('skills/evolver/')               // true
isCriticalProtectedPath('MEMORY.md')                     // true
isCriticalProtectedPath('.env')                          // true
isCriticalProtectedPath('src/custom/code.js')            // false
isCriticalProtectedPath('skills/my-skill/index.js')      // false

EVOLVE_ALLOW_SELF_MODIFY

NOT recommended for production. Only enable for controlled experiments.

When enabled

EVOLVE_ALLOW_SELF_MODIFY=true
Evolver can modify skills/evolver/ for repair genes only:
if (allowSelfModify && norm.startsWith('skills/evolver/') && gene && gene.category === 'repair') {
  warnings.push('self_modify_evolver_repair: ' + norm + ' (EVOLVE_ALLOW_SELF_MODIFY=true)');
} else {
  violations.push('critical_path_modified: ' + norm);
}
Location: src/gep/solidify.js:308-315

Constraints

  • Only repair genes: Innovate/optimize genes still blocked
  • Warning logged: Every self-modification is logged for audit
  • Still requires validation: Gene validation commands must pass

Destructive Change Detection

Evolver detects when critical files are deleted or emptied:
// src/gep/solidify.js:537-567
function detectDestructiveChanges({ repoRoot, changedFiles, baselineUntracked }) {
  const violations = [];
  const baselineSet = new Set((Array.isArray(baselineUntracked) ? baselineUntracked : []).map(normalizeRelPath));

  for (const rel of changedFiles) {
    const norm = normalizeRelPath(rel);
    if (!norm) continue;
    if (!isCriticalProtectedPath(norm)) continue;

    const abs = path.join(repoRoot, norm);
    
    // If a critical file existed before but is now missing/empty, that is destructive.
    if (!baselineSet.has(norm)) {
      if (!fs.existsSync(abs)) {
        violations.push(`CRITICAL_FILE_DELETED: ${norm}`);
      } else {
        const stat = fs.statSync(abs);
        if (stat.isFile() && stat.size === 0) {
          violations.push(`CRITICAL_FILE_EMPTIED: ${norm}`);
        }
      }
    }
  }
  return violations;
}
Example violations:
CRITICAL_FILE_DELETED: MEMORY.md
CRITICAL_FILE_EMPTIED: openclaw.json
CRITICAL_FILE_DELETED: skills/evolver/src/evolve.js
Location: src/gep/solidify.js:1077-1088

Rollback Protection

During rollback, evolver never deletes files inside protected directories:
// src/gep/solidify.js:700-723
for (const rel of toDelete) {
  const safeRel = String(rel || '').replace(/\\/g, '/').replace(/^\.\//+/, '');
  if (!safeRel) continue;
  
  // CRITICAL: Never delete files inside protected skill directories during rollback.
  if (isCriticalProtectedPath(safeRel)) {
    skipped.push(safeRel);
    continue;
  }
  
  // Delete file
  fs.unlinkSync(abs);
  deleted.push(safeRel);
}

if (skipped.length > 0) {
  console.log(`[Rollback] Skipped ${skipped.length} critical protected file(s): ${skipped.slice(0, 5).join(', ')}`);
}
Rationale: Even if an evolution accidentally creates a file inside skills/evolver/, rollback should not delete it (could be a pre-existing backup).

Empty Directory Cleanup

After rollback, evolver removes empty directories to prevent ghost skill directories:
// src/gep/solidify.js:724-756
var dirsToCheck = new Set();
for (var di = 0; di < deleted.length; di++) {
  var dir = path.dirname(deleted[di]);
  while (dir && dir !== '.' && dir !== '/') {
    var normalized = dir.replace(/\\/g, '/');
    if (!normalized.includes('/')) break;
    dirsToCheck.add(dir);
    dir = path.dirname(dir);
  }
}

// Sort deepest first to ensure children are removed before parents
var sortedDirs = Array.from(dirsToCheck).sort(function (a, b) { return b.length - a.length; });
var removedDirs = [];
for (var si = 0; si < sortedDirs.length; si++) {
  if (isCriticalProtectedPath(sortedDirs[si] + '/')) continue;
  var dirAbs = path.join(repoRoot, sortedDirs[si]);
  try {
    var entries = fs.readdirSync(dirAbs);
    if (entries.length === 0) {
      fs.rmdirSync(dirAbs);
      removedDirs.push(sortedDirs[si]);
    }
  } catch (e) { /* ignore */ }
}
Safety: Never removes:
  • Top-level structural directories (skills/, src/)
  • Critical protected directories
  • Non-empty directories

Forbidden Paths in Genes

Genes can declare forbidden_paths constraints:
{
  "type": "Gene",
  "id": "gene_example",
  "constraints": {
    "max_files": 10,
    "forbidden_paths": [
      ".git",
      "node_modules",
      "skills/evolver",
      "skills/feishu-evolver-wrapper"
    ]
  }
}
During solidify, these are checked:
// src/gep/solidify.js:298-301
const forbidden = Array.isArray(constraints.forbidden_paths) ? constraints.forbidden_paths : [];
for (const f of blast.all_changed_files || blast.changed_files || []) {
  if (isForbiddenPath(f, forbidden)) violations.push(`forbidden_path touched: ${f}`);
}

Auto-Generated Gene Protection

When evolver creates an auto-generated gene, it includes default forbidden paths:
// src/gep/solidify.js:923-958
function buildAutoGene({ signals, intent }) {
  const gene = {
    type: 'Gene',
    id: `gene_auto_${stableHash(signalKey)}`,
    category: intent || inferCategoryFromSignals(signals),
    constraints: {
      max_files: 12,
      forbidden_paths: [
        '.git', 'node_modules',
        'skills/feishu-evolver-wrapper', 'skills/feishu-common',
        'skills/feishu-post', 'skills/feishu-card', 'skills/feishu-doc',
        'skills/skill-tools', 'skills/clawhub', 'skills/clawhub-batch-undelete',
        'skills/git-sync',
      ],
    },
  };
  return gene;
}
Note: skills/evolver is NOT in the default forbidden list (to allow opt-in self-modification).

Safe vs. Unsafe Examples

Safe Evolution

{
  "blast_radius": {
    "files": 3,
    "changed_files": [
      "src/custom/feature.js",
      "src/custom/test.js",
      "README.md"
    ]
  }
}
Result: ✅ All files are in non-protected paths.

Unsafe Evolution (Blocked)

{
  "blast_radius": {
    "files": 2,
    "changed_files": [
      "skills/evolver/src/evolve.js",
      "MEMORY.md"
    ]
  }
}
Result: ❌ Solidify fails with:
constraint: critical_path_modified: skills/evolver/src/evolve.js
constraint: critical_path_modified: MEMORY.md

Self-Modify Opt-In (Warning)

EVOLVE_ALLOW_SELF_MODIFY=true node index.js
Gene:
{
  "category": "repair",
  "validation": ["npm test"]
}
Blast radius:
{
  "changed_files": [
    "skills/evolver/src/gep/selector.js"
  ]
}
Result: ⚠️ Warning logged:
self_modify_evolver_repair: skills/evolver/src/gep/selector.js (EVOLVE_ALLOW_SELF_MODIFY=true)
Evolution proceeds if validation passes.

Monitoring Self-Modification

To detect unauthorized self-modification attempts:
# Check recent events for self-modification warnings
grep 'self_modify_evolver' memory/evolution/events.jsonl

# Check for protected path violations
grep 'critical_path_modified' memory/evolution/events.jsonl

# Audit blast radius for evolver changes
jq -r 'select(.blast_radius.changed_files[] | contains("skills/evolver"))' memory/evolution/events.jsonl

Recovery from Self-Modification Bugs

Symptom

Evolver crashes on every cycle after a self-modification.

Diagnosis

# Check last few events
tail -5 memory/evolution/events.jsonl | jq .

# Find self-modification event
grep 'self_modify_evolver' memory/evolution/events.jsonl | tail -1

Recovery

# 1. Disable evolver loop
pm2 stop evolver

# 2. Roll back to last known-good commit
git log --oneline -10
git reset --hard <last-good-commit>

# 3. Disable self-modification
echo 'EVOLVE_ALLOW_SELF_MODIFY=false' >> .env

# 4. Restart
pm2 start evolver

Best Practices

  1. Keep EVOLVE_ALLOW_SELF_MODIFY=false in production
  2. Monitor self-modification warnings in event logs
  3. Review all repair genes that touch evolver code
  4. Maintain backups of working evolver versions
  5. Test self-modifications in isolated environments before production
  6. Add custom paths to forbidden_paths in gene constraints if needed