Natural Selection for AI — a generalized agent-optimization framework that evolves LLM agents against explicit fitness functions.
Project description
nasfai — Natural Selection for AI
Optimize AI agents by natural selection. Give nasfai a declarative agent blueprint, an explicit fitness function, and an eval dataset; it generates a population of agent variants, measures each against the objective, selects and recombines the best, and returns a champion agent — plus a fully reproducible record of how it got there.
The optimization machinery is the product; the agents it produces are the output.
blueprint ─▶ seed population ─▶ ┌─ evaluate fitness ─▶ select ─▶ vary ─┐ ─▶ champion + lineage
└──────────────── repeat ──────────────┘
- Explicit objectives. The fitness function is a first-class, swappable plugin, logged
verbatim in every run — never implicit. Cost (tokens/$) is always a component. Score on
classification metrics, sandboxed
pass@1, or a user-defined multi-criteria LLM judge. - A real search, not a random walk. Fitness-aware LLM prompt mutation, multi-objective Pareto selection, tournament/rank/roulette strategies, variance-aware (repeat + LCB) scoring, adaptive operator rates, successive-halving early elimination, and cross-run warm-start — all opt-in and determinism-preserving.
- Reproducible & auditable. Every genome is content-addressed; every run pins its inputs in a manifest; every champion traces through a lineage DAG back to the seed.
- Observable by default. Instrumented with OpenTelemetry GenAI semantic conventions; swap the exporter (console → jsonl → OTLP) with one config field.
- Provider-neutral. A deterministic mock provider runs the whole loop — and CI — with zero API spend. Real runs go through the Claude Agent SDK or the Anthropic API.
Install
uv sync # dev: creates the venv, installs everything
# or, as a dependency:
pip install nasfai # core; add extras: nasfai[claude,data,otlp]
Quickstart
Evolve and optimize a Claude Agent SDK coding agent on the deterministic mock provider — no API key, no network, fully reproducible:
uv run nasfai evolve --run examples/claude_sdk_coding_agent/run.mock.yaml
You'll watch pass@1 climb across generations and get a champion plus a report at
.nasfai/runs/<id>/report.md. Then inspect what happened:
uv run nasfai report <run-id>
uv run nasfai lineage --genome <champion-id> --run <run-id>
uv run nasfai blueprint list
To run it for real (opt-in, needs credentials + budget), see
examples/claude_sdk_coding_agent/.
Dashboard
A dependency-free local dashboard to browse, trace, and compare runs — fitness curves, champion + lineage, per-task cost and wall-clock, the OpenTelemetry span timeline, and side-by-side run comparison:
uv run nasfai serve # → http://127.0.0.1:8000
Light, dense, and built on the same run store the CLI writes — point it at any
.nasfai/runs directory.
Library API
from nasfai import evolve
from nasfai.config import load_run_config
config = load_run_config("examples/claude_sdk_coding_agent/run.mock.yaml")
run = evolve("claude-sdk-coder", config)
champion = run.champion
print(champion.genome.id, champion.fitness.score, champion.fitness.components)
Use it from another project — the Agent Skill
nasfai ships as a portable Agent Skill in skills/nasfai/,
so an AI coding agent (Claude Code, etc.) can optimize your agents without you copying any
framework code. Drop it in and ask your agent to "optimize my agent against <metric> on
<data>":
mkdir -p ~/.claude/skills && cp -r skills/nasfai ~/.claude/skills/nasfai
It bundles the workflow, the exact blueprint/fitness/run‑config schemas, and a scaffolder that
generates a ready‑to‑run experiment. See skills/nasfai/README.md.
The vocabulary
A small evolutionary vocabulary runs through the whole system: genome (a serializable
agent), phenotype (its behavior when run), population, generation, fitness,
selection, variation (mutation + recombination, bounded by the blueprint's
search space), lineage, and run. Full definitions in
docs/03-concepts.md.
Development
just # lint + test
just test-cov # tests with coverage gate
just lint # ruff + ruff format --check + mypy
just fix # auto-fix lint + format
Documentation
Full design docs, architecture, and ADRs are in docs/. The build plan and
milestones are in docs/13-implementation-plan.md; the
backlog is in stories/.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nasfai-0.20.1.tar.gz.
File metadata
- Download URL: nasfai-0.20.1.tar.gz
- Upload date:
- Size: 473.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
311c7fd83b211ac1059a8528685a5e9ce7b07dab3d7b215b55382eef47ac7c30
|
|
| MD5 |
4fe90354a541ea1696ad0b2e9b108838
|
|
| BLAKE2b-256 |
553dc03a614fec83615bc44a8f17f1c553231f07d584ab68b09d42e6b4bec4a7
|
Provenance
The following attestation bundles were made for nasfai-0.20.1.tar.gz:
Publisher:
publish.yml on david-der/nasfai
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nasfai-0.20.1.tar.gz -
Subject digest:
311c7fd83b211ac1059a8528685a5e9ce7b07dab3d7b215b55382eef47ac7c30 - Sigstore transparency entry: 1967336283
- Sigstore integration time:
-
Permalink:
david-der/nasfai@1e0e98e584eb3b83a8f365597135d4403b04468a -
Branch / Tag:
refs/tags/v0.20.1 - Owner: https://github.com/david-der
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1e0e98e584eb3b83a8f365597135d4403b04468a -
Trigger Event:
release
-
Statement type:
File details
Details for the file nasfai-0.20.1-py3-none-any.whl.
File metadata
- Download URL: nasfai-0.20.1-py3-none-any.whl
- Upload date:
- Size: 100.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbeed67f5db95527f69149f0a1f7b06f659b497b1066f00540ab472f35667056
|
|
| MD5 |
acbe0702e50b0d98910e80a8155e4c55
|
|
| BLAKE2b-256 |
eb2b0818f48c962e2f253a1c6fa9a31d7e901c9558b541701142a355df4339e4
|
Provenance
The following attestation bundles were made for nasfai-0.20.1-py3-none-any.whl:
Publisher:
publish.yml on david-der/nasfai
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nasfai-0.20.1-py3-none-any.whl -
Subject digest:
bbeed67f5db95527f69149f0a1f7b06f659b497b1066f00540ab472f35667056 - Sigstore transparency entry: 1967336336
- Sigstore integration time:
-
Permalink:
david-der/nasfai@1e0e98e584eb3b83a8f365597135d4403b04468a -
Branch / Tag:
refs/tags/v0.20.1 - Owner: https://github.com/david-der
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1e0e98e584eb3b83a8f365597135d4403b04468a -
Trigger Event:
release
-
Statement type: