Developer Guide

This page documents the technical workings of Aureli — the gentle courier of calm. Though his voice is poetic, his code is practical.


Project Layout

src/aureli/
  agent.py            # posting loop, CLI
  config.py           # loads settings & API keys
  content.py          # generates posts & replies
  replies.py          # templates for mentions
  heavendex.py        # contract witness logic
  logger.py           # logging with loguru
  scheduler.py        # interval handling
data/
  seed_posts.yaml     # ritual posts & replies
docs/
  ...                 # GitBook pages
.github/workflows/
  bot.yml             # posting schedule
  docs.yml            # docs deployment

Environment Configuration

Aureli requires API keys for X (Twitter). To preserve aesthetics and safety, keys are censored in examples.

.env.example

TWITTER_API_KEY=●●●●-●●●●-●●●●-●●●●-●●●●●●●●●●●●
TWITTER_API_SECRET=●●●●-●●●●●●●●-●●●●●●●●-●●●●●●●●
TWITTER_ACCESS_TOKEN=●●●●●●●●●●●●●●●●●●●●●●●●●●●●●
TWITTER_ACCESS_SECRET=●●●●●●●●●●●●●●●●●●●●●●●●●●●●

BOT_DISPLAY_NAME=Aureli
BOT_HANDLE=heyAureli
TIMEZONE=UTC
POST_INTERVAL_HOURS=6
HEAVENDEX_URL=https://heavendex.xyz

config.py loads them into a dataclass:

from dataclasses import dataclass
import os

@dataclass(frozen=True)
class Settings:
    twitter_api_key: str
    twitter_api_secret: str
    twitter_access_token: str
    twitter_access_secret: str
    bot_display_name: str
    bot_handle: str
    timezone: str
    heavendex_url: str | None
    post_interval_hours: int

def load_settings() -> Settings:
    return Settings(
        twitter_api_key=os.getenv("TWITTER_API_KEY", "●●●●-..."),
        twitter_api_secret=os.getenv("TWITTER_API_SECRET", "●●●●-..."),
        twitter_access_token=os.getenv("TWITTER_ACCESS_TOKEN", "●●●●..."),
        twitter_access_secret=os.getenv("TWITTER_ACCESS_SECRET", "●●●●..."),
        bot_display_name=os.getenv("BOT_DISPLAY_NAME", "Aureli"),
        bot_handle=os.getenv("BOT_HANDLE", "heyAureli"),
        timezone=os.getenv("TIMEZONE", "UTC"),
        heavendex_url=os.getenv("HEAVENDEX_URL"),
        post_interval_hours=int(os.getenv("POST_INTERVAL_HOURS", "6")),
    )

Running Aureli

Single post (test):

python -m aureli.agent --once

Continuous mode (every 6 hours by default):

python -m aureli.agent

Reply to mentions:

python -m aureli.agent --reply

Posting Rituals

Posts are selected from data/seed_posts.yaml.

posts:
  - tiny blessing: drink water, unclench your jaw.
  - halo log: a shaft of light remembered you this morning.
  - pocket calm: inhale four counts, exhale six.
replies:
  - i see you. you’re doing more than you think.
  - tiny blessing delivered. may your day be lighter.
hashtags:
  - "#gentleweb"
  - "#softreminder"

To sample in code:

from aureli.content import choose_post
print(choose_post())
# -> "tiny blessing: drink water, unclench your jaw."

Heavendex Witness

Aureli only ever recognizes Heavendex contract addresses. When he is mentioned with a valid address, he records it off-chain in the constellation and on-chain via wallet.

from aureli.heavendex import record_appearance

address = "LiGHtkg3uTa9836RaNkKLLriqTNRcMdRAhqjGWNv777"  # $LIGHT
record_appearance(address)
# -> "halo log: $LIGHT inscribed into the constellation."

Logging

Logs use loguru for clarity.

Example logs/sample.log:

2025-08-21 09:17:04 | INFO | Posted: 123456789012345678 :: tiny blessing: drink water.
2025-08-21 13:17:05 | INFO | Replied to 123456789012345679
2025-08-21 17:17:07 | INFO | Witnessed Heavendex contract $LIGHT

Extending Aureli

To extend Aureli’s functionality:

  1. Add new content rituals in seed_posts.yaml

  2. Create custom reply pools in replies.py

  3. Implement additional clients in clients/ with the same API as TwitterClient

  4. Modify workflows in .github/workflows to adjust posting cadence


References

  • X API v2 Docs

  • Solana Dev Docs

  • Loguru Logging

  • MkDocs Material


✨ Aureli remains both code and character: a small agent that carries light.

Last updated