how it works

The app is a body.
The agent is the mind.

A code generator writes an app and walks away. Snug keeps a live wire between the running app and whatever model you point it at — and puts the whole thing, code and data both, in one file you own. Six diagrams, no slideware: here is the actual mechanism.

The bridge

Any model, same app

Anthropic, OpenAI, or Ollama on your laptop. Swap at runtime; the app doesn't change.

The file

One portable .snug

Real SQLite — open it with sqlite3 if you want. Apps, versions, data, chats.

The boundary

No backend, still connected

Your bank, Coinbase, Spotify — called by the host. Tokens never enter the app or the model.

If you read one thing

An app built with Snug has no intelligence of its own — a chess app ships no chess engine. It sends the board over a versioned postMessage protocol and the host's model sends back the move. That makes the app tiny, model-agnostic, and cheap enough to run on a local model — which is what makes a fully private, no-server, no-account deployment possible at all.

Fig 1

Codegen hands you an orphan. Snug keeps the wire live.

The difference is not code quality — it is whether the intelligence is present at runtime. A generated chess app must ship a chess engine. A Snug chess app sends the board over the bridge and animates the reply.

THE USUAL WAY — CODE GENERATIONModelwrites the codeemitsFinished appstatic bundlelink ends at build timeRuns alonelogic frozen in the fileTo get smarter it must beregenerated — a new build.THE SNUG WAY — RUNTIME BRIDGEMicro appthe body · UI + stateHost agentthe mind · any LLMapp-messageapp-responseEvery move, every question, every turn —while the app is running.The app ships no intelligence of its own.A chess game carries no chess engine. A budget app carries nocategorizer. They carry a runtime contract — ~1.26 KB/turn — thattells any brain how to answer. Small local models included.
The consequence: the app never goes stale. Point it at a better model next year and it gets better without a rebuild — and because it carries no model-specific logic, “better model” can also mean “smaller model that now runs on your laptop.”
Fig 2

The runtime is a socket. Anyone can be the brain.

The bridge speaks one versioned wire protocol — thirteen frames, seven message kinds, v1. Whoever supplies the intelligence sits behind an adapter. That is the whole switching cost: an adapter.

THE USER'S DEVICELedgerbudget · own DBRewindSpotify · own DBChessagent plays you…anything the userdescribes in chatuser.snugone SQLite file · all of itcode · versions · data · chatsTHE SNUG ENVELOPE — wire protocol v1, frozenapp-announce · host-ready · app-message · app-response · db-request · net-request · +713 frames7 kinds↕ ADAPTER SEAM — THE ONLY THING THAT CHANGES PER PROVIDERAnthropicshipped adapterBYOK or subscriptionOpenAIshipped adapterBYOK or subscriptionLocal modelOllama · on the laptopnothing leaves the deviceYour runtimeany company, any modelwrite one adapter
What this buys you: Snug is deliberately not a model company and not a cloud. Every provider is a plug behind one frozen wire format, so “which model?” becomes a settings choice instead of a migration — and any company can host the runtime without owning the apps or the data.
Fig 3

No backend — yet it talks to your bank.

There is no Snug server in this picture, and that is the point. The app itself has no network at all. Every outside call is made by the host on the app's behalf, with the credential injected after the app is out of the loop.

SANDBOXED APPMicro appiframe · allow-scripts onlyconnect-src 'none'It cannot open a socket.Not restricted — incapable.net-request“get my balances”no token in itTHE HOST — TRUST BOUNDARYConnected-fetch executorthe only code that may call outsnug_secretstokens live inside the user'sown file — never a server vaultFrozen host ceilinghuman-approved scopes · per connectionInject → call → scrubcredentials stripped from the replyauthenticatedcallYOUR SERVICESYour bankSimpleFIN · real balancesCoinbaseholdings · pricesSpotifylistening historyGmail · WhatsApp · Hueand anything with an APInet-response — data only, credentials scrubbedThe invariant, enforced in code and tested:A credential never enters the app iframe · never reaches the LLM · never reaches a publisher · never leaves as telemetry.
Read the shape, not the boxes: the app sits on the left with no way out, the credentials sit in the middle behind a boundary, and the model never appears on this path at all. Security here is architectural — there is no policy toggle that could weaken it.
Fig 4

One use case, both worlds: where does your money data live?

A budget app is the honest test, because the data is the most sensitive a consumer has. Both rows below use a bridge to reach the bank — that part is unavoidable. The difference is what each intermediary is allowed to keep, and where the consolidated picture is assembled.

TODAY — THE AGGREGATOR MODELYour bankscheckingsavingscardsbrokeragecredsThe aggregatora company, in the data pathHolds your full historyconsolidated, on their serverscopiesTheir analyticscategorization · partnersTheir hosted modelsees your questions + rowsYouget a view of dataheld somewhere elseexit = start overSame bank data. Same question — “where did my money go last month?” — asked of a different architecture.WITH SNUG — THE LEDGER APPYour bankscheckingsavingscardsbrokerageread-onlySimpleFINa bridge, not adestinationtoken you holdand can revokepassesthroughYOUR DEVICE — WHERE THE PICTURE IS ASSEMBLEDLedger appsandboxed · no networkuser.snugthe only consolidated copyLocal modelOllama, on this machineanswers “where did mymoney go?” from your rowsnothing leaves the deviceWho ever holds your consolidated financial picture?Aggregator model: the aggregator, its analytics, its model provider, and whoever acquires them. · Snug: your device.
The one difference: in the top row the consolidated picture is assembled on someone else's server, and that box persists — through acquisitions, policy changes, and shutdowns. In the bottom row every intermediary is a pass-through and consolidation happens only inside user.snug. Note what is not claimed: both rows cross a bridge to reach the bank. SimpleFIN is an aggregator too. The claim is not “no intermediary” — it is no intermediary that accumulates.
Fig 5

