← Both skills · wildhorn-static-ads · wildhorn/paths-and-commands.md
Everything runs on the VPS (ssh vps-claude). Never run Playwright/Chromium or generation on the Mac. Secrets are referenced by path only.
/root/workspace/wh-remix/| Path | What it is |
|---|---|
LESSONS.md |
the anti-regression rulebook (A1–A26, B1–B16, C1–C11, D1–D10, E1–E7). Port the audit rules (A27–A31, B17–B19, C12–C18, D11–D13, E8–E13) from wildhorn/lessons-wildhorn.md when you next edit it. |
lint.py |
blocking linter: python3 lint.py SPECFILE → "LINT OK" or the list of violations. Imported by srun.py. |
PRODUCT.md |
product sheet (FR). Note: "Autoship -50%" is site-only; never in ads (B7). |
kit/ |
brand kit saved at step 5A: research.md (Primal Edge study), angle-01.md (locked angle), product.md, product-jar.jpg, creatives.jsonl (ads already made — don't duplicate). |
product-jar.jpg |
Image 1 of every generation (real jar photo). |
remix.py |
OpenAI gpt-image-2 edit: remix.py NAME --prompt FILE [--concept TEMPLATE] [--product JAR] [--n 1] [--quality high] [--size 1024x1024] → out/NAME_vK.png, copy in /srv/wildhorn-lp/remix/, log log.jsonl, gallery rebuilt. Retries 3× on 5xx/429. Key: /etc/secrets/openai_api_key. |
kie_gen.py |
kie.ai fallback: kie_gen.py NAME --prompt FILE [--concept IMG] [--product IMG] --model seedream|flux|nano [--aspect portrait_16_9|square_hd…] → out/NAME_vK.png. Models: seedream = bytedance/seedream-v4-edit, flux = flux-2/pro-image-to-image, nano = nano-banana-pro. Uses /root/workspace/wildhorn-lp/p6/gen/kie6.py (key loaded there). |
composite.py |
composite.py IN OUT spec.json — pastes the REAL jar cutout /srv/wildhorn-lp/p6/jar-30.webp and exact text. Spec keys: jar {x,y,h[,noshadow]} or jars [..], rects [[x0,y0,x1,y1,color]], band {y0,y1,color}, texts [{y,size,font,weight,align,x,maxw,lh,runs:[[text,color(,weight)]],shadow,sunscreen}], strikes [[x0,y0,x1,y1,color]]. Fonts: Anton, Montserrat, Oswald, Fredoka, DejaVu. All coordinates are fractions of the image. |
jarswap.py |
jarswap.py base.png out.png x0 y0 x1 y1 — swaps ONLY the jar inside the box with a masked gpt-image-2 edit (A25). Its prompt is written for the S11 "jar replaces her head" case — edit the prompt sentence before reusing it for another placement. |
fonts/ |
Anton-Regular.ttf, Montserrat.ttf (variable weight), Oswald.ttf, Fredoka.ttf |
out/ |
every generated image: run 1 <cNNNN>_vK.png / bN_NN…, Sam s_NN_vK.png, Seedream raws s_NN_sd_vK.png, kie temp out/_kie/ |
feedback/ |
loom-b2…b9.{mp4,txt} (run 1), loom-s1…s4.{mp4,txt} (Sam). Transcribe new Looms with mr-transcribe <file> --lang en (OpenAI API, never local whisper). |
batch-01/ … batch-09/ |
run-1 ateliers: bNspecs.py, bNrun.py/run.sh, build_bN.py (page), meta.json, prompts/, logs/. batch-01/families.json (9 concept families), numbers.json (#N → template id), json/ (B1 JSON blueprints), overrides.py (R9 headlines). |
run1-final/ |
the 79 final run-1 PNGs Wildhorn_01..79.png |
stats.py / stats_run1.json |
run-1 hit-rate stats (⚠ ignores batch-09: no meta.json) |
build_lessons.py |
rebuilds https://blueprint.machineroom.app/lessons from LESSONS.md |
build_all.py |
rebuilds https://blueprint.machineroom.app/all-ads (run 1 + Sam = 162) |
templates/ |
Adrien's TEMPLATE WINNER library by family (BEFORE AND AFTER, BOLD CLAIM, Feature benefit, MEME, NEGATIE HOOK, PROBLEME SOLUTION, US VS THEM, offer:sales, statistic) |
concepts/ |
early remix concepts (t100, t144…) |
gallery.py |
rebuilds https://wildhorn-lp.machineroom.app/remix (raw remix gallery) |
/root/workspace/wh-remix/sam-batch/ (the current pipeline)| Path | What it is |
|---|---|
templates/ |
the 83 Sam templates (MM-DD_cNNNN_Brand.ext). S-number = position in sorted(os.listdir(templates)). |
s1specs.py |
round 1 specs S1–S10 (+ shared strings ORGANS, CAPS) |
s2specs.py |
round 2: redos S2 S7 S8 S9 + new S11–S40 |
s3specs.py |
round 3: redos S8 S11 S14 S15 S17 S18 S24 S29 S33 S35 + new S41–S83 |
s3fixspecs.py |
QC round 3: Seedream scene + composite for S55 S58 S74 S79 |
s4specs.py |
Loom-3 redos S11 S18 S29 S42 S50 S52 S56 S57 S74 S80 (helper ad(), OLD avatar string, HORN suffix) |
srun.py |
the pipeline: python3 srun.py SPECFILE NUM → lint (blocking) → engine chain → composite → out/s_NN_vK.png; logs calls.jsonl |
calls.jsonl |
one line per generation call {num, engine, ok, ts} (133 lines) |
prompts/ |
the exact prompt sent per ad (s_NN.txt, s_NN_sd.txt, s_NN_comp*.json, s_NN_bg.png) |
logs/ |
r1_N.log, r2_N.log, fix3_s_NN.log… + done flags _r2done, _r3done |
jobs2.txt, jobs3.txt, round2_list.txt, round3_list.txt |
the S-numbers / templates of each round |
validated.json |
Adrien's verdict per S-number: "✅ Validated (first try)", "✅ Validated (redo)", "✅ Loom 4 (after fix)"… (❌ … / ⏳ when pending) |
sell_override.json |
which try is the SELL version when it isn't the last: {"9":1,"58":1,"79":1,"35":2,"42":1} (A20/A26) |
sell/ |
Wildhorn_SNN.png = sell version of every ad |
validated/ |
Wildhorn_01..83.png = validated sell versions in S order |
build_sam.py |
review page https://blueprint.machineroom.app/sam (hides ✅ ads) |
build_samfinal.py |
https://blueprint.machineroom.app/sam-final (every try + SELL VERSION + stats) and refreshes sell/ |
build_validated.py |
validated/ + https://blueprint.machineroom.app/wildhorn-ads (images only, no text) |
proto_sam2.py |
inserts a feedback-loop section into /srv/blueprint/protocols.html (pattern to copy for each new Loom) |
| URL | Content | Built by |
|---|---|---|
| https://blueprint.machineroom.app/ | the generic AI Blueprint (steps 0–5, rules R1–R14) | hand-edited /srv/blueprint/index.html |
| https://blueprint.machineroom.app/example | Module 2 — the Wildhorn × Primal Edge worked example, 79 run-1 pairs | batch-01/build_pages.py |
| https://blueprint.machineroom.app/before-after | run 1 numbered #1–#79 (anchors #adN) |
batch-01 builder |
| https://blueprint.machineroom.app/batch-02 … /batch-09 | run-1 review pages per round | batch-0N/build_bN.py |
| https://blueprint.machineroom.app/lessons | LESSONS.md as a page | build_lessons.py |
| https://blueprint.machineroom.app/protocols | Protocol 0 (Template DNA), golden rules, copy rules, prompt structure, QC checklist, every feedback loop | edited per round (proto_*.py) |
| https://blueprint.machineroom.app/sam | Sam batch review page (only ads still to review) | sam-batch/build_sam.py |
| https://blueprint.machineroom.app/sam-final | Sam batch: every try + SELL VERSION + hit rate | sam-batch/build_samfinal.py |
| https://blueprint.machineroom.app/wildhorn-ads | 83 validated Sam ads, images only | sam-batch/build_validated.py |
| https://blueprint.machineroom.app/all-ads | 162 ads: Batch 1 (79) + Batch 2 (83) | build_all.py |
| https://blueprint.machineroom.app/skill.md | the generic ad-blueprint skill incl. Section 18 Template Clone Protocol | /srv/blueprint/skill.md |
| https://wildhorn-lp.machineroom.app/remix | raw remix gallery (concept + outputs + prompt) | gallery.py |
| https://wildhorn-lp.machineroom.app/ads-demo/ | run-1 demo (images only) | batch-01 builder |
| https://intel.machineroom.app/en/primaledge | Primal Edge ad-library study (angles, mechanisms, LPs) | /root/workspace/competitors/adlib/site/ |
Static root: /srv/blueprint/ (ex/ = full-size tries, ex/web/ = webp thumbs, all-ads/b1 b2, wildhorn-ads/).
~/Downloads/)| Folder | Content |
|---|---|
~/Downloads/Wildhorn-Final-Ads/ |
run 1 — 79 finals Wildhorn_01..79.png |
~/Downloads/Wildhorn-Sam-Batch/ |
Sam — 83 sell versions Wildhorn_S01..S83.png |
~/Downloads/Wildhorn-Validated/ |
Sam — 83 validated Wildhorn_01..83.png |
~/Downloads/Sam-static-concepts-14-18-Sept/ (+ .zip) |
the 83 Sam templates as Adrien sent them |
Export commands (run on the Mac — the only thing allowed locally):
rsync -a vps-claude:/root/workspace/wh-remix/sam-batch/sell/ ~/Downloads/Wildhorn-Sam-Batch/
rsync -a vps-claude:/root/workspace/wh-remix/sam-batch/validated/ ~/Downloads/Wildhorn-Validated/
rsync -a vps-claude:/root/workspace/wh-remix/run1-final/ ~/Downloads/Wildhorn-Final-Ads/
For a new batch, create a new folder (e.g. ~/Downloads/Wildhorn-Batch-3/), never overwrite the previous exports.
Templates from the Mac to the VPS (Adrien drops them in iCloud BUSINESS/WILDHORN CONCEPTS/, a zip in Downloads, or the TEMPLATE WINNER folder ~/Library/Mobile Documents/com~apple~CloudDocs/BUSINESS/E-COMMERCE/- ADS ECOM/TEMPLATE WINNER/):
scp -r "<local folder>"/* vps-claude:/root/workspace/wh-remix/<new-batch>/templates/
~/.claude/bin/checkpoint wildhorn-batch-test (stored on the VPS in /root/workspace/_checkpoints/). Write: ~/.claude/bin/checkpoint wildhorn-batch-test --write (stdin).wildhorn-remix-system.md, creas-gpt-image-2.md, clone-winner-system.md, english-deliverables.md, wildhorn-lp-compliance.md (project memory folder of the Mybusiness project)./root/claude-vault/knowledge/copywriting/TEMPLATE-CLONE-LESSONS.md./root/claude-vault/knowledge/product-research/primal-bison/etude-marche-primal-edge.md, structured /srv/intel/data/primaledge.json./srv/wildhorn-lp/product-v6-monument.html.ssh vps-claude 'cd /root/workspace/wh-remix && python3 lint.py sam-batch/s5specs.py'
ssh vps-claude 'cd /root/workspace/wh-remix/sam-batch && python3 - <<EOF
import importlib.util, os
T = sorted(os.listdir("templates"))
sp = importlib.util.spec_from_file_location("m", "s5specs.py"); m = importlib.util.module_from_spec(sp); sp.loader.exec_module(m)
for s in m.S:
if not s.get("tpl_abs") and s["tpl"] != T[s["num"]-1]: print("MISMATCH", s["num"], s["tpl"], "->", T[s["num"]-1])
print("checked", len(m.S))
EOF'
ssh vps-claude 'cd /root/workspace/wh-remix/sam-batch && python3 srun.py s5specs.py 84'
Output: #84: openai OK (or REFUSED -> seedream_comp then seedream+comp OK). D10: OK only if a new out/s_84_vK.png exists.
ssh vps-claude 'cd /root/workspace/wh-remix/sam-batch && echo "84 85 86 87 88 89 90 91 92 93" | tr " " "\n" > jobs5.txt && \
nohup sh -c "cat jobs5.txt | xargs -P 5 -I{} sh -c \"python3 srun.py s5specs.py {} > logs/r5_{}.log 2>&1\"; touch logs/_r5done" >/dev/null 2>&1 &'
Check: ssh vps-claude 'ls /root/workspace/wh-remix/sam-batch/logs/_r5done; tail -n1 /root/workspace/wh-remix/sam-batch/logs/r5_*.log'. ~110 s per gpt-image-2 image.
# spec has engine="seedream_comp" (or fallback="seedream_comp"), sd_prompt (scene only: no text, no product, empty zones), composite {...}
python3 srun.py s5specs.py 88
# by hand:
python3 ../kie_gen.py s_88_sd --prompt prompts/s_88_sd.txt --product templates/<tpl> --model seedream [--aspect portrait_16_9]
python3 ../composite.py ../out/s_88_sd_v1.png ../out/s_88_v2.png prompts/s_88_comp.json
python3 ../kie_gen.py s_88_nano --prompt prompts/s_88_nano.txt --product ../product-jar.jpg --concept templates/<tpl> --model nano
# 1) Seedream edits the template itself: age the man, clear the text, nothing else (keep aspect)
python3 ../kie_gen.py s_11_sd --prompt prompts/s_11_sd7.txt --product templates/09-14_c0025_Primal-Viking.png --model seedream --aspect portrait_16_9
# 2) swap only their jar for ours inside a box (pixels of the base image)
python3 ../jarswap.py ../out/s_11_sd_v6.png prompts/s_11_jar.png X0 Y0 X1 Y1
# 3) exact text by script
python3 ../composite.py prompts/s_11_jar.png ../out/s_11_v5.png prompts/s_11_comp5.json
Spec with tpl_abs=O + "s_29_v2.png" (O = /root/workspace/wh-remix/out/) → Image 2 = our own try.
ssh vps-claude 'cd /root/workspace/wh-remix/sam-batch && python3 - <<EOF
import json
v = json.load(open("validated.json"))
v.update({"84": "✅ Validated (first try)", "85": "❌ Loom 6: off-angle (A24)"})
json.dump(v, open("validated.json", "w"), ensure_ascii=False, indent=1)
so = json.load(open("sell_override.json")); so.update({"86": 1}); json.dump(so, open("sell_override.json", "w"))
EOF'
ssh vps-claude 'cd /root/workspace/wh-remix && python3 sam-batch/build_sam.py && python3 sam-batch/build_samfinal.py && python3 sam-batch/build_validated.py && python3 build_all.py && python3 build_lessons.py'
rsync -a vps-claude:/root/workspace/wh-remix/sam-batch/sell/ ~/Downloads/Wildhorn-Sam-Batch/
(For a new batch folder, copy the builders and change their paths/titles; keep SKIP_VALIDATED on the review page.)
ssh vps-claude 'cd /root/workspace/wh-remix/feedback && mr-transcribe loom-s5.mp4 --lang en'
(download the Loom mp4 to that folder first; API transcription only.)
ssh vps-claude 'cd /root/workspace/wh-remix/sam-batch && python3 -c "
import json; v=json.load(open(\"validated.json\")); c=[json.loads(l) for l in open(\"calls.jsonl\")]
ft=sum(\"first try\" in x for x in v.values()); ok=sum(x.startswith(\"✅\") for x in v.values())
print(f\"first try {ft}/{len(v)} = {100*ft/len(v):.1f}% validated {ok}/{len(v)} calls {len(c)} per validated {len(c)/max(ok,1):.2f}\")"'
| Run 1 (79 templates) | Sam batch (83 templates) | |
|---|---|---|
| Generations | 258 + 3 refused = 261 | 133 calls (125 ok, 8 refused/failed) |
| Generations per validated ad | 3.3 | 1.6 |
| Validated first try | 0 / 79 = 0 % | 59 / 83 = 71.1 % |
| After one fix | — | ≈ 87 % |
| Final | 79 / 79 after 9 rounds | 83 / 83 after 4 Looms (+ S11 in Loom 5) |
| Hit rate (validated ÷ generations) | 30.3 % | ≈ 62 % |
| Total validated | 162 ads on https://blueprint.machineroom.app/all-ads |