A framework-neutral, draft-first TypeScript toolkit for building auditable SEO content workflows.
seo-auto separates reusable content orchestration from domain prompts, search-engine integrations, CMS APIs, and production credentials. It gives you a small core for selecting briefs, generating structured drafts, applying deterministic gates, optionally running a second quality review, checking rendered HTML, building JSON-LD, and calculating search metrics.
Status: early public foundation. The API is intentionally small and may change before
1.0.0.
Most content automation projects mix five different concerns in one route or script:
- domain research and editorial rules;
- LLM and image providers;
- content quality gates;
- CMS storage and publishing;
- technical SEO and performance measurement.
That makes the workflow hard to test, reuse, and review. seo-auto keeps the reusable decisions in pure TypeScript and pushes provider-specific behavior behind interfaces.
- Draft-first pipeline — topic context, generation, deterministic audit, optional quality review, and draft storage.
- Configurable content profiles — lengths, required sections, forbidden claims, source counts, internal links, FAQs, and review thresholds.
- Duplicate protection — normalized brief selection and exact normalized-title conflicts.
- Technical SEO checks — title, description, canonical, indexability, single H1, Open Graph, and JSON-LD parsing/type checks.
- Framework-neutral metadata and JSON-LD builders —
BlogPosting,FAQPage, andBreadcrumbList. - Search metric math — explicit CTR denominators, impression-weighted position, comparisons, and visibility buckets.
- Observed-search priorities — rank measured queries and route them to existing-article improvements, new-article briefs, draft review, overlap review, or investigation. Missing/stale data stays unscored.
- No runtime dependencies — adapters can use any LLM, database, CMS, framework, or scheduler.
- a Google, Naver, LinkedIn, Tistory, or CMS publishing client;
- automatic public publishing;
- private prompts, source documents, credentials, or production URLs;
- claims that technical SEO guarantees crawling, indexing, ranking, or traffic;
- a hidden or reverse-engineered search ranking algorithm.
The core always saves a review_required draft. A production publisher should be a separate, explicitly approved adapter.
ContentBrief
|
v
ContentGenerator adapter ---> title / body / FAQ / metadata
|
v
Deterministic audit ---> reject unsupported structure or policy violations
|
v
Optional quality review ---> reject low score, unsupported claims, or high overlap
|
v
DraftStore adapter ---> review_required draft only
Rendered page ---> HTML audit / JSON-LD checks
Search data ---> metric aggregation and comparison
The intended customization boundary is:
seo-auto core
├─ profile: editorial rules for one domain
├─ generator: Anthropic, OpenAI, local model, or deterministic fixtures
├─ store: database, filesystem, CMS draft API, or in-memory test store
└─ channel adapter: web site, blog platform, newsletter, or social draft
Requires Node.js 20 or newer.
git clone https://github.com/promptprobe/seo-auto.git
cd seo-auto
npm ci
npm run check
npm run onboarding:demoNew here? Follow the onboarding walkthrough for the complete path: account-free demo → GSC connection → CMS inventory → reviewable draft → deployment and verification.
| Task | Guide / command |
|---|---|
| Understand priorities without accounts | npm run onboarding:demo |
| Connect finalized search observations | Google Search Console |
| Configure a reference CMS and save a reviewed draft | WordPress |
| Check configured accounts, without writing content | npm run onboarding:doctor |
| Save real observations privately on your computer | npm run onboarding:sync |
| Build and preview a public fixture site | npm run onboarding:site, then npm run onboarding:serve |
| Deploy the intended public artifact | Deployment guide |
| Resolve setup or data issues | Troubleshooting |
The starter defaults to worldwide search and supports configurable languages, countries and devices. WordPress is an example adapter, not a restriction on the reusable core. Live examples read GSC and CMS data but never publish, deploy or mutate an external account. Private outputs go in ignored .seo-auto/ directories; the separate public site build reads explicit public fixtures only.
Run npm run example for the original deterministic generation pipeline or npm run example:opportunities for a minimal scoring example. Neither needs API keys.
The npm package is not published yet. The import below documents the intended package API; use the repository example while the public API is still pre-1.0.0.
import {
createContentPipeline,
defineContentProfile,
type ContentGenerator,
type DraftStore,
} from '@promptprobe/seo-auto';
const profile = defineContentProfile({
name: 'product-education',
requiredPatterns: [
{ name: 'checklist', pattern: /^## Practical checklist$/m },
],
forbiddenPatterns: [
{ name: 'guaranteed ranking claim', pattern: /guaranteed ranking/i },
],
});
const generator: ContentGenerator = {
generateTitle: async (context) => yourModel.title(context),
generateBody: async (context) => yourModel.body(context),
generateFaq: async (context) => yourModel.faq(context),
generateMetadata: async (context) => yourModel.metadata(context),
reviewDraft: async (context) => yourReviewer.review(context),
};
const store: DraftStore = {
listExistingContent: async () => database.listPublishedSummaries(),
saveDraft: async (draft) => database.saveDraft(draft),
};
const pipeline = createContentPipeline({ generator, store, profile });
await pipeline.run({
id: 'brief-001',
topic: 'Reliable webhook retries',
keyword: 'webhook retry strategy',
audience: 'API developers',
intent: 'learn how to retry failed webhooks safely',
sources: [
{ title: 'HTTP Semantics', url: 'https://www.rfc-editor.org/rfc/rfc9110' },
],
internalLinks: ['/guides/idempotency'],
});If a deterministic or quality gate fails, the pipeline throws PipelineGateError and does not call saveDraft.
Profiles hold domain policy outside the core:
const profile = defineContentProfile({
name: 'travel-guides',
bodyMinChars: 1_800,
minH2Count: 4,
minFaqCount: 3,
minSources: 2,
qualityThreshold: 90,
requiredPatterns: [
{ name: 'limitations section', pattern: /^## Limitations$/m },
],
forbiddenPatterns: [
{ name: 'unverifiable superlative', pattern: /the best in the world/i },
],
});Keep keyword maps, source registries, regulated-content restrictions, brand voice, and platform rules in profiles or adapters rather than in src/pipeline.
auditHtml accepts rendered HTML, so it works with Next.js, Astro, Remix, static HTML, or any CMS export.
import { auditHtml } from '@promptprobe/seo-auto';
const report = auditHtml(renderedHtml, {
expectedCanonical: 'https://example.com/guides/webhook-retries',
requireOpenGraph: true,
requiredJsonLdTypes: ['BlogPosting', 'FAQPage'],
});
if (!report.passed) {
console.error(report.checks.filter((check) => !check.passed));
}This validates what a server rendered. It does not prove that a search engine crawled, indexed, or ranked the URL.
import { aggregateSearchMetrics, compareSearchMetrics } from '@promptprobe/seo-auto';
const totals = aggregateSearchMetrics([
{ clicks: 5, impressions: 100, position: 4 },
{ clicks: 1, impressions: 20, position: 10 },
]);
// CTR = 6 / 120, position = impression-weighted average of 5.0Connectors should transform provider data into this explicit row contract. Authentication, API pagination, reporting lag, and data completeness remain adapter responsibilities.
buildContentOpportunities accepts finalized daily query totals, separate query/page attribution, and a content inventory. It makes no network calls and never writes or publishes content.
import { buildContentOpportunities } from '@promptprobe/seo-auto';
const report = buildContentOpportunities({
snapshots, // 56 daily snapshots: current 28 days + prior 28 days
periodEnd: finalizedDate, // confirmed by the search-data adapter
asOfDate: today,
inventory, // include published articles, drafts and hub pages
inventoryComplete: true, // only after a successful, fully paginated inventory read
});
const improvements = report.rows.filter(row => row.action === 'improve' && row.score !== null);
const newBriefs = report.rows.filter(row => row.action === 'create' && row.score !== null);Run npm run example:opportunities for a synthetic, API-key-free example. Read the input contract, score formula and limitations before connecting real data. The score is a transparent editorial heuristic, not market search volume, expected traffic, or a probability of ranking. A new-content candidate still needs intent/source review.
Treat discovery strategy and publishing channel as separate dimensions:
strategy: google | naver | geo | social
channel: owned-site | hosted-blog | newsletter | professional-network
Share briefs, evidence, lineage, and approval state. Keep HTML renderers, platform APIs, credentials, and channel-specific rules isolated. Do not copy one generated body unchanged to every channel.
src/
├─ audit/ deterministic content gates
├─ metrics/ search performance math
├─ pipeline/ draft-first orchestration
└─ technical/ metadata, JSON-LD, and rendered HTML checks
test/ executable behavior and regression fixtures
examples/ account-free demos and read-only connection adapters
docs/onboarding/ first-run, GSC, CMS, deployment and troubleshooting guides
Beginners are welcome. The safest first contribution is a failing fixture or test that demonstrates an observed problem and its expected result.
Read CONTRIBUTING.md and follow the repository instructions in AGENTS.md. Every behavior change must include a test. Pull requests must not contain credentials, private source material, production customer data, or automatic publishing side effects.
- Keep API keys in the consuming application, never in profiles or fixtures.
- Use least-privilege credentials per channel.
- Treat generation, approval, publishing, deployment, and live search reflection as separate states.
- Prefer preview or draft endpoints before enabling any external write.
- Report security concerns through GitHub's private security advisory flow.
MIT. Copyright (c) 2026 promptprobe contributors. The distributed package includes the license notice.