untether 0.22.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.
- untether-0.22.1/LICENSE +23 -0
- untether-0.22.1/PKG-INFO +267 -0
- untether-0.22.1/README.md +200 -0
- untether-0.22.1/pyproject.toml +112 -0
- untether-0.22.1/src/untether/__init__.py +3 -0
- untether-0.22.1/src/untether/api.py +116 -0
- untether-0.22.1/src/untether/backends.py +25 -0
- untether-0.22.1/src/untether/backends_helpers.py +14 -0
- untether-0.22.1/src/untether/cli/__init__.py +189 -0
- untether-0.22.1/src/untether/cli/config.py +320 -0
- untether-0.22.1/src/untether/cli/doctor.py +173 -0
- untether-0.22.1/src/untether/cli/init.py +113 -0
- untether-0.22.1/src/untether/cli/onboarding_cmd.py +126 -0
- untether-0.22.1/src/untether/cli/plugins.py +196 -0
- untether-0.22.1/src/untether/cli/run.py +419 -0
- untether-0.22.1/src/untether/commands.py +135 -0
- untether-0.22.1/src/untether/config.py +144 -0
- untether-0.22.1/src/untether/config_migrations.py +124 -0
- untether-0.22.1/src/untether/config_watch.py +146 -0
- untether-0.22.1/src/untether/context.py +9 -0
- untether-0.22.1/src/untether/cost_tracker.py +110 -0
- untether-0.22.1/src/untether/directives.py +146 -0
- untether-0.22.1/src/untether/engines.py +53 -0
- untether-0.22.1/src/untether/events.py +170 -0
- untether-0.22.1/src/untether/ids.py +17 -0
- untether-0.22.1/src/untether/lockfile.py +158 -0
- untether-0.22.1/src/untether/logging.py +283 -0
- untether-0.22.1/src/untether/markdown.py +298 -0
- untether-0.22.1/src/untether/model.py +77 -0
- untether-0.22.1/src/untether/plugins.py +312 -0
- untether-0.22.1/src/untether/presenter.py +25 -0
- untether-0.22.1/src/untether/progress.py +99 -0
- untether-0.22.1/src/untether/router.py +113 -0
- untether-0.22.1/src/untether/runner.py +712 -0
- untether-0.22.1/src/untether/runner_bridge.py +919 -0
- untether-0.22.1/src/untether/runners/__init__.py +1 -0
- untether-0.22.1/src/untether/runners/claude.py +1539 -0
- untether-0.22.1/src/untether/runners/codex.py +705 -0
- untether-0.22.1/src/untether/runners/mock.py +221 -0
- untether-0.22.1/src/untether/runners/opencode.py +517 -0
- untether-0.22.1/src/untether/runners/pi.py +540 -0
- untether-0.22.1/src/untether/runners/run_options.py +39 -0
- untether-0.22.1/src/untether/runners/tool_actions.py +90 -0
- untether-0.22.1/src/untether/runtime_loader.py +207 -0
- untether-0.22.1/src/untether/scheduler.py +159 -0
- untether-0.22.1/src/untether/schemas/__init__.py +1 -0
- untether-0.22.1/src/untether/schemas/claude.py +238 -0
- untether-0.22.1/src/untether/schemas/codex.py +251 -0
- untether-0.22.1/src/untether/schemas/opencode.py +51 -0
- untether-0.22.1/src/untether/schemas/pi.py +117 -0
- untether-0.22.1/src/untether/settings.py +402 -0
- untether-0.22.1/src/untether/shutdown.py +38 -0
- untether-0.22.1/src/untether/telegram/__init__.py +20 -0
- untether-0.22.1/src/untether/telegram/api_models.py +37 -0
- untether-0.22.1/src/untether/telegram/api_schemas.py +152 -0
- untether-0.22.1/src/untether/telegram/backend.py +184 -0
- untether-0.22.1/src/untether/telegram/bridge.py +445 -0
- untether-0.22.1/src/untether/telegram/chat_prefs.py +257 -0
- untether-0.22.1/src/untether/telegram/chat_sessions.py +133 -0
- untether-0.22.1/src/untether/telegram/client.py +409 -0
- untether-0.22.1/src/untether/telegram/client_api.py +539 -0
- untether-0.22.1/src/untether/telegram/commands/__init__.py +12 -0
- untether-0.22.1/src/untether/telegram/commands/agent.py +205 -0
- untether-0.22.1/src/untether/telegram/commands/browse.py +311 -0
- untether-0.22.1/src/untether/telegram/commands/cancel.py +116 -0
- untether-0.22.1/src/untether/telegram/commands/claude_control.py +171 -0
- untether-0.22.1/src/untether/telegram/commands/dispatch.py +235 -0
- untether-0.22.1/src/untether/telegram/commands/executor.py +457 -0
- untether-0.22.1/src/untether/telegram/commands/export.py +177 -0
- untether-0.22.1/src/untether/telegram/commands/file_transfer.py +586 -0
- untether-0.22.1/src/untether/telegram/commands/handlers.py +49 -0
- untether-0.22.1/src/untether/telegram/commands/media.py +143 -0
- untether-0.22.1/src/untether/telegram/commands/menu.py +139 -0
- untether-0.22.1/src/untether/telegram/commands/model.py +222 -0
- untether-0.22.1/src/untether/telegram/commands/overrides.py +159 -0
- untether-0.22.1/src/untether/telegram/commands/parse.py +30 -0
- untether-0.22.1/src/untether/telegram/commands/ping.py +39 -0
- untether-0.22.1/src/untether/telegram/commands/plan.py +16 -0
- untether-0.22.1/src/untether/telegram/commands/planmode.py +103 -0
- untether-0.22.1/src/untether/telegram/commands/reasoning.py +249 -0
- untether-0.22.1/src/untether/telegram/commands/reply.py +23 -0
- untether-0.22.1/src/untether/telegram/commands/restart.py +29 -0
- untether-0.22.1/src/untether/telegram/commands/topics.py +332 -0
- untether-0.22.1/src/untether/telegram/commands/trigger.py +148 -0
- untether-0.22.1/src/untether/telegram/commands/usage.py +194 -0
- untether-0.22.1/src/untether/telegram/context.py +140 -0
- untether-0.22.1/src/untether/telegram/engine_defaults.py +86 -0
- untether-0.22.1/src/untether/telegram/engine_overrides.py +118 -0
- untether-0.22.1/src/untether/telegram/files.py +178 -0
- untether-0.22.1/src/untether/telegram/loop.py +2035 -0
- untether-0.22.1/src/untether/telegram/onboarding.py +1090 -0
- untether-0.22.1/src/untether/telegram/outbox.py +225 -0
- untether-0.22.1/src/untether/telegram/parsing.py +245 -0
- untether-0.22.1/src/untether/telegram/render.py +247 -0
- untether-0.22.1/src/untether/telegram/state_store.py +88 -0
- untether-0.22.1/src/untether/telegram/topic_state.py +334 -0
- untether-0.22.1/src/untether/telegram/topics.py +256 -0
- untether-0.22.1/src/untether/telegram/trigger_mode.py +68 -0
- untether-0.22.1/src/untether/telegram/types.py +65 -0
- untether-0.22.1/src/untether/telegram/voice.py +110 -0
- untether-0.22.1/src/untether/transport.py +53 -0
- untether-0.22.1/src/untether/transport_runtime.py +319 -0
- untether-0.22.1/src/untether/transports.py +76 -0
- untether-0.22.1/src/untether/triggers/__init__.py +7 -0
- untether-0.22.1/src/untether/triggers/auth.py +68 -0
- untether-0.22.1/src/untether/triggers/cron.py +93 -0
- untether-0.22.1/src/untether/triggers/dispatcher.py +85 -0
- untether-0.22.1/src/untether/triggers/rate_limit.py +29 -0
- untether-0.22.1/src/untether/triggers/server.py +143 -0
- untether-0.22.1/src/untether/triggers/settings.py +110 -0
- untether-0.22.1/src/untether/triggers/templating.py +44 -0
- untether-0.22.1/src/untether/utils/__init__.py +1 -0
- untether-0.22.1/src/untether/utils/git.py +87 -0
- untether-0.22.1/src/untether/utils/json_state.py +21 -0
- untether-0.22.1/src/untether/utils/paths.py +49 -0
- untether-0.22.1/src/untether/utils/streams.py +44 -0
- untether-0.22.1/src/untether/utils/subprocess.py +86 -0
- untether-0.22.1/src/untether/worktrees.py +135 -0
untether-0.22.1/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 banteg
|
|
4
|
+
Copyright (c) 2025-2026 Little Bear Apps and contributors
|
|
5
|
+
Copyright (c) 2025-2026 Nathan Schram and contributors
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
untether-0.22.1/PKG-INFO
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: untether
|
|
3
|
+
Version: 0.22.1
|
|
4
|
+
Summary: Telegram bridge for Claude Code, Codex, and other agent CLIs. Fork of takopi with interactive permission control.
|
|
5
|
+
Keywords: telegram,claude-code,codex,opencode,ai-agents,coding-assistant,remote-control,cli-bridge
|
|
6
|
+
Author: Nathan Schram, banteg (upstream takopi)
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2025 banteg
|
|
10
|
+
Copyright (c) 2025-2026 Little Bear Apps and contributors
|
|
11
|
+
Copyright (c) 2025-2026 Nathan Schram and contributors
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
Classifier: Development Status :: 4 - Beta
|
|
31
|
+
Classifier: Environment :: Console
|
|
32
|
+
Classifier: Framework :: AsyncIO
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
41
|
+
Classifier: Topic :: Communications :: Chat
|
|
42
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
43
|
+
Classifier: Typing :: Typed
|
|
44
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
45
|
+
Requires-Dist: anyio>=4.12.0
|
|
46
|
+
Requires-Dist: httpx>=0.28.1
|
|
47
|
+
Requires-Dist: markdown-it-py
|
|
48
|
+
Requires-Dist: msgspec>=0.20.0
|
|
49
|
+
Requires-Dist: openai>=2.15.0
|
|
50
|
+
Requires-Dist: pydantic>=2.12.5
|
|
51
|
+
Requires-Dist: pydantic-settings>=2.12.0
|
|
52
|
+
Requires-Dist: questionary>=2.1.1
|
|
53
|
+
Requires-Dist: rich>=14.2.0
|
|
54
|
+
Requires-Dist: structlog>=25.5.0
|
|
55
|
+
Requires-Dist: sulguk>=0.11.1
|
|
56
|
+
Requires-Dist: tomli-w>=1.2.0
|
|
57
|
+
Requires-Dist: typer>=0.21.0
|
|
58
|
+
Requires-Dist: watchfiles>=0.21.0
|
|
59
|
+
Requires-Python: >=3.12
|
|
60
|
+
Project-URL: Changelog, https://untether.cc/reference/changelog/
|
|
61
|
+
Project-URL: Documentation, https://untether.cc/
|
|
62
|
+
Project-URL: Homepage, https://github.com/littlebearapps/untether
|
|
63
|
+
Project-URL: Issues, https://github.com/littlebearapps/untether/issues
|
|
64
|
+
Project-URL: Repository, https://github.com/littlebearapps/untether
|
|
65
|
+
Project-URL: Upstream, https://github.com/banteg/takopi
|
|
66
|
+
Description-Content-Type: text/markdown
|
|
67
|
+
|
|
68
|
+
<p align="center">
|
|
69
|
+
<img src="docs/assets/logo.svg" alt="Untether" width="120" />
|
|
70
|
+
</p>
|
|
71
|
+
|
|
72
|
+
<h1 align="center">Untether</h1>
|
|
73
|
+
|
|
74
|
+
<p align="center">
|
|
75
|
+
<strong>Control your AI coding agents from Telegram.</strong><br>
|
|
76
|
+
Stream progress, approve actions, manage projects — from anywhere.
|
|
77
|
+
</p>
|
|
78
|
+
|
|
79
|
+
<p align="center">
|
|
80
|
+
<a href="https://github.com/littlebearapps/untether/actions/workflows/ci.yml"><img src="https://github.com/littlebearapps/untether/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
81
|
+
<a href="https://pypi.org/project/untether/"><img src="https://img.shields.io/pypi/v/untether" alt="PyPI" /></a>
|
|
82
|
+
<a href="https://pypi.org/project/untether/"><img src="https://img.shields.io/pypi/pyversions/untether" alt="Python" /></a>
|
|
83
|
+
<a href="https://github.com/littlebearapps/untether/blob/master/LICENSE"><img src="https://img.shields.io/github/license/littlebearapps/untether" alt="License" /></a>
|
|
84
|
+
</p>
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
Untether is a Telegram bridge for AI coding agents. It connects [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex](https://github.com/openai/codex), [OpenCode](https://github.com/opencode-ai/opencode), and [Pi](https://github.com/nicholasgasior/pi) to Telegram so you can send coding tasks, watch progress live, and approve actions — all from your phone.
|
|
89
|
+
|
|
90
|
+
Walk the dog, watch the footy, sit at a friend's place. Your agents keep working. You stay in control.
|
|
91
|
+
|
|
92
|
+
## Quick start
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
uv tool install -U untether # install
|
|
96
|
+
untether # run setup wizard
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The wizard creates a Telegram bot, picks your workflow, and connects your chat. Then send a message to your bot:
|
|
100
|
+
|
|
101
|
+
> fix the failing tests in src/auth
|
|
102
|
+
|
|
103
|
+
That's it. Your agent runs on your machine, streams progress to Telegram, and you can reply to continue the conversation.
|
|
104
|
+
|
|
105
|
+
## Why Untether?
|
|
106
|
+
|
|
107
|
+
| Problem | Untether's solution |
|
|
108
|
+
|---------|-------------------|
|
|
109
|
+
| You have to sit at your desk while agents work | Stream progress to Telegram — watch from anywhere |
|
|
110
|
+
| Agents need permission to run tools | Approve or deny actions with inline buttons on your phone |
|
|
111
|
+
| You switch between Claude, Codex, and other agents | One bot, multiple engines — switch with `/claude`, `/codex`, `/opencode`, or `/pi` |
|
|
112
|
+
| Managing multiple repos from chat is messy | Register projects, target them with `/myproject`, branch with `@feat/thing` |
|
|
113
|
+
| No cost visibility | Per-run and daily cost tracking with configurable budgets |
|
|
114
|
+
| Can't continue terminal sessions remotely | Stateless resume — pick up any session in chat or terminal |
|
|
115
|
+
|
|
116
|
+
## Supported engines
|
|
117
|
+
|
|
118
|
+
| Engine | Install | What it's good at |
|
|
119
|
+
|--------|---------|-------------------|
|
|
120
|
+
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `npm i -g @anthropic-ai/claude-code` | Complex refactors, architecture, long context |
|
|
121
|
+
| [Codex](https://github.com/openai/codex) | `npm i -g @openai/codex` | Fast edits, shell commands, quick fixes |
|
|
122
|
+
| [OpenCode](https://github.com/opencode-ai/opencode) | `npm i -g opencode-ai@latest` | 75+ providers via Models.dev, local models |
|
|
123
|
+
| [Pi](https://github.com/mariozechner/pi-coding-agent) | `npm i -g @mariozechner/pi-coding-agent` | Multi-provider auth, conversational |
|
|
124
|
+
|
|
125
|
+
Use your existing Claude or ChatGPT subscription — no extra API keys needed (unless you want API billing).
|
|
126
|
+
|
|
127
|
+
## Features
|
|
128
|
+
|
|
129
|
+
### Progress streaming
|
|
130
|
+
|
|
131
|
+
Watch your agent work in real time. See tool calls, file changes, and elapsed time as they happen.
|
|
132
|
+
|
|
133
|
+
### Interactive permissions (Claude Code)
|
|
134
|
+
|
|
135
|
+
When Claude Code needs to run a tool, Untether shows **Approve / Deny / Pause & Outline Plan** buttons in Telegram. Routine tools (Read, Grep, Glob) are auto-approved. Dangerous operations require your explicit approval with a diff preview.
|
|
136
|
+
|
|
137
|
+
### Plan mode
|
|
138
|
+
|
|
139
|
+
Toggle plan mode per chat with `/planmode`. Claude outlines its approach before making changes. Choose between:
|
|
140
|
+
|
|
141
|
+
- **on** — full plan mode with manual approval
|
|
142
|
+
- **auto** — plan mode with auto-approved transitions
|
|
143
|
+
- **off** — no plan phase
|
|
144
|
+
|
|
145
|
+
### Projects and worktrees
|
|
146
|
+
|
|
147
|
+
Register repos with `untether init myproject`, then target them from chat:
|
|
148
|
+
|
|
149
|
+
> /myproject @feat/new-api add the endpoint
|
|
150
|
+
|
|
151
|
+
Each branch runs in an isolated git worktree. Multiple projects and branches can run in parallel.
|
|
152
|
+
|
|
153
|
+
### Cost and usage tracking
|
|
154
|
+
|
|
155
|
+
```toml
|
|
156
|
+
[footer]
|
|
157
|
+
show_api_cost = false # hide API cost line (default: true)
|
|
158
|
+
show_subscription_usage = true # show 5h/weekly window usage (default: false)
|
|
159
|
+
|
|
160
|
+
[cost_budget]
|
|
161
|
+
enabled = true
|
|
162
|
+
max_cost_per_run = 2.00
|
|
163
|
+
max_cost_per_day = 10.00
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
See subscription usage or API costs in the progress footer. Use `/usage` for a detailed breakdown. Budget alerts fire at configurable thresholds, and can optionally auto-cancel runs.
|
|
167
|
+
|
|
168
|
+
### Conversation modes
|
|
169
|
+
|
|
170
|
+
| Mode | Best for | How it works |
|
|
171
|
+
|------|----------|-------------|
|
|
172
|
+
| **Assistant** | Day-to-day use | Ongoing chat with auto-resume. `/new` to start fresh. |
|
|
173
|
+
| **Workspace** | Teams and multi-project | Forum topics bound to repos and branches. |
|
|
174
|
+
| **Handoff** | Terminal-first workflow | Reply-to-continue with resume lines you can paste into terminal. |
|
|
175
|
+
|
|
176
|
+
### More features
|
|
177
|
+
|
|
178
|
+
- **Voice notes** — dictate tasks, Untether transcribes and sends to the agent
|
|
179
|
+
- **File transfer** — upload files to your repo or download results back
|
|
180
|
+
- **Scheduled tasks** — cron expressions and webhook triggers
|
|
181
|
+
- **Forum topics** — map Telegram topics to projects and branches
|
|
182
|
+
- **Session export** — `/export` for markdown or JSON transcripts
|
|
183
|
+
- **File browser** — `/browse` to navigate project files with inline buttons
|
|
184
|
+
- **Plugin system** — extend with custom engines, transports, and commands
|
|
185
|
+
|
|
186
|
+
## Commands
|
|
187
|
+
|
|
188
|
+
| Command | What it does |
|
|
189
|
+
|---------|-------------|
|
|
190
|
+
| `/cancel` | Stop the running agent |
|
|
191
|
+
| `/agent` | Show or set the engine for this chat |
|
|
192
|
+
| `/model` | Override the model for an engine |
|
|
193
|
+
| `/planmode` | Toggle plan mode (on/auto/off) |
|
|
194
|
+
| `/usage` | Show API costs for the current session |
|
|
195
|
+
| `/export` | Export session transcript |
|
|
196
|
+
| `/browse` | Browse project files |
|
|
197
|
+
| `/new` | Clear stored sessions |
|
|
198
|
+
| `/file put/get` | Transfer files |
|
|
199
|
+
| `/topic` | Create or bind forum topics |
|
|
200
|
+
| `/restart` | Gracefully restart Untether (drains active runs first) |
|
|
201
|
+
|
|
202
|
+
Prefix any message with `/<engine>` to pick an engine for that task, or `/<project>` to target a repo:
|
|
203
|
+
|
|
204
|
+
> /claude /myproject @feat/auth implement OAuth2
|
|
205
|
+
|
|
206
|
+
## Configuration
|
|
207
|
+
|
|
208
|
+
Untether reads `~/.untether/untether.toml`. The setup wizard creates this for you, or configure manually:
|
|
209
|
+
|
|
210
|
+
```toml
|
|
211
|
+
default_engine = "codex"
|
|
212
|
+
|
|
213
|
+
[transports.telegram]
|
|
214
|
+
bot_token = "123456789:ABC..."
|
|
215
|
+
chat_id = 123456789
|
|
216
|
+
session_mode = "chat"
|
|
217
|
+
|
|
218
|
+
[projects.myapp]
|
|
219
|
+
path = "~/dev/myapp"
|
|
220
|
+
default_engine = "claude"
|
|
221
|
+
|
|
222
|
+
[cost_budget]
|
|
223
|
+
enabled = true
|
|
224
|
+
max_cost_per_run = 2.00
|
|
225
|
+
max_cost_per_day = 10.00
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
See the [full configuration reference](https://untether.cc/reference/config/) for all options.
|
|
229
|
+
|
|
230
|
+
## Requirements
|
|
231
|
+
|
|
232
|
+
- **Python 3.12+** — `uv python install 3.14`
|
|
233
|
+
- **uv** — `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
|
234
|
+
- At least one agent CLI on PATH: `codex`, `claude`, `opencode`, or `pi`
|
|
235
|
+
|
|
236
|
+
## Engine guides
|
|
237
|
+
|
|
238
|
+
Detailed setup and usage for each engine:
|
|
239
|
+
|
|
240
|
+
- [Claude Code guide](https://untether.cc/reference/runners/claude/runner/) — permission modes, plan mode, cost tracking, interactive approvals
|
|
241
|
+
- [Codex guide](https://untether.cc/reference/runners/codex/exec-json-cheatsheet/) — profiles, extra args, exec mode
|
|
242
|
+
- [OpenCode guide](https://untether.cc/reference/runners/opencode/runner/) — model selection, 75+ providers, local models
|
|
243
|
+
- [Pi guide](https://untether.cc/reference/runners/pi/runner/) — multi-provider auth, model and provider selection
|
|
244
|
+
- [Configuration reference](https://untether.cc/reference/config/) — full walkthrough of `untether.toml`
|
|
245
|
+
- [Troubleshooting guide](https://untether.cc/how-to/troubleshooting/) — common issues and solutions
|
|
246
|
+
|
|
247
|
+
## Documentation
|
|
248
|
+
|
|
249
|
+
Full documentation is available at **[untether.cc](https://untether.cc/)**.
|
|
250
|
+
|
|
251
|
+
- [Install and onboard](https://untether.cc/tutorials/install/) — setup wizard walkthrough
|
|
252
|
+
- [First run](https://untether.cc/tutorials/first-run/) — send your first task
|
|
253
|
+
- [Projects and branches](https://untether.cc/tutorials/projects-and-branches/) — multi-repo workflows
|
|
254
|
+
- [Multi-engine workflows](https://untether.cc/tutorials/multi-engine/) — switching between agents
|
|
255
|
+
- [Architecture](https://untether.cc/explanation/architecture/) — how the pieces fit together
|
|
256
|
+
|
|
257
|
+
## Contributing
|
|
258
|
+
|
|
259
|
+
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and guidelines.
|
|
260
|
+
|
|
261
|
+
## Acknowledgements
|
|
262
|
+
|
|
263
|
+
Untether is a fork of [takopi](https://github.com/banteg/takopi) by [@banteg](https://github.com/banteg), which provided the original Telegram-to-Codex bridge. Untether extends it with interactive permission control, multi-engine support, plan mode, cost tracking, and many other features.
|
|
264
|
+
|
|
265
|
+
## Licence
|
|
266
|
+
|
|
267
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/logo.svg" alt="Untether" width="120" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Untether</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Control your AI coding agents from Telegram.</strong><br>
|
|
9
|
+
Stream progress, approve actions, manage projects — from anywhere.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://github.com/littlebearapps/untether/actions/workflows/ci.yml"><img src="https://github.com/littlebearapps/untether/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
14
|
+
<a href="https://pypi.org/project/untether/"><img src="https://img.shields.io/pypi/v/untether" alt="PyPI" /></a>
|
|
15
|
+
<a href="https://pypi.org/project/untether/"><img src="https://img.shields.io/pypi/pyversions/untether" alt="Python" /></a>
|
|
16
|
+
<a href="https://github.com/littlebearapps/untether/blob/master/LICENSE"><img src="https://img.shields.io/github/license/littlebearapps/untether" alt="License" /></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Untether is a Telegram bridge for AI coding agents. It connects [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex](https://github.com/openai/codex), [OpenCode](https://github.com/opencode-ai/opencode), and [Pi](https://github.com/nicholasgasior/pi) to Telegram so you can send coding tasks, watch progress live, and approve actions — all from your phone.
|
|
22
|
+
|
|
23
|
+
Walk the dog, watch the footy, sit at a friend's place. Your agents keep working. You stay in control.
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
uv tool install -U untether # install
|
|
29
|
+
untether # run setup wizard
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The wizard creates a Telegram bot, picks your workflow, and connects your chat. Then send a message to your bot:
|
|
33
|
+
|
|
34
|
+
> fix the failing tests in src/auth
|
|
35
|
+
|
|
36
|
+
That's it. Your agent runs on your machine, streams progress to Telegram, and you can reply to continue the conversation.
|
|
37
|
+
|
|
38
|
+
## Why Untether?
|
|
39
|
+
|
|
40
|
+
| Problem | Untether's solution |
|
|
41
|
+
|---------|-------------------|
|
|
42
|
+
| You have to sit at your desk while agents work | Stream progress to Telegram — watch from anywhere |
|
|
43
|
+
| Agents need permission to run tools | Approve or deny actions with inline buttons on your phone |
|
|
44
|
+
| You switch between Claude, Codex, and other agents | One bot, multiple engines — switch with `/claude`, `/codex`, `/opencode`, or `/pi` |
|
|
45
|
+
| Managing multiple repos from chat is messy | Register projects, target them with `/myproject`, branch with `@feat/thing` |
|
|
46
|
+
| No cost visibility | Per-run and daily cost tracking with configurable budgets |
|
|
47
|
+
| Can't continue terminal sessions remotely | Stateless resume — pick up any session in chat or terminal |
|
|
48
|
+
|
|
49
|
+
## Supported engines
|
|
50
|
+
|
|
51
|
+
| Engine | Install | What it's good at |
|
|
52
|
+
|--------|---------|-------------------|
|
|
53
|
+
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `npm i -g @anthropic-ai/claude-code` | Complex refactors, architecture, long context |
|
|
54
|
+
| [Codex](https://github.com/openai/codex) | `npm i -g @openai/codex` | Fast edits, shell commands, quick fixes |
|
|
55
|
+
| [OpenCode](https://github.com/opencode-ai/opencode) | `npm i -g opencode-ai@latest` | 75+ providers via Models.dev, local models |
|
|
56
|
+
| [Pi](https://github.com/mariozechner/pi-coding-agent) | `npm i -g @mariozechner/pi-coding-agent` | Multi-provider auth, conversational |
|
|
57
|
+
|
|
58
|
+
Use your existing Claude or ChatGPT subscription — no extra API keys needed (unless you want API billing).
|
|
59
|
+
|
|
60
|
+
## Features
|
|
61
|
+
|
|
62
|
+
### Progress streaming
|
|
63
|
+
|
|
64
|
+
Watch your agent work in real time. See tool calls, file changes, and elapsed time as they happen.
|
|
65
|
+
|
|
66
|
+
### Interactive permissions (Claude Code)
|
|
67
|
+
|
|
68
|
+
When Claude Code needs to run a tool, Untether shows **Approve / Deny / Pause & Outline Plan** buttons in Telegram. Routine tools (Read, Grep, Glob) are auto-approved. Dangerous operations require your explicit approval with a diff preview.
|
|
69
|
+
|
|
70
|
+
### Plan mode
|
|
71
|
+
|
|
72
|
+
Toggle plan mode per chat with `/planmode`. Claude outlines its approach before making changes. Choose between:
|
|
73
|
+
|
|
74
|
+
- **on** — full plan mode with manual approval
|
|
75
|
+
- **auto** — plan mode with auto-approved transitions
|
|
76
|
+
- **off** — no plan phase
|
|
77
|
+
|
|
78
|
+
### Projects and worktrees
|
|
79
|
+
|
|
80
|
+
Register repos with `untether init myproject`, then target them from chat:
|
|
81
|
+
|
|
82
|
+
> /myproject @feat/new-api add the endpoint
|
|
83
|
+
|
|
84
|
+
Each branch runs in an isolated git worktree. Multiple projects and branches can run in parallel.
|
|
85
|
+
|
|
86
|
+
### Cost and usage tracking
|
|
87
|
+
|
|
88
|
+
```toml
|
|
89
|
+
[footer]
|
|
90
|
+
show_api_cost = false # hide API cost line (default: true)
|
|
91
|
+
show_subscription_usage = true # show 5h/weekly window usage (default: false)
|
|
92
|
+
|
|
93
|
+
[cost_budget]
|
|
94
|
+
enabled = true
|
|
95
|
+
max_cost_per_run = 2.00
|
|
96
|
+
max_cost_per_day = 10.00
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
See subscription usage or API costs in the progress footer. Use `/usage` for a detailed breakdown. Budget alerts fire at configurable thresholds, and can optionally auto-cancel runs.
|
|
100
|
+
|
|
101
|
+
### Conversation modes
|
|
102
|
+
|
|
103
|
+
| Mode | Best for | How it works |
|
|
104
|
+
|------|----------|-------------|
|
|
105
|
+
| **Assistant** | Day-to-day use | Ongoing chat with auto-resume. `/new` to start fresh. |
|
|
106
|
+
| **Workspace** | Teams and multi-project | Forum topics bound to repos and branches. |
|
|
107
|
+
| **Handoff** | Terminal-first workflow | Reply-to-continue with resume lines you can paste into terminal. |
|
|
108
|
+
|
|
109
|
+
### More features
|
|
110
|
+
|
|
111
|
+
- **Voice notes** — dictate tasks, Untether transcribes and sends to the agent
|
|
112
|
+
- **File transfer** — upload files to your repo or download results back
|
|
113
|
+
- **Scheduled tasks** — cron expressions and webhook triggers
|
|
114
|
+
- **Forum topics** — map Telegram topics to projects and branches
|
|
115
|
+
- **Session export** — `/export` for markdown or JSON transcripts
|
|
116
|
+
- **File browser** — `/browse` to navigate project files with inline buttons
|
|
117
|
+
- **Plugin system** — extend with custom engines, transports, and commands
|
|
118
|
+
|
|
119
|
+
## Commands
|
|
120
|
+
|
|
121
|
+
| Command | What it does |
|
|
122
|
+
|---------|-------------|
|
|
123
|
+
| `/cancel` | Stop the running agent |
|
|
124
|
+
| `/agent` | Show or set the engine for this chat |
|
|
125
|
+
| `/model` | Override the model for an engine |
|
|
126
|
+
| `/planmode` | Toggle plan mode (on/auto/off) |
|
|
127
|
+
| `/usage` | Show API costs for the current session |
|
|
128
|
+
| `/export` | Export session transcript |
|
|
129
|
+
| `/browse` | Browse project files |
|
|
130
|
+
| `/new` | Clear stored sessions |
|
|
131
|
+
| `/file put/get` | Transfer files |
|
|
132
|
+
| `/topic` | Create or bind forum topics |
|
|
133
|
+
| `/restart` | Gracefully restart Untether (drains active runs first) |
|
|
134
|
+
|
|
135
|
+
Prefix any message with `/<engine>` to pick an engine for that task, or `/<project>` to target a repo:
|
|
136
|
+
|
|
137
|
+
> /claude /myproject @feat/auth implement OAuth2
|
|
138
|
+
|
|
139
|
+
## Configuration
|
|
140
|
+
|
|
141
|
+
Untether reads `~/.untether/untether.toml`. The setup wizard creates this for you, or configure manually:
|
|
142
|
+
|
|
143
|
+
```toml
|
|
144
|
+
default_engine = "codex"
|
|
145
|
+
|
|
146
|
+
[transports.telegram]
|
|
147
|
+
bot_token = "123456789:ABC..."
|
|
148
|
+
chat_id = 123456789
|
|
149
|
+
session_mode = "chat"
|
|
150
|
+
|
|
151
|
+
[projects.myapp]
|
|
152
|
+
path = "~/dev/myapp"
|
|
153
|
+
default_engine = "claude"
|
|
154
|
+
|
|
155
|
+
[cost_budget]
|
|
156
|
+
enabled = true
|
|
157
|
+
max_cost_per_run = 2.00
|
|
158
|
+
max_cost_per_day = 10.00
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
See the [full configuration reference](https://untether.cc/reference/config/) for all options.
|
|
162
|
+
|
|
163
|
+
## Requirements
|
|
164
|
+
|
|
165
|
+
- **Python 3.12+** — `uv python install 3.14`
|
|
166
|
+
- **uv** — `curl -LsSf https://astral.sh/uv/install.sh | sh`
|
|
167
|
+
- At least one agent CLI on PATH: `codex`, `claude`, `opencode`, or `pi`
|
|
168
|
+
|
|
169
|
+
## Engine guides
|
|
170
|
+
|
|
171
|
+
Detailed setup and usage for each engine:
|
|
172
|
+
|
|
173
|
+
- [Claude Code guide](https://untether.cc/reference/runners/claude/runner/) — permission modes, plan mode, cost tracking, interactive approvals
|
|
174
|
+
- [Codex guide](https://untether.cc/reference/runners/codex/exec-json-cheatsheet/) — profiles, extra args, exec mode
|
|
175
|
+
- [OpenCode guide](https://untether.cc/reference/runners/opencode/runner/) — model selection, 75+ providers, local models
|
|
176
|
+
- [Pi guide](https://untether.cc/reference/runners/pi/runner/) — multi-provider auth, model and provider selection
|
|
177
|
+
- [Configuration reference](https://untether.cc/reference/config/) — full walkthrough of `untether.toml`
|
|
178
|
+
- [Troubleshooting guide](https://untether.cc/how-to/troubleshooting/) — common issues and solutions
|
|
179
|
+
|
|
180
|
+
## Documentation
|
|
181
|
+
|
|
182
|
+
Full documentation is available at **[untether.cc](https://untether.cc/)**.
|
|
183
|
+
|
|
184
|
+
- [Install and onboard](https://untether.cc/tutorials/install/) — setup wizard walkthrough
|
|
185
|
+
- [First run](https://untether.cc/tutorials/first-run/) — send your first task
|
|
186
|
+
- [Projects and branches](https://untether.cc/tutorials/projects-and-branches/) — multi-repo workflows
|
|
187
|
+
- [Multi-engine workflows](https://untether.cc/tutorials/multi-engine/) — switching between agents
|
|
188
|
+
- [Architecture](https://untether.cc/explanation/architecture/) — how the pieces fit together
|
|
189
|
+
|
|
190
|
+
## Contributing
|
|
191
|
+
|
|
192
|
+
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and guidelines.
|
|
193
|
+
|
|
194
|
+
## Acknowledgements
|
|
195
|
+
|
|
196
|
+
Untether is a fork of [takopi](https://github.com/banteg/takopi) by [@banteg](https://github.com/banteg), which provided the original Telegram-to-Codex bridge. Untether extends it with interactive permission control, multi-engine support, plan mode, cost tracking, and many other features.
|
|
197
|
+
|
|
198
|
+
## Licence
|
|
199
|
+
|
|
200
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "untether"
|
|
3
|
+
authors = [{name = "Nathan Schram"}, {name = "banteg (upstream takopi)"}]
|
|
4
|
+
version = "0.22.1"
|
|
5
|
+
keywords = ["telegram", "claude-code", "codex", "opencode", "ai-agents", "coding-assistant", "remote-control", "cli-bridge"]
|
|
6
|
+
description = "Telegram bridge for Claude Code, Codex, and other agent CLIs. Fork of takopi with interactive permission control."
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
license = { file = "LICENSE" }
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"aiohttp>=3.9.0",
|
|
12
|
+
"anyio>=4.12.0",
|
|
13
|
+
"httpx>=0.28.1",
|
|
14
|
+
"markdown-it-py",
|
|
15
|
+
"msgspec>=0.20.0",
|
|
16
|
+
"openai>=2.15.0",
|
|
17
|
+
"pydantic>=2.12.5",
|
|
18
|
+
"pydantic-settings>=2.12.0",
|
|
19
|
+
"questionary>=2.1.1",
|
|
20
|
+
"rich>=14.2.0",
|
|
21
|
+
"structlog>=25.5.0",
|
|
22
|
+
"sulguk>=0.11.1",
|
|
23
|
+
"tomli-w>=1.2.0",
|
|
24
|
+
"typer>=0.21.0",
|
|
25
|
+
"watchfiles>=0.21.0",
|
|
26
|
+
]
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Development Status :: 4 - Beta",
|
|
29
|
+
"Environment :: Console",
|
|
30
|
+
"Framework :: AsyncIO",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"License :: OSI Approved :: MIT License",
|
|
33
|
+
"Operating System :: OS Independent",
|
|
34
|
+
"Programming Language :: Python :: 3",
|
|
35
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
36
|
+
"Programming Language :: Python :: 3.12",
|
|
37
|
+
"Programming Language :: Python :: 3.13",
|
|
38
|
+
"Programming Language :: Python :: 3.14",
|
|
39
|
+
"Topic :: Communications :: Chat",
|
|
40
|
+
"Topic :: Software Development :: Build Tools",
|
|
41
|
+
"Typing :: Typed",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/littlebearapps/untether"
|
|
46
|
+
Repository = "https://github.com/littlebearapps/untether"
|
|
47
|
+
Issues = "https://github.com/littlebearapps/untether/issues"
|
|
48
|
+
Documentation = "https://untether.cc/"
|
|
49
|
+
Changelog = "https://untether.cc/reference/changelog/"
|
|
50
|
+
Upstream = "https://github.com/banteg/takopi"
|
|
51
|
+
|
|
52
|
+
[project.scripts]
|
|
53
|
+
untether = "untether.cli:main"
|
|
54
|
+
|
|
55
|
+
[project.entry-points."untether.engine_backends"]
|
|
56
|
+
codex = "untether.runners.codex:BACKEND"
|
|
57
|
+
claude = "untether.runners.claude:BACKEND"
|
|
58
|
+
opencode = "untether.runners.opencode:BACKEND"
|
|
59
|
+
pi = "untether.runners.pi:BACKEND"
|
|
60
|
+
|
|
61
|
+
[project.entry-points."untether.transport_backends"]
|
|
62
|
+
telegram = "untether.telegram.backend:BACKEND"
|
|
63
|
+
|
|
64
|
+
[project.entry-points."untether.command_backends"]
|
|
65
|
+
claude_control = "untether.telegram.commands.claude_control:BACKEND"
|
|
66
|
+
usage = "untether.telegram.commands.usage:BACKEND"
|
|
67
|
+
planmode = "untether.telegram.commands.planmode:BACKEND"
|
|
68
|
+
ping = "untether.telegram.commands.ping:BACKEND"
|
|
69
|
+
export = "untether.telegram.commands.export:BACKEND"
|
|
70
|
+
browse = "untether.telegram.commands.browse:BACKEND"
|
|
71
|
+
restart = "untether.telegram.commands.restart:BACKEND"
|
|
72
|
+
|
|
73
|
+
[build-system]
|
|
74
|
+
requires = ["uv_build>=0.9.18,<0.10.0"]
|
|
75
|
+
build-backend = "uv_build"
|
|
76
|
+
|
|
77
|
+
[dependency-groups]
|
|
78
|
+
dev = [
|
|
79
|
+
"bandit>=1.8.0",
|
|
80
|
+
"mutmut>=3.4.0",
|
|
81
|
+
"pip-audit>=2.7.0",
|
|
82
|
+
"pytest>=9.0.2",
|
|
83
|
+
"pytest-anyio>=0.0.0",
|
|
84
|
+
"pytest-cov>=7.0.0",
|
|
85
|
+
"ruff>=0.14.10",
|
|
86
|
+
"ty>=0.0.8",
|
|
87
|
+
]
|
|
88
|
+
docs = [
|
|
89
|
+
"mkdocstrings-python>=2.0.1",
|
|
90
|
+
"zensical>=0.0.15",
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
[tool.pytest.ini_options]
|
|
94
|
+
addopts = ["--cov=untether", "--cov-branch", "--cov-report=term-missing", "--cov-fail-under=80"]
|
|
95
|
+
testpaths = ["tests"]
|
|
96
|
+
|
|
97
|
+
[tool.mutmut]
|
|
98
|
+
paths_to_mutate = ["src/untether"]
|
|
99
|
+
tests_dir = ["tests"]
|
|
100
|
+
pytest_add_cli_args = ["-q", "--no-cov"]
|
|
101
|
+
do_not_mutate = ["src/untether/cli/*"]
|
|
102
|
+
|
|
103
|
+
[tool.ruff.lint]
|
|
104
|
+
extend-select = ["B", "BLE001", "C4", "PERF", "RUF043", "S110", "SIM", "UP"]
|
|
105
|
+
|
|
106
|
+
[tool.bandit]
|
|
107
|
+
# Untether is a subprocess manager — these are expected patterns
|
|
108
|
+
skips = ["B101", "B105", "B404", "B603", "B607"]
|
|
109
|
+
|
|
110
|
+
[tool.ty.src]
|
|
111
|
+
include = ["src", "tests"]
|
|
112
|
+
exclude = ["scripts"]
|