Agent skill
tuesday-pivots
Install this agent skill to your Project
npx add-skill https://github.com/ChinchillaEnterprises/ChillSkills/tree/main/tuesday-pivots
SKILL.md
Tuesday Pivots
Weekly distribution skill for GFY (Go Farm Yourself) pivot reports. Takes Cliff's image + text from Slack and pushes it out via SMS (SlickText), email (HubSpot), and blog (DropInBlog).
Trigger
User says: "run tuesday pivots", "tuesday pivots", "send pivots", or similar.
Inputs
Content comes from ONE of these sources (ask if unclear):
- Slack #automation channel — fetch latest from GFY workspace
- User pastes text + provides image path — manual input
Prerequisites
- Slack MCP active on GFY workspace (account id:
gfy) - Playwright MCP tools loaded (load ALL needed tools upfront in Step 0)
- Chrome profile "Jamie (gfyag.com)" used for all web steps
- HubSpot token at
~/.config/hubspot/token
Pre-flight: Load all tools at once
Before starting, load every Playwright tool you'll need in a single batch:
ToolSearch: "playwright navigate click fill snapshot type evaluate file_upload wait_for"
This avoids repeated ToolSearch calls mid-workflow.
Step 0: Switch Slack to GFY workspace
Use mcp__slack__switch_account with account_id: "gfy"
Step 1: Fetch content from #automation channel
IMPORTANT: The Slack bot CANNOT access user DMs. Do NOT attempt DM channels.
- Channel: #automation (ID:
C08MZHERDHA) — bot is already a member - Use
mcp__slack__slack_get_channel_historyon channelC08MZHERDHA, limit 5 - Look for today's pivot message (forwarded by user from Cliff's DM)
- Extract the text from the message body
KNOWN LIMITATION: Slack MCP does not return file attachments. Images forwarded to #automation will not be accessible. The image must come from one of these fallback paths:
- User provides a file path directly (e.g.,
~/Downloads/image.png) - User pastes the image into the CLI
- User saves it to Downloads first, then gives the filename
If no pivot message in #automation today, immediately ask user: "Can you forward Cliff's pivot to #automation, or paste the text and image here?"
Step 2: Save files locally
Image save path: ~/Desktop/%/Work/GFY/Pivots/weekly/YYYY/Mon/Mon-DD.png
Text save path: ~/Desktop/%/Work/GFY/Pivots/weekly/YYYY/Mon/Mon-DD.txt
Format rules:
YYYY= 4-digit year,Mon= 3-letter month (Feb, Mar, Jan)DD= day of month, NO leading zero- Examples:
Feb-18.png,Mar-4.png,Jan-7.txt
Create year/month folders if they don't exist:
mkdir -p "~/Desktop/%/Work/GFY/Pivots/weekly/YYYY/Mon"
CRITICAL: Also copy the image into the repo for Playwright uploads:
cp "<saved_image_path>" /Users/tori/Documents/Repos/CHI/pivot-upload.png
Playwright sandbox only allows file uploads from within /Users/tori/Documents/Repos/CHI. Always use /Users/tori/Documents/Repos/CHI/pivot-upload.png for ALL browser file uploads. Clean up this file at the end.
Step 3: Validate text length
- Count characters in the pivot text
- Limit: 1600 characters for SlickText (MMS messages use 3x multiplier)
- If OVER 1600: STOP and show the text with char count. Ask user to trim.
- If UNDER 1600: proceed automatically, note the count
Step 4: SlickText — Send SMS to both lists
URL: https://slicktext.com/dashboard/sendmessage.php
Account: Rupert Williams (Administrator)
Send to BOTH lists sequentially: "data" first, then "ginger"
For EACH list:
-
Navigate to
https://slicktext.com/dashboard/sendmessage.php -
If login required, tell user to log in via the Playwright browser, then snapshot
-
Take a snapshot to see the form
-
Fill the form fields:
- Textword dropdown: Select the list ("data" or "ginger")
- Campaign Name:
Pivots M/DD/YY(e.g., "Pivots 2/18/26") - Message body: Type/fill the pivot text
-
Attach image — use this exact sequence (the attach button has an overlapping div):
browser_evaluate: () => { document.querySelector('input.mmsFile').click(); return 'triggered'; }Wait for file chooser modal, then:
browser_file_upload: paths: ["/Users/tori/Documents/Repos/CHI/pivot-upload.png"] -
HANDLE LINK SHORTENER PROMPTS: SlickText will pop up "Shorten and track the X link?" for every decimal number in the text (459.125, 1097.70, 4.31, etc.). There will be ~20-30 of these. Dismiss them efficiently:
browser_evaluate: () => { const dismissAll = () => { const btns = document.querySelectorAll('.swal2-deny, .swal2-cancel, [data-action="dismiss"]'); btns.forEach(b => b.click()); }; const interval = setInterval(() => { const popup = document.querySelector('.swal2-popup'); if (popup) { const noBtn = popup.querySelector('.swal2-deny') || popup.querySelector('.swal2-cancel'); if (noBtn) noBtn.click(); } }, 200); setTimeout(() => clearInterval(interval), 15000); return 'auto-dismissing link prompts for 15s'; }After running that, click the message body field to trigger remaining prompts, then wait 15 seconds. If prompts persist, click "No" on each one via snapshot + click.
-
Timing:
- Before 9 AM ET: Select "Later..." and schedule for 9:00 AM
- After 9 AM ET: Select "Now"
-
Click "Send Message" button
-
Confirm dialog: Click "Yes, Send It"
-
Verify success message (e.g., "296 people will be receiving your message")
After "data" list is sent, navigate back to the same URL for "ginger" list. Campaign name for second: Pivots M/DD/YY - Ginger.
Step 5: HubSpot — Update email content (API)
Uses HubSpot API — no Playwright needed.
Script: ~/.claude/skills/tuesday-pivots/scripts/hubspot-email-update.sh
Marketing Email ID: 208610266640
Content widget: module-1-0-0 (via content.widgets)
From: Rupert Williams / rwilliams@mail.gfy.ag (already configured)
5a. Upload pivot image to HubSpot
IMAGE_URL=$(~/.claude/skills/tuesday-pivots/scripts/hubspot-email-update.sh upload-image "<saved_image_path>")
This uploads to /pivots/ folder and returns the hosted URL.
5b. Build HTML content with personalization
IMPORTANT: Always prepend the greeting with HubSpot personalization token.
<p>Howdy {{ contact.firstname }},</p>
<p>Paragraph 1 of pivot text...</p>
<p>Paragraph 2...</p>
<img src="HOSTED_IMAGE_URL" alt="Ginger Pivots" style="max-width:100%;" />
- First line is ALWAYS
<p>Howdy {{ contact.firstname }},</p> - Wrap each paragraph in
<p>tags - Escape
&as& - Place the image at the bottom after all text paragraphs
5c. Update email content
~/.claude/skills/tuesday-pivots/scripts/hubspot-email-update.sh update-content "<html_content>"
This updates the draft (PATCH /draft) and publishes (POST /publish) in one call. The footer module is included automatically to pass HubSpot validation.
5d. Verify content
~/.claude/skills/tuesday-pivots/scripts/hubspot-email-update.sh get
Step 6: HubSpot — Turn on Tuesday Pivots workflow (API)
Uses HubSpot API — no Playwright needed.
Script: ~/.claude/skills/tuesday-pivots/scripts/hubspot-workflow.sh
Workflow ID: 519040090
The workflow sends marketing email 208610266640 to contacts in lists 137 (Opt-in Voicemail), 276, and 138 (Trialists). It checks marketability, waits 1 minute, then sends.
# Check current status
~/.claude/skills/tuesday-pivots/scripts/hubspot-workflow.sh status
# Turn on — workflow enrolls contacts and sends the email
~/.claude/skills/tuesday-pivots/scripts/hubspot-workflow.sh on
IMPORTANT: Turn the workflow OFF after enrollment completes (~5 minutes):
~/.claude/skills/tuesday-pivots/scripts/hubspot-workflow.sh off
This prevents re-sending if the workflow's weekly Tuesday 9 AM schedule fires later. The pre-day LaunchAgent (com.gfy.pivots-precheck) also runs Monday nights at 10 PM as a safety net.
Fallback: If API fails, use Playwright:
- Navigate to
https://app.hubspot.com/workflows/23710839/platform/flow/519040090/edit - Click "Review and turn on" → "Skip to turn on" → "Turn on workflow"
TIMING NOTE: The workflow has a built-in weekly schedule (Tuesday 9 AM CT). When turned on:
- It will immediately enroll all contacts in lists 137/276/138 and send the email
- The 1-minute delay in the workflow gives a small buffer
- Turn it OFF within 5 minutes to avoid the scheduled trigger re-firing
Step 7: DropInBlog — Create blog post
URL: https://app.dropinblog.com/posts
-
Navigate to posts page
-
If login required, tell user to log in
-
Click "Add Post" link (bottom right of page, ref to the link not the table button)
-
Fill the post:
Title (textbox):
M/DD/YY Pivotsformat (e.g.,2/17/26 Pivots)- Month: no leading zero, Day: no leading zero, Year: 2-digit
Content (iframe editor) — set via JS, do NOT try to type into it:
browser_evaluate: () => { const iframe = document.querySelector('#seo-content-wrap iframe'); if (iframe && iframe.contentDocument) { iframe.contentDocument.body.innerHTML = '<p>First paragraph...</p><p>Second...</p>'; return 'Content set'; } return 'iframe not found'; }Wrap each paragraph in
<p>tags. Escape&as&.Status: Click the "Published" LABEL text (ref for the label, NOT the radio input — the radio input has an overlapping label that intercepts clicks):
browser_click: ref for "Published" label text (generic element), NOT the radio refVisibility: Should default to "Public" — verify but don't change unless wrong.
-
Featured Image — Click "Select" under Featured Image to open File Manager:
- Click "Upload" in the File Manager sidebar
- Trigger the file input via JS (filepond label intercepts clicks):
browser_evaluate: () => { document.querySelector('input[name="filepond"]').click(); return 'triggered'; } - Use
browser_file_uploadwith/Users/tori/Documents/Repos/CHI/pivot-upload.png - Wait for upload to complete (
browser_wait_fortextGone: "Uploading") - The upload dialog may auto-close. Take a snapshot.
- In File Manager, click the uploaded filename (should be at top, sorted by Modified)
- Click "Insert" button that appears
- Verify alert: "Featured image added."
-
Click "Save Post"
-
Verify alert shows "Saved" and page title changes to "Edit Post"
-
Note the View Post URL from the sidebar link
Step 8: Cleanup & Confirmation
Cleanup:
rm /Users/tori/Documents/Repos/CHI/pivot-upload.png
Turn off workflow (if not already done in Step 6):
~/.claude/skills/tuesday-pivots/scripts/hubspot-workflow.sh off
Report to user:
- Image saved to: [full path]
- Text character count: [X]/1600
- SlickText: Sent to "data" list ([N] recipients) / Sent to "ginger" list ([N] recipients)
- HubSpot email updated + sent via workflow to lists 137/276/138
- DropInBlog post published: [title] — [URL]
Key Reference Data
| Item | Value |
|---|---|
| Cliff Slack ID | U02718MM970 |
| Slack workspace | GFY (account id: gfy) |
| Slack channel | #automation (C08MZHERDHA) |
| Image save path | ~/Desktop/%/Work/GFY/Pivots/weekly/YYYY/Mon/ |
| Playwright upload path | /Users/tori/Documents/Repos/CHI/pivot-upload.png |
| SlickText URL | slicktext.com/dashboard/sendmessage.php |
| SlickText lists | data, ginger |
| SMS char limit | 1600 (MMS = 3x multiplier) |
| HubSpot account ID | 23710839 |
| HubSpot marketing email ID | 208610266640 |
| HubSpot content widget | module-1-0-0 (in content.widgets) |
| Email from | Rupert Williams / rwilliams@mail.gfy.ag |
| Personalization | {{ contact.firstname }} in greeting |
| HubSpot workflow ID | 519040090 |
| Workflow actions | Marketability check → 1-min delay → send email 208610266640 |
| Workflow enrollment lists | 137 (Opt-in Voicemail), 276, 138 (Trialists) |
| Email subject | "Ginger Pivots" |
| Email update script | ~/.claude/skills/tuesday-pivots/scripts/hubspot-email-update.sh |
| Workflow toggle script | ~/.claude/skills/tuesday-pivots/scripts/hubspot-workflow.sh |
| DropInBlog URL | app.dropinblog.com/posts |
| Blog title format | M/DD/YY Pivots |
| Chrome profile | Jamie (gfyag.com) |
Known Platform Quirks
Slack MCP
- Bot CANNOT access user-to-user DMs (channel_not_found error)
- Bot CANNOT see file attachments in messages (images silently stripped)
- Bot is deactivated in GFY workspace — cannot join new channels
- Only use channels where bot is already a member (#automation)
Playwright Sandbox
- File uploads MUST use paths within
/Users/tori/Documents/Repos/CHI - Always copy images to
pivot-upload.pngin repo root before uploading - If a file_upload fails, the file chooser modal CLOSES — must re-trigger the input before retrying
SlickText
- Decimal numbers in text trigger "Shorten and track?" link prompts (~20-30 per send)
- The attach file button (
btnAttach) has an overlappingbtnContainerdiv — use JS to click the hiddeninput.mmsFileinstead - MMS messages use a 3x character multiplier (1600 chars = 3 MMS segments)
HubSpot
- Email 208610266640 is in AUTOMATED state — direct PATCH fails (400), must use PATCH
/draft+ POST/publish - The script handles this automatically — includes footer module (
module_17725218052791,@hubspot/email_footer) in every draft PATCH to pass publish validation - Image upload via Files API (
/files/v3/files) to/pivots/folder - Workflow 519040090 sends the email — toggle on/off via API
- MUST turn workflow OFF after sending to prevent re-fire on weekly schedule
- Old template 51704482 (design template) is deprecated — do NOT use
- Old sales sequence 92766546 is deprecated — workflow now sends email directly
DropInBlog
- Content editor is inside an iframe — must use JS
innerHTMLto set content, NOT type/fill - Radio buttons have overlapping labels — click the label text element, not the radio input
- Featured image upload uses filepond — label div intercepts clicks on the file input, use JS
.click()on the input directly - After upload completes, must manually select the file in File Manager and click "Insert"
Error Handling
- No pivot in #automation: Ask user to forward from Cliff's DM or provide manually
- Image not accessible from Slack: Ask user for file path or have them paste into CLI
- Text over 1600 chars: Stop, show count, ask user to trim
- Login required on any site: Tell user to log in via Playwright browser, then snapshot to continue
- File upload sandbox error: Verify image was copied to repo root first
- File chooser closed after error: Re-trigger the input element via JS before retrying upload
- HubSpot email update fails: Check token at
~/.config/hubspot/token, try refreshing - Image upload fails: Check file exists, try again — HubSpot Files API is reliable
- Workflow already ON: Skip the toggle step, note it in summary
- Workflow toggle fails: Fall back to Playwright (workflow edit page)
Post-Run Assessment (mandatory)
After every run, before closing the session:
- Review all errors, retries, and wasted turns from this run
- Identify any new platform quirks or UI changes
- Update this SKILL.md with fixes — add new quirks, refine JS snippets, fix selectors
- Note what worked well and what was slow
- Update the "Last Run" section below
Last Run
- Date: 2026-03-03
- Model: Opus 4.6
- Changes:
- Email published from AUTOMATED_DRAFT to AUTOMATED state (footer + unsubscribe added via Playwright UI)
- Script rewritten for draft+publish flow (direct PATCH fails on AUTOMATED emails)
- Footer module (
module_17725218052791) included in every draft PATCH for publish validation - Added
get-draftcommand to script - Email from changed to Rupert Williams / rwilliams@mail.gfy.ag
- Added
{{ contact.firstname }}personalization greeting - Workflow 519040090 sends marketing email 208610266640 directly (old sequence deprecated)
- Result: All API calls tested and working.
update-content,update-subject,upload-image,get,get-draftall confirmed. - Target: Run on Sonnet next time, Haiku eventually
Performance Notes
- Load all Playwright tools in one ToolSearch call at the start
- Don't waste turns trying Slack DMs — go straight to #automation
- Don't waste turns trying to create Slack channels — bot is deactivated
- Copy image to repo root immediately after saving — don't discover sandbox error mid-upload
- Use JS for all tricky UI interactions (file inputs, iframes, intercepted elements)
- For SlickText link prompts, try the auto-dismiss JS first before manual clicking
- HubSpot email step is now pure API — fastest step in the workflow
- This skill is designed to run on Sonnet or Haiku — all steps are explicit with exact selectors and JS snippets
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
Red Team
Use this skill when the user says "red team", "stress test", "attack this", "critique this", "run the models against this", "test this plan", "refine this with AI", or wants to use external AI models to critique, validate, or improve a document, pitch, plan, or idea. Also use when the user wants to save Claude Code usage by offloading analysis to other models.
Upwork Scanner
This skill should be used when the user asks to "scan upwork", "find upwork jobs", "check upwork", "run the scanner", "look for jobs", or mentions finding freelance projects for Chinchilla AI.
Polymarket Arb Scanner
This skill should be used when the user asks to "scan polymarket", "find arb opportunities", "check polymarket arbs", "run arb scanner", "polymarket arbitrage", or mentions detecting price inefficiencies on Polymarket.
captain-update
Polymarket Copy Trader
This skill should be used when the user asks to "copy trade", "telegram bot polymarket", "follow traders", "copy polymarket", or mentions building a copy trading bot for Polymarket.
Architecture Diagram
This skill should be used when the user asks to "generate a diagram", "create an architecture diagram", "make a diagram", "draw a system diagram", or needs a branded Chinchilla AI technical diagram for proposals or documentation.
Didn't find tool you were looking for?