--- name: quickish-publish description: > Give an HTML page a live URL on Quickish — and, when asked, give it a real backend. Use whenever the user wants to host, publish, or share an HTML page, slide deck, demo, portfolio, or one-pager (e.g. "publish this to Quickish", "host this page", "make this a live link"), OR wants that page to DO something: store data, sign in users, run server-side logic with a secret key, query a SQL database, or serve at their own domain. Quickish gives the page a URL at .quickish.site (personal) or .quickish.space (work), public or private, with a zero-config backend (quick.db, quick.fn functions, quick.sql) on the same page. Static pages need no build step; framework apps (React/Vite/Astro) must be built first and the build output published. No server to run. --- # Publishing (and building) on Quickish Quickish hosts a folder of web files (HTML + CSS/JS/images/fonts) and serves it at a Quickish URL — and that page can opt into a **zero-config backend** (a database, server-side functions, real SQL) with no keys and no separate service. The simplest unit is a **page**: a folder with an `index.html`. Each account has a **root page** at the bare domain, plus optional **sub-pages** at `//`: - Personal: `https://.quickish.site/` (root) · `…//` (sub-page) - Workspace: `https://.quickish.space/` (root) · `…//` (sub-page) **Goal: do the work for the user.** When they say "publish this," produce one self-contained `index.html` and publish it. When they say "build me a poll / a kanban / a form that emails me," build the page *and* its backend (below) and publish the whole thing. Hand back the live URL, not a list of files. ## Build the page first - Output a folder containing **`index.html`** at its root. Inline the CSS and JS; a single self-contained file is the most robust. Keep everything to web assets; files over ~25 MB are skipped. - Use **relative asset paths** (`./img/x.png`) or root-absolute (`/x.png`); the root page owns absolute paths, so both work. - Add `` to unlock the backend: `quick.db`, `quick.files`, `quick.identity`, `quick.realtime`, `quick.fn`, `quick.sql`. No keys needed. ## Icons (use the hosted set, don't hand-draw) Quickish hosts a curated **Lucide** line-icon set (ISC, ~170 common icons) at a stable path on every page — reach for it instead of pulling a random CDN, drawing inconsistent SVGs by hand, or emoji. Two ways to use it: - **Themeable (recommended)** — one cached fetch, inherits text color: ```html ``` Style with CSS (`svg{color:#3ef07f}` or `stroke`); the icons are `currentColor`. - **Simple** — `` (not recolorable). Names are kebab-case Lucide names: `search` `menu` `x` `check` `arrow-right` `user` `download` `image` `play` `settings` `trash-2` `star` … `GET /quick-icons/icons.json` lists every available name. Brand/social logos (GitHub, X, …) aren't in this set — use a brand-icon source if you need those. ## Framework apps (React, Vite, Next, Astro, …) Quickish hosts the **built static output**, not the framework source. If what you made is a project with a `package.json` and a build step (a Vite/React/Astro/etc. app), do **not** publish the source folder — the browser can't run `.tsx`/`.jsx` or unbuilt modules, so it would 404 or render blank. Instead: - **Build it, then publish the output folder:** run the build (`npm install && npm run build`) and publish the result, e.g. `quickish ./dist` (or `./build` / `./out`). - **Or let the CLI build it for you:** run `quickish --build` in the project. With the user's permission it runs the install + build **on the user's machine** and publishes the output. If a `dist/` already exists, plain `quickish` detects it and publishes that automatically (no rebuild). Only **static** output is hosted — server-rendered apps (Next SSR, Remix, SvelteKit's node adapter) won't run; use the framework's static export/adapter. When you can, a single self-contained `index.html` is still the most robust thing to publish. ## Publish with the `quickish` CLI This works end to end from a terminal and is the most reliable path. 1. Install once: `npm i -g quickish` 2. Sign in once: `quickish login` (opens a browser; the user signs in with Google and a token returns automatically. If headless, print the URL for them). 3. Publish the folder (or a single file): - **Home page**: `quickish ./my-deck` → `https://.quickish.site/` - **Single file**: `quickish ./index.html` → the file becomes the homepage. Any lone file works; an HTML file is served as `index.html`. - **A document** (a lone `.pdf`, `.md`, `.csv`, `.txt`, or image with no HTML) gets a built-in in-browser **viewer** automatically, with a Download button for the raw file — so `quickish ./report.pdf` just gives a real PDF reader at the URL. No wrapper page to build. - **Named sub-page**: `quickish ./my-deck deck` → `…/deck/` 4. The CLI prints the live URL. For a **personal** page it also prints a one-time "publish publicly" link; share it with the user, they click it once to accept the content policy and the page goes public. Updates never re-prompt. The CLI publishes the **whole folder**, so any `functions/` and `sql/` directories travel with it and deploy automatically (see "Add a backend" below). **Visibility flags** (override the defaults below): - `--private` only the owner - `--invites a@co.com,b@co.com` private to the owner and the people listed - `--workspace` anyone signed in at the company domain - `--public` the world, via the one-time consent ## Publish via the assistant API (no shell needed) If you can make HTTP calls but not run a shell, POST the page directly: ``` POST https://api.quickish.website/_assistant/publish Authorization: Bearer Content-Type: application/json { "html": "", "invites": ["a@co.com"] } ``` It returns `{ "url": "..." }`. The user gets their token from the dashboard (Settings -> Publish with AI); setup is at quickish.website/connect. `page`, `share`, and `invites` are optional. ## Overlay vs replace — how a re-publish treats other files A publish runs in one of two modes: - **overlay** (non-destructive) — writes the files you send and **keeps the rest** of the page untouched. This is the default for an **assistant `html`/`files` publish** and for a **CLI single file** (`quickish ./index.html`). Use it to change one or two files without disturbing the others. - **replace** (destructive) — a full sync that **deletes anything not in your bundle**. This is the default for a **`zip`** (a complete build) and a **CLI folder** (`quickish ./dist`) — correct there, because stale build chunks must be swept. Force it with `mode:"replace"` / `--destructive`. Practical guidance: - **Updating a file or two → overlay** (the default for `html`/`files`). Don't send a partial set in replace mode — it removes everything you left out. - **Shipping a fresh build / removing files → replace.** Before a destructive replace of a page **you didn't just author** (the user or another agent may have changed it), confirm with the user first; the live **URL** is the *rendered* page, not its source files, so don't reconstruct a publish from it. (A pull-the-source → edit → re-publish loop with publish-if-unchanged is coming.) - **Data:** `quick.db` rows are **not** touched by any publish, but they're shared and may have changed. Read current rows (`quick.db.collection(...).list()`, or the connector's `db_query`) before an `update`/`remove` so a stale write doesn't overwrite another writer. ## Visibility (defaults, then confirm) Defaults when you don't pass a flag: - **Personal** page -> **public** (after the owner clicks the one-time consent link). - **Workspace** page -> **company-visible** (anyone signed in at the same domain). For fine-grained, per-person access use `--invites` (or the `invites` field on the API). Always confirm the intended audience before publishing something company-wide or public. ## Add a backend (zero-config) With `` on the page, the same site gets a backend — no provisioning, no keys, scoped to that page. Reach for the smallest piece that fits. ### quick.db — a document store ```html ``` - A collection is **owned by the page** that creates it. Default access: **read by the page's audience, write by the owner** — so a public page can show data without letting visitors change it. Set per-op rules when you declare it: `quick.db.collection("comments", { read: "audience", create: "users", update: "author", delete: ["author","owner"] })`. Principals: `owner · audience · author · users · workspace · public` (`write` = create+update+delete). - Also available: `quick.files` (uploads — see below), `quick.identity()` (the signed-in visitor), `quick.realtime(channel)`, `quick.cast()` (turn the page into a screen pushed to from a phone). - **Org directory (workspaces):** `quick.org.sites()` (= `quick.db.collection("org_sites").list()`) returns the org's visible sites with **live hit counts** — each `{ id, name, url, owner, visits, visibility }` — kept current as teammates publish. Build a dynamic company directory/homepage with zero data wiring. - **Sample data for remixes:** `quick.db.collection("cards", { seed: true })` seeds those docs into every remix so a copy works on first run. ### Prebaking — render quick.db into the page for SEO When a **public** page lists quick.db content that needs to be crawlable (a blog, catalog, docs index, changelog, directory, landing page), don't render it with client-side JS — search engines and link-preview bots fetch the HTML and see an empty shell. Instead write the list as a `