tootsies

a discord bot for the tootsies server. ask, recap, discuss, ship features by typing.


Project maintained by mejasonmejason Hosted on GitHub Pages — Theme by mattgraham

X (@tootsiesbar) growth roadmap: 18 → 100 followers

Focus lanes: music, pop culture, sports (the bio already says it: “music, pop culture, and sports served neat”). Goal: a compelling account that earns 100+ followers. Every number below is measured (live account + Axiom + the live DB), and every work item names its exact lever — file, function, env var, config page, or owner action.

1. Measured baseline (2026-07-29)

The account (twitterapi.io user/info + last_tweets)

Fact Value
Created 2026-07-20 (9 days old)
Followers / following 18 / 100
Total posts 1,204 (932 with media)
Tier X Premium (subscription_type=Premium, 25k-char cap)
Pinned tweet none
Views per tweet (last 20) 0–20, median ~3
Likes per tweet (last 20) 0 (one tweet: 1 like)

Output volume (Axiom crosspost, delivered=posted)

Per day, last 7: 178 · 135 · 105 · 135 · 128 · 135 · 138 (avg ~136/day).

Per surface (3d): sports_desk 77 · music_alert 62 · cinema_news 51 · pop_desk 45 · music_news 39 · music 32 · discourse 29 · market_alert 26 · bet_board 16(+32 skip) · market_drop 13 · music_desk 12 · cinema_desk 9.

Write modes (Axiom tweet_posted, 3d)

