# DAI Protocol > An app that is just a file. A .dai container holds an application, its > SQLite database and its runtime in one HTML file that opens offline, runs > in a frame with no origin and no network, and can be sent to anybody. Writing an application that runs inside a container: - [The model file](https://www.dynamicapplicationinterface.io/llms-full.txt): everything needed to write an application, in one pass — the shape decision, every constraint with its reason, the surface, and one complete application per shape. Start here. - [The same, for pasting into a chat](https://www.dynamicapplicationinterface.io/recipe.txt): the model file with a last line inviting you to say what you want. - [Choose a shape](https://www.dynamicapplicationinterface.io/docs/choose-a-shape): the decision before any table is written. - [Constraints](https://www.dynamicapplicationinterface.io/docs/constraints): every rule by id, with its reason and what enforces it. - [Writing apps](https://www.dynamicapplicationinterface.io/docs/writing-apps): tutorials, how-to guides and explanations for people. The surface an application is given: - `await window.dai.openDatabase()` — Opens the database inside this file. In a shared document it waits for the host's write rules first. - `db.exec(sql)` — Runs one or more statements. - `db.exec({ sql, bind })` — Runs a statement with bound parameters. Omit bind when there are none: an empty array throws. - `db.selectObjects(sql, bind?)` — Returns rows as plain objects. bind is an array for ? or an object for :name. - `db.selectValue(sql, bind?)` — The first column of the first row — a count, a setting, a total. - `window.dai.autosaves` — True under a host: every write is saved as it happens, and nothing needs pressing. - `await window.dai.saveDatabase(db)` — Saves now. Needed only where there is no host (a file opened straight in a browser). Returns { saved, method }. - `window.dai.exportDatabase(db)` — The database as bytes, without saving. - `window.dai.documentUuid` — This document's identity. - `window.dai.signature` — "valid", "unsigned" or "invalid" for this container. - `window.dai.onAppModeChange(fn)` — Called when the container enters or leaves full-screen App Mode. - `window.dai.requestShare(session?)` — Opens the host's own share sheet — the same one behind its menu. Does not share anything itself: the person still sees the card, still chooses whether to include their data, and still presses Send. In a session document, pass the session id to make it an invite into that one session: the copy that travels holds only that session's rows, and none of the other sessions or of this copy's local tables. Without one, the whole document is offered. - `window.dai.replicated.insert(table, values, session?)` — Creates a shared row and returns its entity (32 hex characters). values is an object of your own columns. In a session document, session (hex) is required. - `window.dai.replicated.change(table, entity, values)` — Writes a new version of a shared row, naming every current version as its parent — which is also how a conflict is resolved. values carries every one of your columns. Returns the entity. - `window.dai.replicated.remove(table, entity)` — Deletes a shared row by writing a tombstone. The row leaves t_current. Returns the entity. - `window.dai.replicated.session.create()` — Starts a session: seats this copy and leaves one open seat. Returns { session, seat } as hex. - `window.dai.replicated.session.join(session, seat)` — Binds this copy to an open seat. Call it when this copy opens an invite (SESSION-JOIN-ON-OPEN). - `window.dai.replicated.session.close(session)` — Closes a session at what this copy has seen. Throws CLOSE_NOT_PERMITTED for a non-creator under close=creator. - `window.dai.replicated.session.reseat(session)` — The creator's repair for a contested seat: replaces the open seat so a fresh invite can be taken. Throws NOT_SEAT_CREATOR for anyone else and CANNOT_RESEAT when no seat is contested. - `window.addEventListener("dai:merged", fn)` — Fired when another copy's rows arrive. event.detail: { applied, duplicate, rejected, newReplicas, conflicts, via } — via is "carrier" (a file or link was opened) or "mailbox" (rows arrived in the background). - `window.daiKit.refresh()` — Re-runs every kit query on the page. Call it in the dai:merged listener when the page uses or . Custom properties a host sets on the application root: - `--dai-safe-top` — How much of the top edge a status bar covers. - `--dai-safe-right` — How much of the right edge is covered. - `--dai-safe-bottom` — How much of the bottom edge a home indicator covers. - `--dai-safe-left` — How much of the left edge is covered. ## The format - [Specification](https://www.dynamicapplicationinterface.io/docs/specification): the container format. - [Host bridge](https://www.dynamicapplicationinterface.io/docs/host-bridge): the messages between a host and a container, for building a host. - [Security model](https://www.dynamicapplicationinterface.io/docs/security): what is isolated, what is signed, and what a signature does not prove.