A compilation platform where frozen data compiles itself through fold. You build compilation languages — not applications. HTTP, CLI, Telegram, OpenAPI, Pydantic, SQL are libraries on the platform. Your custom compilers sit next to them.
@schema_meta(http_crud("/users", Users)) @dataclass class User: id: Annotated[int, Identity] name: str email: Annotated[str, Unique, MaxLen(255)]
5 REST endpoints. Pydantic models. OpenAPI spec. You write fields, fold writes everything else.
uv add git+https://github.com/prostomarkeloff/emergent.git
The idea
Frameworks today scatter meaning across files. A User lives in a model, a serializer, a view, a URL config, a migration, a test fixture — and none of those files know about each other. An LLM (or a human) has to hold the whole graph in their head to make a correct change.
emergent inverts this. Everything about a thing is on the thing:
@schema_meta( http_crud("/bounties", Board, ops=(LIST, GET, CREATE)), Methods(), ) @dataclass class Bounty: id: Annotated[int, Identity] title: str reward: Annotated[int, Min(0)] status: Annotated[str, MaxLen(20), Doc("Bounty status"), cli.Help("Current status"), openapi.Description("Status field"), sql.Index("idx_status")] @classmethod @post("/bounties/{bounty_id}/claim") async def claim(cls, db: ..., bounty_id: int, hunter: str) -> Result[Bounty, DomainError]: ...
One place. Every concern — validation, CLI help text, OpenAPI description, SQL index, HTTP routes — lives as an annotation on the field it belongs to. The fold compiler reads these annotations and produces correct output for each target. No sync bugs. No scattered state. No framework magic to reverse-engineer.
This is locality by construction, and it's what makes emergent work for humans and machines alike.
The entire platform is one function. Compilation, verification, explanation, query execution, derivation — all are
foldapplied to different data. Everything else is consequences.
Platform, not framework
Frameworks prescribe structure. Rails prescribes MVC. Django prescribes models-views-templates. You write code inside the framework.
emergent provides primitives. You build on the platform:
| Primitive | What it does |
|---|---|
fold(items, ctx, protocol, method) |
Iterate capabilities, dispatch by protocol, accumulate context. 8 lines. |
CompilationPhase(ctx_type, protocol, initial) |
Reified fold configuration. One phase = one compilation language. |
SchemaCompiler(phases) |
Composable set of phases. Algebra: +, |, -, &. |
TargetCompiler(trigger, codecs, pipeline, assemble) |
Surface-level compilation: Application → framework artifact. |
The 4 axes (Schema, Surface, Storage, Query) are libraries built on these primitives. wire.derive is a library. Your custom compilers sit next to them — not inside a framework, but on the same platform.
Create your own compiler
to_pydantic(User, axes) reads capabilities, produces a Pydantic model. to_json_schema produces OpenAPI. You build to_search_index the same way. This runs:
from dataclasses import dataclass, replace from typing import Annotated, Protocol, runtime_checkable from emergent.wire.compile._core import Axes from emergent.wire.compile._phase import CompilationPhase from emergent.wire.compile import to_pydantic, to_json_schema from emergent.wire.axis.schema import Identity, MaxLen, Min from emergent.wire.axis.schema._universal import SchemaAxisCapability from emergent.wire.axis._capability import OpenAPIContext, openapi_schema # ── Your language: search index ────────────────────────────── @dataclass(frozen=True, slots=True) class IndexFieldCtx: field_name: str = "" field_type: type = object searchable: bool = False boost: float = 1.0 facet: bool = False @runtime_checkable class IndexCompilable(Protocol): def compile_index(self, ctx: IndexFieldCtx) -> IndexFieldCtx: ... INDEX_PHASE = CompilationPhase( IndexFieldCtx, IndexCompilable, lambda n, t: IndexFieldCtx(field_name=n, field_type=t), ) # ── Capabilities: one atom, two languages ──────────────────── @dataclass(frozen=True, slots=True) class Searchable(SchemaAxisCapability): boost: float = 1.0 # YOUR language def compile_index(self, ctx: IndexFieldCtx) -> IndexFieldCtx: return replace(ctx, searchable=True, boost=self.boost) # emergent's! def compile_openapi(self, ctx: OpenAPIContext) -> OpenAPIContext: return openapi_schema( ctx, **{"x-searchable": True, "x-search-boost": self.boost} ) @dataclass(frozen=True, slots=True) class Facet(SchemaAxisCapability): def compile_index(self, ctx: IndexFieldCtx) -> IndexFieldCtx: return replace(ctx, facet=True) def compile_openapi(self, ctx: OpenAPIContext) -> OpenAPIContext: return openapi_schema(ctx, **{"x-facet": True}) # ── Your compiler: to_search_index — same shape as to_pydantic @dataclass(frozen=True, slots=True) class IndexField: name: str searchable: bool = False boost: float = 1.0 facet: bool = False @dataclass(frozen=True, slots=True) class SearchIndex: entity: str fields: tuple[IndexField, ...] INDEX_COMPILER = SchemaCompiler(phases=(INDEX_PHASE,)) def to_search_index(cls: type, axes: Axes) -> SearchIndex: ec = INDEX_COMPILER.compile(cls, axes) return SearchIndex( entity=cls.__name__, fields=tuple( IndexField( name=c.field_name, searchable=c.searchable, boost=c.boost, facet=c.facet, ) for fc in ec if (c := fc[INDEX_PHASE]).searchable or c.facet ), ) # ── Entity ─────────────────────────────────────────────────── @dataclass class Product: id: Annotated[int, Identity] name: Annotated[str, MaxLen(200), Searchable(boost=3.0)] description: Annotated[str, Searchable()] category: Annotated[str, Facet()] price: Annotated[float, Min(0), Facet()] # ── Same axes, three compilers ─────────────────────────────── axes = Axes.default() index = to_search_index(Product, axes) # YOUR compiler → SearchIndex model = to_pydantic(Product, axes) # emergent's → Pydantic BaseModel schema = to_json_schema(Product, axes) # emergent's → OpenAPI JSON Schema
index → SearchIndex(entity='Product', fields=( IndexField(name='name', searchable=True, boost=3.0), IndexField(name='description', searchable=True, boost=1.0), IndexField(name='category', facet=True), IndexField(name='price', facet=True), )) model → <class 'Product'> (Pydantic BaseModel with MaxLen, Min validation) schema → { "name": {"type": "string", "maxLength": 200, "x-searchable": true, "x-search-boost": 3.0}, "category": {"type": "string", "x-facet": true}, "price": {"type": "number", "minimum": 0, "x-facet": true}, ... }
to_search_index has the same shape as to_pydantic — takes a class and axes, returns a typed artifact. Searchable implements both compile_index and compile_openapi, so it participates in both compilers. MaxLen has no compile_index — your compiler never sees it.
Execution: nodnod
emergent has two co-equal primitives. fold compiles descriptions. nodnod executes dependency graphs:
@G.node class FetchPrice: @classmethod async def __compose__(cls, product: Product, db: Database) -> float: return await db.get_price(product.id) @G.node class FetchStock: @classmethod async def __compose__(cls, product: Product, db: Database) -> int: return await db.get_stock(product.id) # FetchPrice and FetchStock have no dependency on each other → run in parallel. # No asyncio.gather. No concurrency code. The type signatures ARE the graph. result = await G.compose(BuildReport, product, db)
Types are the specification. fold reads capabilities from Annotated. nodnod reads dependencies from __compose__ signatures. Both: the structure IS the program.
Why this matters
A User in Django lives in a model, a serializer, a view, a URL config, a migration. Five files that must agree. When you change one, you grep for the others and hope. When a new developer joins, they trace the chain by hand. When a coding agent tries to add a field, it hallucinates a signal that doesn't exist because the pattern looked right from the three files it saw.
This is the scattered meaning problem. It is not a tooling problem — it is a language problem. The absence of a primitive that lets you state a fact once and have every consumer derive what it needs.
emergent is that primitive. Four properties make it work:
| Property | What it means |
|---|---|
| Locality | All concerns for a field live on the field. Annotated[str, MaxLen(255), Unique, sql.Index()] — validation, schema, DDL in one place. |
| Defunctionalization | Behavior is data. MaxLen(255) is a frozen dataclass you can print, compare, serialize. Not a closure. Not a decorator. Data. |
| Open-world dispatch | New capabilities participate via isinstance. No registration. No plugin system. Implement the protocol → fold picks you up. |
| Algebraic composition | Compilers compose: FASTAPI_SCHEMA + YOUR_PHASE. Capabilities compose: (MaxLen(255), Unique). No interference between independent concerns. |
The result: any observer — human, LLM, or your future self at 3 AM — reads one declaration and knows everything. One change propagates to all targets. Not by convention. By construction.
Self-describing
emergent's IR reads itself. Every axis has an explain system — structured dicts for tools, human-readable text for you:
explain_schema(User) # === User === # [SchemaName('users')] # # id (int): # [Identity] # # email (str): # [Unique, MaxLen(255)] # cli: Help('Email address') # openapi: Description('User email'), Format('email') # sql: Index('idx_email') explain_application(app) # === Application (3 endpoints) === # # Endpoint #1 (2 exposures): # [POST /api/v1/players] RequestResponseCodec # request: RegisterRequest, response: RegisterResponse # [register (cli)] RequestResponseCodec # request: RegisterRequest, response: RegisterResponse explain_full(User) # 3-layer trace # === User (full trace) === # # Schema: 3 fields (1 identity) # id (int) [Identity] # name (str) # email (str) [Unique] # # Derivation: 1 pattern # Pattern #1: Dialect (11 steps), provider=Users # steps: InspectEntity → RequireIdentity → BindProvider → ... # ops: List, Get, Create, Update, Patch, Delete # # Surface: 6 exposures across 1 endpoint # GET /api/users [ListUserRequest → ListUserResponse] # GET /api/users/{id} [GetUserRequest → GetUserResponse] # ...
Schema, query, storage, surface, compilation trace, derivation pipeline — all explainable. No execution, no side effects. The program describes itself from its own IR.
Verified at import time
verify catches semantic contradictions before your code runs:
from emergent.wire.verify import verify_raising @dataclass class Sensor: id: Annotated[int, Identity] name: Annotated[str, MinLen(50), MaxLen(10)] # ERROR: MinLen > MaxLen temp: Annotated[float, Min(200), Max(125)] # ERROR: Min > Max secret: Annotated[str, ReadOnly(), WriteOnly()] # ERROR: inaccessible field verify_raising(Sensor) # VerificationError with all issues
Three built-in phases — numeric constraints, length constraints, semantic flags — each running as a standard compilation phase. Open-world: add your own verification phases without modifying emergent.
Four levels of control
# Level 1 — auto CRUD: one decorator, full API @schema_meta(http_crud("/products", Store)) @dataclass class Product: id: Annotated[int, Identity] name: str price: float # Level 2 — CRUD + methods: derive CRUD, hand-write domain logic @schema_meta(http_crud("/bounties", Board, ops=(LIST, GET, CREATE)), Methods()) @dataclass class Bounty: id: Annotated[int, Identity] title: str reward: int @classmethod @post("/bounties/{bounty_id}/claim") async def claim(cls, db: ..., bounty_id: int, hunter: str) -> Result[Bounty, DomainError]: ... # Level 3 — hand-written methods: every endpoint explicit, full control @schema_meta(Methods()) @dataclass class Auth: @classmethod @post("/login") async def login(cls, creds: Credentials) -> Result[Token, AuthError]: ... # Level 4 — raw wire: one endpoint, three targets endpoint(runner) .expose(HTTPRouteTrigger("POST", "/register"), rrc(Req, Resp)) .expose(CLITrigger("register"), rrc(Req, Resp)) .expose(TelegrindTrigger(Command("register")), rrc(Req, Resp))
Pick what fits. Mix in one app. Drop down a level when you need control, stay high when you don't.
Semantic transforms
Transforms in emergent dispatch on domain meaning, not syntax. This is a novel mechanism — no existing macro system combines domain-semantic awareness with compositional algebra:
@schema_meta( http_crud("/posts", Posts), WithoutDelete(), # ← removes DELETE op across all targets Paginated(20), # ← adds pagination to ops with Pageable effect Sorted(), # ← adds sorting to LIST Filtered("author"), # ← adds exact-match filter ) @dataclass class Post: id: Annotated[int, Identity] title: str body: str author: str
Capabilities stack as arguments in @schema_meta() — frozen data in, frozen data out. They compose because they operate on algebraic structure, not string templates or AST nodes.
Examples
| Example | What it shows |
|---|---|
roulette/ |
HTTP + CLI + Telegram from one codebase |
cross_compile/ |
Bridge legacy FastAPI → CLI |
full_stack/ |
Full-stack example |
wiring.py |
Raw wire: endpoint + trigger + codec |
Tutorial
A story-driven, 27-chapter walkthrough — from first API to handing your codebase to a coding agent.
Start here → docs/tutorial/00-intro.md
| Part | Chapters | What you'll build |
|---|---|---|
| I–IV | 01–14 | CRUD, methods, transforms, auth, nested resources, multi-target, custom dialects, raw wire, bridge |
| V–VI | 15–18 | Query axis, providers, ops & runners, scope & DI |
| VII–VIII | 19–24 | Enrichers, storage, compilation internals, stateful codecs, roulette walkthrough, design philosophy |
| IX | 25–27 | Verify & explain, why emergent is LLM-native, agent workflows |
Docs
docs/intro.md |
Introduction (EN) |
docs/intro_ru.md |
Введение (RU) |
docs/essence.md |
The essence — one function, one operator |
docs/philosophy.md |
Design philosophy |
docs/theory/architecture.md |
Architecture — theory, invariants, algebraic properties |
docs/internal/wire-reference.md |
Wire reference — axes, capabilities, compile, bridge |
docs/internal/cheatsheet.md |
Cheatsheet — all axes, every import, every pattern |
docs/theory/universal-derivation.md |
Derivation — entity → endpoints via fold |
docs/theory/compiler-deep-dive.md |
Compiler deep-dive — developing custom compilers |
docs/emergent-and-ai.md |
emergent + AI agents |
docs/book/ |
Book — 5-chapter SICP-style deep dive into compilation thinking |
Where we are
emergent is young — started January 2026. Already runs in production. The core architecture (fold, CompilationPhase, SchemaCompiler, TargetCompiler, verify, explain, derive) is stable. What's still growing: the ecosystem, the stdlib, the number of built-in targets and dialects. Breaking changes happen, but we keep them well-motivated.
Stack
| Layer | What |
|---|---|
| deployme.py | Application → infrastructure (compose, k8s) |
| emergent | platform: fold, CompilationPhase, SchemaCompiler, TargetCompiler |
| emergent.wire | libraries: axes (schema, surface, storage, query), derive, bridge, verify |
| emergent.graph | runtime: Composer, ScopeFamily, RuntimePolicy (Cooperative / WorkStealing) |
| emergent.ops/saga/cache | patterns: data-driven dispatch, compensation chains, tiered caching |
| nodnod | typed dependency graphs, auto-parallelization, Either, Scope |
| combinators.py | retry, timeout, fallback, race |
| kungfu | Result, Option, LazyCoroResult |
Define a context. Define a protocol. Call fold.
You just created a compilation language.