# AGENTS.md — zynk ## Project Overview `zynk` is a single-file IRC bot written in C. It connects to an IRC server, maintains a key-value store via SQLite3 (loaded dynamically at runtime), and responds to commands in channels and private messages. ## Build & Run - **Build**: `make` (uses `gcc`, requires `libssl-dev` / `libcrypto` / `libdl`) - **Run**: `./zynk -ssl -nick mybot -join "#chan1,#chan2"` - **Clean**: `make clean` - **Install**: `make install` ## Code Style - C99/C11, single file (`zynk.c`) - No comments in new code unless clarifying a non-obvious edge case - Error strings use ANSI color macros (`CLR_RED`, `CLR_GREEN`, etc.) - 2-space indentation, K&R brace style - Dynamic loading of libsqlite3 via `dlopen` + `dlsym` - TLS via OpenSSL (SSL_read/SSL_write, non-blocking) - Prefer `strncpy` + manual NUL, `snprintf`, `asprintf` ## Project Structure ``` zynk/ zynk.c — single-file IRC bot (1129 lines) Makefile — build system .gitignore AGENTS.md — this file README.md — user-facing docs ``` ## Key Modules in zynk.c ### SQLite3 Integration (lines 40–228) - Dynamically loads `libsqlite3.so.0` from common paths - Tables: `zynk` (key-value store), `ai_pending` (pending AI queries) - Functions: `db_set`, `db_get`, `db_get_raw`, `db_update_lastq`, `db_update_lasta` ### IRC Session (lines 303–317) - `Session` struct holds connection state, buffer, SSL pointer ### Network I/O (lines 319–379) - `net_connect` — TCP connect with DNS resolution - `net_read` / `net_write` — TLS-aware read/write - `net_send` — formatted send with EINTR/EAGAIN retry ### AI Query Pipeline (lines 537–612) - Forks a child process per query - Child runs `opencode run --dangerously-skip-permissions` with the question - Output is stripped of formatting and AI disclaimers - Result stored in DB, parent picks it up in the main poll loop ### IRC Message Handler (lines 667–931) - `irc_handle` parses IRC protocol messages - `irc_feed` buffers line-based input ### Main Poll Loop (lines 960–1128) - Single `poll()` loop with 100ms timeout - Checks for AI process completion via `waitpid` ## Important Constants - `AI_REPLY_MAX = 400` — max chars per IRC reply from AI - `RATE_LIMIT_WINDOW = 2`, `RATE_LIMIT_MAX = 8` — per-nick rate limiting - `OPENCODE_BIN` — path to opencode binary for AI queries - `DEFAULT_SERVER = "irc.libera.chat"`, `DEF_PORT = 6697` ## IRC Commands | Command | Description | |---|---| | `zynk ` | Look up a stored value | | `zynk = ` | Store a value | | `!ping` | Responds with pong | | `!hello` | Responds with hello and the user's name | | `!weather [city]` | Current weather (default: Berlin) | | `!forecast [city]` | 3-day forecast | | `!ai ` | Ask the AI a question | | `!quit` / `!die` | Shut down the bot | | `: hi/hello/hey` | Chat greeting | | `: ` | Address the bot by nick to ask AI | ## Conventions for Contributors - Do NOT add `#include` that aren't strictly needed - Do NOT add comments to obvious code - Match existing style: 2-space indent, no trailing whitespace - Test with `make && ./zynk -h` - Keep the single-file structure unless there's a strong reason to split