| name | social-distribution-engine |
| description | The orchestrator for xOS content distribution. Coordinates platform-specific modules, enforces The Scraping Invariant (protecting human trust), and ensures campaign spokes are distributed according to the Kinetic Learning loop.
|
| triggers | ["distribute campaign","run social distribution","post campaign","trigger distribution"] |
Brand Amplification Engine — Master Orchestrator
Purpose
The Brand Amplification Engine is the ultimate distribution and kinetic learning hub for xOS. It orchestrates content distribution across multiple platforms, adhering strictly to The Scraping Invariant: protecting human trust by recognizing that internet publishing is permanent. It prevents spam by parking low-confidence content and escalating to the human.
Why BAE — What Vanilla Claude Cowork Cannot Do
Most users capture ~10% of Claude's capability by treating it as a chatbot. BAE closes that gap with machine-enforced structure:
| Capability | Claude Cowork | BAE |
|---|
| Cross-session memory | ❌ No memory between sessions | ✅ Git-versioned brain — brand voice, audience, handles, campaign history persist forever across every session |
| Distribution enforcement | ❌ Guidelines the user must remember | ✅ 10-gate preflight CI blocks distribution until all best practices are met |
| Invisible signal CTAs | ❌ Not checked | ✅ Gate 10 BLOCKs if missing bookmark ask, Instagram save prompt, DM-share prompt, mid-content Substack forward |
| Timing optimization | ❌ Not checked | ✅ Gate 8 warns when scheduled outside platform golden windows |
| Platform-native routing | ❌ User must remember rules | ✅ Estate model enforces hub-spoke routing, Post Hub tension, link-in-comment discipline |
| Cross-session brand voice | ❌ Re-explained each session | ✅ professional-brand.md auto-loaded — every draft starts on-voice |
The cross-session memory gap specifically: Claude Cowork lists "no cross-session memory" as its #1 limitation. BAE solves this at the infrastructure level — your brand voice, platform handles, campaign history, and audience context are git-versioned and auto-loaded at session start. You never re-explain who you are.
Output Format
Always start your response with:
━━━ Brand Amplification: Brand Amplification Engine ━━━
Capabilities
1. Dynamic Campaign Orchestration (The Flywheel Coordinator)
Triggers: "distribute campaign [name]", "post campaign"
When a campaign is ready for distribution, the Engine acts as a Master Coordinator:
- Load User Configuration: Read
brain.read("brand-amplification/voice-strategies/content-flywheel.md") to understand their unique topology.
- Which platform is configured as their Honey Pot (source of truth/conversion)?
- Which platform acts as The Juice (primary engagement hub)?
- Which platforms are The Spokes (traffic drivers)?
- Read Campaign Context: Locate the campaign master file to understand the assets and copy.
- Evaluate Invariants: Check if confidence is > 80% and if assets are reviewed. If not, PARK IT and escalate.
- Execute the Customized Flywheel:
- Dynamically prompt the correct platform modules based on the user's defined roles.
- Example: If the user's Honey Pot is Substack and Juice is LinkedIn, trigger
substack-distribution-module first, then linkedin-distribution-module. If another user uses YouTube as the Honey Pot and X as the Juice, adapt the orchestration order accordingly.
- The Vortex: Instruct the selected spoke modules to execute cross-linking and comment cascades to amplify the signal based on the user's specific platform mix.
- Squeezing Old Oranges (Amplification Sweep): Invoke the
flywheel-amplification-module to cross-link the new campaign backward into the last 3 historical campaigns, bumping old hubs and spokes with new comments to reactivate the algorithm.
- Update Ledger: Maintain the campaign tracking ledger to record execution status.
2. Safeguarding Human Trust (Scraping Invariant)
Before distributing to any channel, check the Global Channel Value Directory via brain.read("brand-amplification/campaigns/social-channel-directory.md") (Analytics Engine owns writes to this file).
- If a channel is marked ⚠️ BANNED or Low ROI, skip it.
- If a post's quality is questionable or seems promotional for strict channels, escalate to the user before publishing.
Step 0 — Context Pre-Flight (MANDATORY before any content generation)
Origin: 2026-05-05 — users cold-open with content requests (e.g., "write a LinkedIn post about my AI Fund panel") without prior session context load. The agent drafts without brand voice, IP firewall, or campaign context. The draft is generic at best, violates IP constraints at worst.
Rule: Before writing a single word of content, confirm the following files are loaded this session. If any are missing, read them silently NOW via brain.read():
| File | brain.read() path | What it provides | Fallback if missing |
|---|
professional-brand.md | brain.read("brand-amplification/identity/professional-brand.md") | Brand voice, tone, positioning, narrative pillars | Emit ⚠️ brand context missing — draft may be off-voice and proceed |
handles.md | brain.read("identity/handles.md") | Active platform handles, CTA destinations | Proceed, but omit handle-specific CTAs |
content-flywheel.md | brain.read("brand-amplification/voice-strategies/content-flywheel.md") — IP Firewall section | Terms that must NEVER appear in published content | BLOCK — cannot draft without IP firewall loaded |
| Campaign package (if distributing existing campaign) | brain.read("brand-amplification/campaigns/initiatives/<initiative-slug>/campaigns/<campaign-slug>/campaign.json") | Assets, platform copy, surface coverage matrix | Required for distribution mode; not required for fresh-draft mode |
Context load is silent — do not narrate "loading brand context…" to the user. Just load, then draft.
Litmus test: "Before I wrote the first word, did I read professional-brand.md AND the IP Firewall? If no — stop, load them, restart."
Campaign Pre-Flight Gate (MANDATORY — runs BEFORE Per-Content Gates)
Run once per campaign before distributing any component.
Exit 0 = ALL PASS. Exit 1 = BLOCK (fix and re-run). Exit 2 = WARN (review before distributing).
python3 "$(ls -v ~/.claude/plugins/cache/xos/brand-amplification/*/skills/social-distribution-engine/validate-campaign-preflight.py 2>/dev/null | tail -1)" \
/path/to/campaign.json
This meta-harness runs 10 gates in sequence:
- Planning: campaign-schema-validator, channel-status-check, surface-coverage-check
- Content: content-url-resolution-check (blocks on unresolved
[TOKEN] placeholders)
- Pre-Dist: flywheel-sequence-guard (Estate publish order), visual-asset-review-check, image-brand-completeness-gate (every image has brand signature + substantive SVG visual), golden-hour-scheduling-check (advisory — warns if scheduled_at timestamps fall outside platform golden windows: LinkedIn 07:30–09:00/11:30–13:00/17:00–18:30, X 08:00–10:00/12:00–13:00/17:00–18:00, Instagram 06:00–09:00/11:00–13:00/19:00–21:00, Substack 06:00–10:00; default timezone America/Los_Angeles)
- Semantic: campaign-estate-quality-check (LLM judge — Estate model packaging: hub-spoke routing, Post Hub hook discipline, Article Substack CTA, platform-native copy, comment cascade strategy)
- Semantic: flywheel-cta-quality-check (LLM judge — CTA strength + platform-appropriateness: Substack share specificity + mid-content forward, Article CTA placement, Post Hub tension, X link-in-reply/bookmark ask/profile-click hook, Reddit link-in-comment, Instagram bio-link/save prompt/DM-share prompt, Facebook share ask, comment cascade 2+ topic-specific keywords)
Must PASS before proceeding to per-content gates below.
Draft Handoff Gate (MANDATORY — runs BEFORE presenting any LinkedIn copy to the user)
Origin: 2026-05-14 — posts were drafted directly in conversation, bypassing BAE gates entirely. Gate 1 (structural) and hashtag selection only fired at "pre-publication" — by then the user had already seen and sometimes posted malformatted, hashtag-free copy. Root cause: two failures — (1) BAE workflow bypassed at draft time, (2) even when Gate 1 ran, hashtag_count == 0 was WARN not BLOCK.
Rule: Before handing ANY LinkedIn post copy to the user, this agent MUST:
Step A — Auto-select hashtags (MANDATORY, no exceptions)
Read the hashtag bank from platforms.json _hashtag_banks.linkedin_post. Apply hashtags in priority order as declared in slot_fill_order within that JSON key. Priority criteria (in descending precedence): brand alignment first → campaign relevance second → topic specificity third → reach/highway last. Fill up to hashtag_max: 5. Any tier defined in the hashtag bank is valid if it satisfies the relevance criterion for its declared priority level — including tiers not yet named here (e.g., event tags, partner tags, trending tags).
Append selected hashtags at the end of the post body (never in the body). Platform rule: hashtags in body on LinkedIn are penalized — append only.
No hashtag count can be zero. A LinkedIn post with 0 hashtags is a Gate 1 WARN that must be fixed before handoff. Minimum 3 (brand + 1 niche + 1 highway).
Step B — Run Gate 1 inline before handoff
Run post_validator.py against the draft. If result is fail: fix all violations, re-run, then present fixed copy. If result is warn: surface the warnings as a footnote under the copy so the user can make an informed decision — but present the copy anyway. Never silently skip this step.
python3 "$(ls -v ~/.claude/plugins/cache/xos/brand-amplification/*/skills/social-distribution-engine/post_validator.py 2>/dev/null | tail -1)" \
--platform linkedin_post \
--text "<post body including appended hashtags>"
Litmus test: "Before I handed this LinkedIn copy to the user — did I auto-select hashtags AND run Gate 1? If no to either — I handed over untested copy."
Pre-Publication Gate (MANDATORY)
Every piece of content must pass both gates before status: ready or any publish action.
Skipping either gate is a Ground Zero violation (Irreversible-Action Invariant — LinkedIn cannot un-send, Substack newsletters reach all subscribers).
Gate 1 — Structural (post_validator.py)
Checks character limits, markdown bleed, pipe characters, HTML, URL suppression, promo language.
python3 "$(dirname "$0")/post_validator.py" \
--platform linkedin_post \
--text "<post body>"
Exit 0 = PASS. Exit 1 = FAIL (hard block — revise before Gate 2). Exit 2 = WARN (review then proceed).
Gate 2 — Semantic (social-content-readiness-check)
Runs three parallel LLM judges (tone/authenticity, IP/patent firewall, narrative clarity) plus metadata completeness. Uses OAuth CLIs — no API key required (claude → gemini → codex fallback chain).
GATE=$(ls -v ~/.claude/plugins/cache/xos/career-intelligence/*/rules/social-content-readiness-check/HOW.py 2>/dev/null | tail -1)
if [ -z "$GATE" ]; then
echo '{"verdict":"BLOCK","reason":"social-content-readiness-check script not found — plugin may need reinstall","remediation":"Run: claude plugin update career-intelligence@xos --scope user"}'
exit 1
fi
python3 "$GATE" \
'{"text":"<post body>","platform":"linkedin","title":"<campaign title>","metadata":{"audience":"<target audience>","surface_coverage_matrix":"<path or description>"}}'
Exit 0 = PASS → ship. Exit 1 = BLOCK → revise and re-run both gates. Exit 2 = WARN → surface to human for approval before ship.
Gate sequence: Gate 1 must PASS before running Gate 2. A Gate 1 FAIL is not forwarded to Gate 2.
CI / no-key environments: Set SKIP_LLM_JUDGES=1 to bypass the LLM panel (Gate 2 returns WARN, not BLOCK). Gate 1 always runs. Human review is required before ship when running in CI mode. To enable LLM judges in CI, set ANTHROPIC_API_KEY as a GitHub Actions secret and omit SKIP_LLM_JUDGES.
Gemini auth: ~/.gemini/settings.json must have a valid auth type. If gemini times out, it is skipped and the ip_safety judge falls back to claude. To fix: set GEMINI_API_KEY in ~/.claude/settings.json env section or run gemini auth login to switch to OAuth.
Per-Content Publish Gates (MANDATORY — run immediately before each publish action)
These gates fire per-content-piece, after the Campaign Pre-Flight passes. Each is a one-way-door guard: publishing is irreversible, so the gate must pass before the agent touches any publish UI or API.
Run order: Pre-Flight → (for each component) Per-Content Gate → Pre-Publication Gate → PUBLISH.
Substack Publish Gate
When: Any Substack post that triggers an email send to subscribers. Also fires on republish/resend actions.
GATE=$(ls -v ~/.claude/plugins/cache/xos/brand-amplification/*/rules/substack-publish-gate/HOW.py 2>/dev/null | tail -1)
python3 "$GATE" '{
"platform": "substack",
"action": "publish",
"is_email_send": true,
"is_resend": false,
"email_send_confirmed": false,
"post_title": "<title>",
"post_excerpt": "<first ~500 chars of body>",
"word_count": <N>,
"has_hook": true,
"has_cta": true,
"section": "<Substack section name — omit for single-section publications>",
"tags": ["tag1", "tag2", "tag3"]
}'
email_send_confirmed must be explicitly set to true by the human in the current turn. Standing approvals do not cover email sends. is_resend: true is always BLOCK — no exceptions.
Gates: resend_block (inviolable) → email_send_gate (human confirmation) → completeness (≥300 words + hook + CTA) → metadata (section + tags — WARN if absent on email sends) → quality (LLM judge on excerpt).
Exit 0 = PASS (safe to publish). Exit 1 = BLOCK.
LinkedIn Article Publish Gate
When: Before publishing or updating a LinkedIn Article (Pulse article).
GATE=$(ls -v ~/.claude/plugins/cache/xos/brand-amplification/*/rules/linkedin-article-publish-gate/HOW.py 2>/dev/null | tail -1)
python3 "$GATE" '{
"platform": "linkedin_article",
"article_title": "<title>",
"article_content": "<full article body>",
"article_excerpt": "<first ~500 chars>",
"char_count": <N>
}'
Gates: placeholder_block (REPLACE_ tokens) → backlink_check (missing Substack/honey-pot CTA) → cta_check (weak or missing CTA) → quality (LLM judge on excerpt).
Exit 0 = PASS. Exit 1 = BLOCK.
LinkedIn Post-on-Article Gate
When: Before publishing the LinkedIn hub post that shares a LinkedIn Article URL. This is the spoke post in the hub-spoke flywheel (the "Post Hub").
GATE=$(ls -v ~/.claude/plugins/cache/xos/brand-amplification/*/rules/linkedin-post-on-article-gate/HOW.py 2>/dev/null | tail -1)
python3 "$GATE" '{
"platform": "linkedin_post",
"post_body": "<full post body>",
"article_url": "https://www.linkedin.com/pulse/..."
}'
Gates: external_link_in_body (non-linkedin.com URLs = BLOCK) → article_url_format (must be linkedin.com/pulse/) → placeholder_in_post (REPLACE_ tokens = BLOCK) → hook_visibility (first line < 10 chars = WARN).
Exit 0 = PASS. Exit 1 = BLOCK. Exit 2 = WARN.
X CTA Resolution Gate
When: Before publishing an X (Twitter) thread as part of a campaign. Validates that CTAs are in the reply tweet, not the thread body.
GATE=$(ls -v ~/.claude/plugins/cache/xos/brand-amplification/*/rules/x-cta-resolution-gate/HOW.py 2>/dev/null | tail -1)
python3 "$GATE" '{
"platform": "x_thread",
"thread_tweets": ["Tweet 1 text", "Tweet 2 text", "..."],
"reply_tweet": "Full piece: https://substack.com/...",
"hashtags": ["#tag1", "#tag2"]
}'
Gates: external_link_in_thread_body (URLs in main tweets = BLOCK, move to reply) → cta_in_reply (reply must exist + contain URL) → placeholder_check (REPLACE_ tokens = BLOCK) → hook_strength (first tweet < 50 chars = WARN).
Exit 0 = PASS. Exit 1 = BLOCK. Exit 2 = WARN.
Execution Flow
- Pre-flight: Run
validate-campaign-preflight.py once for the entire campaign. BLOCK = fix before proceeding.
- Per-component: For each content piece, run the appropriate Per-Content Publish Gate above before touching any publish UI.
- Pre-publication: Run Gate 1 (structural post_validator.py) → Gate 2 (semantic social-content-readiness-check) on the final copy.
- Act: Trigger Platform Modules. Human approves each send — no standing approval covers irreversible sends.
- Observe: Modules execute using current algorithmic rules.
- Measure: Hand off to the Distribution Analytics Engine after a window to collect data.
- Learn: Use updated insights for the next campaign.