Containers without a runtime
Until now, every Container and Daemon ran under a small Alien runtime — a Rust process that started your app, supervised it, and brokered access to bindings and commands. That layer is gone. Your entrypoint is now PID 1: what runs in the customer's cloud is exactly what's in your Dockerfile, with nothing in front of it.
Bindings moved in-process to make that possible. Instead of talking to the runtime, your app imports a library, resolves a resource once, and calls it:
import { kv, queue, container } from "@alienplatform/bindings"
const index = kv("index")
const jobs = queue("jobs")
await index.setJson("user:42", { plan: "pro" })
await jobs.send({ type: "welcome-email", userId: 42 })
const db = container("postgres")
const url = await db.getInternalUrl()The library is a native binding over the same Rust core on every language, so behavior is identical across Node, Bun, and Rust. Credentials are minted short-lived and refreshed behind the handle — nothing long-lived sits in your environment.
Commands got the same treatment. A container registers named handlers, with optional schema validation using any Standard Schema library (Zod, Valibot, ArkType), and your control plane invokes them without any inbound port:
import { createCommandReceiver } from "@alienplatform/commands"
import * as z from "zod"
const receiver = createCommandReceiver()
receiver.command("reindex", z.object({ tenant: z.string() }), async input => {
return { started: true, tenant: input.tenant }
})
await receiver.run()Validated commands infer their input types; handleRaw is there when you want
the raw payload.
- No wrapper — your process runs directly, smaller images, one less thing between you and your app
- In-process bindings — resolve once, call like a library; queue and KV APIs no longer take a name on every call
- Typed commands — schema-validated input in Rust and TypeScript