ESC

Type to search...

IOP Levels

IOP has two orthogonal concepts that people confuse:

  1. Code levels (how you write Intents): Dict, TypedDict, Dataclass
  2. Intent levels (what the pipeline does): Ephemeral, Standard, Critical

This page covers both. The code levels determine how much structure you get. The Intent levels determine how much infrastructure runs.


Intent Levels: What the Pipeline Does

Before diving into code levels, understand the three Intent levels. These are the heart of IOP: they determine which processors run, how long you have, and what infrastructure backs you.

Ephemeral — “I don’t care if this disappears”

Pipeline: validate (that’s it) Timeout: 5 seconds Mindset: Fast, disposable, no overhead

# Cache lookup — result can vanish, nobody cares
GET_CACHE = Intent(name="cache_check", level=Level.EPHEMERAL)

# Session check — temporary by definition
CHECK_SESSION = Intent(name="check_session", level=Level.EPHEMERAL)

# Health check — pure liveness probe
HEALTH = Intent(name="health_check", level=Level.EPHEMERAL)

# Game state — position updates, frame-by-frame
PLAYER_MOVE = Intent(name="player_move", level=Level.EPHEMERAL)

Real-world analogy: Checking the weather. You look, you know, you move on. No paperwork, no authorization, no audit trail. If the data is wrong, you’ll check again in 5 minutes.

What runs: Only validate, which makes sure the data shape is correct. No auth, no audit, no protection. The runtime trusts this Intent is cheap.

When to use: Anything where losing the result is inconvenience, not damage. Cache hits, session lookups, temporary state, health checks, telemetry pings, game position updates.

Standard — “Normal business data”

Pipeline: validateauthorize Timeout: 10 seconds Mindset: Balanced: check inputs, check permissions, done

# User profile — someone's identity, worth protecting
GET_PROFILE = Intent(name="get_profile", level=Level.STANDARD)

# Blog post — public content, but author matters
CREATE_POST = Intent(name="create_post", level=Level.STANDARD)

# Order status — business data, needs auth
CHECK_ORDER = Intent(name="check_order", level=Level.STANDARD)

# Chat message — needs to know who's talking
SEND_MESSAGE = Intent(name="send_message", level=Level.STANDARD)

Real-world analogy: Showing your ID at a reception desk. They verify who you are (authorize), then let you in. No cameras, no guards, no paperwork, just a quick identity check.

What runs: validate (data shape) + authorize (permissions). The auth plugin checks if your role is sufficient. If you’re a viewer trying to edit, you get rejected.

When to use: Most business operations. User profiles, posts, comments, settings, general CRUD. The bread and butter of any application.

Critical — “This must never be lost”

Pipeline: validateauthorizeauditprotect Timeout: 30 seconds Mindset: Full protection: every step logged, every action audited

# Payment — real money, real consequences
PROCESS_PAYMENT = Intent(name="process_payment", level=Level.CRITICAL)

# Medical record — legal requirements
SAVE_MEDICAL = Intent(name="save_medical_record", level=Level.CRITICAL)

# Legal document — must be immutable and auditable
SIGN_CONTRACT = Intent(name="sign_contract", level=Level.CRITICAL)

# Admin action — elevated privileges, full audit
DELETE_USER = Intent(name="delete_user", level=Level.CRITICAL)

Real-world analogy: Wire transferring a million dollars. You sign papers (authorize), a camera watches you (audit), a guard stands by (protect), and there’s a paper trail that lasts forever.

What runs: The full pipeline. validateauthorizeaudit (logs everything) → protect (rate limits, circuit breaker). Every step is recorded. Every action is traceable.

When to use: Anything where losing data or making an unauthorized change has real consequences. Payments, medical records, legal documents, authentication, admin operations, data deletion.


How Levels Affect Pipelines

The level you choose determines which processors run by default:

LevelDefault PipelineTimeout
Ephemeralvalidate5s
Standardvalidate, authorize10s
Criticalvalidate, authorize, audit, protect30s

Processors are just registered functions. You can replace, remove, or add any processor at any level:

# Ephemeral: fast path, minimal infrastructure
CACHE_HIT = Intent(name="cache_hit", level=Level.EPHEMERAL)
# → validate → handler (5s timeout)

