A digital assistant chatbot
  • Scala 94.1%
  • Nix 5.8%
  • Shell 0.1%
Find a file
2026-07-05 15:01:57 -07:00
.github/workflows gha: trigger push build only on main (#851) 2026-07-05 15:01:57 -07:00
infra Decompose infra config and add a deployment script (#780) 2025-12-07 18:56:38 -07:00
modules Fix HTML meta title detection (#805) 2026-02-08 08:58:59 -07:00
project sbt: 1.12.13 -> 2.0.1 (#850) 2026-07-05 14:54:00 -07:00
src/test scala: 3.6.4 -> 3.7.1 (#727) 2025-06-15 11:15:27 -07:00
.scalafix.conf scala: 3.6.4 -> 3.7.1 (#727) 2025-06-15 11:15:27 -07:00
.scalafmt.conf scalafmt-core: 3.8.2 -> 3.8.3 (#610) 2024-07-27 07:47:38 -07:00
build.sbt amqp-client: 5.32.0 -> 5.33.0 (#849) 2026-07-05 14:39:42 -07:00
CONTRIBUTING.md Add support for Slack (#588) 2024-06-03 09:27:43 -07:00
default.nix sbt: 1.12.13 -> 2.0.1 (#850) 2026-07-05 14:54:00 -07:00
LICENSE-MIT Initial commit 2015-01-10 18:06:57 -08:00
README.md Add a configurable JDBC database driver (#766) 2025-10-18 11:20:26 -07:00
sbt.nix sbt-derivation -> sbt.nix (#840) 2026-06-06 09:07:08 -07:00
shell.nix Format Nix sources with treefmt 2025-08-09 09:28:12 -07:00

Build status

Sectery

Sectery is a digital assistant chatbot.

Usage

To run Sectery, you'll need API keys for Finnhub, Dark Sky, AirNow, and OpenAI.

To start Sectery, first set a bunch of configuration variables, then run each of the main classes with sbt run:

Backend

$ export RABBIT_MQ_HOSTNAME=localhost
$ export RABBIT_MQ_PORT=5672
$ export RABBIT_MQ_USERNAME=guest
$ export RABBIT_MQ_PASSWORD=guest
$ export DATABASE_DRIVER=com.mysql.jdbc.Driver
$ export DATABASE_URL=jdbc:mysql://username:password@host:port/dbname
$ export FINNHUB_API_TOKEN=my_finnhub_api_token
$ export OPEN_WEATHER_MAP_API_KEY=my_open_weather_map_api_key
$ export AIRNOW_API_KEY=my_airnow_api_key
$ export OPENAI_APIKEY=my_openai_api_key
$ sbt "project producers" run

IRC client

$ export RABBIT_MQ_HOSTNAME=localhost
$ export RABBIT_MQ_PORT=5672
$ export RABBIT_MQ_USERNAME=guest
$ export RABBIT_MQ_PASSWORD=guest
$ export IRC_HOST=irc.libera.chat
$ export IRC_PORT=7000
$ export IRC_USER=my_nick
$ export IRC_PASS=my_password
$ export IRC_CHANNELS=#my_channel
$ sbt "project irc" run

Slack client

$ export RABBIT_MQ_HOSTNAME=localhost
$ export RABBIT_MQ_PORT=5672
$ export RABBIT_MQ_USERNAME=guest
$ export RABBIT_MQ_PASSWORD=guest
$ export SLACK_BOT_TOKEN=xoxb-foo-bar-baz
$ export SLACK_APP_TOKEN=xapp-1-foo-bar-baz
$ sbt "project slack" run

Development

See CONTRIBUTING.md.

Architecture

Layers

Sectery's code is organized as layered modules with both shared and disjoint compile-time visibility. Each layer has access to the layers beneath.

.----------------------------------------------------------------------.
|                                Layer 5                               |
|                                                                      |
|                        irc      slack      producers                 |
|                                                                      |
| o                                                              (ZIO) |
'-|--------------------------------------------------------------------'
  |
.-|--------------------------------------------------------------------.
| v                              Layer 4                               |
| |                                                                    |
| |                 adaptors                 adaptors-with-zio         |
| |                                                                    |
| | o                                  (implementations of L2 effects) |
'-|-|------------------------------------------------------------------'
  | |
  | |                                                             impure
==|=|===================================================================
  | |                                                               pure
  | |
.-|-|------------------------------------------------------------------.
| v v                            Layer 3                               |
| | |                                                                  |
| | |                           use cases                              |
| | |                             |   |                                |
| | |        responders <---------'   '---------> announcers           |
| | | o                                                                |
'-|-|-|----------------------------------------------------------------'
  | | |
.-|-|-|----------------------------------------------------------------.
| v v v                          Layer 2                               |
| | | |                                                                |
| | | |                          effects                               |
| | | | o                                                              |
'-|-|-|-|--------------------------------------------------------------'
  | | | |
.-|-|-|-|--------------------------------------------------------------.
| v v v v                        Layer 1                               |
|                                                                      |
|                                domain                                |
|                                 |  |                                 |
|              entities <---------'  '---------> operations            |
|                                                                      |
'----------------------------------------------------------------------'

Layers 1 through 3 are all pure functions and data structures modelling the domain, business rules, and effects.

Layers 4 and 5 both impure, with effects implementations underneath ZIO to wire everything together.

Message queue

Modules interact with each other via RabbitMQ:

                      .------------.
                     / \            \
    .-----------------> |   inbox    |=================..
    |                \ /            /                  ||
    |                 '------------'                   vv
.-------.                                        .-------------.
|  irc  |                                        |  producers  |-.
'-------'-.                                      '-------------' |-.
  | slack |                                        '-------------' |
  '-------'                                          '-------------'
    ^                 .------------.                   ||
    |                /            / \                  ||
    '---------------|   outbox   | <===================''
                     \            \ /
                      '------------'

External dependencies

Modules access various internal and external resources:

.-----.         .------------.
| irc |-------->| IRC Server |
'-----'         '------------'

.-------.       .-----------.
| slack |------>| Slack API |
'-------'       '-----------'

.-----------.         .----------------.
| producers |-.======>| 3rd party APIs |-.
'-----------' |-.     '----------------' |-.
  '-----------' |       '----------------' |
    '-----------'         '----------------'
         ||
         ||           .-------.
         ''==========>| RDBMS |
                      '-------'