Metadata-Version: 2.5
Name: meta-evolve
Version: 0.2.0.dev0
Summary: Programmable evaluated improvement loops over versioned artifacts
License-Expression: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.12
Provides-Extra: browser
Requires-Dist: jinja2<4,>=3.1.6; extra == 'browser'
Requires-Dist: starlette<2,>=1.3; extra == 'browser'
Requires-Dist: uvicorn<1,>=0.51; extra == 'browser'
Provides-Extra: conformance
Requires-Dist: pytest>=8.4.2; extra == 'conformance'
Description-Content-Type: text/markdown

# Meta-Evolve

[![CI](https://github.com/sentient-xyz/meta-evolve/actions/workflows/ci.yml/badge.svg)](https://github.com/sentient-xyz/meta-evolve/actions/workflows/ci.yml)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sentient-xyz/meta-evolve/blob/main/LICENSE)

**Improve solutions. Improve the methods that produce them.**

Start with a prompt, skill document, program, or agent setup. You provide a way
to propose changes and checks for what counts as better. Meta-Evolve runs the
attempts, selects the best measured version, and keeps the results for inspection.

**Start with a version → propose a change → test it → inspect what happened.**

[Run the notebook walkthrough](https://sentient-xyz.github.io/meta-evolve-docs/start-here/),
or try the example below. No model or API key is needed.

## One improvement experiment

Our time tracker thinks **four minutes means four seconds**. Let's propose a
correction and check both versions against the same six expected answers.
The correction is handwritten; Python executes and scores the parsers.

### 1. Install

Use **Python 3.12 or newer**. In a terminal, run:

```bash
pip install meta-evolve
```

Run the four Python cells below in order.

### 2. Try the starting parser

An [**artifact**](https://sentient-xyz.github.io/meta-evolve-docs/concepts/artifacts/)
is the thing you want to improve—a prompt, skill document, program, or agent
setup. Here it is the parser's Python source. `SEED` holds its starting version;
`load_parser` turns the source into a function we can call.

```python
import meta_evolve as meta

SEED = '''def parse_seconds(text):
    return int(text[:-1])
'''


def load_parser(source):
    namespace = {}
    exec(source, namespace)
    return namespace["parse_seconds"]


print("4m:", load_parser(SEED)("4m"), "seconds")
# Output:
# 4m: 4 seconds
```

### 3. Define what better means

`evaluate(source)` returns the fraction of correct answers; higher is better.
The starting parser passes only the two seconds cases. These checks stay fixed.

```python
CASES = (
    ("30s", 30),
    ("90s", 90),
    ("2m", 120),
    ("3m", 180),
    ("1h", 3600),
    ("2h", 7200),
)


def evaluate(source):
    parse = load_parser(source)
    passed = 0
    for text, expected in CASES:
        actual = parse(text)
        if type(actual) is int and actual == expected:
            passed += 1
    return passed / len(CASES)


print(f"Starting: {evaluate(SEED) * len(CASES):.0f}/{len(CASES)} checks")
# Output:
# Starting: 2/6 checks
```

### 4. Propose a correction

`propose(source)` receives the current parser and returns revised source.
This correction multiplies by the number of seconds in each unit.

```python
def propose(source):
    return '''def parse_seconds(text):
    quantity = int(text[:-1])
    seconds_per_unit = {"s": 1, "m": 60, "h": 3600}
    return quantity * seconds_per_unit[text[-1]]
'''
```

### 5. Run, inspect, and use it

`meta.improve()` checks the starting version, tries one revision (`trials=1`),
and selects the better score. You choose the checks and the attempt limit.
`result.best().value` gives you the selected source to use.

```python
result = meta.improve(
    seed=SEED,
    # This example returns a handwritten correction.
    # Replace it with a function that asks an agent or LLM for new candidates.
    proposer=propose,
    evaluator=evaluate,
    trials=1,
)

summary = result.summary()
print(f"Starting: {evaluate(SEED) * len(CASES):.0f}/{len(CASES)} checks")
print(f"Selected: {summary.primary_score * len(CASES):.0f}/{len(CASES)} checks")
print("Selected source:")
print(result.best().value, end="")

parse_seconds = load_parser(result.best().value)
print("4m:", parse_seconds("4m"), "seconds")
# Output:
# Starting: 2/6 checks
# Selected: 6/6 checks
# Selected source:
# def parse_seconds(text):
#     quantity = int(text[:-1])
#     seconds_per_unit = {"s": 1, "m": 60, "h": 3600}
#     return quantity * seconds_per_unit[text[-1]]
# 4m: 240 seconds
```

**2/6 → 6/6 checks passed. Four minutes now gives 240 seconds.** A tie or a worse
revision keeps the earlier winner. Passing these six checks establishes the
result for those inputs; it doesn't establish correctness for every input.
Selecting this source does not deploy it.

**Try it:** change `trials=1` to `trials=0` and rerun the last cell. The starting
parser stays selected, passes **2/6** checks, and returns **4 seconds** for `"4m"`.
Restore `trials=1` to try the correction again.

The result keeps attempted versions and outcomes in memory. To retain them after
Python closes, [save and reopen the run](https://sentient-xyz.github.io/meta-evolve-docs/learn/06-persist-run/).

## What would you like to improve?

| Your task | Try next | Availability |
|---|---|---|
| Improve an image | [Draw and revise an SVG using visual feedback](https://sentient-xyz.github.io/meta-evolve-docs/build-patterns/feedback-descent/) | **Shipped**; captured live run |
| Teach reusable skills | [Build Claude skills from OfficeQA failures](https://sentient-xyz.github.io/meta-evolve-docs/build-patterns/evoskill/) | **Experimental/live-only**; captured live run |
| Improve instructions | [Improve a meeting-notes extraction prompt](https://sentient-xyz.github.io/meta-evolve-docs/applications/meeting-notes/) | **Shipped**; deterministic example |
| Improve a program | [Optimize a scheduler in a simulator](https://sentient-xyz.github.io/meta-evolve-docs/research/adrs/) | **Shipped**; deterministic study |
| Improve how an agent works | [Revise its repair instructions in Meta-Harness](https://sentient-xyz.github.io/meta-evolve-docs/research/meta-harness/) | **Experimental/live-only**; live capture pending |

Each path explains its setup and limits. To let a model propose the parser's
correction, [connect your model SDK](https://sentient-xyz.github.io/meta-evolve-docs/guides/providers/)
and try the [live parser](https://sentient-xyz.github.io/meta-evolve-docs/guides/live-parser/)
(**Experimental/live-only**). You can also
[adapt the checks](https://sentient-xyz.github.io/meta-evolve-docs/guides/evaluation/) or
[set a different work limit](https://sentient-xyz.github.io/meta-evolve-docs/guides/limits/).

[Documentation](https://sentient-xyz.github.io/meta-evolve-docs/) ·
[API reference](https://sentient-xyz.github.io/meta-evolve-docs/reference/api/) ·
[When to use Meta-Evolve](https://sentient-xyz.github.io/meta-evolve-docs/comparison/) ·
[Contributing](https://github.com/sentient-xyz/meta-evolve/blob/main/dev/contributor-code-tour.md)

## Citation

For research, cite [Meta-Evolve](https://github.com/sentient-xyz/meta-evolve)
and the version used in your experiments.

## License

[Apache License 2.0](https://github.com/sentient-xyz/meta-evolve/blob/main/LICENSE).