Private mode: the whole system, on one machine.

Same protocol, same apps, same file — with the model moved onto the machine. Nothing in the architecture changes, because the provider was always just an adapter.

ONE MACHINE · macOS DESKTOP · SIGNED + NOTARIZEDMicro appssandboxed iframesno network of their ownenvelopeHost runtimenative fetchloopback OAuthLocal LLMOllamalocalhost only~/Snug/user.snugevery app · every version · every row of data · every chat · settings · secretsoptional whole-file encryption · opens with ordinary SQLite toolsoptionalThird partiesonly when the userapproves a connection— and only theseNo Snug serverno account requiredno telemetryIn this mode the prompt, the data and the model all stay inside one perimeter — which is what a regulated environment needs.
Try it yourself: pull the network cable and keep building apps. The same .snug file then opens on a machine running a frontier model in the cloud — same apps, same data, different brain. Desktop is macOS-only through 1.0 for a stated security reason; see the limits below.
Fig 6

What the user actually carries.

Most platforms keep your apps as rows in their database. Snug's unit of ownership is a file — and that single decision is what makes portability across devices and vendors possible at all.

ONE FILE — REAL SQLITEuser.snugApps + ≥5 pinned versionsPer-app isolated databasesChat threads + per-app wiki docsSettings + secrets (stripped on export)Openable with any SQLite tool. No lock-in by construction.movesyncswitchAny devicemacOS desktop · browser · copied to a drive · emailed to yourselfAny origin you pickDropbox · your own hub · nowhere at all — the sync target is your choiceAny providerAnthropic → OpenAI → a local model: the apps and the data come with youThe vendor holds nothing you need back.
The inversion: most platforms retain you because leaving costs you your data. Here leaving costs you nothing — the file is already on your disk, in a format that predates the project and will outlive it. Retention has to come from the protocol being good.

design decisions

Six choices that make it work

None of these are clever code — the whole thing is MIT-licensed and public. They're constraints, and each one closes off something that would otherwise be tempting to build.

The spec is the product

Specification 1.0 is normative and published, with a conformance checker that fails the build when the paper and the schemas disagree. A protocol others implement is a standard; a product others clone is a feature.

13 frames · 7 kinds · wire v1 frozen

Security by construction

The token boundary and the sandbox have no bypass flag — not “secure by default,” but no switch to flip. The published threat model also states what is accepted and not mitigated, with equal prominence.

threat model re-attacked pre-launch

Provider neutrality

A model vendor has little reason to ship “your apps run just as well on our competitor's model.” Snug's whole premise is that sentence, which is easier to mean when you don't sell inference.

adapters: anthropic · openai · local · mock

Runtime contracts

Apps are cheap enough per turn to run on a small local model — the unlock for private, on-device and regulated deployments. It's what turns “portable in principle” into “portable to a laptop that's offline.”

~1.26 KB/turn · version-pinned per app

Embeddable, so it spreads

Any product drops in the runner and SDK, and their users build micro apps powered by their assistant. Snug wins by being adopted, not by being visited — the hosted Playground is the demo, not the business.

@snugprotocol/runner + /sdk

Shipped, not slideware

A signed, notarized macOS build is in users' hands. The protocol, the threat model, the whitepaper and the reference implementation all exist and are public today.

Developer ID · notarized · MIT

What this doesn't do

The diagrams above show the design working. These are the parts where it doesn't, or doesn't yet — stated here because you'd find them anyway, and the published threat model lists them in more detail than this page has room for.

  • The model does see your app's data. That's the entire point of the bridge — if you ask a budget app where your money went, the rows travel to whichever model you chose. What never travels is the credential. Choosing a local model is what makes the data stay put too; with a hosted model, that provider's normal terms apply.
  • Desktop is macOS-only through 1.0. Not a roadmap gap — on Windows, WebView2 injects the shell's IPC key into sandboxed app iframes and no off-switch exists at any layer. That breaks the sandbox guarantee, so no Windows build ships until it's fixed upstream. The browser version runs everywhere.
  • Lose both secrets and the data is gone. Whole-file encryption is opt-in and key-wrapped, with a recovery key as an independent unlock path. If you lose the passphrase and the recovery key, nobody can help you — there is no server-side copy by design.
  • Hosted credential custody isn't built. Credentials live in your own file today. The broker that would let a publisher operate connections on your behalf is deliberately unbuilt and deferred well past 1.0.
  • It's pre-1.0 outside the spec. Specification 1.0 is normative and frozen at wire v1; the implementation packages are still moving and may break between releases.
  • “No telemetry” means the app and this site, not the whole internet. The desktop app has no analytics and no account; this website loads no third-party scripts — check the page source, or your network tab. What it can't speak for is your OS, your browser, or a model provider you choose to connect: those have their own terms.

Read it, run it, or take it apart.

MCP connected agents to tools. Snug connects agents to apps — and hands the app to the user. All of it is MIT.

Or run it with no API key at all: pnpm install && pnpm dev starts a mock model and the Playground in one command.