9.2 KiB
PR#100: matrix send and matrix read
Version: minor
WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.
Related Links
- werkregie PR#91,
matrix react. - werkregie PR#93, the running relay sends the reaction through
control.sock.
Problem
An agent can only react to a message in a Matrix room, not write one or read the room.
The rooms are end-to-end encrypted, so the client API with curl is not enough;
only the verified device of matrix login has the keys.
Non-Goals
- No Markdown: the message is plain text; the human decided against a new runtime dependency for it.
- No replies, threads, edits, files or reactions with
send. - No new device or login: the commands use the device of
matrix login. - No change of
matrix react.
Specification
Feature: an agent writes and reads a Matrix room with the user's device
Scenario#100.01: send a message
… so that an agent can write into an encrypted room.
- Given the device of
matrix loginis verified and member of the room "HSAdmin NG" - When an agent runs
werkregie-dashboard matrix send --room "HSAdmin NG" "Build ist grün" - Then the message is in the room, encrypted like the room, and the command prints
SENTand its event ID,SENTalone when the sync took the message out of the outbox before the client saw its ID
Verified by
- MatrixSenderTest "a sent message gives its event ID, a failed one ends the command"
- MainTest "matrix send takes room and text, the text also from stdin"
Scenario#100.02: the text from stdin
… so that a text with several lines needs no quoting in the shell.
- Given the device is member of the room
- When the agent runs
matrix send --room "HSAdmin NG" -with the text on stdin - Then the message holds the text from stdin, without its final line break
Verified by
Scenario#100.03: read the newest messages
… so that an agent sees what was said in the room.
- Given the room holds messages, some of which the device cannot decrypt
- When the agent runs
matrix read --room "HSAdmin NG" - Then the command prints the newest 20 messages, oldest first, each as a block of time, sender, event ID and text,
and a message without key as
(nicht entschlüsselt)
Verified by
- MatrixReaderTest "the reading takes the messages back to where it starts, at most the limit"
- MatrixReaderTest "a message gives its text, an undecryptable one none, other events nothing"
- MatrixReadingTest "each message is a block of time, sender, event ID and its indented text, the oldest first"
Scenario#100.04: read since a time or an event
… so that an agent reads only what is new since it looked last.
- Given the room holds messages before and after an event
$esent at 14:00 - When the agent runs
matrix read --room "HSAdmin NG" --since '$e', or--since 2026-10-23T14:00 - Then the command prints the messages after
$e, or those from 14:00 on, at most 500 or--limit N(the newest of them); an event ID that is not among the last 500 events of the room fails the command
Verified by
- MatrixReaderTest "the reading takes the messages back to where it starts, at most the limit"
- MatrixReaderTest "an event to start after that the room does not show ends the command, also beyond the limit"
- MatrixReaderTest "an event before the time to start from is skipped, and enough of them in a row end the reading"
- MainTest "matrix read takes room, since and limit"
Scenario#100.05: the running relay sends the message
… so that the relay keeps running, as for matrix react.
- Given the relay of the machine runs
- When an agent runs
matrix send --room "HSAdmin NG" "Build ist grün" - Then the message is in the room, and the relay still runs
Verified by
- MatrixControlTest "the socket takes a reaction, a message or a reading, each with its fields"
- MatrixCommandsTest "while another process syncs, the command asks it"
Scenario#100.06: a wrong call
… so that the agent tells a wrong call from a failure.
- Given any state
- When the agent runs
matrix sendwithout room or text, ormatrix readwith a limit that is no number from 1 to 500, or a time it cannot read - Then nothing is sent, and the command prints its usage and ends with exit code 2
Verified by
- MainTest "matrix send needs room and text, none of them blank"
- MainTest "matrix read needs a room, a limit from 1 to 500 and a readable since"
Solution
MatrixCommands, new: the way ofmatrix reactfor each command that needs the device's client.runaskscontrol.sockfirst and takessync.lockand a client of its own only when nobody answers;handlewaits for the first sync, finds the room by name or ID and runs the command. The answer is the text the command prints, so the socket carries it as it is.MatrixRequest, new:ReactionRequest,SendRequestandReadRequest.MatrixControltakes the commandsreact,sendandread, each with its fields, and refuses any other; a relay of an older version answerssendandreadwith an error, so it needs a restart after the update.MatrixSender:m.textwithbodyonly, through the outbox as the reaction; printsSENTand the event ID, asmatrix reactdoes without the event ID when the outbox gave it up before the client saw it.MatrixReader: the newest events of the room back to--sinceor up to the limit, at most 500; a reaction does not count, by its relation, which stays cleartext also in an encrypted room; an encrypted event of any algorithm counts until its decryption shows that it is no message. Each event gets 30 s for its key, all at once, as forreact; without it the message prints as(nicht entschlüsselt). An event ID of--sincethat is not among the last 500 events fails the command, also with a smaller limit: the reading looks for it beyond the limit and keeps the newest messages after it.- With
--sincea time, an event before it is skipped, and the reading ends after 20 of them in a row: the room orders its events as the server got them, so an older time stamp may stand among newer ones. - The request carries the caller's time zone, so the relay prints the times in the zone of the command.
MatrixReading, free of the client library:--sinceas event ID ($…) or time, time without offset in local time; the blocks with the text indented by two spaces, so that a blank line in a message ends no block.matrix readprints nothing for a room without messages, rather than a blank line.matrix sendrefuses more than one text argument: an unquoted text would send only its first word.- The tests of
settledandsentIdand of the request tocontrol.sockmove fromMatrixReactorTesttoMatrixCommandsTestandMatrixSenderTest, with the code;MatrixReactorTestkeeps those ofreact. pitestPartial mutationCrapCheckagainst main: the highest Mutation-CRAP is 14,readRequestinMain.kt;MatrixReader.candidatestakes the timeline as a flow, so that its tests need no client.- Tested on 2026-10-23 with the relay stopped, by the branch's own client:
matrix readon "HSAdmin NG" decrypted 3 messages in 11 s;matrix sendinto the test room!B8yKiz2HJtweVdVbIhQdo2iOvHdx2L8KoeD4K7QNnW8, with the human's consent, printedSENT $DbfeJUag…, andmatrix readshowed the message.
Release Notes
matrix send --room RAUM TEXTwrites a message into a room, also an end-to-end encrypted one.matrix read --room RAUM [--since ZEIT|EVENT-ID] [--limit N]prints the messages of a room, decrypted.- Both go through the running relay or local mode, as
matrix react; restart it after the update.
Open Questions
None.