Deploy HexBot

1

Requirements

Node.js 24+pnpmDocker + Compose

Node.js and pnpm for manual install. Docker + Compose for containerized deployment.

2

Quick Start — Docker

The recommended deployment method. Plugins, config, and data are mounted from the host so you can edit and reload without rebuilding the image.

bash
git clone https://github.com/jstnmthw/hexbot
cd hexbot
cp config/bot.example.json config/bot.json
cp config/plugins.example.json config/plugins.json
# edit config/bot.json with your IRC server and credentials
docker compose up -d
docker compose logs -f

DCC CHAT ports 49152-49171 are exposed by default.

3

Manual Install

bash
git clone https://github.com/jstnmthw/hexbot
cd hexbot
pnpm install
cp config/bot.example.json config/bot.json
cp config/plugins.example.json config/plugins.json
# edit config files
pnpm start          # production, no REPL
pnpm dev            # development, with interactive REPL
4

Configuration

Two JSON files control the bot. Both are ignored by git — only the example files are committed.

config/bot.json

IRC server, services (NickServ/SASL), queue rate, DCC settings, SOCKS5 proxy, and logging level. Owner, DB path, and plugin directory are bootstrap env vars now: HEX_OWNER_HANDLE, HEX_OWNER_HOSTMASK, HEX_DB_PATH, HEX_PLUGIN_DIR.

config/bot.json
{
  "irc": {
    "host": "irc.rizon.net",
    "port": 6697,
    "tls": true,
    "nick": "HexBot",
    "channels": ["#hexbot"]
  },
  "services": { "type": "anope", "sasl": true, "sasl_mechanism": "PLAIN" },
  "dcc": { "enabled": false, "port_range": [49152, 49171] },
  "proxy": { "enabled": false, "host": "127.0.0.1", "port": 9050 }
}

config/plugins.json

Plugins are auto-discovered from plugins/ — this file is only needed to override config, restrict channels, or disable specific plugins.

config/plugins.json
{
  "chanmod": {
    "channels": ["#hexbot"],
    "config": { "auto_op": true, "enforce_modes": false }
  },
  "greeter": {
    "channels": ["#hexbot"],
    "config": { "message": "Welcome to {channel}, {nick}!" }
  },
  "flood": { "enabled": false }
}
5

REPL Commands

Run with pnpm dev to get an interactive REPL with owner-level access — no IRC auth required.

repl
.help [cmd]List commands or show detail for one
.statusConnection info, uptime, bind and user counts
.uptimeOne-line uptime report
.say <target> <msg>Send a message to a channel or user
.msg <target> <msg>Send a PRIVMSG to any target
.join / .partJoin or part a channel
.flags [handle] [+flags [#chan]]View or set user flags
.adduser / .deluser / .usersUser management
.chpass <handle> <newpass>Set or rotate a user's DCC password (REPL/DCC only)
.chanset / .chaninfoPer-channel plugin settings
.binds [plugin]List active event binds
.pluginsList loaded plugins and their status
.set <scope> <key> <value>Live config write — core, plugin:<id>, or chanset scope
.unset <scope> <key>Revert a setting to its default
.info <scope>Show all settings for a scope
.rehash [scope]Reload config from disk into the live registry
.reset <plugin>Restore a plugin's settings to defaults
.restartRestart the bot process (picks up code edits)
.modlog [filter...]Query the moderation audit log (DCC/REPL only)
.audit-tail [filter...]Stream audit:log events live (REPL only)
6

Applying Plugin Changes

v0.6.0 retired .load / .unload / .reload — the ESM cache-busting they relied on leaked module-graph entries. Plugin lifecycle is now driven through the live settings registry, with .restartas the canonical “pick up code edits” path.

repl
# Enable or disable a plugin live (no restart):
.set core plugins.chanmod.enabled true
.set core plugins.chanmod.enabled false

# Tweak a plugin setting at runtime:
.set plugin:chanmod auto_op true
.unset plugin:chanmod auto_op       # revert to default
.info plugin:chanmod                # show all settings

# Pull edits from disk back into the live registry:
.rehash

# Pick up code edits to a plugin file:
.restart