# Standard: balanced, auth required
GET_USER = Intent(name="get_user", level=Level.STANDARD)
# → validate → authorize → handler (10s timeout)

# Critical: full protection, everything logged
PROCESS_PAYMENT = Intent(name="process_payment", level=Level.CRITICAL)
# → validate → authorize → audit → protect → handler (30s timeout)

Code Levels: How You Write Intents

Now that you understand Intent levels (what the pipeline does), let’s look at code levels (how you structure your code).

Level 1: Dict + Functions

When: Scripts, small tools, <10 commands, single file.

The simplest form of IOP. Data is a dict. Processors are functions. The pipeline is a list.

from evoid import Intent, Level, execute
from evoid.core import Context
from evoid.core.extend import add_intent_with_pipeline

# Level 1: Data is just a dict
state = {"order_id": "ORD-001", "items": ["pizza", "salad"], "total": 25.99}

# Level 1: Processors are plain functions
async def validate_order(ctx: Context) -> dict:
    items = ctx.state.get("items", [])
    if not items:
        raise ValueError("Empty order")
    return {"valid": True}

async def calculate_total(ctx: Context) -> dict:
    items = ctx.state.get("items", [])
    total = len(items) * 12.99  # simplified
    ctx.state["total"] = total
    return {"total": total}

# Level 1: Register with custom pipeline
intent = Intent(name="place_order", level=Level.STANDARD)

add_intent_with_pipeline(
    intent,
    processors=["validate_order", "calculate_total"],
)

result = await execute(intent)
# result.value = {"total": 25.98}
async def clean_data(ctx):
    raw = ctx.state["raw"]
    ctx.state["cleaned"] = [r.strip() for r in raw if r]
    return {"rows": len(ctx.state["cleaned"])}

async def save_to_file(ctx):
    data = ctx.state["cleaned"]
    with open("output.csv", "w") as f:
        f.writerows(data)
    return {"saved": True}

intent = Intent(name="etl_pipeline", level=Level.EPHEMERAL)
add_intent_with_pipeline(intent, processors=["clean", "save"])

result = await execute(intent)
```

What you get: Dicts for data, functions for logic, pipeline for composition. What you don’t get: Type safety, IDE autocomplete, validation.

Level 2: TypedDict + Compose

When: Medium CLIs, 10-30 commands, solo developer, need type hints.

Add type hints to your dicts. The structure becomes visible to your IDE.

from typing import TypedDict, NotRequired
from evoid import Intent, Level, execute
from evoid.core import Context

# Level 2: TypedDict — your IDE knows the shape
class OrderState(TypedDict, total=False):
    order_id: str
    items: list[str]
    total: float
    validated: bool
    error: str | None

# Level 2: Processors are typed
async def validate_order(ctx: Context) -> dict:
    items = ctx.state.get("items", [])
    if not items:
        ctx.state["error"] = "Empty order"
        raise ValueError("Empty order")
    ctx.state["validated"] = True
    return {"valid": True}

async def calculate_total(ctx: Context) -> dict:
    items = ctx.state.get("items", [])
    total = len(items) * 12.99
    ctx.state["total"] = total
    return {"total": total}

async def apply_discount(ctx: Context) -> dict:
    total = ctx.state.get("total", 0)
    if total > 50:
        ctx.state["total"] = total * 0.9  # 10% off
    return {"discounted": True}

# Level 2: Pipeline is explicit
from evoid import register_processor
from evoid.core.extend import add_intent_with_pipeline

intent = Intent(name="place_order", level=Level.STANDARD)

add_intent_with_pipeline(
    intent,
    processors=["validate_order", "calculate_total", "apply_discount"],
)

result = await execute(intent)
class InventoryState(TypedDict, total=False):
    product_id: str
    quantity: int
    warehouse: str
    reserved: bool

async def check_stock(ctx: Context) -> dict:
    # IDE knows: ctx.state["quantity"] is int
    qty = ctx.state.get("quantity", 0)
    if qty <= 0:
        raise ValueError("Out of stock")
    return {"in_stock": True}
```

What you get: Type hints, IDE autocomplete, structured data without classes. What you don’t get: Immutability, schema validation, complex state machines.

