Skip to main content

Telegram bot that journals private messages into an Obsidian vault

Project description

PyPI - Version GitHub Tag GHCR Tag Test Lint

Telegram Journal Bot

A Telegram bot that journals every private message into your Obsidian daily notes.

Demo

User messages sent in a private chat are captured by the bot, including text and media.

Telegram demo

Captured content is appended to your daily note with timestamped entries and structured formatting.

Obsidian demo

Features

  • Private chat journal capture for text, photos, voice recordings, video messages (including circular video notes), and locations
  • UTC daily note partitioning at YYYY/YYYY-MM-DD.md
  • Media storage (photos, voice, video) in YYYY/attachments/
  • YAML frontmatter management for mood, tags, and created
  • In-memory state only (context.chat_data and context.bot_data)
  • Date override commands (/setdate, /resetdate)
  • Tags and mood management with inline keyboard callbacks

Usage

Installation

Choose one installation method:

From PyPI (recommended for end users):

python -m pip install --upgrade telejournal

From source (recommended for contributors):

git clone https://github.com/hugobatista/telejournal.git
cd telejournal
uv sync --extra dev

If running from source, use uv run before commands in the sections below. Example: uv run telejournal run --verbose.

Quick Start

  1. Configure your environment variables as documented in Environment.

  2. Start the bot:

telejournal run --verbose
  1. Open your bot in Telegram and send:
/help
  1. Send a normal message (for example, First journal entry) and confirm it appears in:
<VAULT_ROOT>/YYYY/YYYY-MM-DD.md

Run Modes

Use whichever configuration style best fits your setup.

Environment variables only:

telejournal run

YAML configuration file (config.yaml auto-detected if present):

telejournal run
telejournal run /path/to/config.yaml

CLI overrides (highest priority):

telejournal run \
  --telegram-token your_token \
  --vault-root /path/to/vault \
  --allowed-user-ids 123456,987654 \
  --message-timestamp-window-seconds 60 \
  --secure-file-permissions

Telegram Commands

After the bot is running, these commands are available in your private chat:

  • /help Show bot usage summary
  • /setdate YYYY-MM-DD [HH:MM:SS] Set target note date/time
  • /resetdate Return to current day
  • /tags Show tag buttons
  • /tags work kids Add/select one or more tags
  • /mood Open mood picker
  • /show Show current effective day note
  • /show YYYY-MM-DD Show a specific day note
  • /delete Delete last entry and show deleted content
  • /delete day [YYYY-MM-DD] Delete full day note

Helpful CLI Commands

telejournal version
telejournal help

Using secret-tool

If you use Linux secret service (secret-tool), you can skip a local .env and use secret-tool-run:

secret-tool-run telejournal run

Environment

Create a .env file:

TELEGRAM_TOKEN=your_bot_token
VAULT_ROOT=/path/to/obsidian/vault
LOG_LEVEL=INFO
TELEGRAM_ALLOWED_USER_IDS=123456,987654

Optional Environment Variables

  • MESSAGE_TIMESTAMP_WINDOW_SECONDS (default: 60) - Messages within this window share the same timestamp
  • SECURE_FILE_PERMISSIONS (default: true) - Set restrictive permissions (0o700/0o600) on vault directories and files for security. Set to false only if you need broader file access.

Configuration

The bot supports multiple configuration sources with a clear priority order:

Configuration Priority (highest to lowest)

  1. CLI Arguments - Command-line options override all other sources
  2. YAML File - Configuration file specified via config argument
  3. Environment Variables - Settings from .env file
  4. Defaults - Built-in defaults for optional settings

Later sources override earlier ones. For example, if you specify --telegram-token on the command line, it will override the TELEGRAM_TOKEN environment variable.

YAML Configuration

You can provide a config.yaml file for more organized configuration management. The bot automatically looks for ./config.yaml if no config path is specified.

Example config.yaml:

telegram_token: "${TELEGRAM_TOKEN}"  # Supports environment variable expansion
vault_root: /path/to/obsidian/vault
allowed_user_ids:
  - 123456
  - 987654
log_level: INFO
message_timestamp_window_seconds: 60
secure_file_permissions: true

Configuration Keys:

  • telegram_token (required) - Your Telegram bot token
  • vault_root (required) - Absolute path to your Obsidian vault
  • allowed_user_ids (required) - List of Telegram user IDs that can use the bot
  • log_level (optional, default: INFO) - Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  • message_timestamp_window_seconds (optional, default: 60) - Messages within this window share the same timestamp
  • secure_file_permissions (optional, default: true) - Set restrictive file permissions for security

Environment Variable Expansion:

YAML configuration supports ${VAR_NAME} syntax for environment variable expansion:

telegram_token: "${TELEGRAM_TOKEN}"
vault_root: "${VAULT_ROOT}"

This allows you to keep sensitive values in environment variables while using a configuration file for other settings.

Test

uv run pytest

# With full coverage and type checking
bash validate.sh

Docker

You can run the bot in Docker using either docker run or docker compose.

Using Docker Compose

  1. Create a .env.docker file with your bot token and settings:

    TELEGRAM_TOKEN=your_bot_token
    VAULT_ROOT=/data
    LOG_LEVEL=INFO
    TELEGRAM_ALLOWED_USER_IDS=123456,987654
    SECURE_FILE_PERMISSIONS=false # This will avoid permission issues when running as non-root, but use with caution! 
    
  2. Create an obsidian-journal directory in the same location as your docker-compose.yml to serve as your vault, and set permissions so the container can write to it:

    mkdir obsidian-journal
    chmod 777 obsidian-journal # Use with caution, or set specific user/group permissions as needed
    
  3. Start the container:

    docker compose up --build
    

