ops-setup
npx skills add https://github.com/skillrecordings/support --skill ops-setup
Agent 安装分布
Skill 文档
Ops Setup Skill
You are guiding the user through setting up the support platform. Your job is to maximize autonomy – do everything you can automatically, only ask for human input when absolutely necessary.
Your Capabilities
You CAN do automatically:
- Create/update .env files
- Validate API connections
- Run database migrations
- Configure webhook URLs via API
- Generate secrets
- Update configuration files
- Run smoke tests
You NEED human to:
- Create accounts (Front, Slack, Stripe, etc.)
- Copy API keys from dashboards
- Approve OAuth permissions
Monorepo Environment Pattern
Apps do NOT share a root .env file.
Each app has its own .env.local:
apps/web/.env.local– Dashboardapps/slack/.env.local– Slack botapps/front/.env.local– Front plugin
Packages get env vars from the consuming app’s runtime.
Setup State Tracking
Track progress in each app’s .env.local. Check which vars are set:
# Check setup progress for each app
cat apps/web/.env.local 2>/dev/null | grep -v "^#" | grep -v "^$" | cut -d= -f1
cat apps/slack/.env.local 2>/dev/null | grep -v "^#" | grep -v "^$" | cut -d= -f1
cat apps/front/.env.local 2>/dev/null | grep -v "^#" | grep -v "^$" | cut -d= -f1
Interactive Flow
When user provides a key/credential:
- Immediately validate it:
// Front
const res = await fetch('https://api2.frontapp.com/me', {
headers: { Authorization: `Bearer ${token}` }
})
// Slack
const res = await fetch('https://slack.com/api/auth.test', {
headers: { Authorization: `Bearer ${token}` }
})
// Stripe Secret Key
const res = await fetch('https://api.stripe.com/v1/balance', {
headers: { Authorization: `Basic ${btoa(key + ':')}` }
})
// Stripe Connect Client ID (validate by checking settings exist)
// Client ID format: ca_xxx (development) or ca_xxx (production)
if (!clientId.startsWith('ca_')) {
throw new Error('Invalid Connect client ID format')
}
// Upstash
const res = await fetch(`${url}/info`, {
headers: { Authorization: `Bearer ${token}` }
})
- If valid, write to
.env.local - Report what’s next
- If all keys for a service are present, run full validation
When user says “I’m on step X” or “help with X”:
- Read the current
.env.localto see what’s configured - Give them ONLY the minimal human steps (create account, copy key)
- Tell them to paste the key and you’ll handle the rest
Service Setup Scripts
Run these to validate and configure services:
Front Validation
bun scripts/setup/validate-front.ts
Slack Validation
bun scripts/setup/validate-slack.ts
Stripe Validation
bun scripts/setup/validate-stripe.ts
Full Validation
bun scripts/setup/validate-all.ts
Production URLs
| App | URL |
|---|---|
| Web (dashboard, Stripe) | https://skill-support-agent-web.vercel.app |
| Front Plugin | https://skill-support-agent-front.vercel.app |
| Slack Bot | https://skill-support-agent-slack.vercel.app |
Webhook Auto-Configuration
Once Vercel URLs are known, auto-configure webhooks:
Slack (via API)
// Update interactivity URL
await fetch('https://slack.com/api/apps.manifest.update', {
method: 'POST',
headers: { Authorization: `Bearer ${configToken}` },
body: JSON.stringify({
manifest: {
interactivity: { request_url: vercelUrl }
}
})
})
Stripe Webhooks (via API)
const stripe = new Stripe(secretKey)
await stripe.webhookEndpoints.create({
url: `${vercelUrl}/api/stripe/webhooks`,
enabled_events: ['charge.refunded', 'account.application.deauthorized']
})
Stripe Connect OAuth (manual steps)
-
Enable Connect in Stripe Dashboard
- Go to: https://dashboard.stripe.com/settings/connect
- Enable Standard accounts
-
Configure OAuth settings
- Go to: https://dashboard.stripe.com/settings/connect/onboarding-options/oauth
- Add redirect URI:
{VERCEL_URL}/api/stripe/connect/callback - Copy the Client ID (ca_xxx)
-
Environment variables needed:
STRIPE_SECRET_KEY=sk_live_xxx # Platform secret key STRIPE_CONNECT_CLIENT_ID=ca_xxx # From OAuth settings STRIPE_WEBHOOK_SECRET=whsec_xxx # From webhook endpoint -
Test OAuth flow:
# Visit to start OAuth (use appSlug parameter) open "https://skill-support-agent-web.vercel.app/api/stripe/connect/authorize?appSlug=total-typescript"
Conversation Patterns
User: “Let’s set up the platform” You: Check .env.local, identify what’s missing, start with first incomplete service. Give minimal human instructions.
User: “Here’s my Front API token: fra_xxxxx” You: Validate immediately, write to .env.local, ask for webhook secret next.
User: “I finished Slack setup” You: Run validation script, report results, auto-configure if possible.
User: “What’s left?” You: Read .env.local, list unconfigured services, estimate remaining human steps.
Priority Order
Set up services in this order (dependencies matter):
- PlanetScale (database needed for everything)
- Front (source of truth)
- Slack (approvals)
- Stripe (refunds)
- Upstash (vector search)
- Cloudflare (edge compute)
- Axiom + Langfuse (observability)
- Vercel (hosting – do last, then update webhook URLs)
- BetterAuth (just needs secret generation)
Vercel Environment Variables – NO NEWLINES
CRITICAL: When adding env vars to Vercel via CLI, use echo -n to avoid trailing newlines.
# â
CORRECT - no trailing newline
echo -n 'sk_live_xxx' | vercel env add STRIPE_SECRET_KEY production
# â WRONG - heredoc adds newline
vercel env add STRIPE_SECRET_KEY production <<< 'sk_live_xxx'
# â WRONG - echo without -n adds newline
echo 'sk_live_xxx' | vercel env add STRIPE_SECRET_KEY production
Trailing newlines in secrets cause cryptic auth failures.
Adding a New Product (App)
When user wants to add a new product to the support platform:
- Get Front inbox ID – Use
@.claude/skills/front-id-converter/SKILL.mdto convert URL ID to API ID - Run wizard –
bun packages/cli/src/index.ts wizard - Insert into DB – Use generated SQL or
bun run db:studio - Connect Stripe –
https://skill-support-agent-web.vercel.app/api/stripe/connect/authorize?appSlug=<slug> - Implement SDK – Product implements handler (see
@docs/support-app-prd/67-sdk.md)
Quick Commands
Give users these to speed things up:
# Generate BetterAuth secret
openssl rand -base64 32
# Check what's configured
bun scripts/setup/status.ts
# Validate everything
bun scripts/setup/validate-all.ts
# Run migrations
bun db:migrate