experiment · git:20260826.34a9b20 · 2026-08-26 · sha256 311ec2ece82fadbb
experiment git:20260826.34a9b20A
Immutable. This exact content is served forever at /api/v1/blob/311ec2ece82fadbb.
---
name: experiment
description: Experiment loop for iterative metric-driven code optimization using XLOOP
compatibility: omp
---
# Experiment Loop Skill (XLOOP)
Skill for running automated iterative improvement loops that optimize a measurable metric
while keeping changes simple and reversible.
## Overview
The experiment loop (`auto experiment`) runs an agent-driven cycle:
1. Measure baseline metric
2. Ask an executor agent to make one focused change
3. Measure the new metric
4. Decide: keep (commit) or discard (reset)
5. Check circuit breaker and simplicity gate
6. Repeat until MaxIterations or circuit break
## Setup
```bash
# Initialize experiment branch (requires clean worktree)
auto experiment init --session-id my-session
# Verify metric command works
auto experiment metric \
--metric 'go test -bench=. ./... | grep ns/op | awk "{print \"{\\\"metric\\\":\"$3\"}\"}"' \
--metric-key metric
```
## Full Loop Configuration
```bash
auto experiment init --session-id opt-$(date +%s)
# Then invoke the loop via the agent skill below
```
## Agent Orchestration Pattern
The experiment loop is driven by invoking an executor agent repeatedly.
Pass the full history context on each call so the agent can learn from past iterations.
```
## Experiment Loop — Iteration {N}
### Config
- MetricCmd: {cmd}
- Direction: {minimize|maximize}
- Target: {files}
- Scope: {files or "same as target"}
- SimplicityThreshold: {threshold}
### History (last 5 results)
{JSON array of recent Result objects from `auto experiment record`}
### Baseline: {baseline_value} {unit}
### Best so far: {best_value} at iteration {best_iter}
### Your task
Make ONE focused change to the target files that should improve the metric.
Do NOT modify files outside the allowed scope.
After making your change, run:
auto experiment commit --iteration {N} --description "your change description"
Then output the description in the last line.
```
## Keep / Discard Decision
After each executor run, measure the metric and decide:
```
new_value = RunMetricMedian(cfg, cmd)
simplicity = CalculateSimplicity(baseline, new_value, linesAdded, linesRemoved, direction)
if direction.IsBetter(new_value, best_value):
if simplicity >= cfg.SimplicityThreshold:
status = "keep"
best_value = new_value
circuit_breaker.Record(true)
else:
status = "discard" # improvement too small relative to code complexity
ResetToCommit(last_keep_hash)
circuit_breaker.Record(false)
else:
status = "discard"
ResetToCommit(last_keep_hash)
circuit_breaker.Record(false)
```
Record the result:
```bash
auto experiment record \
--iteration {N} \
--status {keep|discard} \
--metric-value {value} \
--description "{description}"
```
## Crash Handling
When the executor agent's change causes a build failure or test crash:
### Trivial crash (compile error, test panic)
- Reset immediately: `auto experiment reset --commit {last_keep_hash}`
- Record status `crash`
- Continue to next iteration
- Do NOT count as circuit breaker failure (the code was broken, not the approach)
### Fundamental crash (3+ consecutive crashes on same approach)
- Treat as circuit breaker failure
- Record status `crash`
- Call `circuit_breaker.Record(false)`
### Abort condition
- If crash prevents metric measurement entirely for 5+ consecutive iterations: abort loop
## Circuit Breaker
The circuit breaker trips when N consecutive iterations show no improvement.
Default N = 10 (configurable via `--circuit-breaker-n`).
```
if circuit_breaker.IsTripped():
print("Circuit breaker tripped after {N} consecutive non-improvements")
print("Best result: iteration {best_iter}, metric={best_value}")
auto experiment summary
exit loop
```
The breaker resets automatically when a keep is recorded.
## Simplicity Gate
The simplicity score penalizes large code changes relative to metric improvement.
A change that improves the metric by 0.1% but adds 500 lines is likely not worth keeping.
```
score = improvement_ratio / lines_changed
threshold = cfg.SimplicityThreshold # default 0.001
if score < threshold:
# Discard even if metric improved — change is too complex
status = "discard"
```
Special cases:
- `score < 0`: metric got worse → always discard
- `score == 0`: no metric change → always discard
- Zero lines changed with improvement: score is high → always keep
## Scope Validation
After each executor commit, verify changes stay within allowed scope:
```bash
# Check scope (called internally by loop logic)
# Uses git.CheckScope(baseCommit, allowedPaths)
```
If out-of-scope files are modified:
- Record status `scope-violation`
- Reset to last keep hash
- Do NOT count as circuit breaker failure
## SIGINT Graceful Shutdown
When the user presses Ctrl+C during the loop:
1. Finish the current metric measurement if in progress
2. Do NOT start a new executor agent call
3. If last commit was a "discard" candidate: reset to last keep hash
4. Print summary: `auto experiment summary`
5. Exit cleanly
The experiment branch is preserved — the user can resume later.
## Summary
At loop end (natural completion, circuit break, or SIGINT):
```bash
auto experiment summary
```
Outputs:
```
total=25 keep=12 discard=13 best=1.2340 (iter 18)
```
## Example: Benchmark Optimization
```bash
# 1. Initialize
auto experiment init --session-id bench-opt-001
# 2. Run loop (orchestrated by this skill)
# Config:
# --metric 'go test -bench=BenchmarkFoo -benchtime=3s ./pkg/foo/ | grep BenchmarkFoo | awk "{print \"{\\\"metric\\\":\"$3\"}"}'
# --direction minimize
# --target pkg/foo/foo.go
# --max-iterations 30
# --metric-runs 3
# 3. After loop completes
auto experiment summary
```
## Ref
- SPEC-XLOOP-001
- pkg/experiment/ — core loop types and utilities
- internal/cli/experiment.go — CLI entry points