This will mount your Obsidian vault from ./obsidian-journal to /data inside the container.

On SELinux-enabled Linux distributions (for example Fedora/RHEL), make sure the bind mount uses :Z in docker-compose.yml:

volumes:
    - ./obsidian-journal:/data:Z

Using Docker Run

  1. Build the image:

    docker build -t telejournal:latest .
    
  2. Run the container:

    docker run -d \
      --env-file .env.docker \
            -v "$PWD"/obsidian-journal:/data:Z \
      --name telejournal \
      telejournal:latest
    

This will start the bot in detached mode, using your local .env.docker file and mounting your Obsidian vault.

Note: If you see pull access denied for telejournal, you must build the image first:

docker build -t telejournal:latest .

Then run the container as shown above.

For troubleshooting, check logs with:

docker logs telejournal

Signalbackup-Tools HTML Import Utility

A utility is provided to convert HTML exports generated by signalbackup-tools to Obsidian-compatible Markdown, preserving timestamps, attachments, and replies. This is useful for importing Signal chat history into your journal vault.

Usage

python tools/signalbackup-tool-import/html_to_markdown.py <input_html_file> <output_directory>
  • <input_html_file>: Path to your HTML export from signalbackup-tools (e.g., html/self.html)
  • <output_directory>: Directory where year folders and markdown files will be created

Example:

python tools/signalbackup-tool-import/html_to_markdown.py html/self.html obsidian-journal

This will create:

  • Year folders (e.g., 2022/, 2023/) with daily markdown files
  • An attachments/ folder in each year for media files

See the script for more details and options.

Running as a Systemd Service

To run the Telegram Journal Bot as a background service on Linux, you can use systemd. This ensures the bot starts on boot and restarts automatically if it fails.

Automated Service File Generation (Recommended)

The install-service command generates the service file automatically with sensible defaults:

telejournal install-service

This will:

  • Create the service file at /etc/systemd/system/telejournal.service
  • Use your current user account
  • Set working directory to ~/obsidian-journal
  • Use .env from your home directory
  • Automatically detect the telejournal executable path

You can customize these defaults:

# Use custom paths and user
telejournal install-service \
  --user myuser \
  --working-directory /obsidian-journal \
  --environment-file /telejournal/.env \
  --execstart "/home/myuser/.venv/bin/telejournal run"

After running the command, follow the on-screen instructions to enable and start the service.

Manual Service File Creation

Alternatively, you can manually create a service file at /etc/systemd/system/telejournal.service with the following content (adjust paths and user as needed):

[Unit]
Description=Telegram Journal Bot
After=network.target

[Service]
Type=simple
User=youruser
WorkingDirectory=/home/youruser/obsidian-journal
EnvironmentFile=/home/youruser/.env
ExecStart=/home/youruser/.venv/bin/telejournal run
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Configuration details:

  • User - The user account that will run the bot (should own the vault directory)
  • WorkingDirectory - Your Obsidian vault root directory (where notes are stored)
  • EnvironmentFile - Path to your .env file with required environment variables
  • ExecStart - Full path to the telejournal command (installed in your virtual environment)
  • RestartSec - Wait 5 seconds before restarting on failure

If you installed telejournal system-wide via pip, you can use just telejournal run without the full path.

Enable and Start the Service

sudo systemctl daemon-reload
sudo systemctl enable telejournal.service
sudo systemctl start telejournal.service

Check logs with:

journalctl -u telejournal.service -f

This will keep the bot running in the background and restart it automatically on failure or reboot.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

telejournal-0.0.2.tar.gz (391.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

telejournal-0.0.2-py3-none-any.whl (39.7 kB view details)

Uploaded Python 3

File details

Details for the file telejournal-0.0.2.tar.gz.

File metadata

  • Download URL: telejournal-0.0.2.tar.gz
  • Upload date:
  • Size: 391.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.0.1 CPython/3.12.8

File hashes

Hashes for telejournal-0.0.2.tar.gz
Algorithm Hash digest
SHA256 3e0887cf983a88f2630c21195e63da77e8a7af283fcc2cffff456c73630a432c
MD5 513d47a3e37b17845fb0ec2442df4f23
BLAKE2b-256 c34a8a88ab7fac789a6cdd21835a543b9fa89666fb4376f64204e28ad3a1b735

See more details on using hashes here.

Provenance

The following attestation bundles were made for telejournal-0.0.2.tar.gz:

Publisher: pypi.yml on hugobatista/telejournal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file telejournal-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: telejournal-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 39.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.0.1 CPython/3.12.8

File hashes

Hashes for telejournal-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d6c99a47858e351700fce370c44b1747c34b0c4ce9ed35cda78a6b42340bf513
MD5 f97cc741a0cbba0a6e18434e029eabbb
BLAKE2b-256 94dc060889a572966659127017a1dd98eec93ae9a1fdb6628489c347f4619ecc

See more details on using hashes here.

Provenance

The following attestation bundles were made for telejournal-0.0.2-py3-none-any.whl:

Publisher: pypi.yml on hugobatista/telejournal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page