Zvessa docs

Engines

Engines are the only server code a feature needs. Each is abstract (it knows records, members, rounds, balances, never "orders" or "VIP"), so every kit is settings on top of one or more of them. A new engine is added only when no engine can express a need. Ids and status: ENGINES in convex/lib/kits.ts and the Catalog.

Every engine follows the same pattern:

EngineStatusWhat it isDeep doc
CollectionsReadyAny records with fields the space definesData
SpacesReadyMembers, friends, every kind of conversation, feedsconvex/kits/talk/README.md, docs/SOCIAL.md
StructureReadyUnits of any kind (teams, classes, branches), levels and badgesconvex/kits/structure/README.md
LedgerReadyBalances in any unit and moves between themconvex/kits/ledger/README.md
RoundsReadyLive games and quick roundsconvex/lib/rounds/
RoomsReadyCalls, group calls, live streams (LiveKit)docs/LIVE.md
FilesReadyThe space's media librarydocs/LIVE.md
ScreensReadyA TV or big screen joins and shows pagesdocs/LIVE.md
TimeReadyBookings and posts scheduled for later
EventsReadyCounts of what happens, for analytics and leaderboardsData
AppsReadySandboxed mini-appsMini-apps
CapabilitiesReadyMCP server, key vault, outside connectionsdocs/CAPABILITIES.md
AudiencesReadyKids spaces with safe rulesPeople
LifecycleReadyDrafts, sending later, and posts held for approvalconvex/kits/talk/README.md

Collections #

Any records with fields the space defines: forms, contacts, boards, catalogs, notes. Blueprint collections; table records; functions records.*; blocks records.list, records.form, records.count, and split (totals a money field and settles up who owes whom).

Spaces #

A place with members, roles and conversation. Members, invites, join requests and friends live in members.* and friends.*. Every conversation is one engine (convex/kits/talk), keyed by a conversation key, so a new kind of conversation is a setting, not new code:

KeyIs
<stream id>A stream from blueprint.streams: mode room (everyone talks), broadcast (a channel: few post, many follow) or queue (each person opens a private case; a team answers)
dm:<a>:<b>A direct chat; it follows the two people across spaces
g:<chat id>A group people made themselves
c:<case id>One person's case in a queue (support request, application, order)

A stream's settings say who sees, posts, moderates and answers it (seeRoles, postRoles, modRoles, teamRoles), whether only one unit sees it (unit), replies inline or in threads, reactions, slow mode, roles whose posts wait for review, and a queue's statuses. blueprint.talk turns on direct chats, groups, emoji, read receipts, typing, edits and sending later. Every word is words["talk.<key>"]. Blocks stream, inbox, direct, queue, ask, drafts, members, invite; full screen at /c/<key>. Calls can attach to any conversation. Kits: group chat, channels, direct chat, teamspace, support desk, drafts and approvals.

Feeds (blueprint.feeds, convex/kits/social): a named place where people publish posts with words, photos and videos, and reply, react, repost, quote, save and follow. Every behaviour is a feed setting (replies off, flat or nested; media off, optional or required; length; titles; star ratings; reactions; posts that expire; approval; outside sources from X, Bluesky, Mastodon, Instagram, Threads, YouTube and RSS). The same code makes posts and threads, a photo feed, gallery, stories, a forum, a guestbook and outside feeds. Blocks feed.*; screens /post/<id>, /u/<handle>, /tag/<tag>. Detail: docs/SOCIAL.md.

Reviews #

