Programmatic SEO workflows
Use contentbit to plan, write, inspect, and enforce search-targeted pages with agents.
Use this workflow when content is part of a search program, not just a one-off Markdown edit. The goal is to give humans and agents the same contract before writing, the same preview while reviewing, and the same checks in CI.
The loop is:
- Model the page family in
contentbit.seo.config.ts. - Run
doctorto see current gaps. - Open Studio to inspect the page and brief.
- Give an agent the brief before it writes.
- Run
doctor --strict-seobefore publishing.
1. Model the page family
Start with reusable page types. A page type describes what every page in that family must contain:
import { defineSeoConfig } from '@contentbit/core'
export default defineSeoConfig({
pageTypes: {
glossary: {
requiredFrontmatter: ['name', 'summary', 'seoKeywords.primary'],
requiredSections: [
{ id: 'definition', headings: ['What it means', 'Definition'] },
{ id: 'why-it-matters', headings: ['Why it matters'] },
],
recommendedBlocks: ['quick-ref', 'faq'],
minOutgoingLinks: 2,
},
},
pageDefaults: [
{
pathPrefix: 'content/glossary/',
type: 'glossary',
intent: 'definition',
},
],
})Use pageDefaults for folders that already imply a page type. Use explicit
pages entries for planned pages that do not exist yet, or for pages that need
extra planning data such as primary keywords and required links.
2. Add planned pages
Planned pages are briefs before files exist:
pages: {
'content/glossary/recipe-import/en.md': {
type: 'glossary',
key: 'glossary/recipe-import',
slug: 'recipe-import',
title: 'Recipe import',
intent: 'definition',
keywords: {
primary: 'recipe import',
secondary: ['recipe importer', 'save recipes from websites'],
},
linksTo: ['glossary/recipe-manager', 'guides/save-recipes-from-websites'],
},
}The pages key can be a planned file path, a stable key, or a slug. If a
matching Markdown file exists later, its frontmatter wins for live page facts.
The config stays useful as the planning layer.
3. Check the project
Run Doctor over the same content set you publish:
contentbit doctor "content/**/*.md" \
--registry ./blocks/registry.ts \
--seo-config ./contentbit.seo.config.tsDoctor adds SEO findings to the normal repair plan:
- missing required frontmatter
- missing required sections
- missing required or recommended blocks
- missing required outgoing links
- not enough outgoing or incoming SEO links
Use JSON when an agent or CI job needs stable data:
contentbit doctor "content/**/*.md" \
--registry ./blocks/registry.ts \
--seo-config ./contentbit.seo.config.ts \
--jsonUse strict mode when contract warnings should fail the build:
contentbit doctor "content/**/*.md" \
--registry ./blocks/registry.ts \
--seo-config ./contentbit.seo.config.ts \
--strict-seo4. Inspect the page in Studio
Open the read-only Studio on the same glob and config:
contentbit studio "content/**/*.md" \
--registry ./blocks/registry.ts \
--seo-config ./contentbit.seo.config.tsStudio shows project-level SEO counts, keyword coverage, link health, document preview, source, stats, findings, and the page's Brief view. The Brief view is for humans reviewing the plan: it includes target facts, required sections, required links, related pages, acceptance checks, and copy/download actions for Markdown or JSON.
5. Give the brief to the writer
Print the brief for an existing or planned page:
contentbit brief glossary/recipe-import "content/**/*.md" \
--seo-config ./contentbit.seo.config.tsFor an agent, JSON is usually better:
contentbit brief glossary/recipe-import "content/**/*.md" \
--seo-config ./contentbit.seo.config.ts \
--jsonAsk the agent to satisfy the brief, not to invent a structure:
Use this contentbit brief as the writing contract. Preserve target facts,
include every required section, satisfy the required links, and finish by
running contentbit doctor with --strict-seo.For block syntax, still give the agent the live registry instructions:
contentbit instructions --audience llm --registry ./blocks/registry.ts6. Enforce before publishing
Make the workflow boring in package.json:
{
"scripts": {
"content:doctor": "contentbit doctor \"content/**/*.md\" --registry ./blocks/registry.ts --strict-seo",
"studio": "contentbit studio \"content/**/*.md\" --registry ./blocks/registry.ts"
}
}CI should run content:doctor. Writers and agents can call brief directly
with the page target while they work:
contentbit brief glossary/recipe-import "content/**/*.md"Multilingual projects
For translated slugs with stable page keys, use the same resolver everywhere:
contentbit doctor "content/**/*.md" --link-resolve same-locale-key
contentbit brief glossary/recipe-import "content/**/*.md" --link-resolve same-locale-key
contentbit studio "content/**/*.md" --link-resolve same-locale-keyAuthor translated pages with shared keys and locale-specific slugs:
---
key: glossary/recipe-import
locale: fr
slug: import-recettes
linksTo:
- glossary/recipe-manager
seoKeywords:
primary: import de recettes
---seoKeywords is treated as keyword data when keywords is absent. That lets
projects keep their existing frontmatter vocabulary while contentbit still
builds briefs, keyword coverage, link indexes, and SEO findings.
What to read next
- SEO briefs and contracts for config fields and brief output.
- Content Studio for the local review UI.
- Content doctor for the audit command and exit behavior.
- Internal linking for resolver modes and backlinks.
- LLM-agent integration for wiring this loop into agent instructions.