maubot-plugins/docs/2026-06-02-chateau-pilot-review.md
2026-09-20 17:30:51 +02:00

45 KiB

title subtitle date author
Château du Faune — Tracker / Journal pilot review Findings from the first week of !journal, !goals, !tasks usage across four Signal rooms 2026-06-02 aiolabs / Château du Faune

Executive summary

For the past two weeks, members of the Château du Faune have been "going through the motions" of using !journal, !tasks, !goals, !reminder, !buy, !sidequest, and related commands across four Signal rooms — Operations, Animals, Gardens & Food, Events, and the general castle room. Nothing was hooked up yet: the chats are mirrors of what the maubot stack on the new Matrix homeserver will eventually capture. The point was to generate signal — to find out which verbs people actually reach for, how they phrase entries, where the syntax gets in the way, and which features the protocol spec is quietly missing.

This document reads that signal. It is written for both the chateau members (who will see their words quoted back and choices made about how the bot will treat their phrasing) and for the aiolabs/maubot-plugins developers (who will turn the recommendations into code and spec changes). The community-organizer spec is the contract; the tracker/ and journal/ plugins are the reference implementation; the data we collected over the past two weeks is the field test.

Top-line findings:

  1. The capture habit is sticking. The bot doesn't exist yet, and people are still using the syntax — sometimes correcting each other on it. The most surprising data point is that Coco told Helena "!journal is the required format" unprompted. Social enforcement of a syntax we haven't actually shipped is the best possible adoption signal.

  2. The vocabulary the community reaches for is broader than the spec. The current spec lists !task, !sidequest, !journal, !remind, !add, !done, !list, !setup. The chats show people typing !buy, !need, !goals, !stewards, !tasks, !task (singular), !reminders (plural), !idea, !plans, !priority (inline), !side quests, and a few more. Some of these are per-room shortcuts the spec already accommodates; others want a small protocol-level addition.

  3. The 5-level priority scheme came directly from this pilot. Coco proposed "1 urgent / 2 crucial / 3 important / 4 future / 5 frequent/ongoing" in the operations chat on May 24. It is now §3.3.1 of the spec, exactly as proposed. This loop — observe → spec → implement → re-observe — is the one we want to keep running.

  4. The bot will need to be more grammar-tolerant than the spec currently implies. Multiple verbs per message, edited messages that add content, !-words inside bullet points used as priority markers, pinning as a "this is the current list" signal, no-prefix journals — these are all behaviors the bot doesn't catch today but should.

  5. The community is already designing the bot's voice. Alfred got named on May 24 ("we trusted him with resource management, safety, tool use, etc."). Photos got captioned, journals got pinned, Cocopis explained what !tags are to other members. The chateau is treating the bot as a collaborator before it exists. We should lean into that — bot personality is now a design surface.

The rest of this report:

  • §1 What we observed, by room and by pattern
  • §2 What the existing spec + plugins handle well
  • §3 Spec changes proposed
  • §4 Plugin changes proposed
  • §5 New ideas the data surfaced
  • §6 How this fits the larger omnixy / aiolabs ecosystem
  • §7 A phased plan
  • §8 Open questions for the chateau

1 — What we observed

1.1 Verbs in actual use

A frequency-sorted list of every !verb we saw across the four rooms (case-folded), grouped by what the spec or current shortcut config covers:

Verb seen Already in spec Status
!journal Yes (universal) Heavy use across all four rooms
!reminder / !reminders Spec verb is !remind Mismatch — see §3.1
!tasks / !task Spec verb is !task !tasks plural also appears
!goals No New — see §3.2
!stewards No (per-room shortcut candidate) Used as a list/backlog, not a one-off task
!buy Per-room shortcut, fits cleanly Should ship pre-configured for cdf rooms
!need No Distinct from !buy in usage — see §3.2
!sidequest / !side quests Yes Used; "side quests" with space appeared once
!idea / !plans No Speculative / design-phase items
!priority (inline) No (priority is a tag) Used as a bullet-level marker — see §1.4
!move Mentioned by Ulo as a future verb Not in spec

And a usage example per verb so the design instinct is grounded in actual phrasing rather than imagined phrasing:

!journal — past-tense daily log, multi-line is the dominant form:

!journal - opened/closed, watered and fed hens, babies & pacas - put insulators on the rebars so they're ready to go for fence - mentally plotted potential hidden-in-plain-sight stable locations. I want opinions next - should scrape clean duck babes straw tmrw - should clean and dry very well sapphis wound again

Note the mix of past-tense ("opened/closed") and forward-looking ("should scrape clean tmrw") bullets in the same !journal. People do not bucket their day cleanly. §3.4 addresses this.

!goals — a list of current intentions, often nested with sub-categories:

!goals & notes next week for garden/kitchen crew

GARDEN - documentation & journaling process - prepping & starting the Lady Godiva pumpkin patch. …

KITCHEN - forage, harvest & food processing resource improvements (ex. cherries into vinegars…) - filling the shop up (& soon looking into certifying our kitchen/lab) …

