1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# =============================================================================
# Tuitbot Configuration
# =============================================================================
#
# Tuitbot is an autonomous X (Twitter) growth assistant for founders
# and indie hackers.
#
# Setup:
# 1. Copy this file to ~/.tuitbot/config.toml
# 2. Fill in your X API credentials (get them at https://developer.x.com)
# 3. Add your LLM provider API key
# 4. Customize the business profile for your product
# 5. Run: tuitbot auth
# 6. Run: tuitbot test
# 7. Run: tuitbot run
#
# All fields shown here use their default values unless marked REQUIRED.
# Uncommented fields with placeholder values must be filled in.
# =============================================================================
# --- Approval Mode ---
# Enabled by default. Posts are queued for human review before posting.
# Use `tuitbot approve` or the dashboard's Approval Queue to review items.
# Set to false only after you've reviewed enough drafts to trust the AI's tone.
# approval_mode = true
# --- X API Credentials ---
# Get your credentials from https://developer.x.com/en/portal/dashboard
[]
# REQUIRED: Your OAuth 2.0 client ID.
= "your-client-id-here"
# Optional: Client secret (only needed for confidential clients).
# client_secret = "your-client-secret-here"
# --- Authentication Settings ---
[]
# Auth mode: "local_callback" (auto-catch via local server) or "manual" (paste code from browser).
= "local_callback"
# Host for the local callback server (used in local_callback mode).
= "127.0.0.1"
# Port for the local callback server.
= 8080
# --- Business Profile ---
# Describe your product so Tuitbot can find relevant conversations
# and generate on-brand content.
[]
# REQUIRED: Your product name.
= "Docklet"
# REQUIRED: One-line description of your product.
= "Floating command strip for macOS — media controls, clipboard, AirDrop, timers, and more"
# Optional: URL to your product website.
= "https://getdocklet.app"
# REQUIRED: Who is your target audience?
= "Mac power users, developers, and productivity enthusiasts"
# REQUIRED: Keywords for tweet discovery (at least 1).
# Tuitbot searches for tweets containing these keywords.
= ["macos productivity", "mac menu bar", "mac clipboard manager"]
# Optional: Competitor keywords for discovery.
= ["notchnook alternative", "dynamic island mac", "bartender mac"]
# REQUIRED: Topics for original content generation (at least 1).
# Tuitbot creates educational tweets and threads on these topics.
= [
"Mac productivity tips",
"macOS power user workflows",
"Building native Swift apps",
"Indie Mac app development",
]
# Optional: Describe your brand's voice and personality.
# This shapes how all generated content sounds.
# Example: "Friendly technical expert. Casual tone, occasionally witty,
# explains complex topics simply. Sounds like a knowledgeable friend."
# brand_voice = "your brand voice description here"
# Optional: Specific guidelines for how replies should feel.
# Example: "Lead with genuine help. Ask follow-up questions. Only mention
# our product if directly relevant. Never be pushy or salesy."
# reply_style = "your reply style guidelines here"
# Optional: Specific guidelines for original tweets and threads.
# Example: "Share practical tips with real examples. Prefer 'here's what I
# learned' framing over lecturing. End threads with actionable takeaways."
# content_style = "your content style guidelines here"
# Optional: Opinions the persona holds (adds variety to content).
# persona_opinions = ["Native apps beat web wrappers for performance", "Keyboard shortcuts are underrated"]
# Optional: Experiences the persona can reference (keeps content authentic).
# persona_experiences = ["Built a macOS menu bar app from scratch", "Switched from Electron to SwiftUI"]
# Optional: Core content pillars (broad themes the account focuses on).
# content_pillars = ["macOS productivity", "indie development", "Swift programming"]
# --- Scoring Engine ---
# Controls how tweets are scored for reply-worthiness (0-100 scale).
# Six signals: keyword(25) + follower(15) + recency(10) + engagement(15) + reply_count(15) + content_type(10) = 90 max.
[]
# Minimum score to trigger a reply (0-100).
= 60
# Maximum points for keyword relevance.
= 25.0
# Maximum points for author follower count (bell curve, peaks ~1K followers).
= 15.0
# Maximum points for tweet recency.
= 10.0
# Maximum points for engagement rate (likes + retweets + replies).
= 15.0
# Maximum points for reply count signal (fewer replies = higher score).
# Targets underserved conversations where your reply is more visible.
= 15.0
# Maximum points for content type signal.
# Text-only original tweets score max; media/quote tweets score 0.
= 10.0
# --- Safety Limits ---
# Prevent aggressive posting that could trigger account restrictions.
# Conservative defaults — better to under-post than get flagged.
[]
# Maximum replies per day (keep low to avoid looking like a bot).
= 5
# Maximum original tweets per day.
= 6
# Maximum threads per week.
= 1
# Minimum delay between any two actions (seconds).
# Also controls the minimum jitter added to all loop intervals.
= 45
# Maximum delay between any two actions (seconds).
# Also controls the maximum jitter added to all loop intervals.
= 180
# Maximum replies to the same author per day (prevents harassment patterns).
= 1
# Phrases that should never appear in generated replies.
# If the LLM outputs any of these, the reply is discarded.
= ["check out", "you should try", "I recommend", "link in bio"]
# Fraction of replies that may mention your product (0.0 - 1.0).
# 0.2 means ~20% of replies reference the product; 80% are purely helpful.
= 0.2
# --- Automation Intervals ---
# How often each loop runs. Shorter intervals use more API quota.
[]
# Seconds between mention checks.
= 300
# Seconds between discovery searches.
= 900
# Minimum seconds between content tweets.
= 10800
# Minimum seconds between thread posts.
= 604800
# --- LLM Provider ---
# Configure the AI provider for content generation.
# Supported: "openai", "anthropic", "ollama"
[]
# REQUIRED: LLM provider name.
= "openai"
# REQUIRED for openai/anthropic: API key.
= "your-api-key-here"
# Model to use for content generation.
= "gpt-4o-mini"
# Optional: Override the API base URL (useful for proxies or Ollama).
# base_url = "http://localhost:11434/v1"
# --- Target Account Monitoring ---
# Monitor specific accounts for relationship-based engagement.
# Instead of keyword-spray, engage meaningfully with people you follow.
[]
# Usernames to monitor (without @). Their tweets are fetched and scored
# independently of the keyword discovery loop.
# accounts = ["pmarca", "naval", "paulg"]
# Maximum replies to target account tweets per day (separate from general limit).
= 3
# --- Data Storage ---
[]
# Path to the SQLite database file.
= "~/.tuitbot/tuitbot.db"
# Number of days to retain data (0 = keep forever).
= 90
# --- Logging ---
[]
# Seconds between periodic status summaries (0 = disabled).
# When enabled, prints action counts and loop health.
= 3600
# --- Active Hours Schedule ---
# The bot sleeps outside these hours, preventing 3 AM posts.
# Wrapping ranges are supported (e.g. start=22, end=6 for night owls).
[]
# IANA timezone name. Full list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
= "UTC"
# Hour (0-23) when the bot becomes active.
= 8
# Hour (0-23) when the bot goes to sleep.
= 22
# Days of the week the bot is active. Use 3-letter abbreviations.
= ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
# Preferred posting times for tweets (HH:MM in 24h format, in timezone above).
# When set, the content loop posts at these specific times instead of every N hours.
# Use "auto" for research-backed defaults: 09:15 (morning), 12:30 (lunch), 17:00 (end-of-day).
# preferred_times = ["auto"]
# preferred_times = ["09:15", "12:30", "17:00"]
# Per-day overrides for preferred posting times.
# Days not listed use the default preferred_times above.
# Use an empty list to skip posting on a specific day.
# [schedule.preferred_times_override]
# Sat = ["11:00"]
# Sun = []
# Preferred day and time for weekly thread posting (overrides thread_interval_seconds).
# thread_preferred_day = "Tue"
# thread_preferred_time = "10:00"
# --- MCP Mutation Policy ---
# Controls whether MCP mutation tools (post, reply, like, follow, etc.)
# are gated by policy checks before execution. This is the safety layer
# between AI agents and real X API actions.
[]
# Master switch: set to false to disable all policy enforcement.
# enforce_for_mutations = true
# Tools that require routing through the approval queue before execution.
# In Composer mode, ALL mutations require approval regardless of this list.
# require_approval_for = ["post_tweet", "reply_to_tweet", "follow_user", "like_tweet"]
# Tools that are completely blocked from execution.
# A tool cannot be in both blocked_tools and require_approval_for.
# blocked_tools = []
# When true, mutations return a dry-run response without executing.
# Useful for testing agent behavior without side effects.
# dry_run_mutations = false
# Maximum MCP mutations allowed per hour (aggregate across all tools).
# max_mutations_per_hour = 20