agentbell 1.6.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MoodTechBasti
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ prune tests
2
+ prune internal
3
+ exclude .license-secret
@@ -0,0 +1,502 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentbell
3
+ Version: 1.6.3
4
+ Summary: Push notifications and phone approvals for AI coding agents and scripts (ntfy, Telegram, OS fallback).
5
+ Author-email: MoodTechBasti <basti@moodtechsolutions.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/MoodTechBasti/agentbell
8
+ Project-URL: Repository, https://github.com/MoodTechBasti/agentbell
9
+ Project-URL: Changelog, https://github.com/MoodTechBasti/agentbell/blob/main/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/MoodTechBasti/agentbell/issues
11
+ Keywords: ntfy,notification,push-notifications,cli,ai-agents,claude-code,codex,gemini-cli,cursor,opencode,mcp,approval,telegram
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Communications
24
+ Classifier: Topic :: System :: Monitoring
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Dynamic: license-file
30
+
31
+ # agentbell
32
+
33
+ **One place for all your AI agent notifications — phone push + Approve/Deny from your pocket.**
34
+
35
+ [![CI](https://github.com/MoodTechBasti/agentbell/actions/workflows/ci.yml/badge.svg)](https://github.com/MoodTechBasti/agentbell/actions) [![License](https://img.shields.io/github/license/MoodTechBasti/agentbell)](LICENSE) ![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg) ![Dependencies: 0](https://img.shields.io/badge/dependencies-0-brightgreen.svg)
36
+
37
+ [Setup](#60-second-setup) · [Approval flow](#approval-flow-human-in-the-loop) · [Agents](#agents-what-gets-wired-up) · [Any other agent](#any-other-agent) · [Free vs. premium](#free-vs-premium) · [Commands](#quick-reference) · [MCP](#desktop-apps-and-editors-mcp) · [Trust model](#trust-model) · [Troubleshooting](#troubleshooting) · [FAQ](#faq)
38
+
39
+ ---
40
+
41
+ Be honest — how many times have you already checked your screen today while your AI agent still wasn’t done?
42
+
43
+ You jump between ChatGPT, Claude, Gemini, Cursor, DeepSeek… Desktop apps, CLI, browser windows. Always checking. Always a bit on edge.
44
+
45
+ `agentbell` is the single place that tells you when something actually needs you.
46
+
47
+ - **Push notification** straight to your phone the moment an agent finishes, fails, or waits for input
48
+ - When it really needs a decision, you tap **Approve** or **Deny** from your phone — no running back to the keyboard
49
+ - One stdlib-only Python file, zero dependencies, free, no account, no server
50
+
51
+ Works with **Claude Code, Codex, OpenCode, Cursor, Gemini CLI, Kimi Code, Qwen Code, Windsurf, Cline, Continue, Zed, Aider**, the **ChatGPT and Claude desktop apps** (via MCP), CI jobs, any shell script — and [any other agent](#any-other-agent), via `agentbell integrate`.
52
+
53
+ > **Status:** v1.6.3 — feedback wanted.
54
+
55
+ **The loop:**
56
+
57
+ ```text
58
+ agent finishes or blocks -> agentbell -> phone
59
+ agent receives decision <- agentbell <- Approve / Deny
60
+ ```
61
+
62
+ **Requirements:** Python 3.9+ · the free [ntfy](https://ntfy.sh) app (iOS/Android) · no account and no server of your own for the free core.
63
+
64
+ ---
65
+
66
+ ## 60-second setup
67
+
68
+ ### PyPI install — in preparation
69
+
70
+ The primary installation path will be `pipx`, which keeps the CLI isolated
71
+ while making `agentbell` available on your `PATH`:
72
+
73
+ ```bash
74
+ pipx install agentbell
75
+ agentbell init # wizard: topic name, quiet hours, agent hooks, test push
76
+ ```
77
+
78
+ Inside an existing virtual environment, `pip install agentbell` will be the
79
+ alternative. **The package is not published yet:** these commands remain
80
+ unverified until a fresh PyPI install reports v1.6.3 and `agentbell doctor`
81
+ completes its health check. Until that evidence is recorded in
82
+ `FIELD_TEST.md`, use the checkout path below.
83
+
84
+ ### Checkout install — available now
85
+
86
+ **No dev experience needed.** On macOS or Linux, open a terminal and run:
87
+
88
+ ```bash
89
+ git clone https://github.com/MoodTechBasti/agentbell && cd agentbell
90
+ ./install.sh # picks pipx, pip --user or a plain copy — whichever works
91
+ agentbell init # wizard: topic name, quiet hours, agent hooks, test push
92
+ ```
93
+
94
+ That's it. `agentbell init` prints the next steps; `agentbell doctor` tells you exactly what's wrong and how to fix it at any point.
95
+
96
+ **Windows (PowerShell):** install from the checkout without `install.sh`:
97
+
98
+ ```powershell
99
+ git clone https://github.com/MoodTechBasti/agentbell
100
+ Set-Location agentbell
101
+ py -m pip install --user .
102
+ py -m agentbell init # works even before the Scripts folder is on PATH
103
+ ```
104
+
105
+ To make `agentbell` available to future terminals, hooks, and desktop MCP clients, run this once in PowerShell, then close and reopen PowerShell:
106
+
107
+ ```powershell
108
+ $scripts = py -c "import sysconfig; print(sysconfig.get_path('scripts', scheme='nt_user'))"
109
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
110
+ [Environment]::SetEnvironmentVariable("Path", "$userPath;$scripts", "User")
111
+ ```
112
+
113
+ After reopening PowerShell, `agentbell doctor` confirms the installation.
114
+
115
+ > **New to the terminal?** You need Python 3.9+. On macOS: `brew install python3`. On Debian/Ubuntu: `sudo apt install python3`. On Windows, install Python from [python.org](https://www.python.org/downloads/) and use `py --version`. If `agentbell` is not found after installation, run `py -m agentbell doctor` for a copy-pasteable PATH fix.
116
+
117
+ ### Developer path — full reference below
118
+
119
+ If you know your way around hooks, MCP and config files, jump straight to [Agents: what gets wired up](#agents-what-gets-wired-up), the [Quick reference](#quick-reference), or [MCP](#desktop-apps-and-editors-mcp).
120
+
121
+ ---
122
+
123
+ ## Approval flow (human in the loop)
124
+
125
+ This is the part no notifier gives you: the agent doesn't just tell you it's blocked, it **waits for your answer** — and you give it from your phone.
126
+
127
+ ```
128
+ agent ── ask "Deploy to prod?" ──► phone: 🔴 Approval requested
129
+ [Approve] [Deny] (or type any answer)
130
+ agent ◄── approved / denied / your text / timeout ◄── phone
131
+ ```
132
+
133
+ The answer travels **through ntfy itself** — you don't expose an endpoint:
134
+
135
+ - The question goes to your main topic with action buttons.
136
+ - Buttons and app replies publish to a dedicated `<topic>-responses` topic.
137
+ - `ask` waits on a live stream **plus** a polling fallback (robust when a server buffers streams).
138
+
139
+ **Button answers never get crossed.** Every question carries a 64-bit request ID, and button answers are matched to exactly that ID. Free-text replies carry no ID, so they always go to the newest open question — with two asks in flight, answer with the buttons. Answers that were already on the topic when a question is asked are ignored, so a new `ask` can never inherit an old answer.
140
+
141
+ **How your reply is read:**
142
+
143
+ | You reply | Result | Exit |
144
+ |---|---|---|
145
+ | tap **Approve**, or type `yes` / `ok` / `y` | approved | 0 |
146
+ | tap **Deny**, or type `no` / `deny` / `stop` | denied | 1 |
147
+ | `no, not before the release` | denied, reason kept | 1 |
148
+ | `use the staging cluster` | answered (text on stdout) | 0 |
149
+ | `yes, but use staging` | answered, **not** a bare approval | 0 |
150
+ | nothing | timeout | 2 |
151
+
152
+ Exit 0 means "approved **or** answered" — so if you chain `agentbell ask "Deploy?" && deploy`, a free-text reply also proceeds. For a strict gate, read the `--json` output and check `approved` together with `answer`.
153
+
154
+ > **Before you gate anything real on this:** the answer path is only as private as your topic name, and on public ntfy.sh anyone who knows that name can approve your questions. Read the [trust model](#trust-model) — for sensitive approvals, self-host ntfy with auth.
155
+
156
+ ---
157
+
158
+ ## Agents: what gets wired up
159
+
160
+ `agentbell hooks install <agent>` does the wiring for you. Nothing is written into your agent session, nothing blocks a turn. (Your agent isn't in the table? See [Any other agent](#any-other-agent).)
161
+
162
+ | Agent | Mechanism | Scope | Events |
163
+ |---|---|---|---|
164
+ | **Claude Code** | `~/.claude/settings.json` hooks | global | finished (with duration), failed, needs-input |
165
+ | **Codex** | `~/.codex/config.toml` `[[hooks.…]]` | global | finished (with duration) |
166
+ | **OpenCode** | real plugin in `~/.config/opencode/plugin/` | global | finished (with duration), failed, permission asked |
167
+ | **Gemini CLI** | `~/.gemini/settings.json` `AfterAgent` | global | finished |
168
+ | **Kimi Code** | `~/.kimi-code/config.toml` `[[hooks]]` | global | finished (with duration), failed |
169
+ | **Qwen Code** | `~/.qwen/settings.json` hooks | global | finished (with duration), failed |
170
+ | **Cursor** | `.cursor/rules/agentbell.mdc` (`alwaysApply`) | project | finished, needs-input, failed |
171
+ | **Windsurf** | `.windsurf/rules/agentbell.md` (`trigger: always_on`) + legacy `.mdc` for pre-Devin builds | project | finished, needs-input, failed |
172
+ | **Cline** | `.clinerules/agentbell.md` | project | finished, needs-input, failed |
173
+ | **Continue** | `.continue/rules/agentbell.md` | project | finished, needs-input, failed |
174
+ | **Zed** | `.rules` block | project | finished, needs-input, failed |
175
+ | **Aider** | Aider-scoped `AGENTS.md` block | project | finished, needs-input, failed |
176
+
177
+ Claude Code, Codex, OpenCode, Gemini CLI, Kimi Code and Qwen Code have real hook/plugin systems — the wiring is exact and deterministic. The editors (Cursor, Windsurf, Cline, Continue, Zed, Aider) have no lifecycle hooks, so they get a clearly marked rule file that tells the agent when to call the CLI. That's best-effort by construction: it's an instruction the model can skip. Existing configs are merged, never overwritten; `uninstall` removes only what was added.
178
+
179
+ Older Aider installs used a shared `AGENTS.md` instruction that other agents
180
+ could follow too. `agentbell hooks status` and `agentbell verify` display an
181
+ ACTION REQUIRED banner when they find one. Run `agentbell hooks install aider`
182
+ from that project to update only agentbell's marked block; all other
183
+ `AGENTS.md` content is preserved.
184
+
185
+ `agentbell init` lists every agent it detects on your system (CLI on `PATH` or config dir) and offers to wire it up; `agentbell hooks install all` wires every supported agent at once.
186
+
187
+ ### No spam while you're watching
188
+
189
+ "Finished" fires after *every* turn — a 20-second answer you watched happen isn't worth a push. So for Claude Code, Codex, OpenCode, Kimi Code and Qwen Code the installed hook carries `--min-duration 60`: turns shorter than a minute stay silent (logged as `hook.skipped_short` in `history`, so it's never a mystery). **Failures always send a notification**, and so does any turn whose duration is unknown.
190
+
191
+ The same push twice within 5 s (same agent, event and text) is one piece of news: the repeat is suppressed and logged as `hook.skipped_duplicate` — a host that reports one turn end twice, or six parallel sessions failing on the same outage, buzzes once.
192
+
193
+ Want a different threshold? Change the number in the hook command, or re-install:
194
+
195
+ ```bash
196
+ agentbell hooks install claude # default: 60 s
197
+ # then edit the "--min-duration 60" in ~/.claude/settings.json to taste (0 = every turn)
198
+ ```
199
+
200
+ Custom agents and scripts just call the CLI:
201
+
202
+ ```bash
203
+ long_job && agentbell notify "done" || agentbell notify "FAILED" --priority urgent
204
+ agentbell watch -- long_job # …or let watch do both
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Any other agent
210
+
211
+ The runtime is agent-agnostic: any agent that can run a shell command or register an MCP server can use agentbell — it doesn't need to be in the table above. Instead of shipping an installer per vendor, agentbell publishes a **contract** and observes the results:
212
+
213
+ ```bash
214
+ agentbell integrate # prints the self-integration guide (changes nothing)
215
+ agentbell verify # did it actually work? (read-only, sends nothing)
216
+ ```
217
+
218
+ Hand the `integrate` output to the agent ("integrate yourself with this"). It wires up **its own** config files, with its own permissions — agentbell never edits configs it doesn't have an installer for. Then one real turn plus `agentbell verify --agent <slug> --since 10m` shows whether events actually arrived, were held by quiet hours, or look like a double integration. `agentbell integrate --json` prints the same contract as a machine-readable manifest.
219
+
220
+ Three classes, honestly labeled:
221
+
222
+ - **Native** — the 12 agents in the table: installers maintained and tested here.
223
+ - **Self-integrated** — wired by the agent itself against the printed contract. Counts as *verified* only after `verify` has seen a real lifecycle event (a `--force` smoke test is marked as such and doesn't count).
224
+ - **Rules-based** — the agent only reads an instructions file: best-effort by construction; the model can skip the rule.
225
+
226
+ > **Status:** field-verified with a previously unknown agent so far: **GitHub Copilot CLI 1.0.80** (2026-08-21: self-integrated from the printed contract alone — real lifecycle events, `verify` exit 0, idempotent re-run, clean removal; evidence in `FIELD_TEST.md`). *This line gets updated as real integrations are reported.*
227
+
228
+ ---
229
+
230
+ ## What it fixes
231
+
232
+ | The annoying part | What agentbell does |
233
+ |---|---|
234
+ | Alt-tabbing every two minutes: "is it done yet?" | Push on finish / fail — with exit code and duration (`✅ npm run build succeeded in 4m12s`) |
235
+ | The agent silently waits for a permission you never saw | `input_required` push the second it blocks |
236
+ | You must sit at the keyboard to say "yes, deploy" | `agentbell ask` → **Approve / Deny buttons on your phone**; the agent blocks until you answer |
237
+ | Notifier tools want an account, a hosted server, or a subscription | Free core. No account, no server, no subscription. Telegram extras: **€4.99 once** |
238
+ | Wiring notifications into every agent, by hand, per repo | `agentbell init` detects your agents and installs their hooks — globally, so every repo is covered |
239
+ | It breaks at 3 a.m. and you have no clue why | `agentbell doctor` names the problem **and prints the command that fixes it** |
240
+ | "Notifications" that spam you all night | Quiet hours: drop *or* hold-and-bundle. Urgent always gets through |
241
+ | A wifi blip silently eats the notification | Retry, then a persistent queue that gets replayed |
242
+ | Uninstalling leaves junk in five config files | `agentbell uninstall` — dry run first, removes only its own markers |
243
+
244
+ ---
245
+
246
+ ## Free vs. premium
247
+
248
+ **Free and open source — the complete core:**
249
+ ntfy push · native OS notifications · agent hooks for 12 agents · the full approval flow (buttons + free text) · `watch` · webhook server · MCP server · priorities · quiet hours (with defer) · history · retry + offline queue · `doctor` · clean uninstall.
250
+
251
+ That list is the whole product for most people. Nothing above nags, expires, or asks for a key.
252
+
253
+ > **Premium — €4.99 one-time, lifetime. No subscription, no account, no phone-home.**
254
+ > - **Approve/Deny buttons that are authenticated to you.** A Telegram chat is tied to your account — unlike an ntfy topic, which anyone who learns its name could answer. (Via the `agentbell bot` daemon.)
255
+ > - Plus **parallel delivery**: ntfy *and* Telegram at once, first answer wins.
256
+ >
257
+ > [**Buy a lifetime key — €4.99**](https://buy.polar.sh/polar_cl_MAAwIuriOXF45xu9Fm0dbgr9iTIJFqsKM) — you get an `AB1-…` key by email within 24 hours (usually much faster), then: `agentbell license activate AB1-...`
258
+ > The key never expires and isn't tied to a machine — use it on every computer you work on. It's verified offline; nothing about you is ever sent anywhere. VAT is included and the payment provider sends your invoice. Not what you expected? Reply to the purchase email within 14 days and you get a refund, no questions asked.
259
+ >
260
+ > **The honest part:** the paywall is one `if` in a file you can read, and the project is MIT — a fork that deletes it is legal. €4.99 is priced as "less than the five minutes that would take." If it isn't worth that to you, the free core is complete and I'd rather you use it. What the key *is*: an Ed25519 signature over your customer id, checked against a public key that sits in plain sight in `agentbell.py`. It can't be forged, it's verified entirely on your machine (no network, ever), and there's no secret hidden in the install for anyone to dig out. See `DECISIONS.md` §2b for the full scheme and what it deliberately doesn't protect against.
261
+
262
+ ---
263
+
264
+ ## Telegram approvals (premium)
265
+
266
+ Real Approve/Deny buttons in Telegram, powered by a small opt-in long-polling daemon — no public endpoint, still zero dependencies.
267
+
268
+ ```bash
269
+ agentbell license activate <key>
270
+ agentbell init # enter bot token + chat id
271
+ agentbell bot install-service # answer daemon in the background
272
+ agentbell ask "Deploy to production?"
273
+ ```
274
+
275
+ - Buttons are attached only while the daemon's heartbeat is fresh — never dead buttons.
276
+ - Free-text replies in the bot chat count as answers; only your configured chat can answer.
277
+ - With ntfy **and** Telegram configured, both get the question — first answer wins.
278
+ - `agentbell bot status` shows daemon state, lock, last error, open questions, queue counts.
279
+
280
+ ---
281
+
282
+ ## Quick reference
283
+
284
+ ```bash
285
+ # notify
286
+ agentbell notify "Build finished" --priority high --tags build
287
+
288
+ # run something and get told how it went (exit code is passed through)
289
+ agentbell watch -- npm run build
290
+
291
+ # ask and wait for the answer (exit 0=approved/answered, 1=denied, 2=timeout, 3=error)
292
+ agentbell ask "Deploy to production?" --timeout 600
293
+ agentbell ask "Which environment?" --no-buttons # free-text answer
294
+ agentbell ask "Deploy?" --json
295
+
296
+ # wire up agents (global — applies in every repo)
297
+ agentbell hooks install claude codex opencode gemini cursor
298
+ agentbell hooks install all # every supported agent, detected or not
299
+ agentbell hooks status
300
+ agentbell hooks uninstall all
301
+
302
+ # any agent not in the list above
303
+ agentbell integrate # print the self-integration contract (changes nothing)
304
+ agentbell integrate --json # same contract as a machine-readable manifest
305
+ agentbell verify --agent <slug> # did events actually arrive? read-only, sends nothing
306
+
307
+ # expose as an MCP tool (desktop apps + editors)
308
+ agentbell mcp add # all clients it can detect
309
+ agentbell mcp add claude-desktop # just one
310
+ agentbell mcp add --print # print the snippet, change nothing
311
+
312
+ # health check with copy-paste fixes
313
+ agentbell doctor
314
+ agentbell doctor --send # …and send a real test notification
315
+
316
+ # premium: Telegram answer daemon
317
+ agentbell bot install-service # run in the background (systemd/launchd) — recommended
318
+ agentbell bot # or in the foreground, for debugging
319
+ agentbell bot status
320
+
321
+ # reliability + inspection
322
+ agentbell queue list # what is waiting and why
323
+ agentbell queue flush # deliver it now
324
+ agentbell history --limit 20
325
+ agentbell config show # secrets redacted
326
+ agentbell config set ntfy.topic <new> # change one setting, no wizard
327
+
328
+ # webhook for CI / a VPS without the CLI
329
+ agentbell server # POST /notify, POST /ask, GET /healthz
330
+
331
+ # complete removal
332
+ agentbell uninstall # dry run, deletes nothing
333
+ agentbell uninstall --yes
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Desktop apps and editors (MCP)
339
+
340
+ `agentbell mcp add` registers a stdio MCP server exposing two tools:
341
+ `notify(message, title, priority, tags)` and `ask_approval(message, timeout_seconds)`.
342
+
343
+ | Client | Where it's registered | Works |
344
+ |---|---|---|
345
+ | **ChatGPT Desktop** | `~/.codex/config.toml` (shared with Codex CLI) | yes — local stdio |
346
+ | **Claude Desktop** | `claude_desktop_config.json` | yes — local stdio |
347
+ | Claude Code | `claude mcp add --scope user` | yes |
348
+ | Codex CLI | `~/.codex/config.toml` | yes |
349
+ | Cursor | `~/.cursor/mcp.json` (global) | yes |
350
+ | VS Code / Copilot | user `mcp.json` | yes |
351
+ | Gemini CLI, OpenCode | their settings files | yes |
352
+ | **Qwen Code** | `~/.qwen/settings.json` (global; `--project` → `.qwen/settings.json`) | yes |
353
+ | **Kimi Code** | `~/.kimi-code/mcp.json` (global; `--project` → `.kimi-code/mcp.json`) | yes |
354
+ | ChatGPT **web** | — | no: web accepts remote MCP servers only |
355
+
356
+ Restart the client afterwards. `agentbell mcp add --print` gives you the raw snippet for anything not in that list (Windsurf, Zed, LM Studio, …); `examples/README.md` has the same snippets to copy. Kimi Code exposes the tools as `mcp__agentbell__notify` and `mcp__agentbell__ask_approval`.
357
+
358
+ ---
359
+
360
+ ## Events, priorities, quiet hours
361
+
362
+ | Event | Priority | Emoji |
363
+ |---|---|---|
364
+ | `run_completed` | normal (3) | ✅ |
365
+ | `run_failed` | urgent (5) | 🔴 |
366
+ | `input_required` | high (4) | 🔵 |
367
+ | `permission_required` | high (4) | 🔐 |
368
+ | `started` | low (2) | ▶️ |
369
+
370
+ Quiet hours (e.g. `22:00-07:30`) hold back everything below `normal`:
371
+
372
+ | `quiet_hours_mode` | Behavior |
373
+ |---|---|
374
+ | `suppress` (default) | dropped, logged to history |
375
+ | `defer` | delivered after the window; more than 3 are bundled into one summary |
376
+
377
+ `--force` bypasses quiet hours, `--defer` defers a single message. **Approval questions are never suppressed or deferred.**
378
+
379
+ ---
380
+
381
+ ## Reliability
382
+
383
+ Transient failures (network down, timeout, 5xx) are retried with backoff, then the notification goes into a persistent queue instead of being lost:
384
+
385
+ - replayed after your next successful send, by `queue flush`, or by the bot daemon
386
+ - `queue list` shows exactly what's waiting, how old it is and why
387
+ - bounded: 100 items / 24 h, oldest dropped first — everything logged to history
388
+ - `notify` exits 0 when queued (not lost, just delayed); `ask` is never queued
389
+
390
+ This is best-effort delivery, not a guarantee — see [trust model](#trust-model) for what ntfy.sh's free tier does and doesn't promise.
391
+
392
+ ---
393
+
394
+ ## Configuration
395
+
396
+ `~/.config/agentbell/config.json` (mode 600 — it holds your license key, bot token and ntfy password):
397
+
398
+ | Key | Meaning |
399
+ |---|---|
400
+ | `ntfy.server` / `ntfy.topic` / `ntfy.auth` | channel + optional `user:pass` (or an access token) for self-hosted ntfy |
401
+ | `ntfy.action_auth` | optional scoped credential for approval buttons (see the [trust model](#trust-model)) |
402
+ | `telegram.bot_token` / `telegram.chat_id` | Telegram channel (premium) |
403
+ | `license` | premium key |
404
+ | `channels` | `["ntfy"]`, `["ntfy","os"]`, `["ntfy","telegram"]` |
405
+ | `quiet_hours` / `quiet_hours_min_priority` / `quiet_hours_mode` | see above |
406
+ | `approval_timeout` | default seconds for `ask` (300) |
407
+ | `webhook.listen` / `webhook.port` / `webhook.token` | `agentbell server` (token = bearer auth; required for any non-loopback `listen`) |
408
+
409
+ State (history, queue, deferred, bot state): `~/.local/state/agentbell/`.
410
+ Env overrides: `AGENTBELL_CONFIG_DIR`, `AGENTBELL_CONFIG`, `AGENTBELL_STATE_DIR`, `AGENTBELL_LICENSE`.
411
+
412
+ ---
413
+
414
+ ## Trust model
415
+
416
+ What this tool actually protects, and what it doesn't. Read this before you gate a production deploy on it.
417
+
418
+ **Your topic name is the only credential in the free setup.** Anyone who learns it can read every notification, publish fake ones, and approve or deny any open `ask`. Treat it like a password — that's ntfy's own wording in their terms. `init` generates a long random topic for exactly this reason, so don't shorten it, and **don't paste `doctor` or `config show` output into public issues.**
419
+
420
+ **Sensitive approvals get a runtime warning when ntfy authentication is absent.** AgentBell recognizes only a narrow set of high-impact requests (for example, production deployments, production database deletion, credential rotation, money transfers, and firewall changes). This is a reminder, not a security decision: it cannot understand every action's real impact. Use self-hosted ntfy with auth before relying on phone approval for a sensitive action.
421
+
422
+ **ntfy.sh is a third-party relay.** Your message text passes through servers you don't control and can be read there — including the working directory that hook notifications carry. If that matters for your work, self-host ntfy and point `ntfy.server` at it.
423
+
424
+ **Action buttons carry their credential inside the message.** On a protected server, every subscriber to the topic can see a button's `Authorization` header. Set `ntfy.action_auth` to a token that may only publish to the `-responses` topic instead of reusing your account password.
425
+
426
+ **Free-text replies go to the newest open question.** Button answers are matched by request ID and are unambiguous. With two asks in flight, answer with the buttons.
427
+
428
+ **The webhook server trusts its loopback.** On loopback it accepts requests from any local process. Set `webhook.token` even locally; browser-originated requests are rejected. A non-loopback `listen` without a token is refused outright.
429
+
430
+ **ntfy.sh free-tier limits that matter:** 250 messages/day · at most 3 action buttons per notification · 4 KB message size · **no delivery guarantee** — it's best-effort. Self-hosting or ntfy's paid tiers are the reliability path.
431
+
432
+ **Self-integration is the agent's work, not agentbell's.** `agentbell integrate` only prints instructions — agentbell never edits configs of agents it has no installer for, and gains no new write surface from the feature. The guide's safety rails (only your own configs, diff + explicit OK outside the project, never read agentbell's config or state) are instructions to a model, not something agentbell can enforce. That's also why `verify` deliberately never prints your topic, server or paths: it's the one status command designed to be safe to hand to an agent. `doctor` does print the topic — keep it for humans.
433
+
434
+ **Not a security boundary:** agentbell doesn't authenticate who publishes to your topic and doesn't encrypt message bodies end-to-end.
435
+
436
+ ---
437
+
438
+ ## Troubleshooting
439
+
440
+ **Start here: `agentbell doctor`** — it checks the installation, PATH, config, server reachability, quiet hours, license, hooks, MCP, queue and state dir, and prints a fix command for everything that's wrong.
441
+
442
+ | Symptom | Usually |
443
+ |---|---|
444
+ | Nothing arrives | you haven't subscribed to the topic in the app, or quiet hours are active → `agentbell doctor` |
445
+ | Nothing arrives, no error | `agentbell history --limit 10` shows `suppressed` / `queued` / `deferred` |
446
+ | Telegram buttons missing | the answer daemon isn't running → `agentbell bot install-service` |
447
+ | Topic too guessable | `agentbell config set ntfy.topic <long-random>`, then re-subscribe in the app |
448
+ | "webhook is active" | another process holds a Telegram webhook: `curl -s "https://api.telegram.org/bot<TOKEN>/deleteWebhook"`, then restart the bot |
449
+ | Hooks don't fire | `agentbell hooks status`; for Codex check `/hooks` inside Codex |
450
+ | Start over | `agentbell uninstall` → `--yes`; while PyPI publishing is pending, reinstall from a checkout with `./install.sh && agentbell init` (macOS/Linux) or `py -m pip install --user .` then `agentbell init` (Windows) |
451
+
452
+ ---
453
+
454
+ ## FAQ
455
+
456
+ **Is my data private?**
457
+ Nothing goes to me — there's no account, no telemetry, and no phone-home, and the license check is offline. But your notification text does pass through whichever ntfy server you use, and on the default `ntfy.sh` that's a third-party relay. Self-host ntfy if your message text is sensitive; see the [trust model](#trust-model).
458
+
459
+ **Does it work self-hosted?**
460
+ Yes, and that's the recommended setup for anything sensitive. Point `ntfy.server` at your own instance, put credentials in `ntfy.auth`, and give the approval buttons a scoped publish-only token via `ntfy.action_auth`. Everything else — hooks, approvals, quiet hours, queue — behaves identically.
461
+
462
+ **Can I use it without Telegram?**
463
+ Yes. Telegram is the premium add-on; the free core is complete without it, approval flow included. ntfy alone gives you push, Approve/Deny buttons and free-text replies.
464
+
465
+ **Why is Telegram paid if it's MIT?**
466
+ Because the code being open and the work being worth paying for aren't in conflict. The gate is one `if` you can read, and deleting it in a fork is legal — €4.99 once is priced below the effort of doing that. It funds the maintenance; it isn't a moat, and it isn't pretending to be one.
467
+
468
+ **Found a bug, or stuck on something?**
469
+ [Open an issue](https://github.com/MoodTechBasti/agentbell/issues) — the bug template asks for `agentbell doctor` output (redact your topic names first).
470
+
471
+ ---
472
+
473
+ ## Removal
474
+
475
+ ```bash
476
+ agentbell uninstall # dry run: lists everything, deletes nothing
477
+ agentbell uninstall --yes # binary, config, state, hooks, MCP entries
478
+ ```
479
+
480
+ Only its own markers are removed — your other hooks and MCP servers stay. Not removed automatically: the ntfy subscription on your phone, a Telegram bot at BotFather, `AGENTBELL_*` env vars in your shell rc.
481
+
482
+ ---
483
+
484
+ ## Development
485
+
486
+ ```bash
487
+ python3 -m unittest discover -s tests -v # macOS/Linux, no external deps
488
+ py -m unittest discover -s tests -v # Windows
489
+ ```
490
+
491
+ - [`CONTRIBUTING.md`](CONTRIBUTING.md) — how to propose a change, and what gets merged
492
+ - [`SECURITY.md`](SECURITY.md) — how to report a vulnerability
493
+ - [`DECISIONS.md`](DECISIONS.md) — why the tool is built the way it is, including what was deliberately left out
494
+ - [`CHANGELOG.md`](CHANGELOG.md) — what changed per version
495
+ - [`FIELD_TEST.md`](FIELD_TEST.md) — the 2-week field-test checklist this build is running against
496
+ - [`examples/`](examples/) — reference copies of every config it writes, plus script patterns
497
+
498
+ ---
499
+
500
+ ## License
501
+
502
+ MIT — see [`LICENSE`](LICENSE).