Skip to main content

What is an EvolutionEvent?

An EvolutionEvent is an immutable audit log entry that records every evolution cycle. Events form a tree structure via parent_id, enabling:
  • Complete Audit Trail: Every change is traceable
  • Evolution Trees: Visualize branching and lineage
  • Outcome Tracking: Success/failure rates over time
  • Rollback Support: Trace back to any historical state

Event Structure

type
string
required
Must be "EvolutionEvent"
schema_version
string
required
Current: "1.5.0"
id
string
required
Unique identifier (e.g., evt_1770477654236)
parent
string
ID of the parent event (forms evolution tree). null for root events.
intent
string
required
Evolution intent: repair, optimize, or innovate
signals
array
required
Signals that triggered this evolution cycle
genes_used
array
required
IDs of Genes applied in this cycle
mutation_id
string
ID of the Mutation that gated this evolution
personality_state
object
Personality configuration at the time of evolution
blast_radius
object
required
Actual impact: { files: number, lines: number }
outcome
object
required
Result: { status: "success" | "failed", score: number }
capsule_id
string
ID of the Capsule created (only present if status=success)
env_fingerprint
object
required
Environment metadata (node version, platform, OS, etc.)
validation_report_id
string
ID of the ValidationReport
meta
object
Detailed metadata: selector decision, constraints, validation results, etc.

Real Event Examples

Example 1: Failed Innovation Event

This event attempted innovation but violated constraints:
{
  "type": "EvolutionEvent",
  "schema_version": "1.5.0",
  "id": "evt_1770477201173",
  "parent": "evt_1770476523037",
  "intent": "innovate",
  "signals": [
    "user_missing",
    "user_feature_request"
  ],
  "genes_used": [
    "gene_gep_innovate_from_opportunity"
  ],
  "mutation_id": "mut_1770476534173",
  "personality_state": {
    "type": "PersonalityState",
    "rigor": 0.7,
    "creativity": 0.35,
    "verbosity": 0.25,
    "risk_tolerance": 0.4,
    "obedience": 0.9
  },
  "blast_radius": {
    "files": 1,
    "lines": 2
  },
  "outcome": {
    "status": "failed",
    "score": 0.2
  },
  "capsule_id": null,
  "env_fingerprint": {
    "node_version": "v22.22.0",
    "platform": "linux",
    "arch": "x64",
    "os_release": "6.1.0-42-cloud-amd64",
    "evolver_version": "1.7.0",
    "cwd": "/home/crishaocredits/.openclaw/workspace",
    "captured_at": "2026-02-07T15:13:21.123Z"
  },
  "validation_report_id": "vr_1770477201172",
  "meta": {
    "at": "2026-02-07T15:13:21.173Z",
    "signal_key": "user_feature_request|user_missing",
    "selector": {
      "selected": "gene_gep_innovate_from_opportunity",
      "reason": [
        "signals match gene.signals_match",
        "signals: user_missing, user_feature_request",
        "memory_graph: memory_prefer:gene_gep_innovate_from_opportunity | gene_prior:0.667"
      ],
      "alternatives": []
    },
    "constraints_ok": false,
    "constraint_violations": [
      "forbidden_path touched: assets/gep/events.jsonl"
    ],
    "validation_ok": true
  }
}
Validation Passed: All commands succeeded (validation_ok: true)Constraint Violation: Attempted to modify assets/gep/events.jsonl, which is forbiddenLow Score: outcome.score = 0.2 reflects constraint violationNo Capsule: Failed events don’t create Capsules (capsule_id: null)Parent Reference: parent: "evt_1770476523037" links to previous event in tree

Example 2: Successful Repair Event

