diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000000000000000000000000000000000..7760c70f351377c624690ad33a4575d4d7ce7093 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,74 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +The Mumbling Herald is a Bash script that monitors Mumble server logs and sends XMPP notifications when users join or leave specified channels. It acts as a "grumpy old herald" that announces comings and goings. + +## Core Architecture + +- **Single executable**: `mumblingherald` - Main Bash script containing all functionality +- **Configuration**: Variables at the top of the script for paths, recipients, and monitored channels +- **Dependencies**: + - `go-sendxmpp` for XMPP messaging + - `tail -F` for log monitoring + - Standard Bash utilities + +## Key Components + +- **Log parsing**: Uses regex to extract user movements and disconnections from Mumble server logs +- **Message templates**: Arrays of varied join/leave messages with placeholder substitution, embodying a playfully grumpy herald persona +- **Channel filtering**: Only monitors specific channels defined in `MONITORED_CHANNELS` array +- **XMPP integration**: Sends notifications via `go-sendxmpp` to configured recipients + +## Configuration Variables + +Edit these variables in the `mumblingherald` script: + +- `MUMBLE_LOG_FILE`: Path to Mumble server log file +- `XMPP_RECIPIENTS`: Target JID for notifications +- `MONITORED_CHANNELS`: Array of channel names to watch + +## Development Commands + +Since this is a single Bash script, there are no build or test commands, just shellcheck. + +```bash +# Make executable +chmod +x mumblingherald + +# Test syntax +bash -n mumblingherald + +# Run shellcheck +shellcheck mumblingherald + +# Run directly +./mumblingherald +``` + +## Deployment + +The script is designed to run as a systemd service under a dedicated user account. See README.md for full setup instructions including user creation, file permissions, and systemd service configuration. + +## Log Format Parsing + +The script parses specific Mumble server log formats: + +- Move events: `YYYY-MM-DD HH:MM:SS.mmm N => Moved Username:ID(N) to ChannelName[ID:N]` +- Disconnect events: `YYYY-MM-DD HH:MM:SS.mmm N => Connection closed: reason` + +## Message Templates + +The herald's personality is expressed through varied message templates: + +- **Join messages**: Varied announcements ranging from formal to grumbling observations +- **Leave messages**: Poetic farewells and wistful commentary +- **Tone**: Playfully grumpy rather than mean-spirited - like a lovably cranky character +- **Format**: Messages use `{USERNAME}` and `{CHANNEL}` placeholders for substitution +- **Character actions**: Include physical actions like `*grumbles*`, `*adjusts spectacles*`, `*mutters*` + +## Development Best Practices + +- Use shellcheck after every edit. diff --git a/mumblingherald b/mumblingherald index 426199d01dbbbb2c20bc2bad476fb1a6e444a54a..607a988e969844c5131b9777db5a517b36b93602 100755 --- a/mumblingherald +++ b/mumblingherald @@ -41,6 +41,28 @@ JOIN_MESSAGES=( "➡️ {USERNAME} finds their way to {CHANNEL}" "➡️ Lo! {USERNAME} enters {CHANNEL}" "➡️ {USERNAME} materializes in {CHANNEL}" + "➡️ *grumbles* Oh, look who's decided to grace {CHANNEL} with their presence... {USERNAME}" + "➡️ *mutters* {USERNAME} has arrived in {CHANNEL}. The halls seem livelier already..." + "➡️ *adjusts spectacles* Hmph! {USERNAME} wanders into {CHANNEL} with purpose unknown" + "➡️ *sighs heavily* Another soul wanders into {CHANNEL}... {USERNAME}, was it?" + "➡️ *coughs wheezily* {USERNAME} has deigned to visit {CHANNEL}. How... delightful." + "➡️ *chuckles dryly* {USERNAME} stumbles through the door of {CHANNEL} with characteristic grace" + "➡️ *squints curiously* {USERNAME} enters {CHANNEL}. Wonder what brings them here..." + "➡️ *waves vaguely* {USERNAME} arrives in {CHANNEL}. Mind the ancient furniture!" + "➡️ *mutters under breath* {USERNAME} finds their way to {CHANNEL}. Probably seeking wisdom..." + "➡️ *croaks* Ah, {USERNAME} graces {CHANNEL} with their interesting presence" + "➡️ *grumbles thoughtfully* {USERNAME} has somehow found their way to {CHANNEL}. Remarkable navigation." + "➡️ *peers over ancient tome* {USERNAME} joins the gathered souls in {CHANNEL}. Welcome, I suppose." + "➡️ *mutters* {USERNAME} makes their way to {CHANNEL}. The determination is... admirable" + "➡️ *nods grudgingly* {USERNAME} appears in {CHANNEL} like morning mist. Atmospheric." + "➡️ *shakes head* {USERNAME} wanders into {CHANNEL}. The sense of direction improves..." + "➡️ *grumbles* {USERNAME} shuffles into {CHANNEL} with their usual enthusiasm" + "➡️ *wheezes* {USERNAME} has emerged from elsewhere to visit {CHANNEL}" + "➡️ *mutters approvingly* {USERNAME} enters {CHANNEL} like they belong here. Perhaps they do..." + "➡️ *coughs* Behold! {USERNAME} graces {CHANNEL} with their notable presence" + "➡️ *adjusts robes* {USERNAME} ventures into {CHANNEL}. Mind the ancient cobwebs!" + "➡️ *grumbles* Another wanderer... {USERNAME} discovers {CHANNEL}" + "➡️ *sighs contentedly* {USERNAME} has arrived in {CHANNEL}. The company improves..." ) # shellcheck disable=SC2034 @@ -53,6 +75,34 @@ LEAVE_MESSAGES=( "⬅️ {USERNAME} has made their exit..." "⬅️ {USERNAME} has fled our realm..." "⬅️ *sighs* And thus {USERNAME} departs..." + "⬅️ *grumbles* Well, that was brief... {USERNAME} has wandered off to other adventures" + "⬅️ *mutters* {USERNAME} has departed from us. Just when things were getting interesting..." + "⬅️ *coughs* {USERNAME} has evaporated like morning mist. Until next time, I suppose..." + "⬅️ *shrugs* {USERNAME} has left the scene. Probably remembered important business elsewhere" + "⬅️ *waves hand thoughtfully* {USERNAME} vanishes with mysterious purpose and timing" + "⬅️ *mutters under breath* {USERNAME} has slipped away into the digital realm. How intriguing..." + "⬅️ *sighs deeply* {USERNAME} departs, leaving only fond memories and ancient wisdom" + "⬅️ *croaks* {USERNAME} has dissolved into the ether. Poof! Like morning fog..." + "⬅️ *grumbles* {USERNAME} has made their exit. Probably off to share tales elsewhere" + "⬅️ *adjusts spectacles* {USERNAME} retreats to their domain. The quiet has its merits..." + "⬅️ *wheezes* {USERNAME} has ghosted us. How very contemporary of them..." + "⬅️ *mutters thoughtfully* {USERNAME} slips away like mist at dawn. Quite poetic..." + "⬅️ *nods* {USERNAME} has disconnected from our realm. Until we meet again..." + "⬅️ *grumbles* {USERNAME} departs swiftly, like autumn leaves on the wind" + "⬅️ *sighs* {USERNAME} has vanished without fanfare. The modern way of things..." + "⬅️ *coughs* {USERNAME} evaporates like ancient ink on weathered parchment" + "⬅️ *mutters* {USERNAME} retreats to whatever cozy corner they call sanctuary" + "⬅️ *waves appreciatively* {USERNAME} fades like shadows at dawn. Rather elegant, really..." + "⬅️ *grumbles contentedly* {USERNAME} has departed. Probably remembered pressing matters" + "⬅️ *shakes head* {USERNAME} dissolves into the digital realm. How wonderfully modern..." + "⬅️ *mutters* {USERNAME} has pulled a vanishing act. The masters would be impressed" + "⬅️ *sighs wistfully* {USERNAME} departs, leaving only pleasant echoes behind" + "⬅️ *croaks* {USERNAME} has melted away like snow in spring. The natural order..." + "⬅️ *grumbles* {USERNAME} moves on faster than news travels in peaceful times" + "⬅️ *adjusts robes* {USERNAME} has retreated to their digital sanctuary. Journey well..." + "⬅️ *mutters approvingly* {USERNAME} vanishes like my enthusiasm for new technology" + "⬅️ *wheezes* {USERNAME} has departed this virtual realm... err, channel" + "⬅️ *sighs* {USERNAME} evaporates like morning dew on pleasant meadows" ) # Function to get a random message from an array