Level 3: Dataclass + Decorator

When: Production systems, teams 5+, complex state machines, need validation.

Frozen dataclasses for immutable data. Decorators for registration. Full IOP.

from dataclasses import dataclass, field
from evoid import Intent, Level, execute
from evoid.core import Context
from evoid.core.extend import add_intent_with_pipeline

# Level 3: Frozen dataclass — immutable, validated, thread-safe
@dataclass(frozen=True)
class OrderState:
    order_id: str = ""
    items: tuple[str, ...] = ()  # tuple, not list — immutable
    total: float = 0.0
    validated: bool = False
    error: str | None = None

# Level 3: Processors are typed, registered, composable
async def validate_order(ctx: Context) -> dict:
    items = ctx.state.get("items", ())
    if not items:
        raise ValueError("Empty order")
    return {"valid": True}

async def calculate_total(ctx: Context) -> dict:
    items = ctx.state.get("items", ())
    total = len(items) * 12.99
    return {"total": total}

# Level 3: Intent with full control
PLACE_ORDER = Intent(
    name="place_order",
    level=Level.STANDARD,
    timeout=10.0,
    priority=0,
)

# Level 3: Register and execute with full Result
add_intent_with_pipeline(
    PLACE_ORDER,
    processors=["validate_order", "calculate_total"],
)

result = await execute(PLACE_ORDER)

if result.success:
    print(f"Done in {result.duration:.3f}s")
    print(f"Processors: {result.processors}")
else:
    print(f"Failed: {result.error}")
@dataclass(frozen=True)
class PaymentResult:
    transaction_id: str
    status: str
    amount: float
    currency: str

PROCESS_PAYMENT = Intent(
    name="process_payment",
    level=Level.CRITICAL,
    timeout=30.0,
    priority=100,
    metadata={"currency": "USD"},
)

add_intent_with_pipeline(
    PROCESS_PAYMENT,
    processors=["validate_payment", "charge_card", "send_receipt"],
)

# Pipeline runs:
# 1. validate (built-in) — checks data shape
# 2. authorize (built-in) — checks your role
# 3. audit (built-in) — logs everything
# 4. protect (built-in) — rate limit, circuit breaker
# 5. validate_payment (yours) — business validation
# 6. charge_card (yours) — payment logic
# 7. send_receipt (yours) — notification
```

What you get: Frozen dataclasses, full Result, pipeline control, plugin system. What you don’t get: Simplicity: more code, more concepts.


Comparison

Code Levels

FeatureLevel 1Level 2Level 3
DatadictTypedDictdataclass(frozen=True)
Type hintsNoYesYes + validation
ImmutabilityNoNoYes
RegistrationManualManualDecorator or manual
PipelineList of namesList of namesList of names + config
Best forScriptsMedium CLIsProduction systems

Intent Levels

LevelPipelineTimeoutPlugins ActiveUse Case
Ephemeralvalidate5sCache, transportSessions, cache, game state
Standardvalidateauthorize10sAuth, storageProfiles, posts, orders
Criticalvalidateauthorizeauditprotect30sAuth, audit, storage, rate limitPayments, medical, legal

How They Combine

The magic: code levels and Intent levels are independent. You can use Level 1 code with Critical Intent, or Level 3 code with Ephemeral Intent.

# Level 1 code + Critical Intent (works, but you lose type safety)
intent = Intent(name="payment", level=Level.CRITICAL)

# Level 3 code + Ephemeral Intent (overkill, but works)
@dataclass(frozen=True)
class CacheKey:
    key: str

CACHE_GET = Intent(name="cache_get", level=Level.EPHEMERAL)

Recommendation: Match the code level to your team size and project maturity. Match the Intent level to your data’s criticality.


When to Upgrade

SignalAction
”I keep passing the wrong keys”Upgrade code to Level 2 (TypedDict)
“Two devs keep breaking state”Upgrade code to Level 3 (frozen dataclass)
“I need to audit who changed what”Upgrade Intent to Level CRITICAL
”Auth is too slow for this endpoint”Downgrade Intent to Level EPHEMERAL
”I’m over-engineering this”Stay at Level 1 code, use the simplest Intent level that fits