Open-source alternative to sites/artifacts
Sites, apps, documents and designs — built by agents, hosted on your machine.
Quick start · What you can build · Connect an agent · Documentation
Flats turns your own machine into a home for the things you build with AI. Deploy a website, run a small server app, share an HTML page, collaborate on a Markdown document or lay out a design canvas. Start Private on local loopback, then choose who can reach it through explicitly permitted network providers.
One CGO-free Go binary. macOS and Linux. A web console, CLI, HTTP API and MCP endpoint. No hosted Flats control plane.
| Your machine, your data | Built for agent workflows | Private by default |
|---|---|---|
| Keep code, SQLite databases, persistent files and encrypted secrets locally. | Connect Claude Code, Codex, Cursor or another MCP client. Inspect and approve deployments in the console. | Use Local or a permitted private network. Public sharing is a separate, approved choice. |
| Type | Made for | How it goes live |
|---|---|---|
| Website | Static sites and sandboxed JavaScript or WASI server apps | Save a Private Draft and preview it. Approve saving it as a numbered version, then approve deploying that version. Deployed versions support rollback. |
| Page | A single HTML document with bundled assets: charts, reports and visualizations | The same Draft, version and deployment flow as websites. No server code or data storage. |
| Document | Live, collaborative Markdown | Create or save to run immediately, initially Private. No Draft, versions or publish step. |
| Design | A canvas of HTML artboards: screens, landing pages, posters and click-through prototypes | Changes are live at once, initially Private. Every change is kept as a revision you can pin or roll back. |
Websites and pages follow the version model: you work on a Private Draft while the live version keeps serving, and previews use isolated data. Saving a version (v1, v2, ...) and deploying it are separate approved steps, so a version can exist without ever going live. Publication and rollback require console approval.
Documents and designs are edited live by people and agents together: private visitors can edit while public visitors read, and changes to an already Public flat are visible immediately. Documents merge agent saves into people's edits; designs keep every change as a whole-canvas revision. Changing visibility in either direction requires approval for every type.
Explore content types for the full lifecycle and
agent tools, including save_page, update_document and save_design.
On macOS or Linux, with an amd64 or arm64 machine:
curl -fsSL https://raw.githubusercontent.com/gosuda/flats/main/install.sh | shThe installer verifies the release, installs flats to ~/.local/bin and
starts it as a background service, without sudo. The default network is
Local; other providers are off.
mkdir -p hello
printf '<h1>Hello from Flats</h1>\n' > hello/index.html
flats save-draft hello ./helloRun the exact flats create-version command printed by the save above; its
--revision and --hash freeze the files you saved, even if someone edits
the Draft afterwards. The command asks to save that Draft as version 1. Follow the approval URL it
returns, or open the local console, and approve it.
That creates v1 but puts nothing live yet. Deploy it with Publish v1 in
the console, or request it from the CLI and approve that request too:
flats deploy --flat hello --version 1Then visit hello.localhost:7879.
flats deployreturns exit code 3 while a request awaits approval, including with--json. Saving a Draft or a version does not make a site live; only deploying a version does.
Run flats status to check the host. See
installation and upgrades for installer
options, upgrades and backups.
Other ways to run Flats: container, foreground or source
A Linux image for amd64 and arm64 is published with every release. On Linux, use host networking so the console, CLI and agents reach it on loopback:
docker run -d --name flats --restart unless-stopped --network host \
-v flats-data:/data ghcr.io/gosuda/flats:latestNever publish the console port to your network: anything that reaches it can approve deploys. See Running Flats in a container for other Docker hosts and network modes.
flats serve --config ./flats-demo-data/config.jsonOn first start, this creates a host with the defaults in ./flats-demo-data.
It never does that over a directory that already holds Flats data. Each
running host needs its own data directory and ports; see
Configuration and storage.
Requires Go 1.27.1 or newer:
go install github.com/gosuda/flats/cmd/flats@latestUse @main for unreleased changes. This build does not include NetBird; see
Serving through NetBird to build
the release binary from a checkout.
Connect Claude Code, Codex or Cursor with the Flats plugin, which runs
flats mcp (the flats CLI must be on the agent's PATH) to relay the
selected host's MCP endpoint; any other MCP client registers
http://127.0.0.1:7878/mcp directly. For example, in Claude Code:
claude plugin marketplace add gosuda/flats && claude plugin install flats@flatsConnecting agents covers the other clients, remote hosts
(flats connect), client updates and llms.txt. The agent starts with
read-only check_client, then reads the server's current guide.
For the whole server contract in one document, read resource
flats://docs/runtime-api/v1 or call get_runtime_reference with {}.
The runtime API v1 reference is embedded in the host
and available through MCP without an installed skill or source checkout.
Static builds need an index.html. For a JavaScript app, add a flats.json:
{"kind":"server"}Then create server.js:
export default {
async fetch(request, env) {
env.DB.exec("CREATE TABLE IF NOT EXISTS hits (n INTEGER)");
env.DB.exec("INSERT INTO hits VALUES (1)");
const [{ n }] = env.DB.query("SELECT count(*) AS n FROM hits");
return Response.json({ hits: n });
}
};Save the directory with flats save-draft <slug> <dir>, create a version with
flats create-version <slug>, then deploy that version after approval. JavaScript runs in
QuickJS on WebAssembly, with SQLite (env.DB), persistent string files
(env.FILES), Web Crypto and WebSocket callbacks. There are no Node.js APIs;
bundle imports into the uploaded version. Server-side fetch can call exact
operator-granted HTTP(S) origins; see Calling external APIs.
WASI, persistent data and environment variables
A .wasm server is a WASI preview1 command instantiated afresh per request:
request JSON on stdin, response JSON on stdout, only the flat's configured
environment variables and secrets, with no inherited host environment, plus
clocks and randomness. It has no SQLite/FILES host ABI, filesystem mounts,
outbound network or WebSocket API. See the
capability table and response format.
Data survives deploys and ordinary rollbacks. flats rollback hello restores
code; --restore-data requests a separately approved restore of the
pre-deploy DB and FILES snapshot. Preview data is isolated from live data.
Ordinary environment variables (flats env set hello GREETING 'Hello') and
encrypted secrets reach server code as env.NAME, or as environment variables
for WASI. Saving a value leaves running workers on their snapshot. The live
worker picks up current values at the next approved deployment, redeployment,
rollback or data restore, or when the Flats host restarts; a newly created
preview also loads them. See
App environment variables and
Secrets.
Start locally, then enable the providers you need in Settings → Network providers. Allow a provider for an individual flat under Networks on its Settings tab.
| Access | Providers |
|---|---|
| Private | Local (always on), Tailscale (tailnet ACLs), NetBird¹ (access policies) |
| Public | Portal, Tailscale Funnel, zrok, Cloudflare quick tunnel, NetBird Expose¹ |
¹ NetBird and NetBird Expose are in the release binary (install.sh and the
container image) but not in go install; see
NetBird setup.
Host permission alone does not grant a provider to a flat. Configured provider defaults can grant providers to new flats; changing those defaults does not retroactively change existing flats. Tailscale permission does not imply Funnel permission.
Making a flat Public requires an approved transition and a configured, permitted public route. Websites and pages also need a published version; documents and designs run without publication. Configuration alone never publishes or changes visibility. Wait for a route to report ready and verify its endpoint before sharing it: relay availability and network connectivity are external dependencies.
See Private and public access for provider setup, tailnet consoles and upgrades from older hosts.
- Sandboxed execution. Server code runs in separate worker processes with WebAssembly memory and time limits, bounded request bodies and WebSocket connections, SQLite and FILES quotas, and restricted host capabilities. Each flat and preview gets its own origin.
- Privileged console. The management listener and console can approve deployments. Approval decisions require the console header and a same-origin browser request. That is CSRF protection, not authentication: a local process that sends those headers can decide approvals. Run only trusted agents on the host and restrict console access with tailnet ACLs.
- Local secrets. Secrets are encrypted with the local
secret.key; secret APIs expose names only. A flat can read and return its own secrets, so deploy code you trust with them. Anyone who can read the data directory can recover those secrets. - Back up your data. Immutable code versions are not data backups. Back up
the data directory, including
secret.key; see what to back up.
Read the design and trust model for the details.
Browse the complete documentation index for contracts, internal design and verification guides, and the product specs for what Flats is meant to do, including targets that are not fully implemented yet.