!goals lists evolve over days — Coco's gardens !goals on May 27 and June 2 are the same list, refined. This is the strongest argument we found for replaceable-event semantics (§3.3).

!reminder — a future-pointed list, often with embedded @-mentions and !priority markers inside bullets:

!goals this week/soon - attempt to secure alpaca deposit & arrival of the boys - !priority confirm if teeth & nails will also be done by the shearer 'sometime in july' - !priority diagnosis of sapphis skin condition be made by a vet in person. !reminder following shearing, immediately start sapphis skin infection protocol - fencing add in doors & handles. Start soon on setting up 2nd stable paddock

Look at that message carefully: it is one !goals entry, with !priority and !reminder appearing inside bullets as inline markers, not as new commands. This is the single most important parser decision we have to make — see §4.1.

!buy — shopping list, sometimes added-to over days via edit:

!buy - roll out flypaper for stable(s) - door handles for electric (or from laura) - la fourche order, sesame & produce will be thursday, 28th - buy more pans & x2 induction adapters

!need — semantically distinct from !buy. Means "stock is low" rather than "purchase this":

!need puppy & cat food, hay & straw soon

Coco used both in the same week. The distinction matters because !need items become !buy items only after someone agrees to act on them, where !buy is already a decision.

1.2 Cadence patterns — the recurring chore problem

The operations chat opened with a chores list dominated by recurring items with fuzzy intervals:

pacas: - every ~3 days scoop manure - every ~3 days fluff bedding - every 2 wks to 1 month - change out whole bedding - daily fresh water - daily light green/yellow hay - training - max 1x/day - approach with treats in a bucket…

hens & ducks: - am let out, pm close in - every ~3 days fresh water & food - every 1 week change out straw - spend time with the puppies every day

Coco flagged the problem herself: "weird thing is tasks that are every few days or variable timeframes?"

The spec partially anticipates this with priority:5 ("frequent / ongoing"), but priority:5 is a marker, not a cadence. "Every 3 days" and "daily" are different cadences and the bot should know. RFC 5545 RRULE is the canonical answer; NIP-52 doesn't yet codify recurrence (§11 of the spec lists this as open). A lightweight stopgap is proposed in §3.5.

1.3 Multi-verb messages

Helena posted in the Gardens & Food room:

!journal • bigger Team meet and on board of Marta what we did the last weeks… • weeding • getting fresh alpaca manure and distributing • collecting seeds for next year planting

!task - research thing for rain tank - update online garden map - check on sprouting pumpkin seeds and plant when ready

This is one Matrix message but two distinct entries — a !journal and a !task list. The current tracker dispatch regex matches the first verb at start-of-message and stops. The plugin will silently drop Helena's !task block.

This is a real bug, not a theoretical one — Helena was the first person who naturally typed in this shape, and the bot would have lost the task list. §4.2 fixes it.

Skye independently did the same thing on the same day:

!goals !tasks - [ ] organise conversation about image ai making with pat and coco - [ ] Look into creation of the funding via our socials… - [ ] For flyers/posters the !goals is to make one for pats new events app for ariege…

!goals !tasks on one line is yet another shape: two verbs sharing one body. Likely "this entry belongs to both lists" — but the spec needs to say so explicitly.

1.4 Inline !priority and !reminder markers

Returning to Coco's May 27 !goals:

- !priority confirm if teeth & nails will also be done by the shearer 'sometime in july' - !priority diagnosis of sapphis skin condition be made by a vet in person. !reminder following shearing, immediately start sapphis skin infection protocol

!priority and !reminder are appearing inside body content as bullet-level annotations, not as commands. A naïve parser that matches !\w+ anywhere in a message would interpret these as new commands and produce four entries from one message.

The fix is the rule the journal plugin already enforces: a !verb counts as a verb only if it is at the very start of the message (or, with §4.2 in place, at the very start of a top-level block). Everything else is body content with inline tags.

But "inline tags" is itself a feature worth keeping: a bullet starting with !priority is a natural way to mark that bullet as urgent within a larger list. The bot can:

  1. Treat the inline !priority as a tag on the bullet body (preserves the user's intent).
  2. Leave the parent entry's priority alone (the user didn't priority the list; they priority'd one item in it).

A renderer can then surface that bullet as priority-1 within the parent entry. This is a richer model than the spec currently sketches, but it matches what users are actually doing. §3.3 proposes the wire format.

1.5 Pinning as state

Across all four rooms, the dominant !goals / !tasks / !stewards messages are pinned to the room. When the list evolves, the new version is pinned and the old one is unpinned. Matrix has native support for this (m.room.pinned_events).

We propose treating "the latest pinned message matching !goals from a given room" as the current state of that group's working list. This gives every room a queryable "what's on our plate right now" view without requiring users to remember an item id.

§3.3 + §4.5 develop this.

1.6 Implicit subjects — animals, people, places

The animals room is full of entries like:

- thinking of long-term solutions for pups barking and neighbors. - 45 min in the alpaca paddock with both pups, no electricity. - carefully choose feeding station(s) so they are isolated and don't compete with any other animals

(and elsewhere)

lets clean sapphis wound again soon? also just realized the shearer will come in july

The community has named entities — Sapphi, Loki, Leia, Tango, Morrigan, the alpacas, the pups, the hens, the south paddock, the orchard, the coop — that recur across many entries. A useful query is "show me everything mentioning Sapphi this month" or "what tasks involve the south paddock?".

NIP-52 already supports ["p", "<pubkey>"] for people. Animals and places need a convention — see §3.6.

1.7 Inline @-mentions = informal assignment

- location & plans for stable, cont. @coco - closing the main property gate? guardian dogs sign @coco - pruning & landscaping @Thomasss**] - following a budget per person for food orders, picking up produce @Skye 🌟

