A personal accountability bot that connects your weekly Google Sheet journal to Telegram — with Claude-powered pattern detection, repeat-goal callouts, and daily morning/evening check-ins.
This bot reads your weekly goals and reflections from a Google Sheet, delivers structured morning and evening nudges via Telegram, and uses Claude (Anthropic) to analyze your full multi-week history for patterns, contradictions, and genuine progress. It stores everything locally in SQLite so your data stays under your control.
- Monday refresh — automatically pulls the current week's row from Google Sheets, stores it to memory, and sends a Claude-powered pattern analysis before your week begins
- Daily morning messages — surfaces your goals for the week and asks what you'll focus on today
- Daily evening messages — prompts reflection and progress rating on your goals
- Repeat goal detection — flags goals that have appeared 2+ weeks in a row with a direct callout
- Full history analysis — Claude reads your entire multi-week journal (all columns, not just goals) and delivers honest, specific insights
- Notification preferences — choose morning only, evening only, or both
- Pause/resume — temporarily stop all messages without losing your data
- Local SQLite memory — all data stored on your own machine or server, never externally
- Rotating log file — production-ready logging with configurable file rotation
- Python 3.11+
- A Telegram account
- A Google account with Google Sheets
- An Anthropic API key
- A Google Cloud project with the Sheets API enabled
- Open Telegram and search for
@BotFather - Send
/newbotand follow the prompts to name your bot - BotFather will give you a bot token — save it (looks like
123456789:ABCdef...) - Optional: send
/setcommandsto BotFather to register the command list:start - Set up the bot goals - See this week's goals reflect - Run a fresh pattern analysis memory - Browse past weeks settings - Change notification preferences update - Manually refresh goals from sheet pause - Pause all notifications resume - Resume notifications
- Go to Google Cloud Console
- Create a new project (or select an existing one)
- Navigate to APIs & Services > Library
- Search for "Google Sheets API" and click Enable
- Go to APIs & Services > Credentials
- Click Create Credentials > Service Account
- Give it a name (e.g.,
goal-bot) and click Create and Continue - Skip optional role assignment for now, click Done
- Click on your new service account in the list
- Go to the Keys tab, click Add Key > Create new key, choose JSON
- The JSON file will download automatically — this is your
credentials.json - Move
credentials.jsoninto the project folder (same directory asmain.py) - Note the service account email address (looks like
goal-bot@your-project.iam.gserviceaccount.com)
- Open your Google Sheet
- Click Share (top right)
- Enter the service account email address from step 2.13
- Set permission to Viewer (read-only is sufficient)
- Click Send
- Copy the Sheet ID from the URL:
https://docs.google.com/spreadsheets/d/SHEET_ID_HERE/edit
- Go to console.anthropic.com
- Sign in or create an account
- Navigate to API Keys and create a new key
- Save the key — it starts with
sk-ant-
cp .env.example .envOpen .env and fill in all values:
TELEGRAM_BOT_TOKEN=123456789:ABCdef_your_token_here
GOOGLE_SHEET_ID=1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
GOOGLE_CREDENTIALS_PATH=credentials.json
ANTHROPIC_API_KEY=sk-ant-your_key_here
USER_TIMEZONE=America/Los_Angeles
MORNING_HOUR=8
EVENING_HOUR=20
DB_PATH=bot_data.db
LOG_FILE=bot.logCommon timezones: America/New_York, America/Chicago, America/Denver, America/Los_Angeles, Europe/London, Europe/Paris, Asia/Tokyo
cd /path/to/telegram-goal-bot
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtpython main.pyYou should see log output confirming:
- Database initialized
- Scheduler started (Monday refresh, morning, evening jobs)
- Bot polling started
Open Telegram, find your bot, and send /start. Then use /update to do your first sync from the sheet.
- Upload your project files (excluding
.env— set env vars separately on the server) - Upload
credentials.jsonsecurely (viascpor secrets manager) - Install Python 3.11+ and set up a virtualenv
- Use
systemdorscreen/tmuxto keep the bot running:
systemd service example (/etc/systemd/system/goalbot.service):
[Unit]
Description=Telegram Goal Accountability Bot
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/telegram-goal-bot
EnvironmentFile=/home/ubuntu/telegram-goal-bot/.env
ExecStart=/home/ubuntu/telegram-goal-bot/venv/bin/python main.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetsudo systemctl enable goalbot
sudo systemctl start goalbot
sudo systemctl status goalbot- Push your project to a GitHub repo (do NOT commit
.envorcredentials.json) - Create a new Railway project and connect your repo
- Add all environment variables in Railway's dashboard under Variables
- For
credentials.json: paste the entire JSON content as an environment variableGOOGLE_CREDENTIALS_JSON, then modifyconfig.pyandsheets.pyto read it fromos.getenv("GOOGLE_CREDENTIALS_JSON")and write it to a temp file at startup - Railway will auto-deploy on every push
Your sheet should follow this structure:
| Week | Goal 1 | Goal 2 | Goal 3 | Reflection | Gratitude | Energy | Lessons |
|---|---|---|---|---|---|---|---|
| 2024-03-18 | Exercise 3x | Read 30min | ... | ... | ... | High | ... |
| 2024-03-25 | Exercise 3x | ... | ... | ... | ... | ... | ... |
Key requirements:
- Row 1 must be headers (column names)
- One row per week
- Include a date column with a name containing "week", "date", or "week start" for automatic date-matching (e.g.,
Week,Week Start,Date,Week Of) - Date values should be in
YYYY-MM-DDorMM/DD/YYYYformat - If no date column is found, the bot will use the last row as the current week
- Goal columns should contain the word "goal" anywhere in the header (e.g.,
Goal 1,Weekly Goal,Top Goal) for evening rating prompts and repeat-goal detection - All other columns (Reflection, Gratitude, Energy, Lessons, etc.) are included in the morning message and Claude analysis
Example headers that work well:
Week Start | Goal 1 | Goal 2 | Goal 3 | Reflection | Gratitude | Energy (1-5) | Lesson Learned | Notes
All memory is stored locally in SQLite. Data is only sent to the Claude API transiently for analysis — nothing is stored externally beyond your own machine or server.
Your Google Sheets data is accessed read-only via a service account. The bot does not write anything back to your sheet.
| Command | Description |
|---|---|
/start |
Register with the bot and see the welcome message |
/goals |
Display this week's goals from the cached sheet data |
/reflect |
Run a fresh Claude analysis of your full history |
/memory |
Browse the last 10 weeks of stored journal data |
/settings |
Change notification preferences (morning/evening/both) with inline buttons |
/update |
Manually pull the latest data from Google Sheets and re-run analysis |
/pause |
Pause all scheduled notifications |
/resume |
Resume scheduled notifications |
Bot doesn't respond to commands
- Confirm
TELEGRAM_BOT_TOKENis correct in.env - Check
bot.logfor error messages - Make sure the bot is running (
python main.pyis active)
"Missing required environment variables" error on startup
- Ensure
.envexists in the project directory and all three required vars are set:TELEGRAM_BOT_TOKEN,GOOGLE_SHEET_ID,ANTHROPIC_API_KEY
Google Sheets returns empty data
- Confirm the sheet is shared with the service account email
- Verify
GOOGLE_SHEET_IDmatches the ID in the sheet URL - Confirm the sheet is named
Sheet1(default) — or update therange="Sheet1"insheets.py - Check
credentials.jsonis present and valid
"Could not find current week's row by date; using last row"
- This warning means no date column was matched. Either add a date column with a recognized name, format the date as
YYYY-MM-DD, or the bot will fall back to using the last row
Claude analysis fails or returns an error
- Verify
ANTHROPIC_API_KEYis correct and has available credits - Check internet connectivity on the machine running the bot
- The
/reflectcommand will show the error; try again after a moment
Scheduled messages not arriving
- Confirm
USER_TIMEZONEis a valid IANA timezone string - Check that
MORNING_HOURandEVENING_HOURare set correctly (24h format) - The bot must be running continuously for scheduled messages to fire
- Check
bot.logaround the scheduled time for any scheduler errors
Messages are too long and getting cut off
- Telegram has a 4096 character limit per message; the bot auto-splits long messages
- If
/memoryoutput is truncated, this is expected — only the last 10 weeks are shown and each entry is capped at 120 characters per field
Database errors
- Delete
bot_data.dband restart to reinitialize (you will lose stored memory) - Ensure the process has write permission in the project directory