Rust-Tiny: tiny — A terminal IRC client

tiny - Yet another console IRC client

tiny is an IRC client written in Rust.


  • Clean UI: consecutive join/part/quit messages are shown in a single line, time stamps for a message is omitted if it's the same as the message before. (inspired by irc-core)

  • All mentions to the user are collected in a "mentions" tab, including server and channel information. "mentions" tab solves the problem of missing mentions to you in channels after hours of inactivity.

  • Mentions to the user in a channel is highlighted (the channel tab is also highlighted in the tab list)

  • Simple config file format for automatically connecting to servers, joining channels, registering the nickname etc. See configuration section below.

  • Nick tab-completion in channels

  • Nicks in channels are colored.

  • Disconnect detection and automatic reconnects. You can keep tiny running on your laptop and it automatically reconnects after a sleep etc.

  • Key bindings inspired by terminal emulators and vim. See key bindings section below.

  • Configurable colors

  • SASL authentication

  • Configurable desktop notifications on new messages (opt-in feature behind a feature flag, see below)

  • znc compatible

  • TLS support


For pre-built binaries see releases. To build from source install Rust nightly toolchain. By default tiny uses rustls for TLS support, and desktop notifications are disabled.

  • To use system TLS library (OpenSSL or LibreSSL), add --no-default-features --features=tls-native to the command you're using. Note that this requires OpenSSL or LibreSSL headers and runtime libraries on Linux.

  • To enable desktop notifications add --features=desktop-notifications. This requires libdbus on Linux.

To install in a clone:

cargo install --path tiny

If you don't want to clone the repo, you can use

cargo install --git

If you have an older version installed, add --force to the command you're using.

Arch Linux users can install tiny from AUR.

tiny is tested on Linux and OSX.


tiny looks for these places for a config file:

  • $XDG_CONFIG_HOME/tiny/config.yml
  • (when $XDG_CONFIG_HOME is not defined) $HOME/.config/tiny/config.yml
  • (deprecated) $HOME/.tinyrc.yml

when a config file is not found in one of these locations tiny creates one with defaults and exists, printing path to the config file. Edit that file before re-running tiny to change the defaults.

A note on nick identification: Some IRC servers such as ircd-seven (used by Freenode) and InspIRCd (used by Mozilla) support identification via the PASS command. This way of identification (rather than sending a message to a service like NickServ) is better when some of the channels that you automatically join require identification. To use this method enter your nick password to the pass field in servers.

Command line arguments

By default (i.e. when no command line arguments passed) tiny connects to all servers listed in the config. tiny considers command line arguments as patterns to be matched in server addresses, so you can pass command line arguments to connect to only a subset of servers specified in the config. For example, in this config:

    - addr:

    - addr:

By default tiny connects to both servers. You can connect to only the first server by passing freenode as a command line argument.

You can use --config <path> to specify your config file location.

Key bindings

  • C-a/C-e to move cursor beginning/end in the input field

  • C-k for deleting rest of the line

  • C-w for deleting a word

  • C-left/C-right for moving one word backward/forward

  • page up/page down or shift-up/shift-down or for scrolling

  • C-n/C-p for next/previous tab

  • C-c enter to quit.

  • alt-{1,9} switch to nth tab

  • alt-{char} switch to next tab with underlined char

  • alt-0 switch to last tab

  • alt-left/right move tab to left/right

  • C-x edit current message in $EDITOR


Commands start with / character.

  • /msg <nick> <message>: Send a message to a user. Creates a new tab.

  • /join <channel>: Join to a channel

  • /close: Close the current tab. Leaves the channel if the current tab is a channel. Leaves the server if the tab is a server.

  • /connect <hostname>:<port>: Connect to a server. Uses defaults in the config file for nick, realname, hostname and auto cmds.

  • /connect: Reconnect to the current server. Use if you don't want to wait tiny to reconnect automatically after a connectivity problem.

  • /away <msg>: Set away status

  • /away: Remove away status

  • /nick <nick>: Change nick

  • /names: List all nicks in the current channel. You can use /names <nick> to check if a specific nick is in the channel.

  • /reload: Reload configuration

  • /clear: Clears tab contents

  • /switch <string>: Switch to the first tab which has the given string in the name.

  • /statusline: Enable or disable status line on top which gives you info about current settings of a tab.

  • /ignore: Ignore join/quit messages in a channel. Running this command in a server tab applies it to all channels of that server. You can check your ignore state in the status line.

  • /notify [off|mentions|messages]: Enable and disable desktop notifications. Running this command in a server tab applies it to all channels of that server. You can check your notify state in the status line.

Server Commands

