← Workstreams

Workstream: LambdaServer

Status: Planned · Component: Maximize developer productivity

This document is an aspirational vision and design-scope document, not a milestone plan. It describes the end-state we are building toward and the architecture decisions that define it; decomposition into concrete tasks and milestones happens later. The MVP vs. mature-platform split is the closest thing here to sequencing.

North star

Everything required to run, secure, observe, evolve, and monetize remote functions — without forcing developers to become distributed-systems experts.

Make running a unit of code in the cloud a zero-infrastructure step. A developer registers a function (or a simple service) and invokes it on demand — without provisioning a server, writing a Dockerfile, or thinking about where or when it runs. "I just need to run this code remotely" collapses to register-and-invoke; everything around the code — discovery, placement, isolation, authentication, billing, observability, versioning — is supplied by the platform, solved once, for every function.

The five verbs in the framing sentence are the five pillars of the design, and each maps to a design section below:

Guiding principles

  • The platform owns the distributed-systems problems; the function owns only domain logic. Discovery, load balancing, retries, isolation, health, tracing, quota, and billing are platform concerns implemented once — never boilerplate repeated in every registered unit of code.
  • Serializable in, serializable out, every call independent. The contract is deliberately constrained: parameters and return values must be serializable, and a follow-up call is a completely separate call — no session, no affinity, no in-memory state carried between invocations. This constraint is not a limitation to apologize for; it is what makes load balancing, side-by-side versioning, retry, scale-to-zero, and per-call billing tractable — and what lets the platform choose where execution happens (the caller's own process, a fused chain, the shared pool, a host colocated with the data, or a homed instance) without changing a call's meaning.
  • The caller pays. Every invocation is a W3Wallet-billed operation funded by the caller, not the function's owner. This inverts the public-cloud default (where the owner foots the bill for whoever invokes) — so publishing a function is safe by default and monetizable by default.
  • A library first, a hosted service second. LambdaServer sits on the deployment spectrum: the same Api is consumable as an embeddable in-process library, a self-hosted subservice on the user's own infrastructure, or the managed hosted instance at lambdaserver.wasmserver.com. Per the Decentralized by Default philosophy, nobody is forced through a centralized service to run remote functions — embedding LambdaServer in your own app is a first-class mode, not a fork. See design §9.
  • Mitigations must be loud. Rate limits, circuit breakers, and health-driven restarts protect the shared platform, but they must never silently mask defects: every trip, throttle, and restart is a first-class observable event that preserves the underlying failure evidence. A tripped circuit is an alarm, not a fallback.
  • Compose with the platform, don't duplicate it. Identity, quota, and payment come from W3Wallet; monitoring feeds ProductionHealth; transport is url://; storage candidates are LambdaStore, SimpleFileSystem, and the Event Log. LambdaServer should be remarkable for what it doesn't reimplement.
  • Meet code where it already lives. Registration accepts Maven coordinates, an uploaded fat JAR, or a git repository built on the fly (Gradle/Maven/kompile auto-detected) — no LambdaServer-specific packaging step. It also accepts a skill-style markdown document: a function defined in prose and executed by a bound agent (design §11) — prose is a fourth place code lives.

The programming model

Two tiers, sharing one invariant — serializable parameters and return values, per the contract defined by the Serialization workstream — plus an optional ergonomics layer on top. Within the function tier, a definition is either code (Maven artifact, uploaded JAR, built-from-git) or a skill-style markdown document executed by an agent — same contract, same registry entry, different backend (design §11).

Functions — define a function, we handle the rest

The base tier: the user registers a single function and the platform handles the rest. Parameters and the return value must be serializable. A follow-up call is a completely separate call — the platform may run it on a different executor, against a different version, after a cold start, with no memory of the previous call. Functions are therefore trivially placeable, balanceable, retryable by their callers, and billable per call. The platform itself never retries: one accepted request is one execution and one bill — retry policy belongs to the caller, idempotency to the function implementer (see billing).

Services — a managed lifecycle for code that needs setup

For code with expensive setup (connection pooling, caches, loaded models), the user implements a ServiceImplementation interface exposing serviceStartup() and serviceShutdown() — the owner's opportunity to do setup and cleanup, invoked by the platform when it starts or drains an instance. The set of exposed functions is exactly the functions on the service interface — essentially global/static functions — still with serializable parameters and return values. Callers needing object-oriented state pass identifiers rather than object references; the default interface may not be the most ergonomic, but it is simple and straightforward, and it keeps the platform's freedoms (placement, balancing, side-by-side versions) intact. Out of the box, a service gets authentication/authorization via W3Wallet and billing via W3Wallet — neither is the owner's code to write.

Markdown functions — prose definitions, agent execution

The function tier's fourth definition format: instead of code, the owner registers a skill-style markdown document — YAML frontmatter declaring the function's name, description, typed parameter schema and return schema (the same serializable contract as every function, per Serialization), and the capabilities it needs; the body is natural-language instructions. Invocations are executed by a bound agent as if the markdown were code, and an optional maintainer agent compiles the document into real code that serves the same function with the agent as fallback. The registry entry has the same shape as any function's — a caller cannot tell, and never needs to know, which backend fulfilled a call. Full design in design §11. Markdown definitions cover the function tier only — per-invocation agent execution is stateless by construction, so there is no markdown ServiceImplementation.

Client libraries — optional ergonomics over the raw API

Optionally, the owner can provide a client library — as source, a binary, or a Maven artifact — that papers over the raw serializable API with an idiomatic one (real types, builders, suspend functions, identifier handling hidden). The platform contract remains the raw API; the client library is sugar distributed alongside the function, the same way LambdaServerApiClientImplementation already wraps workspace execution behind the kompile.Workspace interface.

Current state — built vs. aspirational

This exists today as the LambdaServer family — a remote code-execution / serverless platform for Kotlin, modeled after the kotlin.build server and hosted at lambdaserver.wasmserver.com:

Repository What it provides
LambdaServerApi Transport-neutral interfaces and data types for function registration, invocation, workspace synchronization/build/test, and typed job records
LambdaEmbedded In-process FunctionService implementations plus WorkspaceManager, typed uploaded-JAR analysis, parameter-policy resolution, advisory execution limits, and invocation-observation support
LambdaServer The thin execution server: workspace sync, build execution, and function invocation through the typed url://lambdaserver/ service; local or remote (LambdaStore) storage modes; addressable with path-based URLs for individual functions (url://lambdaserver/functions/{id}) and invocations (url://lambdaserver/invocations/{id})
LambdaServerApiClientImplementation Typed client implementations for the LambdaServer contracts, including UrlLambdaService and RemoteLambdaWorkspace for url:// and remote workspace operations
LambdaServerCli The single function-management CLI for create, invoke, list, delete, and get; the LambdaCli repository redirects here
LambdaServerWui HTTP browser UI over the typed url:// client to register functions (Maven artifact / uploaded JAR / built-from-git), configure per-parameter behavior (caller-provided / default / override), and invoke (sync/async, invocation tracking); it has no WebSocket console
LambdaStoreApi Interface definitions for function, JAR, invocation, source-provenance, parameter-policy, and durable invocation-observation records
LambdaStoreApiClientImplementation Typed url:// client that opens sandboxed connections to the LambdaStore store interfaces
LambdaStore Storage service for function definitions, JARs, source-provenance and parameter-policy metadata, and invocation records with optional durable observations

It is already used in practice — e.g. the *RefreshCallback functions that fire when a GithubWatchman webhook triggers. So this workstream is adopt-and-mature, not build-from-scratch.

The current LambdaServer transport is typed url:// only; the former HTTP/Jetty and WebSocket server interfaces are gone. The WUI is an HTTP browser facade over that client path, and its previously claimed WebSocket console is not present.

Already built: the function tier of the programming model (register by id/class/method/params, serializable values); WUI-side artifact preparation from Maven, uploaded JAR, or git (not a three-source platform registry capability); sync and async invocation with invocation tracking; per-parameter configuration; url://lambdaserver/ reachability with path-based function/invocation URLs; pluggable storage (local or LambdaStore). The layered implementation now includes the transport-neutral LambdaServerApi contracts and the LambdaEmbedded function and workspace implementations, including WorkspaceManager, parameter-policy resolution, and invocation observations. It also includes advisory in-process execution limits, hardened workspace extraction and recovery, the A6 server wiring that passes FunctionService and WorkspaceService into the URL RPC handler, B1 source-provenance and parameter-policy metadata, B3 typed uploaded-JAR analysis, and C5 durable invocation observations through LambdaStore.

Open implementation work: B4 Maven-source registration is tracked in the open LambdaEmbedded pull request; A7 serving-lifecycle extraction is tracked in the open LambdaServer pull request; and D1 immutable versioning is tracked in the open LambdaStoreApi pull request and the open LambdaStore pull request. These changes are not complete on main.

Aspirational (the substance of this workstream): the remaining parts of the design — the ServiceImplementation service tier and client-library distribution; markdown-defined, agent-executed functions with maintainer compilation and agent fallback (design §11); W3Wallet capability provisioning and complete caller-pays billing, metering, and settlement; a complete process or container isolation boundary for hosted code beyond the optional child-JVM executor and advisory in-process limits; an executor pool with load balancing; full health, tracing, and metrics integration; rate limiting and circuit breaking; side-by-side versioning and formalized hot deployment; and completion of the standard layered serving lifecycle.

The design

A capability map of the platform — what each pillar buys the developer:

Category Capability What the developer gets
Run Registry & discovery Clients look up functions dynamically; nothing hard-codes where code runs
Run Load balancing Invocations routed to the least-busy executor; scale-out without client changes
Run Isolation & limits A runaway function cannot starve the host or its neighbors
Run Deployment spectrum Embed the platform in-process, self-host it, or use the managed instance — same Api
Run Flexible execution placement Client-side execution, call-chain fusion, and data-locality placement eliminate round trips, IPC, serialization, and wide-area data transfer where they aren't needed
Run Markdown (agent-executed) functions Define a function in prose; an agent executes it, a maintainer compiles it to code, and callers can't tell
Secure W3Wallet authn/authz Who may register and who may invoke, capability-gated, no auth code in the function
Secure Capability provisioning Functions exercise granted secrets (API keys, etc.) they never see
Observe Centralized logs & tracing Debugging distributed "heisenbugs" without ssh-ing anywhere
Observe Health checks & metrics Know the black box is actually working: latency, throughput, error rates
Evolve Side-by-side versioning & hot deploy Ship V2 without breaking V1 callers or taking anything offline
Protect Rate limiting Fair use — no caller monopolizes the platform
Protect Circuit breaking Partial failure doesn't cascade — and never fails silently
Monetize Caller-pays billing Every registered function is a sellable API with zero billing code

1. Registry and discovery

The function catalog is the service registry — a single authoritative directory of every registered function and service, what version(s) of each are live, and where they can be executed. Clients perform dynamic lookup: a function is addressed by its stable identity (url://lambdaserver/functions/{id} already works today), never by host or port. For the service tier, executor instances register on startup and deregister on shutdown (the platform calls serviceStartup()/serviceShutdown() at exactly those edges), so the directory always reflects what is actually invocable. The registry is also where client libraries, parameter configuration, pricing, and version metadata live — one place to ask "what is this function and how do I call it?"

2. Placement, load balancing, and the executor pool

Because the function contract is stateless and serializable, any executor is eligible to run any invocation — that is the freedom the programming model buys. The deliberate exception is a homed function — pinned to a specific instance because it wraps a secret or needs particular hardware or network locality (design §9); for a homed function, placement is the route, not a free choice. Placement also generalizes beyond the pool entirely — to the caller's own process and to fused chain images (design §10). The platform maintains a pool of executor workers; when multiple instances of the same function or service are warm, invocations route to the least-busy instance. Placement decisions (which host, warm vs. cold instance, when to reap idle instances) are invisible to callers. Service-tier instances are warmed via serviceStartup() before receiving traffic and drained via serviceShutdown() before being reaped — so scale-out, scale-in, and rebalancing never drop in-flight work. The pool starts as one host under ContainerNursery; multi-host is an explicit open question.

3. Observability and health

Developers need to know their "black box" is actually working:

  • Centralized logging. Every invocation's output is captured and queryable by function, version, caller, and invocation id — no per-function logging setup.
  • Distributed tracing. When a request flows through multiple functions (or a function invokes another function), a trace ties the hops together — the platform's answer to debugging distributed heisenbugs. Trace ids propagate automatically through the invocation path.
  • Health checks. The platform actively probes registered services; an instance that hangs or fails is deregistered (and restarted) — loudly: the unhealthy state, the probe evidence, and the restart are all recorded as first-class events, never silently absorbed. Supervision bookkeeping must be exact — exactly one registered instance per intended instance, with reaping that provably completes.
  • Metrics dashboard. Real-time per-function latency, throughput (calls per second), and error rates, with invocation history (already partially built as the WUI's invocation tracking).
  • ProductionHealth integration. Per-function health and error-rate signals feed ProductionHealth, so hosted functions get production monitoring for free.

4. Versioning and lifecycle

Functions evolve; existing callers must not break:

  • Side-by-side versioning. my-function@2 runs simultaneously with my-function@1. Callers pin a version or follow the latest; the registry resolves. Versions are immutable — a registered version's JAR never changes (Maven-coordinate registration already carries this property naturally).
  • Hot deployment. Registering a new version takes neither the platform nor the previous version offline — registration is already a runtime operation today; the gap is formalizing it as versioned deployment with both versions invocable during and after the rollout.
  • Lifecycle management. Deprecating and retiring a version is explicit and visible: callers of a deprecated version can be enumerated (the billing ledger knows exactly who they are) and warned before retirement.

5. Security — identity, authorization, and capability provisioning

Invoking arbitrary code is the highest-trust surface on the platform, so this pillar leans entirely on W3Wallet:

  • Authentication and authorization via W3Wallet capabilities gate both registration (who may publish or replace a function) and invocation (who may call it), using the turnkey enforcement gate from W3Wallet → enforcement and trust roots. Both tiers of the programming model get this out of the box.
  • Capability provisioning into functions (W3Wallet → principals, delivery, and recovery): a function registered with a granted capability (e.g. a reference capability wrapping an API key) exercises it at invocation time and never sees the raw secret — the platform injects an attenuated, invocation-scoped capability rather than the function reading a key from its environment. Each invocation is a hosted-workload principal, lifecycle-bound and auto-revoked when the invocation completes.

6. Execution isolation and limits

Confirm, enforce, and document the sandboxing model: memory, CPU, and wall-clock limits per invocation; the concurrency model per function and per executor; and what a function can reach (by default, only the url:// fabric and the capabilities it was provisioned). A runaway or hostile function must not be able to starve the host, its neighbors, or the platform itself. The limits are also billing inputs — see below.

7. Traffic management — protection that never hides defects

  • Rate limiting. Per-caller invocation rates are enforced by the same W3Wallet allowance machinery that handles billing — "max 100 calls per minute" is just a rate-limited allowance, whether the per-call price is positive or zero. No caller can monopolize the platform.
  • Concurrency caps. Per-function and per-executor concurrency bounds protect the shared pool.
  • Circuit breaking. If a function fails consistently, the platform trips a circuit and fails fast instead of letting the failure cascade through callers and executors. Per the guiding principle, a trip is loud: it preserves and surfaces the underlying failure evidence (the failing invocations, their errors, the trip decision) as first-class observable events, alerts via ProductionHealth, and never quietly degrades into a "temporarily unavailable" answer that hides the defect from operators.

8. Billing — the caller pays

A key feature of the platform: every invocation is paid for by its caller, via W3Wallet, and the bill is grounded in the resources the server actually spends.

  • Metered execution, paid by the caller. The caller pays for all time the server spends on their behalf — compute and memory are metered for the duration of the invocation, so a function costs money while it is executing. An invocation request carries (or its established session carries) a W3Wallet spend capability — an allowance drawn from the caller's pool, denominated in an asset class such as w3coin or lambdaserver:credits (already a named example in W3Wallet → spend and settlement). The platform meters, draws, and settles via W3Wallet — the placeholder ledger first, the custodial hub as it matures. No spend capability, no invocation.
  • Storage fees, paid by the owner. A registered function also costs money while it is held: its stored artifacts (JAR, definition, invocation records) accrue a holding fee even when it never executes. A function at rest has no caller, so this standing charge falls to the owner, as a W3Wallet standing registration / spend agreement — which supplies the lifecycle semantics for free: an owner who stops funding storage enters the agreement's grace period, after which the platform reclaims the storage per its terms.
  • Owner pricing rides on top. The metered resource fee is the floor — the platform always recovers its own cost, so even a zero-priced function costs its caller the resources it consumes, and the platform never subsidizes anonymous traffic. An owner may price a function above that floor; the markup is owner revenue (platform cut is an open question). Quota and billing are deliberately the same machinery: a rate-limited allowance bounds a caller whether the draw is resource-cost-only or priced.
  • One request, one execution, one bill. The platform does not retry: an accepted invocation request is executed once and billed once. Retry logic is up to the caller (each retry is a new, separately billed invocation), and idempotency is up to the function implementer. The service provides a place to store and execute code in the cloud — it does not paper over failures with hidden re-execution, which would both mask defects (per the guiding principles) and bill the caller for work they did not request.
  • Why caller-pays matters. It inverts the public-cloud default, where the function's owner pays for every invocation and a popular (or abused) endpoint is a financial liability. Caller-pays makes publishing a function safe by default — the owner's exposure is bounded regardless of traffic — and makes every registered function a monetizable API with zero billing-integration work. This is the "monetize" pillar of the north star, and a concrete enabler of the open ecosystem candidate for component 3.

9. Deployment spectrum — embed it, self-host it, or use the hosted instance

LambdaServer must not be only a centralized service. A key consequence of restructuring onto the standard layered architecture is that the platform lands on the deployment spectrum — the same code, consumable in three modes:

  • Embeddable library. An application depends on the LambdaServer Embedded module directly and gets a function registry and invoker inside its own process — no IPC, no network, no central service. This is how an app offers a plugin surface (its users register functions that extend it), how an agent can carry a private tool catalog, and how end-to-end tests run a real LambdaServer in-process per the testing standards.
  • Self-hosted subservice. Run your own LambdaServer (the ServiceServer in standalone P2P mode) on your own hardware and point clients at its url://. Functions, JARs, and invocation records never leave your infrastructure, and under W3Wallet's trust-root model your instance is the sole authority for capabilities over its own functions — fully operational with no coordinator.
  • Hosted service. The managed instance at lambdaserver.wasmserver.com under ContainerNursery: a shared executor pool, zero operations, convenience for everyone who doesn't want sovereignty.

Why a user runs their own instance. These are not hypothetical conveniences; each is a concrete reason to be at the embedded or self-hosted end of the spectrum, and each is a requirement the design must honor:

  1. Independence and de-risking. A function you depend on keeps being invocable when the hosted instance is down. Service independence matters: per the cattle over pets philosophy, your instance is fully operational without any coordinator — downtime of the shared service must never cascade into downtime of yours.
  2. Privacy. Function code, parameters, return values, and invocation records never leave your infrastructure. Nothing about what you run or how often is visible to a shared operator.
  3. Secret functionality stays home. A function that wraps a secret — an API key, a signing key, proprietary logic — should never have to be stored on the shared platform at all. The owner registers it on their own instance, and invocations of that function route directly to that instance: callers hold a capability to invoke and receive only results, while the secret never travels. This is the function-shaped twin of W3Wallet's reference capabilities (the secret stays with its owner; the holder calls home), and it composes with capability provisioning — the shared platform can grant and meter access to such a function without ever hosting it.
  4. Hardware and network locality. Some functions can only execute in particular places: they need a GPU or custom hardware, or LAN access to devices unreachable from shared infrastructure. An embedded or self-hosted instance pins execution to the machine that has what the function needs, while the function stays discoverable and invocable over url:// like any other.

Reasons (3) and (4) make function homing a first-class registry concept: a function's registry entry can name the specific instance(s) permitted to execute it, and the platform routes invocations of a homed function directly to its home rather than to the shared executor pool — while discovery, capability checks, and (where priced) caller-pays billing flow through the same machinery as for any other function (see the federated-discovery open question).

Every mode exposes the same Api, so a consumer moves along the spectrum — prototype against an embedded instance, self-host for sovereignty, call the hosted instance for convenience — without changing calling code. And because dependencies are injected as Api interfaces (local-or-remote, per the spectrum doc), a parent app embedding LambdaServer retains full control over what its registered functions can reach. This is the platform-level expression of the Decentralized by Default philosophy.

10. Execution placement — not every invocation crosses the network

The serializable, every-call-independent contract means where a function executes is a platform decision, not part of a call's meaning. Because LambdaServer controls execution end to end, it can allocate intelligently — three placements take that beyond the shared executor pool:

  • Client-side execution. A function can be configured for execution on the caller's side — possible exactly when it holds nothing private (no embedded secrets, no homed hardware or data). Its bytecode is shipped to the client and executed there, so round trips to the server are avoided entirely — while the server remains the source of truth for the code: when the registered version advances, clients transparently re-fetch. The result is a transparent auto-update style: remote updatability with local-call latency (pin-or-follow per versioning, §4), reusing the platform's established sandboxed client-bytecode machinery rather than inventing a new distribution channel. This is distinct from the embeddable library: an embedding app runs its own registry, whereas a client-side function stays registered on — and updated from — the server; only the execution moves.
  • Call-chain fusion. When functions invoke functions, the platform may — at its discretion — fuse a chain into a single binary/executable/image, so one container start covers the whole chain and each intra-chain call is a direct, in-process function call: no per-hop container, no IPC, no serializing and deserializing of intermediate results. Fusion is purely an optimization and must be invisible except in cost and latency: tracing still records per-function spans, billing still meters the resources actually consumed (now smaller), and each function in the chain is still capability-checked as if invoked individually.
  • Data-locality placement. Execution moves to where the data is. If a caller is processing data that lives in a particular datacenter and the executor pool has a suitable host there, the platform places the function on that host — the code travels (it is small), the data does not (it is large) — saving transfer cost and time. This is intelligent allocation the platform performs on the caller's behalf, not a topology the caller designs; it is the long-term payoff of a multi-host pool (see the executor-pool-scope open question) and pairs naturally with SimpleFileSystem: when data lives in a platform-known store, the platform knows exactly where execution belongs.

Together with homing, placement becomes a per-function spectrum — the caller's own process, the shared pool, a fused chain image, a host colocated with the data, or the owner's home instance — recorded as registry policy and chosen by the platform within each function's configured constraints. The caller just invokes.

11. Markdown functions — agent execution, maintainer compilation, and deoptimization

A function can be defined in prose (decisions 2026-08-13 — see the decision log). The owner registers a skill-style markdown document: YAML frontmatter declares the function's name, description, typed parameter schema and return schema (per Serialization), and the capabilities the function needs; the body is natural-language instructions. This is a fourth definition format inside the function tier — not a new tier and not a separate catalog: the registry entry has the same shape as any function (stable url://lambdaserver/functions/{id} identity, immutable versions, pricing, capability gating, discovery), and a caller cannot tell, and never needs to know, whether an invocation was fulfilled by code or by a model.

  • Agent execution. The registry entry binds the function to an executing agent — an agent definition homed on an AiCliHostSupervisor. This is an instance of function homing (§9): the function's home is the bound agent's supervisor, and invocations route there directly. Each invocation launches a fresh, independent conversation from the stored agent definition (the supervisor's launch-from-definition operation): the schema-validated parameter values are rendered into the markdown body and delivered as the conversation's opening message; the agent works with the tools its definition grants; its final output is validated against the declared return schema before being returned to the caller. A schema-invalid output is an invocation failure — billed, loud, and recorded as evidence for the maintainer. Nothing carries between invocations — the every-call-independent invariant applies to agents exactly as to code — so warm-agent reuse may exist only as an invisible cold-start optimization that guarantees zero context bleed. The supervisor's one-live-conversation-per-agent lifecycle makes a markdown function's default concurrency one, invocations queueing at the supervisor; that is accepted rather than fought — agent execution is the slow tier, and hot functions graduate to compiled execution below.
  • Capabilities intersect. The invocation-scoped grant is the intersection of the executing agent's granted capabilities and the frontmatter's declared needs — authority strictly diminishes, per W3Wallet. The compiled artifact (below) runs under the same declared capability set, exercised programmatically, so the two backends are security-equivalent.
  • Maintainer compilation — the JIT model. An optional second binding names a maintainer agent — typically a more powerful model — responsible for compiling the markdown into executable code. The analogy is exact and load-bearing: the markdown is the source, agent execution is the interpreter, the compiled artifact is JIT output, and fallback is deoptimization. The markdown spec defines the immutable version; the compiled artifact is a platform-managed backend attached to that same version — swapping, repairing, or recompiling it is backend maintenance, invisible to callers per §10's where-and-how-is-a-platform-decision stance, never a version bump. A compiled artifact serves traffic only after passing a conformance gate: a test suite the maintainer derives from the spec, seeded by replaying recorded invocations (inputs and agent-produced outputs are already in the invocation records) against the compiled code. When to compile is the maintainer's call, informed by the registry's own economics — the billing ledger knows exactly which functions are hot and expensive. Changing the markdown itself is different in kind: that is a new immutable version, owner-approved — the spec is the owner's contract with callers, and the maintainer proposes rather than decides.
  • Fallback is deoptimization — always, and loud. When the compiled backend fails in a defect-shaped way — an unhandled crash, a blown resource limit, schema-invalid output — the platform always falls back to agent execution within the same invocation: one accepted request, one invocation, one bill covering the metered resources of both stages. Declared domain errors are results, never fallback triggers — otherwise the agent path would mask legitimate failures and the backends would diverge. Fallback is a declared execution policy of markdown functions, not a hidden retry: every deopt is a first-class event on the invocation record (the caller can see which backend produced their result), on the dashboard, and in the maintainer's work queue with the full failure evidence — the deopt stream is the maintainer's primary defect feed. A sustained deopt rate demotes the artifact: the platform stops attempting the compiled path until the maintainer ships a repaired artifact back through the conformance gate. Because a failed compiled attempt may already have performed side effects, fallback can re-execute work — the platform's existing stance carries that consequence: idempotency belongs to the function implementer, and a markdown function whose instructions have side effects must specify them idempotently, exactly as any function must to tolerate caller-driven retries. (This is a deliberate, dated carve-out from the no-platform-retries decision — see the decision log.)
  • Billing — model usage joins the metered floor. The dominant resource of an agent-executed invocation is the executing agent's model usage; it is metered at cost into the caller-pays floor alongside compute and memory, drawn from the caller's spend capability, with settlement compensating the owner whose model credential funded the call. The agent's own spend-rate budget (its accrual-rate token bucket) remains a protective cap, not the billing mechanism — an invocation that would exceed the remaining bucket is refused up front (no spend capability, no invocation). The gradient this creates is a feature: an agent-executed function is visibly expensive per call, and compilation collapses the caller's price floor from model tokens to milliseconds of CPU — the same function becomes dramatically cheaper, faster, and concurrent once compiled, and the ledger's per-function cost data is precisely the compile-here signal. The maintainer's own compilation and repair work is attributable to no caller and is owner-funded through the maintainer agent's budget — the running-cost twin of the storage holding fee.
  • The composition closes a loop. AiCliHostSupervisor already mounts LambdaServer functions as an agent's CLI tools; markdown functions run the arrow the other way — an agent as a function's implementation. An agent's tool can therefore itself be markdown-defined and agent-executed. Each workstream depends only on the other's Api, so the two compose deliberately rather than cyclically (see relationships).

Prioritization — MVP vs. mature platform

MVP — trustworthy register-and-invoke. The function tier, three registration sources, sync/async invocation, the WUI, and url://lambdaserver/ addressing already exist; the MVP is what makes that core loop safe to open to more callers and more code:

  • [ ] Standard layered architecture. Restructure onto Api / Embedded / ServiceServer per the standard layered architecture, so sandboxed clients invoke functions the way they reach every other service. (url://lambdaserver/ itself is already live — the gap is the layering, not the route.) The Embedded module this produces is also what makes LambdaServer embeddable in a consumer's own process — see design §9.
  • [ ] W3Wallet authentication/authorization gating registration and invocation.
  • [ ] Execution isolation and limits, confirmed and documented (memory/CPU/time/concurrency).
  • [ ] Metered invocation, rate limiting, and quota — the caller presents an allowance; metering and enforcement land now, against W3Wallet's placeholder settlement.
  • [ ] Baseline observability — centralized invocation logs, history with durations and failures, fed into ProductionHealth.
  • [ ] Cold-start budget. Measure and document time-to-first-invocation under ContainerNursery lazy-start; keep it fast enough for interactive use.
  • [ ] End-to-end tests that register a function (all three sources), invoke it sync and async, and assert invocation records, per the testing standards.

Mature platform — the full pillars, roughly in dependency order:

  • [ ] ServiceImplementation service tier with platform-managed serviceStartup()/serviceShutdown().
  • [ ] Client-library distribution (source / binary / Maven artifact) attached to a function's registry entry.
  • [ ] Side-by-side versioning and formalized hot deployment, with deprecation/retirement lifecycle.
  • [ ] Executor pool with least-busy load balancing and drain-before-reap for service instances.
  • [ ] Distributed tracing and the metrics dashboard.
  • [ ] Circuit breaking (loud, evidence-preserving).
  • [ ] Capability provisioning into functions (invocation-scoped, never-see-the-secret).
  • [ ] Client-side execution — ship a no-private-data function's bytecode to the caller, with transparent re-fetch on update (design §10).
  • [ ] Call-chain fusion — merge function chains into a single image at the platform's discretion, preserving tracing, billing, and capability semantics (design §10).
  • [ ] Data-locality placement — multi-host intelligent allocation that moves the code to the data (design §10).
  • [ ] Real settlement and owner revenue — caller-pays billing graduates from metering-against-placeholder to real w3coin settlement as W3Wallet's hub matures.
  • [ ] Markdown functions, stage 1 — registration and agent execution (design §11): the skill-style definition format, homed routing to the bound agent, fresh-conversation invocation, schema-validated results, model usage in the metered floor. Depends on AiCliHostSupervisor's launch-from-definition core.
  • [ ] Markdown functions, stage 2 — maintainer compilation: the maintainer-agent binding, the spec-derived conformance gate seeded by recorded invocations, and the compiled artifact as a same-version backend.
  • [ ] Markdown functions, stage 3 — fallback and deoptimization: always-fall-back within one invocation, loud deopt events feeding the maintainer's queue, demotion on sustained failure.

Positioning — existing platforms and the differentiation thesis

Platform What it shares with LambdaServer Where LambdaServer differs
AWS Lambda / Google Cloud Functions FaaS: deploy a function, scale to zero, event-driven invocation Owner pays vs. caller pays; IAM + cloud console vs. portable W3Wallet capabilities; zip/container packaging vs. registration from Maven/JAR/git; locked to a cloud vs. native to the url:// fabric
gRPC + service mesh (Envoy/Istio) Discovery, load balancing, circuit breaking, mTLS, observability The mesh manages traffic between servers you still run and deploy; LambdaServer runs the code itself — mesh features become platform features with no servers to operate; the mesh secures transport, not invocation-level payment
Java RMI / distributed objects "Call a remote method" ergonomics on the JVM No remote object references — serializable values and identifiers only, every call independent. This deliberately avoids the classic distributed-object fallacies (stateful stubs, distributed GC, version-locked interfaces) that sank RMI
Knative / OpenFaaS Self-hosted serverless The unit is a JVM function/service, not a container image; capability-based security and caller-pays billing are absent there; their self-hosting floor is a Kubernetes cluster, while LambdaServer's deployment spectrum goes all the way down to an in-process embeddable library
Temporal / durable workflows Reliability for multi-step logic Explicitly out of scope: no orchestration state, no workflow history — a follow-up call is a completely separate call. Composition above LambdaServer can provide orchestration

The differentiation thesis. Every column above offers a slice; LambdaServer's bet is the integrated whole on one fabric: the unit of deployment is a function, not a container; registration meets JVM code where it already lives (Maven, JAR, git); the same W3Wallet capability that authenticates a caller also pays for the call — auth, quota, and monetization are one mechanism, not three integrations; functions can hold provisioned secrets they never see; agents are first-class callers and publishers (AiCliHostSupervisor mounts an agent's granted LambdaServer functions as its CLI tools); and the platform itself spans the deployment spectrum — embed it in-process, self-host it, or use the managed instance — so adopting LambdaServer never means surrendering to a centralized service. No general-purpose platform combines caller-pays micro-billing with capability security — that combination is what makes "publish a function, the world can safely pay to call it" a one-step act, and it is the most direct expression of the north star: everything required to run, secure, observe, evolve, and monetize remote functions, without the developer becoming a distributed-systems expert.

Decision log

Decisions taken on questions this document previously left open (2026-06-11 unless dated otherwise):

  • Billing is resource-metered. The caller pays for all time the server spends on their invocation — compute and memory while the function executes; the owner pays storage holding fees while the function is held, even when it never executes. Owner-set pricing is a markup on top of that metered floor. See design §8.
  • No platform retries, no platform idempotency. Retry logic is up to the caller; idempotency is up to the function implementer. The service provides a place to store and execute code in the cloud — one accepted request is one execution and one bill.
  • LambdaServer vs. ContainerNursery layering. ContainerNursery hosts full applications and ServiceServers inside Docker containers, exposing arbitrary http(s):// or url:// endpoints. LambdaServer exposes a function's own Java/Kotlin API as remotely invokable methods — its units are super-lightweight functions, not applications. LambdaServer is itself an app that can be hosted on ContainerNursery (the hosted instance is exactly that); the reverse is not true.
  • There is one function-management CLI codebase (2026-08-13). LambdaCli is a GitHub redirect/alias of LambdaServerCli; LambdaClientMain in LambdaServerApiClientImplementation remains the separate workspace build/test entry point and is not part of this function-management CLI decision.
  • Markdown functions are a definition format, not a tier (2026-08-13). A skill-style markdown document (typed parameter/return schemas in frontmatter, prose instructions in the body) registers as an ordinary function-tier entry — same registry shape, URL identity, versioning, pricing, and capability gating; outputs are schema-validated before return. Function tier only; there is no markdown ServiceImplementation. See design §11.
  • Agent execution is homing plus a fresh conversation (2026-08-13). A markdown function is bound to an executing agent homed on an AiCliHostSupervisor; invocations route to that supervisor (homed-function machinery) and each runs as a fresh, independent launch-from-definition conversation — default concurrency one, per the supervisor's one-live-conversation-per-agent lifecycle. Warm reuse only ever as an invisible, zero-context-bleed optimization.
  • Compilation follows the JIT model (2026-08-13). The markdown spec defines the immutable version; the maintainer agent's compiled artifact is a swappable backend of that same version, promoted only through a conformance gate (spec-derived tests plus replayed recorded invocations) — never a version bump. Changes to the markdown itself are new, owner-approved versions.
  • Compiled-path failures always fall back to agent execution (2026-08-13 — a deliberate carve-out from the no-platform-retries decision above). Defect-shaped failures (crash, resource limits, schema-invalid output — never declared domain errors) deopt to the agent path within the same invocation, regardless of side effects the compiled attempt already performed: one invocation, one bill across both stages. Every deopt is loud (invocation record, dashboard, maintainer queue); sustained deopts demote the artifact. Idempotency remains the function implementer's job, exactly as for caller-driven retries.
  • Model usage is metered into the caller-pays floor; the maintainer is owner-funded (2026-08-13). The executing agent's model spend is billed at cost to the caller alongside compute and memory, with the agent's spend-rate budget as a protective cap only; compilation visibly collapses the caller's price floor. The maintainer agent's work is the owner's investment, funded like the storage holding fee.
  • Serialization contract → the Serialization workstream (2026-07-02). "What counts as serializable" is now owned ecosystem-wide by the Serialization plan: parameters and return values are @Serializable types — compiler-verified immutable values (serialized by value) or recognized reference types (serialized by reference) — with the wire format a pluggable serializer choice rather than fixed here. The same plugin makes functions serializable (code identity + verified-immutable captures), giving register-and-invoke its ideal form — hand the platform a lambda — as that plan's committed LambdaServer milestone. How type changes interact with versioning is likewise tracked there (schema evolution at the serializer layer).

Open questions

  • Owner pricing economics. The metered resource fee is decided (decision log); what remains open is the markup layer: does the platform take a cut of an owner's revenue, and is there a platform-funded free tier (e.g. a starter allowance) for new users?
  • Storage. Is LambdaStore the long-term home for JARs and invocation records, or should JARs live in SimpleFileSystem / BlobStorage and records in the Event Log?
  • Two function-management CLIs — RESOLVED (2026-08-13). LambdaCli is a GitHub redirect/alias of LambdaServerCli; there is one current function-management CLI codebase. The separate LambdaClientMain workspace build/test entry point in LambdaServerApiClientImplementation is not part of this decision and is not an open question.
  • Executor-pool scope. Single host under ContainerNursery first — but does multi-host placement arrive via ContainerNursery itself, a dedicated scheduler, or the url:// fabric's own peer discovery?
  • Billing across the deployment spectrum. The hosted instance bills caller-pays; an embedded instance is the consumer's own process and presumably free. Does a self-hosted subservice settle through the shared W3Wallet hub, mint its own bound asset class, or opt out of billing entirely — and what is the default at each point of the spectrum?
  • Federated discovery and direct routing for homed functions. Should the hosted instance's registry index functions homed on self-hosted/embedded instances — one searchable directory across the fabric, with invocations routed directly to the owner's instance rather than through the shared pool? If so, what does a caller hold (a url:// address, a registry entry, an invocation capability), is the directory consulted per call or cached, and how is a home instance's availability surfaced when it is offline?
  • Agent angle (partially resolved 2026-08-13). Agents now stand on both sides of the registry: AiCliHostSupervisor mounts functions as agent tools, and markdown functions (§11) make an agent a function's implementation — so this workstream serves component 2 directly. Still open: should an agent swarm register and invoke functions as its work-offload mechanism?
  • Markdown-function scale-out. Default concurrency is one (§11); when a still-uncompiled markdown function gets hot, does scale-out arrive as multiple ephemeral executor instances launched from the same agent definition (relaxing one-live-conversation for executor agents), or does the answer stay "compile it"?
  • Conformance-gate strength. What evidence must the gate produce before a compiled artifact serves traffic — and who judges semantic equivalence for text-shaped return values, where exact match is the wrong comparator (the maintainer itself, a separate judge model, per-function declared comparators)? Relatedly, how much observed nondeterminism across agent executions of the same inputs is tolerable before the spec is declared ambiguous and sent back to the owner?
  • Executor/maintainer identity. May the executor and maintainer bindings name the same agent (at different reasoning effort), or is separation-of-duties (the author of the compiled artifact never grades its own conformance) worth mandating?
  • Backend visibility. Should the registry surface which backend (agent vs. compiled) currently serves a function — callers may legitimately want the price/latency expectation — or is even that too much backend leakage into a contract that promises callers never need to know?
  • Client-side execution economics and trust. With execution on the caller's own hardware (design §10), the metered execution fee disappears — is anything billed (a distribution fee per fetched version, the owner's markup per call), and is per-call billing even enforceable once the bytecode is local? And what sandbox does the client run the fetched bytecode in?
  • Placement intelligence. What signals drive call-chain fusion and data-locality placement (design §10) — observed call graphs, data-location hints from the caller or from SimpleFileSystem, cost models? And in a fused chain, how are intra-chain calls attributed for billing and capability checks — is the original caller the principal for every hop?
  • Languages. Kotlin/JVM-only for now — is non-JVM execution ever in scope?

Relationship to other workstreams

  • W3Wallet — the deepest dependency: authentication/authorization (turnkey enforcement), quota and rate limiting (allowances), caller-pays billing (spend and settlement, where lambdaserver:credits is already a named asset class), and capability provisioning into functions (hosted-workload principals). LambdaServer is, in turn, one of W3Wallet's three motivating provisioning platforms.
  • AiCliHostSupervisor / MyLittleAgi — a deliberate mutual composition, each side depending only on the other's Api: agent tools are LambdaServer functions mounted as CLI executables (the agent tool catalog is a registry consumer), while markdown functions (§11) run the arrow the other way — LambdaServer consumes the supervisor's launch-from-definition operation to execute a bound agent as a function's implementation. Agents are thereby callers, publishers, and implementations.
  • Kotlin Build — built-from-git registration builds with kompile; LambdaServerApiClientImplementation provides RemoteLambdaWorkspace, which implements the kompile.Workspace interface for remote build/test execution.
  • SimpleFileSystem and EventLog — candidate storage homes for JARs and invocation records respectively (see open questions).
  • ContainerNursery — a host, not a sibling: ContainerNursery runs full applications and ServiceServers in Docker containers behind arbitrary http(s):///url:// endpoints, and the hosted LambdaServer instance is one such app. LambdaServer's own units are far lighter — individual Java/Kotlin functions invoked as remote methods — so the two platforms layer (LambdaServer on ContainerNursery) rather than compete; see the decision log.
  • Open ecosystem (component 3 candidate) — caller-pays monetization is a concrete enabler: outside developers publishing paid functions on the shared fabric is exactly the "network others extend" shape.
  • Decentralized, user-run services — the embeddable-library and self-hosted-subservice modes of design §9 are LambdaServer's concrete instance of the everyone-runs-their-own direction, per the Decentralized by Default philosophy.

Graduation

There is no Documentation Repository project page for LambdaServer yet. This workstream graduates when the MVP tier is live: a standard-layered url://lambdaserver/ service with W3Wallet-gated, metered access and documented isolation. At that point add a Documentation Repository project doc + ALL_PROJECTS entry, and it is no longer tracked as a workstream here.