Weekly ecosystem blog worker: collect sources, generate via Replicate, editor passes #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Build a scheduled worker that produces a weekly CL8Y ecosystem blog draft: collect primary sources, pick a style and topic that is consistent with recent posts but not repetitive, outline, generate the article via the Replicate API, then run structured editor passes before emitting an MDX draft that matches the existing
CL8Y-webblog contract.This issue covers repo placement, source collection, generation + editor pipeline, and how a draft becomes a post on cl8y.com. It does not auto-publish to production.
Related: homepage positioning remains CL8Y-web#1. Token addresses / listings / venues remain CL8Y-web#2. Do not remount
RETIRED_HOMEPAGE_MODULES. Do not rewriteCL8Y_WHITEPAPER.md.Current codebase
CL8Y-webis a single-package static Vite + React 19 SPA. There is no Yarn/pnpm workspace, no worker process, no scheduler, and no server-side runtime in production. The site prerenders/,/blog, and/blog/:slug, then writesdist/rss.xml.Blog publish contract (already shipped):
src/blog/posts/*.mdx.title,description,slug,date,author,image,tags.wordCountis computed at build time, not authored.vite.config.ts(blogPostMetaVirtualModule,getBlogPrerenderRoutes) indexes frontmatter and prerender routes.src/blog/blogIndex.tsloadsimport.meta.glob("./posts/*.mdx")+virtual:blog-post-meta./blog(BlogListPage.tsx),/blog/:slug(BlogPostPage.tsx+ArticleLayout.tsx+SEO.tsx)./blog(src/data/copy.tsheader.blog).scripts/generate-rss.mjs(also served in Vite viarssDevPlugin).public/images/blog/only. Do not put published rasters insrc/blog/assets.Existing generation helper is image-only:
blog_gen/generate_image.pycalls Replicateopenai/gpt-image-2.predictions.createper command. Never wrap create in a retry loop (proxy disconnects after Replicate accepts the job, which duplicates spend). Short create wait, then poll the same prediction id.--submit-only/--fetchfor recovery.blog_gen/SKILL.mdis the voice, rhythm, AI-tell, and art-direction source for human/agent drafts. Target 2000–2500 words for a full post.blog_gen/.env.exampleonly documentsREPLICATE_API_TOKENplus optional poll/wait knobs.Today there is one post:
src/blog/posts/cl8y-roadmap-cmm-bridge-yieldomega.mdx(2026-05-10). Topic selection has nothing recent to diversify against except that one long roadmap piece.Ecosystem sources the site already cites, but never ingests:
blog_gen/SKILL.md)PlasticDigits/yieldomega,PlasticDigits/cl8y-bridge-monorepo,PlasticDigits/cl8y-dex-terraclassic,PlasticDigits/ustr-cmmhttps://bridge.cl8y.com, DEXhttps://dex.cl8y.com, YieldOmega,ust1cmm.comhttps://t.me/ceramicliberty(src/data/links.ts).https://t.me/plasticannis not referenced in this repo.useCl8yPrice, etc.) are homepage-only and out of scope for blog generation.Positioning split:
src/content/invariants.tsBANNED_CURRENT_COPYandCURRENT_PRODUCT_SURFACESapply to the homepage / chrome / share cards, not to long-form blog. The existing roadmap post legitimately discusses USTR / UST1 / CMM / YieldOmega. Weekly posts may cover those products when the sources support it, but they must not rewrite homepage IA or reintroduce banned current-product marketing copy on/.Why this is needed
The blog is a real visitor surface (
/blog, RSS, OG tags) but it is still a manual, one-off pipeline. There is no weekly ecosystem recap, no ingest of repo activity or dapp stats, and no reuse of Telegram conversation context.blog_gencan make a hero image. It cannot choose a non-boring topic, write the article, or run editor passes.A worker is needed so a weekly draft can:
Without it, posts stay rare, thin, or generic, and any future automation would be bolted onto a static marketing SPA that should not hold Telegram sessions or long-lived API secrets.
Constraints / guardrails
CL8Y-webis a static marketing site. A scheduled worker with Telegram auth, indexer tokens, and Replicate spend does not belong in the Vite app runtime. Prefer a new repo (for examplecl8y-blog-worker) that emits drafts. Keepblog_gen/SKILL.mdandblog_gen/generate_image.pyas the canonical voice + image contract consumed by the worker. Only put a thin publish helper in this repo if a draft-to-MDX check is required. A monorepo is acceptable only if it stays a sibling package that this SPA never imports at build time.CL8Y-web. No direct push tomain, no deploy webhook that skips review.RETIRED_HOMEPAGE_MODULES. Do not change homepage copy,#tokenplaceholder (CL8Y-web#2), orCL8Y_WHITEPAPER.md.blog_gen/SKILL.md. Positive, professional, technically minded. 2000–2500 words unless the week is a short announcement (document that exception in the run log). Natural paragraphs, lists sparingly, vary sentence length by paragraph.onchain,cross chain); straight quotes only; no stacked headings with empty prose; no fake one-sentence paragraphs unless a deliberate beat.https://t.me/plasticannandhttps://t.me/ceramicliberty. Do not scrape public web previews, do not store full room history longer than the retention window, do not quote private DMs, and do not publish usernames or message text that can identify a non-team speaker without consent. Treat chat as theme and sentiment signals, not as citable onchain facts.dex.cl8y.com/bridge.cl8y.com. Time-bound every stat (as of <ISO timestamp>).predictions.createper generation step (or per image). Never retrycreate. Poll the returned prediction id. Cap weekly budget. Fail the run rather than loop. Reuse the create/poll pattern fromblog_gen/generate_image.py.REPLICATE_API_TOKEN, Telegram credentials, GitHub/GitLab tokens, indexer keys live in the worker host env / secret manager. Never commit.env. Never echo secrets into MDX, logs, or MR descriptions.<script>,javascript:URLs, or imported runtime components. Frontmatter strings are escaped. Slug is[a-z0-9-]+and unique.public/images/blog/<slug>-hero.jpg(or a staging folder the publish MR copies there). Frontmatterimageis that public path. Follow existing Replicate image rules inblog_gen/SKILL.md.Relevant files
blog_gen/SKILL.md,blog_gen/generate_image.py,blog_gen/.env.example,blog_gen/requirements.txtsrc/blog/posts/*.mdx,src/blog/blogIndex.ts,src/blog/BlogPostPage.tsx,src/blog/BlogListPage.tsx,src/blog/ArticleLayout.tsx,src/blog/SEO.tsxvite.config.ts,scripts/generate-rss.mjs,scripts/verify-prerender-meta.mjssrc/app/index.tsx,src/components/chrome/SiteHeader.tsx,src/components/chrome/SiteFooter.tsx,src/data/copy.ts,src/data/links.ts,src/lib/siteUrls.tssrc/content/invariants.ts,skills/cl8y-site-positioning/SKILL.md,STYLE_GUIDE.md,PROJECT_GUIDE.mdSource allowlist to encode in config (not hardcoded in prompts):
yieldomega,cl8y-bridge-monorepo,cl8y-dex-terraclassic,ustr-cmm, plus other official CL8Y remotes added by review.https://t.me/plasticann,https://t.me/ceramiclibertyonly.Recommended direction
1. New worker repo (default)
Create
cl8y-blog-worker(name flexible) with a weekly CLI, for exampleyarn generate --week 2026-W35orpython -m worker run --week …. Persist a run directory:If a monorepo is strongly preferred, the same layout lives in a sibling package that
CL8Y-webdoes not import.2. Collect (deterministic, testable)
repo,sha/iid,url,summary.src/blog/posts/*.mdx(clone or path config) for title, description, tags, first/last 200 words, heading outline. This is the anti-boredom input.A source failure (indexer 5xx, Telegram outage) degrades: the week still runs on remaining sources, and
report.mdlists gaps. Do not hallucinate the missing feed.3. Plan (style + topic)
After sources + recent posts, call Replicate once to propose 3 candidate
{style, topic, hook}objects, then pick one with a deterministic ranker:Write the winner and the rejected candidates into
plan.jsonso review can see why.4. Outline, then generate
plan.json+sources.jsononly. Every H2 must map to at least one citation or be marked “commentary.”5. Editor passes (separate, ordered, one create each)
Run after the draft, in this order, each with a focused rubric and a fail-closed lint where possible:
PRODUCT_URLS/siteUrls.ts).blog_gen/SKILL.md).sources.json.A mechanical lint (no model) must fail the run if the final MDX still contains
—, curly quotes, or banned homepage current-copy phrases used as current marketing (Buy CL8Y,the future of DeFi, etc.). Ecosystem history (USTR/CMM) is allowed when sourced.6. Emit + optional image + draft MR
blogIndex.tsfrontmatter.blog_gen/generate_image.pyonce for the hero.CL8Y-web(or attach files for a human to copy). CI on this repo remainsyarn test && yarn typecheck && yarn lint && yarn build.Acceptance criteria
plan.json,outline.md,post.mdx, editor-pass artifacts, andreport.md.t.me/plasticann, andt.me/ceramicliberty, with graceful degradation when a source is down.src/blog/postsand rejects near-duplicate titles, tags, and openings.predictions.createwith poll-by-id. No create retry loop.wordCountauthoring).CL8Y-web.src/blog/posts/andpublic/images/blog/such thatyarn buildprerenders/blog/<slug>and RSS includes the item.Test plan — functional paths
Happy path (fixtures)
post.mdxfrontmatter, unique slug, and that every numeric claim appears insources.json.Recent-post diversity
recent_posts.jsonwith last week = “bridge volume recap” / same opening sentence.Source gaps
report.mdlists the gap; no invented volume.Telegram redaction
Editor lint
—, “This is not X. It is Y.”, curly quotes, andBuy CL8Yas a CTA fails the mechanical pass.MDX contract
post.mdx+ hero into a throwawayCL8Y-webcheckout.yarn typecheck,yarn lint,yarn test,yarn build./blog/<slug>prerendered;dist/rss.xmlcontains title, description,/blog/<slug>.Slug collision
cl8y-roadmap-cmm-bridge-yieldomega→ worker suffixes or fails; never overwrite an existing post.Image path
imageis/images/blog/<slug>-hero.jpg(or documented equivalent). No file undersrc/blog/assets.Budget / create-once
--fetchequivalent).Scheduler dry-run
--dry-run(collect + plan only).Short-announcement exception
Test plan — attack, hack, and abuse vectors
The worker reads untrusted text (Telegram, READMEs, issue titles) and then asks a model to write visitor-facing HTML/MDX. Review as if an attacker wants prompt injection, secret leak, phishing, or unbounded Replicate spend.
Prompt injection via Telegram / README
<script>/javascript:survives emit, and product hrefs are allowlisted (bridge.cl8y.com,dex.cl8y.com, documented repos). Unknown hosts are stripped or the run fails.Phishing / address substitution
#token/ the directory issue rather than embedding addresses.Homograph / open redirect links
cl8y.com.attacker.tld, punycode lookalikes, and?url=redirectors. External links in the post must be https and on an allowlist, or converted to plain text.XSS / MDX component smuggling
importof a React component,{<img onError=…>}, and HTML event handlers. Emitter allows only safe Markdown. Build-time MDX compile of the fixture must not introduce a new runtime import.Secret exfiltration
REPLICATE_,BOT_TOKEN,api_key,BEGIN. Fail if present.Replicate cost amplification
Indexer / SSRF
http://169.254.169.254/or an internal hostname is rejected. No user-controlled URL fetch.Repo supply chain
SEO / spam abuse
Defamation / unauthorized quotes
Legal / financial advice
Clickjacking / chrome regression
render.yamlor homepage modules. If a publish MR touches onlysrc/blog/posts+public/images/blog, say so in the MR template.Auth to Telegram
Draft MR hijack
CL8Y-webMR is contents:write on a feature branch only, notmain, not repo admin.Verification criteria
Done when a reviewer can:
CL8Y-webstays a static SPA.plan.json→ outline → passes →post.mdx+report.md.post.mdxis insources.jsonwith a timestamped citation.CL8Y-web, runyarn test && yarn typecheck && yarn lint && yarn build, and load/blog/<slug>plusrss.xml.CL8Y-webmain.Out of scope
CL8Y_WHITEPAPER.md.Also need vector search so agents can find information
moved from CL8Y-web#4
Moved from CL8Y-web#4.
Implementation notes for this ticket:
blog_gen/SKILL.mdandblog_gen/generate_image.py.mentioned in commit
0a47ac42c2mentioned in merge request !13
mentioned in commit CL8Y-web@cb19bd4eb3c5101466d58ba63a7aa608d9a64d05
mentioned in merge request CL8Y-web!16
Implementation MR: https://gitlab.com/PlasticDigits/cl8y-research/-/merge_requests/1
Stack is Rust + Postgres (pgvector). Fixture
cargo testandcl8y-research weekrun without live tokens. Vector search iscl8y-research search. CL8Y-web pointer: https://gitlab.com/PlasticDigits/CL8Y-web/-/merge_requests/4mentioned in commit
5175e9eacamentioned in issue #2
mentioned in issue #3
mentioned in issue #6
mentioned in issue CL8Y-web#7