For commands not supported by tiny as a slash command, sending the command in the server tab will send the message directly to the server.


  • LIST will list all channels on the server
  • MOTD will display the server Message of the Day
  • RULES will display server rules
  • etc...




  • Long, spaceless messages get cut off
    Long, spaceless messages get cut off

    May 30, 2020

    Long messages that don't have enough spaces to line wrap get truncated.

    I believe this is due to the draw() in and how it handles when there is no whitespace to split on.

                        // Not possible to split. Need to make sure we don't render out
                        // of bounds.
                        if col - pos_x < width {
                            if line >= first_line {
                                tb.change_cell(col, pos_y + line, char, sty.fg,;
                            col += 1;

    This isn't a huge problem. Personally, I would just resize the window and hope that the message/link can all fit, but it's probably a pain for people using a tiling window manager...

    Wide view: image Compact view: image

    Tested on master

    bug libtiny_tui 
  • [Feature request] Support for DCC file transfers
    [Feature request] Support for DCC file transfers

    Jun 5, 2020

    Some IRC servers with search bots are based on DCC transfers to send search results in the .txt format to the user, such as #bookz or #ebooks and others.

    tiny sends a notification about the DCC transfer being initiated, but can't actually receive anything. I am afraid it would be a lot of work to implement, but it is worth asking. For reference, this is how irssi handles DCC transfers:

    feature request 
  • Align nicks and messages
    Align nicks and messages

    Jun 6, 2020

    Personally I prefer when nicks and wrapped messages are aligned, merge it if you agree I guess. Otherwise it could also be made configurable quite easily.

    Review carefully though, first time using rust so there are likely mistakes.

  • Input area improvements/tasks
    Input area improvements/tasks

    Jun 12, 2020

    I was reading the code today and found some potential improvements and a problem in the code.

    • [ ] Starting with the problem: InputArea::height is never set. It starts its life as None and stays that way. That means InputArea::get_height always recomputes the height even if nothing changes in InputArea.

    • [ ] I think it'd be better to invalidate InputLine::ws_indices (renamed from InputLine::line_starts) on update. Currently we don't update it until calculate_height is called, and if I update a line and forget to call calculate_height then draw will render input area incorrectly.

    • [ ] We should have a fast path for the common case of inserting at the end. ~~Currently this causes quadratic behavior on paste, where we turn a long string into a series of key press events (see handle_input_event), and for every key press we compute the whitespace indices from scratch.~~ (this comments was incorrect, see my update in the comments section below) I think InputLine::insert could be easily updated to handle this and efficiently update ws_indices when inserting at the end.

      This also means InputLine::calculate_height shouldn't generate ws_indices from scratch if it's already up-to-date (related to the second point above), otherwise the update in insert will never be used.

    cc @trevarj

    enhancement good first issue help wanted implementation libtiny_tui 
  • Implemented DCC get for downloading files.
    Implemented DCC get for downloading files.

    Jun 12, 2020

    Does not yet support sending files. Closes #206

  • Caching InputLine calculation. Caching InputArea::height.
    Caching InputLine calculation. Caching InputArea::height.

    Jun 16, 2020

    First attempt at solving some of the issues on #208

  • Desktop notifications
    Desktop notifications

    Jan 6, 2018

    for #72

    By default notifications is set to mentions

    • [x] Notifications on messages
    • [x] /notify [off/mentions/messages] command to notify mode
    • [ ] config file option for notify setting on a per server basis ( is this necessary? )
  • Text field refactor - word wrap support
    Text field refactor - word wrap support

    May 20, 2020

    Closes #101

    See #183 for conversation history.

  • Implement Termbox cell API using termion
    Implement Termbox cell API using termion

    Oct 3, 2019

    This ports termbox's "cell" abstraction to Rust, removing the last piece of C code from the repo.

    Input and event handling of the original termbox was removed long time ago, and we've been removing bits and pieces from the original termbox since then, leaving only the bits we need. The remaining pieces was basically just the cell abstraction, which we implement in Rust with this patch, getting some help from termion.

    Performance is on par with the original C implementation: libtiny_tui's "bench" example, when passed a 19M file, runs in 20.1s in C implementation, and 20.2s in Rust implementation. C implementation writes 918,141,709 bytes to stdout, Rust implementation write 915,387,921 bytes (-0.2%). The difference may either be better cursor location caching in the Rust version or a bug. So far I'm unable to find any rendering bugs, so I'm inclined to think the former.

    Co-authored-by: Emilio González [email protected]

  • Better `/ignore`
    Better `/ignore`

    Nov 15, 2017

    Rest of the fixes from

    • [x] What if I disabled notifications in a server, and then run /join #channel ? The channel won't inherit the notification state.
    • [x] Because of this, /ignore in auto_cmds won't be useful right now.
    • [x] There's no way to see /ignore state (true or false) in a tab, so there's no way to tell whether the channel is quiet or /ignore is enabled.
    • [x] If I have 3 /ignored channels, and 3 non-/ignored, and run /ignore in the server tab, I'll still have 3 ignores and 3 non-ignores. This is not really intuitive, I think most UIs would keep /ignore state of the server, toggle it, and then set every other tab's /ignore state to the server's.
  • SASL authentication
    SASL authentication

    Feb 15, 2018

    Need to set this in config file, as drafted in

        - addr:                                                                                                                         
          port: 6667                                                                                                                                      
          hostname: archlinux                                                                                                                             
          realname: Chiu Yue Chun                                                                                                                         
          nicks: [BrianOn99]                                                                                                                              
          auto_cmds: []                                                                                                                                   
              sasl_method: PLAIN                                                                                                                          
              sasl_username: BrianOn99                                                                                                                    
              sasl_password: password_hidden_for_security

    Only PLAIN authenication is implemented. I think it is sufficient for most users.

    Fix #90

    I have only tested it on freenode.

  • TUI feature request: grow text field vertically instead of scrolling #101
    TUI feature request: grow text field vertically instead of scrolling #101

    Apr 3, 2020

    Modified to expand vertically when reaching the end of the line.

    @osa1 let me know if there's anything I should fix or look out for (maybe I didn't test enough areas).

    Side by side diff may be easier to see the changes.