Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
#+TITLE: Harlie #+AUTHOR: Brian O'Reilly #+OPTIONS: toc:t num:nil /With respect to David Gerrold's/ When HARLIE Was One. Harlie is a multi-channel IRC bot written in Common Lisp. It maintains persistent user state in PostgreSQL, shortens and annotates URLs, learns from conversation using a Markov chainer, and serves a small web interface per channel showing the URL archive and bot source. * Features - Connects to multiple IRC servers and channels simultaneously, each with its own nick and web port - Auto-reconnect with exponential backoff and keepalive PING - NickServ authentication and registration via an event-driven state machine - URL shortener with title fetching, UTM-parameter stripping, and a per-channel web archive - Markov-chain text generation (~!babble~, ~!haiku~) with per-channel contexts - Memo system (~!tell~, ~!memos~) for leaving messages for offline users - METAR weather lookups (~!metar~) - Wikipedia, dictionary, GitHub, and timezone lookups (~!wiki~, ~!define~, ~!gh~, ~!tz~) - Channel quote database (~!addquote~, ~!quote~) - Per-user and per-channel persistent state in PostgreSQL - Built-in web server (Hunchentoot) per context - Slynk REPL server for live inspection (~slynky~) - Cron-style scheduled tasks * Requirements | Requirement | Notes | |--------------+--------------------------------------------| | SBCL | Tested on current releases | | Quicklisp | For library loading | | PostgreSQL | 14+ recommended; bot uses Unix socket auth | | clatter-irc | [[https://github.com/glenneth1/clatter-irc][glenneth1/clatter-irc]] — clone to a path | | | visible to ASDF's source registry | All other Lisp dependencies are fetched by Quicklisp. * Quickstart ** 1. Create the database #+begin_src sh createdb botdb sed 's/<bot_runner_uid>/YOUR_UNIX_USER/g' \ database/bot-schema.sql.template > database/bot-schema.sql psql botdb -f database/bot-schema.sql #+end_src ** 2. Configure the bot Copy ~config-template.lisp~ to ~config.lisp~ and edit it: #+begin_src lisp (defparameter *bot-config* (make-config :db-credentials (list "botdb" (uiop:getenv "USER") nil :unix) :web-server-name "localhost" :connections (list (make-connection-spec :server "irc.libera.chat" :ssl t :nick "MyBot" :channel "#mychannel" :web-port 9000)))) #+end_src NickServ credentials should come from the environment, never from literals: #+begin_src lisp (make-connection-spec ... :nickserv-password (uiop:getenv "HARLIE_NICKSERV_PASSWORD") :nickserv-email (uiop:getenv "HARLIE_NICKSERV_EMAIL")) #+end_src #+begin_src sh export HARLIE_NICKSERV_PASSWORD="your-nickserv-password" export HARLIE_NICKSERV_EMAIL="[email protected]" #+end_src ** 3. Load and start the bot #+begin_src lisp (ql:quickload :harlie) (in-package :harlie) (run-bot) #+end_src To also open a Slynk REPL for live inspection: #+begin_src lisp (slynky :port 4007) #+end_src ** 4. Stop the bot #+begin_src lisp (kill-bot) #+end_src * Running the Tests A test database is required. Create it once: #+begin_src sh createdb harlie-test pg_dump botdb --schema-only | psql harlie-test #+end_src Then from a Lisp image: #+begin_src lisp (asdf:test-system :harlie) #+end_src This runs the complete test suite: NickServ flow integration tests, pure-function unit tests, and database integration tests. All tests target ~harlie-test~; the production ~botdb~ database is never touched. See the [[file:Manual.org][Operator's Manual]], §Testing, for a full description of the test suite architecture. * Configuration Reference ~make-config~ accepts: | Key | Type | Purpose | |------------------+--------+----------------------------------------------| | ~:db-credentials~ | list | Postmodern connection spec (db user pw host) | | ~:web-server-name~ | string | Hostname for web server ~Location:~ headers | | ~:connections~ | list | One ~make-connection-spec~ per channel | ~make-connection-spec~ accepts: | Key | Required | Default | Purpose | |--------------------+----------+---------+-----------------------------------| | ~:server~ | yes | — | IRC server hostname | | ~:nick~ | yes | — | Bot nick | | ~:channel~ | yes | — | Channel to join | | ~:ssl~ | no | ~nil~ | Use TLS | | ~:web-port~ | no | ~nil~ | Hunchentoot port for this context | | ~:channel-key~ | no | ~nil~ | Channel password | | ~:nickserv-password~ | no | ~nil~ | NickServ IDENTIFY password | | ~:nickserv-email~ | no | ~nil~ | NickServ REGISTER email | | ~:extra-channels~ | no | ~nil~ | List of additional channels to join | * IRC Commands | Command | Effect | |------------------+----------------------------------------------| | ~!help~ | List available commands | | ~!help CMD~ | Show help for a specific command | | ~!babble~ | Generate text via Markov chain | | ~!haiku~ | Generate a haiku | | ~!metar ICAO~ | Fetch weather for airport ICAO code | | ~!status~ | Short status report | | ~!status full~ | Full status including chainer phrase count | | ~!tell USER MSG~ | Leave a message for USER, delivered on return | | ~!memos~ | Check your pending memos | | ~!wiki TOPIC~ | Wikipedia summary | | ~!define WORD~ | Dictionary definition | | ~!tz TIMEZONE~ | Current time in a timezone | | ~!gh OWNER/REPO~ | GitHub repository summary | | ~!addquote TEXT~ | Save a channel quote | | ~!quote~ | Recall a random quote | | ~!quote N~ | Recall quote number N | | ~!uptime~ | How long the bot has been running | | ~!seen USER~ | When a user was last seen speaking | | ~!remind TIME MSG~ | Set a reminder (e.g. ~!remind 30m check build~) | | ~!rpn EXPR~ | RPN calculator | * License See [[file:LICENSE][LICENSE]].