Hull
A secure, capability-limited runtime for agent-native, local-first applications. Single binary, zero dependencies, runs anywhere.
Install / Use
/learn @artalis-io/HullREADME
A capability-secure, local-first runtime for programmable tools and workflows. Single binary, zero dependencies, runs anywhere.
The name reflects the architecture: Hardened — capability-secure, sandboxed execution. Userspace — single binary, no kernel modules, no cloud, runs anywhere. Lockdown — the app declares what it can touch, the runtime enforces it. Layer — sits on top of Keel (Kernel Event Engine — Lightweight), mirroring the nautical metaphor: the hull protects the keel from the sea.
Hull is a sandboxed runtime where application code runs inside declared capability boundaries — the app states what it can access (files, hosts, env vars), and the kernel enforces it. Whether the code is written by an AI agent, a human developer, or generated by a service, Hull constrains what it can do.
Write backend logic in Lua or JavaScript, frontend in HTML5, data in SQLite. hull build produces a single portable executable — under 2 MB — that runs on Linux, macOS, Windows, FreeBSD, OpenBSD, and NetBSD. AI coding agents get structured JSON access to routes, schema, tests, and HTTP responses through the built-in hull agent command — no plugins, no MCP servers, no configuration.
Why
AI coding agents solved code generation. But they created two new problems: deployment (the output is always React + Node + Postgres + cloud) and trust (who verifies what AI-generated code actually does?).
Hull solves both. Write Lua or JavaScript, hull build produces a single file. That file is the product — no cloud, no hosting, no dependencies. And because Hull apps declare their capabilities in a manifest enforced by the kernel, the user knows exactly what the app can touch. In a world where AI writes the code, the runtime must be the trust boundary. Hull is that boundary. The same properties — single-binary deployment, capability enforcement, structured tooling — make Hull equally useful for human developers building local tools and services.
Six vendored C libraries. One build command. One file. That's the entire stack. Works out of the box with Claude Code, Codex CLI, OpenCode, and any agent that can run shell commands.
Quick Start
# Build hull
make
make test
# Create a new project
./build/hull new myapp
cd myapp
# Run in development mode (hot reload)
../build/hull dev app.lua
# Build a standalone binary
../build/hull build -o myapp .
# Run it
./myapp -p 8080 -d app.db
Hull Tools
Hull ships 14 subcommands for the full development lifecycle:
| Command | Purpose |
|---------|---------|
| hull new <name> | Scaffold a new project with example routes and tests |
| hull dev <app> | Development server with hot reload |
| hull build -o <out> <dir> | Compile app into a standalone binary |
| hull test <dir> | In-process test runner (no TCP, memory SQLite) |
| hull agent <subcommand> | AI agent interface — routes, schema, tests, requests as JSON |
| hull inspect <dir> | Display declared capabilities and signature status |
| hull verify [--developer-key <key>] | Verify Ed25519 signatures and file integrity |
| hull eject <dir> | Export to a standalone Makefile project |
| hull keygen <name> | Generate Ed25519 signing keypair |
| hull sign-platform <key> | Sign platform library with per-arch hashes |
| hull manifest <app> | Extract and print manifest as JSON |
| hull <app> --max-instructions N | Set per-request instruction limit (default: 100M) |
| hull <app> --audit | Enable capability audit logging (JSON to stderr) |
| hull <app> --max-connections N | Max concurrent connections (default: 256) |
| hull <app> --body-max-size SIZE | Max request body size (default: 1m) |
| hull <app> --read-timeout MS | Read timeout in milliseconds (default: 30000) |
| hull <app> --workers N | Thread pool worker count (default: 4) |
| hull <app> --queue-capacity N | Thread pool queue capacity (default: 64) |
| hull <app> --no-compress | Disable gzip response compression |
| hull migrate [app_dir] | Run pending SQL migrations |
| hull migrate status | Show migration status (applied/pending) |
| hull migrate new <name> | Create a new numbered migration file |
Build Pipeline
Source files (Lua/JS/HTML/CSS/static assets)
↓
hull build: collect → generate sorted registry (hl_app_entries[]) → compile → link → sign
↓
Single binary + package.sig (Ed25519 signed)
The build links against libhull_platform.a — a static archive containing Keel HTTP server, Lua 5.4, QuickJS, SQLite, mbedTLS, TweetNaCl, and the kernel sandbox. The platform library is signed separately with the gethull.dev key.
Cross-Platform Builds
Hull supports three compiler targets:
| Compiler | Target | Binary Type |
|----------|--------|-------------|
| gcc / clang | Linux | ELF |
| gcc / clang | macOS | Mach-O |
| cosmocc | Any x86_64/aarch64 | APE (Actually Portable Executable) |
Cosmopolitan APE binaries run on Linux, macOS, Windows, FreeBSD, OpenBSD, and NetBSD from a single file. Hull builds multi-architecture platform archives (make platform-cosmo) so the resulting APE binary is a true fat binary for both x86_64 and aarch64.
Architecture
┌─────────────────────────────────────────────┐
│ Application Code (Lua / JS) │ ← Developer writes this
├─────────────────────────────────────────────┤
│ WASM Compute Plugins (WAMR) │ ← Sandboxed data-plane computation
├─────────────────────────────────────────────┤
│ GPU Compute Shaders (wgpu-native) │ ← Parallel data processing (optional)
├─────────────────────────────────────────────┤
│ Standard Library (stdlib/) │ ← cors, ratelimit, csrf, auth, jwt, session
├─────────────────────────────────────────────┤
│ Runtimes (Lua 5.4 + QuickJS) │ ← Sandboxed interpreters
├─────────────────────────────────────────────┤
│ Capability Layer (src/hull/cap/) │ ← C enforcement boundary
│ fs, db, crypto, time, env, http, gpu, tool │ ← audit logging (--audit)
├─────────────────────────────────────────────┤
│ Hull Core │ ← Manifest, sandbox, signatures, VFS
├─────────────────────────────────────────────┤
│ Keel HTTP Server (vendor/keel/) │ ← Event loop + routing + async + thread pool
│ │ ← gzip compression + client connection pool
├─────────────────────────────────────────────┤
│ Kernel Sandbox (pledge + unveil) │ ← OS enforcement
└─────────────────────────────────────────────┘
Each layer only talks to the one directly below it. Application code cannot bypass the capability layer.
Standard Library
Hull ships a full set of middleware and utility modules for building secure backends:
| Module | Lua | JS | Purpose |
|--------|-----|-----|---------|
| cors | hull.middleware.cors | hull:middleware:cors | CORS headers + preflight handling |
| ratelimit | hull.middleware.ratelimit | hull:middleware:ratelimit | In-memory rate limiting with configurable windows |
| csrf | hull.middleware.csrf | hull:middleware:csrf | Stateless CSRF token generation/verification |
| auth | hull.middleware.auth | hull:middleware:auth | Session-based and JWT-based authentication middleware |
| session | hull.middleware.session | hull:middleware:session | Server-side sessions backed by SQLite |
| cookie | hull.cookie | hull:cookie | Cookie parse/serialize helpers |
| jwt | hull.jwt | hull:jwt | JWT sign/verify (HMAC-SHA256) |
| template | hull.template | hull:template | HTML template engine with inheritance, includes, filters |
| csv | hull.csv | hull:csv | CSV parse/encode (RFC 4180) |
| search | hull.search | hull:search | Full-text search (SQLite FTS5) |
| rbac | hull.middleware.rbac | hull:middleware:rbac | Role-based access control |
| logger | hull.middleware.logger | hull:middleware:logger | Request logging with logfmt output and request IDs |
| transaction | hull.middleware.transaction | hull:middleware:transaction | Wraps handlers in SQLite BEGIN IMMEDIATE..COMMIT |
| idempotency | hull.middleware.idempotency | hull:middleware:idempotency | Idempotency-Key middleware with response caching |
| outbox | hull.middleware.outbox | hull:middleware:outbox | Transactional outbox for reliable webhook delivery |
| inbox | hull.middleware.inbox | hull:middleware:inbox | Inbox deduplication for incoming events/webhooks |
| validate | hull.validate | hull:validate | Declarative input validation with schema rules |
| form | hull.form | hull:form | URL-encoded form body parsing |
| i18n | hull.i18n | hull:i18n | Internationalization: locale detection, translations, formatting |
| health | hull.middleware.health | hull:middleware:health | Health check + readiness endpoints |
| etag | hull.middleware.etag | hull:middleware:etag | ETag response helpers with 304 Not Modified |
| json | hull.json | (built-in) | JSON encode/decode |
All middleware modules follow the same factory pattern: module.middleware(opts) returns a function (req, res) -> 0|1 where 0 = continue, 1 = short-circuit.
Background Timers
app.every(ms, fn) and app.daily("HH:MM", fn) register repeating background callbacks. Timer callbacks run on the event loop thread with full async support — hull.sleep(), http.fetch(), and db.* all work inside timers.
-- Flush outbox every 30 seconds
app.every(30000, function()
outbox.flush()
end)
-- Clean up expired sessions daily at 2am UTC
app.daily("02:00", function()
session.