People mention each other inline to mean "this bullet is yours". The bot can extract these into structured ["p", …] tags and a renderer can surface a per-person "your bullets" view. §4.6.

1.8 Cross-group routing ambiguity

Skye said in the Events room:

"organise a mini meeting to talk about ai image making etc with pat/coco …. I'm not sure which chat to put these social things in hehe"

Some items belong to multiple groups. The current 1-room ↔ 1-community mapping makes this expensive — you'd have to type the same entry twice. Coco's answer ("i think events would be the fitting place") is the human workaround; the bot should help. §5.2 proposes optional multi-room fan-out.

1.9 No-prefix journal-shaped content

Lots of messages look like journals without using any command:

today plan for me: - working in other groups on animals and operations

Today's plan for me: - making bulk buckwheat zucchini burgers some for today and rest in freezer

journal started but did not complete: bathroom clean, mapping stables, fencing the internal 150m paddock

The chateau is explicitly standardizing on !journal (Coco corrected Helena on this in real time). So we should not make the bot fuzzy-match — they want explicit syntax. But the data suggests an opt-in "capture every non-command message in this specific room" mode could be valuable for very-low-friction rooms (e.g. a private journal room per member). Default: off. §5.1.

1.10 Capitalization, punctuation, language

The same intent appears as !journal, Journal:, journal, !journal:, Today plan for me, today plan:, sometimes mixed with French.

The bot's regex needs to be:

  • case-insensitive on the verb (!Journal == !journal)
  • tolerant of a trailing colon (!journal: is fine)
  • bilingual on body content (already true — body is opaque text)

The current _CMD_RE = re.compile(r"^!(\w+)(?:[ \t\r\n]+(.*))?$", re.DOTALL) in tracker.py:52 does match !Journal because \w is case-insensitive in unicode mode, and the dispatch already calls .lower(). But it does not match !journal: because the colon follows the verb with no whitespace. One-line fix in §4.3.

1.11 Edits matter

Two distinct edit patterns appeared:

A. Edit-to-append. Coco edited a !journal post-hoc and commented: "just added that i also fed puppies 2x today". The intent is "this is the same entry, with more content".

B. Edit-to-correct. Coco scheduled a vet appointment for "June 5 @ 14h", then edited the same entry to "May 30 @ 15h" with the note "updated to May 30 @ 15h because they need the vaccination within the month".

The tracker's current known-quirks note (tracker/README.md:133) says:

"Edited messages don't re-trigger the bot. Matrix sends edits as a separate m.replace event that maubot doesn't pass to handlers. Type a fresh message instead of editing."

This is solvable — m.replace events are visible to maubot; the handler just needs to be wired. §4.4.


2 — What the existing spec and plugins handle well

Before proposing changes, let's mark what's already right. The pilot validates a lot of the design.

2.1 The split between universal verbs and per-room shortcuts

The spec says: every implementation must recognize the universal verbs (!task, !journal, etc.); per-room shortcuts (!buy, !harvest, …) expand to them. The data agrees: every room developed its own dialect (animals uses !journal heavily, operations uses !buy and !stewards, events uses !goals). A single plugin serves all of them.

We just need to pre-configure the cdf rooms with sensible shortcuts so members don't have to !setup add buy task #buy on day one. §4.7.

2.2 The passive regex / multi-line story

The journal plugin's switch to @command.passive with a regex was right. Every multi-line entry we observed (and many one-line ones) would have been silently dropped under @command.new. The CLAUDE.md footgun is real and the plugin avoided it.

2.3 The 5-level priority scheme

priority:1..5 with the labels urgent / crucial / important / future / frequent-ongoing came out of the pilot. The renderer plan is to surface labels rather than numbers; the wire tag stays priority:N for sort stability. The data didn't push back on this — Coco's proposal landed exactly as written.

2.4 Sidequests as a separate kind

!sidequest (with a 🎯 emoji ack) gives a distinct surface for "would be cool to do" items. Coco's "!side quests lists which are different from the rest of the tasks" is exactly the use case. The spec already excludes sidequests from default !list output, which is the right default.

2.5 The Matrix-only Phase 1 posture

