com um clique
preview
// Manage isolated Convex preview environments with per-worktree port assignment. MANDATORY before any Playwright, E2E test, or browser testing.
// Manage isolated Convex preview environments with per-worktree port assignment. MANDATORY before any Playwright, E2E test, or browser testing.
| name | preview |
| description | Manage isolated Convex preview environments with per-worktree port assignment. MANDATORY before any Playwright, E2E test, or browser testing. |
Manages isolated Convex preview environments. Each worktree gets its own backend, database, seeded data, and unique port.
This skill is MANDATORY before:
/preview or /preview start — Create/resume preview and start dev server/preview stop — Stop this worktree's dev server only/preview status — Check preview status across all worktreesFollow these steps IN ORDER. Steps 3-9 must run atomically — do not stop halfway.
WORKTREE_ROOT=$(git rev-parse --show-toplevel)
WORKTREE_NAME=$(basename "$WORKTREE_ROOT")
MAIN_REPO_PATH="{{MAIN_REPO_PATH}}"
if [ ! -f "$WORKTREE_ROOT/.env.local" ]; then
cp "$MAIN_REPO_PATH/.env.local" "$WORKTREE_ROOT/.env.local"
fi
Check if this worktree already has a port assigned and a server running:
if [ -f "$MAIN_REPO_PATH/.preview-ports.registry" ]; then
EXISTING_PORT=$(grep "^$WORKTREE_NAME=" "$MAIN_REPO_PATH/.preview-ports.registry" | cut -d= -f2)
if [ -n "$EXISTING_PORT" ]; then
lsof -ti ":$EXISTING_PORT" | xargs kill 2>/dev/null || true
echo "Killed existing server on port $EXISTING_PORT"
fi
fi
Read the deploy key from .env.local and deploy. The --cmd flag captures the preview URL to a temp file:
source "$WORKTREE_ROOT/.env.local"
npx convex deploy \
--preview-create "$WORKTREE_NAME" \
--cmd "echo \"\$VITE_CONVEX_URL\" > /tmp/preview-$WORKTREE_NAME-url.txt" \
--cmd-url-env-var-name VITE_CONVEX_URL \
-y
PREVIEW_URL=$(cat /tmp/preview-$WORKTREE_NAME-url.txt)
echo "Preview URL: $PREVIEW_URL"
CRITICAL: Each --preview-create creates a FRESH deployment:
Ports are allocated from range 5173-5273. The shared registry is at $MAIN_REPO_PATH/.preview-ports.registry.
Atomic locking via mkdir (cannot race):
LOCK="$MAIN_REPO_PATH/.preview-ports.lock"
# Try to acquire lock (30-second stale timeout)
while ! mkdir "$LOCK" 2>/dev/null; do
LOCK_AGE=$(( $(date +%s) - $(stat -f %m "$LOCK" 2>/dev/null || echo 0) ))
if [ "$LOCK_AGE" -gt 30 ]; then
rm -rf "$LOCK"
echo "Removed stale lock"
else
sleep 1
fi
done
# Read registry, find next available port
REGISTRY="$MAIN_REPO_PATH/.preview-ports.registry"
touch "$REGISTRY"
EXISTING_PORT=$(grep "^$WORKTREE_NAME=" "$REGISTRY" | cut -d= -f2)
if [ -n "$EXISTING_PORT" ]; then
PORT="$EXISTING_PORT"
else
# Find next available port in 5173-5273
USED_PORTS=$(cut -d= -f2 "$REGISTRY" | sort -n)
PORT=5173
while echo "$USED_PORTS" | grep -q "^$PORT$"; do
PORT=$((PORT + 1))
done
echo "$WORKTREE_NAME=$PORT" >> "$REGISTRY"
fi
# Release lock
rm -rf "$LOCK"
echo "Port assigned: $PORT"
Read each secret from .env.local and set on the Convex preview:
source "$WORKTREE_ROOT/.env.local"
npx convex env set --preview-name "$WORKTREE_NAME" RESEND_API_KEY "$RESEND_API_KEY"
npx convex env set --preview-name "$WORKTREE_NAME" RESEND_FROM_EMAIL "${RESEND_FROM_EMAIL:-noreply@example.com}"
npx convex env set --preview-name "$WORKTREE_NAME" JWT_PRIVATE_KEY -- "$JWT_PRIVATE_KEY"
npx convex env set --preview-name "$WORKTREE_NAME" JWKS "$JWKS"
npx convex env set --preview-name "$WORKTREE_NAME" SITE_URL "http://localhost:$PORT"
Add any other env vars your project needs (e.g., AI API keys).
npx convex run seed:seedData --preview-name "$WORKTREE_NAME"
This creates test users and data for E2E tests. The seed script should be idempotent (upsert, not insert).
Update .env.local with the preview-specific values:
# Read existing secrets
source "$WORKTREE_ROOT/.env.local"
# Rewrite with preview-specific additions
cat > "$WORKTREE_ROOT/.env.local" << ENVEOF
# Secrets
CONVEX_DEPLOY_KEY=$CONVEX_DEPLOY_KEY
RESEND_API_KEY=$RESEND_API_KEY
JWT_PRIVATE_KEY=$JWT_PRIVATE_KEY
JWKS=$JWKS
# Preview-specific (set by /preview)
CONVEX_PREVIEW_NAME=$WORKTREE_NAME
VITE_CONVEX_URL=$PREVIEW_URL
CONVEX_URL=$PREVIEW_URL
# PostHog
VITE_POSTHOG_KEY=$VITE_POSTHOG_KEY
VITE_POSTHOG_HOST=${VITE_POSTHOG_HOST:-https://eu.i.posthog.com}
# Dev server
BASE_URL=http://localhost:$PORT
DEV_PORT=$PORT
ENVEOF
Start ONLY the web dev server — not the root pnpm dev (which runs concurrently with Convex). The Convex backend is already deployed to a preview environment in step 4.
cd "$WORKTREE_ROOT"
pnpm --filter '{apps/web}' dev --port $PORT --strictPort
--strictPort ensures Vite fails if the port is already taken (instead of silently picking another). This keeps the port registry accurate.
The server runs in the foreground. Use Ctrl+C to stop, or /preview stop from another terminal.
Preview ready:
Worktree: $WORKTREE_NAME
Port: $PORT
URL: http://localhost:$PORT
Convex: $PREVIEW_URL
Seeded: yes
WORKTREE_NAME=$(basename "$(git rev-parse --show-toplevel)")
MAIN_REPO_PATH="{{MAIN_REPO_PATH}}"
PORT=$(grep "^$WORKTREE_NAME=" "$MAIN_REPO_PATH/.preview-ports.registry" | cut -d= -f2)
if [ -n "$PORT" ]; then
lsof -ti ":$PORT" | xargs kill 2>/dev/null || true
echo "Stopped server on port $PORT"
else
echo "No port found for $WORKTREE_NAME"
fi
rm -f /tmp/preview-$WORKTREE_NAME-url.txt
Do NOT remove the port from the registry — it stays allocated for this worktree.
Read all entries from the port registry. For each:
lsof -i :$PORT)MAIN_REPO_PATH="{{MAIN_REPO_PATH}}"
REGISTRY="$MAIN_REPO_PATH/.preview-ports.registry"
if [ ! -f "$REGISTRY" ]; then
echo "No previews registered"
exit 0
fi
while IFS='=' read -r name port; do
if lsof -i ":$port" > /dev/null 2>&1; then
echo "$name → http://localhost:$port (running)"
else
echo "$name → port $port (stopped)"
fi
done < "$REGISTRY"
.env.localScaffold a production-ready SaaS project. Checks stack freshness, product brief, design, generates a working hello world, and sets up GitHub CI/CD.
Full quality gate: build, lint, format, typecheck, unit tests, Minter integrity, visual verification, and E2E tests. Run after implementing a feature.
Multi-pass code review covering Minter spec coverage, code quality, design system compliance, test strategy, and architecture. Use before considering a feature done or creating a PR.