Skip to content

Latest commit

 

History

History
293 lines (225 loc) · 9.81 KB

File metadata and controls

293 lines (225 loc) · 9.81 KB

Contributing

Bot setup

Warning

The bot is tailor-made for the Ghostty community and will most definitely be unsuitable for other servers. If you're looking to use similar features, you should consider looking for a more general-purpose bot, or forking this project and modifying it to suit your needs. That said, the core intent of this guide is to help contributors set up their development environment for building and testing new features. Contributions are the goal, not standalone usage.

1. Preparing a Discord application

1.1. Creating a Discord application

  1. Go to the Discord Developer Portal.
  2. Click on the "New Application" button.
  3. Pick a name for your bot.

1.2. Getting a Discord token

On your newly created bot's dashboard:

  1. Go to "Bot" on the sidebar.
  2. Click on the "Reset Token" button.
  3. Save the newly generated token for later.
  4. Under "Privileged Gateway Intents", enable:
    • Server Members Intent
    • Message Content Intent

1.3. Inviting the bot to your server

  1. Go to "OAuth2" on the sidebar.
  2. Under "OAuth2 URL Generator", select the bot scope.
  3. Under "Bot Permissions" that appears, choose the following permissions:
    • Attach Files
    • Manage Messages
    • Manage Roles
    • Manage Threads
    • Manage Webhooks
    • Send Messages
    • Use External Apps
      (your URL should contain a 1125917892061184 bitfield for permissions)
  4. Use the generated URL at the bottom of the page to invite the bot to your server.

2. Getting a GitHub token

A GitHub token is necessary for the bot's Entity Mentions feature.

You can get one in two ways:

  • On GitHub, go to Settings > Developer settings > Personal access tokens > Tokens (classic) > Generate new token, or use this link: Generate new token. As the bot only accesses public repositories, it doesn't require any scopes.
  • If you have the gh CLI installed and authenticated, run gh auth token.

3. Creating a GitHub webhook

Tip

This can be skipped if you're not going to interact with the bot's webhook feature.

The bot has a webhook feed feature which lets it stream customized GitHub repo activity to Discord channels. In order to set up a webhook stream from your repo:

  1. Go to https://smee.io/ (any webhook relay service should work, but smee.io is field-tested) and choose "Start a new channel".
  2. Copy the URL of your channel.
  3. Go to your GitHub repository, then Settings > Webhooks > Add webhook.
  4. In "Payload URL", paste in your channel's URL.
  5. Set "Content type" to application/json.
  6. Set a "Secret" (optional, but recommended). It can be any string.
  7. For "Which events would you like to trigger this webhook?", it's easiest to choose "Send me everything." because the bot's webhook client still only triggers for events specified by hooks in the code.

More resources:

4. Preparing a Discord server

The following text channels will be necessary:

  • #media
  • #showcase
  • #webhook
  • #discussion-feed
  • #botlog-everything

Additionally, a forum channel named #help is needed. It must have the following tags:

  • Moved to GitHub
  • Solved
  • Stale
  • Duplicate

The following roles will be necessary (both requiring the Manage Messages permission):

  • mod
  • helper

5. Preparing the config file

Create a config.toml file in the root of the project based on config-example.toml. Below are explanations for all fields variable:

  • accept_invite_url: a URL to visit to accept the Ghostty invite
  • Channel/role IDs from step 4:
    • guild_id: the id of the server you prepared (optional; useful when your bot is in multiple servers).
    • channels.hcb_feed
    • channels.help
    • channels.help_tags: a table of tag_nametag_id pairs. The tag names are moved, solved, stale and duplicate.
    • channels.media
    • channels.showcase
    • channels.log pairs. The feed type names are main and discussions.
    • roles.mod
    • roles.helper
  • data_dir: a directory path for persistent state
  • tokens.discord: the Discord bot token from step 1.
  • tokens.github: the GitHub token from step 2.
  • sentry_dsn: the Sentry DSN (optional).
  • Webhook environment variables from step 3 (if you skipped that section, you can use the dummy values from config-example.toml):
    • webhook.url: the URL to receive events from.
    • webhook.secret: a token for validating events (optional).
    • webhook.channels: a table of feed_typechannel_id pairs.

5.1. Config overrides

.env files are also supported, although they have a lower priority than the TOML file.

For temporary changes, you can set environment variables in the command-line or use the CLI interface available under uv run -m app --help.

Since the TOML config has a nested structure, the environment variable names indicate nesting with a double underscore, e.g. overriding roles.mod would be done with the BOT__ROLES__MOD variable, and overriding channels.help_tags would be done with the BOT__CHANNELS__HELP_TAGS variable.

The complete priority is, in decreasing order:

  1. CLI arguments
  2. Environment variables
  3. __init__ arguments
  4. .toml config
  5. .env files

6. Running the bot

This bot runs on Python 3.14+ and is managed with uv. To get started:

  1. Install uv.

  2. Run the bot:

    uv run -m app
  3. After you've made your changes, run the required checks with just:

    just check

    These checks are enforced by CI, so make sure to fix any issues shown. You can format all code as required by running just format, and fixable issues (including formatting issues) can have their fixes applied with just fix.

    If you do not want to use just, you will have to run the checks manually, which is significantly more complicated.
    1. There are a large number of checks to run. CI ensures that everything is formatted uniformly, so first run the formatters:

      uv run taplo fmt pyproject.toml packages/*/pyproject.toml config-example.toml
      uv run ruff format
      uv run mdformat --number --wrap 80 *.md

      These must be run from the project root.

    2. Ghostty Bot is split into many packages. Ruff performs many checks on all packages at the same time. Run it from the project root:

      uv run ruff check
    3. The other checks do not work on all packages at the same time. Run these for every directory under packages:

      cd packages/<package name>
      uv run basedpyright src tests
      uv run pytest tests
      uv run taplo fmt --check --diff pyproject.toml

      For example:

      cd packages/toolbox
      uv run basedpyright src tests
      uv run pytest tests
      uv run taplo fmt --check --diff pyproject.toml

      Do not skip the checks for subpackages you did not modify, as subpackages may depend on each other.

    4. The same checks must be run for the application itself, as changes to the subpackages may have broken the bot. Run these from the project root.

      uv run basedpyright app tests
      uv run pytest tests

      Note that the basedpyright command uses app, not src.

Project structure

Ghostty Bot's code is split into multiple packages:

  • The main package, containing the bot's features and integration code.
  • toolbox, containing common code, utilities, and code to move messages.

All packages but the main one are in their own directory under packages/. The main package, under app/, is structured as follows:

flowchart LR;

config{{config.py}} --> bot{{bot.py}}
config --> components(components/)
config --> main{{\_\_main__.py}}
log{{log.py}} --> main
bot --> main
bot --> components
Loading
  • components/ is a place for all dedicated features (cogs), such as message filters or entity mentions. Most new features should become modules belonging to this package. Events (e.g. on_ready, on_message, on_error) should be defined within the component.
  • bot.py contains custom attributes and behaviors for the overall Discord bot and then loads extensions found in components.
  • config.py handles reading and parsing the environment variables and the local config.toml file, and creates the GitHub client.
  • log.py sets up logging and optionally Sentry.
  • __main__.py initializes logging and starts the bot.