Skip to main content

Introduction

Evolver is a protocol-constrained self-evolution engine for AI agents. Unlike ad-hoc prompt tweaks, Evolver transforms runtime observations into auditable, reusable evolution assets through the Genome Evolution Protocol (GEP). This document provides a high-level overview of the core concepts that power the evolution cycle.

Architecture Overview

The evolution system consists of five interconnected components:

Core Components

Signals

Extracted patterns from logs that trigger evolution

Evolution Cycle

Three-phase loop: Analysis, Selection, Execution

Mutations

Explicit change directives with risk levels

Personality

Evolvable traits that guide mutation behavior

How the Pieces Fit Together

The evolution workflow follows this pattern:

1. Signal Extraction

Evolver scans session logs, error traces, and memory snapshots to extract signals:
// From src/gep/signals.js:137
function extractSignals({ recentSessionTranscript, todayLog, memorySnippet, userSnippet, recentEvents }) {
  var signals = [];
  var corpus = [
    String(recentSessionTranscript || ''),
    String(todayLog || ''),
    String(memorySnippet || ''),
    String(userSnippet || ''),
  ].join('\n');
  // ... pattern matching logic
}
Signals include:
  • Error patterns (log_error, errsig:...)
  • Opportunity signals (user_feature_request, capability_gap)
  • Stability signals (stable_success_plateau, evolution_stagnation_detected)

2. Gene & Capsule Selection

The selector matches signals to Genes (strategy templates) and Capsules (validated solutions):
// From src/gep/selector.js:185
function selectGeneAndCapsule({ genes, capsules, signals, memoryAdvice, driftEnabled }) {
  const { selected, alternatives } = selectGene(genes, signals, {
    bannedGeneIds: effectiveBans,
    preferredGeneId,
    driftEnabled,
  });
  const capsule = selectCapsule(capsules, signals);
  // ...
}

3. Mutation Construction

A Mutation object encodes the change intent with risk levels and safety constraints:
// From src/gep/mutation.js:100
function buildMutation({ signals, selectedGene, driftEnabled, personalityState }) {
  const category = mutationCategoryFromContext({ signals, driftEnabled });
  const base = {
    type: 'Mutation',
    id: `mut_${Date.now()}`,
    category,  // repair | optimize | innovate
    trigger_signals: signals,
    target: targetFromGene(selectedGene),
    expected_effect: expectedEffectFromCategory(category),
    risk_level: 'low',  // low | medium | high
  };
  // ...
}

4. Personality Modulation

The PersonalityState evolves through natural selection to optimize for success:
// From src/gep/personality.js:255
function selectPersonalityForRun({ driftEnabled, signals, recentEvents }) {
  const model = loadPersonalityModel();
  const best = chooseBestKnownPersonality(model.stats);
  // Natural selection: nudge towards best-known configuration
  // Triggered mutation: adapt to current signals
  // ...
}

5. Evolution Execution

The cycle executes the mutation and records the outcome to the Memory Graph for future learning.
All evolution events are append-only and auditable via assets/gep/events.jsonl.

Decision Points

The evolution cycle includes several guard conditions to prevent unsafe changes:

Loop Gating

Prevents starting a new cycle until the previous one is solidified:
// From src/evolve.js:701
if (bridgeEnabled && loopMode) {
  const st = readStateForSolidify();
  const pending = !lastSolid || lastSolid.run_id !== lastRun.run_id;
  if (pending) {
    writeDormantHypothesis({ backoff_reason: 'loop_gating_pending_solidify' });
    await sleepMs(waitMs);
    return;
  }
}

Load Awareness

Backs off when system load is too high:
// From src/evolve.js:686
const LOAD_MAX = parseFloat(process.env.EVOLVE_LOAD_MAX || getDefaultLoadMax());
if (sysLoad.load1m > LOAD_MAX) {
  writeDormantHypothesis({ backoff_reason: 'system_load_exceeded' });
  await sleepMs(QUEUE_BACKOFF_MS);
  return;
}

Repair Loop Circuit Breaker

Detects when the evolver is stuck in a repair loop and forces innovation:
// From src/evolve.js:791
const recent = allEvents.slice(-REPAIR_LOOP_THRESHOLD);
if (recent.every(e => e.intent === 'repair' && e.outcome.status === 'failed')) {
  process.env.FORCE_INNOVATION = 'true';
}

Next Steps

Dive deeper into each component:

Evolution Cycle

Learn the three-phase execution model

Signals

Understand signal extraction and de-duplication

Mutations

Explore mutation categories and risk levels

Personality

See how personality traits evolve over time

Build docs developers (and LLMs) love