This event successfully repaired a shell compatibility error:
{
  "type": "EvolutionEvent",
  "schema_version": "1.5.0",
  "id": "evt_1770477654236",
  "parent": "evt_1770477201173",
  "intent": "repair",
  "signals": [
    "log_error",
    "errsig:**TOOLRESULT**: { \"status\": \"error\", \"tool\": \"exec\", \"error\": \"error: unknown command 'process'\\n\\nCommand exited with code 1\" }",
    "user_missing",
    "windows_shell_incompatible",
    "perf_bottleneck"
  ],
  "genes_used": [
    "gene_gep_repair_from_errors"
  ],
  "mutation_id": "mut_1770477615603",
  "personality_state": {
    "type": "PersonalityState",
    "rigor": 0.7,
    "creativity": 0.35,
    "verbosity": 0.25,
    "risk_tolerance": 0.4,
    "obedience": 0.9
  },
  "blast_radius": {
    "files": 1,
    "lines": 2
  },
  "outcome": {
    "status": "success",
    "score": 0.85
  },
  "capsule_id": "capsule_1770477654236",
  "env_fingerprint": {
    "node_version": "v22.22.0",
    "platform": "linux",
    "arch": "x64",
    "os_release": "6.1.0-42-cloud-amd64",
    "evolver_version": "1.7.0",
    "cwd": "/home/crishaocredits/.openclaw/workspace",
    "captured_at": "2026-02-07T15:20:54.155Z"
  },
  "validation_report_id": "vr_1770477654235",
  "meta": {
    "at": "2026-02-07T15:20:54.236Z",
    "signal_key": "errsig_norm:870c3a82|log_error|perf_bottleneck|user_missing|windows_shell_incompatible",
    "selector": {
      "selected": "gene_gep_repair_from_errors",
      "reason": [
        "signals match gene.signals_match",
        "signals: log_error, errsig:**TOOLRESULT**: { \"status\": \"error\", \"tool\": \"exec\", \"error\": \"error: unknown command 'process'\\n\\nCommand exited with code 1\" }, user_missing, windows_shell_incompatible, perf_bottleneck",
        "memory_graph: memory_prefer:gene_gep_repair_from_errors | gene_prior:0.500"
      ],
      "alternatives": [
        "gene_gep_innovate_from_opportunity"
      ]
    },
    "constraints_ok": true,
    "validation_ok": true
  }
}
Parent Event: evt_1770477201173 (the failed innovation attempt)Intent Switch: Changed from innovate to repair due to error signalsGene Selection: Repair Gene chosen over innovation GeneSuccess: Both validation and constraints passedCapsule Created: capsule_1770477654236 captures this solution

Tree Structure via parent_id

Building Evolution Trees

Events form a directed acyclic graph (DAG) via parent_id:
evt_1770476523037 (root)
  └── evt_1770477201173 (failed innovate)
      ├── evt_1770477654236 (success repair, 1 file/2 lines)
      └── evt_1770478341769 (success repair, 2 files/44 lines)

Querying Event History

From src/gep/assetStore.js:
function readAllEvents() {
  try {
    const raw = fs.readFileSync('assets/gep/events.jsonl', 'utf8');
    return raw.split('\n')
      .map(l => l.trim())
      .filter(Boolean)
      .map(l => {
        try { return JSON.parse(l); }
        catch { return null; }
      })
      .filter(Boolean);
  } catch { return []; }
}

function getLastEventId() {
  const events = readAllEvents();
  if (events.length === 0) return null;
  const last = events[events.length - 1];
  return last.id || null;
}

Computing Success Streaks

Capsule success streaks are computed by walking the event tree:
// From src/gep/a2a.js
function computeCapsuleSuccessStreak(capsuleId, events) {
  let streak = 0;
  for (let i = events.length - 1; i >= 0; i--) {
    const ev = events[i];
    if (!ev || ev.type !== 'EvolutionEvent') continue;
    if (String(ev.capsule_id) !== String(capsuleId)) continue;
    
    const status = ev.outcome?.status || 'unknown';
    if (status === 'success') streak++;
    else break; // streak broken by failure
  }
  return streak;
}

Validation Reports

ValidationReport Structure

Each event references a ValidationReport:
{
  "type": "ValidationReport",
  "schema_version": "1.5.0",
  "id": "vr_1770477654235",
  "gene_id": "gene_gep_repair_from_errors",
  "env_fingerprint": {
    "node_version": "v22.22.0",
    "platform": "linux",
    "arch": "x64",
    "os_release": "6.1.0-42-cloud-amd64",
    "evolver_version": "1.7.0"
  },
  "env_fingerprint_key": "b98472b2ef785976",
  "commands": [
    {
      "command": "node scripts/validate-modules.js ./src/evolve ./src/gep/solidify",
      "ok": true,
      "stdout": "ok\n",
      "stderr": ""
    },
    {
      "command": "node scripts/validate-modules.js ./src/gep/selector ./src/gep/memoryGraph",
      "ok": true,
      "stdout": "ok\n",
      "stderr": ""
    }
  ],
  "overall_ok": true,
  "duration_ms": 80,
  "created_at": "2026-02-07T15:20:54.236Z",
  "asset_id": "sha256:404345b559ec9a29d30444c3d66ff8f346d87017b7dea1d965ae35f029c8d5c6"
}

Event Metadata

Selector Decision

