ESC

Type to search...

Your First Intent

Build a sandwich order system in 5 minutes. One file, one Intent, one processor.

Sandy runs a small sandwich shop. Paper orders get lost. Let’s fix that with a simple EVOID program.

The Smallest Possible EVOID Program

import asyncio
from evoid import Intent, Level, execute
from evoid.core.extend import add_intent

# 1. Define what you want
ORDER_SANDWICH = Intent(
    name="order_sandwich",
    level=Level.STANDARD,
    metadata={"shop": "Sandy's Sandwiches"},
)

# 2. Define how to do it
async def handle_order(ctx) -> dict:
    sandwich = ctx.intent.metadata.get("sandwich", "unknown")
    qty = ctx.intent.metadata.get("qty", 1)
    return {
        "status": "confirmed",
        "order": sandwich,
        "quantity": qty,
        "total": qty * 8.99,
    }

# 3. Wire it together
add_intent(ORDER_SANDWICH, handle_order)

# 4. Execute
async def main():
    result = await execute(ORDER_SANDWICH)
    print(result.value)

asyncio.run(main())
python main.py
# {'status': 'confirmed', 'order': 'BLT', 'quantity': 2, 'total': 17.98}

That’s IOP. Three lines of setup, one line of execution.

What Just Happened?

ORDER_SANDWICH (Intent — what you want)

execute() (Runtime — builds pipeline, runs processors)

handle_order (Processor — how to do it)

Result (Data — what you got)

Intent = data that declares purpose. It carries a name, a level, and metadata. Processor = a function that does the work. Takes an Intent, returns a result. Pipeline = the chain of processors. Here it’s just one step: handle_order. Result = the output. Success or failure, with timing.

Adding a Level

Sandy’s BLT is popular but takes longer. More importantly, some operations need different treatment:

from evoid import Intent, Level

# Ephemeral — "I don't care if this disappears"
VIEW_MENU = Intent(
    name="view_menu",
    level=Level.EPHEMERAL,  # Fast, disposable, no overhead
)

# Standard — "Normal business data"
ORDER_SANDWICH = Intent(
    name="order_sandwich",
    level=Level.STANDARD,  # Balanced — auth check, reasonable timeout
)

# Critical — "This must never be lost"
PROCESS_PAYMENT = Intent(
    name="process_payment",
    level=Level.CRITICAL,  # Full protection — audit, rate limit, 30s timeout
)

Three levels, three behaviors:

LevelPipelineTimeoutReal-World Analogy
ephemeralvalidate5sChecking the weather — glance, know, move on
standardvalidate, authorize10sShowing ID at reception — verify who you are
criticalvalidate, authorize, audit, protect30sWire transfer — papers, cameras, guards, paper trail

You choose the level. The runtime handles the infrastructure.

# Placing an order needs to know who's ordering
# Auth check, but no audit trail needed
ORDER = Intent(name="place_order", level=Level.STANDARD)
# Pipeline: validate → authorize → handler (10s)

# Processing a payment — real money, real consequences
# Full audit, rate limiting, protection
PAYMENT = Intent(name="process_payment", level=Level.CRITICAL)
# Pipeline: validate → authorize → audit → protect → handler (30s)
```

Adding More Intents

Sandy needs to manage the menu too:

from evoid import Intent, Level, execute
from evoid.core.extend import add_intent

# Define intents
ORDER_SANDWICH = Intent(
    name="order_sandwich",
    level=Level.STANDARD,
    metadata={"shop": "Sandy's Sandwiches"},
)

VIEW_MENU = Intent(
    name="view_menu",
    level=Level.EPHEMERAL,  # Fast, no persistence needed
    metadata={"shop": "Sandy's Sandwiches"},
)

# Define processors
async def handle_order(ctx) -> dict:
    sandwich = ctx.intent.metadata.get("sandwich", "BLT")
    qty = ctx.intent.metadata.get("qty", 1)
    return {"status": "confirmed", "order": sandwich, "quantity": qty}

async def handle_menu(ctx) -> dict:
    return {
        "menu": [
            {"name": "BLT", "price": 8.99},
            {"name": "Club", "price": 9.99},
            {"name": "Veggie", "price": 7.99},
        ]
    }

# Register everything
add_intent(ORDER_SANDWICH, handle_order)
add_intent(VIEW_MENU, handle_menu)
# Execute any intent by name
result = await execute(ORDER_SANDWICH, sandwich="Club", qty=3)
# {'status': 'confirmed', 'order': 'Club', 'quantity': 3}

!!! warning “What add_intent() actually does” add_intent() creates a pipeline with only your handler. The level’s default processors (validate, authorize, etc.) are skipped. Good for learning, not for production.

For the full level pipeline, use `add_intent_with_pipeline()`:

```python
from evoid.core.extend import add_intent_with_pipeline

add_intent_with_pipeline(
    ORDER_SANDWICH,
    processors=["validate", "authorize", handle_order],
)
# Pipeline: validate → authorize → handle_order
```

Processors can be strings (registered names) or callables (functions). The level determines the default pipeline — see [IOP Levels](../learn/iop-levels.md).

Using Context

Processors share data through a Context object. One processor writes, the next reads. Think of it as a conveyor belt in Sandy’s kitchen:

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

CHECK_INVENTORY = Intent(name="check_inventory", level=Level.STANDARD)
PREPARE_ORDER = Intent(name="prepare_order", level=Level.STANDARD)

async def check_inventory(ctx: Context) -> dict:
    """Step 1: Check if we have ingredients."""
    sandwich = ctx.intent.metadata.get("sandwich", "BLT")
    ctx.state["sandwich"] = sandwich
    ctx.state["in_stock"] = True  # Simplified check
    return {"checked": True}

async def prepare_order(ctx: Context) -> dict:
    """Step 2: Prepare the sandwich."""
    sandwich = ctx.state.get("sandwich")  # Reads what check_inventory wrote
    in_stock = ctx.state.get("in_stock", False)
    if not in_stock:
        return {"error": "Out of stock"}
    return {"status": "preparing", "sandwich": sandwich}

add_intent(CHECK_INVENTORY, check_inventory)
add_intent(PREPARE_ORDER, prepare_order)

ctx.state is shared between processors — data flows from one step to the next. ctx.intent is the current Intent (immutable). ctx.deps is for injected dependencies like databases and caches (covered later).

# Processor 2 reads from ctx.state:
sandwich = ctx.state.get("sandwich")  # "BLT"

# It's like passing a ticket down the kitchen line.
# Each station reads what the previous one wrote.
```

What You Learned

ConceptWhat It Is
IntentData that declares purpose — name, level, metadata
LevelInfrastructure behavior — ephemeral/standard/critical
ProcessorPure function that does the work
PipelineChain of processors executed in order
ContextShared state between processors
ResultOutput — success/failure with timing

Next: The Menu

Now that Sandy can take orders, let’s build a proper menu system with The Menu.