maubot-plugins/CLAUDE.md
Padreug 1f195fb36d docs: add community-organizer protocol spec
Defines the vocabulary, NIP-52 event shapes, NIP-72 community model,
and lifecycle for a chat-captured + Nostr-stored community organizer
spanning the `tracker` maubot plugin (forthcoming) and renderers like
inky-impression.

Reuses existing standards (RFC 5545 VTODO, NIP-52, NIP-72,
ActivityStreams vocab) instead of inventing new event kinds, so other
communities can adopt the same shape and renderers interop across
implementations. Spec lands before any plugin code so the contract
isn't an after-the-fact derivation from the implementation.

CLAUDE.md + README now point at the spec as the source of truth for
verb/event/tag changes — future sessions update the spec first, not
the plugin code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:12:37 +02:00

4.2 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this repo is

Umbrella of plugins for maubot, the Matrix bot framework. The maubot daemon itself is provisioned by ~/dev/deploy/server-deploy/modules/services/maubot.nix on the castle hosts (currently cfaun). This repo is the canonical place for plugin code; do not edit plugin code from a server-deploy session.

Layout: one subdir per plugin, each containing maubot.yaml + the Python sources. Built .mbp files are gitignored and live next to their source dir after zip -j ../<plugin>.mbp ....

Where to find context

  • Per-plugin docs: <plugin>/README.md covers commands, schema, quirks, etc.
  • Repo-wide build/upload flow: root README.md.
  • Community-organizer protocol spec: docs/community-organizer-spec.md defines the vocabulary, event shapes (NIP-52 + NIP-72), lifecycle states, and tag conventions shared across the tracker plugin, the inky-impression renderer, and any future surface (webapp form, CLI, etc.). Read this before changing any verb behavior, tag shape, or event structure — it's the contract other implementations (and other communities) build against. Don't redesign these in plugin code; update the spec first.
  • Maubot patterns and footguns: ~/dev/CLAUDE.md under "Maubot plugin development" — covers database_type semantics, @command.new vs @command.passive, multi-line caveats, etc. Read that before adding new plugins or non-trivial command handlers; there are several silent-data-loss footguns.
  • Daemon configuration / nginx / sops secrets: in ~/dev/deploy/server-deploy/modules/services/maubot.nix and the host's sops.nix / secrets.yaml. Don't edit those from here — cross-repo coordination point.

Iteration loop

Standard cycle when modifying an existing plugin:

cd <plugin>/
# edit
$EDITOR journal.py
# bump version in maubot.yaml so the UI surfaces the new build
$EDITOR maubot.yaml
# zip
rm -f ../<plugin>.mbp
zip -j ../<plugin>.mbp maubot.yaml *.py
# upload via maubot UI → Plugins → click existing → upload
# then click into the instance and hit SAVE (toggling Enabled
# alone doesn't persist — easy facepalm)

For brand-new plugins, also create the bot's Matrix account first (via Continuwuity registration token from the admin room — !admin token issue --once, then register through Element), add it as a Client in the maubot UI, then create an Instance binding the plugin to that client. Existing example: @journalbot:ariege.io for journal/.

maubot.yaml conventions for new plugins

  • id: use the dev.aiolabs.<name> namespace. Maubot keys plugins by this string in its DB and on disk (/var/lib/maubot/plugins/ dev.aiolabs.<name>-v<ver>.mbp), so it must be globally unique across every maubot ecosystem — reverse-DNS is the convention (cf. xyz.maubot.reminder). Reserving dev.aiolabs.* for our plugins keeps ids predictable and rename-safe. Changing the id later is a fork, not a rename: every existing instance gets orphaned.
  • database_type: if you need storage → asyncpg (or sqlalchemy for legacy code). That field names the API style, NOT the storage backend. sqlite or postgres there fails at instance start with RuntimeError: Unrecognized database type ... — the storage backend is chosen at the daemon level via plugin_databases.{sqlite,postgres} in the maubot config and is independent of what the plugin declares.

Commits

Direct commits to main are the working convention while this stays single-maintainer. Conventional-commits style (feat(<plugin>):, fix(<plugin>):, docs:). Tag at deploy-ready boundaries if/when the repo ever needs publishable releases — for now, the maubot UI reads versions from the uploaded .mbp, not from git tags.

Pyright noise

maubot / mautrix imports are unresolved in pyright + .subcommand "unknown attribute" warnings on decorator-extended functions are expected — the SDK is heavily dynamic and pyright can't introspect the decorators. Ignore these; they don't reflect runtime behavior.