The philosophy and practical benefits of agent fungibility in multi-agent software development. Why homogeneous, interchangeable agents outperform specialized role-based systems at scale.
日本語の概要は準備中です。原文の説明を表示しています。
Configure Supabase for Next.js SaaS: Drizzle + pooler, Google-only Auth, RLS, cost optimization. Use when setting up Supabase, connecting Drizzle, SSR auth, or optimizing costs.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Core Insight: Two lanes: user-scoped data via Supabase client (RLS-enforced), server-scoped via Drizzle (privileged). Use
getClaims()notgetSession(). Transaction pooler requiresprepare: false.
Set up Supabase for a Next.js SaaS with:
1. Auth: Google OAuth only
2. ORM: Drizzle with Supabase pooler (IPv4)
3. Environment: [Vercel / Cloudflare / local dev]
4. Cost tier: [Free / Pro with Spend Cap / Team]
Follow supabase-guide skill patterns.
┌─────────────────────────────────────────────────────────────────────┐
│ TWO-LANE DATA ACCESS MODEL │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ LANE A: User-scoped (RLS-enforced) │
│ ══════════════════════════════════ │
│ @supabase/ssr → PostgREST Data API │
│ • Browser + Server Components │
│ • JWT validated via getClaims() │
│ • Multi-tenant reads/writes obey RLS "naturally" │
│ │
│ LANE B: Server-scoped (privileged) │
│ ══════════════════════════════════ │
│ Drizzle → postgres.js → Supavisor pooler │
│ • Migrations, admin tasks, billing webhooks │
│ • Transaction mode (port 6543): prepare: false │
│ • Session mode (port 5432): migrations only │
│ │
└─────────────────────────────────────────────────────────────────────┘
Why this split: Browser access uses Data API with RLS. Server/serverless uses pooler. IPv4-only environments (Vercel/GH Actions) cannot use direct connections (IPv6).
// src/db/index.ts
import postgres from "postgres"
import { drizzle } from "drizzle-orm/postgres-js"
import * as schema from "./schema"
const g = globalThis as unknown as { __sql?: ReturnType<typeof postgres> }
export const sql = g.__sql ?? postgres(process.env.DATABASE_URL!, {
prepare: false, // REQUIRED for transaction pooler
max: process.env.NODE_ENV === "production" ? 5 : 1,
})
if (process.env.NODE_ENV !== "production") g.__sql = sql
export const db = drizzle(sql, { schema })
// src/lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr"
export function supabaseBrowser() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
)
}
// src/lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr"
import { cookies } from "next/headers"
export function supabaseServer() {
const store = cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll: () => store.getAll(),
setAll: (toSet) => {
try { toSet.forEach(({ name, value, options }) => store.set(name, value, options)) }
catch {}
},
},
}
)
}
// middleware.ts
import { createServerClient } from "@supabase/ssr"
import { NextResponse, type NextRequest } from "next/server"
export async function middleware(request: NextRequest) {
let response = NextResponse.next({ request: { headers: request.headers } })
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll: () => request.cookies.getAll(),
setAll: (toSet) => {
toSet.forEach(({ name, value }) => request.cookies.set(name, value))
response = NextResponse.next({ request: { headers: request.headers } })
toSet.forEach(({ name, value, options }) => response.cookies.set(name, value, options))
},
},
}
)
await supabase.auth.getClaims() // NOT getSession()
return response
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)"],
}
# Supabase Auth / API
NEXT_PUBLIC_SUPABASE_URL="https://<project_ref>.supabase.co"
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY="sb_publishable_..." # or anon key during transition
SUPABASE_SERVICE_ROLE_KEY="..." # server-only, NEVER ship to client
# Postgres: app runtime (transaction pooler, port 6543)
DATABASE_URL="postgresql://postgres.<project_ref>:<PASSWORD>@aws-0-<region>.pooler.supabase.com:6543/postgres?sslmode=require"
# Postgres: migrations (session pooler, port 5432)
DATABASE_URL_MIGRATIONS="postgresql://postgres.<project_ref>:<PASSWORD>@aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require"
Username format: postgres.<project_ref> — the dot is real, copy from Dashboard → Connect button.
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, DATABASE_URL, DATABASE_URL_MIGRATIONShttps://<project_ref>.supabase.co/auth/v1/callbackbun add drizzle-orm postgres && bun add -d drizzle-kitsrc/db/index.ts with prepare: false — DRIZZLE-SETUP.mddrizzle.config.ts pointing to session pooler for migrationsdrizzle-kit generate and drizzle-kit migrateuser_profiles table keyed by auth.users.idpublic schemaprivate schema| Symptom | Cause | Fix |
|---|---|---|
ENETUNREACH / network unreachable | Direct connection is IPv6 | Use pooler connection string |
prepared statement does not exist | Transaction pooler + prepared statements | Set prepare: false in postgres.js |
Tenant or user not found | Wrong pooler host or username format | Copy exact string from Connect dialog; include .project_ref in username |
| Users randomly logged out | Token not refreshing in middleware | Use getClaims() in middleware, not getSession() |
| RLS policy not blocking | Table missing enable row level security | Run ALTER TABLE x ENABLE ROW LEVEL SECURITY |
| Slow queries with RLS | No index on RLS filter columns | Add index on user_id, tenant_id columns |
| Surprise bills | No Spend Cap, uncached egress | Enable Spend Cap; use Smart CDN + high cache-control |
Full troubleshooting: TROUBLESHOOTING.md
getClaims(), not getSession() — cookies can be spoofed; getClaims() validates JWT signature every timeservice_role key — bypasses RLS, backend-onlypublic — tables without RLS are accessible via anon roleapp_metadata not user_metadata for tenant_id — user_metadata is user-modifiable# Supabase CLI
supabase login
supabase link --project-ref $PROJECT_REF
supabase db pull # Pull remote schema
supabase migration new <name> # Create migration
supabase db push # Apply migrations
# Drizzle
drizzle-kit generate # Generate migrations
drizzle-kit migrate # Apply migrations
drizzle-kit studio # Visual browser
# Secrets (Edge Functions)
supabase secrets set --env-file .env # Push secrets
supabase secrets list # Verify
Copy this to your project's AGENTS.md:
### Supabase
Supabase CLI is installed. Project: `<PROJECT_REF>`.
Auth:
\`\`\`bash
supabase login
supabase link --project-ref $PROJECT_REF
\`\`\`
Database:
\`\`\`bash
supabase db pull # Pull schema to migrations
supabase migration new <name>
supabase db push # Apply migrations
\`\`\`
Connection strings:
- **Runtime (Drizzle):** Transaction pooler (port 6543), `prepare: false`
- **Migrations:** Session pooler (port 5432)
Copy exact connection string from Dashboard → Connect button.
| Topic | Reference |
|---|---|
| Copy-paste patterns | QUICK-REFERENCE.md |
| Two-lane architecture + cost model | ARCHITECTURE.md |
| Drizzle + pooler setup | DRIZZLE-SETUP.md |
| Next.js SSR auth with getClaims() | AUTH-SSR.md |
| Google OAuth setup | GOOGLE-OAUTH.md |
| RLS patterns for SaaS | RLS-PATTERNS.md |
| Pooler gotchas (IPv4/IPv6, modes) | POOLER-GOTCHAS.md |
| Cost optimization (Spend Cap, cron) | COST-OPTIMIZATION.md |
| Troubleshooting guide | TROUBLESHOOTING.md |
# After setup, verify:
# 1. Google OAuth flow works (login → callback → dashboard)
# 2. Drizzle can connect: bun run -e "import { db } from './src/db'; console.log('OK')"
# 3. RLS blocks unauthorized access via Data API
# 4. Middleware refreshes tokens (check cookies in DevTools)
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
The philosophy and practical benefits of agent fungibility in multi-agent software development. Why homogeneous, interchangeable agents outperform specialized role-based systems at scale.
日本語の概要は準備中です。原文の説明を表示しています。
MCP Agent Mail for multi-agent coordination. Use when agents need file locks, messaging, inboxes, or conflict prevention. Handles macro_start_session, file_reservation_paths, send_message, threading, pre-commit guards.
日本語の概要は準備中です。原文の説明を表示しています。
Jeffrey Emanuel's multi-agent implementation workflow using NTM, Agent Mail, Beads, and BV. The execution phase that follows planning and bead creation. Includes exact prompts used.
日本語の概要は準備中です。原文の説明を表示しています。
Convert markdown plans into beads with dependencies using br CLI. Use when creating task graphs, polishing beads before implementation, or bridging planning to agent swarm execution.
日本語の概要は準備中です。原文の説明を表示しています。
Beads Viewer - Graph-aware triage engine for Beads projects. Computes PageRank, betweenness, critical path, and cycles. Use --robot-* flags for AI agents.
日本語の概要は準備中です。原文の説明を表示しています。
Manage AI coding CLI accounts with sub-100ms switching. Use when hitting rate limits on Claude Max, GPT Pro, or Gemini Ultra subscriptions and need instant account swapping without browser OAuth.
日本語の概要は準備中です。原文の説明を表示しています。