# Content Brief

> Generates a fully structured SEO content brief for a target keyword and optionally pushes it to a Notion database. Use this skill whenever the user says 'create a content brief', 'brief this keyword', 'run a content brief for', 'generate a brief', 'write a brief for [keyword]', 'content brief on [topic]', or any variation where someone needs a keyword researched and turned into a structured writing assignment with H1, H2 outline, FAQ, internal links, word count target, and writer notes. Also triggers when the user provides a keyword and asks for an SEO brief, editorial brief, or writing spec. Outputs a mandatory structured format that the text parser maps directly to Notion properties. Supports single-keyword and batch (CSV) modes.

- Skill: `infrasity-labs/content-brief` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add infrasity-labs/content-brief`
- Raw SKILL.md: https://api.skillmd.com/api/skills/infrasity-labs/content-brief/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: infrasity-labs (https://skillmd.com/u/infrasity-labs)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/infrasity-labs/content-brief

---


# Content Brief — Keyword-to-Notion Brief Generator

Generates a structured SEO content brief from a target keyword. Output follows the mandatory Direction prompt format so the `text_parser.py` script can extract every field for Notion without manual cleanup.

## Invocation Triggers

**Explicit phrases** (any of):
- "create a content brief for [keyword]"
- "brief this keyword: [keyword]"
- "content brief on [topic]"
- "generate a brief for [keyword]"
- "write a brief for [keyword]"
- "run the content brief skill"

**Implicit signals:**
- User provides a keyword and asks for an SEO spec, editorial spec, or writing assignment
- User pastes a keyword list and asks for briefs

When triggered, run immediately — no upfront intake beyond the keyword itself.

## Grill-Me Intake (One Question, Optional)

Run the brief without questions when the keyword is clear.

Ask **one** clarifying question only when **both** are true:
1. The target audience or client is not inferrable from context
2. Audience changes the content angle meaningfully (e.g., "project management software" could target PMs or developers)

> **Quick clarification — who is the primary audience for "[keyword]"?**
> 1. [Inferred persona A — e.g., HR Director]
> 2. [Inferred persona B — e.g., Operations Manager]
> 3. Tell me
>
> *Why I'm asking: audience shapes the H1, content angle, and writer notes. One question prevents a wrong brief.*

Max one question. If audience is inferable, skip and proceed.

## Data Gathering (Before Writing the Brief)

Run these steps before generating the Direction prompt output:

### Step 1 — Keyword Metrics
**Preferred:** Ahrefs MCP (`keywords_explorer_overview`) → volume, KD, CPC, SERP data.

**Fallback (no Ahrefs MCP):** Use WebSearch to estimate:
- Search `[keyword] search volume KD CPC site:ahrefs.com OR site:semrush.com OR site:moz.com`
- Extract available volume/KD/CPC estimates
- If no data found, set VOLUME/CPC/DIFFICULTY to `[not available — add manually]`

### Step 2 — Competitor H2/H3 Analysis
- WebSearch `[keyword]` → identify top 3 organic results (skip ads, maps, featured snippets)
- WebFetch each URL → extract all H2 and H3 headings
- Note: competitor structure informs the H2_OUTLINE. Do not copy — use as gap analysis.

### Step 3 — Search Intent Classification
Based on keyword + SERP type, classify as one of exactly four options:
- `Informational` — user wants to learn
- `Commercial` — user is comparing options before buying
- `Transactional` — user is ready to act/purchase
- `Navigational` — user seeks a specific brand/site

### Step 4 — Priority Scoring
Apply routing logic from `references/routing-logic.md`:
- HIGH: Volume > 200 AND KD < 40 AND intent is Commercial or Transactional
- MEDIUM: Doesn't meet HIGH criteria but has meaningful volume or strategic importance
- LOW: Low volume, high difficulty, or informational with limited conversion value

## Direction Prompt Output Format (Mandatory)

**This format is non-negotiable.** The `text_parser.py` script performs label-exact extraction. If any label deviates from the format below — wrong case, extra space, missing underscore — the Notion property will arrive empty.

After data gathering, output the brief using EXACTLY this structure:

```
TARGET_KEYWORD: [keyword]
VOLUME: [number or "not available"]
CPC: [decimal or "not available"]
DIFFICULTY: [0-100 integer or "not available"]
SEARCH_INTENT: [Informational | Commercial | Transactional | Navigational]
AUDIENCE: [persona — job title or role]
RECOMMENDED_H1: [final proposed title]
CONTENT_ANGLE: [one paragraph describing the unique angle, why this beats competitors, what the post must do]
WORD_COUNT: [number]
SCHEMA: [schema type — e.g., FAQ, HowTo, Article, FAQ + HowTo]
PRIORITY: [HIGH | MEDIUM | LOW]
H2_OUTLINE:
- H2: [heading]
  - H3: [subheading]
  - H3: [subheading]
- H2: [heading]
  - H3: [subheading]
