- C 98%
- CMake 2%
- Added optional full keyword to !gitlog and !changelog for showing full commit messages and changelog entries instead of just headers. - !gitlog full uses git log (without --oneline) and strips leading indentation from commit blocks, collapses multiple spaces. - !changelog full collects full entry text with bullet points and shows the newest entries (first N in file, not last N). - Added optional pull argument to !rebuild: !rebuild pull runs git pull before make clean/make, plain !rebuild only rebuilds. - Added collapse_spaces() call in !gitlog oneline path to remove double spaces in compact output. - Changed default GITLOG_COUNT and CHANGELOG_COUNT from 5 to 1. - Reduced GITLOG_MAX from 10 to 5. - Updated !help text to document [full] and [pull] options. - Updated README.md with full option for !gitlog/!changelog and pull option for !rebuild. - Added CHANGELOG.md entry for v0.38.2. |
||
|---|---|---|
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| zynk.c | ||
zynk - Companion AI Logic Chatbot
A single-file IRC bot in C. Features a key-value store backed by SQLite3, weather lookups via wttr.in, stock quotes, calculator, time, user tracking, and AI-powered replies.
Features
- Key-Value Store: Persist facts, notes, or any data with
zynk key = value - Weather: Current conditions and 3-day forecasts via
wttr.in - Stock Quotes: Real-time stock prices via Yahoo Finance
- Calculator: Evaluate math expressions with
!calc - Time: Show current time in any timezone with
!time - User Tracking: Track when users were last seen with
!seen - Offline Messages: Leave messages for offline users with
!tell - AI Queries: Ask questions via
!aior by addressing the bot; powered byopencode - Code Changes: AI-powered code editing with auto-recompile and hot reload
- Chat Greetings: Responds to
hi,hello,hey,bye, and more - Hot Reload: Reload or restart without disconnecting from IRC
- TLS: Secure connections via OpenSSL
- Rate Limiting: Per-nick protection against spam
- Reconnection: Auto-reconnect with exponential backoff
- Single File: Easy to deploy and modify
Requirements
gcc(or any C99 compiler)libssl-dev(OpenSSL)libdl(dynamic linker)libsqlite3(loaded at runtime viadlopen)curl(for weather, forecast, and stock lookups)bc(for the calculator command)git(for the gitlog command)date(for timezone-aware time lookups)tzdata(optional — without it,!timefalls back to 45 built-in timezones)opencode(for AI queries)
Build
make
Set custom compiler or flags:
make CC=clang CFLAGS="-O2 -Wall -Wextra"
Usage
./zynk [options]
Options
| Option | Description |
|---|---|
-ssl |
Enable TLS (auto-enabled on ports 6697/7000) |
-noverify |
Skip TLS certificate verification |
-server <host> |
IRC server (default: irc.libera.chat) |
-port <p> |
Port (default: 6697) |
-pass <p> |
Server password |
-nick <n> |
Nickname (default: zynk) |
-join <c> |
Auto-join channels, comma-separated (default: #zynk) |
-opencode <p> |
Path to opencode binary (default: /usr/bin/opencode) |
-h |
Show help |
Example
./zynk -ssl -nick mybot -join "#mychan,#myotherchan"
IRC Commands
General
| Command | Description |
|---|---|
!help |
List all available commands |
!version |
Show the bot version |
!ping |
Responds with pong |
!uptime |
Show bot uptime |
!quit / !die |
Shut down the bot (ops only) |
Key-Value Store
| Command | Description |
|---|---|
zynk <key> |
Look up a stored value |
zynk <key> = <value> |
Store a value (key is lowercased) |
zynk! <key> = <value> |
Overwrite an existing value (ops in channels) |
zynk |
Get a random stored entry |
Weather & Finance
| Command | Description |
|---|---|
!weather [city] |
Current weather (default: Berlin) |
!forecast [city] |
3-day forecast (default: Berlin) |
!stock <SYMBOL>[,SYMBOL...] |
Stock quotes, up to 3 symbols (e.g. !stock AAPL,MSFT) |
Utilities
| Command | Description |
|---|---|
!calc <expression> |
Evaluate math (see below) |
!time [timezone] |
Show current time (see below) |
!seen <nick> |
Check when a user was last seen |
!tell <nick> <message> |
Leave a message for an offline user |
!gitlog [count] [full] |
Show recent git commits (default: 1, max: 5; full shows full commit messages) |
!changelog [count] [full] |
Show changelog entries (default: 1, max: 10; full shows full entry text) |
Time (!time)
Shows the current date and time. Without arguments, displays the bot's local time. With a timezone argument, displays the time in that timezone using POSIX TZ format.
Output format: YYYY-MM-DD HH:MM:SS
Examples:
| Command | Description |
|---|---|
!time |
Bot's local time |
!time UTC |
Current UTC time |
!time US/Eastern |
US Eastern time |
!time US/Pacific |
US Pacific time |
!time Europe/Berlin |
Central European time |
!time Europe/London |
UK time |
!time Asia/Tokyo |
Japan time |
!time Australia/Sydney |
Australian Eastern time |
If the system has tzdata installed, any IANA/Olson timezone name works. Otherwise, the bot falls back to a built-in table with the following timezones:
Built-in timezones (no tzdata required):
| Timezone | Region | Offset | DST |
|---|---|---|---|
UTC / GMT |
Global | +0 | No |
EST / CST / MST / PST / HST |
US (fixed) | -5 to -10 | No |
US/Eastern |
US Eastern | -5 / -4 | Yes |
US/Central |
US Central | -6 / -5 | Yes |
US/Mountain |
US Mountain | -7 / -6 | Yes |
US/Pacific |
US Pacific | -8 / -7 | Yes |
US/Alaska |
US Alaska | -9 / -8 | Yes |
US/Honolulu |
US Hawaii | -10 | No |
Canada/Toronto |
Canada Eastern | -5 / -4 | Yes |
Canada/Vancouver |
Canada Pacific | -8 / -7 | Yes |
America/Sao_Paulo |
Brazil | -3 / -2 | Yes |
America/Mexico_City |
Mexico | -6 / -5 | Yes |
America/Argentina/Buenos_Aires |
Argentina | -3 | No |
Europe/London |
UK | 0 / +1 | Yes |
Europe/Berlin |
Central Europe | +1 / +2 | Yes |
Europe/Paris |
France | +1 / +2 | Yes |
Europe/Moscow |
Russia | +3 | No |
Europe/Istanbul |
Turkey | +3 | No |
Asia/Tokyo |
Japan | +9 | No |
Asia/Shanghai |
China | +8 | No |
Asia/Kolkata |
India | +5:30 | No |
Asia/Dubai |
UAE | +4 | No |
Asia/Singapore |
Singapore | +8 | No |
Asia/Seoul |
South Korea | +9 | No |
Asia/Hong_Kong |
Hong Kong | +8 | No |
Asia/Taipei |
Taiwan | +8 | No |
Australia/Sydney |
Australia Eastern | +10 / +11 | Yes |
Australia/Melbourne |
Australia Eastern | +10 / +11 | Yes |
Australia/Brisbane |
Australia Eastern | +10 | No |
Australia/Perth |
Australia Western | +8 | No |
Australia/Adelaide |
Australia Central | +9:30 / +10:30 | Yes |
Australia/Darwin |
Australia Central | +9:30 | No |
Pacific/Auckland |
New Zealand | +12 / +13 | Yes |
Pacific/Honolulu |
Hawaii | -10 | No |
Pacific/Fiji |
Fiji | +12 / +13 | Yes |
Africa/Cairo |
Egypt | +2 | No |
Africa/Johannesburg |
South Africa | +2 | No |
Africa/Lagos |
West Africa | +1 | No |
Africa/Nairobi |
East Africa | +3 | No |
Atlantic/Reykjavik |
Iceland | +0 | No |
Calculator (!calc)
The calculator uses bc -l (POSIX arbitrary-precision calculator with the math library). Any valid bc expression works.
Basic arithmetic:
| Expression | Result |
|---|---|
!calc 2+2 |
4 |
!calc 100-37 |
63 |
!calc 6*7 |
42 |
!calc 100/3 |
33.3333333333333333333 |
!calc 10%3 |
1 |
Parentheses for grouping:
| Expression | Result |
|---|---|
!calc (3+7)*2 |
20 |
!calc (100-50)/5 |
10 |
Powers:
| Expression | Result |
|---|---|
!calc 2^10 |
1024 |
!calc 3^3 |
27 |
Constants:
| Expression | Description |
|---|---|
!calc pi() |
Pi (3.14159...) |
!calc pi()*2 |
Circumference of a unit circle |
!calc pi()^2 |
Pi squared |
Math library functions (enabled by -l):
| Expression | Description |
|---|---|
!calc s(1) |
Sine of 1 (radians) |
!calc c(0) |
Cosine of 0 |
!calc a(1) |
Arctangent of 1 |
!calc l(100) |
Natural logarithm of 100 |
!calc e(1) |
e^1 |
Scale (decimal places):
| Expression | Description |
|---|---|
!calc scale=4; 1/3 |
0.3333 |
Variables and multi-statement:
| Expression | Description |
|---|---|
!calc x=5; x*2 |
10 |
!calc 2+2; 3*3 |
4 (first line of output) |
AI
| Command | Description |
|---|---|
!ai <question> |
Ask the AI a question (plan mode, read-only) |
!code <instruction> |
AI code change with auto-recompile (ops only, in channels) |
<nick>: <question> |
Address the bot by nick to ask the AI |
Admin (Ops Only)
| Command | Description |
|---|---|
!reload |
Hot reload (save TLS state, fork new process) |
!restart |
Restart the bot |
!rebuild [pull] |
Rebuild and restart (ops only, in channels; pull runs Git pull before rebuilding) |
!code <instruction> |
Make AI-powered code changes |
Chat
| Command | Description |
|---|---|
<nick>: hi/hello/hey |
Greeting response |
<nick>: bye |
Farewell response |
<nick>: <anything> |
AI-powered conversation |
Database
Data is stored in zynk.db (SQLite3) in the working directory. The bot creates four tables:
zynk- key-value pairs with nick and timestamp metadataai_pending- single-row table for managing in-flight AI queriesseen- tracks when users were last seen (nick, timestamp, channel, action)tell- stores pending offline messages for delivery
Architecture
zynk uses a single poll() loop with a 100 ms timeout. AI queries fork a child process that runs the opencode CLI; the parent picks up the result on the next poll iteration. SQLite3 is loaded at runtime via dlopen to avoid a compile-time dependency. The bot supports hot reload: !reload and !restart save TLS session state, fork a new process with the inherited socket, and resume without dropping from IRC.
License
MIT - see LICENSE file.