From structured rows to polished articles — automatically
Open-source article publishing pipeline for Framer CMS, GitHub, and Markdown
Turn structured rows from CSV, NocoDB, Google Sheets, or JSON into validated articles — published to Framer CMS, GitHub, or Markdown without manual copy-paste.
Framer CMS publishing automation
Built for Framer CMS publishing
Publish straight to Framer CMS over Framer's server-side API — structured rows in, published collection items out.
-
Server-side
Bearer-token calls to
api.framer.comfrom your own environment. -
Structured fields
Title, slug, description, and body map to the Framer fields you configure.
-
Repeatable
Every row runs the same generate → validate → publish path.
# each H2 → its own field POST /…/collections/{id}/items { "fieldData": { "title": "Framer vs Webflow", "slug": "framer-vs-webflow", "howItWorks": "## How it works …", "faq": "## FAQ …" } }
# whole article → one rich-text field POST /…/collections/{id}/items { "fieldData": { "title": "Framer vs Webflow", "slug": "framer-vs-webflow", "content": "## How it works …\n## FAQ …" } }
disabled by default · dry-run preview · creates published entries
New to the Framer API? Read the official Framer developers documentation for how server-side CMS access works. PublishRail is an independent open-source project and is not affiliated with or endorsed by Framer.
How it works
How PublishRail works
One configurable workflow — five stages, run identically for every row.
-
Source
Point the pipeline at a structured source. Each row becomes one article run.
csvjsonnocodbsheets -
Context
Positioning, messaging, and glossary files are injected into every prompt — not just the row.
positioningmessagingglossary -
Generate
A configurable AI provider writes the draft. Anthropic or any OpenAI-compatible endpoint.
AnthropicOpenAIlocal -
Validate
Deterministic checks then an optional AI judge. Below-threshold drafts are rewritten automatically.
validatorsAI judgerewrite -
Publish
Markdown, a GitHub folder, or a Framer CMS collection — single-body or section-mapped.
MarkdownGitHubFramer
Section-mapped publishing
How Framer CMS section mapping works
Framer CMS section mapping lets PublishRail send individual sections of a generated article into predefined Framer CMS fields. Instead of placing an entire article in one rich-text field, the pipeline can map sections such as “How it works,” “Pricing comparison,” or “FAQ” into structured CMS fields automatically, based on the article's H2 (##) headings.
You define the heading-to-field mapping in your project config. The pipeline extracts each H2 section from the generated article and sends it to the corresponding Framer CMS field. Headings can be matched exactly or normalized, and unmapped sections can be ignored, warned on, appended to the body, or treated as an error.
Sources and publishing targets
One source-to-publish workflow
PublishRail reads from structured sources and publishes to file- and CMS-based destinations. Switch either end in your project config without rewriting the pipeline.
Publish from structured sources
Each row becomes one article run.
- CSV
- NocoDB
- Google Sheets
- JSON
Publish to your destination
Choose one or several targets per run.
- Framer CMS
- GitHub
- Markdown
Validation
Validate before you publish
Deterministic checks, an optional AI judge, and dry-run previews — issues are caught in the pipeline, not your live CMS.
Deterministic checks
Fast, rule-based validators run without extra AI calls. They check article structure and formatting and flag issues by severity.
- At least three H2 sections; no empty or duplicate headings
- FAQ formatting and heading levels
- Word-count range and overlong inline bold
- Escaped-quote cleanup and banned “AI-tell” vocabulary
- FAQ content aligned with its JSON-LD
AI judge & rewrite
When enabled, an AI judge scores the draft against your evaluation criteria and returns a decision.
- Per-dimension scoring against your rubric
- Automatic rewrite when a draft is below threshold
- Re-evaluation after the rewrite
- Configurable models and maximum rewrite count
Dry-run preview
The GitHub and Framer publishers default to dry run, so you preview before anything is sent.
- See the exact payload that would be published
- Framer dry run lists each mapped section and its size
- Missing or unmapped headings are reported
- Live publishing is an explicit, deliberate step
Validation helps teams catch issues early. It does not guarantee accuracy — review remains part of the workflow.
Who it's for
Who PublishRail is for
PublishRail is for teams that publish many structured articles and need a reliable workflow from source data to a live CMS entry. It is especially useful for Framer teams, content operations teams, agencies, product marketers, developer-led marketing teams, and technical teams that manage editorial production through spreadsheets, databases, GitHub, or AI models.
Framer teams
Publish structured entries straight into Framer CMS collections, including section-mapped fields.
Content ops & agencies
Run separate configurations per project or client, each with its own context, prompts, source, and target.
Developer-led marketing
Keep content in Git or a database and publish to Markdown or GitHub folders from the same run.
Open source & self-hosted
Self-hosted. MIT licensed. Bring your own keys.
PublishRail runs entirely on your own machine or server. Your content, context, API keys, and tokens stay in your environment — nothing is sent anywhere except the AI provider and publishing targets you configure.
The publisher architecture is extensible: implement the interface to add your own output target without modifying core pipeline code.
- MIT licensed — use it, fork it, modify it
- Self-hosted Node.js app with an optional local web UI
- API keys and tokens stay in your own
.env - Model flexibility — Anthropic or any OpenAI-compatible provider
- Dry-run mode for the GitHub and Framer publishers
# AI provider — anthropic | openai (OpenAI-compatible) AI_PROVIDER=anthropic AI_MODEL=claude-opus-4-8 AI_API_KEY=your_api_key_here # Source (set the type in your project config) NOCODB_BASE_URL=https://nocodb.example.com NOCODB_API_TOKEN=your_token_here # GitHub publisher (optional, disabled by default) GITHUB_TOKEN=your_github_token_here GITHUB_OWNER=your-org GITHUB_REPO=your-repo # Framer publisher (optional, disabled by default) FRAMER_TOKEN=your_framer_token_here FRAMER_COLLECTION_ID=collection_id_here
FAQ
Frequently asked questions
Can PublishRail publish directly to Framer CMS?
Yes. PublishRail publishes directly to a Framer CMS collection using Framer's server-side HTTP API. Add a Framer API token and collection ID, enable the Framer target in your project config, and each generated article becomes a new published item in your collection. Framer publishing is disabled by default, and you can run it in dry-run mode first to preview the exact payload before anything is sent.
Does PublishRail use the Framer Server API?
Yes. PublishRail calls Framer's server-side API at api.framer.com, authenticating with a bearer token you store in your own environment. Because the requests happen server-side, the pipeline can create CMS items programmatically without opening the Framer editor for each article. You supply the API token and collection ID, and PublishRail sends structured field data for every row it processes.
How does PublishRail map article sections to Framer CMS fields?
In section-mapped mode, PublishRail splits a generated article by its H2 (##) headings and sends each section to a specific Framer CMS field you define. You configure a mapping of heading text to field name in your project config — for example, “FAQ” to a faq field. Headings can be matched exactly or normalized, and unmapped sections can be ignored, warned on, appended to the body, or treated as an error.
Can PublishRail publish content from Google Sheets or NocoDB to Framer?
Yes. PublishRail reads structured rows from Google Sheets, NocoDB, CSV, or JSON, and any of those sources can feed the Framer CMS target. You set the source type in your project config; the rest of the pipeline — generation, validation, and publishing — stays the same. A row in a NocoDB table or a Google Sheet can become a published Framer CMS item in a single run.
Can PublishRail publish articles to GitHub as Markdown?
Yes. The GitHub target commits each article as a Markdown file into a folder of a repository you choose, using the GitHub Contents API — no local git checkout required. You configure the owner, repository, branch, and folder, and the commit message is templated per article. Like the other publishers, it supports dry-run mode so you can preview commits before they are created.
Is PublishRail self-hosted?
Yes. PublishRail is self-hosted and runs entirely on your own machine or server. It is a Node.js application you clone and run yourself, with an optional local web UI for managing runs and editing prompts. Your API keys and tokens live in your local environment, and nothing is sent anywhere except the AI provider and publishing targets you explicitly configure.
Does PublishRail support dry runs before publishing?
Yes, for the GitHub and Framer targets. Dry-run mode builds the full payload and prints exactly what would be published — for Framer, that includes each mapped section, its character count, and any missing or unmapped headings — without calling the remote API. Dry run is the default for these publishers, so live publishing is something you opt into deliberately rather than by accident.
What does PublishRail validate before publishing an article?
PublishRail runs deterministic local checks plus an optional AI judge. Local validators cover article structure (a minimum number of H2 sections, no empty or duplicate headings), FAQ formatting, word count, escaped-quote cleanup, banned “AI-tell” vocabulary, and alignment between FAQ content and its JSON-LD. The AI judge then scores the draft against your criteria and can trigger an automatic rewrite, helping teams catch issues before content reaches Framer CMS, GitHub, or Markdown.