media 387 ok · upload 355 ok · tweet 52 ok · upload_video 48 ok · like 31 ok · quote 28 ok / 17 rejected (38% fail — the #1575 third-party 403) · reply 3 ok / 1 fail (own-thread only; replies to non-mentioners are tier-blocked, #1732).

The game (Axiom x_game_round / x_game_answer)

64 rounds opened in 7d (~9/day). 3 correct answers in 30 days.

The exact config producing this (live settings rows, master guild 1482402399342825522)

Setting Current value
hours_start_et / hours_end_et 0 / 23 — the bot posts 24/7
scheduler_firehose_surfaces 9 surfaces on the every-30-min firehose: cinema_desk, cinema_news, curator, discourse, market_drop, music_desk, music_news, pop_desk, sports_desk
scheduler_firehose_hourly_surfaces music (hourly)
post_schedule (calendar) yaps: 12× market_drop + 11× x_game; chill: 6× x_game (17 game slots/day)
x_crosspost_surfaces (X picker) music, music_news, discourse, market_drop, market_alert, cinema_desk, pop_desk, sports_desk, cinema_news (bet_* already off X)

So the ~136/day isn’t a bug — it’s 9 firehosed surfaces × 24/7 working hours, mirrored to X, thinned only by each surface’s own self-gate/dedup.

2. Diagnosis

  1. Firehose to nobody. X ranks by engagement rate. 136 posts/day at 0–20 views each trains the algorithm the account is noise → suppressed distribution → zero engagement → repeat. Volume is actively hurting.
  2. Wire service, not a person. One hour of timeline: WNBA box score → Chelsea keeper loan → Luminate units → Netflix leaderboard %. No legible identity to follow. Most takes read as AP copy; the one post in the sample that earned a like was the one with a voice (“Come & Talk to Me still clears a room thirty-five years later”).
  3. Zero discovery loops. Sub-1k accounts get found in the quotes tab of viral posts, in replies, in trends, in communities, or by referral. We use none: API replies to third parties 403, wire desks post standalone photos (no quote → no quotes-tab presence), nothing names a trend, the Discord was never recruited.
  4. A game with no audience. 9 unanswered rounds/day is noise; games amplify an audience, they don’t create one.

3. Target state (exact)

≤ 25 X posts/day, budgeted per surface, every post the surface’s best:

Surface (X) Budget/day Notes
pop_desk 4 breaking + biggest lanes
sports_desk 4 breaking + biggest lanes
music (drops + alerts + desk, one toggle group) 5 the alert stream is today’s 21/day — the budget forces best-of
music_news 3  
cinema_news 3  
discourse (trending reacts) 2  
x_game 2 rounds (≈5 writes: 2 opens + boards/reveals) 12:30 + 20:30 ET
trend beat (new, Phase 5) 2 11:00 + 19:00 ET
Total ≈ 23–25 writes/day verified by the APL query in §10

market_drop + market_alert: off X entirely (Kalshi swings are room content). Discord rooms keep their current firehose untouched — the budgets live X-side only.

Follower ladder (dated): ≥35 by Aug 5 · ≥45 by Aug 12 · ≥70 by Aug 26 · 100+ by Sep 9. Each gate blocks the next phase until telemetry (§9) explains a miss.


4. Phase 0 — config + owner actions (today, ~30 min, no code)

0.1 X picker trim (/menu → experiments page → x_crosspost picker): uncheck market_drop and market_alert. Saves ~13 posts/day immediately (39/3d measured).

0.2 Firehose off → packed calendar cycle (owner decision 2026-07-29). Clear scheduler_firehose_surfaces + scheduler_firehose_hourly_surfaces and pack the calendar grid instead. Recommended ratio over a 28-slot day (working hours trimmed to 10:00–24:00 ET — overnight slots earn zero US engagement; if hours stay 24/7, keep this same ratio in the daytime block and give overnight slots only to the Discord-only surfaces):

Surface Slots/day Placement notes
pop_desk 4 spread 11:00–22:00, one in 18:00–21:00 prime
sports_desk 4 one near lunch, two in the 19:00–23:00 game window
music (drops) 3 mid-morning, afternoon, evening
music_news 3  
music_desk 2  
cinema_news 2  
cinema_desk 2  
discourse (trending reacts) 3  
x_game 2 12:30 + 20:30 ET (US lunch + prime)
curator (Discord-only on X picker) 2  
market_drop (off X) 1  
Total 28 X-mirrored ≈ 25 writes/day incl. game boards

In ratio terms: pop : sports : music-group : cinema : discourse : game ≈ 4 : 4 : 8 : 4 : 3 : 2, plus 3 Discord-only slots. The remaining X-side leak is the event-driven music_alert stream (rides the music toggle, ~21/day measured) — cap it via its tunable or let the Phase 1a budget close it.

0.3 Discord recruit (owner). One announcement in the master guild: follow @tootsiesbar, tap the notification bell, like/reply when you see her — first-hour engagement is what buys distribution. Target: +15–25 followers from the server by Aug 5. Optional: X game wins get a server shoutout.

0.4 Pin an intro tweet (owner, 5 min). In her voice: who she is, what the account serves, the Discord link. No pinned tweet exists today.

5. Phase 1 — the two first code PRs (this week)

1a. Per-surface X daily budgets + score floor (the durable volume fix)

1b. Reply drafts — the hand-off loop (SHIPPED with this PR; owner steer 2026-07-29)

The account’s API tier can’t reply to third-party tweets (#1732), but the owner can — and replies are the one discovery channel that grows a sub-100 account. So Toots does the drafting, the owner does the posting, and X stays visually unchanged:

(The earlier “reply-scout” variant — proactively hunting posts she has NOT already covered, 3×/day into the discourse channel — stays in the backlog as a follow-up once the draft loop proves out; the drafts cover her already-sourced topics first.)

6. Phase 2 — mentions responder (week 2: broadcast → conversation)

7. Phase 3 — ride other audiences (weeks 2–4)

3a. Quote-first breaking lane — REJECTED (owner steer 2026-07-29). Quotes weren’t earning traction when on, and visually they read dead-similar to the tweet they quote — a bad look. The owner replies manually instead, powered by the 1b draft loop. (Kept here so the decision is on record; don’t re-propose.)

3b. In-lane follow-on-amplify. When a quote ships, follow the quoted account if in-lane, capped 8/day (durable counter). Follow-backs are real at this size; aggressive following is a suspension vector, so the cap is hard.

3c. Communities dry run. POST /2/tweets accepts community_id; write scripts/dryrun_x_community.py, post one test into a large music Community. If the tier 403s, the item dies; if it lands, wire community_id through XPoster.post_tweet and give the x_game 12:30 round a Community home.

8. Phase 4 — every post earns its slot (weeks 3–4)

4a. “Take, not headline” X prompt pass. The desks’ compose prompts get an X-side nudge: lead with the verdict in her voice; a box score is garnish, never the lead. Measured by §9’s per-surface views.

4b. Weekly thread. One music/pop deep-dive thread per week (reply-to-self works; Premium longform distributes). Anniversary, chart story, sample-lineage.

4c. Polls. POST /2/tweets supports polls — “which album wins the week” / “who takes tonight” — small XPoster addition, 2–3/week.

9. Phase 5 — telemetry (ships alongside Phase 1, decisions come from it)

10. Verification queries (Axiom APL)

# posts/day (acceptance for Phase 0/1: ≤25)
['tootsies'] | where event == 'crosspost' and delivered == 'posted' | summarize count() by bin(_time, 1d)

# per-surface budget adherence + skip reasons
['tootsies'] | where event == 'crosspost' | summarize count() by surface, delivered, reason

# mention-responder volume
['tootsies'] | where event == 'x_mention_reply' | summarize count() by bin(_time, 1d)

# audience curve (once x_audience ships)
['tootsies'] | where event == 'x_audience' | project _time, followers, views_median, engagement_rate

11. Cost + risk

12. Sequenced backlog (→ epic #1793)

# Item Phase Effort Type
1 X picker: market_drop + market_alert off 0.1 2 min /menu config
2 Firehose off → packed calendar per the §4 ratio 0.2 15 min /menu config (owner)
3 Discord follow campaign + pinned intro tweet 0.3–0.4 30 min owner
4 Per-surface X budgets + 0.75 score floor 1a S–M code (utils/x_crosspost.py)
5 Reply drafts under every linked tweet — SHIPPED 1b cogs/x_reply_draft.py
6 X mentions responder (standing rule → /ask → in-thread) 2 L code (cogs/x_mentions.py)
7 Quote-first breaking lane 3a rejected (owner steer)
8 Follow-on-amplify, 8/day cap 3b S code
9 Communities dry run → community_id 3c S script, then S
10 “Take, not headline” X prompt pass 4a S prompt
11 Weekly thread surface 4b M code
12 Poll support + 2–3 polls/week 4c S–M code
13 x_audience + x_surface_perf telemetry + ops line 5 M code
14 Trend beat (2/day, names the trend) 5 M code
15 Reply-scout (posts she has NOT already covered) later M follow-up to 1b