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.

Once it's connected and tuned, the system runs itself — a post or so a day, drawn from real data, published while you sleep. This page is the reference for how it behaves day to day and how to keep it healthy.

This page vs. the Playbooks. Here you'll find how the system behaves and how to keep it healthy — the operating reference. For numbered, step-by-step procedures with exact commands (connect an account, approve a post, change cadence, stop everything), see playbooks.html. When a task below needs real steps, we link straight to the relevant playbook rather than restating the commands.

A day in the life

There is almost nothing to do on a normal day. That's the point. Every night a short chain of scheduled jobs wakes up, reads fresh data off the website network, drafts finished posts from that data using fixed templates, and publishes whatever is due. By morning a new post (or two) has gone out, the logs have advanced, and no alert has fired. You can go days without touching it.

Your job as operator is not to run the machine — it's to watch that it's running, glance at what it's saying, and keep the one paid channel topped up. Think of it like a well-behaved appliance with a pilot light: you check the flame occasionally, you don't stand over it.

~1/day
posts, healthy pace
$24/mo
whole system
5
nightly jobs
0
alerts = all well

The nightly schedule

Five scheduled jobs make up the chain. They run in a deliberate order every night (all times UTC): MAIN builds the feed first and ships it over, then the hub drafts from it, publishes what's due, and writes a digest. Publishing runs on its own short loop all day so posts go out on time, not just at night.

Time (UTC)ServerJobWhat it does
04:17HUBbackup.shNightly backup — database, portal data, and config, copied off-box to cloud object storage.
05:00MAINgen-social-feed.pyBuilds the content feed from real network data and ships it to the hub at /opt/portal/listings/wholetech.json.
05:10HUBgenerate.pyDrafts posts from the fresh feed items + templates into the queue (portal.db).
every 10 minHUBpublish_due.pyPublishes anything that's due — respects the X daily cap and the PAUSE kill switch.
05:20HUBreport.pyWrites the digest of what went out and what's queued.
Why the order matters. The feed must land on the hub before the drafter runs, which is why MAIN goes at 05:00 and the hub drafter at 05:10. The 10-minute publish loop is separate on purpose — it lets a post scheduled for, say, 14:00 go out at 14:00 rather than waiting for the next nightly pass.

What normal looks like

Healthy is quiet. If you want a one-line mental model of a good day, it's this: a post or so went out, the logs moved forward, and your phone stayed silent. Here's what each of those means concretely.

The signs of a healthy system

  • Output is trickling, not flooding. Roughly one post a day at the default cadence (7 posts kept in flight ≈ one per day). Not zero for a week; not a burst of ten in an hour.
  • The logs are advancing. Each nightly job appends fresh, recent timestamps to its log. Yesterday's date at the bottom of portal-gen.log means the drafter ran; today's entries in portal-pub.log mean posts are going out.
  • No ntfy alerts. The system pushes a phone notification only on failure. Silence is success — a quiet channel means every job finished clean.
  • The digest reads sensibly. The morning report shows a handful of posts published and a queue with more waiting, and few or no items HELD for missing facts.
  • Bluesky always moves. Bluesky is free and uncapped, so it keeps posting even if X has hit its daily cap or run out of credit. If Bluesky went quiet, something upstream stalled — that's a real signal.
The honesty guard at work. Seeing a post marked HELD is not a bug — it's the system refusing to state a fact it couldn't verify from source data. A steady trickle of HELD items just means the guard is doing its job. It only warrants attention if everything is being held (see troubleshooting.html).

Monitoring & logs

Everything the system does leaves a trail in a plain text log. When you want to know what happened last night, you read a log — no dashboard required. Four logs cover the whole chain; one lives on MAIN, the rest on the hub.

Log fileServerWhat it shows
/var/log/social-feed.logMAINThe feed build — which real data was gathered and whether the feed shipped to the hub.
/var/log/portal-gen.logHUBThe drafter — how many posts were written into the queue, and what was HELD for missing fields.
/var/log/portal-pub.logHUBPublishing — what went out, to which channels, and any X-cap or PAUSE skips.
/var/log/portal-rep.logHUBThe report run — confirmation the digest was written.

A quick health glance

ssh root@64.227.29.192           # into the hub
tail -n 20 /var/log/portal-pub.log   # did posts go out?
tail -n 20 /var/log/portal-gen.log   # did drafting run, anything HELD?
ntfy failure alerts. You don't have to watch the logs to catch a problem. The system pushes a notification to a phone channel via ntfy the moment a job fails. Treat an alert as your cue to open the matching log above and read the last few lines — that's usually enough to see what broke.

The kill switch

There is one file that stops everything: /opt/portal/PAUSE. If that file exists, publish_due.py publishes nothing — on every channel, for every tenant, immediately. Drafting and reporting still run; only the outbound door is shut. It is the safest, fastest thing you can do when you're unsure.

Stop and resume

touch /opt/portal/PAUSE   # freeze ALL publishing, instantly
rm /opt/portal/PAUSE      # resume — the next 10-min loop picks up

Because the publish loop checks for that file every ten minutes, the pause takes effect within minutes and nothing is lost — queued posts simply wait. When you remove the file, the next loop resumes as if nothing happened. No accounts are disconnected, no data is deleted, no credit is spent while paused.

When to use it. Reach for the kill switch any time you're not sure something is right: a template looks wrong, a data source seems off, an account may be compromised, or you're about to make a change and want everything still while you work. It is total and instant — there is no faster way to make the system quiet. Full steps in Playbook 10.