Review boards (blueprint.reviews, convex/kits/reviews): star ratings with words and photos about anything (services, products, places, games, mini-apps, people, a collection's records). A board is a setting: scale (3 to 10 stars), icon (★, ❤️, 🔥 or an icon name), subjects or subjectsFrom a collection, up to 6 aspects rated on their own, writers and verified (role ids, member, level:, badge:, and booked for people with a booking), managers (may the owner review their own space), text, length, titles, photos (0 to 10), approval, replyRoles, helpful, reports with hideAfter, perDay, links and edit. Each person writes one review per subject; a subject is a listed id, record:<id>, main, or any short id a visible block names (app:weather, game:trivia, @handle), so putting reviews.stars with a new subject on a page makes that thing reviewable. Words are words["reviews.<key>"]. A summary reads one totals row however many reviews there are; lists load a page at a time. Detail and recipes: docs/REVIEWS.md.

"reviews": {
  "reviews": {
    "name": "Reviews",
    "subjects": [{ "id": "cut", "name": "Haircut" }, { "id": "colour", "name": "Colour" }],
    "aspects": [{ "id": "value", "name": "Value" }, { "id": "friendly", "name": "Friendly" }],
    "writers": ["member", "visitor"],
    "verified": ["booked", "badge:verified"],
    "managers": false,
    "photos": 4
  }
}

Structure #

Any shape a group of people has: teams and departments, years and classes, squads, branches, ranks. blueprint.structure holds kinds (what units are called and what their leads are called: "Class" with "Teacher") and units (a tree up to 8 deep, up to 500 units, open to join or placed by leads). Who is where, with a title and a lead mark, is live data. Managers change units; a unit's leads (and leads above it) place people; anyone joins or leaves an open unit. A stream with unit set is a room only that unit and those under it see. Block units; functions kits.structure.structure.*. Kit: teams and hierarchy.

Levels (tiers, VIP, memberships) and badges (verified) are kept with the Ledger (blueprint.ledger). visibleTo can name level:<id>, level:<id>+ or badge:<id>. Blocks ledger.levels, ledger.marks, ledger.grants. Kits: tiers, VIP, verified, memberships.

Ledger #

Balances in any unit (coins, points, credits) and moves between people, the space's purse (@space) and issuing (@issue). One function moves units; amounts are whole steps; balances never go below zero; every move is an entry that is never edited. A unit's issue permission names a verb from the space's roles. Blocks ledger.balance, send, give, history, leaderboard. Other engines pay prizes and charge fees through it (award, charge). Kits: coins, leaderboards. Card payments (Stripe) are designed but not built yet; levels and units can be bought with the space's own units today.

Rounds #

Live sessions with players, teams, turns, a timer, randomness, a result and a prize. Every game is a definition in blueprint.games, built from nine mechanics:

MechanicIs
askEveryone answers the same prompt: a choice, a typed answer or a number
buzzPlayers race to buzz, the host judges; optionally a board of categories
surveyHidden ranked answers a team uncovers, with strikes and a steal
actOne player sees a secret prompt and acts, draws or describes it
spinA random pick from options, players or a deck
drawEveryone draws a card; highest or lowest wins
passPass a thing around until a hidden fuse runs out
assignEach player privately gets a person or a role
bingoCalled items are marked on each grid; a full line wins

People start a game, join with a code (visitors too) and play on their phones; game.screen and the Screens engine show the big view. Randomness, timers and scores are decided on the server, so everyone sees the same result and nobody can cheat; the big screen never shows secret words, hidden answers or gift names. Quick rounds (poll, wheel) need no session. Functions rounds.sessions.*, rounds.quick.*. Kits: polls, wheel, Hot Potato, High Card, trivia, quiz board, survey showdown, charades, party pack, game maker, group plans, Secret Santa.

Rooms #

Live audio and video on self-hosted LiveKit. A room block is a group call (mode talk) or a stage with hosts and an audience (mode stage), with screen share and recording; a call block rings people, including a closed phone by push. Convex makes room tokens; media never passes through Convex. Needs LiveKit set up on the server and a development build on phones.

Files #

The space's media library: photos, videos, audio and files. Small files go to Convex storage, big ones to Cloudflare R2 when it's set up. Functions media.*; blocks media.gallery, media.player. Other kits point at library items by id (a post's photos, a profile picture).

Screens #

A TV, projector or any browser opens /tv, shows a code, and someone with the pair permission types it into a screen.pair block. The screen joins the space as its own member with the block's role and shows a page; screen.remote switches what each screen shows. Because the screen is a member, every block works on it, live.

Time #

Bookings (booking block: opening days and hours in the owner's time zone, minutes per booking; functions bookings.*) and posts scheduled to go out later in a chat, channel or feed (scheduled block; streams.schedule, checked again when it goes out). Kits: appointments, scheduler.

Events #

Daily counts of what happens in a space: page views, posts, records, joins, plays, and custom events from blocks. Functions events.track, events.summary, events.leaders; block analytics (managers only); leaderboards rank by an event. Data.

Automations #

Bots and rules that run when something happens, on a schedule, by webhook or by hand, with approval rules and safety caps. Blueprint bots and automations; blocks bots.*. Detail: AI and docs/BOTS.md.

Apps #

Sandboxed mini-apps: games, calculators, anything blocks can't express. Blueprint apps; block miniapp. Mini-apps.

Capabilities #

The space reaches outside Zvessa, and anything outside can build it: an MCP server at /mcp with access tokens, a key vault (AES-256-GCM; keys scoped to hosts; the AI sees names, never values), and connections to outside MCP servers and HTTPS APIs in blueprint.connections. Kits: connections, web research. AI and docs/CAPABILITIES.md.

Audiences #

blueprint.audience: "kids" keeps a space private and invite-only, out of Explore, and tells the AI to keep everything kid-safe. Kit: kids space.

Lifecycle #

Drafts, posts scheduled to go out later (checked again when they go out; ones that can no longer go out come back as drafts), and posts from chosen roles held until a moderator approves them. Blocks drafts, scheduled. Kits: drafts and approvals, scheduler, support desk. Still coming on it: moderation (reports, blocks, word filters).

Settings by example #

Every engine is driven by a blueprint field. These are small, valid examples to copy; the deep docs list every option.

Streams and talk (blueprint.streams, blueprint.talk; a missing part of talk is off; all options in convex/kits/talk/README.md):

"streams": [
  { "id": "news", "name": "News", "icon": "📣", "mode": "broadcast", "postRoles": ["owner", "coach"], "replies": "threads" },
  { "id": "under-12", "name": "Under 12s", "unit": "u12", "slow": 10, "review": ["player"] },
  { "id": "help", "name": "Help", "mode": "queue", "teamRoles": ["staff"], "statuses": ["New", "Working", "Done"], "open": "anyone" }
],
"talk": { "direct": {}, "groups": { "who": ["owner", "coach", "player"], "max": 20 }, "emoji": ["👍", "❤️", "😂"],
          "receipts": true, "typing": true, "edits": true, "schedule": true }

A feed (blueprint.feeds; options in docs/SOCIAL.md):

"feeds": [{ "id": "reviews", "name": "Reviews", "replies": "flat", "media": "optional", "maxMedia": 4,
            "maxLength": 1000, "rating": true, "reactions": ["❤️", "😂"], "approval": true }]

Structure (blueprint.structure):

"structure": {
  "kinds": [{ "id": "team", "name": "Team", "plural": "Teams", "lead": "Coach" }],
  "units": [
    { "id": "club", "name": "Riverside FC" },
    { "id": "u12", "name": "Under 12s", "kind": "team", "parent": "club", "join": "open" }
  ]
}

Ledger (blueprint.ledger: units, levels, badges; rules in convex/kits/ledger/README.md):

"ledger": {
  "units": [{ "id": "coins", "name": "coin", "plural": "coins", "symbol": "🪙", "transfers": true, "startWith": 10 }],
  "levels": [{ "id": "gold", "name": "Gold", "rank": 2, "mark": "💎", "color": "gold",
               "perks": ["Members-only page"], "price": { "unit": "coins", "amount": 100, "every": "month" } }],
  "badges": [{ "id": "verified", "name": "Verified", "mark": "✓", "grant": "manage" }]
}

A unit's issue and a level's or badge's grant name a permission verb (manage by default; only manage, edit or invite are accepted). decimals (up to 4) makes amounts behave like money. Welcome units (startWith) can be spent in the space but not sent.

A game (blueprint.games; every field in convex/lib/rounds/types.ts):

"games": [{
  "id": "pub-quiz", "name": "Pub quiz", "icon": "🧠", "players": { "min": 2 }, "teams": { "count": 2 },
  "decks": [{ "id": "q", "name": "Questions", "items": [
    { "id": "q1", "prompt": "Largest planet?", "choices": ["Mars", "Jupiter", "Venus"], "correct": 1 },
    { "id": "q2", "prompt": "Capital of Japan?", "answer": "Tokyo" }
  ] }],
  "rounds": [
    { "id": "r1", "mechanic": "ask", "deck": "q", "answer": "choice", "score": "correct", "timer": 20, "points": 10 }
  ],
  "prize": { "text": "Bragging rights", "coins": 50 }
}]

Show it with { "kind": "game", "props": { "game": "pub-quiz" } } and on a TV with game.screen. Each mechanic reads its own options (board for a quiz board, strikes for a survey, sketch for drawing, fuse for pass, assign and avoid for gift draws, grid for bingo).

Adding an engine #

Only when no engine can express the need. An engine brings: its tables (with indexes for every query) spread into convex/schema.ts, one Convex file of functions that all check a verb, its blueprint field with a check in checkBlueprint and a default in upgradeBlueprint, its blocks (Blocks), an entry in ENGINES, its first kits, and tests (npm test). Then regenerate the catalog.