# Session Handoff — GHL OAuth + Social Media Pipeline (2026-08-03)

## What We Accomplished

### 1. GHL OAuth App V3 — Complete Rebuild
- **Problem:** V2 ("Hermes1") was freemium-locked, blocking direct OAuth installs. Multiple failed install attempts yielded only agency-level tokens.
- **Solution:** Created V3 with free pricing, sub-account target, agency-only install, 168 scopes (full set).
- **Key learning:** "Agency Only" install setting + direct chooselocation link = location-level tokens. UI Install button = agency-level only.
- **Current state:** V3 installed at agency level, auto-installs to future sub-accounts. Tokens stored in multi-token handler (v2.0 patched 2026-08-03).
- **Sub-accounts:** RRR (`4yTvHUHrmVuP8CgCt1Q9`), Test Sandbox (`VLPUVcvUDOaXhgFPKiGl`), Pipeline Layer (`k6PTFz0gXAdNJLDT1aji` — created today).

### 2. Multi-Token Handler Patch
- **File:** `/root/.hermes/ghl-oauth/ghl_oauth_server.py` v2.0
- **Change:** Tokens stored keyed by locationId (`{"tokens": {"<locationId>": {...}}}`) instead of single token file
- **Benefit:** No more clobbering. Sandbox + agency + RRR tokens coexist.
- **New endpoints:** `/ghl/health` (lists all tokens), `/ghl/token?locationId=<id>` (per-location token)
- **Backup:** `ghl_oauth_server.py.bak-20260803`

### 3. Social Media Connections
- **Pipeline Layer:** LinkedIn (Rob Blake personal profile) — for B2B SaaS RevOps content
- **RRR:** Facebook (Real Results Ready LLC page) — for local service SMB content
- **Note:** Initially connected backwards (RRR FB to Pipeline Layer, LinkedIn to RRR). Swapped 2026-08-03.

### 4. Pipeline Layer Sub-Account
- Created via API (`POST /locations/`) with agency token
- V3 auto-installed (the "automatic installation to future locations" checkbox worked)
- Website cloned from RRR sub-account via GHL UI snapshot feature (API can't do this)

### 5. Brand Assets
- **Pipeline Layer logo:** 3 iterations, final = typography-only, dark charcoal (#2D3748) + warm amber (#E8893A)
- **Sizes:** 40-52px light bg, 36-44px dark bg (GHL brand settings)
- **Files:** `/root/.hermes/images/pipeline-layer-logo-*.png`

### 6. LinkedIn Content Batch (Week of Aug 3-7)
- **5 posts scheduled** via GHL Social Planner API, 9 AM MDT each day
- **Images:** OpenAI gpt-image-2 generated quote cards (verified text accuracy via vision_analyze)
- **Topics:** AI slop system, dashboard posture, 7 AI certs, judgment transfers, engagement bait crackdown
- **Status:** All scheduled, media attached, verified

### 7. Skills Created/Updated
- **`social-media-content-pipeline`** (new) — full workflow: research → write → image → schedule → verify
- **`brand-asset-generation`** (existing, validated) — the iterate loop, vision_analyze checks
- **`gohighlevel-ops`** (updated) — V3 app details, multi-token handler, Social Planner endpoints

### 8. Cron Job
- **`linkedin-content-batch`** — Sundays 6 AM UTC, generates next week's LinkedIn batch
- Human-in-the-loop: delivers summary for Rob's review before posts go live

## Key Decisions

1. **V3 over V2:** Free pricing unblocks direct OAuth installs. Agency-level install + auto-install to sub-accounts is the working pattern.
2. **Agency token for writes:** Contrary to 7/30 findings, V3 agency token CAN write to sub-accounts (Social Planner verified). Funnels still 401 per-endpoint.
3. **OpenAI for images:** gpt-image-2 > FAL Klein for text rendering. No more "Pirolene" issues.
4. **Nginx image serving:** GHL OAuth handler serves LinkedIn images at `/ghl/images/linkedin/` — no separate nginx config needed.
5. **Human-in-the-loop:** Cron generates, Rob reviews before publish. No fully autonomous posting.

## RRR Positioning Pivot (2026-08-03)

**Problem:** "AI Assistant" is the commodity pitch — every GHL guy leads with it. Rob's instinct: "Oh you're another one of those GHL guys. I get 20 calls a day from them...not thanks!"

**New direction:** Lead with revenue intelligence, not call answering.

**Candidates:**
- A) **Leak Report:** "Most contractors know they're missing calls. Few know which marketing dollar actually booked the job. We find the leak before we fix it."
- B) **27-years-enterprise-data:** "We spent 27 years tracking marketing ROI for companies spending millions. Now we bring that rigor to Brighton contractors — without the enterprise price tag."
- C) **Contrarian:** "Everyone's selling AI receptionists. We sell revenue intelligence. The difference: we show you which marketing dollars actually booked the job — then we fix the leak."
- D) **Local expertise:** "Brighton contractors don't need another AI tool. They need to know which of their marketing actually works. We track it, we prove it, we fix what's broken."