The tracker is matrix-only for v1 — no Nostr publishing yet. This turns out to be the right call: the four-week dataset shows the community is still finding its vocabulary. Publishing to a public relay before the vocabulary stabilizes would make schema migrations visible to anyone subscribed. Stay matrix-only until the verb set is stable, then bridge.

2.6 The journal plugin's append-only stance

The spec's "!done on a journal entry is undefined behavior; implementations SHOULD reject it" matches the data: nobody tried to close a journal. They edit, they re-journal, they pin — they don't close. Good call.


3 — Spec changes proposed

These are protocol-level additions to docs/community-organizer-spec.md. Each is small. None breaks existing conformance — they extend, they don't refactor.

3.1 Plural aliases for universal verbs

!reminders and !tasks should be accepted as equivalents of !remind and !task. !sidequests likewise. This is a one-line parser change; it costs nothing and removes a footgun (users will naturally pluralize when a list is multi-item).

Spec change: in §3.1, add a row: "Implementations MUST accept the bare plural form of each verb (!tasks, !sidequests, !reminders) as equivalent."

3.2 New universal verbs: !goals and !need

Both verbs got real, repeated, distinct-from-existing usage. Both deserve protocol-level status, not per-room shortcut status, because:

  • They had identical meaning across all four rooms. A bakery co-op reading this spec should be able to use them without re-configuring.
  • The shortcut mechanism is for vocabulary the community invented (e.g. !harvest, !brewery). !goals and !need are not vocabulary inventions — they're a category the spec missed.
New verb Purpose Underlying kind
!goals <text> A list of current intentions for the author/group/period. Replaceable per (author, room, period?). 31922 with ["t", "goals"]
!need <text> A supply that is running low. Distinct from !buy (which is "I will purchase this"). Default lifecycle: open → !buy (converts to task) or !done. 31922 with ["t", "need"]

!goals deserves §3.3 (replaceable semantics) since the goals lists visibly evolved over days in the pilot.

3.3 Replaceable-event semantics for !goals (and stewards lists)

NIP-52 kind 31922 is a parameterized replaceable event keyed by d-tag. Today the tracker assigns a unique d per entry. For !goals (and the per-room !stewards list pattern), we want the opposite: the latest !goals from a given (author, room) pair should replace the previous one.

Spec change: in §3.3, add: "Implementations MAY designate certain verbs as replaceable per (author, room, period?). When a verb is replaceable, the bot reuses the same d-tag for successive captures, so the relay retains only the latest version. Recommended replaceable verbs: goals, stewards."

The period qualifier lets !goals this week and !goals next week coexist. Suggested encoding: a period: tag (e.g. period:2026-w22). For v1 we keep it simple — no period qualifier, latest wins.

The pinning UX hooks straight in: when a !goals message is the latest replaceable entry from its author, the bot can ask Matrix to pin it (and unpin the previous one). This makes the room's pinned message a live mirror of the relay state.

3.4 Forward + retrospective in a single !journal

The data shows people blend "did X" and "will do Y tomorrow" in the same !journal. The spec currently says journals are past-tense and append-only. Rather than fight the user, we accept the blend.

Spec change: in §3.1, clarify: "!journal is append-only; implementations MUST NOT close journals. Bodies MAY contain forward-looking statements; the classifier MAY surface these as candidate tasks at review time but MUST NOT auto-create derived task entries."

The "candidate task" idea is a v2 nicety: a weekly digest that pulls "should…" bullets out of journals and offers them as !task candidates. Not in v1.

3.5 Recurrence tags (lightweight, pre-RRULE)

For the chore-list problem (every ~3 days scoop manure, daily fresh water), we propose a frequency: tag namespace that lives inside the existing ["t", …] mechanism. Renderers parse it.

Suggested values:

Tag Meaning
frequency:daily Once per day
frequency:weekly Once per week
frequency:3d Every 3 days
frequency:2w Every 2 weeks
frequency:as-needed No fixed cadence; on demand

This is a stopgap. When NIP-52 or a sibling NIP defines proper recurrence, we migrate. For now, the eink renderer can group frequency:daily items into a "today" panel and frequency:weekly into a "this week" panel without parsing RRULE.

Spec change: in §3.3, add: "frequency:<spec> is reserved for recurrence hints. Recommended values: daily, weekly, Nd (every N days), Nw (every N weeks), monthly, as-needed. Implementations MAY define additional values."

3.6 Subject tags — animals and places, not just people

NIP-52 has ["p", <pubkey>] for people but no convention for non-human subjects. We propose a namespaced t-tag:

Tag Meaning
subject:animal/sapphi Animal named Sapphi
subject:animal/loki Animal named Loki
subject:place/south-paddock A named place on the property
subject:object/electric-fence A named asset/object

A community can define its own subject vocabulary via !setup:

!setup subjects animal/sapphi animal/loki animal/leia
!setup subjects place/south-paddock place/orchard

When typing, members can reference subjects with a @-prefix as shorthand:

