# seo-brief — SEO content-brief & keyword-planning microservice

SEO content-brief & keyword-planning microservice: turn a target keyword into a ready-to-write brief — a heading outline (H1/H2/H3), semantic entities to cover, People-Also-Ask style questions, a...


Turns a **target keyword** into everything you need before you write: an outline, semantic entities,
People-Also-Ask questions, a target word count, internal-link ideas, title-tag and meta-description
drafts, FAQ JSON-LD, content-gap analysis, and related/long-tail keyword expansion. A paid
"intelligent microservice": every tool has a **deterministic keyword-expansion + template core that
runs fully offline**, and the generative tools **optionally** call an LLM (via `../_shared/llm.js`) to
enrich, silently falling back. Every result is tagged `mode: 'heuristic' | 'llm'`.

## Tools

| tool | output |
|---|---|
| `brief` | keyword → outline (H1/H2/H3), entities, PAA questions, target word count, internal-link ideas, related keywords. |
| `titleTags` | N SERP title tags within pixel-safe length (≤60 chars), brand-suffixed, intent-flavored. |
| `metaDescription` | Meta descriptions within pixel-safe length (≤155 chars), keyword-front-loaded + CTA. |
| `faqSchema` | FAQPage JSON-LD (schema.org) from `{question,answer}` pairs — or synthesized from the keyword — plus a ready `<script>` tag. |
| `contentGaps` | Compares your draft `text` to the topic model → missing entities, questions, keywords + a coverage score. |
| `relatedKeywords` | Expanded related / long-tail keyword list, each tagged with its own search intent. |

Intent is auto-detected (`informational · commercial · transactional · navigational`) or can be forced
via `intent`. Word-count targets scale with intent.

## Usage

```js
import seoBrief from './index.js';

await seoBrief.adapters.brief({ keyword: 'email marketing', count: 8 });
await seoBrief.adapters.titleTags({ keyword: 'email marketing', brand: 'Leumas' });
seoBrief.adapters.faqSchema({ faqs: [{ question: 'What is X?', answer: 'X is …' }], url: 'https://ex.com/x' });
seoBrief.adapters.contentGaps({ keyword: 'email marketing', text: myDraft });
seoBrief.adapters.relatedKeywords({ keyword: 'email marketing', count: 20 });
```

Each call takes ONE args object (maps 1:1 to an HTTP POST body). `brief`/`titleTags`/`metaDescription`/
`contentGaps`/`relatedKeywords` require `keyword`; `contentGaps` also requires `text`; `faqSchema`
requires either `faqs` or `keyword`. Missing inputs throw `TypeError`.

## Hybrid intelligence

Templates + keyword expansion always produce output. When an LLM is reachable, `brief` (richer
entities/questions via JSON), `titleTags`, and `metaDescription` enrich the result and keep the
heuristic as `fallback`. A down/absent model never throws — the pack works 100% offline.

## DRY boundary — distinct from `seo`

- **`seo`** *audits* content that already exists: it takes provided HTML/meta/text and analyzes it
  (meta tags, OpenGraph, JSON-LD from a data payload, sitemap, keyword density, SERP preview).
- **`seo-brief`** *plans* content that does not exist yet, starting from a keyword. Different input
  (a keyword, not HTML) and a different job (planning vs. auditing). `faqSchema` here builds FAQPage
  JSON-LD for planning; `seo.jsonLd` still serves arbitrary schema from a data payload.
- No cross-pack imports except `../_shared/llm.js`. Pure ESM, Node built-ins only, zero npm deps.


---
Source: shared/engines/adapters/domain/seo-brief/README.md
Canonical: https://docs.leumas.tech/p/adapters/domain/seo-brief
