Documentation for Cumments v0.31.0.

Quick start

This guide runs a complete local stack with the official images: a tuwunel homeserver and Cumments as its Matrix Application Service. The ready-made compose file lives at misc/docker/compose.yaml and is a minimal, self-contained example: both services are configured entirely through environment variables; the only manual step outside the compose file is generating the AppService registration and copying its tokens in.

Prerequisites

  • Docker with Compose (v2).
  • curl, for creating the first Matrix account.

1. Copy the compose file

Copy the example into a directory of its own so the generated registration.yaml does not end up inside the repository:

mkdir -p ~/cumments-demo && cd ~/cumments-demo
cp /path/to/cumments/misc/docker/compose.yaml docker-compose.yml

For a local test the defaults work as-is: the Matrix server name is localhost:8008, tuwunel is published on port 8008, and the Cumments API on port 7931. For a real deployment, create a .env file next to the compose file before generating the registration:

MATRIX_DOMAIN=matrix.example.com

MATRIX_DOMAIN is the Matrix server name, i.e. the part after : in user IDs and aliases. Both services read it from the same variable, so changing it in one place keeps them consistent.

2. Generate the AppService registration

docker run --rm --entrypoint cumments \
  ghcr.io/curious-r/cumments:latest \
  appservice generate-registration \
  --server-name localhost:8008 \
  --url http://cumments:7931 > registration.yaml
  • --server-name must equal MATRIX_DOMAIN (localhost:8008 for the local default).
  • --url is the callback URL the homeserver uses to push events. Inside Compose this is the service name, http://cumments:7931; behind a reverse proxy use the public URL instead.
  • The YAML is written to stdout and saved as registration.yaml. The matching as_token and hs_token are printed to stderr — copy them for the next step.

3. Fill in the tokens

Open docker-compose.yml and replace the two placeholders:

      CUMMENTS__MATRIX__APPSERVICE__AS_TOKEN: "<as_token>"
      CUMMENTS__MATRIX__APPSERVICE__HS_TOKEN: "<hs_token>"

The same file is mounted into both containers: tuwunel loads it as its AppService registration, and Cumments validates its configuration against it at startup, so a typo or a mismatched token fails fast.

4. Start the stack

docker compose up -d
docker compose logs -f tuwunel
docker compose logs -f cumments

Cumments should log Configuration loaded successfully., Database initialized., and Server listening on 0.0.0.0:7931.

The example intentionally keeps registration open on tuwunel so the first account can be created with one request. Set TUWUNEL_REGISTRATION_TOKEN and remove TUWUNEL_YES_I_AM_VERY_VERY_SURE_I_WANT_AN_OPEN_REGISTRATION_SERVER_PRONE_TO_ABUSE before exposing the homeserver beyond your machine.

5. Create an account and register the first site admin

The first account registered on tuwunel is granted homeserver admin privileges. Cumments itself does not read a fixed admin account from configuration. Create an account for whoever will run the site:

curl -sS -X POST http://localhost:8008/_matrix/client/v3/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"alice","password":"your-password","auth":{"type":"m.login.dummy"}}'

The response contains the user_id (e.g. @alice:localhost:8008).

If alice is registering for herself, she can DM the bot !cumments sites register my-blog: invite @_cumments_bot to a DM (any Matrix user — local or federated, e.g. @alice:matrix.org — may invite the bot; the bot may auto-join subject to a per-inviter rate limit, which is independent from governance authorization) and send the command in that DM. The bot registers the site, creates the Space and makes the sender the first site admin immediately, without a prior pending claim. Bot membership alone grants no governance privilege; the private-channel check still applies.

DM must be unencrypted for Bot commands. The Bot currently does not decrypt m.room.encrypted, so it cannot read !cumments ... (including the first sites register) in an encrypted room — it will join but appear unresponsive. Create / recreate the DM with encryption off. In particular, if Tuwunel is configured with encryption_enabled_by_default_for_room_type = "invite", new DMs are E2EE by default: turn that off for the Bot DM or set it to none, create a fresh unencrypted DM, re-invite the bot and resend the command. This is a Cumments Bot-command limitation, not a Matrix rule (comment rooms themselves may be encrypted or not; only the Bot DM for commands must be unencrypted). The site owner may still be on a different homeserver than Cumments — federated @alice:matrix.org inviting @_cumments_bot:comments.example works the same, provided the DM is unencrypted.