!journal cleaned @sapphi's wound, fed @hens at noon

The bot expands @sapphi to subject:animal/sapphi tags and preserves the original text in the body. Renderers can then offer "recent entries about Sapphi" without the bot needing to do NLP.

For people the existing ["p", "<mxid-or-pubkey>"] already works; inline @person:name (or just @-mentions resolved through the Matrix room's member list) feeds straight into that.

3.7 Inline !verb markers within a body are tags, not commands

This is half a spec change, half a clarification:

Spec change: in §3.3, add: "A !verb occurring at the start of a message (or, with multi-verb support, at the start of a top-level block) is a command. A !verb appearing inside body content is body content and MAY be extracted by the bot as an inline:<verb> tag on the parent entry. This preserves user intent without spawning ghost entries."

So Coco's - !priority diagnosis of sapphis skin condition… bullet gets recorded as part of the parent !goals entry, and the parent gets an inline:priority tag. A renderer can surface that bullet with priority styling.

3.8 Multi-line entries with sub-headers

A small content-format convention so renderers can do something sensible with Coco's GARDEN / KITCHEN sub-headers:

Spec change: in §10, add: "Bodies MAY use Markdown-style headers (#, ##) as in-body section markers. Renderers MAY surface them as visual groupings. The body remains a single content blob; sub-headers do not split the entry."


4 — Plugin changes proposed

These are concrete edits to tracker/, journal/, and a small amount of wiki/ if we want cross-plugin discovery. Each maps to a specific file path so the work is sized.

4.1 Parse inline !verb markers as tags, not commands

tracker/tracker.py:184 — the dispatch handler matches a verb at start-of-message. Today, anything else is unmatched and the message is dropped (correct). We extend: after dispatching the top-level verb, scan the body for inline !verb occurrences and add them as inline:<verb> tags on the recorded entry. Implementation is a single pass over the body before recording.

This makes Coco's - !priority … bullets actually do something useful at the entry level without inventing ghost entries.

4.2 Split multi-verb messages

tracker/tracker.py:52 — the _CMD_RE regex anchors at start-of-string and captures everything to end-of-string. We change to a two-pass parse:

  1. Split the message at every line that starts with !verb (and only such lines — bullets like - !priority … are NOT split points).
  2. Each split block becomes its own captured entry.

Helena's !journal … !task … message becomes two entries. Skye's !goals !tasks on a single line stays as one entry but gets both tags applied. This requires a second regex for the multi-verb-one-line case.

The order matters: split first on newline-prefixed !verbs, then on the single-line multi-verb case.

4.3 Tolerate trailing colon and case on verb

tracker/tracker.py:52 — change the regex to allow an optional trailing colon and explicit case-insensitive flag:

_CMD_RE = re.compile(r"^!(\w+):?(?:[ \t\r\n]+(.*))?$", re.DOTALL | re.IGNORECASE)

(The .lower() already happens in dispatch; the regex flag is for unicode \w consistency. Trailing colon is the visible change.)

Apply the same change to journal/journal.py:34 for _JOURNAL_RE.

4.4 Handle Matrix edits

tracker/tracker.py — register a handler for m.room.message events with rel_type == "m.replace". The handler:

  1. Looks up the original event id in the items table (we need to start recording it — schema change below).
  2. If the original is a captured entry, treat the edit as a body update on that entry. Bump a last_edited_ts.
  3. Reply with a small ack ("✏️ Updated entry 42").

Schema change: add mx_event_id TEXT column to items, indexed. This is a real change to upgrade_table — add as upgrade_v2.

tracker/README.md:133 — strike the "Edited messages don't re-trigger the bot" caveat.

This is the single change that unlocks the most observed user behavior. People do edit, and treating edits as no-ops loses substantial information.

4.5 Detect pin events; mark replaceable verbs as pinned

tracker/tracker.py — subscribe to m.room.pinned_events. When a captured entry's source Matrix message becomes pinned, mark the entry as pinned=true. When a !goals entry is recorded, the bot itself asks Matrix to pin the message (and unpin the previous !goals from the same author).

This makes the pinned-message UX a transparent mirror of the relay state, without users needing to manually pin/unpin.

(This requires the bot to have pin-event permission in the room. The admin can grant it via Element. Document in the README.)

4.6 Extract inline @-mentions as p-tags

tracker/tracker.py — alongside the existing _TAG_RE extraction for #tag, add an _MENTION_RE extraction for @user. Resolve against the Matrix room's member list (best-effort; if it doesn't resolve, store the literal string).

The recorded entry gets ["p", "<mxid>"] tags for each resolved mention, and keeps the @user substring in the body for human readability. A renderer can then offer a "your bullets" view per person.

4.7 Ship sensible default shortcuts for the cdf rooms

tracker/tracker.py — add a one-time bootstrap that, on first !setup (or first capture) in a room whose name matches a known chateau room, pre-populates shortcuts. Suggested defaults:

Room name Shortcuts
Animals !buy task #buy, !chores task #priority:5, !vet task #vet, !need need
Gardens !buy task #buy, !harvest task #harvest, !plant task #plant, !need need
Operations !buy task #buy, !steward task #steward, !repair task #repair, !need need
Events !host task #host, !ticket task #ticket

These are starting points, not a final list. Communities edit them via !setup once they're in.

A safer way to ship this is a default_shortcuts.yaml config the plugin reads, so changes don't need a code redeploy.

4.8 New universal verbs implementation

tracker/tracker.py:56 — add to UNIVERSAL_VERBS:

UNIVERSAL_VERBS = {
    "add", "task", "tasks", "sidequest", "sidequests",
    "remind", "reminders", "done", "list", "setup",
    "goals", "need", "needs",
}

(Plural aliases per §3.1.)

Add _handle_goals and _handle_need handlers. !goals uses replaceable-event semantics (§3.3) — for the matrix-local v1, this means upserting on (user, room, kind='goals') rather than inserting. One row per author per room.

!need records a kind='need' item that stays open until either !done (we got some) or another verb explicitly converts it to a !buy task.

4.9 Frequency tag parsing in !list

tracker/tracker.py:302 — when listing items, group by frequency: tag so the chore-list renders as:

**Daily (3):**
- `5` fresh water for alpacas
- `7` fresh water for ducks
- `12` open & close hens

**Every 3 days (2):**
- `19` scoop alpaca manure
- `23` fluff alpaca bedding

**Weekly (1):**
- `4` change out hen straw

This is rendering, not protocol — the spec just stores tags.

4.10 Replace the tracker/README.md quirk note

After §4.4 lands, strike the edit caveat. Add a paragraph on the new pin behavior, the new universal verbs, and the multi-verb splitting.


5 — New ideas the pilot surfaced

5.1 Opt-in "private journal room" mode

For a per-user private journal room (one bot account, one human member), the prefix friction adds nothing — every message is journal content by definition. We can add a per-room flag auto_journal: true (default false) that records every plain message as a !journal entry. This is opt-in per room and the bot acks loudly the first time it activates so nobody is surprised by it.

For shared rooms — which is everywhere in the pilot — the default stays explicit-prefix-only, matching Coco's "!journal is the required format" enforcement.

5.2 Multi-room fan-out

Skye's "I'm not sure which chat to put these social things in" suggests an entry can sometimes belong to multiple rooms. We propose a +#room syntax:

!task +#events +#general organize image-AI brainstorm with pat and coco

This records the entry in both communities. The same entry has two a-tags (one per NIP-72 community). Renderers in either room see it. !done closes it in both.

Implementation: parse +#<roomname> tokens out of the body, resolve to room ids the bot is also a member of, and insert one row per target room with a shared link_id. v2 work, not v1.

Helena's "checked feathered babies" entry was actually a photo + caption. Thomas shares YouTube links. Coco shared a PDF on toxic plants. The body field today is text; the bot can capture media attachments by storing their mxc:// URI in a media JSON column. A renderer can fetch and display.

Especially valuable for the eink panel — a photo of the daily chores list, a graph of fed/watered checkmarks, the duck-pool-water-runoff diagram.

5.4 Calendar feed for timed entries

Pat already saw the vet appointment on the castle calendar — "nice i already see it on the castle calendar". This integration should be documented: where it lives, what feeds it. If it's manual, it should be automated; if it's automated, it should be tested for all kind 31923 timed entries.

The natural shape: an iCalendar feed at https://docs.ariege.io/calendar.ics produced from the bot's timed-entry table. Castle members subscribe in their calendar app of choice.

5.5 Daily / weekly digests

The pilot showed the value of summary. Coco pins a current !goals. Ulo posts meeting summaries. Helena writes "homework" recaps. The bot can produce these on a cron:

  • Morning digest (per room): "Yesterday's journal entries (3), Open tasks this week (12), Goals pinned (1)."
  • Weekly digest (Sunday evening): "This week's completed tasks (28), Open carry-over (15), Journal highlights (a sampling)."

This is a content surface, not protocol. The data is already there. Implementation = a cron handler + a markdown template + posting to the room. Maubot has cron support via asyncio + croniter.

5.6 Bot personality — Alfred

The community named the bot Alfred (the butler). Replies should match: a slightly formal, helpful, occasionally dry tone.

Concretely:

  • Current acks: 📥 Logged for @alice.
  • Alfred-flavored: Very good, @alice. Logged.

A personality config field with default | alfred | minimal lets other adopting communities pick. Keep default deadpan and neutral.

This is low-priority but it costs nothing and the data shows the community will engage with the bot more if it feels like a collaborator. "What should we name our assistant?" — "Alfred would be my go to" — "doiittt" is a community taking ownership of the tool before it exists.

5.7 LLM fallback inside the chateau network

The spec's classifier conformance level 2 is LLM fallback. The chateau has an existing Ollama setup or can run one on the same host as maubot. The fallback fires only when:

  • The user typed !add (explicit ambiguity),
  • The rules classifier returned unclassified,
  • The LLM is reachable.

If any condition fails, the entry stays in the inbox until human-sorted (level 0 fallback). The architecture stays self-hostable.

Smallest reasonable model for this is in the llama3:1b / phi3:mini size range — runs comfortably on the maubot host.

5.8 Wiki / docs lookup inside the tracker context

The wiki plugin already exists. Inside a tracker reply, if an entry mentions e.g. "recycling", the bot could surface a [?] hint: "Related: docs.ariege.io/spaces/waste-recycling". One-line link, ignorable.

This makes the chateau's docs site organically discoverable from chat without anyone needing to remember URLs. Implementation: inside the tracker's record path, fire a quick keyword query at the wiki plugin's index and append top-1 result if confidence is high.


6 — How this fits the larger omnixy / aiolabs ecosystem

The Château pilot is one community using one piece of the stack. The broader picture:

6.1 The protocol survives the implementation

The community-organizer spec is CC0 and references only open standards (RFC 5545 VTODO, NIP-52, NIP-72, ActivityStreams). If the maubot plugin disappears tomorrow, the events on the relay are still readable by any NIP-52 client. The chateau's organizational memory is not coupled to maubot. That's the design property we're protecting.

6.2 Nostr bridge (Phase 2)

Today the tracker is matrix-only. When the vocabulary stabilizes (probably 2-4 more weeks of pilot), Phase 2 bridges to Nostr:

  • Bot writes captured entries to a community Nostr relay.
  • The relay can be private (auth-gated) or public per the publish posture config.
  • Renderers (the eink panel, a future webapp dashboard) subscribe to the relay and surface the data.

This is the unlock for the inky-impression panel in the foyer — the data shape it consumes is exactly the events the bot will be producing.

6.3 Identity — the signer abstraction

Today everything is signed by the bot. The spec's §7.2 / §12 develop the per-user-signing endgame: a sidecar nsecbunkerd on the same host, the bot holding only scoped NIP-46 connection tokens.

At chateau scale (10-20 members), this is overkill for v1. We run v1 (trust the bot, author tag carries the human MXID) for as long as the community is small and physical-trust-bounded. We migrate to per-user signing when:

  • More than one community is using the same bot account, or
  • An external party (visitor, woofer, neighbor) needs to write entries without being a fully-trusted member, or
  • LNbits #18 (the bunker integration) ships and we want a single identity story across the stack.

The signer abstraction is already in the spec, so the migration is design-for-it-now, do-it-later.

6.4 LNbits / Lightning

Two Lightning hooks the pilot suggests:

Marketplace / payable buy items. A !buy item could optionally carry a price and produce a Lightning invoice via LNbits when clicked through. "Roll-out flypaper — €12 — pay" with the invoice generated against the chateau's funding wallet. Useful for outside contributors who want to chip in a specific item.

Visa funding stream. Coco's alpaca funding stream (€23k over time) is exactly the kind of recurring-pledge use case LNbits has. This is a partnership channel between the tracker and the LNbits extension at the marketplace level, not v1.

6.5 Events app

Coco's events-app side-project is in the pilot data: "developing the app & biz plan for tech company of an ariege-wide calendar of events app". The tracker's NIP-52 31923 events are the right shape to feed that calendar. The webapp consumes NIP-52 already (per the bunker spec discussion). One data shape, two surfaces: the bot records, the events app displays.

6.6 Continuwuity homeserver

The Matrix homeserver running this is Continuwuity, deployed via deploy/server-deploy/modules/services/matrix.nix. The maubot daemon registers via the admin-room token flow (see ~/dev/CLAUDE.md Matrix-homeserver section). All bot accounts in this report (@journalbot, future @trackerbot, @wikibot, etc.) are regular Matrix users on that homeserver.

The bot-as-user pattern means a chateau member can DM the bot privately (e.g. for personal !journal entries the public room shouldn't see). The current journal plugin already supports this — just invite the bot to a 1-1 room.

6.7 Wiki cross-cutting

The wiki plugin (!ask, !doc) reads docs.ariege.io. The chateau's documentation should grow alongside the tracker — when a new community-life protocol gets agreed on at a meeting (e.g. "who feeds the cat"), it should land in docs.ariege.io/spaces/... and be !ask-able. The pilot showed several decisions that would benefit from durable documentation: the chickens' opening time, the puppy training schedule, the vet's number.

This argues for a small tracker → wiki integration: when a !journal entry contains a decision (heuristically: contains "we decided" / "rule" / "from now on"), the bot pings the room with "This looks like a durable decision — would you like to file it as a docs page?". One-click → wiki page draft.


7 — Phased plan

A 5-phase rollout that keeps each step small, deployable, and reversible.

Phase 0 — Verb normalization and edit handling (next 1-2 weeks)

Small parser / dispatch changes. No schema migrations beyond mx_event_id.

  • §4.1 inline !verb markers as tags
  • §4.2 multi-verb-per-message splitter
  • §4.3 trailing-colon + case
  • §4.4 edit handling (schema v2: add mx_event_id)
  • §4.8 new universal verbs (!goals, !need, plural aliases)
  • §4.10 README updates

After Phase 0, the bot won't drop any of the entries we observed.

Phase 1 — Replaceable goals and pinning (2-4 weeks)

  • §3.3 replaceable-event semantics in spec
  • §4.5 pin/unpin behavior on !goals recording
  • §4.7 default shortcuts for cdf rooms
  • §4.9 !list grouping by frequency

After Phase 1, !goals becomes a living list per author and the chore-recurrence model is at least visible to renderers.

Phase 2 — Subjects, mentions, recurrence (4-6 weeks)

  • §3.5 frequency: tag in spec
  • §3.6 subject tags (animals, places)
  • §4.6 inline @-mention extraction
  • §3.7, §3.8 grammar clarifications in spec
  • §5.5 daily/weekly digests

After Phase 2, the eink panel can render meaningful views without needing protocol changes.

Phase 3 — Nostr bridge (6-10 weeks)

  • Wire the tracker's local SQLite to a Nostr publisher.
  • Subscribe to events tagged with the bot's communities for bidirectional sync.
  • Eink panel goes live against the relay.

Phase 4 — Per-user signing and identity (when LNbits #18 ships)

  • Operator-IdP + sidecar bunker per spec §12.
  • Chat-handle ↔ pubkey binding via LNbits.
  • Bot acquires scoped NIP-46 tokens per member.
  • BotSigner becomes the fallback only.

8 — Open questions for the Château

Things the team should weigh in on before we lock the next phase:

  1. Verb names. Is !goals the right word, or !intentions / !focus / !agenda? Same for !need vs !stock vs !low. The bot will accept what the community uses — but the spec name will stick.

  2. Default shortcuts per room. §4.7 lists candidates. Anything missing? Anything wrong? Specifically: does the Animals room want !vet and !med as separate kinds, or one !health?

  3. Subject vocabulary. Which animals, places, and assets are worth naming as subjects? Suggested first pass: animals — Sapphi, Loki, Leia, Tango, Morrigan, plus group names (alpacas, hens, ducks, pups, hatchlings). Places — orchard, south-paddock, coop, garage, kitchen, lab, dependence. Assets — tractor, electric-fence, van, irrigation.

  4. Calendar integration. Today something turns dated journal entries into castle-calendar items. Who owns that pipeline? Should the bot own it? Should we publish an .ics feed off the maubot host?

  5. Photo / media capture. Does it matter that journal entries capture the photos attached to them, or is text enough for v1? (Materially affects storage and the eink panel.)

  6. The "Alfred" persona. Yes / no / opt-in per room?

  7. The private-journal room mode. Would members value a 1-1 DM with the bot where every message is auto-journaled, or does the explicit !journal everywhere feel cleaner?

  8. LLM fallback. Comfortable running a local model on the same host that classifies !add entries? Or stay rules-only?

  9. Cross-room fan-out. Do members value +#room1 +#room2 syntax, or is "I'll just repost in the other room" fine?


Appendix A — Glossary

  • Verb — A !-prefixed word at the start of a message that the bot recognizes as a command (e.g. !journal, !task).
  • Tag — A #-prefixed word inside a message that gets attached to the entry as metadata (e.g. #buy, #priority:1).
  • Subject — A @-prefixed word that names an entity (animal, place, asset) the entry is about.
  • Shortcut — A per-room alias that expands to a universal verb
    • tags (e.g. !buy expands to !task #buy).
  • Replaceable event — A NIP-52 event keyed by a d-tag, where newer events overwrite older ones with the same key. Used for living lists like !goals.
  • Inbox — Where !add entries land when the classifier can't determine a kind. Cleared via !sort or !reclassify.
  • Bot — The maubot plugin instance attached to a Matrix client account (e.g. @journalbot:ariege.io).
  • Renderer — Any output surface (eink panel, webapp dashboard, mobile notification) that consumes captured events.

Appendix B — File map

Concrete files this report's proposals would change:

File Change
docs/community-organizer-spec.md §3.1 plural aliases, §3.2 new verbs, §3.3 replaceable, §3.5 frequency, §3.6 subjects, §3.7 inline markers, §3.8 sub-headers
tracker/tracker.py:52 Regex updates (case-insensitive, trailing colon)
tracker/tracker.py:56 UNIVERSAL_VERBS additions
tracker/tracker.py:184 Dispatch — multi-verb + inline tag extraction
tracker/tracker.py New _handle_goals, _handle_need, _handle_edit
tracker/tracker.py (upgrade table) upgrade_v2 — mx_event_id, link_id, pinned columns
tracker/classify.py Optional — LLM fallback wiring
tracker/README.md:133 Strike the edit caveat, document new behaviors
journal/journal.py:34 Regex update consistent with tracker
wiki/wiki.py Optional !ask-from-tracker integration

End of report.