SEO briefs and contracts
Define page contracts and print agent-ready briefs for existing or planned pages.
SEO contracts describe what a page must satisfy. Briefs turn those contracts plus the current content inventory into a writer-ready plan.
Use this page as a reference while editing contentbit.seo.config.ts. To build
the workflow from start to finish, follow
Build a programmatic SEO workflow.
How the config files fit together
The project config tells Contentbit where the SEO config lives:
// contentbit.config.ts
import { defineContentConfig } from '@contentbit/core'
export default defineContentConfig({
content: 'content/**/*.md',
registry: './blocks/registry.ts',
seo: './contentbit.seo.config.ts',
})The SEO config holds page-family contracts and individual page plans. Keeping the two concerns separate lets every CLI command share the same project paths without mixing them into the editorial model.
Config file
Create contentbit.seo.config.ts at the project root, or point to another path
from contentbit.config.ts. Keep the file small at first. Define one page type,
add folder defaults, then add explicit plans where a writer needs a brief before
the Markdown file exists.
import { defineSeoConfig } from '@contentbit/core'
export default defineSeoConfig({
pageTypes: {
alternative: {
requiredFrontmatter: ['type', 'intent', 'keywords.primary'],
requiredSections: [
{ id: 'overview', headings: ['Overview', 'Summary'] },
{ id: 'alternatives', headings: ['Best alternatives', 'Top alternatives'] },
{ id: 'comparison', headings: ['Comparison', 'Feature comparison'] },
],
requiredBlocks: ['comparison'],
recommendedBlocks: ['faq', 'key-metrics'],
requiredLinksTo: ['seo-tools-comparison'],
minOutgoingLinks: 2,
minIncomingLinks: 1,
},
},
pageDefaults: [
{
pathPrefix: 'content/alternatives/',
type: 'alternative',
intent: 'commercial',
},
],
pages: {
'ahrefs-alternatives': {
type: 'alternative',
key: 'ahrefs-alternatives',
slug: 'ahrefs-alternatives',
title: 'Ahrefs Alternatives',
intent: 'commercial',
keywords: { primary: 'ahrefs alternatives' },
linksTo: ['seo-tools-comparison'],
},
},
})Page types
pageTypes are reusable contracts. Use them for page families such as docs
pages, glossary entries, alternatives pages, comparison pages, product pages, or
blog posts.
| Field | Meaning |
|---|---|
requiredFrontmatter | Dot paths that must exist after frontmatter normalization. |
requiredSections | Headings that must appear in the document outline. Each section can provide allowed heading variants. |
requiredBlocks | Block names that must appear at least once. |
recommendedBlocks | Block names that produce informational suggestions when absent. |
requiredLinksTo | Link targets that must appear in linksTo. |
minOutgoingLinks | Minimum number of outgoing SEO links. |
minIncomingLinks | Minimum number of backlinks from other scanned pages. |
Frontmatter is normalized before SEO checks run. If a project uses
seoKeywords, contentbit also exposes that data as keywords for page facts.
That means a contract can require the source field (seoKeywords.primary) or
the normalized field (keywords.primary), depending on the convention you want
writers to see in the file.
Page defaults
pageDefaults classify existing files by path. Use them when a folder already
means something:
pageDefaults: [
{ pathPrefix: 'content/docs/', type: 'docs-page', intent: 'documentation' },
{ pathPrefix: 'content/blog/', type: 'blog-post', intent: 'publication' },
]Defaults fill in missing facts. Existing frontmatter and explicit planned page entries still win.
Planned pages
pages can describe pages before Markdown exists. That is the part that makes
briefs useful for agents:
pages: {
'content/alternatives/semrush.md': {
type: 'alternative',
key: 'semrush-alternatives',
slug: 'semrush-alternatives',
title: 'Semrush Alternatives',
keywords: { primary: 'semrush alternatives' },
linksTo: ['seo-tools-comparison'],
},
}When the file is later created, contentbit merges the plan with the live
frontmatter and stats. Existing frontmatter wins for page facts such as title,
slug, key, intent, keywords, and linksTo.
Print a brief
contentbit brief semrush-alternatives
contentbit brief semrush-alternatives "content/**/*.md"
contentbit brief semrush-alternatives "content/**/*.md" --jsonTargets resolve by key first, then by slug, then by internal page id. With a
project config, brief scans the configured content paths. If the page is only
planned, the brief still prints.
The Markdown brief is meant to paste into an agent or editorial task. The JSON brief is better for tools.
Brief contents
A brief includes:
- target page facts: id, source, key, slug, title, type, intent, and keywords
- the matching page-type contract
- required sections, blocks, and links
- SEO findings for the target page
- related pages from the same type or link neighborhood
- acceptance checks the writer should satisfy before handoff
Studio shows the same data in the document Brief view, with copy and download actions for Markdown and JSON.
Doctor integration
When an SEO config exists, doctor includes SEO findings in the normal repair
plan:
contentbit doctor "content/**/*.md" --strict-seo
contentbit doctor "content/**/*.md" --no-seoUse --strict-seo in CI when missing contract requirements should fail the
build. Use --no-seo when you only want validation, link, and stats checks.
Multilingual pages
Use the same link resolver options for brief, doctor, studio, and
links.
contentbit brief glossary/recipe-import "content/**/*.md" \
--link-resolve same-locale-key \
--locale-field locale \
--key-field key \
--slug-field slugFor translated slugs, share a stable key across locales and localize slug.
Contentbit keeps localized SEO pages separate while still resolving links by
same-locale key.