docs: add umbrella + journal READMEs
Root README orients new contributors on the build/upload/iterate loop and points at ~/dev/CLAUDE.md for maubot patterns. journal/ README covers the three commands, the SQLite schema, known quirks (edits don't re-trigger, subcommand detection scope), and documents why this plugin uses @command.passive instead of the more obvious @command.new. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
057ed0ed45
commit
b21ad2890f
2 changed files with 140 additions and 0 deletions
58
README.md
Normal file
58
README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# maubot-plugins
|
||||||
|
|
||||||
|
Umbrella for [maubot](https://github.com/maubot/maubot) plugins used by
|
||||||
|
the aiolabs / Château du Faune Matrix stack. The maubot daemon itself
|
||||||
|
is provisioned via `server-deploy/modules/services/maubot.nix` on the
|
||||||
|
castle hosts; the actual plugin code lives here.
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
| Plugin | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| [`journal/`](./journal/) | Farm-journal bot. `!journal <text>` records what you did, scoped per-user/room/timestamp. `!journal show [@user]` and `!journal today` query back. |
|
||||||
|
|
||||||
|
## Building a plugin
|
||||||
|
|
||||||
|
A `.mbp` is just a zip containing `maubot.yaml` + the plugin's Python
|
||||||
|
modules at the root. No special tooling needed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd <plugin>/
|
||||||
|
zip -j ../<plugin>.mbp maubot.yaml *.py
|
||||||
|
```
|
||||||
|
|
||||||
|
(`-j` strips the directory prefix so files land at the zip root.)
|
||||||
|
|
||||||
|
## Uploading / iterating
|
||||||
|
|
||||||
|
1. Open the maubot UI (e.g. `https://maubot.<domain>/_matrix/maubot/`).
|
||||||
|
2. **Plugins → +** (first time) or click the existing plugin → upload
|
||||||
|
the new `.mbp`. Maubot keys plugins by `id`; uploading a new
|
||||||
|
`version` of the same `id` replaces the old one.
|
||||||
|
3. **Hit Save** on the affected instance after upload — toggling
|
||||||
|
Enabled without Save will revert. Easy facepalm.
|
||||||
|
|
||||||
|
Bump `version:` in `maubot.yaml` for every meaningful change so the
|
||||||
|
maubot UI surfaces it cleanly and old `.mbp` files in
|
||||||
|
`/var/lib/maubot/plugins/` aren't ambiguous.
|
||||||
|
|
||||||
|
## Bot account convention
|
||||||
|
|
||||||
|
Each plugin attaches to a Matrix client (a regular Matrix user account
|
||||||
|
controlled by maubot). For the journal bot: `@journalbot:ariege.io`.
|
||||||
|
Bot accounts are created the same way as any user — issue a
|
||||||
|
registration token from the Continuwuity admin room
|
||||||
|
(`!admin token issue --once`) and register through Element, then add
|
||||||
|
the client in the maubot UI.
|
||||||
|
|
||||||
|
Invite the bot to whichever rooms it should serve via `/invite
|
||||||
|
@<bot>:<domain>` — maubot's autojoin handles new invites that arrive
|
||||||
|
after the client's sync loop is up.
|
||||||
|
|
||||||
|
## Patterns + gotchas
|
||||||
|
|
||||||
|
Maubot-specific patterns (command decorators, multi-line caveats,
|
||||||
|
`database_type` in `maubot.yaml`, etc.) live in `~/dev/CLAUDE.md`
|
||||||
|
under "Maubot plugin development". Read that before writing a new
|
||||||
|
plugin — there are several footguns that look fine but silently lose
|
||||||
|
data.
|
||||||
82
journal/README.md
Normal file
82
journal/README.md
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# journal
|
||||||
|
|
||||||
|
Daily-journal Matrix bot. Each room member can record what they did,
|
||||||
|
and anyone in the room can query the log.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```
|
||||||
|
!journal <what you did> record an entry (multi-line OK)
|
||||||
|
!journal show [@user:domain] last 10 entries, optionally filtered by user
|
||||||
|
!journal today all entries from today (UTC)
|
||||||
|
```
|
||||||
|
|
||||||
|
Multi-line works either inline or after a newline:
|
||||||
|
|
||||||
|
```
|
||||||
|
!journal Did three things today:
|
||||||
|
- planted garlic
|
||||||
|
- mucked out the goat pen
|
||||||
|
- finished the irrigation patch
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
!journal
|
||||||
|
- planted garlic
|
||||||
|
- mucked out the goat pen
|
||||||
|
```
|
||||||
|
|
||||||
|
Both record the full body verbatim.
|
||||||
|
|
||||||
|
## Storage
|
||||||
|
|
||||||
|
One SQLite database per maubot instance, at
|
||||||
|
`/var/lib/maubot/plugin-dbs/journal.db` on the host. Schema (managed
|
||||||
|
by `mautrix.util.async_db.UpgradeTable`):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE entries (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user TEXT NOT NULL, -- @sender:domain
|
||||||
|
room TEXT NOT NULL, -- !roomid:domain
|
||||||
|
ts BIGINT NOT NULL, -- ms since epoch (from evt.timestamp)
|
||||||
|
text TEXT NOT NULL -- raw entry body
|
||||||
|
);
|
||||||
|
CREATE INDEX entries_user_ts ON entries (user, ts DESC);
|
||||||
|
CREATE INDEX entries_ts ON entries (ts DESC);
|
||||||
|
```
|
||||||
|
|
||||||
|
Wipe data via the maubot UI's per-instance **Database** tab:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
DELETE FROM entries;
|
||||||
|
DELETE FROM sqlite_sequence WHERE name = 'entries';
|
||||||
|
```
|
||||||
|
|
||||||
|
(The second line resets the auto-increment counter; skip it if you'd
|
||||||
|
rather keep IDs monotonic across resets.)
|
||||||
|
|
||||||
|
## Known quirks
|
||||||
|
|
||||||
|
- **Edited messages don't re-trigger the bot.** Matrix sends edits as
|
||||||
|
a separate `m.replace` event that bots don't react to. If you typed
|
||||||
|
`!journal` then edited the message to add content, the bot saw only
|
||||||
|
the empty `!journal` and won't record. Send a fresh message instead
|
||||||
|
of editing.
|
||||||
|
- **`!journal show <random text>` runs the show query with that text
|
||||||
|
as the user filter.** If it doesn't match any MXID, you get
|
||||||
|
"No entries." Use a fully-qualified MXID like `@pat:ariege.io`.
|
||||||
|
- **Subcommand detection only looks at the first line.** Anything
|
||||||
|
starting with `show ` or `today` on the first line dispatches to
|
||||||
|
the query handlers; anything else (including prose that happens to
|
||||||
|
contain "show" mid-text) records as an entry.
|
||||||
|
|
||||||
|
## Architecture note
|
||||||
|
|
||||||
|
This plugin uses `@command.passive` with a regex matcher rather than
|
||||||
|
`@command.new`. The reason — and why other plugins should consider the
|
||||||
|
same pattern for prose-input commands — is documented in `~/dev/CLAUDE.md`
|
||||||
|
under "Multi-line freeform parent commands". Short version:
|
||||||
|
`@command.new` silently drops `!journal\n<content>` because maubot's
|
||||||
|
parser only treats space as the command/args delimiter, leading to
|
||||||
|
invisible data loss when users naturally hit Enter after the command.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue