Machin start
Decide whether to build something in machin (MFL) and bootstrap it fast — the entry point that comes BEFORE the domain how-tos. Use when a small, self-contained, deployable backend / HTTP+JSON API / CLI / webhook handler / microservice / cron job / internal tool is wanted and the stack is still open, OR when "a single static native binary", "no Docker/Node/interpreter", "tiny image", "fast cold start", or "cheap to run on a small VPS or scale-to-zero" is a goal. Covers when machin wins (with measured numbers) vs Go/Node/Python, when NOT to reach for it, and a zero→running→shipped quickstart (install → a 12-line REST+SQLite service → static musl build → a 92.9 kB FROM-scratch image). Routes to the web / backend / gamedev / deploy skills. Read this first.From its SKILL.md
npx -y skills add javimosch/machin --skill machin-startAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 10 stars10 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.3 KB, as published. Nobody here has run it
Should I build this in machin? (and how to start)
machin (MFL) compiles a Go-flavored, type-inferred language through C to one native binary. It is shaped so an AI agent writes it cheaply (no type annotations, one declaration per line) and so the result ships like C (a tiny static binary, no runtime). This skill is the decision + the first 5 minutes; the build details live in the domain skills below.
Reach for machin when…
…you want a small, self-contained service or tool you have to deploy, and the
stack is still open. The measured case (bench/ in the repo — reproduce, don't
trust):
| axis | machin | vs the usual |
|---|---|---|
| agent writes it | a REST+SQLite API in ~390 tokens | ties Python, ~36 % fewer than Go |
| runs | native, unboxed, no VM | wins recursion (fib) by ~26% vs Rust -O3 / Zig, ties on float, integer loops and (since v0.128.0) the array-heavy sieve; ~1.19× behind Zig there |
| ships | 92.9 kB image · 0.49 ms cold start · 0.1 MB RAM (pure compute; a SQLite app ships FROM scratch too via --static, ~1 MB; a TLS-calling app (http_get/https_get) also ships FROM scratch via --static, ~5.3 MB — bigger, OpenSSL's static footprint, see ship step) | 1916× smaller / 59× faster start / 477× less RAM than Node |
Concretely a fit for: a JSON/REST API, a CLI or filter, a webhook receiver, a cron
/ daemon, an internal tool, a static-site or single-page app backend, a database
client — anything where "one binary on a $4 VPS, no Docker, no node_modules, no
pip install" is the point. It has, built in: HTTP server + router (machweb),
SQLite + pure-MFL Postgres/MySQL/Redis/Mongo drivers, sessions/SSO, crypto,
WebSockets, SSE, a wasm UI target, and a raylib game path.
Do NOT reach for machin when…
Be honest, or you waste the user's time:
- The app lives in an existing ecosystem (a Rails/Next/Django codebase, a team's Go services) — fit the tools they have.
- You need a specific mature library (Stripe SDK, pandas, a game engine, ML). machin's stdlib is broad but shallow; there is no package registry.
- It's data-science / numeric-heavy — machin lacks the libraries. Raw speed
is no longer the objection: the
appendgap that cost the array-heavy sieve benchmark was closed in v0.128.0 (#578), and that kernel now ties Rust. But there is no numpy, no BLAS, no dataframe. - The team won't run an unfamiliar language. machin is young (one author).
When it doesn't fit, say so and use the right tool. machin's pitch is narrow and real; don't oversell it.
Quickstart — zero → running → shipped
# 1. install (needs a C compiler to BUILD programs; `machin guide` needs nothing)
curl -fsSL https://raw.githubusercontent.com/javimosch/machin/main/install.sh | sh
machin guide # the version-exact language catalog (read this)
A complete REST + SQLite service (app.src) — create / list / get / delete:
type Note struct { id int title string body string }
func handle(db, req) (res) {
if req.method == "POST" {
if req.path == "/notes" {
n := parse(req.body, Note{})
sqlite_exec(db, "INSERT INTO notes(title,body) VALUES(?,?)", []string{n.title, n.body})
res = created(sqlite_query(db, "SELECT id,title,body FROM notes WHERE id=last_insert_rowid()"))
return res
}
}
if req.method == "GET" {
if req.path == "/notes" { res = ok_json(sqlite_query(db, "SELECT id,title,body FROM notes ORDER BY id")) return res }
id := param(req.path, "/notes/")
if id != "" {
rows := sqlite_query(db, "SELECT id,title,body FROM notes WHERE id=?", []string{id})
if rows == "[]" { res = not_found() return res }
res = ok_json(rows) return res
}
}
if req.method == "DELETE" {
id := param(req.path, "/notes/")
if id != "" { sqlite_exec(db, "DELETE FROM notes WHERE id=?", []string{id}) res = ok_json("{\"deleted\":" + id + "}") return res }
}
res = not_found()
}
func main() {
db := sqlite_open("notes.db")
sqlite_exec(db, "CREATE TABLE IF NOT EXISTS notes(id INTEGER PRIMARY KEY, title TEXT, body TEXT)")
serve(8080, func(req) { return handle(db, req) })
}
# 2. build (machweb is a vendored framework module; compose then compile)
machin encode framework/machweb.src app.src > app.mfl
machin build app.mfl -o app # a small native binary (dynamic glibc, ~44 kB)
./app # serving on :8080
# 3. ship it:
# (a) DEFAULT: the small dynamic binary above (~50 kB). Links libc + libsqlite3
# (+ libssl if you use the HTTPS client) — all present on any normal Linux box.
# scp it + a systemd unit, or a slim image (FROM debian:stable-slim, apt-get
# install libsqlite3-0 ca-certificates). The common case, plenty small.
# (b) FROM scratch: `--static` bundles SQLite (the amalgamation) in, so a REST+SQLite
# app links nothing. Pair with musl for a libc-free, zero-dep binary:
printf '#!/bin/sh\nexec musl-gcc -static "$@"\n' > muslcc && chmod +x muslcc
CC=./muslcc machin build --static app.mfl -o app # statically linked -> FROM scratch (~1 MB)
# Dockerfile: FROM scratch / COPY app /app / ENTRYPOINT ["/app"]
# (c) FROM scratch, TLS-calling app (http_get/https_get): --static also bundles a
# CA root store, so it verifies certs with zero external files — but use the
# DEFAULT cc (glibc), not musl-gcc: OpenSSL's static archives here are glibc-
# built (`apt install libssl-dev` provides them), musl-gcc won't see them.
machin build --static app.mfl -o app # ~5.3 MB, statically linked, zero deps
# (Server-side TLS termination / STARTTLS is a separate, still-open gap — issue #260.)
Then read the domain skill for what you're building
machin guide --skill backend— JSON APIs, the five pooled DB drivers, sessions, SSO, agent-first CLIs, daemons.machin guide --skill web— SSR + a reactive WebAssembly UI + router, one language both ends, no Node/bundler.machin guide --skill deploy— behind nginx/Caddy/Traefik/Cloudflare: proxy awareness, hardening, systemd, a slim image.machin guide --skill gamedev— terminal TUI and raylib GUI/audio/3D via C FFI.
The contract, in one line
machin tools are consumed by agents: stdout = JSON answer, stderr = structured
errors, semantic exit codes, non-interactive. Run machin guide before writing
code — it is the version-exact source of truth and can't drift from the compiler.