salamander
Salamander 🦎
Salamander is a visual, interactive, and desktop notification UI subframework for building LLM applications using the Mantle framework.
It extracts the complex UI handling—such as terminal dimension calculations, ANSI escape sequences, animated spinners, Waybar system integrations, and TTS buffering—into a reusable library.
The Yielding Sandbox Pattern
Salamander is designed around the Yielding Sandbox Pattern.
Instead of Salamander owning your application's while loop or control flow, it acts as a structural wrapper. It handles the dirty environment setup and teardown (trapping Ctrl+C, initializing the Waybar socket, clearing the terminal, or setting up the audio buffer), and then yields a clean UI toolbelt object back to your application block.
Your application retains 100% control over the flow.
Installation
Add this to your application's shard.yml:
dependencies:
salamander:
path: ../salamander # Or github link once published
Quickstart Guide
Here is a minimal example of how to wrap your application logic using Salamander::Terminal.run and utilize the ui toolbelt:
require "salamander"
# Salamander sets up the terminal, Waybar, and TTS, then yields control.
Salamander::Terminal.run(bot_name: "Emma", icon: "🐾") do |ui|
ui.print_separator
# The Application dictates the actual flow.
# For a chat app, you write the interactive loop here:
loop do
user_input = ui.ask_user("You: ")
break unless user_input
ui.waybar.update(:thinking)
ui.spin_while("Mantle is generating...") do
# Integrate Mantle here!
# result = session.run_turn(user_input) do |chunk|
# ui.stream_text(chunk)
# end
# Simulate delay
sleep 2.seconds
ui.clear_line
ui.stream_text("Response from Mantle goes here.\n")
end
ui.waybar.update(:idle)
end
end
UI Toolbelt Methods
The ui object yielded by the sandbox provides the following methods:
ui.ask_user(prompt : String): Safely prompts the user for CLI input.ui.spin_while(message : String, state_getter : Proc(Symbol)?, &block): Wraps a block in an animated spinner. The spinner automatically stops when the block completes or when thestate_gettertransitions to:responding.ui.stream_text(chunk : String, tts_buffer = nil): Streams text to the terminal and automatically feeds the TTS buffer if provided.ui.clear_line: Erases the current terminal line (useful for clearing the spinner before streaming).ui.print_separator: Prints a full-width boxed separator╔═════╗.ui.waybar: Accesses theWaybarNotifierto send status updates (ui.waybar.update(:thinking)) or desktop notifications (ui.waybar.notify("Title", "Message")).ui.menu: Accesses the interactive generic terminal chooser (Salamander::Menu.choose).
Included Showcase
You can test all the interface elements provided by Salamander by running the included playground script:
crystal run src/playground.cr
salamander
- 0
- 0
- 0
- 0
- 0
- 2 days ago
- September 23, 2026
MIT License
Wed, 23 Sep 2026 03:12:47 GMT