Telegram newsletter

Once a day Pulse turns the archive into an issue, stores it, and sends it to a Telegram chat or channel. The same issue is readable in the dashboard and through the API.

Set up in four steps#

  1. Create a bot. Message @BotFather on Telegram, send /newbot, and copy the bot token.
  2. Choose the destination. A private chat with the bot, a group, or a channel. For a channel, add the bot as an administrator with permission to post. Use the channel handle (for example @my_channel) or the numeric chat id.
  3. Set the variables. Add them to .env:
    TELEGRAM_BOT_TOKEN=123456:ABC...
    TELEGRAM_CHAT_ID=@my_channel
    REPORT_TIMEZONE=America/New_York   # defines the local day, default UTC
    REPORT_HOUR=13                     # local hour to send at or after, default 13
    PUBLIC_URL=https://pulse.example.com  # optional, adds a dashboard link
  4. Keep Pulse running. The newsletter is a scheduled job inside the main process, so it needs pulse start to stay up. See Deployment.

When an issue is built#

At the end of every collection cycle Pulse checks whether the current local day (in REPORT_TIMEZONE) already has an issue. If not, and the local hour is REPORT_HOUR or later, it builds one. That makes the send time resilient: if the process was down at 13:00 it sends at the first cycle after it comes back, still once per day.

Each issue covers the last 24 hours (the windowHours field) and is stored in daily_reports before anything is sent, so a failed Telegram call never loses the issue.

Preview without sending#

npm run report -- --no-send --print
npx -y -p pulse-trenches pulse report --day 2026-10-09 --no-send --print

Flags: --day YYYY-MM-DD picks the day (default today, UTC), --no-send stores the issue without sending it, --print prints the Markdown rendering. Without --no-send, the same command builds and sends on demand. You can also preview the structured data of any day with /api/reports/:day/live.

What is in an issue#

Sections appear only when they have something to say. Nothing is padded.

SectionContents
Market pulseChain-wide market cap, volume and tracked tokens.
LaunchpadsLaunches and graduations in the window, by launchpad.
Daily runnersTokens with status running.
New and already movingFresh launches that already show volume.
Tech watchTokens classified as technology rather than meme, ranked by tech score.
Staying powerTokens that kept showing up on discovery lists across the window.
Holder growthLargest holder-count gains.
Volume leadersTop 24h volume.
What fadedTokens that turned dying or dead, with their peak.
KOL activity, Where KOLs are tradingLabelled KOL wallets and the tokens they hold.
Smart money, Where smart money is tradingScored and discovered smart wallets and the tokens they hold.
SectorsVolume and move by category.
Robinhood ChainLaunches and activity on Robinhood Chain.
Paid attentionTokens that bought promotion on DexScreener (boosts and profiles).
ArchiveTokens and snapshots on record, plus tokens seen, snapshots, tracked trades and watched wallets in the last 24 hours.

Optional written overview#

Set ANTHROPIC_API_KEY and each issue opens with a three to five sentence overview written by Claude (model set by ANTHROPIC_MODEL). The model receives only that day's numbers as JSON and is told never to invent a token, number or cause. If the call fails the issue goes out without it. Without a key, issues are data only, and the stored narrative is null.

Delivery details#

Reading issues elsewhere#

Failures. The issue is stored before sending. If Telegram rejects a send (wrong chat id, bot not an admin), the error is logged and the day is not marked done, so Pulse retries on the next collection cycle until it goes through. Fix the variable and restart, or run pulse report yourself.