Map Leads v2

Organized AIOpenClaw + CF WorkersHardened

Firecrawl + 4-channel outreach (email/form/GBP/voice) + ElevenLabs + autoresearch flywheel. Auth via GWS CLI. Dynamic CF Workers via wrangler.


GWS CLI — Full Setup

All Google API authentication uses gcloud Application Default Credentials (ADC) and service accounts. No manual OAuth tokens.

#!/usr/bin/env bash # scripts/setup-gws.sh — run once to provision all GCP resources set -euo pipefail PROJECT_ID="${GCP_PROJECT_ID:?Set GCP_PROJECT_ID}" SA_NAME="map-leads-sa" SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" KEY_FILE="credentials/map-leads-sa.json" echo "==> Authenticating..." gcloud auth login --quiet gcloud config set project "$PROJECT_ID" echo "==> Enabling APIs..." gcloud services enable \ places.googleapis.com \ mybusinessbusinessinformation.googleapis.com \ mybusinessaccountmanagement.googleapis.com \ businessprofileperformance.googleapis.com echo "==> Creating service account..." gcloud iam service-accounts create "$SA_NAME" \ --display-name="Map Leads SA" --quiet 2>/dev/null || echo "SA exists" echo "==> Granting roles..." for ROLE in \ "roles/businessprofileperformance.viewer" \ "roles/iam.serviceAccountTokenCreator"; do gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member="serviceAccount:${SA_EMAIL}" --role="$ROLE" --quiet done echo "==> Generating SA key..." mkdir -p credentials gcloud iam service-accounts keys create "$KEY_FILE" \ --iam-account="$SA_EMAIL" --quiet echo "Key written → $KEY_FILE" echo "==> Setting ADC..." export GOOGLE_APPLICATION_CREDENTIALS="$(pwd)/$KEY_FILE" echo "GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/$KEY_FILE" >> .env echo "==> Creating Places API key..." gcloud services api-keys create \ --api-target=service=places.googleapis.com \ --display-name="map-leads-places" 2>/dev/null || true echo "Done. Add $KEY_FILE to .gitignore and CF Workers secrets."

Wrangler Secrets (GCP key for CF Workers)

cat credentials/map-leads-sa.json | \ wrangler secret put GOOGLE_SA_JSON --name map-leads-analyzer # (repeat for each worker that calls GBP API)

Dynamic CF Workers Architecture

Workers (one per agent)

worker-discovery — cron → Places API
worker-scraper — Firecrawl reviews + site
worker-analyzer — Claude / Gemma (via Tailscale)
worker-scorer — dynamic weights from KV
worker-outreach — 4 channels
worker-flywheel — EXP-N loops

Auth via GWS CLI

GOOGLE_APPLICATION_CREDENTIALS — SA JSON path (local)
GOOGLE_SA_JSON — wrangler secret (CF Workers)
gcloud auth adc — local dev
gcloud services enable — API provisioning
No manual OAuth tokens or refresh flows

CF Infrastructure

CF Queues — worker-to-worker messaging
Durable Objects — LeadStateMachine/lead
CF KV — weights, prompts, run log
CF R2 — ElevenLabs audio, JSONL exports
CF Pages — mapleads.organizedai.vip

Local Infra (Tailscale)

claws-mac-mini — 100.82.244.127
NoClaw/Gemma — :11434 (free inference)
Hermes — :7700 (orchestration + memory)
ExoClaw — CF Worker → Tailscale bridge
OpenClaw — :18789 (agent routing)


Wrangler Deploy — All Workers

#!/usr/bin/env bash # scripts/deploy-workers.sh set -euo pipefail ACCOUNT_ID="691fe25d377abac03627d6a88d3eeac9" WORKERS=( "map-leads-discovery:apps/worker-discovery" "map-leads-scraper:apps/worker-scraper" "map-leads-analyzer:apps/worker-analyzer" "map-leads-scorer:apps/worker-scorer" "map-leads-outreach:apps/worker-outreach" "map-leads-flywheel:apps/worker-flywheel" ) for entry in "${WORKERS[@]}"; do NAME="${entry%%:*}" DIR="${entry##*:}" echo "==> Deploying $NAME from $DIR..." CLOUDFLARE_ACCOUNT_ID="$ACCOUNT_ID" \ wrangler deploy --name "$NAME" \ --config "$DIR/wrangler.toml" \ --commit-dirty=true done echo "==> Deploying dashboard..." CLOUDFLARE_ACCOUNT_ID="$ACCOUNT_ID" \ wrangler pages deploy apps/dashboard/dist \ --project-name map-leads \ --commit-dirty=true echo "All deployed."

Phase Plan (v2)

PHASE 0
Bootstrap + GWS CLI + CF Workers Scaffold
Organized Codebase, pnpm monorepo, wrangler.toml (6 workers + queues), GWS CLI setup, Durable Object schema.
gcloud CLIwrangler CLIOrganized Codebase
PHASE 1
worker-discovery — Google Places
CF Worker on cron. Places API key via gcloud. Pushes to scrape-queue. Creates Durable Object per lead.
Google Placesgcloud API key
PHASE 2 UPDATED
worker-scraper — Firecrawl (replaces SerpAPI)
Reviews + website crawl. Contact form discovery, staff names, services. KV cache 7d TTL.
Firecrawlfc-a48926b25c7848bcad8c1354430359f7
PHASE 3
worker-analyzer — Claude / Gemma via Tailscale
Pain point extraction. Routes to Gemma (claws-mac-mini via ExoClaw) for bulk, Claude for final output.
Claude SonnetGemma 27BExoClaw
PHASE 4
worker-scorer — Dynamic Weights
Weights loaded from KV (flywheel updates). Hot/warm → outreach. All → flywheel baseline.
Dynamic weights (KV)
PHASE 5 EXPANDED
worker-outreach — 4 Channels + GWS CLI Auth
Email (Resend) + Form (Firecrawl) + GBP Messages (gcloud SA) + Voice (ElevenLabs + VAPI). All run in parallel.
ResendFirecrawlGBP + gcloud SAElevenLabs + VAPI
PHASE 6 NEW
worker-flywheel — Autoresearch EXP-N
Overnight EXP-N loops. Aggregate outcomes → test weight variations → update KV weights + prompts. JSONL to CF R2.
Autoresearch EXP-NCF KV + R2
PHASE 7
Dashboard + Wrangler Deploy
CF Pages Kanban dashboard. Deploy all 6 workers + dashboard via scripts/deploy-workers.sh.
CF Pageswrangler CLI

See github.com/Organized-AI/map-leads · v1 baseline at plan-v1