User Manual · 04 · Daily Operations
WholeReach — Automated Marketing System

Daily Operations

Running the machine day to day: the schedule, the kill switch, cost control, cadence, logs, and manual posting.

Looking for the how-to?This page is the day-to-day reference. For numbered, step-by-step procedures with the exact commands, see Playbooks.

The daily schedule

Time (UTC)WhereJobDoes
05:00maingen-social-feed.pyBuild the day's content feed, ship to hub
05:10hubgenerate.pyTurn feed into scheduled posts
*/10 (every 10 min)hubpublish_due.pyPublish anything due
05:20hubreport.pyWrite the digest
04:17hubbackup.shBack up the hub

The kill switch

Freeze all posting instantlyCreate one file and nothing publishes on any tenant until you remove it:
# stop everything
ssh root@64.227.29.192 touch /opt/portal/PAUSE

# resume
ssh root@64.227.29.192 rm /opt/portal/PAUSE

The publisher checks for this file first, every run. Use it any time something looks wrong — it is instant and total.

Cost control

The whole system costs $24/month to run (the hub server). Content generation is free. The only per-post cost is X.

ControlSettingEffect
Facebook & Instagram—Free to post. No cap is applied, deliberately — throttling a free channel only costs reach.
X daily capX_DAILY_CAP in publish_due.py (default 3)Never more than N paid X posts/day; Bluesky is unaffected and free.
Cadencecadence per tenant in clients.jsonHow many posts a tenant keeps in flight (~1/day at 7).
Channelschannels per tenantDrop "x" to go 100% free.
Hard ruleThe system runs on a flat subscription. It never uses per-token AI billing — content is template-generated, so audits and scale can't blow a budget.

Changing cadence or channels

# edit the tenant config on the hub
ssh root@64.227.29.192 nano /opt/portal/clients.json
# then regenerate (safe to run anytime)
ssh root@64.227.29.192 python3 /opt/portal/generate.py

Set "require_approval": true to route a tenant through the approval queue instead of auto-posting.

Posting on demand

To push something immediately, add it to the queue with its time set to now and run the publisher:

ssh root@64.227.29.192 python3 /opt/portal/publish_due.py

The publisher processes any post whose scheduled time has passed.

Monitoring & logs

LogWhat
/var/log/social-feed.logNightly feed build (main droplet)
/var/log/portal-gen.logPost generation
/var/log/portal-pub.logPublishing results + live URLs
/var/log/portal-rep.logReports

Failures also push a phone notification via ntfy, so you hear about a problem without watching logs.