Skip to content
View as .md

Sync

Postgres → Electric SQL shapes → TanStack DB collections → Svelte components. Every house-scoped table carries a flat house_id so the Electric where stays a literal equality (Electric’s optimised fast path; subqueries and ANY() over arrays degrade). Per-entity tables, schemas in @arbe/core/schemas/rows.ts, single-table shapes — no joins on the wire; relations = multiple shapes the client glues.

login → mount discovery shape (members WHERE agent_id = $me)
enter house → mount content shapes (houses, environments, configs, threads
WHERE house_id = $hid AND deleted_at IS NULL;
agents arrive via the members-join shape — no house_id column)
switch house → unmount old content, mount new; discovery untouched
logout → unmount everything

A central shape registry owns mounting/unmounting, driven by auth + route state — components read live collections and stay ignorant. Shapes are immutable per subscription: a membership change produces a different where on the next request and a full re-sync. Optimistic writes apply locally, POST to the matching per-entity route (createHouse, updateThread, …), and reconcile on the txid Electric replays back.

agents is the one v1 table without a house_id scope (one identity, N houses). members is the house-scoped access edge: (house_id, agent_id, role), plus denormalised display_name + kind for render paths — Discord’s User vs GuildMember split. A house roster is members joined to agents. The full agents row carries settings and is mounted only when a user edits their own profile or a bot they admin; rename = server-side fan-out across that agent’s members rows.

member is the term Discord, Slack, GitHub, Linear, Notion all use. House membership grants access to every thread under the house. Ownership lives on members.role = 'owner'; there’s no author_id on houses. RLS gates every table by is_house_member / is_house_owner; the shape where mirrors the same predicate so unauthorised rows never leave the server. members RLS in v1 is peer-visible within shared houses, so a member can see the house roster.

Code: packages/core/schemas/rows.ts (HouseRowSchema, RoomRowSchema, MemberRowSchema, AgentRowSchema, plus AgentKind / MemberRole / TriggerMode enums), apps/www/src/routes/api/shapes/, apps/www/src/lib/collections/.
See system/storage, system/permissions, website/www.

Open: single mutation endpoint vs per-entity POSTs; conflict reconciliation strategy; admin listing of other house members (relax RLS conditionally vs separate endpoint outside sync); whether Electric carries a live connection across a JWT refresh or we tear down + remount.