More time to build, everything in one place. LOOK is a scripting language that carries the database, sessions, WebSocket, email and more in its core — so you spend your time building features, not wiring tools together. No packages to install, no dependency tree to resolve: one static file, and a complete workspace for the developer.
// Fetch a user by ID — embedded database, zero setup route("GET", "/users/:id", function($req) { $id = int(request::param("id")) $user = db::query(app::db(), "SELECT * FROM users WHERE id = ?", [$id]) if ($user == null) { return response::error(404, "not found") } return response::json($user) })
A simple API pulls in dozens of packages, a dependency tree, a separate database driver, yet another service for real time... LOOK collapses that stack into a single file.
LOOK is open source (Apache-2.0) and development happens entirely in the open on GitHub — read the source, open an issue, contribute.
Most languages say "batteries included," then leave you alone with a package manager. LOOK actually includes them.
MySQL, MariaDB, PostgreSQL, SQLite and Redis (RESP2) — all in the core with a hand-written wire protocol. No libpq/hiredis.
The default bytecode VM is ~41× faster than the tree-walking interpreter on the CLI. On the web, a route-level safety-net fallback.
WebSocket and Server-Sent Events are embedded in the language — broadcast with ws:: / sse:: in one line.
No external service needed to send email. A built-in SMTP server with STARTTLS, plus an IMAP server.
An undefined variable is an error (strict). Type-strict ==. 64-bit integers — phone numbers/IDs don't silently corrupt.
A static binary built on AlmaLinux 8 runs unchanged on Ubuntu, Debian, Rocky, RHEL 8·9·10+. Or just docker run codlook/look.
Just start writing — nothing to install, no new ecosystem to learn.
route("GET","/product/:id", fn) — REST, WS, SSE share one syntax. URL parameters are parsed automatically.
fn($x) => $x * 2 — an expression-bodied arrow function with implicit return. Classic function works too.
app::set("db", $conn) once → routes reach it with app::db() without capturing. The explicit-scope philosophy is preserved.
The wire protocol, directly. One API: db::query / exec / col. Transactions: db::begin / commit / rollback.
LOOK's task model. Fan-out, pipeline, producer-consumer — over channels. No blocking, no callbacks.
route("WS","/chat", fn) — RFC 6455, SHA-1+Base64 handshake. ws::broadcast() to every client.
route("SSE","/events", fn) — Server-Sent Events. Periodic push: timer::every(3000, fn).
SQLite-backed durable queue. jobs::push / worker / run. Delayed jobs, retries — survives a process restart.
In-memory, thread-safe, named queue. queue::push / pop / peek / size.
TTL-aware, thread-safe singleton. Shared across all workers. cache::get / set / has / flush.
Layout inheritance, partial include, {#each} loop, {#if} condition. Server-rendered — no runtime.
AST → register bytecode → switch dispatch. The default engine everywhere — ~41× faster than tree-walking on the CLI.
sha256, hmac_sha256, rs256_sign/verify, base64url, UUID v4, timing-safe constant_compare — no external deps. Passwords: auth::hash (PBKDF2). JWT builds on this.
Two layers: per-IP burst + global cap. LOOK_RATE_LIMIT_* — your code doesn't change, it's at the runtime level.
Outbound email is signed RSA-SHA256 automatically. Port 25 relay is off — authenticated SMTP only (587/465).
Built-in MTA (25/587) + IMAP4rev1 (143/993). SMTP → Maildir, IMAP → Thunderbird/Roundcube. No Dovecot/Postfix needed.
Throw with throw; error::new($type,$msg) for structured errors. try/catch + error::is / code / message.
GET/POST/PUT/PATCH/DELETE. JSON body, custom headers, timeout, TLS included. Fan-out API calls with parallel().
lk install github.com/... — JWT, payments and more. No registry, no config. Packages →
lk test — assertions, before/after_each. lk repl — interactive. Install packages from GitHub.
Email, number, integer, required field, min/max rules. Secure user input in a route with a single call.
It's not a framework — it's a language. If one of the needs below is yours, LOOK fits.
You want the drop-a-file, shared-hosting / Plesk simplicity — and also WebSocket, SSE and concurrency. Drop the file, run it, and you get real-time connections and parallel() on top.
Routing, DB (MySQL/SQLite/PostgreSQL), validation, cache, JWT — all in the language. No dependency manager, no package tree — one binary.
Copy one file to a VPS, run it with systemd/Plesk. No separate runtime, no package manager. 28 MB RAM, flat across 1M requests.
Built-in SMTP + IMAP server — no Postfix/Dovecot. Build a secure mail system, e-commerce notifications or a blog entirely in LOOK. How? ↓
One-line endpoints with arrow functions, or a full function body. Request data via request::, response via response:: — no middleware layer.
// One line — arrow function route("GET", "/", fn($req) => response::json(["hello" => "world"])) // Submit a form — POST body route("POST", "/signup", function($req) { $body = request::json() if (!validator::email($body["email"])) { return response::error(400, "invalid email") } db::exec(app::db(), "INSERT INTO users(email) VALUES(?)", [$body["email"]]) return response::json(["ok" => true], 201) })
// Real-time chat — 5 lines route("WS", "/chat", function($conn) { ws::on($conn, "message", function($m) { ws::broadcast($m) // send to everyone }) }) // Live event stream (SSE) route("SSE", "/prices", function($conn) { sse::send($conn, json::encode($tick)) })
No Socket.io, no separate service. WebSocket and SSE are part of the language. ws::broadcast() reaches every connected client in one call.
A template engine, background jobs, a queue, Redis, even AI — normally each needs a separate library/service. We built LOOK to make the developer's job easier; it's all in the core.
Which language ships a template engine in the box? LOOK has layout inheritance, partial includes, {#each} / {#if} — server-rendered, no runtime. Automatic XSS protection via template::escape.
// page.html: {#each products as p}<li>{$p.name}</li>{/each} $html = template::render("page.html", [ "title" => "Products", "products" => db::query(app::db(), "SELECT * FROM products", []) ]) return response::html($html)
// Don't make the request wait — enqueue, return instantly jobs::push("mail", ["to" => $email, "subject" => "Welcome"]) return response::json(["ok" => true]) // Separate worker — durable (SQLite), survives a restart jobs::worker("mail", function($job) { mail::send($job["to"], $job["subject"], $body) }) jobs::run()
Don't make slow work (mail, reports, webhooks) block the request — enqueue it and let a worker chew on it in the background. jobs:: is a SQLite-backed durable queue: delayed jobs, retries, dead-letter. queue:: is a fast in-memory FIFO between requests.
Run 3 DB queries at once in a single request — total time equals the slowest query, not the sum of all three. Go's channel model, in LOOK syntax: parallel() starts a task, channel() carries the result back. There's blocking (natural backpressure), no callback hell.
Every HTTP request already runs on its own worker thread — --workers N, no code changes. An isolated interpreter copy + a connection pool.
// 3 queries AT ONCE — time = the slowest query $result = channel(3) parallel(function() use ($result, $db) { $n = db::query($db, "SELECT count(*) n FROM companies", []) send($result, $n[0]["n"]) }) parallel(function() use ($result, $db) { $n = db::query($db, "SELECT count(*) n FROM orders", []) send($result, $n[0]["n"]) }) $companies = receive($result) $orders = receive($result)
No client to install, no driver to pick. Set LOOK_REDIS_URL — cache:: speaks RESP2 itself. Leave it unset and it runs in-memory. The code stays the same.
# env: LOOK_REDIS_URL=redis://127.0.0.1:6379/0 cache::set("stock:42", $stock, 300) // 300s TTL $stock = cache::get("stock:42")
The official ai module is built on the core http::stream. Ask Claude a question, stream it token by token — the key lives in a single env var.
use ai // lk module install github.com/codlook/look-modules/ai $reply = ai_chat([ ["role" => "user", "content" => "Describe LOOK in one sentence"] ], ["model" => "claude-sonnet-5"]) print($reply["content"])
Every component of LOOK is written from scratch in C++23 — no drivers, no ORM, no middleware.
Precedence-aware parser, full operator set, string interpolation, error reporting with line/column positions.
AST → 3-address register bytecode → switch dispatch. 41× faster than tree-walking on the CLI. Safety net: tree-walk fallback.
--workers N, a per-request interpreter copy, a per-DSN connection pool. Hot reload: zero downtime.
epoll (Linux), IOCP (Windows). RFC 6455 WS, an SSE frame codec. Optional fiber runtime (Go netpoller model).
Wire protocol from scratch. No driver. One db:: API, different DSNs — only the connection string changes.
Apache/nginx FastCGI, standalone HTTP, CGI fallback. One binary, three modes.
Measured with ab on a live AlmaLinux 8 · MariaDB server (64 workers, direct port).
The classic model spawns a separate process per request/worker — each tens of MB. LOOK is one process + N worker threads: memory is shared, and each request only takes a lightweight isolated interpreter copy. The result: a ~8 MB idle baseline (~8.5 MB holding 200 open keepalive connections), and under sustained high-throughput load it holds flat at ~28 MB across 1.75M requests — leak-free, verified with valgrind/heaptrack. With --workers 2 it runs stably without OOM even on a 1 CPU / 1 GB RAM VPS.
All tests measured with ab on a live AlmaLinux 8 server (running apps: test.codlook.com). Throughput is flat from c=1,000 to c=20,000 (~7.5–10k) — the bottleneck is CPU; kernel walls (backlog, syn_backlog) were cleared with tuning. The TLS chain (nginx→FCGI) does ~1,100–1,240 req/sec; the difference is double TLS termination, not LOOK.
Every line is tested — it passes fuzzing, ThreadSanitizer and data-integrity tests.
| Concern | LOOK's protection |
|---|---|
| SQL injection | db::query($conn, sql, [params]) — automatic parameterized ?, driver-correct escaping |
| DoS — huge body | Exceeding LOOK_MAX_BODY_SIZE (10 MB) → 413; unbounded-body memory exhaustion is prevented |
| Request smuggling | Content-Length + Transfer-Encoding together → 400 (RFC 7230 §3.3.3) |
| Session security | 128-bit /dev/urandom token; cookie HttpOnly + Secure + SameSite |
| Password storage | auth::hash / verify — PBKDF2-SHA256, in the core |
| Upload security | Magic-byte type validation (blocks extension spoofing) + SHA-256 |
| WebSocket masking | An unmasked client frame → closed with 1002 (RFC 6455 §5.1) |
| Parser stack overflow | Deeply nested ((…)) → expression/statement depth guard (150) — segfault prevented |
| Arithmetic UB | 64-bit integers; signed-overflow/shift/unary-minus UB eliminated — UBSan clean. BIGINT/ID/phone round-trips exactly |
Security isn't a layer bolted on afterward — because we wrote the protocols ourselves, we control every byte.
We wrote the MySQL, PostgreSQL, SQLite, Redis, HTTP, SMTP and IMAP wire protocols ourselves in C++23. No third-party driver → no hidden vulnerability in an unknown dependency. A malformed server response can't crash a worker — every number conversion and allocation is bounded.
Before every build, CI runs 16,000+ rounds of malformed-HTTP fuzzing under AddressSanitizer + UndefinedBehaviorSanitizer and a ThreadSanitizer data-race scan (security.yml). The one race found was fixed. Memory is flat across 1.75M requests — no leaks.
Beyond fuzzing: protocol parsers, VM arithmetic and network paths were reviewed line by line. Every hardening point found — an unguarded number conversion, an unbounded allocation, signed-overflow UB — was closed and pinned to a test. An external independent audit also caught real CRITICAL findings, all resolved.
Most scripting languages send mail; LOOK serves it. A built-in SMTP (RFC 5321) and IMAP4rev1 (RFC 3501 + IDLE) server — no Postfix/Dovecot. You can build a secure mail system end to end entirely in LOOK.
Thunderbird, Roundcube, Apple Mail and mobile clients connect directly — list, read, compose, search, get live notifications. All over TLS.
From text to cryptography, from queues to templates — the core library comes ready.
The official Docker image and VS Code extension are live — or install the static binary on your server.
One portable binary for glibc ≥ 2.28: AlmaLinux/Rocky/RHEL 8·9·10, Ubuntu 18.10→24.04, Debian 10+ — future releases work automatically too. CentOS 7 / RHEL 7 (glibc 2.17, EOL) is not supported → move to AlmaLinux 8.
The fastest path from a clean machine. The official image is live on Docker Hub — the first run pulls it automatically (~43 MB).
Run your app — the ./app folder is mounted into the container
docker run -p 7400:7400 -v "$PWD/app:/app" codlook/lookDrop in ./app/index.lk, open http://localhost:7400/ in the browser
Image page: hub.docker.com/r/codlook/look · Build from source: docker build -f cpp/docker/Dockerfile.production -t look .
The same package for Ubuntu/Debian and AlmaLinux/Rocky/RHEL — one portable binary.
Download and unpack the package from GitHub Releases
unzip look-lang-linux-*.zip -d look && cd lookOne command — installs the binary, creates a sample app + systemd service, starts it
sudo bash install.shVerify
curl http://127.0.0.1:9000/ · systemctl status lookPick a custom port with LOOK_PORT=8080 sudo bash install.sh. The service is managed by systemd — systemctl restart look.
Install from the panel, attach LOOK to domains in one click — a full workspace with an in-browser code editor, live monitor and log viewer.
Open the Plesk Terminal: Server Management → Terminal (or ssh root@server_ip)
Download and install the ZIP — at the end you'll see "The extension was successfully installed."
wget -O /tmp/look-lang-plesk-1.0.0.zip "https://github.com/codlook/look/releases/download/v1.0/look-lang-plesk-1.0.0.zip"
plesk bin extension --install /tmp/look-lang-plesk-1.0.0.zipFinish the install — one root command (required on new servers)
plesk php /usr/local/psa/admin/plib/modules/look-lang/scripts/post-install.phpOpen the panel: Extensions → My Extensions → LOOK Language → Open
Applications → Add New Domain → pick the domain (script path and port fill in automatically) → Add & Start. It shows Running in the list within seconds — the systemd service + Apache proxy are set up automatically.
Edit index.lk in the browser with Edit Code → Save & Redeploy — the file is written and the service restarts.
Step 3 is required: Plesk doesn't run the extension's install hook; this command installs the binary to /opt/look + grants sudo rights. Skip it and enabling a domain fails with sudo: a password is required. Re-running is safe; it's idempotent. The workspace: a live system dashboard, an in-browser code editor, a per-domain monitor (CPU/RAM/PID/connections) and a journalctl log viewer.
A native MSVC build with Schannel TLS — zero external DLLs. LOOK's HTTP server is built in, so no Apache or extra web server is needed.
Download look-lang-windows-1.0.0.zip from GitHub Releases and extract it
Expand-Archive look-lang-windows-1.0.0.zip -DestinationPath lookRun the built-in HTTP server — it serves index.lk from the current folder
cd look; .\lk-fcgi.exe --mode http --port 8080Open http://localhost:8080. Or run a script directly: lk.exe app.lk
The package is lk.exe (CLI / REPL) + lk-fcgi.exe (HTTP / FastCGI server) + README — plain binaries, no installer, no Apache.
Live error checking as you write .lk, autocompletion for 247 functions, hover signatures — the official extension.
Install "LOOK Language" from the VS Code Marketplace — or via the command line:
code --install-extension codlook.look-langOpen a .lk file — errors are underlined in red as you type
Marketplace: marketplace.visualstudio.com/…/codlook.look-lang · If lk isn't on PATH, Settings → look.binaryPath.
The official LOOK extension: live error checking (parse + undefined function), autocompletion for 247 built-in functions, hover signatures, and Run / Service / REPL shortcuts. Live on the VS Code Marketplace.
$name = "Ada" print("Hello, " . $name) mathh::sqrt(16) ⌇ Undefined function: mathh::sqrt // ▲ underlined in red as you type
No registry, no config — straight from GitHub. Two separate official repos: modules (pure LOOK) and packages (integrations).
lk module install github.com/codlook/look-modules/ailk install github.com/codlook/look-packages/iyzicoEvery new feature has to serve these three principles — if it doesn't, it doesn't get into the language.
Drop the file on the server, let the server route it — done. Nothing to install or compile. Shared hosting, VPS, Plesk — the same workflow.
Clean scope, explicit dependencies, concurrency built into the language. use() declares exactly what comes in. No hidden globals, no surprises.
Routing, DB, auth, cache, jobs, WebSocket, SSE, templates — all in the language. No package manager to open, no dependency hell.
Start writing for the web without setup fatigue. Download LOOK, run it, deploy it.