A source-agnostic article publishing pipeline for Framer, GitHub, and modern CMS workflows. Open source, self-hosted, MIT licensed.
Each step is configurable. You control the source, the prompt, the model, and the destination.
Point the pipeline at any structured data source. Each row becomes one article run — no scripting required.
Drop in a positioning document, messaging guide, product glossary, or evaluation rubric. Every prompt gets the full context — not just the row.
Set your provider and API key in .env. Switch between Anthropic, OpenAI-compatible endpoints, OpenRouter, or any local model without touching the pipeline logic.
The pipeline writes the article, then runs it through local validators and an AI judge. If quality thresholds aren't met, it rewrites automatically before moving on.
Output to local Markdown files, commit directly to a GitHub repository folder, or push to a Framer CMS collection — including section-mapped mode for structured field mapping.
Most teams hit the same three walls once they try to publish more than a handful of articles.
AI_PROVIDER in your .env. Swap providers without touching the pipeline. Works with any OpenAI-compatible endpoint..env file. No data leaves your environment.Three built-in publishers, each configurable via your project config. Add your own by implementing the publisher interface.
Generate clean .md files with YAML frontmatter. Works with Astro, Hugo, Jekyll, Eleventy, or any file-based CMS.
Commit articles directly to a folder in any GitHub repository using the Contents API. No local git checkout required.
Push structured article data directly to a Framer CMS collection. Supports single-body entries or section-mapped fields.
Section-mapped mode lets each H2 heading in your article target a specific Framer CMS field — no copy/paste required.
Configure the section-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.
No lock-in. Set your provider in AI_PROVIDER and swap models at any time.
Claude models via the Anthropic API. Configurable model name and max tokens.
Any provider that implements the OpenAI chat completions API. Set AI_BASE_URL to point anywhere.
Access dozens of models through a single API key. Model selection stays in config.
Point AI_BASE_URL at Ollama, LM Studio, or any local OpenAI-compatible server.
Any time a row in a spreadsheet or database should become a published article, the pipeline fits.
Maintain a spreadsheet of product pairs. The pipeline turns each row into a structured comparison article published directly to your site or CMS.
Define topics in a CSV or NocoDB table. Generate, validate, and publish a full editorial article for each one in a single pipeline run.
Turn a data sheet of keywords, use cases, or segments into complete landing page copy published as Markdown or Framer CMS entries.
Keep content in Google Sheets or NocoDB, then publish structured entries directly to Framer collections — including section-mapped field output.
Commit Markdown articles directly into a content folder in your GitHub repository. Trigger deployments from the same pipeline run.
Run pipelines per client with separate context files, prompt templates, and publish targets. Repeatability at the account level, not just the article level.
PublishRail runs entirely on your machine. Your content, your context, and your API keys never leave your environment.
The publisher architecture is extensible — implement the interface and add your own output target without modifying core pipeline code.
.env.example included — no guessing which keys are needed
localhost:3737
# Source SOURCE_TYPE=csv CSV_PATH=./inputs/articles.csv # AI provider AI_PROVIDER=anthropic AI_MODEL=claude-opus-4-5 AI_API_KEY=your_api_key_here # Publisher PUBLISHER=markdown OUTPUT_DIR=./outputs # GitHub publisher (optional) GITHUB_TOKEN=your_github_token_here GITHUB_REPO=your-org/your-repo GITHUB_CONTENT_PATH=content/articles # Framer publisher (optional) FRAMER_API_KEY=your_framer_key_here FRAMER_COLLECTION_ID=collection_id_here FRAMER_MODE=section-mapped
SOURCE_TYPE in your .env to switch between them.PUBLISHER=framer and configure your Framer API key and collection ID. Supports both single-body mode (full article as one field) and section-mapped mode (each H2 section maps to a separate CMS field).FRAMER_MODE=section-mapped and 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 field.AI_PROVIDER=openai-compatible and point AI_BASE_URL at any local OpenAI-compatible server — Ollama, LM Studio, or similar. The pipeline doesn't care where the completions come from..env file and never leave your machine. The pipeline reads them at runtime. Nothing is sent to any external service other than the AI provider you configure.