Architecture · design notes

Meet Wippy.

An open-source, actor-model runtime for agentic systems. A few decisions shape the whole thing. Here is each one.

01   the language

Just Lua.

Small enough to read on day one, strict enough to trust.

Lua is small: an AI writes it and you read it without a manual. Wippy runs it typed, linted, and capability-scoped, so mistakes are caught before they execute and generated code only touches what you grant. Underneath sits the full Go ecosystem, reachable as modules, with WASM and Temporal for heavier compute; the runtime is open source (MPL-2.0) and extensible in Go.

local funcs = require("funcs")

-- typed; returns (value, nil) or (nil, error)
local function plan_for(id: integer): (string?, error?)
    local user, err = funcs.call("api:get_user", id)
    if err then return nil, err end
    return user.plan
end
02   the execution model

The actor model.

Isolation, concurrency, and recovery from one rule.

Code runs as lightweight processes that share nothing and talk by message. A crash stays contained; the scheduler runs thousands of them with no locks; and a supervisor restarts whatever fails instead of letting it cascade.

process own state process own state process own state msg msg
no shared memory · a crash is contained · a supervisor restarts it
03   going multi-node

One node, or many.

Address a process by name, not a machine.

Actors are addressed by name, not by machine, so the same code runs on one node or many. Gossip tracks which nodes are alive with no central coordinator; a bounded Raft core agrees on the few values that need one source of truth. Spawn, send, and supervise behave the same whether the target is local or remote.

send by name → routed to the owner noderaft proc noderaft proc node proc · · · · gossip membership · · · ·
gossip for membership · bounded Raft for one truth · your code doesn't change
04   how an app is defined

Everything is an entry.

One versioned store, not config plus code plus a database.

Every part of an app is a typed entry, and its kind decides what it becomes. Change one while it runs and the system reacts; every change is versioned and rolls back in a call. That's what makes editing a live app, by a person or an agent over MCP, safe.

REGISTRY live · versioned api:get_userkind: http.endpoint workers:emailerkind: process.lua app:databasekind: sql.database HTTP server running process connection pool
the kind decides what an entry becomes · change it live · roll it back
05   what code may do

Security is a capability.

Nothing runs with power it wasn't granted.

Every request carries an actor and a scope; declarative policies weigh the action, the resource, and metadata, and decide before it runs. In a multi-tenant system that's the isolation boundary itself: one policy set enforced centrally, not re-checked in every handler.

Actor + Scope who · metadata Policy action · resource ✓ Allow ✗ Deny
checked on every request, before the action runs