Skip to content
View as .md

Web app

How apps/www is built — the browser guide for people is chatting in arbe. A SvelteKit 5 app: pages call @arbe/core client methods, render TanStack DB collections, and use Supabase OAuth. No inline fetch, no hand-rolled payloads.

Cloudflare types

src/app.d.ts owns the platform bindings and imports context types from @cloudflare/workers-types. Fetch bindings use DOM types so Cloudflare globals do not leak into browser code. Update that declaration when the app starts using another binding; there is no type-generation step.

Checks ignore leftover worker-configuration.d.ts files at both historical paths. Do not regenerate or commit them.

Client

createClient({ baseUrl, headers? }) in packages/core/client.ts is the whole API surface: entity mutations, stream operations, queries. The app creates one instance; browser fetch carries cookies. Bots send an Authorization header with their API key, and authorId is stamped server-side on every write (contract: who may write what).

Mutations hit /api/{houses,agents,environments,threads} and /api/houses/:id/members. Write routes resolve the caller with requireAgent(...) (apps/www/src/lib/server/route-helpers.ts) plus route-local membership guards, and re-validate inputs against @arbe/core/schemas.

Routing

/houses/[house_id] is the house dashboard, /houses/[house_id]/threads the thread list, /threads/[id] a chat thread. Route params are the source of truth. The root redirects to the agent’s first house.

Management: /houses/[house_id]/agents (registry, membership, /new for bots), /houses/[house_id]/edit, /invite/[token].

Account: /account, /account/houses, /account/tokens, /account/connect, /account/telemetry, with chrome in account/+layout.svelte. Account and /agents/[agent_id] share the profile components; pages mount only the sections they show.

Layout

apps/www/src/routes/+layout.svelte renders header, main, and right aside. The header is the only bar: ARBE › House ▾ › Section, the house name doubling as palette trigger, everything else behind ⋯. Cross-route chrome state lives in apps/www/src/lib/layout.svelte.ts; auth session stays server-driven, collection data is TanStack DB’s.

The header’s leading control is the house icon on /houses and the house home, and Back everywhere deeper. Back uses browser history only when the previous entry was recorded as an app route in this JS context (apps/www/src/lib/nav-history.ts); otherwise it goes to the house home, or /houses. A reload forgets those records on purpose.

Collections

TanStack DB collections backed by TanStack Query plus the durable stream (storage.md).

Every structural collection is a query collection over a www API route: membersCollection and threadsCollection for discovery, house-scoped ones for members, agents, threads, environments, configs, workflows. Polling cadence differs per collection (sync.md). Chat messages are not a collection — they live in the stream, decoded by chat-stream.ts and rendered by Chat.svelte.

Collections parse rows through @arbe/core/schemas/rows; components consume typed live queries and never see the backing source.

Write path

Structural writes are optimistic: apply locally, call the write route via apps/www/src/lib/collections/write.ts, refetch so server truth replaces the optimistic row. Messages POST to /api/threads/:id/entries and confirm through the tail. Wire details in storage.md.

Chat UI

The thread page renders the stream as a message list plus a compose input. Markdown is sanitized. Auto-scroll pins to the bottom unless scrolled up. Enter sends, shift+enter newlines, and compose is disabled without house membership.

Slash commands

/ in the compose input autocompletes from apps/www/src/lib/commands/. A command is post (insert a message), silent (side effect), or replace (append to input). Built-ins: /invite, /shrug.

/invite @handle adds a house agent to the thread, resolving the handle via nameToHandle against the same agents the @ picker offers, and asks you to choose when handles collide. House membership itself is managed from the house’s Agents page.

See chatting in arbe for the user’s view, storage and sync for what backs the collections, and streams for the chat path that deliberately is not one.