PowerChat is a real-time local-first chat app for experimenting with collaborative AI agents on top of PowerSync.
Built with SolidStart, PowerSync, Supabase Postgres, Drizzle, and Mastra.
- 💬 Real-time chat channels
- 🤖 AI agents you can @mention in channels
- ✨ Agent runs triggered directly from message upload handling
- 👥 Right sidebar with channel members and agents
- 🗂️ Live workspace filesystem section in each channel sidebar
- 📱 Offline-first sync with PowerSync local SQLite on web
- ⚡ Instant UI updates via client-side writes
- 🔐 Anonymous cookie-based sessions for MVP
- Frontend: SolidStart + Solid Router + Tailwind
- Database: Supabase Postgres
- ORM: Drizzle
- Sync: PowerSync (Web SDK + Cloud service)
- AI: Mastra
- Auth: Anonymous cookie-based sessions + PowerSync JWTs
bun installThis app expects a Postgres database with the chat schema already created.
Primary tables used by the app:
usersagentschannelschannel_membersmessagesagent_runsworkspace_nodes
Schema source:
src/db/schema/server.ts
Migrations:
db/migrations- generated with
bun run db:generate
Set DATABASE_URL in your env file.
PowerSync setup is split across a few files:
db/replication.sql— SQL for replication user + publicationpowersync/service.yaml— PowerSync service connection configpowersync/sync-config.yaml— sync rules used by apppowersync/cli.yaml— PowerSync CLI project link metadata
For Supabase:
- Create or update your Postgres connection in
powersync/service.yaml - Ensure the
powersyncpublication exists in Supabase - Run the SQL in
db/replication.sqlor equivalent SQL manually in Supabase - Deploy service config:
powersync deploy service-config --directory powersync- Deploy sync config:
powersync deploy sync-config --directory powersyncCurrent sync rules subscribe each user to channels where they are a member and sync:
usersagentschannelschannel_membersmessagesagent_runsworkspace_nodes
Create a .env or .env.local file with:
DATABASE_URL="postgresql://..."
VITE_POWERSYNC_SERVICE_URL="https://<instance>.powersync.journeyapps.com"
POWERSYNC_SERVICE_URL="https://<instance>.powersync.journeyapps.com"
POWERSYNC_JWT_SECRET="<base64url-secret>"
POWERSYNC_JWT_KID="powerchat"
OPENAI_API_KEY="<openai-key>"
AI_MODEL="openrouter/anthropic/claude-haiku-4.5"Notes:
POWERSYNC_JWT_SECRETshould match the JWKS/shared-secret configured in PowerSyncPOWERSYNC_JWT_KIDshould match the configured key idVITE_POWERSYNC_SERVICE_URLis used by browser clientPOWERSYNC_SERVICE_URLis used by server token generation
bun run devDefault dev server:
http://localhost:9009
- Choose a username
- Create or open a channel
- Send messages normally
- Mention an agent with
@AgentNameto trigger an AI reply - Use the right sidebar to:
- inspect members
- inspect agents
- inspect live workspace filesystem metadata for channel
Each channel has a workspace on the server filesystem under .mastra-workspaces/channels/<channel-id>.
The app watches those directories and projects metadata into workspace_nodes, which is then synced down through PowerSync. The sidebar tree is metadata-only in current version:
- file/folder name
- relative path
- kind (
file/dir) - size for files
- modified time
No file preview or editing yet.
PowerChat organizes UI behavior by feature slice instead of technical layer.
Each slice usually lives in src/slices/{feature-name}/ and contains:
index.tsx— component/hook implementationindex.test.tsx— colocated tests when present
Route components in src/routes/ compose slices together.
Query slices:
- fetch and render data
- use
useQueryfrom~/lib/powersync-solid
Examples:
channel-listchat-messageschannel-headerchannel-member-listchannel-agents-listchannel-workspace-treeagent-viewermention-autocomplete
Mutation slices:
- handle writes and user actions
- use PowerSync write transactions or server actions
Examples:
create-channelchat-inputusername-registrationchannel-invitecreate-agentdelete-channel
- Messages are written to local PowerSync SQLite first
- PowerSync queues uploads to service
- Upload handler validates and writes to Postgres with Drizzle
- New user messages can trigger agent runs directly from upload path
- Agent replies stream back into persisted messages
- Workspace filesystem metadata is indexed on server and synced through
workspace_nodes
Run tests with:
bun run testUseful targeted commands:
bunx vitest run src
bunx vitest run src/server/workspace-node-indexer.test.ts
bunx tsc --noEmitTest philosophy:
- keep tests simple
- mock external dependencies where useful
- test behavior, not implementation details
- prefer colocated slice tests
Experimental project. Not production app. Main purpose is exploring collaborative agentic apps with PowerSync.