PM Notifier is an automation tool that bridges Jira and Telegram for engineering and product teams. It runs on GitHub Actions every 3 minutes, polls Jira for any activity since the last run, and pushes targeted notifications directly to team members' Telegram accounts.
The problem it solves is simple: most engineers do not check Jira unprompted. Email notifications from Jira pile up and get ignored. Telegram is where teams are already communicating. PM Notifier brings the signal into the channel where people are actually present.
The system is stateful: it tracks what it has already notified about to prevent duplicates across runs. State is committed back to the repository as a JSON file after each run, which means it persists without needing a separate database or server.
My Role
Designed and built the full system as sole developer and the PM who needed the tool
Designed the notification taxonomy: which Jira events matter enough to push a notification, what the message should contain, and who should receive it
Built the Jira polling layer using the Jira REST API with incremental change detection
Built the Telegram dispatch layer using Telethon: each notification goes to the right user based on their Jira account to Telegram mapping
Designed the state management system: JSON file committed to the repo after each run to track sent notifications and prevent duplicates
Set up the GitHub Actions workflow: cron schedule every 3 minutes, secrets management for Jira and Telegram tokens, and auto-commit for state updates
Defined the weekly summary format for Monday PM review: open tasks by assignee, tasks completed since last week, and any blocked items
Architecture
Python script running inside a GitHub Actions workflow on a 3-minute cron schedule. The script imports Telethon for Telegram access and makes direct HTTP requests to the Jira REST API. No server, no database, no infrastructure beyond the GitHub repository itself.
State is stored in a JSON file in the repo. After each run, any new notifications are recorded in state and the file is committed back. This means the workflow is idempotent: if a run processes the same Jira events twice (due to timing), the state check prevents double notification.
User mapping (Jira account ID to Telegram user) is configured in the repo. New team members are added by updating the mapping file and pushing. No deployment needed, just a config change.
Secrets (Telegram session token and Jira API token) are stored in GitHub Actions secrets and injected into the workflow environment. The Telegram session is a Telethon-generated session string, not a bot token, which allows the tool to operate as a Telegram account rather than a bot.
Key Decisions
GitHub Actions as the runtime, not a server
Running a cron job on a server would require provisioning, maintaining, and paying for infrastructure that does nothing most of the time. GitHub Actions gives a free hosted runner that executes on schedule with zero infrastructure management. The 3-minute minimum cron interval on GitHub Actions was the deciding factor: frequent enough to feel real-time without needing a persistent process.
State in the repository rather than a database
A database would require a separate service and credentials. Storing state as a committed JSON file keeps everything in one place: code, config, and state all live in the same repository. The trade-off is that high-frequency state changes generate a lot of small commits. For a tool that runs every 3 minutes, that commit noise is acceptable compared to the simplicity of not needing a separate data store.
Telethon instead of the Telegram Bot API
The Telegram Bot API requires users to start a conversation with the bot before it can message them. Telethon operates as a full Telegram account, which means it can message any user directly without that precondition. This made onboarding new team members simpler: add their Telegram username to the mapping, no action required on their end.
Targeted per-user notifications rather than a group broadcast
A group channel approach would mean everyone sees every notification, even for tasks assigned to someone else. Sending each notification to the relevant individual keeps the signal-to-noise ratio high. The weekly summary is the one exception: that goes to a shared group because it is meant for collective review.
Challenges
Preventing duplicate notifications across 3-minute runs
Jira does not provide a clean webhook-style event stream. Polling means the same change can appear in multiple consecutive runs if the timestamp comparison is not precise. The state file tracks every notification by a combination of issue key and event type so that the same event is never dispatched twice, regardless of how many runs see it in the polling window.
Mapping Jira users to Telegram accounts reliably
The Jira API returns account IDs for assignees and commenters. Telegram uses usernames or numeric user IDs. The mapping between the two has to be maintained manually: when someone joins the team, their Jira account ID and Telegram username both need to be added to the config. The risk is that the mapping goes stale if someone changes their Telegram username or Jira account. The current approach accepts that risk for a small team where these changes are infrequent.