Notifications API Reference

Docstrings for telling you when long-running work has finished. The narrative guides are Setup & Usage for configuring a channel, and Examples for what to send.

Three channels are available, and every function below can use any of them:

channelreaches youneeds
bellthe machine you are sitting atnothing
emailanywherean address in the config
Zulipa team chat streama bot token in the config

Configuration lives in ~/.mera.toml, found by mera_config_path, which checks $MERA_CONFIG, then ~/.mera.toml, then ~/.config/mera/config.toml. Environment variables take precedence over the file, which keeps secrets off disk. The older ~/email.txt, ~/zulip.txt and ~/bell.txt are still read when no TOML config exists.

Platform support

Tested on macOS and Linux. Windows is not tested. The bell depends on the system sound command, so it is the one most likely to be silent elsewhere; email and Zulip are plain network calls and are not platform specific.

Sending a notification

Mera.notifymeFunction

Get an email and/or Zulip notification, e.g., when your calculations are finished.

Both channels are configured in ~/.mera.toml. Print a template with mera_config_example, fill in the parts you want, then chmod 600 ~/.mera.toml — it holds an API key. Configure either channel, or both; each is used only if present.

[email]
to = "you@example.com"

[zulip]
bot_email = "mybot@zulip.example.com"
api_key   = "..."                        # or set MERA_ZULIP_API_KEY instead
server    = "https://zulip.example.com"

Email additionally needs the command-line mail client installed; Mera pipes the message to it. Nothing is sent if [email] to is unset.

Zulip needs all three keys. It is the richer channel: it carries image and file attachments, and posts to a channel/topic (zulip_channel=, zulip_topic=), which email does not.

Every value can also come from an environment variable — MERA_EMAIL_TO, MERA_ZULIP_BOT_EMAIL, MERA_ZULIP_API_KEY, MERA_ZULIP_SERVER, MERA_ZULIP_CHANNEL — which take precedence over the file and keep secrets off disk. The legacy email.txt, zulip.txt and bell.txt in $HOME still work; ~/.mera.toml wins where both exist. See mera_config.

Output Capture (optional):

  • capture_output: Can be a Cmd, Function, or String to capture terminal/function output
  • The captured output will be appended to your message

File Attachments (optional):

  • image_path: Single image file to attach
  • attachments: Vector of file paths to attach (multiple files)
  • attachment_folder: Path to folder - all image files (.png, .jpg, .jpeg, .gif, .svg) will be attached
  • maxattachments: Maximum number of files to attach when using attachmentfolder (default: 10)
  • maxfilesize: Maximum file size in bytes for non-image attachments (default: 25000000 ≈ 25 MB). Files larger than this are skipped with an explanatory warning (Zulip itself may enforce stricter limits – typical defaults are 25–50 MB). For images a stricter 1 MB optimization target is applied automatically to keep uploads fast and reliable; large images are resized down to <=1024px on the longest side.

Time Tracking (optional):

  • start_time: Start time for execution tracking (use time() or now())
  • include_timing: Boolean to include automatic timing information (default: false)
  • timing_details: Include detailed performance metrics (memory, allocations)

Exception Handling (optional):

  • exception_context: Exception object to include stack trace and error details
  • includestacktrace: Boolean to include full stack trace (default: true when exceptioncontext provided)
julia> notifyme()
julia> notifyme("Calculation 1 finished!")
julia> notifyme(msg="Calculation finished!", zulip_channel="alerts", zulip_topic="Run Status")
julia> notifyme(msg="Plot ready!", zulip_channel="plots", zulip_topic="Results", image_path="result.png")
julia> notifyme(msg="Multiple results!", attachments=["plot1.png", "plot2.png", "data.csv"])
julia> notifyme(msg="All plots from analysis!", attachment_folder="./plots/")
julia> notifyme(msg="Limited plots!", attachment_folder="./plots/", max_attachments=5)
julia> notifyme(msg="Large dataset results!", attachments=["data.csv"], max_file_size=50_000_000)  # 50MB limit
# Example: enforce a tighter 5 MB limit to avoid heavy uploads when on slow networks
julia> notifyme(msg="Quick summary only", attachments=["summary.log"], max_file_size=5_000_000)
# Time tracking examples
julia> start = time(); heavy_computation(); notifyme("Computation done!", start_time=start)
julia> notifyme("Analysis finished!", include_timing=true, timing_details=true)
# Exception handling examples  
julia> try
           risky_computation()
       catch e
           notifyme("Computation failed!", exception_context=e)
       end
julia> notifyme(msg="Directory listing:", capture_output=`ls`)
julia> notifyme(msg="Function output:", capture_output=() -> sum(rand(100)))
Mera.bellFunction
bell(sound = nothing)

Play a short notification sound — e.g. when a long calculation finishes.

Pick the sound in any of these ways (first match wins):

  1. by namebell(:chime) (a Symbol or String);
  2. by numberbell(2) (the position shown by bell(:list), also a numeric string like bell("2"));
  3. a configured default[bell] sound = "gong" in ~/.mera.toml, the MERA_BELL_SOUND environment variable, or the legacy ~/bell.txt (see mera_config);
  4. the built-in fallback:strum (the original Mera sound).

19 sounds ship with Mera. List them with their numbers using bell(:list): arpeggio, bell, bird, bloop, bongo, chime, coin, coindrop, cosmic, ding, done, door, frog, gong, knock, oscillations, owl, strum, whistle.

You can also drop your own *.wav into the package's src/sounds/ folder and select it by its file name or number.