The API path below is the generic path — use it when the registrant and the first admin are different accounts:

# Registration is mandatory before the site can receive comments. Pick an id
# (it becomes the Space/room aliases), or omit the body for a random id.
curl -sS -X POST http://localhost:7931/api/v1/sites \
  -H "Content-Type: application/json" \
  -d '{"site_id":"my-blog"}' > site.json
SITE_ID=my-blog
CLAIM=$(jq -r .claim_token site.json)

curl -sS -X POST "http://localhost:7931/api/v1/sites/$SITE_ID/admin-claims" \
  -H "Content-Type: application/json" \
  -H "X-Cumments-Claim-Token: $CLAIM" \
  -d '{"user_id":"@alice:localhost:8008"}' | tee admin.json

The response contains a one-time verify_token. The account proves ownership by sending exactly cumments-claim:<token> as a direct message to the AppService bot (@_cumments_bot:localhost:8008):

VERIFY_TOKEN=$(jq -r .verify_token admin.json)
# From the alice account in any Matrix client, DM this text to the bot:
# cumments-claim:$VERIFY_TOKEN

After verification the admin holds power 100 in the site Space and every comment room, and can appoint managers and per-room moderators (see site governance).

6. Verify

  1. Use the visitor frontend from https://github.com/Curious-r/cumments-web (or any API client) against http://localhost:7931 and post a comment.
  2. In Matrix, check that a Space (Comments: <site>), a comment room (Comments: <site>/<page>), and the virtual user were created, and that the admin account appears with power 100 in both.
  3. The comment should appear in the frontend in real time via SSE.

If comments exist in Matrix but not in the API, rebuild the read model from Matrix history:

docker compose exec cumments cumments backfill

Optional: room version 12

Room version 12 hardens rooms (hash-based room IDs, immutable creator power). On tuwunel, set TUWUNEL_DEFAULT_ROOM_VERSION: "12" in the compose environment, or request v12 per room with CUMMENTS__MATRIX__APPSERVICE__ROOM_VERSION: "12" (see configuration.md).

Existing comment rooms on an older room version can be upgraded without recreating the site (the target version must be newer than the room's current version):

docker compose exec cumments cumments rooms upgrades create <room_id> 12

Pre-v12 rooms work too: new Cumments rooms give the bot explicit tombstone power (150) so it can perform the upgrade. Legacy pre-v12 rooms whose bot is only 100 have no in-product upgrade path.

The homeserver moves the room alias to the replacement, Cumments re-adopts the new room, re-links it into the site Space, re-invites site roles, and supersedes the old room. The same operation is available to operators through !cumments rooms upgrades create <room_id> <version> --confirm and POST /api/v1/operator/rooms/{room_id}/upgrades; site admins can trigger it themselves with !cumments pages upgrades create <site_id> <page_slug> <version> --confirm or POST /api/v1/sites/{site_id}/pages/{page_slug}/upgrades (claim token). Every path executes the upgrade as the bot, which stays the new room's creator. Because several surrounding standards are still open (MSC4168/MSC4433), the current behavior includes a few documented compromises — see Architecture.

Troubleshooting

  • Compose refuses to start: the ./registration.yaml bind mount does not exist yet. Run step 2 first.
  • as_token / hs_token mismatch: the values in the compose file do not match the registration YAML. Regenerate both together, or copy them from the stderr output of step 2.
  • Cumments logs invalid hs_token: the token registered on the homeserver differs from CUMMENTS__MATRIX__APPSERVICE__HS_TOKEN; fix and restart both services.
  • Comments exist in Matrix but not in the API: the push queue was blocked or a transaction was never acked; restart the service and, if needed, run cumments backfill.
  • The server name changed after first start: tuwunel stores the server name in its database and cannot change it later. Remove the tuwunel-data volume (docker compose down -v) and start over.