**Entry point:** $497 Missed Call Diagnostic — opportunity-shaped, not fear-shaped.

## RRR Verticals Analysis

**Current 18 on site:**
Accountants, Auto Repair, Cleaning, Contracting, Electricians, Garage Door, HVAC, Landscaping, Med Spas, Painting, Pest Control, Plumbers, Real Estate Brokers, Restoration, Roof Repair, Tax Preparers, Tree Service, Funeral Homes

**Recommended prune (different sales motion):**
- Accountants, Tax Preparers, Real Estate Brokers, Funeral Homes (appointment/relationship-driven, not speed-to-lead)
- Maybe Med Spas (high-touch consultative)

**Recommended add (home services, missed-call pain):**
- Appliance Repair, Handyman, Locksmith, Carpet Cleaning, Window Cleaning, Pressure Washing

**Target:** ~16-18 focused on home services where "missed call = lost job"

## Content Engine Cadence (Pending)

**Rob's workflow:** Blog posts FIRST (~1000 words, 18 vertical versions), then FB posts as summaries.

**Proposed structure:**
- **Cron A (Sunday):** Generate blog post draft for next vertical → save to file → notify Rob for review
- **Rob reviews/edits/publishes blog** (manual)
- **Cron B (Tuesday):** Check if blog live → generate FB summary + image → schedule FB post

**Open question:** Same-day blog+FB, or 1-2 day lag?

## Files Created/Modified

| File | Action | Notes |
|------|--------|-------|
| `/root/.hermes/ghl-oauth/ghl_oauth_server.py` | Patched v2.0 | Multi-token store, webhook endpoint, image serving |
| `/root/.hermes/ghl-oauth/ghl_oauth_server.py.bak-20260803` | Backup | Pre-patch version |
| `/root/.hermes/secrets/ghl-oauth.json` | Migrated | Legacy single-token → multi-token format |
| `/root/.hermes/secrets/ghl-oauth.env` | Updated | V3 client ID + secret |
| `/root/.hermes/secrets/abacus.env` | Created | Abacus AI key (deprecated — 403 on generation) |
| `/root/.hermes/config.yaml` | Updated | image_gen.provider = openai |
| `/root/.hermes/skills/marketing-ops/social-media-content-pipeline/SKILL.md` | Created | Full workflow documentation |
| `/root/.hermes/skills/marketing-ops/gohighlevel-ops/SKILL.md` | Patched | V3 app, multi-token, Social Planner |
| `/root/.hermes/images/linkedin/linkedin_2026-08-*.png` | Created | 5 OpenAI-generated quote cards |
| `/root/.hermes/images/pipeline-layer-logo-*.png` | Created | Logo variants |
| `/root/.hermes/Business_Projects/.../RRR_FB_POSTS_2026-08-03.md` | Created | 5 FB posts (superseded by blog-first workflow) |

## Open Items for Next Session

1. **RRR positioning decision** — pick lead message (A/B/C/D or hybrid)
2. **Vertical list finalization** — prune/add from 18 to ~16
3. **Blog post template** — structure for 18 vertical versions
4. **FB cron job** — cadence and human-in-the-loop points
5. **V3 secret rotation** — secret was chat-pasted, regenerate when convenient
6. **RRR website messaging** — update to reflect new positioning (not "AI Assistant")
7. **Pipeline Layer website** — verify clone landed correctly, update domain DNS

## Credentials State

| Service | Status | Location |
|---------|--------|----------|
| GHL V3 Client ID | Active | `ghl-oauth.env` |
| GHL V3 Client Secret | **Chat-pasted — rotate** | `ghl-oauth.env` |
| OpenAI API Key | Active | `config.yaml` |
| Abacus AI Key | **Deprecated** (403 on generation) | `abacus.env` |
| FAL | Active (via Nous subscription) | Default backend |

## Quick Verification Commands

```bash
# GHL token health
curl -s http://127.0.0.1:9120/ghl/health | python3 -m json.tool

# Scheduled posts
TOKEN=$(python3 -c "import json; print(json.load(open('/root/.hermes/secrets/ghl-oauth.json'))['tokens']['agency:e4QT67gW4Bz6yO6r7Teu']['access_token'])")
curl -s -H "Authorization: Bearer $TOKEN" -H "Version: 2021-07-28" -H "Content-Type: application/json" \
  "https://services.leadconnectorhq.com/social-media-posting/k6PTFz0gXAdNJLDT1aji/posts/list" -X POST -d '{"limit": "5"}'

# Image serving
curl -s -o /dev/null -w "%{http_code}" https://robblake.cloud/ghl/images/linkedin/linkedin_2026-08-03.png
```

## Pickup Instructions

1. Read this handoff
2. Check `/ghl/health` for token status
3. Verify scheduled posts look correct in GHL UI
4. Confirm RRR positioning direction with Rob
5. Proceed with vertical list finalization and blog template

---
*Session ended: 2026-08-03 ~13:30 UTC*
*Next session: RRR positioning finalization + content engine setup*
