Chat bot that tracks your mood over time using the Russell circumplex model of affect. It periodically asks how you feel, maps your emotions to valence/arousal coordinates, and generates charts of your trends. Currently supports only Telegram interface.
The brain has two independent neurophysiological systems for affect, making emotional states inherently two-dimensional (Colibazzi et al., 2010; Posner et al., 2009). Feelinq uses the Russell circumplex model (Russell, 1980):
- Valence (x-axis): pleasant (+1) to unpleasant (−1)
- Arousal (y-axis): energised (+1) to calm (−1)
Examples: Excited = high valence, high arousal; Relaxed = high valence, low arousal; Angry = low valence, high arousal; Bored = low valence, low arousal.
When multiple emotions are selected, the bot stores their mean valence and arousal — a single point on the circumplex representing your overall state for that entry.
During onboarding you pick which emotions you want to track: at least 6, with at least one from each quadrant, and no upper limit. Check-ins then show only your selection. Change it any time in /settings → Emotions.
Requires TimescaleDB (PostgreSQL with the TimescaleDB extension). The bot creates all tables and hypertables automatically on startup.
The primary deployment method. Runs the bot and TimescaleDB as rootless Podman containers managed by systemd.
- The database and user are created automatically by the official TimescaleDB image.
- The TimescaleDB extension and hypertables are set up by the bot on startup.
- The env file lives at
~/.config/feelinq/.env(XDG convention), keeping secrets out of the source tree. - Inside the shared
feelinq.network, the container is reachable assystemd-postgres. Do not uselocalhostin the env file.
# Build the bot image
podman build -t feelinq:latest .
# Set up the env file
mkdir -p ~/.config/feelinq
cp .env.example ~/.config/feelinq/.env
# Edit ~/.config/feelinq/.env and fill in TELEGRAM_BOT_TOKEN
# Create persistent data directories
mkdir -p ~/feelinq-data/postgres
# Install quadlet units
mkdir -p ~/.config/containers/systemd
cp quadlet/*.container quadlet/*.network ~/.config/containers/systemd/
# Reload systemd and start
systemctl --user daemon-reload
systemctl --user start feelinq.serviceTo start containers at boot:
# This keeps your user systemd running without login.
sudo loginctl enable-linger $USERCheck status:
systemctl --user status feelinq.service
systemctl --user status postgres.serviceUpdating
git pull ; podman build -t feelinq:latest . ; systemctl --user restart feelinq.serviceRequires Python 3.12+, uv, and TimescaleDB running separately.
-
Create the PostgreSQL database:
CREATE USER feelinq WITH PASSWORD 'feelinq'; CREATE DATABASE feelinq OWNER feelinq;
-
Configure and start:
cp .env.example .env
Edit
.env: setTELEGRAM_BOT_TOKENand uncomment the localhost DSN line:POSTGRES_DSN=postgresql://feelinq:feelinq@localhost:5432/feelinqThen run:
uv sync uv run feelinq
The bot will create the user_settings table and mood_entry hypertable automatically on startup.
| Command | Description |
|---|---|
/start |
Onboarding (language, timezone) |
/checkin |
Log how you feel right now (manual check-in) |
/settings |
Emotions, reminder window, timezone, language, weekly report |
/stats |
Circumplex scatter plus 12-month mood and energy calendars |
/weekly |
Weekly report on demand |
/help |
How the bot works |
/theory |
The science behind the circumplex model |
/feedback <text> |
Send feedback to admins |
Every Monday at 09:00 local time the bot sends one image, captioned with the summary:
- Caption — number of check-ins, the dominant quadrant in plain words, your top 3 emotions, and the brightest and toughest check-in of the week.
- Top panel — the circumplex: every check-in of the week against your all-time spread, both as 2σ contours.
- Bottom panel — the same map as a path. Each day is a dot at that day's mean valence and arousal, joined oldest to newest, so the shape of the week is visible at a glance. The dot grows with the number of check-ins behind it. The line fades in from the start of the week and ends in a ring on today. A dashed jump means a day without a check-in. The emotion names are left off here, to keep the weekday labels readable.
The day is configurable in /settings → Reminders, where the report can also be
switched off. A week with no check-ins produces no report. /weekly sends the
same report on demand.
All via environment variables (see .env.example):
| Variable | Description | Default |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Bot token from @BotFather | required |
POSTGRES_DSN |
PostgreSQL connection string (postgresql://user:pass@host:port/db) |
postgresql://feelinq:feelinq@localhost:5432/feelinq |
ADMIN_USER_IDS |
Comma-separated Telegram chat IDs for admin access | (empty) |
LOG_LEVEL |
DEBUG or INFO |
INFO |


