Where social automation actually stands — wired vs configured vs live, per channel and per loop, with the gaps named honestly.

Status

Last verified: 2026-07-26 (against Vercel production env and live endpoint probes).

The code is in good shape. The configuration is not. This page exists because the overview describes what the pipeline can do, and it is easy to read that as what it is doing. It isn't — yet.

One-line summary: 1 of 9 channels is live, 1 of 3 loops works, and the daily cron has been a no-op since it shipped.

Three words that mean different things

TermMeans
WiredThe code path exists and is tested
ConfiguredCredentials are present in Vercel production
LiveA post can actually reach the platform

Most of the gap on this page is between wired and configured. That is the good kind of gap — it closes with credentials, not engineering.

Channels

ChannelWiredConfiguredLiveBlocker
Facebook — hogwarts · mkan · databayt
TelegramBot exists and is valid, but its token was never pushed to Vercel and no TELEGRAM_CHANNEL_ID exists anywhere
Slack (via Hermes)No HERMES_API_URL in production — and Hermes is down
Facebook — sijillee · moalimeeNo Facebook Page created yet
Instagramregistry onlyBusiness account + App Review
LinkedInregistry onlyCommunity Management API approval
Xregistry onlyPay-per-use since Feb 2026 — needs /decide
TikTokregistry onlyFull app audit, 1–4 weeks
Snapchatregistry onlyAllowlist-only via a Snap contact
WhatsAppregistry onlyNo organic posting API exists

Live: 1 of 9 channels, for 3 of 5 brands.

Telegram is the notable one. It is free, has no platform gate, the bot already exists and answers getMe, and the code has been ready since 2026-07-10. It is switched off for want of two environment variables. Setup steps: Telegram guide.

Loops

The three publish paths are described in Architecture & Loops. Their current state:

LoopStateWhy
A — HubWorks (Facebook only)The one working path. Compose in /social, publish directly.
B — CronDead — three independent blockersSOCIAL_AUTOPOST_PRODUCTS is unset, so the cron is a no-op. ② Even if set, SOCIAL_DRAFT_SOURCE defaults to hermes, which Vercel cannot reach. ③ Even if a draft existed, no review destination is configured, so sendReview fails.
C — Hermes relayUnverifiedThe endpoint is deployed and authenticating, but Hermes is currently down and this path has never been observed end to end.

Both /api/social/cron and /api/social/relay return 401 to an unauthenticated request — which confirms they are deployed and CRON_SECRET is set. The cron fires daily at 06:00 UTC and returns drafted: 0.

What's done

  • Egress — per-channel results, three transports in parallel, media through the whole chain (Facebook /photos, Telegram sendPhoto, media signed into the approval token)
  • Per-product Facebook — its own Page and permanent token per brand, with the resolved Page name shown before you publish, which is how a crossed token gets caught
  • Registry — 5 products × 9 channels, AND-gated so a channel is publishable only when the transport and that brand's destination are both wired
  • Approval — signed HMAC links, 12h TTL, contributor re-checked inside every mutating action
  • Hub — bilingual en/ar with RTL, Server-Component header, one-round-trip status probe
  • Docs — overview, architecture, strategy, five brand pages, and the channel guides

What's not

  • Configuration — the largest gap and the cheapest to close. Being handled by Cowork, which can drive the platform consoles directly.
  • Hermes — down, no production config, and the outbound draft lane dead-ends silently when it is.
  • Measurement — half available, and the blocked half is a permissions problem, not an engineering one.
    • UTM tagging works. Every outbound link is tagged at delivery with utm_source=<channel>, utm_medium=social, utm_campaign=<brand>, so traffic is attributable at our own site — which is the only lane that does not depend on a platform choosing to share numbers. Already-tagged links are left alone.
    • Platform-side numbers are not fetchable. The Facebook Page token carries pages_show_list, pages_read_engagement, pages_manage_posts. Reading impressions additionally needs read_insights; reading reactions, comments and shares needs pages_read_user_content. Neither is granted, so a metrics job would return errors on every call — it is deliberately not built until the scopes exist.
    • No analytics destination. There is no PostHog dependency or key in the app, so nothing consumes the UTMs yet. The tags are still worth having: they are recorded in the platform link and in any downstream analytics added later.
    • SocialMetric exists and externalId is populated, so posts are addressable the moment the scopes land.
  • Scheduling — the queue exists (SocialPiece / SocialVariant / SocialMetric on Neon, added 2026-07-26) and approval links are now single-use, but nothing drains scheduledFor yet, so there is still no way to pick a date and time.
  • Metrics — the table is there; nothing writes to it.
  • Variant-awareness — the cron drafts one text and fans it to every channel, which contradicts the one core piece → N platform-native variants multiplier the strategy depends on.

The honest constraints

Hermes flaps. Vercel can never call into it — it listens on localhost with no public route — and it will be up and down unpredictably. So kun is the source of truth and Hermes is a client that pulls work and pushes results. Any design where kun must reach Hermes to make progress is the wrong shape.

Which makes persistence load-bearing. Today, a Hermes outage during the 06:00 cron loses that day's draft outright. With a queue, it just waits.

Scheduling can't ride on Vercel cron. A drain needs to run every few minutes; cron granularity is a plan-tier limit and kun already uses a slot. GitHub Actions is free, runs at ~5-minute granularity, and the endpoints are already bearer-token authenticated for exactly this — so it also keeps a Vercel Pro upgrade off the critical path.

Highest-leverage next moves

Ordered by value ÷ cost, not by size:

  1. Three environment variables revive an entire loop. A review destination, a draft source, and an opt-in list turn Loop B from dead to working. No code.
  2. Turn Telegram on. Free, instant, no gate, bot already exists — doubles the live-channel count.
  3. Wire measurement. The strategy sets kill criteria at "zero signal after 3 months of consistent posting." That decision cannot currently be made, because nothing is measured.
  4. Add persistence. Unlocks scheduling, single-use approvals, metrics, and Hermes flap-tolerance in one move.

See also