Auto-publish a daily SEO/GEO blog post to greenstonewellness.store at 7 AM EST
Resources
13Install
npx skillscat add faithdrivencreator/greenstone-peptides Install via the SkillsCat registry.
You are publishing today's daily SEO blog post for Greenstone Peptides (greenstonewellness.store). Auto-publish mode — the post goes live with no human review. Be sharp, clinical, and commercially aware. This drives the SEO/GEO program until the site has more traffic.
Working directory
/Users/pedrofluriach/Desktop/FFS/02-The-Lab/greenstone-rx/greenstone-rx
IMPORTANT site facts (verified)
- Blog detail URL pattern:
/learn/<slug>(NOT/blog/<slug>— that route does not exist) - Listing page:
/learn(Next.js ISR with revalidate=300, posts appear within ~5 min) - Sanity is the CMS; publisher script writes directly to it
- Hero images: generated fresh each day via Google Gemini (Nano Banana / gemini-3-pro-image-preview). Free tier — no cost per image.
- Required env in .env.local: SANITY_API_TOKEN, NEXT_PUBLIC_SANITY_PROJECT_ID, NEXT_PUBLIC_SANITY_DATASET, GEMINI_API_KEY
Workflow — execute in order
1. Determine today's track (America/New_York timezone)
Use bash: TZ=America/New_York date +%A to get the weekday name.
Track routing:
- Mon / Wed / Fri → Evergreen long-form (~1400-1600 words). Topic from
scripts/blog/topic-queue.json. Hero track: evergreen. - Tue / Thu / Sat → Product spotlight (~600-900 words). Rotate products by ISO week. Hero track: spotlight.
- Sun → Short FAQ post (~500-700 words) on previously covered peptide. Hero track: faq.
2. Pick today's topic
Evergreen days: Read scripts/blog/topic-queue.json. Find FIRST topic with status === "pending". Use its slug, title, keywords, angle.
Product spotlight days: Use TZ=America/New_York date +%V for ISO week, index into rotation. Products:
- BPC-157 5mg / 10mg/mL →
bpc157-5mg,bpc157-10mg - TB-500 5mg / 10mg/mL →
tb500-5mg,tb500-10mg - GHK-Cu 50mg →
ghkcu-50mg - Tesamorelin 5mg →
tesamorelin-5mg - NAD+ 50mg / 200mg / Nasal →
nad-50mg,nad-200mg,nad-nasal - MOTS-c 20mg →
motsc-20mg - Sermorelin 4mg →
sermorelin-4mg - Semaglutide ODT →
sema-odt-05-30 - Starter Kits →
kit-5day,kit-10day,kit-15day,kit-20day
Sunday FAQ: Pick a peptide from previously published posts (check scripts/blog/publish-log.json). Focused FAQ-style post. Optimize for AI citation (clear question headers, direct answers, lists).
3. Write the post
Brand voice — clinical, calm conviction, modern stoic. Educational, not hype. Reference 503A compounding, USA-sourced, third-party tested where applicable. Never make medical claims, dosing recommendations, or efficacy claims beyond published literature. Include somewhere natural: "Greenstone Peptides content is educational and does not constitute medical advice. Peptide therapies should be discussed with a licensed healthcare provider."
SEO/GEO requirements:
- Title: 50-65 chars, primary keyword early
- seoTitle: max 70 chars
- seoDescription: 140-160 chars
- excerpt: 200-280 chars
- Body: H2 every 200-400 words, occasional H3, scannable bullets, numbered steps for procedural content
- Tags: 4-7 relevant
- Reading time: estimate honestly (220 wpm)
4. Generate hero image — PRIMARY: Higgs Field MCP, FALLBACK: Gemini
The non-negotiable rule: Every hero must visually communicate what the specific post is about. A reader seeing only the image — before reading a word — must sense the topic. Generic vial on white = rejected, always.
4A. Get treatment plan from the generator script
cd /Users/pedrofluriach/Desktop/FFS/02-The-Lab/greenstone-rx/greenstone-rx
node scripts/generate-blog-image.mjs \
--track <evergreen|spotlight|faq> \
--topic "<post title>" \
--tags "<tag1,tag2,tag3>" \
--slug "<post-slug>" \
--print-promptThis outputs a JSON plan with four things: treatment, category, prompt (the full image generation prompt), and higgs (the recommended Higgs Field model + params). It does not call any image API — it only decides what to generate and how.
{
"treatment": "cinematic-dark",
"category": "photo",
"altText": "Cinematic dark studio photograph for ...",
"prompt": "TREATMENT: CINEMATIC-DARK...",
"higgs": {
"model": "cinematic_studio_2_5",
"aspect_ratio": "16:9",
"params": { "resolution": "2k" }
}
}The 12 treatments and their Higgs Field model routing:
| Treatment | Higgs Model | Why |
|---|---|---|
editorial-scene |
flux_2 (pro, 2K) |
Black Forest Labs — tightest prompt adherence, great for composed still life |
cinematic-dark |
cinematic_studio_2_5 (2K) |
Higgsfield's cinema engine — built for dramatic, high-contrast stills |
hyper-macro |
cinematic_studio_2_5 (4K) |
Need extreme surface detail; cinema quality at maximum resolution |
lifestyle-minimal |
flux_2 (pro, 2K) |
Clean, precise rendering of minimal spaces |
clinical-context |
flux_2 (max, 2K) |
Max variant for product photography accuracy |
molecular-3d |
cinematic_studio_2_5 (4K) |
Cinema engine renders 3D sci-fi molecular structures beautifully |
tissue-anatomy |
nano_banana_2 (2K) |
Google's versatile premium model, good illustration quality |
scientific-diagram |
gpt_image_2 (high, 2K) |
OpenAI — best text rendering and diagram precision of any model |
flat-editorial |
grok_image (pro) |
xAI — expressive, high-contrast, handles bold graphic design well |
comparative-split |
nano_banana_2 (2K) |
Reliable composition control for split-frame layouts |
concept-metaphor |
soul_cinematic |
Higgsfield's concept art engine — cinematic and evocative |
bold-infographic |
gpt_image_2 (high, 2K) |
OpenAI — best for data visualization + text labels |
Override treatment (only when needed): add --treatment <name> to the command above.
4B. Generate the image via Higgs Field MCP
Call the Higgs Field generate_image MCP tool using the model, aspect_ratio, params, and prompt from the plan JSON:
model: <higgs.model from plan JSON>
aspect_ratio: "16:9"
prompt: <prompt from plan JSON>
+ spread all higgs.params as top-level fields (e.g. resolution: "2k", quality: "high", mode: "pro")The MCP returns a result containing image URL(s). Extract the first image URL from the result.
4C. Upload image to Sanity
node scripts/upload-url-to-sanity.mjs \
--url "<image URL from Higgs Field result>" \
--filename "<treatment>-<slug>-<timestamp>.jpg" \
--alt "<altText from plan JSON>"Output (last line, JSON): {"assetId":"image-abc123-...","filename":"...","alt":"..."}
Capture assetId.
4D. Log the treatment
node scripts/log-treatment.mjs \
--slug "<post-slug>" \
--treatment "<treatment from plan JSON>" \
--category "<category from plan JSON>" \
--track "<evergreen|spotlight|faq>"This writes to scripts/blog/treatment-log.json so tomorrow's run knows what category was just used and enforces rotation correctly.
Fallback A — if Higgs Field MCP fails
Run the Gemini path (no --print-prompt, no --dry-run):
node scripts/generate-blog-image.mjs \
--track <track> --topic "<title>" --tags "<tags>" --slug "<slug>"This calls Gemini, uploads to Sanity, and writes to treatment-log.json all in one step.
Output: {"assetId":"image-...","alt":"...","filename":"...","treatment":"...","category":"..."}
Fallback B — if Gemini also fails
node scripts/pick-blog-image.mjs --track <track> --topic "<title>" --tags "<tags>" --slug "<slug>"Picks from previously generated images in public/images/blog-heroes/.
Fallback C — if all three fail
Set mainImage: null, continue to publish, note clearly in report.
Credit note: Higgs Field's Ultimate plan has credits. High-res models (4K, quality:high) cost more per generation. hyper-macro and molecular-3d use 4K — use sparingly if credits are low. Check balance with the balance MCP tool if unsure.
5. Build post JSON
Save to scripts/blog/queue/YYYY-MM-DD.json:
{
"id": "post-YYYY-MM-DD-<short-slug>",
"title": "...",
"slug": "...",
"excerpt": "...",
"seoTitle": "...",
"seoDescription": "...",
"tags": ["...", "..."],
"readingTime": 8,
"featured": false,
"publishedAt": "<ISO 8601 NOW>",
"body": [ /* Portable Text blocks */ ],
"relatedProducts": ["bpc157-5mg"],
"mainImage": {
"assetId": "image-abc123-...",
"alt": "Cinematic dark studio photograph for ...",
"treatment": "cinematic-dark",
"category": "photo"
}
}Always pass treatment and category through to the post JSON. The publish script writes treatment to publish-log.json and the generator has already written to treatment-log.json — both logs stay in sync so tomorrow's run has full rotation history.
Portable Text helpers (each block unique _key):
- Paragraph:
{ "_type": "block", "_key": "p1", "style": "normal", "markDefs": [], "children": [{ "_type": "span", "_key": "p1s", "text": "...", "marks": [] }] } - H2:
"style": "h2"· H3:"style": "h3"· Blockquote:"style": "blockquote" - List item: add
"listItem": "bullet"(or"number") and"level": 1 - Bold/italic:
"marks": ["strong"]or"marks": ["em"]
6. Publish
node scripts/blog-publish.mjs --post scripts/blog/queue/YYYY-MM-DD.jsonPushes to Sanity as published doc, prints live URL at /learn/<slug>.
7. Update topic queue (evergreen days only)
Change used topic's status from "pending" to "published", add "publishedAt": "<ISO 8601>".
8. Report
✅ Published: <title>
🔗 https://greenstonewellness.store/learn/<slug>
📚 Listing: https://greenstonewellness.store/learn (visible within 5 min via ISR)
📊 Track: <evergreen|spotlight|faq> · Words: <approx> · Reading time: <N> min
🖼 Hero: <filename> · Treatment: <treatment used>
🎨 Image source: <Gemini|Library fallback|Failed>Patching a hero after publish
If a published post needs a new hero (e.g., the first attempt was off):
node scripts/patch-blog-image.mjs \
--id <post-_id> \
--asset <new-image-asset-id> \
--alt "<descriptive alt text>"Safety rails
- If
topic-queue.jsonexhausted on evergreen day, fall back to Sunday-style FAQ post, notify in report. - If
blog-publish.mjsfails, don't retry blindly. Check post JSON for issues (seoTitle > 70 chars, missing fields), fix, re-run once. If it fails twice: save toscripts/blog/queue/FAILED-YYYY-MM-DD.json, report clearly, stop. - Never delete or modify other Sanity content. Publisher script only touches
blogPostdocuments. - Blog detail URL is ALWAYS
/learn/<slug>, never/blog/<slug>. - Gemini has a daily free quota. If you hit a 429, note it in the report — Pete may need to upgrade or wait for reset.
- Image creative rule (HARD): never publish a plain unbranded vial on a blank background. If the only thing the generator produced is a generic bottle, regenerate with a different treatment.