An org-mode inbox fed from a Matrix room
The bots in Matrix status messages from a cron job and A daily morning summary in Matrix only write into Matrix. This one goes the other way: I write a message into a Matrix room, and it ends up as a TODO in an org-mode file in my notes repo.
The setup is a Forgejo Action that runs once an hour.
It reads the room, adds every new message from me to matrix-inbox.org, commits and pushes the file, and then reacts to the message with a checkmark.

The bot has its own account @org-bot on my Conduit homeserver.
The access token is stored as a Forgejo secret.
The room is not encrypted to reduce complications with olm/megolm persistence.
Reading the room
The script uses the plain client-server API with httpx.
It fetches the last 100 events of the room with /messages?dir=b, so the newest event comes first.
Then it collects the bot's checkmarks and walks back through my messages until it hits one that is already acked:
acked = { ev["content"]["m.relates_to"]["event_id"] for ev in events if ev["type"] == "m.reaction" and ev["sender"] == BOT } new = [] for ev in events: if ev["type"] != "m.room.message" or ev["sender"] != OWNER: continue if ev["event_id"] in acked: break # everything older is acked too new.append(ev)
The script skips edits, otherwise fixing a typo in Matrix would add a new entry.
The inbox file
The first line of a message becomes the headline, every further line becomes the body. Entries are grouped by day, newest day on top and newest entry on top within a day:
Ack only after the push
The order matters: if the bot reacts before the push and the push fails, the message is acked but the entry is lost with the runner.
So the script has two modes, matrix-inbox.py to add the messages and matrix-inbox.py ack to react, and the git part stays in the workflow between them:
steps: - uses: actions/checkout@v7 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Install uv uses: https://github.com/astral-sh/setup-uv@v6 - name: Add new messages to inbox run: uv run matrix-inbox.py - name: Commit and push run: | git config user.name "Automated" git config user.email "actions@forgejo.local" git remote set-url origin https://oauth2:${{ secrets.GITHUB_TOKEN }}@forgejo.example.com/${{ github.repository }} git add matrix-inbox.org git diff --staged --quiet || git commit -m "matrix inbox - $(TZ=Europe/Berlin date +'%Y-%m-%d %H:%M')" git push - name: Ack messages run: uv run matrix-inbox.py ack
The event ids of the added messages are handed from the first uv run matrix-inbox to the second one via a small file in $RUNNER_TEMP.

