claude-telegram-bridge 0.4.1__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 Claude Telegram Bridge contributors
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,265 @@
1
+ Metadata-Version: 2.4
2
+ Name: claude-telegram-bridge
3
+ Version: 0.4.1
4
+ Summary: Control an existing interactive Claude Code session from Telegram.
5
+ Author: Claude Telegram Bridge contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/ssamssae/claude-telegram-bridge
8
+ Project-URL: Repository, https://github.com/ssamssae/claude-telegram-bridge
9
+ Project-URL: Releases, https://github.com/ssamssae/claude-telegram-bridge/releases
10
+ Project-URL: Issues, https://github.com/ssamssae/claude-telegram-bridge/issues
11
+ Keywords: claude,telegram,tmux,bridge,automation
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Communications :: Chat
19
+ Classifier: Topic :: Software Development
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Dynamic: license-file
24
+
25
+ # Claude Telegram Bridge
26
+
27
+ Control an already-running interactive Claude Code session from Telegram.
28
+
29
+ This bridge polls Telegram, pastes incoming messages into a visible tmux Claude
30
+ Code pane, tails Claude transcript JSONL, and sends only the matching final
31
+ answer back to Telegram.
32
+
33
+ The bridge is Claude-specific. It is not a general multi-AI bridge and it does
34
+ not share runtime code with the Codex Telegram Bridge.
35
+
36
+ ## What It Supports
37
+
38
+ - Text prompts from Telegram into a live Claude Code tmux session.
39
+ - Telegram photos and image documents saved locally, then injected as
40
+ `local_path` prompts for Claude to inspect.
41
+ - Telegram voice, audio, video, animation, and document uploads saved locally
42
+ with caption and metadata preserved.
43
+ - Optional audio transcription through a local command configured with
44
+ `CLB_AUDIO_TRANSCRIBE_CMD`.
45
+ - Transcript-based final-answer extraction instead of screen scraping.
46
+ - Optional flow mirror: live "work in progress" card that mirrors each tool-use
47
+ step of the current turn to Telegram so you can follow long runs.
48
+ - Single Telegram chat allowlist and token ownership registry.
49
+ - Duplicate-egress guard hooks for users who also have Telegram MCP reply tools
50
+ or terminal mirror hooks installed.
51
+
52
+ This is not MCP. It is a local bridge daemon for one visible Claude Code
53
+ session.
54
+
55
+ ## Public Export Model
56
+
57
+ This public repository is maintained from a private operator source through a
58
+ sanitized export step. The export keeps the reusable Claude bridge behavior,
59
+ hook templates, config examples, and documentation, while stripping private chat
60
+ ids, token paths, hostnames, node labels, and local automation paths before
61
+ release.
62
+
63
+ Claude Telegram Bridge and Codex Telegram Bridge remain separate programs
64
+ because they drive different interactive CLIs and transcript formats. The shared
65
+ maintenance rule is the same: keep one internal source for each bridge, generate
66
+ the public copy through an export script, and never publish private wrappers or
67
+ operator-specific trigger paths.
68
+
69
+ ## Billing And Terms
70
+
71
+ This project does not use `claude -p` and does not create hidden one-shot
72
+ Claude sessions. It drives an interactive Claude Code session that you already
73
+ started.
74
+
75
+ The subscription billing classification of a 24/7 daemon that automatically
76
+ injects prompts into an interactive Claude Code session is unverified. This
77
+ project does not claim that this usage is subscription-safe. You are responsible
78
+ for deciding whether to run it under your account, plan, and applicable terms.
79
+
80
+ ## Verified Backend
81
+
82
+ - Claude Code interactive tmux session: experimental, locally verified by the
83
+ maintainers.
84
+ - Other AI CLIs: not supported.
85
+
86
+ ## How It Works
87
+
88
+ ```text
89
+ Telegram user message/media
90
+ -> getUpdates polling
91
+ -> single chat id allowlist
92
+ -> media download to local state directory when present
93
+ -> paste prompt envelope into tmux Claude pane
94
+ -> SessionStart sidecar binds tmux pane to Claude transcript JSONL
95
+ -> transcript tail finds the final answer for the injected nonce
96
+ -> Telegram sendMessage
97
+ ```
98
+
99
+ The bridge uses one Bot API egress path. The included hooks prevent Claude's
100
+ Telegram MCP reply tool and terminal mirror hooks from sending duplicate
101
+ answers while the bridge owns a turn.
102
+
103
+ ## Slash Commands
104
+
105
+ Slash commands sent from Telegram are classified before anything is injected
106
+ into the Claude pane. Commands that would open an interactive picker or dialog
107
+ are never pasted raw, because a blocking dialog can freeze the one visible
108
+ session. Each command falls into one of these groups.
109
+
110
+ | Command | Behavior |
111
+ | --- | --- |
112
+ | `/context`, `/usage`, `/cost` | Read-only info commands. The bridge widens the tmux capture window, runs the command, waits for the render to finish before capturing (no more blank "in progress" frame), trims the terminal chrome to a clean text view, and mirrors that screen back to Telegram. |
113
+ | `/model` | Intercepted. Pasting `/model` raw opens an interactive picker that can freeze the session, so the bridge shows an inline keyboard of model choices instead and applies the pick non-interactively as `/model <alias>`. |
114
+ | `/clear`, `/exit`, `/quit` | Passed through unchanged; these do not open a dialog. `/exit` and `/quit` end the session, so the bridge triggers watchdog recovery for a graceful restart afterward. `/clear` only resets context. |
115
+ | `/ping`, `/start`, `/status` | Bridge health and status, answered by the bridge itself. |
116
+ | Anything else | Blocked from injection as a freeze-guard fail-safe. The bridge replies with the supported list instead of risking a stuck session. |
117
+
118
+ To bypass the freeze guard and inject a slash command raw, prefix the Telegram
119
+ message with `!` (for example `!/theme`).
120
+
121
+ Capture tuning for `/context`, `/usage`, and `/cost`:
122
+
123
+ - `CLB_CONTEXT_SETTLE_SEC` - floor delay before the first capture attempt.
124
+ Defaults to `1.2` seconds.
125
+ - `CLB_CONTEXT_CAPTURE_TIMEOUT_SEC` - how long to keep polling for a finished
126
+ render before sending the last captured frame. Defaults to `8.0` seconds.
127
+ - `CLB_MODEL_CHOICES` - optional comma-separated list of model aliases shown in
128
+ the `/model` inline keyboard.
129
+
130
+ ## Files
131
+
132
+ - `claude_telegram_bridge.py` - bridge daemon.
133
+ - `hooks/claude-telegram-bridge-session-start.sh` - records transcript and tmux
134
+ pane binding for the daemon.
135
+ - `hooks/claude-telegram-bridge-pretool-block.sh` - blocks Telegram MCP replies
136
+ during bridge-owned turns.
137
+ - `config.example.env` - local environment template.
138
+
139
+ ## Minimal Manual Setup
140
+
141
+ 1. Start Claude Code in tmux:
142
+
143
+ ```bash
144
+ tmux -L default new -s claude
145
+ claude --dangerously-skip-permissions
146
+ ```
147
+
148
+ 2. Create a Telegram bot with BotFather. Paste the bot token only into your
149
+ local terminal or local config file. Never send it in Telegram.
150
+
151
+ 3. Copy the example config:
152
+
153
+ ```bash
154
+ cp config.example.env .env
155
+ chmod 600 .env
156
+ ```
157
+
158
+ 4. Edit `.env` and set:
159
+
160
+ ```bash
161
+ CLB_TOKEN_FILE="$HOME/.config/claude-telegram-bridge/token.json"
162
+ CLB_CHAT_ID="123456789"
163
+ CLB_TOKEN_REGISTRY="$HOME/.config/claude-telegram-bridge/token-registry.json"
164
+ CLB_STATE_DIR="$HOME/.local/state/claude-telegram-bridge"
165
+ ```
166
+
167
+ 5. Store the token locally:
168
+
169
+ ```bash
170
+ mkdir -p "$HOME/.config/claude-telegram-bridge"
171
+ printf '{"token":"%s"}\n' 'PASTE_BOTFATHER_TOKEN_HERE' \
172
+ > "$HOME/.config/claude-telegram-bridge/token.json"
173
+ chmod 600 "$HOME/.config/claude-telegram-bridge/token.json"
174
+ ```
175
+
176
+ 6. Create a token registry entry. The `token_id` is the first 16 hex chars of
177
+ the SHA-256 of the token.
178
+
179
+ ```bash
180
+ python3 - <<'PY'
181
+ import hashlib, json, pathlib
182
+ root = pathlib.Path.home() / ".config/claude-telegram-bridge"
183
+ token = json.loads((root / "token.json").read_text())["token"]
184
+ token_id = hashlib.sha256(token.encode()).hexdigest()[:16]
185
+ (root / "token-registry.json").write_text(json.dumps({
186
+ "tokens": {
187
+ "default": {
188
+ "token_id": token_id,
189
+ "mode": "polling",
190
+ "owner": "claude-telegram-bridge",
191
+ "expected_consumer": "claude",
192
+ "allow_delete_webhook": False
193
+ }
194
+ }
195
+ }, indent=2) + "\n")
196
+ PY
197
+ ```
198
+
199
+ 7. Register the SessionStart hook in Claude Code settings. The exact settings
200
+ file location depends on your Claude Code install.
201
+
202
+ ```json
203
+ {
204
+ "hooks": {
205
+ "SessionStart": [
206
+ {
207
+ "hooks": [
208
+ {
209
+ "type": "command",
210
+ "command": "/absolute/path/to/hooks/claude-telegram-bridge-session-start.sh"
211
+ }
212
+ ]
213
+ }
214
+ ]
215
+ }
216
+ }
217
+ ```
218
+
219
+ 8. Run the daemon:
220
+
221
+ ```bash
222
+ set -a
223
+ . ./.env
224
+ set +a
225
+ python3 claude_telegram_bridge.py
226
+ ```
227
+
228
+ Send `/ping` to the bot, then send a normal prompt.
229
+
230
+ ## Safety Defaults
231
+
232
+ - Polling only; no public webhook is required.
233
+ - One allowed Telegram chat id.
234
+ - Token ownership registry must match the local token before polling starts.
235
+ - Interactive slash commands that could open a blocking dialog are held back by
236
+ a freeze guard rather than pasted raw; a set of read-only and safe commands is
237
+ supported and mirrored. See [Slash Commands](#slash-commands) for the full set
238
+ and the `!` escape hatch.
239
+ - The PreToolUse egress guard is included for users who also have Telegram MCP
240
+ reply tools installed.
241
+ - Outgoing media auto-send is not part of this minimal export.
242
+
243
+ ## Optional Settings
244
+
245
+ - `CLB_FLOW_MIRROR_FLAG` - path to a flag file that enables the flow mirror.
246
+ When the file exists, the bridge mirrors each tool-use step of the current
247
+ turn to Telegram as one live-updating card. Off by default (no file). Enable
248
+ with `touch "$HOME/.config/claude-telegram-bridge/flow-mirror.on"` and disable
249
+ by removing the file.
250
+ - `CLB_ACTIVE_TURN_STALE_SECONDS` - releases a previously observed Telegram turn
251
+ when Claude is idle but no final reply was captured, so later queued messages
252
+ can continue instead of being blocked behind a stale active turn. Defaults to
253
+ 900 seconds.
254
+
255
+ ### Advanced settings
256
+
257
+ The bridge reads ~20 more tuning knobs (self-update via `CLB_AUTO_UPDATE` /
258
+ `CLB_NO_UPDATE_CHECK`, send-retry policy, durable queue/outbox paths, session
259
+ binding TTLs, an optional `CLB_WATCHDOG_SCRIPT` lifecycle hook, and more). All
260
+ of them ship with safe defaults; the full annotated list lives at the bottom
261
+ of `config.example.env`.
262
+
263
+ ## Release Checklist
264
+
265
+ See `RELEASE_CHECKLIST.md` before publishing a fork or release.
@@ -0,0 +1,241 @@
1
+ # Claude Telegram Bridge
2
+
3
+ Control an already-running interactive Claude Code session from Telegram.
4
+
5
+ This bridge polls Telegram, pastes incoming messages into a visible tmux Claude
6
+ Code pane, tails Claude transcript JSONL, and sends only the matching final
7
+ answer back to Telegram.
8
+
9
+ The bridge is Claude-specific. It is not a general multi-AI bridge and it does
10
+ not share runtime code with the Codex Telegram Bridge.
11
+
12
+ ## What It Supports
13
+
14
+ - Text prompts from Telegram into a live Claude Code tmux session.
15
+ - Telegram photos and image documents saved locally, then injected as
16
+ `local_path` prompts for Claude to inspect.
17
+ - Telegram voice, audio, video, animation, and document uploads saved locally
18
+ with caption and metadata preserved.
19
+ - Optional audio transcription through a local command configured with
20
+ `CLB_AUDIO_TRANSCRIBE_CMD`.
21
+ - Transcript-based final-answer extraction instead of screen scraping.
22
+ - Optional flow mirror: live "work in progress" card that mirrors each tool-use
23
+ step of the current turn to Telegram so you can follow long runs.
24
+ - Single Telegram chat allowlist and token ownership registry.
25
+ - Duplicate-egress guard hooks for users who also have Telegram MCP reply tools
26
+ or terminal mirror hooks installed.
27
+
28
+ This is not MCP. It is a local bridge daemon for one visible Claude Code
29
+ session.
30
+
31
+ ## Public Export Model
32
+
33
+ This public repository is maintained from a private operator source through a
34
+ sanitized export step. The export keeps the reusable Claude bridge behavior,
35
+ hook templates, config examples, and documentation, while stripping private chat
36
+ ids, token paths, hostnames, node labels, and local automation paths before
37
+ release.
38
+
39
+ Claude Telegram Bridge and Codex Telegram Bridge remain separate programs
40
+ because they drive different interactive CLIs and transcript formats. The shared
41
+ maintenance rule is the same: keep one internal source for each bridge, generate
42
+ the public copy through an export script, and never publish private wrappers or
43
+ operator-specific trigger paths.
44
+
45
+ ## Billing And Terms
46
+
47
+ This project does not use `claude -p` and does not create hidden one-shot
48
+ Claude sessions. It drives an interactive Claude Code session that you already
49
+ started.
50
+
51
+ The subscription billing classification of a 24/7 daemon that automatically
52
+ injects prompts into an interactive Claude Code session is unverified. This
53
+ project does not claim that this usage is subscription-safe. You are responsible
54
+ for deciding whether to run it under your account, plan, and applicable terms.
55
+
56
+ ## Verified Backend
57
+
58
+ - Claude Code interactive tmux session: experimental, locally verified by the
59
+ maintainers.
60
+ - Other AI CLIs: not supported.
61
+
62
+ ## How It Works
63
+
64
+ ```text
65
+ Telegram user message/media
66
+ -> getUpdates polling
67
+ -> single chat id allowlist
68
+ -> media download to local state directory when present
69
+ -> paste prompt envelope into tmux Claude pane
70
+ -> SessionStart sidecar binds tmux pane to Claude transcript JSONL
71
+ -> transcript tail finds the final answer for the injected nonce
72
+ -> Telegram sendMessage
73
+ ```
74
+
75
+ The bridge uses one Bot API egress path. The included hooks prevent Claude's
76
+ Telegram MCP reply tool and terminal mirror hooks from sending duplicate
77
+ answers while the bridge owns a turn.
78
+
79
+ ## Slash Commands
80
+
81
+ Slash commands sent from Telegram are classified before anything is injected
82
+ into the Claude pane. Commands that would open an interactive picker or dialog
83
+ are never pasted raw, because a blocking dialog can freeze the one visible
84
+ session. Each command falls into one of these groups.
85
+
86
+ | Command | Behavior |
87
+ | --- | --- |
88
+ | `/context`, `/usage`, `/cost` | Read-only info commands. The bridge widens the tmux capture window, runs the command, waits for the render to finish before capturing (no more blank "in progress" frame), trims the terminal chrome to a clean text view, and mirrors that screen back to Telegram. |
89
+ | `/model` | Intercepted. Pasting `/model` raw opens an interactive picker that can freeze the session, so the bridge shows an inline keyboard of model choices instead and applies the pick non-interactively as `/model <alias>`. |
90
+ | `/clear`, `/exit`, `/quit` | Passed through unchanged; these do not open a dialog. `/exit` and `/quit` end the session, so the bridge triggers watchdog recovery for a graceful restart afterward. `/clear` only resets context. |
91
+ | `/ping`, `/start`, `/status` | Bridge health and status, answered by the bridge itself. |
92
+ | Anything else | Blocked from injection as a freeze-guard fail-safe. The bridge replies with the supported list instead of risking a stuck session. |
93
+
94
+ To bypass the freeze guard and inject a slash command raw, prefix the Telegram
95
+ message with `!` (for example `!/theme`).
96
+
97
+ Capture tuning for `/context`, `/usage`, and `/cost`:
98
+
99
+ - `CLB_CONTEXT_SETTLE_SEC` - floor delay before the first capture attempt.
100
+ Defaults to `1.2` seconds.
101
+ - `CLB_CONTEXT_CAPTURE_TIMEOUT_SEC` - how long to keep polling for a finished
102
+ render before sending the last captured frame. Defaults to `8.0` seconds.
103
+ - `CLB_MODEL_CHOICES` - optional comma-separated list of model aliases shown in
104
+ the `/model` inline keyboard.
105
+
106
+ ## Files
107
+
108
+ - `claude_telegram_bridge.py` - bridge daemon.
109
+ - `hooks/claude-telegram-bridge-session-start.sh` - records transcript and tmux
110
+ pane binding for the daemon.
111
+ - `hooks/claude-telegram-bridge-pretool-block.sh` - blocks Telegram MCP replies
112
+ during bridge-owned turns.
113
+ - `config.example.env` - local environment template.
114
+
115
+ ## Minimal Manual Setup
116
+
117
+ 1. Start Claude Code in tmux:
118
+
119
+ ```bash
120
+ tmux -L default new -s claude
121
+ claude --dangerously-skip-permissions
122
+ ```
123
+
124
+ 2. Create a Telegram bot with BotFather. Paste the bot token only into your
125
+ local terminal or local config file. Never send it in Telegram.
126
+
127
+ 3. Copy the example config:
128
+
129
+ ```bash
130
+ cp config.example.env .env
131
+ chmod 600 .env
132
+ ```
133
+
134
+ 4. Edit `.env` and set:
135
+
136
+ ```bash
137
+ CLB_TOKEN_FILE="$HOME/.config/claude-telegram-bridge/token.json"
138
+ CLB_CHAT_ID="123456789"
139
+ CLB_TOKEN_REGISTRY="$HOME/.config/claude-telegram-bridge/token-registry.json"
140
+ CLB_STATE_DIR="$HOME/.local/state/claude-telegram-bridge"
141
+ ```
142
+
143
+ 5. Store the token locally:
144
+
145
+ ```bash
146
+ mkdir -p "$HOME/.config/claude-telegram-bridge"
147
+ printf '{"token":"%s"}\n' 'PASTE_BOTFATHER_TOKEN_HERE' \
148
+ > "$HOME/.config/claude-telegram-bridge/token.json"
149
+ chmod 600 "$HOME/.config/claude-telegram-bridge/token.json"
150
+ ```
151
+
152
+ 6. Create a token registry entry. The `token_id` is the first 16 hex chars of
153
+ the SHA-256 of the token.
154
+
155
+ ```bash
156
+ python3 - <<'PY'
157
+ import hashlib, json, pathlib
158
+ root = pathlib.Path.home() / ".config/claude-telegram-bridge"
159
+ token = json.loads((root / "token.json").read_text())["token"]
160
+ token_id = hashlib.sha256(token.encode()).hexdigest()[:16]
161
+ (root / "token-registry.json").write_text(json.dumps({
162
+ "tokens": {
163
+ "default": {
164
+ "token_id": token_id,
165
+ "mode": "polling",
166
+ "owner": "claude-telegram-bridge",
167
+ "expected_consumer": "claude",
168
+ "allow_delete_webhook": False
169
+ }
170
+ }
171
+ }, indent=2) + "\n")
172
+ PY
173
+ ```
174
+
175
+ 7. Register the SessionStart hook in Claude Code settings. The exact settings
176
+ file location depends on your Claude Code install.
177
+
178
+ ```json
179
+ {
180
+ "hooks": {
181
+ "SessionStart": [
182
+ {
183
+ "hooks": [
184
+ {
185
+ "type": "command",
186
+ "command": "/absolute/path/to/hooks/claude-telegram-bridge-session-start.sh"
187
+ }
188
+ ]
189
+ }
190
+ ]
191
+ }
192
+ }
193
+ ```
194
+
195
+ 8. Run the daemon:
196
+
197
+ ```bash
198
+ set -a
199
+ . ./.env
200
+ set +a
201
+ python3 claude_telegram_bridge.py
202
+ ```
203
+
204
+ Send `/ping` to the bot, then send a normal prompt.
205
+
206
+ ## Safety Defaults
207
+
208
+ - Polling only; no public webhook is required.
209
+ - One allowed Telegram chat id.
210
+ - Token ownership registry must match the local token before polling starts.
211
+ - Interactive slash commands that could open a blocking dialog are held back by
212
+ a freeze guard rather than pasted raw; a set of read-only and safe commands is
213
+ supported and mirrored. See [Slash Commands](#slash-commands) for the full set
214
+ and the `!` escape hatch.
215
+ - The PreToolUse egress guard is included for users who also have Telegram MCP
216
+ reply tools installed.
217
+ - Outgoing media auto-send is not part of this minimal export.
218
+
219
+ ## Optional Settings
220
+
221
+ - `CLB_FLOW_MIRROR_FLAG` - path to a flag file that enables the flow mirror.
222
+ When the file exists, the bridge mirrors each tool-use step of the current
223
+ turn to Telegram as one live-updating card. Off by default (no file). Enable
224
+ with `touch "$HOME/.config/claude-telegram-bridge/flow-mirror.on"` and disable
225
+ by removing the file.
226
+ - `CLB_ACTIVE_TURN_STALE_SECONDS` - releases a previously observed Telegram turn
227
+ when Claude is idle but no final reply was captured, so later queued messages
228
+ can continue instead of being blocked behind a stale active turn. Defaults to
229
+ 900 seconds.
230
+
231
+ ### Advanced settings
232
+
233
+ The bridge reads ~20 more tuning knobs (self-update via `CLB_AUTO_UPDATE` /
234
+ `CLB_NO_UPDATE_CHECK`, send-retry policy, durable queue/outbox paths, session
235
+ binding TTLs, an optional `CLB_WATCHDOG_SCRIPT` lifecycle hook, and more). All
236
+ of them ship with safe defaults; the full annotated list lives at the bottom
237
+ of `config.example.env`.
238
+
239
+ ## Release Checklist
240
+
241
+ See `RELEASE_CHECKLIST.md` before publishing a fork or release.