1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
# xmppcb
A lean XMPP AI chatbot in C. It joins MUC rooms, logs messages, and
answers `@bot` commands via an OpenAI-compatible LLM HTTP API.
A C reimplementation of the Python `bot.py` in the parent directory,
written in the suckless spirit: one source file, one library
dependency (OpenSSL), fixed buffers, no runtime config parser.
There is **no end-to-end / OMEMO encryption**. Transport is still
encrypted: STARTTLS for the XMPP connection, HTTPS for the LLM API.
## Build
Needs a C compiler and OpenSSL development headers
(`apt install libssl-dev`).
```sh
make
```
The makefile copies `config.def.h` to `config.h` on first build.
Edit `config.h` (not the `.def`) to set your server, rooms and model.
## Configure
Non-secret settings live in `config.h`. Recompile after changing it.
Secrets are read from the environment, never stored on disk by the bot:
```sh
export XMPP_PASSWORD='the-bot-account-password'
export LLM_API_KEY='sk-...'
```
`instruction.md` holds the system prompt; it is read once at startup.
On a fresh checkout, copy `instruction.md.sample` to `instruction.md`,
then edit it and restart to change the bot's behaviour.
### Choosing the LLM model and provider
The bot speaks the OpenAI-compatible `/v1/chat/completions` protocol, so
it works with any provider that does — OpenAI, OpenRouter, Together, a
local Ollama/llama.cpp server, etc. Four macros in `config.h` select it:
| Macro | Purpose |
|-------------|--------------------------|
| `LLM_HOST` | API hostname |
| `LLM_PORT` | API port (usually 443) |
| `LLM_PATH` | chat/completions path |
| `LLM_MODEL` | model identifier |
OpenAI (default):
```c
#define LLM_HOST "api.openai.com"
#define LLM_PATH "/v1/chat/completions"
#define LLM_MODEL "gpt-5.4-mini"
```
OpenRouter:
```c
#define LLM_HOST "openrouter.ai"
#define LLM_PATH "/api/v1/chat/completions"
#define LLM_MODEL "anthropic/claude-sonnet-4-6"
```
Change the macros, run `make` again, and set `LLM_API_KEY` to a key for
that provider. The bot sends `max_completion_tokens`; a few non-OpenAI
servers still expect the older `max_tokens` field and would need a
source change.
## Run
Run from the directory containing `instruction.md` and `config.h`:
```sh
./xmppcb
```
It reconnects automatically after a dropped connection. On an
authentication failure it exits with status 1 (no retry loop).
Logs go to stderr. Per-room chat history is appended to
`history/<room>.log`.
## Usage
In a joined room:
| Command | Effect |
|---|---|
| `@bot help` | Show commands |
| `@bot summarize [period]` | Summarise the conversation |
| `@bot tasks [period]` | Extract action items |
| `@bot <question>` | Ask anything, using recent chat as context |
Period tokens: `1h 1d 2d 1w 2w 1m`. Without one, the last 50 messages
are used.
## Run under a supervisor
The bot does not daemonise. Use a process supervisor so it restarts
and starts at boot.
systemd (`/etc/systemd/system/xmppcb.service`):
```ini
[Unit]
Description=xmppcb XMPP AI bot
After=network-online.target
[Service]
WorkingDirectory=/home/youruser/xmpp-bot/xmppcb
ExecStart=/home/youruser/xmpp-bot/xmppcb/xmppcb
Environment=XMPP_PASSWORD=...
Environment=LLM_API_KEY=...
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
Prefer an `EnvironmentFile=` with mode 600 over inline secrets.
## Notes and limitations
- The bot only sees messages sent while it is in the room.
- LLM calls are blocking: the bot pauses for the few seconds a reply
takes. Adequate for a low-traffic bot.
- The XML parser is intentionally narrow — it understands only the
XMPP stanzas this bot needs, not arbitrary XML.
- Resource use is small: ~37 KB binary, a few MB RSS.
## Layout
```
xmppcb/
├── xmppcb.c all logic: TCP, TLS, XML, SASL, MUC, HTTP, LLM
├── config.def.h config template (committed)
├── config.h your config (copied from .def, gitignored)
├── instruction.md.sample system prompt template (committed)
├── instruction.md system prompt in use (gitignored)
├── start.sample run-script template (committed)
├── start run script exporting the secrets (gitignored)
├── makefile
└── history/ per-room chat logs (generated, gitignored)
```
|