Autopilot Troubleshooting
Runbook
Quick diagnosis — start here
| Symptom | Section | Most likely cause |
|---|---|---|
| No Slack messages on Monday morning | Section 1 | Cron didn't fire, or Vercel function timed out |
| Slack messages appeared but all say "0 actions" | Section 2 | MCP data returned empty — auth or parsing issue |
| Clicked Approve but nothing changed in Google Ads | Section 3 | Writer MCP auth, API access, or SIMULATION_MODE still true |
| ClickUp tasks not created | Section 4 | ClickUp API token expired or list ID wrong |
| Bot not responding to @mentions in Slack | Section 5 | Event subscription not configured or app not in channel |
| Anomaly alerts not firing | Section 6 | Daily cron not set up, or daily_snapshots table empty |
| One specific client fails, others work | Section 7 | Client config — missing customer ID, GSC URL, or GA4 property |
| Everything worked but recommendations are poor | Section 8 | Rules engine thresholds or sub-agent prompts need tuning |
No Slack messages on Monday morning
Check the Vercel function logs
Go to: vercel.com/teddi-coder/mm-google-ads-autopilot/logs ↗
Filter by the cron time (Sunday 20:00 UTC = Monday 7:00am AEST). Look for:
- No log entries at all — the cron didn't fire. Check
vercel.jsonhas the correct schedule. - Log entries with errors — the function started but crashed. Read the error message.
- FUNCTION_INVOCATION_TIMEOUT — hit Vercel's 300 second limit. A single client should take 90–130 seconds. The MCP server may be slow or unresponsive.
Check Vercel cron configuration
In vercel.json, each client should have its own cron entry staggered 3 minutes apart. If all clients run at once, they will all timeout.
Check the Supabase runs table
Go to Supabase → Table Editor → runs. Filter by today's date. If there are run records with status "error", the function ran but failed mid-pipeline.
Manual trigger to test
curl -X POST https://mm-google-ads-autopilot.vercel.app/api/run-client -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{"client_name": "Ultra Tune North Ryde"}'
If this returns a response, the app is working and the issue is with the cron schedule.
Slack messages appeared but 0 actions proposed
The pipeline ran but the rules engine and AI agents found nothing to recommend. This is either correct (healthy accounts) or a data problem.
Check if data actually came through
In Vercel logs, look for lines like:
[fetchAllClientData] Results for Ultra Tune North Ryde:
campaigns: 814 chars
keywords: 3002 chars
If all values show "0 chars" or are missing, the MCP server returned empty data.
MCP server returning empty data
Test the MCP server directly:
python3 -c "
import asyncio
from fastmcp import Client
async def main():
async with Client('https://mechanic-mcp-server.fly.dev/mcp') as c:
r = await c.call_tool('account_snapshot', {'customer_id': '2106714025'})
print(r)
asyncio.run(main())
"
If this returns data but the app doesn't, check MCP_MM_SERVER_TOKEN in Vercel env vars matches the bearer token on the MCP server. Token: 748e3cc9c5a1bba9 (rotate if compromised).
MCP server itself is down
flyctl status -a mechanic-mcp-server
# If stopped or crashed:
flyctl deploy -a mechanic-mcp-server
Clicked Approve but nothing changed in Google Ads
Check SIMULATION_MODE
In Vercel environment variables, check SIMULATION_MODE=false. If this is "true" or not set, the app logs actions as "simulated" but never calls the writer.
Check the writer MCP
flyctl status -a hedgehog-ads-writer
Check MCP_ADS_WRITER_TOKEN in Vercel matches the token on the writer server.
Check the audit log
In Supabase → audit_log, find the action you approved. Check:
status— should be "executed" or "failed", not "simulated" or "pending"error_message— if status is "failed", the error will tell you what went wrong
ClickUp tasks not being created
- Check CLICKUP_API_TOKEN in Vercel env vars. ClickUp personal API tokens can expire or be revoked. Generate a new one at Settings → Apps → API Token in ClickUp.
- Check the client's
clickup_list_idin Supabase → clients table. If it's null, the app doesn't know where to create the task. - Check Vercel logs for ClickUp errors — look for HTTP 401 (auth), 404 (list not found), or 429 (rate limited).
Bot not responding to @mentions
Check Slack app event subscriptions
In api.slack.com/apps ↗ → Your App → Event Subscriptions:
- Events must be enabled
- "app_mention" event must be subscribed
- Request URL must be:
https://mm-google-ads-autopilot.vercel.app/api/slack/events - The URL must be verified (green checkmark)
Check bot is in the channel
The bot must be a member of #mm-ads-autopilot. Invite it with /invite @autopilot if needed.
Anomaly alerts not firing
Check the daily cron
In vercel.json, the anomaly check should be:
{ "path": "/api/anomaly-check", "schedule": "0 21 * * 1-5" }
This is 8:00am AEST Tuesday through Saturday.
Check daily_snapshots table
The anomaly check compares today's snapshot against a 7-day rolling average. If there are fewer than 7 days of snapshots, the check has no baseline to compare against.
Thresholds may be too high
The default thresholds are conservative (CPA 50% above average = critical). If client accounts are volatile, these thresholds may never trigger. Check src/lib/analysis/anomaly-detection.ts.
One client fails, others work fine
Check the clients table in Supabase
The failing client may have:
- Missing
googleAdsCustomerId— MCP server can't pull data without it - Missing
gscSiteUrl— GSC calls will fail (but shouldn't block the rest) - Missing
ga4PropertyId— GA4 calls will fail (but shouldn't block the rest) - Missing
clickupListId— ClickUp tasks won't be created for this client is_active = false— client is disabled and will be skipped
Check the cron for that client
Each client has its own cron entry in vercel.json. If the entry is missing or has a typo, that client won't run.
Recommendations are poor quality
Rules engine thresholds
Key thresholds to check in src/lib/analysis/rules-engine.ts:
- Keyword pause: $50+ spend with 0 conversions in 14 days
- CPA threshold: 3x above ad group average
- CTR threshold: below 1% after 1000+ impressions
- Quality Score: QS 3 or below with $50+ spend
Sub-agent prompt quality
Each sub-agent has a system prompt in src/lib/analysis/sub-agents/. If recommendations are consistently off:
- Too aggressive — add more conservative guardrails to the system prompt
- Missing context — check feedback rules, top-performing copy, and competitor data are being passed through
- Wrong tone in ad copy — check the MM brand context is being injected into Agents 4 and 5
Feedback rules not applying
Check the feedback_rules table in Supabase. Active rules should be filtering out previously-rejected actions. If not:
- Check
is_active = true - Check
expires_athasn't passed - Check the scope matches (entity vs pattern vs global)
- For entity-level rules, check the
entity_idmatches exactly
Quick reference — key URLs
| What | Where |
|---|---|
| Vercel dashboard | vercel.com/teddi-coder/mm-google-ads-autopilot ↗ |
| Vercel function logs | /logs ↗ |
| Supabase dashboard | Check NEXT_PUBLIC_SUPABASE_URL in Vercel env vars |
| Fly.io MCP servers | flyctl status -a mechanic-mcp-server / flyctl status -a hedgehog-ads-writer |
| Slack app config | api.slack.com/apps ↗ — MM Ads Autopilot app |
| Google Ads API | console.cloud.google.com → APIs & Services → Google Ads API |
| App URL | mm-google-ads-autopilot.vercel.app ↗ |
Restarting everything from scratch
flyctl status -a mechanic-mcp-server and flyctl status -a hedgehog-ads-writer