The meta.selector object records why a particular Gene/Capsule was chosen:
"selector": {
  "selected": "gene_gep_repair_from_errors",
  "reason": [
    "signals match gene.signals_match",
    "signals: log_error, exception, failed",
    "memory_graph: memory_prefer:gene_gep_repair_from_errors | gene_prior:0.500"
  ],
  "alternatives": ["gene_gep_innovate_from_opportunity"]
}

Signal Key

The meta.signal_key is a normalized, sorted concatenation of all signals:
"signal_key": "errsig_norm:870c3a82|log_error|perf_bottleneck|user_missing|windows_shell_incompatible"
This key is used for:
  • Deduplication: Prevent identical signal patterns from triggering multiple times
  • Memory Graph: Track success rates per signal combination
  • Capsule Matching: Find Capsules that handled similar signal patterns

Personality State

Each event captures the personality configuration:
"personality_state": {
  "type": "PersonalityState",
  "rigor": 0.7,
  "creativity": 0.35,
  "verbosity": 0.25,
  "risk_tolerance": 0.4,
  "obedience": 0.9
}
Parameters:
  • rigor: Strictness of validation (0.0-1.0)
  • creativity: Willingness to try new approaches (0.0-1.0)
  • verbosity: Output detail level (0.0-1.0)
  • risk_tolerance: Acceptance of larger blast radius (0.0-1.0)
  • obedience: Follow Gene strategy exactly vs. adapt (0.0-1.0)

Querying Event History

Find Events by Intent

const events = readAllEvents();
const repairEvents = events.filter(e => e.intent === 'repair');
const successRate = repairEvents.filter(e => e.outcome.status === 'success').length / repairEvents.length;

Find Events by Gene

const geneEvents = events.filter(e => e.genes_used.includes('gene_gep_repair_from_errors'));
const avgBlastRadius = geneEvents.reduce((sum, e) => sum + e.blast_radius.files, 0) / geneEvents.length;

Build Evolution Tree

function buildTree(events) {
  const nodes = new Map();
  events.forEach(e => nodes.set(e.id, { ...e, children: [] }));
  
  events.forEach(e => {
    if (e.parent) {
      const parent = nodes.get(e.parent);
      if (parent) parent.children.push(nodes.get(e.id));
    }
  });
  
  return Array.from(nodes.values()).filter(n => !n.parent);
}

Find Latest Event

// From src/gep/assetStore.js
function getLastEventId() {
  try {
    const raw = fs.readFileSync('assets/gep/events.jsonl', 'utf8');
    const lines = raw.split('\n').map(l => l.trim()).filter(Boolean);
    if (lines.length === 0) return null;
    const last = JSON.parse(lines[lines.length - 1]);
    return last?.id || null;
  } catch { return null; }
}

Event Storage Format

JSONL (JSON Lines)

Events are stored in assets/gep/events.jsonl with one JSON object per line:
{"type":"ValidationReport","id":"vr_1770477201172",...}
{"type":"EvolutionEvent","id":"evt_1770477201173","parent":"evt_1770476523037",...}
{"type":"ValidationReport","id":"vr_1770477654235",...}
{"type":"EvolutionEvent","id":"evt_1770477654236","parent":"evt_1770477201173",...}
Why JSONL?:
  • Append-Only: Fast writes, no parsing entire file
  • Immutable: Each line is a separate record
  • Crash-Resistant: Partial writes don’t corrupt entire log
  • Stream-Friendly: Can process line-by-line for large logs

Forbidden Modifications

The events.jsonl file is strictly forbidden from modification by Genes:
"constraints": {
  "forbidden_paths": [
    ".git",
    "node_modules",
    "assets/gep/events.jsonl"
  ]
}
This ensures the audit trail remains immutable and tamper-proof.

Event Lifecycle

1

Signal Extraction

Parse logs, errors, and user instructions to extract signals
2

Gene/Capsule Selection

Selector chooses best match based on signals and history
3

Mutation Gating

Create Mutation object to gate the evolution cycle
4

Apply Changes

Execute Gene strategy or apply Capsule solution
5

Validation

Run validation commands; rollback on failure
6

Constraint Check

Verify blast radius and forbidden paths
7

Solidify

Append EvolutionEvent + ValidationReport to events.jsonl
8

Capsule Creation

If successful, create Capsule and append to capsules.json

Next Steps

A2A Protocol

Learn how events and capsules are shared between agents

Hub Integration

Query hub for solutions before local evolution

Build docs developers (and LLMs) love