brisk

Everything Brisk does

One page, because that's all it needs. A Brisk site is a folder of static files plus, if you want it, six backend primitives reachable from one script tag. There are no other features.

Deploying

Install the CLI once, then any folder is one command away from being a site:

npm install -g @usebrisk/cli

brisk login this-host  # sign in once, stores a profile (like AWS profiles)
brisk init my-site     # scaffold (optional — any folder works)
brisk deploy my-site   # → https://my-site.your-host/
brisk dev my-site      # redeploy on every save
brisk list             # everything on this instance
brisk pull some-site   # download any site's source to remix it

Signed-in members can also skip the CLI entirely: drag a folder anywhere onto the dashboard, name it, launch. Deploys are atomic: files upload to a fresh version, then the live pointer swaps. Site names are first come, never owned. Anyone signed in can overwrite anything, including this dashboard (deploy a site called home).

Every publish is a versioned snapshot. Only the current version is ever served; by default the previous one is cleaned up once the pointer swaps, so storage stays bounded. The person running the instance can set DEPLOY_HISTORY=on to retain every version instead — groundwork for rollback, which isn't exposed yet.

brisk login opens the browser, finishes this instance's login, and stores a personal token under a profile — so deploys are attributed to you, and you can hold profiles for several Brisk instances at once (--profile or BRISK_PROFILE picks one; brisk whoami tells you where you are). CI skips profiles: BRISK_SERVER + BRISK_TOKEN.

The SDK

Every site, deployed or not, can load the SDK from its own origin:

<script src="/brisk.js"></script>

That's the entire setup. No API keys (they live on the server), no configuration, no build step. brisk is a global with five namespaces, each scoped to the site that loads it.

One caveat: every namespace below needs the viewer to be signed in. On a public (view-only) instance, signed-out visitors can see pages but every brisk.* call rejects with a 401 — build demos so they degrade gracefully.

Database

Schemaless JSON collections, Firebase-style. Treat it like a big persisted JSON store: no schemas, no migrations, shape your data freely.

const posts = brisk.db.collection('posts');

const doc = await posts.create({ title: 'Hello', votes: 0 });
const all = await posts.list({ sort: '-created', limit: 50 });
await posts.update(doc.id, { votes: doc.votes + 1 });  // shallow merge
await posts.delete(doc.id);

// realtime: fires for every change anyone makes
const stop = posts.subscribe({
  onCreate: (doc) => {},
  onUpdate: (doc) => {},
  onDelete: (id) => {},
});

Docs carry id, createdAt, updatedAt. Collections are namespaced per site, so name things whatever you like — except the reserved _plugin:* namespace: plugin data reads (and subscribes) like any collection, but writing it goes through the plugin's own actions, which stamp the author and keep the audit trail honest.

Identity

The platform authenticates members before any page loads, so sites get identity for free. No login flows, ever.

const user = await brisk.me();
// { email: 'sam@yourco.com', name: 'Sam', picture: '…' }
// rejects with a 401 for signed-out visitors on a public instance

AI

LLM calls straight from the browser. The server holds the provider keys (Anthropic or OpenAI) and proxies the request.

const res = await brisk.ai.chat('Turn these notes into a haiku: …');
res.text;

// or full control:
await brisk.ai.chat(
  [{ role: 'user', content: 'hello' }],
  { system: 'You are terse.', model: 'claude-opus-4-8' },
);

Files

const [file] = await brisk.fs.upload(input.files);
file.url;   // permanent, immutable URL

Channels

Realtime messaging with presence. This is the multiplayer primitive: cursors, games, live polls, collaborative anything.

const room = brisk.channel('lobby');

room.send({ x: 128, y: 64 });                    // to everyone else
room.on('message', (data, from) => { … });       // from = { email, name }
room.on('presence', (members) => { … });         // join/leave
room.members;                                    // current list
room.leave();

Plugins

Curated, first-party features a site switches on in brisk.json, injected into its pages automatically. A platform layer, not a seventh primitive — sites consume plugins; extending the set is a fork concern. Each is mandatory, on by default, or optional:

{ "name": "my-site", "plugins": { "comments": false } }

Comments (on by default) lets teammates leave feedback on any element. Notes start as local drafts (copy them as markdown for an agent — drafts sit in the browser's localStorage, which path-mode sites share, so local ≠ private); publish to share with realtime + a best-effort audit trail. Drive it from the terminal — the same verbs an agent uses:

brisk plugin comments list   my-site        # open feedback, as a table
brisk plugin comments export my-site        # markdown an agent can act on
brisk plugin comments reply  my-site <id> "fixed it"
brisk plugin comments resolve my-site <id>

The widget minimizes to a corner bubble you click to reopen; Shift+C fully hides it. brisk plugin list shows what's installed; brisk plugin <id> --help lists a plugin's verbs, loaded live from the server.

Philosophy

Brisk stays useful by staying small. No site owners, no permissions, no custom backends, no cron jobs. Everything is open to every teammate, which is exactly why a leaderboard takes five minutes instead of a security review. When a feature request shows up, the answer is usually a demonstration that the six primitives above already cover it.

Running your own instance — setup, login, subdomains, and cost — is on the hosting page; the architecture and internals live in the repo.