FAQ:
- Q: [question the audience actually searches]
- Q: [question]
- Q: [question]
INTERNAL_LINKS:
- [anchor text] → [relative URL or page title if URL unknown]
WRITER_NOTES:
[one paragraph of specific guidance: tone, POV, what to avoid, key differentiators to emphasize, CTAs, any client-specific requirements]
```

**Critical rules:**
- Every field label must appear exactly as shown (ALL_CAPS with underscores)
- SEARCH_INTENT value must exactly match one of the four options (capitalized)
- PRIORITY value must be exactly HIGH, MEDIUM, or LOW
- H2_OUTLINE, FAQ, INTERNAL_LINKS, WRITER_NOTES are block fields — content follows on the next line(s)
- No additional text before TARGET_KEYWORD or after WRITER_NOTES block

## Workflow Architecture (9 Nodes)

| Node | Role | Tool |
|---|---|---|
| 1 — Input | Accept keyword + optional client/audience context | User message |
| 2 — Keyword Metrics | Pull volume, KD, CPC, SERP type | Ahrefs MCP OR WebSearch fallback |
| 3 — SERP Scrape | Extract H2/H3 from top 3 organic results | WebFetch |
| 4 — Brief Generation | Process data through Direction prompt → structured output | Claude (this skill) |
| 5 — Text Parser | Extract labeled fields → structured variables | `scripts/text_parser.py` |
| 6 — Conditional Router | Route based on PRIORITY value | Routing logic |
| 7A — Notion Create (HIGH) | Create page, Status = "Briefed: Ready for Assignment" | Notion MCP |
| 7B — Notion Create (MED/LOW) | Create page, Status = "Briefed: Weekly Review Queue" | Notion MCP |
| 8A — Slack Notify (HIGH only) | Post brief summary + Notion link to channel | Slack MCP |
| 9 — Calendar Sync | Create linked entry in Content Calendar database | Notion MCP |

In Claude Code without MCP connectors: Nodes 1–5 run automatically. Nodes 6–9 produce a ready-to-paste summary and instruct the user on manual Notion entry.

## Batch Processing Mode

Trigger: user provides a CSV with a `Target Keyword` column (optional `Priority Override` column).

Process:
1. Confirm CSV is readable and `Target Keyword` column exists
2. Run each keyword through the full pipeline sequentially
3. Output all briefs in sequence, separated by `---`
4. After all briefs: output a summary table (keyword | priority | word count | schema)

Expected throughput: 20 briefs in 20–25 minutes (60–75 seconds per brief).

If any keyword fails (no SERP data, ambiguous intent): note it in the summary table as `[FAILED — reason]` and continue processing remaining keywords.

## Notion Push (When MCP Available)

Map parser output to Notion properties using `references/notion-schema.md`.

Two paths based on PRIORITY:

**HIGH:**
- Status → "Briefed: Ready for Assignment"
- Target Publish Date → today + 14 days
- Trigger Slack notification (Node 8A)

**MEDIUM:**
- Status → "Briefed: Weekly Review Queue"
- Target Publish Date → today + 28 days

**LOW:**
- Status → "Briefed: Weekly Review Queue"
- Target Publish Date → today + 42 days

After page creation: run Calendar Sync (Node 9) to create linked entry in Content Calendar database.

Pre-check before creating: query Notion for existing page with same TARGET_KEYWORD. If found → route to `update_page` instead of `create_page` to prevent duplicates.

## Multi-Client Setup

Each client has:
- Separate Notion integration token
- Separate database ID
- Client-specific Direction prompt variant (adjust audience, tone, internal link base URLs)

Onboarding a new client: ~45–60 minutes to configure connector + test one brief end-to-end.

## Output When Notion MCP Is Not Connected

If Notion MCP is not available, after generating the Direction prompt output, append:

```
---
NOTION PUSH: Not connected. To add this brief to Notion manually:

1. Open your Notion database
2. Create a new page
3. Paste the following field values:
   [formatted summary of all extracted fields]

Or run: python scripts/text_parser.py brief.txt --output json
to get a JSON payload ready for the Notion API.
---
```

## Validation Gate

After generating output, mentally verify:
- All 11 simple fields are present and non-empty
- SEARCH_INTENT is one of the 4 valid values
- PRIORITY is exactly HIGH, MEDIUM, or LOW
- H2_OUTLINE has at least 4 H2s each with at least 1 H3
- FAQ has at least 3 questions
- INTERNAL_LINKS has at least 2 entries
- WRITER_NOTES is a substantive paragraph (not a placeholder)

Run `scripts/brief_validator.py` on the output file for automated validation.

## Error Handling

| Situation | Behavior |
|---|---|
| No keyword data available | Set numeric fields to "not available", add note in WRITER_NOTES instructing editor to verify manually |
| SERP scrape blocked (403/paywalled) | Skip scrape, note "competitor outline not available" in WRITER_NOTES, proceed with brief |
| Ambiguous search intent | Default to Informational; flag in WRITER_NOTES: "Intent ambiguous — verify before briefing writer" |
| Select value mismatch in Notion | Capitalize values exactly; Notion select is case-sensitive |
| Duplicate keyword detected | Route to update_page instead of create_page |
| >2 empty properties in parsed brief | Flag for manual review; do not push to Notion |
| Batch keyword fails | Note in summary table, continue processing |
| CSV missing Target Keyword column | Stop and ask user to confirm column name |

See `references/error-handling.md` for full failure-point catalog.

## Tooling

| Script | Role |
|---|---|
| `scripts/text_parser.py` | Extracts labeled fields from Direction prompt output → structured dict. `python text_parser.py brief.txt --output json` |
| `scripts/brief_validator.py` | Validates all required fields are present, values are in allowed sets. `python brief_validator.py brief.txt` |

## References

- `references/notion-schema.md` — Notion database property config (names, types, allowed values)
- `references/routing-logic.md` — Priority scoring rules and publish date calculations
- `references/error-handling.md` — Known failure points and fixes

## Anti-Patterns To Reject

- Deviating from the mandatory Direction prompt label format (breaks parser)
- Using lowercase or mixed-case field labels (TARGET_KEYWORD not Target_Keyword)
- Putting SEARCH_INTENT outside the four allowed values
- Generating a brief without first gathering keyword + SERP data
- Asking multiple intake questions before running
- Writing vague WRITER_NOTES ("write a good post about this topic")
- Fabricating keyword metrics when data is unavailable — always flag as "not available"
- Pushing to Notion when >2 fields are empty


