Open Fabrica is a single binary that builds and serves your ideas to the world. AI-powered apps, (real-time) multiplayer games, websites, secure end-2-end encrypted communication apps, collaboration tools, headless APIs...anything that runs in a browser. Everything is stored and served from your machine. It's a portable ecosystem in which there's no need for a dedicated webserver, database engine or third party plugins to have as little friction as possible.
Unfortunately not everyone has the tools, time, technical know-how or finances to put them into fruition. We want to enable anyone from all walks of life to build, own and publish their ideas for free, regardless of skill-level and background. Ideally one day Open Fabrica will be pre-installed on computers all over the world instead of a link to AliExpress and a trial version of Fruit Ninja.
If your company wants to support Open Fabrica and its goals please do reach out on X @antifoundering. We are in desperate need of model-access and powerful local hardware so finetuning can be done faster and in parallel.
In similar fashion...we do eventually want to ship with a default coding model, accessible for anyone for free. We understand it needs a paid upgrade path on your side for higher usage but it allows for a zero friction experience.
Anything, promised. As long as it runs in a browser. You can even fork it to modify the build loop for other platforms such as Android or iOS.
Well yes and no. They will create a site for you, a tool, a game but then what? You have to go figure out how to get it online, how does hosting work, where do I host it, where do I store my databases? Then the headache starts. You're bound to buy into whatever cloud provider and go to the painful process of making the parts work together. Open Fabrica gives you everything right outside the box. No need for ANY configuration, we will even protect your domain name so your apps run HTTPS. Free of course. We promise you that you'll be amazed on how easy this is, it might even feel like magic to some.
- Forever Free. No sign-up, no subscription, no per-project fee. Download the binary and run it.
- No phone-home. No usage or error reporting, no analytics SDK, no "check for updates" call. The admin panel is fully self-contained (every script, style, and font is served from the binary), so it works fully offline.
- Local First. One binary, your data, your machine. The only time anything leaves your computer is whenyou trigger it.
- Bring your own key. Use your own Anthropic, OpenAI, Google, or any OpenAI-compatible key, or run fully offline models.
- Portable. Copy the binary and your
data/folder to any Windows, macOS, or Linux box and it picks up where it left off.
Important: This is an early release which focuses on getting the core build loop as stable as possible: things will break and tokens will be wasted. Ideally you're on a cheap coding plan or run a local model when your hardware allows for that. Many architectural decisions are not finalized.
- Download latest binary fromReleases .
- Run it. Double-click the file, or run
./openfabricain your terminal. - Open
http://localhost:5734in your browser. - Pick an AI provider. The setup wizard asks for an API key (Anthropic, OpenAI, Google, or any OpenAI-compatible provider). A local Ollama is auto-detected, no key needed.
- Describe your idea. Open Fabrica takes it from there.
- Fully self-contained binary which runs everywhere.
- Instantly live by eliminating the concept of hosting.
- Unlimited projects from a single instance.
- Accounts and logins with optional Google/GitHub social login (any OAuth2 provider works), TOTP 2FA, and passwordless magic links.
- Payments via Stripe, PayPal, or Mollie; one-off, or recurring on Stripe and PayPal. Stripe reconciles itself from signed webhooks; PayPal and Mollie payments are reconciled manually.
- Email (SendGrid, Mailgun, Resend, or any JSON endpoint) andSMS (Twilio, MessageBird, or any JSON endpoint).
- Notifications in-app, plusWeb Push with auto-managed VAPID keys.
- Real-time chat rooms, live feeds, P2P calling, and file uploads, with optional end-to-end encryption.
- Image generation via OpenAI or a local Stable Diffusion (Automatic1111) instance.
- Stock photos from Pexels, Pixabay, and Unsplash, picked automatically.
- PDF generation for invoices, receipts, tickets, and reports (needs a local Chromium based browser).
- CSV import/export ,RSS/Atom feeds served straight from a table.
- Keyword and semantic search out of the box.
- Analytics (visits, unique visitors, top pages, referrers, AI usage/cost), all stored locally.
- SEO (Open Graph, Twitter cards, JSON-LD, sitemaps, robots.txt) handled automatically.
- Native PWA support for offline and installable apps.
- Auto-generated APIs with rate limiting and docs.
- Per-project AI assistants with configurable personality and memory.
- AI agents that plan and act over multiple steps: a hosted endpoint that reasons, calls your app's own functions and reads its data in a loop, and can spawn and manage sub-agents to break down bigger jobs. Stream progress live or run in the background, each bounded by a per-endpoint daily token budget.
- Server-side AI hooks to auto-summarize, classify, or embed new rows on insert.
- Telegram bot so you can plan/build projects and get push notifications from your phone.
- Scheduled jobs (cron or intervals) that run SQL, send emails, hit HTTP endpoints, or invoke the AI.
- Event-driven actions reacting to signups, logins, payments, and data changes.
- Roles and permissions with wildcard-based access control.
- Project templates : save any project as a template and spin up new ones in seconds.
- Free HTTPS automatically, no manual actions needed.
If you only run locally, the Quick Start is all you need. If you expose generated apps to the internet or enable payments, do these first:
- Back up your encryption key with your data.
data/.security/encryption.keydecrypts every stored secret (API keys, OAuth tokens, payment credentials, TOTP seeds). Lose it and those are unrecoverable. Back it uptogether with thedata/folder, kept somewhere the data backup alone can't leak it. - Set a spend ceiling. Unattended AI, the build/self-repair loopplus event triggers, scheduled jobs, and server functions, calls the LLM on your key. A safe ~1M-token-per-project-per-day ceiling shipson by default and is a single shared pool across all of those paths (change it in the wizard orSettings → Daily AI spend limit , or set
OPENFABRICA_ENGINE_DAILY_TOKEN_BUDGET=0for unlimited). When a project hits the ceiling those calls instead of billing all night. - Isolate untrusted/multi-user apps. The public CSP is permissive by design. Serve each project on itsown domain/subdomain so one app can't reach another's same-origin storage, and tighten the CSP instance-wide via
OPENFABRICA_PUBLIC_CSPor per project inProject → Settings → Advanced . - Cap memory for untrusted apps. Model-authored server functions run in a JS sandbox that limits CPU and output butnot heap , so a runaway handler can exhaust memory and crash the whole instance. Set a soft ceiling with
OPENFABRICA_MEMORY_LIMIT(e.g.1GiB) so GC pushes back before the process climbs into the OS OOM-killer, and for a hard backstop run under an OS/container memory limit with auto-restart. The shippedDockerfilewires--memory+GOMEMLIMITfor you; on bare metal use systemdMemoryMax=/Restart=or a cgroup. This is a floor, not tenant isolation. SeeSecurity . - Keep the admin panel on localhost (the default). SeeSecurity below.
Health probes on either port (both bypass auth and routing): GET /health (alias /healthz) is a liveness check that always returns {"status":"ok"} while the process can answer requests. GET /ready (alias /readyz) is a readiness check that pings the database and returns {"status":"ready"} (200) when it can serve, or {"status":"unavailable"} (503) when the database is unreachable, point your load balancer or orchestrator at /ready.
Point your domain's DNS at your server, open ports 80 and 443, then add the domain to a project (Project → Settings → General → Domain). HTTPS goes live on demand: Open Fabrica binds :80/:443 and Let's Encrypt issues the certificate within ~30 seconds, no restart. If another web server already owns those ports, set "tls_disabled": true in config.json (or OPENFABRICA_TLS_DISABLED=1) to skip the bind.
When you set a public domain, the admin UI offers a one-click Allow through firewall button (Project → Settings → General) if the local OS firewall is blocking inbound. It adds the allow-rule after a single system prompt (UAC on Windows, polkit on Linux), scoped to your active network profile. This opens the local firewall only; reaching the machine from the internet still needs your router to forward ports 80 and 443.
The admin panel runs on port 5734 and binds to localhost only (127.0.0.1) by default. It can read every project's data and decrypt stored secrets, so it is treated as a local control plane, not a public surface. To reach it on a remote server, use an SSH tunnel:
ssh -L 5734:localhost:5734 user@yourserver
If you genuinely need it reachable over the network (behind your own firewall or authenticating reverse proxy), set both OPENFABRICA_ADMIN_BIND to the interface (e.g. 0.0.0.0) and OPENFABRICA_ADMIN_EXPOSE=1 to acknowledge the exposure, or the server refuses to start. The public project server on port 5733 is always network-reachable.
Admin login is protected by a per-IP rate limit and a per-account lockout (five wrong passwords locks the account with escalating backoff). Changing or resetting a password immediately invalidates every existing session for that user.
Zero-config by default. To tweak, use config.json or environment variables.
| Variable | Default | What it does |
|---|---|---|
OPENFABRICA_ADMIN_PORT |
5734 | Port for the admin panel |
OPENFABRICA_ADMIN_BIND |
127.0.0.1 | Interface the admin panel binds to (loopback by default) |
OPENFABRICA_ADMIN_EXPOSE |
Set to 1 to allow binding admin to a non-loopback address (required alongside a routable bind) |
|
OPENFABRICA_PUBLIC_PORT |
5733 | Port where your project is served |
OPENFABRICA_DATA_DIR |
./data | Where project data is stored |
OPENFABRICA_DB_PATH |
<data_dir>/openfabrica.db |
Path to the core SQLite database |
OPENFABRICA_SEED_PATH |
./seed.json | Seed data loaded on first run |
OPENFABRICA_JWT_SECRET |
auto-generated | JWT signing key (min 32 chars) |
OPENFABRICA_ENCRYPTION_KEY |
auto-generated | At-rest encryption key (64 hex chars) |
OPENFABRICA_ALLOW_KEY_REGEN |
Set to 1 to permit generating anewjwt.key /encryption.key when the file is missing but a database already exists. Off by default: a missing key on a populated data dir makes the serverrefuse to start rather than silently mint a new one. Regeneratinginvalidates every session (JWT key) and makes previously-encrypted secrets - provider keys, OAuth/payment tokens, TOTP seeds -permanently unreadable (encryption key). Set it only if you have no key backup and accept that loss. |
|
OPENFABRICA_TLS_DISABLED |
false | Skip binding :80/:443 (use when another web server owns those ports) |
OPENFABRICA_TLS_STAGING |
false | Use Let's Encrypt's staging CA (avoids the production rate limit while iterating) |
OPENFABRICA_LOG_LEVEL |
info | debug ,info ,warn ,error |
OPENFABRICA_MEMORY_LIMIT |
Soft heap ceiling (e.g. 1GiB ,512MiB , or raw bytes;0 disables). Applied via Go's soft memory limit so GC pushes back before the process is OOM-killed. When unset, aGOMEMLIMIT in the environment is still honored. Not tenant isolation: pair it with a container/OS hard limit + auto-restart for untrusted apps. |
|
OPENFABRICA_RATE_LIMIT_RATE |
100 | Requests per second per IP |
OPENFABRICA_RATE_LIMIT_BURST |
200 | Burst allowance above the rate |
OPENFABRICA_LLM_TIMEOUT |
900 | Per-LLM-call deadline in seconds |
OPENFABRICA_ENGINE_DAILY_TOKEN_BUDGET |
1000000 | Max cost-weighted engine tokens per project per UTC day. The build/self-repair loop s when reached. Set 0 for unlimited. Resolution order: env var > admin/setup setting > config.json > default (applies live). |
OPENFABRICA_ENGINE_STAGE_EXPAND_TIMEOUT_MIN |
2 | Wall-clock timeout (minutes) for the EXPAND stage. Overrides the built-in default; raise it when a slow provider makes a legitimate build exceed it, instead of rebuilding the binary. |
OPENFABRICA_ENGINE_STAGE_PLAN_TIMEOUT_MIN |
30 | Wall-clock timeout (minutes) for the PLAN stage. |
OPENFABRICA_ENGINE_STAGE_BUILD_TIMEOUT_MIN |
90 | Wall-clock timeout (minutes) for the BUILD stage. |
OPENFABRICA_PUBLIC_CSP |
(permissive) | Override the CSP on public project pages. The permissive default carries 'wasm-unsafe-eval' so WebAssembly modules (TensorFlow.js, MediaPipe, ffmpeg.wasm, game engines) compile - the browser gates WASM behind CSP, and this keyword permits only WASM compilation, not JavaScripteval() . Put the literal{nonce} token in ascript-src and the server mints a per-request nonce so inline scripts work without'unsafe-inline' . Or set it to the keywordhardened for a built-in strict preset (scripts locked to'self' + nonce +'wasm-unsafe-eval' ; external images, fonts, and styles still load). Also settable per project. Empty string removes the header. |
OPENFABRICA_NO_BROWSER |
Set to any value to suppress auto-opening the admin URL on startup. | |
OPENFABRICA_OLLAMA_KEEP_ALIVE |
30m | How long Ollama keeps a model (and its prefix cache) resident between calls. -1 keeps it resident,0 unloads after each call. |
OPENFABRICA_OLLAMA_NUM_CTX |
Ollama context window for build calls. Set it at least as large as the build prompt (~16k+ tokens) so the cached prefix isn't evicted. |
A few knobs are set only in config.json (no env-var override). cors_origins is a JSON array of origins allowed to call the public project APIs cross-origin; when omitted it defaults to permissive (*, credentials withheld) - set it to your app's origins if you serve untrusted or multi-user apps.
When using Ollama, run the daemon with OLLAMA_NUM_PARALLEL=1 for best prefix-cache reuse. Stock-photo providers (Pexels, Unsplash, Pixabay) are optional: configure them from the admin UI or seed a key via PEXELS_KEY, UNSPLASH_KEY, and PIXABAY_KEY.
Requires Go 1.26+. No C compiler needed, the SQLite driver is pure Go.
git clone https://github.com/markdr-hue/open-fabrica.git
cd open-fabrica
make dev # run directly, or: go run ./cmd/openfabrica
make build # stripped, version-stamped binary in ./bin
Before opening a pull request, run the local quality gates with make check
(gofmt + vet + build + tests). See CONTRIBUTING.md for the
full developer guide and CONVENTIONS.md for house rules.
To see what a build actually did, and what it cost, read TRIAGE.md.
Open Fabrica runs a per-project background worker, the engine (engine/), which walks each project through a stage pipeline:
EXPAND → PLAN → BUILD → LIVE
|
+--- (validators; any failure feeds a bounded fix-pass)
EXPAND sharpens a sparse brief; PLAN seeds a build checklist; BUILD works through it in one continuous, prompt-cached session, then runs the validators (a headless-Chrome runtime probe plus websockets smoke tests). Failures feed back as a bounded fix-pass until clean (or they ship as known issues), then the project goes LIVE. Chat changes re-enter at PLAN and BUILD rebuilds only what actually changed.
Every stage runs through one unified session loop (engine/session.go): an append-only, byte-stable transcript so provider prompt caches hit across iterations, plus a content-addressed replay cache (of_llm_cache) that makes crash resume and retries nearly free. Context overflow ends the segment and reseeds deterministically from database state, the same mechanism that powers crash recovery.
All LLM-facing guidance lives in one knowledge tree (knowledge/): an always-on mental-model.md, recall-on-demand capability guides, canonical contracts, and per-stage frames + fragments. The pack package selects and renders them into each stage's byte-stable system prompt. Load-bearing facts (REST envelope, auth_token key, E2EE wire envelope, realtime frames, trigger events, payment flow) are defined once in contracts/ and transcluded via {{contract:<id>}}, so a copy can't silently drift; a consistency test fails the build if it does. Tools live under tools/, each registering a declarative tools.Tool. Guard tests ( TestNoCrossPackDuplication, TestGovernedDocsMatchContracts, the *_drift tests) fail the build on a drifted copy.
See LICENSE (MIT) for details.
Open Fabrica stands on a lot of excellent open-source work. Special thanks to Let's Encrypt for free HTTPS, and to the libraries it's built on:
- modernc.org/sqlite : a pure-Go SQLite, and the reason the whole app ships as one binary with no cgo and cross-compiles anywhere.
- goja : the embedded JavaScript engine that runs model-authored server functions and multiplayer game logic in a sandbox.
- esbuild : parses and statically analyses the JavaScript the model writes.
- chromedp +cdproto : headless-Chrome automation for the runtime validator and PDF generation.
- certmagic : automatic Let's Encrypt issuance and on-demand TLS.
- chi : HTTP routing.
- coder/websocket : WebSockets for realtime rooms, feeds, and calls.
- golang-jwt : JSON Web Tokens for end-user auth.
- ledongthuc/pdf : PDF text extraction.
Plus google/uuid, zap, and the Go team's golang.org/x`` crypto, net, and text packages.
Hi I'm Mark.
Be nice to others. It makes the world a much nicer place to live in!
If you need me I'm on X (@antifoundering)
I don't do hype, and I believe real talent is hard to find. A significant portion of workplace activity is self-justifying: processes and tasks that exist to preserve roles rather than produce outcomes.
The workplace fascinates me precisely because I've never figured it out. Sandboxes governed by their own rules and power dynamics, none of which ever made sense to me. But people want to belong to something. A group, a mindset, a reassurance that they're doing great things while wearing a hoodie with the company logo on it. Until a higher paying job comes along.
I think there's comfort in that, in running on autopilot. Honestly, I wish I could. It would have spared me the mental toll, and everything that followed from it: the physical, the relational, the financial. That's the cost of trying to act like a machine when you aren't one.
So if you want to take anything from this: you'd better hope you're a robot. Otherwise life will bring you to your knees while the world keeps moving. I've used the workplace as an example, but this applies to everything.
Or maybe, just maybe, it's all just me.