Decide whether Chatto client code goes into `@chatto/client` (packages/chatto-client) or the bundled frontend (apps/frontend). Use before you add a request, store, state, helper, or protocol rule to either, or when you move code between them.
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
@chatto/client is the one Chatto client (ADR-111). The bundled frontend,
ChattoBot, and third-party bots and frontends use it. The frontend uses the
client. The client never calls into the frontend.
Ask these questions in sequence. Stop at the first "yes".
serverUi or
$lib/state.| Concern | @chatto/client | Frontend |
|---|---|---|
| A new RPC | Facade in src/api/ | Only the allowed modules below |
| Server and room data | Stores in src/server/ and src/room/ | Derive from the store in components |
| A copy of server data | Emit a boundary event (src/server/storeEvents.ts) for new boundaries | Keep the copy and clear it at the boundary events |
| Per-server UI state | None | serverUi(store) in $lib/state/server/serverUi.ts |
| Snapshot query caches | None | $lib/query; cacheRegistry.ts connects them to boundary events |
| Errors | Keep the error object | errorMessage() or toastError() from $lib/utils/errorMessage |
| Render data from client stores | src/timeline/ | Other render data in $lib/render |
| Text in client data | Take labels from the host (DirectMessageLabels in timeline/users.ts) | Supply translated labels ($lib/render/directMessageLabels.ts) |
| Server catalogue policy | Registry API only (ADR-112) | $lib/serverCatalogue |
Most features have three parts:
src/api/.serverUi. It derives from the store. When it keeps
a copy of server data, it clears the copy at the store's boundary events:
onReset, onRoomAccessLost, onRoomAccessRestored, onUserDeleted,
onAuthorityChanged, onPermissionsChanged, onSessionEnded, and
onDispose.Use these features as examples:
packages/chatto-client/src/api/messageSearch.ts.
The client keeps no search state. The frontend keeps the search sessions in
$lib/state/server/messageSearch.ts. serverUi.ts clears them at
onReset, onRoomAccessLost, onUserDeleted, and onPermissionsChanged.src/api/voiceCalls.ts. Store state:
projection.activeCalls. The frontend keeps the LiveKit media, sounds, and
toasts in $lib/state/server/voiceCall.svelte.ts.src/api/notifications.ts. Store:
src/server/notifications.ts, with notificationTarget. The frontend
keeps attention and read views (notificationAttention.ts, readViews.ts)
and turns targets into routes ($lib/notificationPath.ts).The frontend calls ConnectRPC services directly only for its own screens:
$lib/api).$lib/api/externalIdentities.ts). The sign-in flow uses page redirects
and the origin's cookie session. Account linking starts a browser redirect.
Only the frontend's sign-in and account settings screens use these flows.
Bots do not use them, and a different frontend makes its own flows.$lib/auth/sessionChannel.ts).Do not add other requests there.
Some features have a protocol part in the client and a display part in the frontend. Use them as patterns:
messaging/timestampTokens.ts has
the <t:EPOCH:F> format. $lib/messageTimestamps.ts renders tokens.util/customStatusTemplates.ts has
the chatto:status:<id> tokens. $lib/customStatusTemplates.ts adds the
translated labels.util/permissionCatalog.ts mirrors
cli/internal/core/permission.go. $lib/permissions.ts adds the
translated descriptions and help.server/presenceTracking.ts loads the choice and
sends heartbeats. $lib/state/server/presenceTracking.ts connects one
tracker to the chat root.These modules stay in the frontend. Do not move them without a new reason:
$lib/mentions.ts: mention detection uses the frontend's Markdown
renderer. The server resolves mentions and tells bots why a message
addresses them.$lib/state/server/roomUnread.ts and roomDirectory.ts: optimistic
read-state and membership changes, so the UI responds before the server
confirms. Store events confirm them. Each host decides about its own
optimistic UI.$lib because "only the frontend uses it".svelte/reactivity, or $lib imports in the client outside
src/svelte/.packages/chatto-client/AGENTS.md:
how to write client code.apps/frontend/AGENTS.md: how to write
frontend code.chattocorp/chatto
bf769cf
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.