Turn this into your community's hub in under an hour. Works with any AI coding agent (Claude Code, Cursor, Copilot, Windsurf) or just a human with a terminal.
ZAO OS is a gated, music-first social client built on Farcaster. Everything community-specific lives in one file β community.config.ts. Change that file, set your env vars, run the database scripts, and deploy. You have your own community hub.
| Tool | Version | Why |
|---|---|---|
| Node.js | 22+ | Runtime |
| npm | 10+ | Package manager |
| Supabase | Free tier | PostgreSQL database with RLS + Realtime |
| Neynar | Free tier (1000 casts/day) | Farcaster API β reading/writing casts, user data |
| Vercel | Free tier | Deployment (or any Node.js host) |
Optional services (enable as needed):
- Alchemy β ENS resolution, NFT discovery (free: 30M compute units/month)
- Bluesky β cross-posting to AT Protocol
- X/Twitter β cross-posting approved governance proposals
- PostHog β analytics
- Perspective API β AI content moderation
- Snapshot β gasless governance polls
- Arweave β permanent music storage + NFTs
git clone https://github.com/bettercallzaal/zaoos.git my-community
cd my-community
npm installThe postinstall script automatically patches dependencies and copies XMTP WASM files.
This is the only file you must change to rebrand the entire app. Open it and update each section:
name: 'YOUR COMMUNITY', // Appears in nav, titles, meta tags
tagline: 'Your tagline here', // Shown on landing page
colors: {
primary: '#f5a623', // Accent color (buttons, links, highlights)
primaryHover: '#ffd700', // Hover state for primary
background: '#0a1628', // Page background (dark theme)
surface: '#0d1b2a', // Card/panel backgrounds
surfaceLight: '#1a2a3a', // Elevated surfaces (modals, dropdowns)
},farcaster: {
appFid: 12345, // Your app's Farcaster ID (from Neynar dashboard)
channels: ['your-channel'], // Farcaster channels to display as chat rooms
defaultChannel: 'your-channel', // Which channel loads first
},adminFids: [12345], // Farcaster IDs with admin privileges
adminWallets: [], // Ethereum addresses with admin privileges (optional)voiceChannels: [
{ id: 'general', name: 'General', emoji: 'π¬', description: 'Main hangout' },
// Add/remove/rename as needed β these appear in Spaces
],If your community has on-chain tokens or governance, update these. Otherwise leave them β features gracefully degrade when contracts aren't configured.
respect: {
ogContract: '0x...', // Your ERC-20 reputation token (Optimism)
zorContract: '0x...', // Your ERC-1155 reputation token (Optimism)
// ...
},
zounz: {
tokenContract: '0x...', // Your Nouns Builder DAO token (Base)
// ...
},
snapshot: {
space: 'your.eth', // Your Snapshot space for gasless polls
// ...
},Update partners array with your ecosystem links, and pillars to rename navigation tabs.
If you want permanent music storage and NFTs:
arweave: {
appName: 'YOUR-APP', // Tag on Arweave transactions
// ...other settings have sensible defaults
},cp .env.example .env.localOpen .env.local and fill in values. The env file is organized by priority:
| Variable | How to Get It |
|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Supabase dashboard β Settings β API |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Same location |
SUPABASE_SERVICE_ROLE_KEY |
Same location (keep secret!) |
NEYNAR_API_KEY |
neynar.com β Create app β API key |
NEXT_PUBLIC_SIWF_DOMAIN |
Your domain (e.g., myapp.com) |
SESSION_SECRET |
Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" |
APP_FID |
Your app's Farcaster ID (same as farcaster.appFid in config) |
APP_SIGNER_PRIVATE_KEY |
Generate: npx tsx scripts/generate-wallet.ts |
Everything else in .env.example is optional. Each variable has a comment explaining what feature it enables. Add them as you need the features.
Create a new Supabase project, then run these SQL scripts in order in the SQL Editor:
scripts/setup-database.sql -- base schema + RLS policies
scripts/create-users-table.sql -- user accounts
scripts/add-channel-casts-table.sql -- cached Farcaster casts
scripts/create-proposals.sql -- governance proposals
scripts/create-notifications.sql -- notification system
scripts/create-respect-tables.sql -- reputation tracking
scripts/create-streaks-tables.sql -- engagement streaks
scripts/create-track-of-day.sql -- daily track nominations
scripts/migrations/applied/create-music-library.sql -- music library + playlists
scripts/migrations/applied/add-song-likes.sql -- song likes
scripts/migrations/applied/add-song-reactions.sql -- track reactions
scripts/migrations/applied/add-song-comments.sql -- waveform comments
scripts/migrations/applied/add-collaborative-playlists.sql -- collaborative playlists
scripts/migrations/applied/add-poll-config.sql -- admin poll configuration
scripts/migrations/applied/create-respect-transfers.sql -- on-chain transfer history
scripts/migrations/applied/add-fulltext-search.sql -- full-text search indexes
scripts/migrations/applied/create-moderation-log.sql -- moderation audit log
scripts/migrations/applied/add-publishing-columns.sql -- cross-platform publishing
scripts/migrations/applied/add-member-crm-columns.sql -- member CRM fields
scripts/migrations/applied/add-submission-status.sql -- music submission workflow
scripts/migrations/applied/add-proposal-x-columns.sql -- X/Twitter cross-post tracking
scripts/migrations/applied/fix-proposal-categories-v2.sql -- proposal category fixes
scripts/setup-connected-platforms.sql -- platform connection storage
scripts/setup-broadcast-targets.sql -- cross-posting targets
scripts/setup-push-subscriptions.sql -- push notification subscriptions
scripts/setup-rooms-tables.sql -- voice/listening rooms
ZAO OS uses a dedicated signing wallet for Farcaster actions (posting casts, reactions). Never use a personal wallet.
npx tsx scripts/generate-wallet.tsThis outputs a private key. Add it to .env.local as APP_SIGNER_PRIVATE_KEY.
Then register the signer with Neynar β this happens automatically when the first user signs in via the app.
npm run devOpen http://localhost:3000. You should see your community name and branding.
- Landing page shows your community name and colors
- "Sign In With Farcaster" button appears
- After signing in, the chat feed loads with your configured channels
- Admin panel accessible at
/adminfor configured admin FIDs
Or manually:
npm run build # verify build succeeds
vercel # deploy (follow prompts)Set all env vars in Vercel dashboard β Settings β Environment Variables.
ZAO OS is a standard Next.js 16 app. Deploy anywhere that supports Node.js 22+:
- Railway, Render, Fly.io, AWS Amplify, Cloudflare Pages, self-hosted
-
Register Neynar webhook β receives cast events for your channels:
npx tsx scripts/register-neynar-webhook.ts
-
Seed voice channels (optional):
npx tsx scripts/seed-voice-channels.ts
-
Import existing members (optional) β from CSV:
npx tsx scripts/import-community-csv.ts --file members.csv
-
Set up Alchemy webhooks (optional) β for auto-syncing respect token transfers:
- Create webhooks in Alchemy dashboard pointing to
https://yourdomain.com/api/webhooks/alchemy
- Create webhooks in Alchemy dashboard pointing to
Once deployed, your community has:
| Feature | Description |
|---|---|
| Gated social feed | Discord-style chat on Farcaster channels with reactions, threads, search |
| Encrypted DMs | E2E encrypted messaging via XMTP (1-on-1 + groups) |
| 9-platform music player | Spotify, SoundCloud, YouTube, Audius, Sound.xyz, Apple Music, Tidal, Bandcamp, generic |
| Community radio | Audius-powered stations with continuous playback |
| Governance | Three-tier: on-chain proposals + Snapshot polls + community proposals |
| Reputation system | On-chain respect tokens with weighted voting |
| Member profiles | Public directory with ENS resolution, badges, activity stats |
| Cross-posting | Auto-publish to Farcaster + Bluesky + X |
| Admin panel | User management, moderation, config, data import |
| AI moderation | Content safety scoring via Perspective API |
| Mobile-first | Full MediaSession, haptics, Wake Lock, swipe gestures |
Add channel names to farcaster.channels in community.config.ts. They appear as chat rooms automatically.
Update colors in community.config.ts. The app uses Tailwind CSS v4 β for deeper theme changes, edit src/app/globals.css.
Features are modular. Each has its own API routes in src/app/api/[feature]/ and components in src/components/[feature]/. Remove a feature by:
- Removing its nav entry from
pillarsin config - Removing the route group from
src/app/(auth)/[feature]/
Update the partners array in config. Partners appear on the /ecosystem page.
- Snapshot polls: Change
snapshot.spaceandweeklyPollChoicesin config - On-chain proposals: Deploy your own Nouns Builder DAO and update
zounzin config - Community proposals: Work out of the box β respect-weighted voting using your configured contracts
community.config.ts <-- YOUR BRANDING + CHANNELS + CONTRACTS
.env.local <-- YOUR API KEYS + SECRETS
β
βββ src/app/ Next.js App Router
β βββ (auth)/ Protected routes (chat, governance, admin, etc.)
β βββ api/ 121 route handlers
β βββ page.tsx Landing page
βββ src/components/ React components by feature
βββ src/hooks/ 16+ custom hooks
βββ src/lib/ Utilities by domain
βββ src/providers/ Audio providers, PostHog
βββ scripts/ Database setup, wallet generation, imports
- Auth: iron-session (encrypted httpOnly cookies, 7-day TTL)
- Database: Supabase PostgreSQL with Row Level Security on all tables
- Social: Farcaster (public casts) + XMTP (encrypted DMs)
- State: React Query β no Redux/Zustand
- Styling: Tailwind CSS v4, dark theme, mobile-first
- Validation: Zod on every API route
- Music: 9 platform providers, crossfade engine, binaural beats via Web Audio API
The app needs to register a signer with Neynar on first use. If it fails, check that APP_FID, APP_SIGNER_PRIVATE_KEY, and NEYNAR_API_KEY are set correctly.
Make sure you ran the core SQL scripts in order. The setup-database.sql script creates base tables that others depend on.
The build requires at minimum: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, and NEXT_PUBLIC_SIWF_DOMAIN. Other vars can be empty strings during build.
XMTP requires a wallet connection. Users need to connect their wallet on the Settings page before DMs work. The WASM files are copied during npm install via postinstall.
Each platform has its own embed strategy. Spotify/YouTube/SoundCloud use oEmbed. Audius uses their API directly. If a specific platform isn't working, check browser console for CORS or CSP errors.
If you're an AI coding agent setting up a fork:
- Read this file first (you're doing it)
- Read
community.config.tsfor the full config schema - Read
AGENTS.mdfor codebase conventions and patterns - Ask the user for: community name, Farcaster channel(s), admin FID(s), color scheme
- Update
community.config.tswith their values - Guide them through env var setup (Step 3)
- Run database scripts (Step 4)
- Test locally (Step 6)
- Deploy (Step 7)
The entire fork process should take 30-60 minutes for a human, or a single conversation with an AI agent.
MIT β fork it, ship it, make it yours.