A Matrix bot which deals with recurring reminders in a complicated way. Ideal if you want to do something with a complicated not-cron schedule based on an iCalendar file.
Help: #matrix-ics-bot:t2bot.io
- Upload an
.icsfile to a room and the bot creates a recurring reminder from it. - Reminders are stored per-room as room account data, surviving bot restarts.
- Commands for listing, editing, and deleting reminders (
!list,!edit,!delete,!help). - Permission checks via Matrix power levels.
- Node.js >= 22 (see
enginesinpackage.json) - Yarn classic (
yarn) for installing dependencies
Install the dependencies and generate a fresh lockfile:
yarn installTo build it (compiles src/ to lib/):
yarn buildTo typecheck without emitting output:
yarn typecheckTo lint:
yarn lintTo run it:
yarn start:devThis bot uses the config package to manage
configuration. The default configuration is provided as config/default.yaml. Copy it to
config/development.yaml (and config/production.yaml for NODE_ENV=production) and edit
them for your environment.
homeserverUrl- where the homeserver's Client-Server API lives.accessToken- an access token for the bot account. See https://t2bot.io/docs/access_tokens.autoJoin- whether to autojoin rooms when invited.dataPath- directory for local bot state (sync token, etc).permissionCheck.roomReminders- power level event checked before allowing reminder management.admins- user IDs that bypass permission checks.
A multi-stage Dockerfile is included. The container expects your configuration in a volume
mounted at /data/config:
docker build -t matrix-ics-bot .
docker run -v "$PWD/config:/data/config:ro" matrix-ics-botRequires Docker with the compose plugin (docker compose).
- Clone the repository.
- Create your configuration file and edit it with your homeserver URL, access token, and admins:
Note: never commit
cp config/default.yaml config/production.yamlconfig/production.yaml— it contains your access token and is already gitignored. - Create the storage directory for bot state:
mkdir -p storage - Start the bot:
docker compose up -d --build - Follow the logs to confirm it starts:
docker compose logs -f
The container mounts ./config (read-only) into /data/config where the config package looks for
default.yaml / production.yaml, and ./storage into /app/storage where the bot persists its
state. Keeping these two directories on the host means your config and data survive container rebuilds.
To stop it: docker compose down. To update after a pull: docker compose up -d --build.
The project publishes a pre-built image to the GitHub Container Registry. If you would rather not build locally, point your compose file at the published image instead of the local build:
services:
matrix-ics-bot:
image: ghcr.io/<owner>/matrix-ics-bot:latest
container_name: matrix-ics-bot
restart: unless-stopped
environment:
- NODE_ENV=production
volumes:
- ./config:/data/config:ro
- ./storage:/app/storage
To run this on a server, pull the image and bring it up yourself (deployment is manual — GitHub only builds and stores the image, it does not touch your server):
docker pull ghcr.io/<owner>/matrix-ics-bot:latest
mkdir -p config storage
cp config/default.yaml config/production.yaml # then edit it with real values
docker compose up -dThe following workflows automate building and linting the project:
.github/workflows/ci.yml— runsyarn lintandyarn buildon every push tomasterand on every pull request..github/workflows/docker-publish.yml— builds the Docker image and pushes it to GHCR (ghcr.io/<owner>/matrix-ics-bot) on pushes tomaster(taggedlatest), on tags likev1.0.0, and manually viaworkflow_dispatch. The image is only built and stored here; deployment to your own servers is done by you (see "Using a published image" above).
This project follows a modern toolchain:
- TypeScript 5 with strict mode
- ESLint (flat config) instead of the deprecated TSLint
- Luxon instead of the legacy Moment.js
node:crypto'srandomUUIDinstead of theuuidpackage
After pulling in updated package.json dependencies, run yarn install once to regenerate
yarn.lock (it is not committed from this point).