bell()            # the configured default, else :strum
bell(:gong)       # a deep blooming gong
bell("chime")     # a glassy three-note chime
bell(4)           # the 4th sound in bell(:list)
bell(:list)       # print the numbered catalogue of available sounds
Mera.timed_notifyFunction

Track execution time and send notification with timing information

Convenience function that automatically tracks execution time of a code block and sends a notification with timing details.

Parameters:

  • task_name: Description of the task being timed
  • code_block: Function or code to execute and time
  • zulip_channel: Zulip channel for notification (default: "timing")
  • zulip_topic: Zulip topic for notification (default: "Execution Times")
  • include_details: Include detailed performance metrics (default: false)

Examples:

# Time a function execution
timed_notify("Data processing", () -> process_large_dataset())

# Time with detailed metrics
timed_notify("Complex analysis", () -> analyze_galaxy_formation(), 
             include_details=true, zulip_channel="research")

# Time with custom messaging
timed_notify("Simulation run #47", () -> run_simulation(params), 
             zulip_channel="simulations", zulip_topic="Run Times")
Mera.send_resultsFunction

Send multiple plots or results with a single notification

Convenience function for common research workflows where you want to share multiple files (plots, data, results) at once.

Parameters:

  • msg: Message to send
  • folder: Path to folder containing files to attach
  • file_pattern: Pattern to match files (default: images only)
  • max_files: Maximum number of files to attach (default: 10)
  • zulip_channel: Zulip channel/stream name (default: "results")
  • zulip_topic: Zulip topic name (default: "Analysis Results")

Examples:

# Send all plots from analysis folder
send_results("Temperature analysis complete!", "./plots/")

# Send specific files
send_results("Key results ready!", ["figure1.png", "data.csv", "summary.txt"])

# Send with custom channel and topic
send_results("Paper plots ready!", "./figures/", 
             zulip_channel="publications", zulip_topic="Paper 1 - Figures")

Progress tracking

A tracker reports long-running work as it goes, rather than only at the end. Create one, update it inside the loop, and complete it when the work is done.

Mera.create_progress_trackerFunction

Progress tracking with automatic time-based notifications

Creates a progress tracker that automatically sends notifications at specified time intervals or progress milestones.

Parameters:

  • total_items: Total number of items to process
  • time_interval: Send notification every N seconds (default: 300 = 5 minutes)
  • progress_interval: Send notification every N% progress (default: 10%)
  • task_name: Name of the task for notifications
  • zulip_channel: Zulip channel (default: "progress")
  • zulip_topic: Zulip topic (default: "Task Progress")

Returns: ProgressTracker object with update!() method

Examples:

# Create progress tracker for 1000 items, notify every 5 minutes or 10% progress
tracker = create_progress_tracker(1000, task_name="Galaxy analysis")

for i in 1:1000
    # Do some work
    process_galaxy(i)
    
    # Update progress (automatically sends notifications at intervals)
    update_progress!(tracker, i)
end

# Final completion notification
complete_progress!(tracker)
Mera.update_progress!Function

Update progress tracker and send notifications if thresholds are met

Parameters:

  • tracker: Progress tracker created by createprogresstracker()
  • current_item: Current item number being processed
  • custom_message: Optional custom message for this update

Examples:

tracker = create_progress_tracker(1000, task_name="Data analysis")

for i in 1:1000
    analyze_data_point(i)
    update_progress!(tracker, i)
    
    # Optional: Add custom message for specific milestones
    if i == 500
        update_progress!(tracker, i, "Reached halfway point - results looking good!")
    end
end
update_progress!(tsp::ThreadSafeProgress, filename::String)

Thread-safe function to update progress bar with current file information. Uses locking to prevent race conditions when multiple threads update simultaneously.

Thread Safety

  • Acquires exclusive lock before any modifications
  • Updates both counter and description atomically
  • Releases lock automatically when function exits
  • Prevents progress bar corruption from concurrent updates

Display Format

  • Shows [completed/total] ratio
  • Displays currently processing filename
  • Updates speed calculation automatically
Mera.complete_progress!Function

Send final completion notification for progress tracker

Parameters:

  • tracker: Progress tracker to complete
  • final_message: Optional final message
  • include_summary: Include full execution summary (default: true)

Examples:

tracker = create_progress_tracker(1000, task_name="Simulation")
# ... do work with update_progress! calls ...
complete_progress!(tracker, "All galaxies processed successfully!")

Utilities

Mera.safe_executeFunction

Enhanced exception handler with automatic notification

Wraps risky code with automatic exception notification including full context.

Parameters:

  • code_block: Function to execute with exception handling
  • task_description: Description of what the code is doing
  • zulip_channel: Channel for error notifications (default: "errors")
  • zulip_topic: Topic for error notifications (default: "Exception Reports")
  • include_context: Include system context in error report (default: true)

Examples:

# Basic exception handling with notification
result = safe_execute("Galaxy temperature calculation") do
    calculate_galaxy_temperatures(data)
end

# Custom error channel and additional context
result = safe_execute("Critical simulation step", 
                     zulip_channel="critical-errors",
                     include_context=true) do
    run_critical_simulation_step()
end
Mera.optimize_image_for_zulipFunction
optimize_image_for_zulip(image_path; max_dimension=1024, max_file_size=1_000_000)

Shrink an image so it uploads comfortably to Zulip, returning a path to use.

Downscales past max_dimension and re-encodes to approach max_file_size. Re-encoding can make an already-small PNG larger, so the result is whichever file is genuinely smaller — the original is returned unchanged when optimisation would not help.