Another IRC client & UI, because Irssi is great but painful to script. gawel/irc3 works, but its design flaws are limiting and hard to work around. jaraco/irc is weirdly over-engineered while making seemingly simple things very hard.
This is a minimalistic, portable, yet almost complete rfc2812 implementation (~900 LOC client, ~500 LOC UI), which I should have written years ago, instead of fighting above tools.
- Irssi inspired UI (powered by blessed
♥️ ) - Colorized nicks
- MIRC color/formatting
- Tabbed layout (
ARROW_LEFT,ARROW_RIGHT) - Scrollable buffers (
PAGE_UP,PAGE_DOWN) - Multi-server enabled (switch through with
/switch)
- Fully
asyncio - Implements the majority of rfc2812
- Symmetric E2E encryption with
cryptography.Fernet(Kirk exclusive feature) - In-band DH key exchange (
/handshake <nick>) with mnemonic fingerprint verification - Auto-join
- Auth support (NickServ or SASL)
- CTCP support
- DCC support
- SSL support
- Super easy to extend and adapt!
- Select IRCv3 support
Super simple IRC bot ollama_chatbot.py that reacts to private messages. Uses a locally running ollama LLM.
By default, Kirk will look into the user's home directory for a startup config file.
This is just a convenience. Most settings can also be reached via CLI. See kirk --help for more info.
uvx --from git+https://github.com/tfranzel/kirk kirk --host irc.libera.chat --nick NosySpockpython -m kirk.run --host irc.libera.chat --nick NosySpock[kirk]
# save buffer history on exit and load on startpersistence = false# Custom IrcClient class that Kirk should use instead, as 'path/to/file.py:ClassName'.# Relative paths resolve against this config file's directory, not the CWD.# client_class = "clients/my_client.py:MyClient"
[[kirk.client]]
host = "irc.libera.chat"nick = "NosySpock"auto_join = [
"#testchannel",
]
ssl = true# Optional: authenticate after connecting.auth = "sasl_plain"password = "YOURPASSWORD"# Symmentric encrpytion with peer. Both need the same key# Key generation: base64.urlsafe_b64encode(os.urandom(32))keys.CpnKirk25 = "R3k4JBrPet51XYzkD64KNeuOljzANxBT6yIHZT-yY7w="# Use "console" with headless and "file" or "none" for Kirklog_mode = "none"# another server
[[kirk.client]]
# ...importasynciofromkirk.clientimportIrcClientfromkirk.kirkimportKirkasyncdefmain() ->None:
loop=asyncio.get_running_loop()
client=IrcClient(
host="irc.libera.chat",
nick="NosySpock",
)
kirk=Kirk([client], loop)
# UI is select()-based, so run in a separate thread_=loop.run_in_executor(None, kirk.run)
# start the actual clientawaitasyncio.gather(client.run())
if__name__=="__main__":
asyncio.run(main(), debug=False)
