Skip to content

Commit 266547b

Browse files
Add AI-readable architecture documentation (v1.1.2)
- Add ARCHITECTURE.md with detailed codebase documentation for AI assistants - Includes file descriptions, data flows, database schema, extension points - Update README.md to reference the new documentation
1 parent 9923959 commit 266547b

File tree

2 files changed

+338
-1
lines changed

2 files changed

+338
-1
lines changed

ARCHITECTURE.md

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
# Architecture Guide for AI Assistants
2+
3+
This file is designed for AI tools (ChatGPT, Claude, Cursor, Copilot, etc.) to quickly understand the codebase and help users modify or extend the bot.
4+
5+
---
6+
7+
## Project Overview
8+
9+
**Purpose:** Autonomous Twitter bot that generates original content and responds to mentions using LLM.
10+
11+
**Core behavior:**
12+
- Posts original tweets on a schedule (autoposting)
13+
- Monitors mentions and replies to selected ones (mention handling)
14+
- Optionally generates images for posts and replies
15+
- All content generation is powered by LLM with structured JSON output
16+
17+
**Tech stack:**
18+
- Python 3.10+ with async/await
19+
- FastAPI for HTTP server
20+
- APScheduler for cron-like job scheduling
21+
- PostgreSQL for persistence (asyncpg driver)
22+
- OpenRouter API for LLM inference (Claude Sonnet 4.5)
23+
- OpenRouter API for image generation (Gemini 3 Pro)
24+
- Twitter API v2 via tweepy
25+
26+
---
27+
28+
## File Structure
29+
30+
```
31+
main.py # Application entry point
32+
config/
33+
__init__.py
34+
settings.py # Environment configuration
35+
personality.py # Bot personality definition
36+
services/
37+
__init__.py
38+
autopost.py # Autoposting service
39+
mentions.py # Mention handling service
40+
llm.py # LLM client
41+
twitter.py # Twitter API client
42+
image_gen.py # Image generation service
43+
database.py # Database operations
44+
tools/
45+
__init__.py
46+
registry.py # Tool registry for function calling
47+
assets/ # Reference images for generation
48+
.env.example # Environment template
49+
requirements.txt # Python dependencies
50+
```
51+
52+
---
53+
54+
## Detailed File Descriptions
55+
56+
### main.py
57+
FastAPI application with lifespan management. On startup:
58+
1. Connects to PostgreSQL database
59+
2. Initializes AutoPostService and MentionHandler
60+
3. Schedules two recurring jobs via APScheduler:
61+
- `autopost_job` — runs every POST_INTERVAL_MINUTES
62+
- `mentions_job` — runs every MENTIONS_INTERVAL_MINUTES
63+
4. Starts the scheduler
64+
65+
HTTP endpoints:
66+
- `GET /health` — health check with scheduler status
67+
- `GET /callback` — OAuth callback for Twitter authentication
68+
- `POST /trigger-post` — manually trigger autopost
69+
- `POST /trigger-mentions` — manually trigger mention processing
70+
71+
### config/settings.py
72+
Pydantic Settings class that loads configuration from environment variables and `.env` file. All settings are typed and validated on startup.
73+
74+
Key settings:
75+
- `openrouter_api_key` — API key for OpenRouter (LLM + image gen)
76+
- `twitter_*` — Twitter API credentials (5 values)
77+
- `database_url` — PostgreSQL connection string
78+
- `post_interval_minutes` — autopost frequency (default: 30)
79+
- `mentions_interval_minutes` — mention check frequency (default: 20)
80+
- `enable_image_generation` — toggle for image generation (default: true)
81+
82+
### config/personality.py
83+
Contains `SYSTEM_PROMPT` constant — the complete personality definition for the bot. This prompt is prepended to all LLM calls and defines:
84+
- Personality traits and character
85+
- Communication style (tone, grammar, punctuation)
86+
- Topics to discuss and avoid
87+
- Behavioral rules (no hashtags, no engagement bait, etc.)
88+
- Example tweets that capture the vibe
89+
90+
**To change the bot's personality, edit this file.**
91+
92+
### services/autopost.py
93+
`AutoPostService` class handles scheduled tweet generation.
94+
95+
Flow:
96+
1. Fetches last 50 posts from database for context
97+
2. Calls LLM with structured output format requesting `{text, include_picture}`
98+
3. If `include_picture=true` and image generation enabled, generates image
99+
4. Posts tweet to Twitter (with optional media)
100+
5. Saves post to database
101+
102+
Structured output schema:
103+
```json
104+
{
105+
"text": "string (max 280 chars)",
106+
"include_picture": "boolean"
107+
}
108+
```
109+
110+
### services/mentions.py
111+
`MentionHandler` class processes Twitter mentions.
112+
113+
Flow:
114+
1. Fetches recent mentions from Twitter API
115+
2. Filters out already-processed mentions using database
116+
3. Sends all unprocessed mentions to LLM in single request
117+
4. LLM selects ONE mention to reply to (or none if all low quality)
118+
5. LLM returns selection + reply text + image decision
119+
6. If mention selected, optionally generates image
120+
7. Posts reply to Twitter
121+
8. Saves interaction to database
122+
123+
Structured output schema:
124+
```json
125+
{
126+
"selected_tweet_id": "string (tweet ID to reply to, empty if none)",
127+
"text": "string (reply text, max 280 chars)",
128+
"include_picture": "boolean",
129+
"reasoning": "string (why this mention was selected)"
130+
}
131+
```
132+
133+
**Design decision:** LLM evaluates ALL pending mentions and picks the best one, rather than replying to every mention. This creates more authentic engagement.
134+
135+
### services/llm.py
136+
`LLMClient` class — async client for OpenRouter API.
137+
138+
Methods:
139+
- `generate(system, user)` — simple text completion
140+
- `generate_structured(system, user, response_format)` — JSON structured output
141+
- `chat(messages, tools)` — chat completion with optional tool calling
142+
143+
Uses `anthropic/claude-sonnet-4.5` model by default (configurable via TEXT_MODEL constant).
144+
145+
### services/twitter.py
146+
`TwitterClient` class — Twitter API integration using tweepy.
147+
148+
Methods:
149+
- `post(text, media_ids)` — post new tweet (API v2)
150+
- `reply(text, reply_to_tweet_id, media_ids)` — reply to tweet (API v2)
151+
- `upload_media(image_bytes)` — upload image (API v1.1, required for media)
152+
- `get_me()` — get authenticated user info
153+
- `get_mentions(since_id)` — fetch mentions (API v2)
154+
155+
Note: Media upload uses API v1.1 because v2 doesn't support it yet.
156+
157+
### services/image_gen.py
158+
`ImageGenerator` class — image generation via OpenRouter.
159+
160+
Uses `google/gemini-3-pro-image-preview` model. Supports reference images from `assets/` folder for consistent character appearance.
161+
162+
Flow:
163+
1. Loads reference images from `assets/` folder (up to 2 randomly selected)
164+
2. Sends reference images + text prompt to model
165+
3. Receives base64-encoded image in response
166+
4. Returns raw image bytes
167+
168+
### services/database.py
169+
`Database` class — async PostgreSQL client using asyncpg.
170+
171+
Tables (auto-created on startup):
172+
- `posts` — stores all posted tweets
173+
- `mentions` — stores mention interactions
174+
- `bot_state` — key-value store for state (e.g., last_mention_id)
175+
176+
Key methods:
177+
- `get_recent_posts_formatted(limit)` — posts as formatted string for LLM context
178+
- `save_post(text, tweet_id, include_picture)` — save new post
179+
- `save_mention(...)` — save mention interaction
180+
- `mention_exists(tweet_id)` — check if mention already processed
181+
- `get_state(key)` / `set_state(key, value)` — state management
182+
183+
### tools/registry.py
184+
Tool registry for LLM function calling. Contains:
185+
- `TOOLS` — dict mapping tool names to async functions
186+
- `TOOLS_SCHEMA` — list of JSON schemas in OpenAI function calling format
187+
188+
Currently empty, ready for extension. To add a tool:
189+
1. Create tool function in `tools/` directory
190+
2. Import and add to `TOOLS` dict
191+
3. Add JSON schema to `TOOLS_SCHEMA` list
192+
193+
---
194+
195+
## Database Schema
196+
197+
```sql
198+
CREATE TABLE posts (
199+
id SERIAL PRIMARY KEY,
200+
text TEXT NOT NULL,
201+
tweet_id VARCHAR(50),
202+
include_picture BOOLEAN DEFAULT FALSE,
203+
created_at TIMESTAMP DEFAULT NOW()
204+
);
205+
206+
CREATE TABLE mentions (
207+
id SERIAL PRIMARY KEY,
208+
tweet_id VARCHAR(50) UNIQUE,
209+
author_handle VARCHAR(50),
210+
author_text TEXT,
211+
our_reply TEXT,
212+
action VARCHAR(20), -- 'replied', 'ignored', 'tool_used'
213+
created_at TIMESTAMP DEFAULT NOW()
214+
);
215+
216+
CREATE TABLE bot_state (
217+
key VARCHAR(50) PRIMARY KEY,
218+
value TEXT,
219+
updated_at TIMESTAMP DEFAULT NOW()
220+
);
221+
```
222+
223+
---
224+
225+
## Data Flow Diagrams
226+
227+
### Autoposting
228+
```
229+
[Scheduler]
230+
→ AutoPostService.run()
231+
→ Database.get_recent_posts_formatted(50)
232+
→ LLMClient.generate_structured()
233+
→ returns {text, include_picture}
234+
→ [if include_picture] ImageGenerator.generate()
235+
→ [if include_picture] TwitterClient.upload_media()
236+
→ TwitterClient.post()
237+
→ Database.save_post()
238+
```
239+
240+
### Mention Handling
241+
```
242+
[Scheduler]
243+
→ MentionHandler.process_mentions_batch()
244+
→ TwitterClient.get_mentions()
245+
→ Database.mention_exists() [filter processed]
246+
→ LLMClient.generate_structured()
247+
→ returns {selected_tweet_id, text, include_picture, reasoning}
248+
→ [if selected] ImageGenerator.generate() [optional]
249+
→ [if selected] TwitterClient.upload_media() [optional]
250+
→ [if selected] TwitterClient.reply()
251+
→ Database.save_mention()
252+
```
253+
254+
---
255+
256+
## Extension Points
257+
258+
### Adding a new tool
259+
1. Create `tools/my_tool.py`:
260+
```python
261+
async def my_tool(query: str) -> str:
262+
# Implementation
263+
return result
264+
```
265+
266+
2. Update `tools/registry.py`:
267+
```python
268+
from tools.my_tool import my_tool
269+
270+
TOOLS = {
271+
"my_tool": my_tool
272+
}
273+
274+
TOOLS_SCHEMA = [
275+
{
276+
"type": "function",
277+
"function": {
278+
"name": "my_tool",
279+
"description": "What this tool does",
280+
"parameters": {
281+
"type": "object",
282+
"properties": {
283+
"query": {"type": "string", "description": "..."}
284+
},
285+
"required": ["query"]
286+
}
287+
}
288+
}
289+
]
290+
```
291+
292+
3. Update `services/mentions.py` to handle tool execution in the response flow.
293+
294+
### Changing LLM model
295+
Edit `services/llm.py`, change `TEXT_MODEL` constant to any OpenRouter model ID.
296+
297+
### Changing image model
298+
Edit `services/image_gen.py`, change `IMAGE_MODEL` constant.
299+
300+
### Adding new scheduled job
301+
In `main.py` lifespan function:
302+
```python
303+
scheduler.add_job(
304+
my_function,
305+
"interval",
306+
minutes=N,
307+
id="my_job",
308+
replace_existing=True
309+
)
310+
```
311+
312+
---
313+
314+
## API Reference
315+
316+
### OpenRouter
317+
- Base URL: `https://openrouter.ai/api/v1/chat/completions`
318+
- Auth: Bearer token in Authorization header
319+
- Models used:
320+
- `anthropic/claude-sonnet-4.5` — text generation
321+
- `google/gemini-3-pro-image-preview` — image generation
322+
323+
### Twitter API
324+
- API v2 for tweets, mentions, user info
325+
- API v1.1 for media uploads only
326+
- Auth: OAuth 1.0a (consumer key/secret + access token/secret)
327+
- Bearer token for read-only operations
328+
329+
### PostgreSQL
330+
- Connection via asyncpg
331+
- Connection pooling enabled
332+
- Tables auto-created on startup if not exist

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,16 @@ my-agent/
228228
229229
├── main.py # FastAPI + APScheduler entry point
230230
├── requirements.txt # Dependencies
231-
└── .env.example # API keys template
231+
├── .env.example # API keys template
232+
└── ARCHITECTURE.md # AI-readable technical documentation
232233
```
233234

234235
Everything is modular. Swap the LLM provider, add new tools, adjust posting schedules — the architecture supports it.
235236

237+
### AI-Friendly Documentation
238+
239+
The `ARCHITECTURE.md` file is specifically designed for AI assistants (ChatGPT, Claude, Cursor, Copilot). Feed it to your AI tool of choice and it will understand the entire codebase structure, data flows, and how to extend the bot. This enables AI-assisted development and customization.
240+
236241
---
237242

238243
## Services Documentation

0 commit comments

Comments
 (0)