.agents/skills/forbotsake-content-check/SKILL.md
Reviews your marketing content against your strategy before publishing. Checks brand voice consistency, messaging alignment, channel format fit, CTA clarity, and length. Rates each dimension pass/fail with specific feedback and gives an overall READY TO PUBLISH or NEEDS REVISION verdict. Use when: "review my content", "check this post", "is this ready to publish", "content review", "check my thread", "review before posting", "does this match my brand", "content check". Proactively invoke when the user has written content and is about to publish, or when /forbotsake-create suggests running this as a next step.
npx skillsauth add forbotsake/forbotsake forbotsake-content-checkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The gate between "written" and "published." Catches messaging drift, weak CTAs, and channel misfits before your audience sees them.
FORBOTSAKE_HOME="${FORBOTSAKE_HOME:-$HOME/.forbotsake}"
mkdir -p "$FORBOTSAKE_HOME"
# Discover forbotsake install directory
_FBS_ROOT=""
for _FBS_CANDIDATE in "$HOME/.codex/skills/forbotsake" "$HOME/.agents/skills/forbotsake"; do
[ -d "$_FBS_CANDIDATE" ] && _FBS_ROOT="$_FBS_CANDIDATE" && break
done
if [ -z "$_FBS_ROOT" ]; then
echo "WARNING: forbotsake not found. Install: bash <(curl -fsSL https://raw.githubusercontent.com/forbotsake/forbotsake/main/bin/install.sh)"
fi
# Check for updates
_UPD=""
[ -n "$_FBS_ROOT" ] && [ -x "$_FBS_ROOT/bin/forbotsake-update-check" ] && _UPD=$("$_FBS_ROOT/bin/forbotsake-update-check" 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
# Orchestrated mode (invoked by forbotsake-go, propagated via file flag)
_ORCH_FILE="${FORBOTSAKE_HOME:-$HOME/.forbotsake}/orchestrated-$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
FORBOTSAKE_ORCHESTRATED=$(cat "$_ORCH_FILE" 2>/dev/null || echo 0)
echo "ORCHESTRATED: $FORBOTSAKE_ORCHESTRATED"
# Fast mode (skip adversarial gates)
# Read from env var OR file flag (file flag set by forbotsake-go for pipeline propagation)
_FAST_FLAG="$FORBOTSAKE_HOME/fast-$(basename "$(git rev-parse --show-toplevel 2>/dev/null || pwd)")"
FORBOTSAKE_FAST="${FORBOTSAKE_FAST:-0}"
[ "$FORBOTSAKE_FAST" = "0" ] && [ -f "$_FAST_FLAG" ] && FORBOTSAKE_FAST=$(cat "$_FAST_FLAG" 2>/dev/null || echo 0)
echo "FAST_MODE: $FORBOTSAKE_FAST"
# Check for strategy.md
if [ -f strategy.md ]; then
echo "STRATEGY_EXISTS: yes"
echo "STRATEGY_FILE: strategy.md"
elif [ -f forbotsake-strategy.md ]; then
echo "STRATEGY_EXISTS: yes"
echo "STRATEGY_FILE: forbotsake-strategy.md"
else
echo "STRATEGY_EXISTS: no"
fi
# Check for content directory and list recent files
if [ -d content ]; then
echo "CONTENT_DIR: exists"
echo "RECENT_CONTENT:"
ls -1t content/*.md 2>/dev/null | head -10
echo "LATEST_FILE: $(ls -1t content/*.md 2>/dev/null | head -1)"
else
echo "CONTENT_DIR: missing"
fi
If output shows UPGRADE_AVAILABLE <old> <new>: read the forbotsake-upgrade SKILL.md
at $_FBS_ROOT/forbotsake-upgrade/SKILL.md (where _FBS_ROOT is the variable already
resolved in the preamble bash above) and follow the "Inline upgrade flow" section Step 1
only. If Step 1 results in "Yes" or "Always" (proceed with upgrade), continue through
Steps 2-7 of the inline flow. If Step 1 results in "Not now" or "Never" (declined),
skip Steps 2-7 entirely and continue with this skill immediately.
If output shows JUST_UPGRADED <old> <new>: tell user
"Running forbotsake v{new} (just updated from v{old})!" and continue.
If STRATEGY_EXISTS is no:
"No strategy.md found. I can still review content for general quality, but I can't check it against your brand voice, ICP, or messaging pillars without a strategy.
Want to proceed with a general review, or run
/forbotsake-marketing-startfirst?"
Ask the user directly in conversation with options: A) General review (no strategy checks), B) I'll create a strategy first.
If option B, stop here.
If CONTENT_DIR is missing:
"No content/ directory found. What file do you want me to review? Paste the path or the content directly."
Ask the user directly in conversation.
Orchestrated mode (ORCHESTRATED is 1):
status: draft in frontmatter. Review ONE file at a time (the skill's review flow is designed for single-file review). If multiple drafts exist, review only the newest one.reviewed-override and continue.Interactive mode (ORCHESTRATED is 0):
If content files exist, ask via direct conversation with the user:
"Which content piece should I review?
Recent files: {numbered list of files from RECENT_CONTENT, showing filename and frontmatter channel/topic}
Pick a number, paste a file path, or paste raw content directly."
If only one file exists in content/, default to it:
"Found one content file:
{filename}. Reviewing that one. Say 'no' if you meant something else."
Read the selected content file completely. Extract from its frontmatter:
channel -- which platform this is formessaging_pillar -- which pillar it supportstopic -- what it's aboutstatus -- current statusRead strategy.md completely. Extract:
Skip this phase if FAST_MODE is 1. Print: "FORBOTSAKE_FAST=1: skipping adversarial review."
This is an independent adversarial review of the content by a fresh-context subagent. The reviewer has NOT seen your conversation or the scorecard dimensions. It sees only the content draft, strategy.md, and the banned patterns list.
FORBOTSAKE_HOME="${FORBOTSAKE_HOME:-$HOME/.forbotsake}"
_SKILL_DIR=$(dirname "$(find $HOME/.codex/skills -path "*/forbotsake-marketing-start/SKILL.md" -type f 2>/dev/null | head -1)" 2>/dev/null)
_FBS_ROOT=$(cd "${_SKILL_DIR}/.." 2>/dev/null && pwd || true)
# Load default patterns
_DEFAULTS=""
[ -n "$_FBS_ROOT" ] && [ -f "$_FBS_ROOT/knowledge/banned-patterns-defaults.md" ] && _DEFAULTS="$_FBS_ROOT/knowledge/banned-patterns-defaults.md"
echo "BANNED_DEFAULTS: ${_DEFAULTS:-not_found}"
# Load user patterns
_USER_PATTERNS="$FORBOTSAKE_HOME/banned-patterns.md"
[ -f "$_USER_PATTERNS" ] && echo "USER_PATTERNS: $_USER_PATTERNS" || echo "USER_PATTERNS: none"
Run the review inline to spawn an independent reviewer subagent. The subagent prompt must contain ONLY:
Subagent prompt:
You are a content red team reviewer. Your job is to REJECT bad content, not approve good content.
Read these files:
- {content file path} -- the content to review
- {strategy.md path} -- the strategy it should align with
- {banned patterns path(s)} -- patterns that signal AI-generated content
Review the content on 6 dimensions:
- AI-SLOP DETECTION: Check for patterns from the banned patterns file. Count matches.
- VOICE AUTHENTICITY: Does this sound like a human wrote it, or like an AI? Check against brand voice in strategy.md.
- ICP SPECIFICITY: Would the target person from strategy.md actually engage with this, or scroll past?
- ORIGINALITY: Does this say something the ICP hasn't heard before, or is it generic advice anyone could write?
- STRATEGY ALIGNMENT: Does the content execute the positioning and messaging pillars from strategy.md?
- PUBLIC REPUTATION RISK: Would the founder be embarrassed if this went viral for the wrong reasons?
Respond with ONLY valid JSON, no markdown fences, no explanation outside the JSON: {"result": "PASS" | "SOFT_FAIL" | "HARD_FAIL", "findings": [{"dimension": "...", "verdict": "PASS" | "FAIL", "spans": ["quoted text from content"], "fix": "suggested replacement"}], "summary": "one-line overall assessment"}
Parse the subagent's response as JSON.
Before parsing: Strip markdown fences if present (remove leading json and trailing lines). Then attempt JSON parse.
If JSON parsing still fails after stripping fences:
{"gate":"content","result":"PARSE_FAIL"}If parsed successfully, act on the result:
PASS: Print "Content Red Team: PASS. Proceeding to scorecard review." Continue to Phase 3.
SOFT_FAIL: Present the findings to the user:
"Content Red Team: SOFT_FAIL
An independent reviewer flagged these issues: {for each finding with verdict FAIL:}
- {dimension}: "{spans}" ... suggested fix: "{fix}"
This is iteration {N} of 2."
Interactive mode: Ask the user directly in conversation: A) Apply fixes and re-review B) Override and proceed to scorecard C) I'll revise manually
Orchestrated mode: Auto-apply fixes, re-dispatch reviewer. Max 2 iterations total (hard counter). After 2 iterations, if still SOFT_FAIL, proceed to Phase 3 with concerns logged.
If the user chooses A: apply fixes using Edit tool, re-dispatch the reviewer (Step 2). Max 2 total iterations. After 2, proceed to Phase 3 regardless.
If the user chooses B: update content frontmatter with reviewer_notes: containing the findings. Log override. Continue to Phase 3.
HARD_FAIL: The content needs a fundamental rewrite.
"Content Red Team: HARD_FAIL
The independent reviewer says this content needs a fundamental rewrite: {summary}
Specific issues: {for each finding with verdict FAIL:}
- {dimension}: "{spans}"
Next action: Run
/forbotsake-createagain. The reviewer's notes will be available as context to avoid the same issues."
status: hard-failed and reviewer_notes: {JSON findings}status: hard-failed to frontmatter. Present user with explicit proceed/abort choice (this is the one gate that always requires user input, even in orchestrated mode).If override: set status: reviewed-override, log override reason, continue to Phase 3.
After the red team phase completes, log the result:
FORBOTSAKE_HOME="${FORBOTSAKE_HOME:-$HOME/.forbotsake}"
mkdir -p "$FORBOTSAKE_HOME"
echo '{"gate":"content","ts":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'","result":"RESULT","content_file":"FILENAME","iterations":N,"override":BOOL}' >> "$FORBOTSAKE_HOME/review-metrics.jsonl" 2>/dev/null || true
Replace RESULT, FILENAME, N, BOOL with actual values.
Evaluate the content against these 7 dimensions. For each, give a PASS or FAIL with specific, actionable feedback. Not vague ("could be better") -- specific ("tweet 3 uses 'leverage' which your ICP wouldn't say; replace with 'use'").
Does the content sound like it comes from the same person/brand as the strategy?
Check for:
PASS criteria: A reader familiar with the brand would recognize this as on-brand. FAIL example: "Strategy says 'direct, technical, no fluff' but this post opens with 'In today's fast-paced world of innovation...'"
Does the content reinforce at least one messaging pillar without contradicting the others?
Check for:
PASS criteria: You can point to the specific pillar this content supports. FAIL example: "Strategy positions you as the 'simple' alternative, but this post emphasizes 'powerful enterprise features.'"
Is this content written FOR the ICP, not for a generic audience?
Check for:
PASS criteria: The ICP from strategy.md would feel "this was written for me." FAIL example: "ICP is 'backend engineers at Series A startups' but this post reads like it's targeting CTOs at enterprises."
Does the content respect the platform's conventions and constraints?
Check per channel:
PASS criteria: The content would not look out of place on the target platform. FAIL example: "This X thread has 15 tweets -- that's too long. Most readers drop off after tweet 5-7."
Is there one clear call-to-action, and does it match the content's funnel position?
Check for:
PASS criteria: A reader knows exactly what to do next and why. FAIL example: "CTA says 'sign up now' but this is an awareness-stage thread. Try 'follow for more' or 'bookmark this.'"
Is the content the right length for its channel and purpose?
Guidelines:
PASS criteria: Length serves the content. Nothing feels padded or cut short. FAIL example: "This blog post is 600 words. For the SEO goal noted in your strategy, aim for 1500+."
Would the first line/tweet/sentence make the ICP stop scrolling?
Check for:
PASS criteria: Reading only the first line, the ICP would want to read the second. FAIL example: "Opens with 'Excited to announce...' -- nobody stops scrolling for your excitement. Lead with the benefit."
If the content file has schema_version: 2 and visual_treatment is not none, check:
Visual treatment appropriateness: Does the chosen treatment (text-card/ai-image/video) fit the channel and content type? Flag mismatches:
visual_treatment: none → "Product Hunt posts need gallery images. Recommend ai-image."visual_treatment: none → "LinkedIn posts with images get 2x engagement. Consider text-card or ai-image."visual_treatment: ai-image → "Hacker News is text-focused. Visual adds no value here."Visual prompt quality: Does visual_prompt reference brand elements from brand.md?
Visual asset existence: If visual_status is generated, check that the visual file actually exists at the expected path.
Accessibility: Does visual_alt provide a meaningful description? Not just "image" or empty — it should describe what's depicted for screen readers.
If visual file exists: Use the Read tool to display the image to the user. Ask: "Does this image match your brand and content? Quick visual sanity check."
PASS criteria: Visual treatment fits the channel, prompt references brand, asset exists, alt text is meaningful. FAIL example: "visual_treatment is ai-image but visual_status is 'failed'. No image file exists. Either regenerate or switch to text-card."
Present the review as a scorecard:
## Content Review: {filename}
| Dimension | Verdict | Notes |
|-----------|---------|-------|
| Brand Voice | PASS/FAIL | {one-line summary} |
| Messaging Alignment | PASS/FAIL | {one-line summary} |
| ICP Targeting | PASS/FAIL | {one-line summary} |
| Channel Format | PASS/FAIL | {one-line summary} |
| CTA Clarity | PASS/FAIL | {one-line summary} |
| Length | PASS/FAIL | {one-line summary} |
| Hook Strength | PASS/FAIL | {one-line summary} |
| Visual Consistency | PASS/FAIL/N/A | {one-line summary} |
**Overall: READY TO PUBLISH / NEEDS REVISION**
"READY TO PUBLISH. This content is on-brand, on-strategy, and channel-appropriate.
Quick sanity checks before hitting post:
- Read it out loud one more time
- Verify all links work
- Double-check any specific numbers or claims
When ready, use
/forbotsake-publishto ship it."
Present the failures with specific edit suggestions. Not "make the hook better" -- provide an actual rewritten alternative.
"NEEDS REVISION. {N} of 7 dimensions failed. Here are the specific fixes:
{Failed Dimension 1}: Current: "{quote the problematic part}" Problem: {why it fails} Suggested fix: "{rewritten version}"
{Failed Dimension 2}: Current: "{quote the problematic part}" Problem: {why it fails} Suggested fix: "{rewritten version}"
Want me to apply these fixes? Or do you want to revise manually?"
Ask the user directly in conversation with options: A) Apply all suggested fixes B) Apply some fixes (tell me which) C) I'll revise manually D) Override -- publish as-is (I disagree with the review)
If A or B: apply the edits to the content file using the Edit tool, then re-run the review on the updated version. Repeat until all dimensions pass or the user overrides.
If D: update the content file's frontmatter status to reviewed-override and proceed.
After the review is complete (pass or override), update the content file's frontmatter:
# Update status in frontmatter
Use the Edit tool to change status: draft to:
status: reviewed if all dimensions passedstatus: reviewed-override if the user chose to override failuresstatus: revised if edits were applied and the re-review passedOrchestrated mode (ORCHESTRATED is 1): Skip this phase entirely. Confirm: "Review complete for content/{filename}. Status: {reviewed/revised/reviewed-override}." Then stop.
Interactive mode (ORCHESTRATED is 0): Tell the user:
"Review complete for
content/{filename}.{If READY TO PUBLISH:} Next step: Use
/forbotsake-publishto ship it.{If NEEDS REVISION and user chose to revise manually:} Next step: Edit the file, then run
/forbotsake-content-checkagain.{If user wants to create more content:} Create more:
/forbotsake-createto write your next piece from the calendar.{If no content calendar exists:} Get organized:
/forbotsake-content-planto build a content calendar so you always know what to write next."
testing
Upgrade forbotsake to the latest version. Detects install type (git clone vs vendored), runs the upgrade, and shows what's new. Use when: "upgrade forbotsake", "update forbotsake", "get latest version", "forbotsake update".
research
Stage 3: RESEARCH (competitors). Analyzes 3-5 competitors to find messaging whitespace and positioning gaps. Produces competitor-analysis.md with a messaging matrix showing what each competitor says, what's missing, and where you can win. Use when: "competitor analysis", "competitive research", "what are others doing", "market landscape", "who am I competing with", "spy on competitors", "messaging whitespace", "differentiation research". Proactively invoke when the user mentions competitors or asks how to differentiate.
development
Stage 4.5: SHARPEN. Takes a specific outreach target (person or organization) and produces a deep execution plan with contextual research, relationship mapping, angle selection, and a multi-touch sequence. Reads your founder profile and strategy to leverage warm paths and unfair advantages. Use when: "refine this plan", "go deeper on this", "sharpen execution", "how do I approach [person]", "outreach to [person]", "target [person/org]", "approach [person]", "engage [org]". Proactively invoke when the user mentions approaching a specific person or organization as part of their marketing strategy. Requires: strategy.md (from /forbotsake-marketing-start).
data-ai
Stage 9: MEASURE. Reviews what you published, analyzes performance data, and produces a retro report with evidence-based recommendations. Tells you what to double down on, what to drop, and what to try next. Use when: "what worked", "marketing retro", "measure results", "review performance", "which content performed best", "should I keep doing this". Proactively invoke one week after /forbotsake-publish was last run.