Cost control, in depth

The whole system costs $24/month — that's the hub droplet, and it doesn't climb as you add sites, clients, or posts. This is the economic heart of the design: because content is generated from fixed templates filling verified fields, there is no per-post AI billing. Drafting one post and drafting a thousand cost exactly the same — nothing. The system runs on a flat subscription and never uses per-token AI billing. That's a hard rule, not a preference.

The one paid channel

The single place money moves is X / Twitter. Since the free tier closed in February 2026, X charges roughly 1.5 cents per post, or about 20 cents for a post carrying a link. A $25 credit is loaded to cover it. Every other connected channel — Bluesky today, Mastodon, LinkedIn, and Meta when connected — is free.

ItemCostNotes
Hub droplet~$24/monthFlat — does not grow with scale.
Content generation$0Template-based; no AI billing, ever.
Bluesky (and other free channels)$0Uncapped — keeps posting always.
X post (text)~1.5¢ eachOnly paid channel; capped — see below.
X post (with a link)~20¢ eachLinks cost more on X.

The X daily cap

Auto-fire is made safe by a hard limit in publish_due.py: X_DAILY_CAP = 3. No more than three paid X posts go out in a day, no matter how full the queue is. Bluesky and the other free channels are unaffected — they publish uncapped. So even a runaway queue can't run up a bill; the worst case is three X posts a day.

Going fully free. If you'd rather spend nothing at all, drop X from a tenant's channel list and keep only free channels like Bluesky. Output continues exactly as before, at zero cost. X is opt-in spend, not a requirement — the system is fully useful without it. To watch or adjust X spend, see Playbook 16.

Tuning the cadence

Cadence is the number of posts the system keeps in flight for a tenant — roughly, 7 keeps about one post a day. It's the main dial you'll ever turn, and the right setting depends on what the account is for.

Reviving a quiet account

If you're bringing a dormant account back to life, resist the urge to blast. A sudden flood of posts on a long-silent handle reads as spammy to both the audience and the platform. Start gentle — a low cadence, one post a day or fewer — and let it build a rhythm before you turn it up. Steady beats sudden.

Feeding an active account

An account that's already busy and has an engaged audience can carry more. Raise the cadence so the queue stays full and the account posts consistently. Keep an eye on the mix, though — more volume draws more from the four content families, so make sure there's enough real data (site features, tips, milestones, spotlights) to keep it varied rather than repetitive.

Rule of thumb. New or reviving → low and steady. Established and engaged → higher, watching variety. And remember the X cap sits underneath all of this — raising cadence sends more to the free channels first; paid X stays capped at three a day regardless. Step-by-step in Playbook 4.

The operator's routine

You don't need a daily ritual — the system is built to be left alone. But a light weekly touch and a slightly deeper monthly one keep it healthy and let you spot anything drifting before it matters.

Weekly — a few minutes

  1. Skim the recent logs (portal-pub.log and portal-gen.log) — confirm posts went out and drafting ran.
  2. Glance at what actually got published — do the posts read well and stay on-brand?
  3. Check the X credit if you're using X — top up before it runs dry if you want it to keep posting.
  4. Read the latest digest report for anything unusual (a spike in HELD items, an empty queue).

Monthly — a deeper look

  1. Review the last month's output as a whole — is the cadence and mix still right for each account? Tune if needed.
  2. Verify backups are landing off-box — confirm recent, dated backup entries exist (see security.html).
  3. Review the tenant list and any pending platform connections — anything worth finishing (Mastodon, LinkedIn, Meta)?
  4. Confirm the free channels are healthy and the paid X spend is where you want it.
Silence is fine. If a week passes with no alerts and the posts look good, there is genuinely nothing to do. The routine is a safety net, not a chore — skipping a light week won't break anything.

Capacity & limits

One hub handles far more than a single account. It's already running the owner's own network — drawing content from 177 network sites and a 47-skill marketing library — alongside separate client tenants, each isolated with its own accounts, cadence, content, and approval setting. Because content generation is free and deterministic, the drafting side has effectively no ceiling: it can write a thousand posts as cheaply as one.

The real limits are the sensible ones, not compute:

  • Paid X output is capped at three posts a day per the cap — a cost guardrail, not a technical one.
  • How much real data exists to draw from — the honesty guard won't invent filler, so genuine variety comes from having enough source material across the four families.
  • MAIN is memory-constrained, which is exactly why the publishing brain lives on a separate hub. Keeping the two jobs split is what lets the hub scale without straining the network server.

In practice, one $24/month hub comfortably serves the owner's network plus a roster of clients — and the cost of adding another tenant is essentially zero. That flat economics is the whole point: scale doesn't raise the bill.

Common day-to-day tasks

Most of what you'll ever want to do maps to one playbook. Use this as a quick "I want to…" index — each row links to the exact steps.

I want to…Go to
Connect a new social accountPlaybook 1
Approve, edit, or skip a post before it goes outPlaybook 3
Post something right nowPlaybook 5
Change how often an account posts (cadence)Playbook 4
Turn a channel on or off for a tenantPlaybook 6
Preview what would go out before it doesPlaybook 9
Stop all publishing immediatelyPlaybook 10
See what has been publishedPlaybook 11
Watch or adjust X spendPlaybook 16
Refresh the feed / content sourcesPlaybook 8
When something's actually wrong. If a job failed, a log looks stalled, or posts stopped when they shouldn't have, head to troubleshooting.html — it walks the known failure modes (Temporal down, HTTPS cookie, database locked, X credit empty) and how to recover from each.