From 95f1903d138b97cab7abc8fbe111d8531a359986 Mon Sep 17 00:00:00 2001 From: Nathan Schram <5553883+nathanschram@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:22:33 +0000 Subject: [PATCH 1/4] docs: replace 25 screenshot placeholders with styled markdown admonitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace text-reproducible screenshot placeholders across 14 doc files with styled admonitions using existing custom !!! untether (pink) and !!! user (green) types. Terminal output uses code blocks instead. This covers Phase 1 of the screenshot strategy — 25 of 47 placeholders replaced with maintainable markdown. The remaining 22 require actual Telegram UI captures (inline buttons, voice bubbles, file attachments). Co-Authored-By: Claude Opus 4.6 --- docs/how-to/chat-sessions.md | 13 ++++++++++- docs/how-to/cost-budgets.md | 12 ++++++++-- docs/how-to/dev-setup.md | 7 +++++- docs/how-to/projects.md | 4 +++- docs/how-to/route-by-chat.md | 11 +++++++++- docs/how-to/switch-engines.md | 7 +++++- docs/how-to/troubleshooting.md | 23 ++++++++++++++++++-- docs/how-to/verbose-progress.md | 2 -- docs/how-to/worktrees.md | 8 ++++++- docs/tutorials/first-run.md | 6 ----- docs/tutorials/install.md | 8 ++++--- docs/tutorials/interactive-control.md | 29 ++++++++++++++++++------- docs/tutorials/multi-engine.md | 2 -- docs/tutorials/projects-and-branches.md | 4 ---- 14 files changed, 101 insertions(+), 35 deletions(-) diff --git a/docs/how-to/chat-sessions.md b/docs/how-to/chat-sessions.md index b9dc48d..66a1b94 100644 --- a/docs/how-to/chat-sessions.md +++ b/docs/how-to/chat-sessions.md @@ -24,7 +24,18 @@ If you chose **handoff** during onboarding and want to switch to chat mode: With `session_mode = "chat"`, new messages in the chat continue the current thread automatically. - +!!! user "You" + explain the auth flow + +!!! untether "Untether" + done · claude · 15s · step 4 + + The auth flow uses JWT tokens… + +!!! user "You" + now add rate limiting to it + +The second message automatically continues the same session — no reply needed. ## Reset a session diff --git a/docs/how-to/cost-budgets.md b/docs/how-to/cost-budgets.md index 33e43d1..e8ac5c9 100644 --- a/docs/how-to/cost-budgets.md +++ b/docs/how-to/cost-budgets.md @@ -49,7 +49,8 @@ After each run completes, Untether checks the reported cost against your budgets When `auto_cancel = true` and a budget is exceeded, Untether cancels the run automatically. Otherwise, you see the alert but the run continues. - +!!! untether "Untether" + ⚠️ **cost warning** — run cost $1.45 is 73% of $2.00 per-run budget ### Daily reset @@ -72,7 +73,14 @@ This shows: The `/usage` command reads your Claude Code OAuth credentials to fetch live data from the Anthropic API. If you see "No Claude credentials found", run `claude login` in your terminal. - +!!! untether "Untether" + **Claude Code usage** + + **5h window**: 42% used (2h 6m left)
+ **Weekly**: 28% used (5d 2h left) + + sonnet: 38% · opus: 4%
+ extra credits: $0.00 ## Subscription usage footer diff --git a/docs/how-to/dev-setup.md b/docs/how-to/dev-setup.md index b49cb9f..3c470c9 100644 --- a/docs/how-to/dev-setup.md +++ b/docs/how-to/dev-setup.md @@ -57,7 +57,12 @@ uv run untether # Ctrl+C first if already running # 4. Test via @your_dev_bot in Telegram ``` - +``` +$ journalctl --user -u untether-dev -f +Mar 10 09:15:23 lba-1 untether[12345]: untether.started version=0.34.0 engine=codex projects=3 +Mar 10 09:15:23 lba-1 untether[12345]: telegram.connected bot=@untether_dev_bot +Mar 10 09:15:23 lba-1 untether[12345]: telegram.polling started +``` Always test via the dev bot before merging. Never send test messages to the production bot. diff --git a/docs/how-to/projects.md b/docs/how-to/projects.md index 0e25e38..ce86e11 100644 --- a/docs/how-to/projects.md +++ b/docs/how-to/projects.md @@ -9,7 +9,9 @@ cd ~/dev/happy-gadgets untether init happy-gadgets ``` - +``` +saved project 'happy-gadgets' to ~/.untether/untether.toml +``` This adds a project to your config: diff --git a/docs/how-to/route-by-chat.md b/docs/how-to/route-by-chat.md index 83cd455..6784348 100644 --- a/docs/how-to/route-by-chat.md +++ b/docs/how-to/route-by-chat.md @@ -29,7 +29,16 @@ Then send any message in the target chat. Untether captures the `chat_id` and up Messages from that chat now default to the project. - +!!! user "You" + fix the failing tests + +!!! untether "Untether" + done · codex · 8s · step 3 + + Fixed the two failing assertions in test_auth.py… + + dir: happy-gadgets
+ codex resume abc123 ## Rules for chat ids diff --git a/docs/how-to/switch-engines.md b/docs/how-to/switch-engines.md index 9354286..8d428d3 100644 --- a/docs/how-to/switch-engines.md +++ b/docs/how-to/switch-engines.md @@ -17,7 +17,12 @@ Prefix the first non-empty line with an engine directive: Directives are only parsed at the start of the first non-empty line. - +!!! untether "Untether" + working · codex · 5s · step 1 + + ✓ Read `src/timeline.py` + + `🏷 codex` ## Set a default engine for the current scope diff --git a/docs/how-to/troubleshooting.md b/docs/how-to/troubleshooting.md index cf28090..3c958a6 100644 --- a/docs/how-to/troubleshooting.md +++ b/docs/how-to/troubleshooting.md @@ -11,7 +11,16 @@ untether --debug # start with debug logging → writes debug.log untether doctor # preflight check: token, chat, topics, files, voice, engines ``` - +``` +$ untether doctor +✓ bot token valid (@my_untether_bot) +✓ chat 123456789 reachable +✓ engine codex found at /usr/local/bin/codex +✓ engine claude found at /usr/local/bin/claude +✗ engine opencode not found +✓ voice transcription configured +✓ file transfer directory exists +``` ## Bot not responding @@ -258,7 +267,17 @@ It validates: - Voice transcription configuration (API reachability) - Engine CLI availability (on PATH) - +``` +$ untether doctor +✓ bot token valid (@my_untether_bot) +✓ chat 123456789 reachable +✓ engine codex found at /usr/local/bin/codex +✓ engine claude found at /usr/local/bin/claude +✓ engine opencode found at /usr/local/bin/opencode +✓ voice transcription configured +✓ file transfer directory exists +all checks passed +``` ## Checking logs diff --git a/docs/how-to/verbose-progress.md b/docs/how-to/verbose-progress.md index 08a8ec0..986fa23 100644 --- a/docs/how-to/verbose-progress.md +++ b/docs/how-to/verbose-progress.md @@ -26,8 +26,6 @@ Compact mode shows only the action status and title — no extra detail. This is Here's the same action shown in both modes: - - !!! note "Compact" ``` ...tool: edit: Update import order diff --git a/docs/how-to/worktrees.md b/docs/how-to/worktrees.md index 4559660..560cd0e 100644 --- a/docs/how-to/worktrees.md +++ b/docs/how-to/worktrees.md @@ -31,7 +31,13 @@ Send a message like: /happy-gadgets @feat/memory-box freeze artifacts forever ``` - +!!! untether "Untether" + working · codex · 5s · step 2 + + ✓ Read `src/memory.py`
+ … Edit `src/memory.py` + + dir: happy-gadgets @feat/memory-box ## Ignore `.worktrees/` in git status diff --git a/docs/tutorials/first-run.md b/docs/tutorials/first-run.md index 6a8a711..1d9d82c 100644 --- a/docs/tutorials/first-run.md +++ b/docs/tutorials/first-run.md @@ -45,8 +45,6 @@ Untether immediately posts a progress message and updates it as the agent works: !!! untether "Untether" starting · codex · 0s - - As the agent calls tools and makes progress, you'll see updates like: !!! untether "Untether" @@ -60,8 +58,6 @@ The progress message is edited in-place. ## 4. See the final answer - - When the agent finishes, Untether sends a new message and replaces the progress message, so you get a notification. @@ -115,8 +111,6 @@ While the progress message is showing, tap the **cancel** button or reply to it !!! user "You" /cancel - - Untether sends `SIGTERM` to the agent process and posts a cancelled status: !!! failure "" diff --git a/docs/tutorials/install.md b/docs/tutorials/install.md index 8b6e969..85925e9 100644 --- a/docs/tutorials/install.md +++ b/docs/tutorials/install.md @@ -150,8 +150,6 @@ Untether validates the token by calling the Telegram API. If it fails, double-ch ## 7. Pick your workflow - - Untether shows three workflow previews: === "assistant" @@ -287,7 +285,11 @@ Press **y** or **Enter** to save. You'll see: Untether is now running and listening for messages! - +!!! untether "Untether" + 🐕 untether v0.34.0 is ready + + engine: `codex` · projects: `0`
+ working in: /Users/you/dev/your-project ## What just happened diff --git a/docs/tutorials/interactive-control.md b/docs/tutorials/interactive-control.md index ffc3c12..4e97286 100644 --- a/docs/tutorials/interactive-control.md +++ b/docs/tutorials/interactive-control.md @@ -27,7 +27,8 @@ Open your Telegram chat with the bot and send: /planmode on ``` - +!!! untether "Untether" + plan mode: **on** The bot confirms that plan mode is now active. This setting is stored per chat and persists across sessions. @@ -39,8 +40,6 @@ Send Claude Code a task that will require file changes: add a comment to the top of README.md explaining what this project does ``` - - Claude Code starts working and you'll see a progress message stream in. ## 4. See approval buttons @@ -61,7 +60,11 @@ Your phone will also buzz with a push notification so you don't miss it. Tap **Approve** to let Claude Code proceed with the action. The button clears instantly — no spinner, no waiting. Claude Code continues with its work. - +!!! untether "Untether" + working · claude · 8s · step 2 + + ✓ Read `README.md`
+ … Edit `README.md` You may see several approval requests in a row as Claude Code works through multiple steps. @@ -69,7 +72,8 @@ You may see several approval requests in a row as Claude Code works through mult If something doesn't look right, tap **Deny** instead. Claude Code receives a denial message explaining that you've blocked the action and asking it to communicate via visible text instead. - +!!! untether "Untether" + I was going to add a comment to the top of README.md with a project description. Would you prefer I explain what I had in mind first, or should I take a different approach? This is useful when you want Claude Code to explain its reasoning before making changes. After denying, Claude Code will typically describe what it was trying to do and ask for guidance. @@ -85,7 +89,14 @@ Tap it to require Claude Code to write a comprehensive plan as a visible message 4. Key decisions and trade-offs 5. The expected end result - +!!! untether "Untether" + Here's my plan: + + 1. **Read** `README.md` to understand current content + 2. **Edit** `README.md` to add a project description comment at line 1 + 3. **Verify** the comment is correctly formatted + + Files to modify: `README.md` After Claude Code writes the outline, **Approve Plan** and **Deny** buttons appear automatically — no need to type "approved": @@ -128,7 +139,8 @@ Once you're comfortable with how Claude Code works, you might want less interrup /planmode auto ``` - +!!! untether "Untether" + plan mode: **auto** In auto mode, tool calls (Edit, Write, Bash) are still auto-approved — Claude Code works without interruption. Plan transitions are also auto-approved, so you won't see ExitPlanMode buttons. The agent preamble still requests summaries and structured output. @@ -148,7 +160,8 @@ To check your current mode at any time: /planmode show ``` - +!!! untether "Untether" + plan mode: **on** (chat default) ## What just happened diff --git a/docs/tutorials/multi-engine.md b/docs/tutorials/multi-engine.md index de7b8ed..c889839 100644 --- a/docs/tutorials/multi-engine.md +++ b/docs/tutorials/multi-engine.md @@ -78,8 +78,6 @@ Check the current default: !!! user "You" /agent - - Example response: !!! untether "Untether" diff --git a/docs/tutorials/projects-and-branches.md b/docs/tutorials/projects-and-branches.md index 04a1240..669ff77 100644 --- a/docs/tutorials/projects-and-branches.md +++ b/docs/tutorials/projects-and-branches.md @@ -63,8 +63,6 @@ And target the project by prefixing your message: Untether runs the agent in `~/dev/happy-gadgets`, not your current directory. - - The response includes a context footer: !!! untether "Untether" @@ -115,8 +113,6 @@ Untether: 3. If the branch doesn't exist, it creates it from `worktree_base` (or the repo default) and adds the worktree 4. Runs the agent in that worktree - - The response shows both project and branch: !!! untether "Untether" From 986e1839586bd8a95e412f2c7a7de79023348485 Mon Sep 17 00:00:00 2001 From: Nathan Schram <5553883+nathanschram@users.noreply.github.com> Date: Tue, 10 Mar 2026 08:46:35 +0000 Subject: [PATCH 2/4] docs: replace 13 more screenshot placeholders with styled markdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2a: convert remaining text-reproducible placeholders to styled admonitions, code blocks, and formatted descriptions. Includes BotFather conversation flow, /browse file listing, /file put/get confirmations, diff preview, forum topic binding, webhook notification, and schedule picker instructions. 47 original placeholders → 38 replaced with markdown, 9 remain for actual Telegram UI screenshots (inline buttons + voice waveform). Co-Authored-By: Claude Opus 4.6 --- docs/how-to/browse-files.md | 8 +++++++- docs/how-to/file-transfer.md | 6 ++++-- docs/how-to/inline-settings.md | 2 -- docs/how-to/interactive-approval.md | 11 ++++++++++- docs/how-to/schedule-tasks.md | 3 ++- docs/how-to/topics.md | 5 ++++- docs/how-to/webhooks-and-cron.md | 7 ++++++- docs/tutorials/conversation-modes.md | 4 ---- docs/tutorials/install.md | 12 +++++++++++- docs/tutorials/interactive-control.md | 7 +++---- 10 files changed, 47 insertions(+), 18 deletions(-) diff --git a/docs/how-to/browse-files.md b/docs/how-to/browse-files.md index ca1d4a3..4f4a7e8 100644 --- a/docs/how-to/browse-files.md +++ b/docs/how-to/browse-files.md @@ -12,7 +12,13 @@ Send `/browse` to open the project root: Untether replies with a directory listing rendered as inline keyboard buttons. Each button is a file or directory you can tap. - +!!! untether "Untether" + **/ happy-gadgets** + + `📁 src/` · `📁 docs/` · `📁 tests/`
+ `📄 pyproject.toml` · `📄 README.md`
+ `📄 CHANGELOG.md` · `📄 .gitignore`
+ `(..)` back ## Navigate directories diff --git a/docs/how-to/file-transfer.md b/docs/how-to/file-transfer.md index f367fc3..c19923b 100644 --- a/docs/how-to/file-transfer.md +++ b/docs/how-to/file-transfer.md @@ -55,7 +55,8 @@ Use `--force` to overwrite: /file put --force docs/spec.pdf ``` - +!!! untether "Untether" + 📄 saved `docs/spec.pdf` (42 KB) ## Fetch a file (`/file get`) @@ -67,7 +68,8 @@ Send: Directories are zipped automatically. - +!!! untether "Untether" + 📎 `src/main.py` (1.2 KB) ## Related diff --git a/docs/how-to/inline-settings.md b/docs/how-to/inline-settings.md index cbe7ab4..5c630f1 100644 --- a/docs/how-to/inline-settings.md +++ b/docs/how-to/inline-settings.md @@ -12,8 +12,6 @@ Send `/config` in any chat: The home page shows current values for all settings: - - ``` Settings diff --git a/docs/how-to/interactive-approval.md b/docs/how-to/interactive-approval.md index b76dc21..f3312e6 100644 --- a/docs/how-to/interactive-approval.md +++ b/docs/how-to/interactive-approval.md @@ -37,7 +37,16 @@ For tools that modify files, the approval message includes a compact diff so you This lets you make informed approve/deny decisions without leaving Telegram. - +!!! untether "Untether" + **Edit** `src/main.py` + + ```diff + - import sys + + import sys + + from pathlib import Path + ``` + + `Approve` · `Deny` ## Answering questions diff --git a/docs/how-to/schedule-tasks.md b/docs/how-to/schedule-tasks.md index 7c7b57a..53e02b7 100644 --- a/docs/how-to/schedule-tasks.md +++ b/docs/how-to/schedule-tasks.md @@ -10,7 +10,8 @@ In Telegram, long-press the send button and choose **Schedule Message** to run t This is the simplest approach — no server or config changes needed. - +!!! tip "How to schedule" + In Telegram, **long-press the send button** (iOS) or tap the **clock icon** (Android/Desktop) and choose **Schedule Message**. Pick a date and time, then tap **Send**. Untether receives the message at the scheduled time and starts the run automatically. ## Cron triggers diff --git a/docs/how-to/topics.md b/docs/how-to/topics.md index 35f9726..bddf35d 100644 --- a/docs/how-to/topics.md +++ b/docs/how-to/topics.md @@ -64,7 +64,10 @@ Examples: Untether will bind the topic and rename it to match the context. - +!!! untether "Untether" + topic bound: **backend** @feat/api + + Topic renamed to `backend @feat/api` ## Inspect or change the binding diff --git a/docs/how-to/webhooks-and-cron.md b/docs/how-to/webhooks-and-cron.md index 63bc71a..672fb3b 100644 --- a/docs/how-to/webhooks-and-cron.md +++ b/docs/how-to/webhooks-and-cron.md @@ -85,7 +85,12 @@ curl -X POST http://127.0.0.1:9876/hooks/github \ A `202 Accepted` response means the run was dispatched. - +!!! untether "Untether" + 🔔 **webhook** · github-push + + Review push to refs/heads/main by alice + + working · claude · 4s · step 1 ## Set up a cron schedule diff --git a/docs/tutorials/conversation-modes.md b/docs/tutorials/conversation-modes.md index 4eb4e07..e43ecf1 100644 --- a/docs/tutorials/conversation-modes.md +++ b/docs/tutorials/conversation-modes.md @@ -14,8 +14,6 @@ This page explains what those settings mean and how to change them. ## Chat mode (auto-resume) - - **What it feels like:** a normal chat assistant. !!! user "You" @@ -44,8 +42,6 @@ Tip: set a default engine for this chat with `/agent set claude`. ## Stateless (reply-to-continue) - - **What it feels like:** every message is independent until you reply. !!! user "You" diff --git a/docs/tutorials/install.md b/docs/tutorials/install.md index 85925e9..f1b77fc 100644 --- a/docs/tutorials/install.md +++ b/docs/tutorials/install.md @@ -114,7 +114,17 @@ If you answered **n**, follow these steps (or skip to step 6 if you already have 3. Choose a display name (the obvious choice is "untether") 4. Choose a username ending in `bot` (e.g., `my_untether_bot`) - +!!! user "You" + /newbot + +!!! untether "BotFather" + Alright, a new bot. How are we going to call it? Please choose a name for your bot. + +!!! user "You" + untether + +!!! untether "BotFather" + Good. Now let's choose a username for your bot... BotFather will congratulate you on your new bot and will reply with your token: diff --git a/docs/tutorials/interactive-control.md b/docs/tutorials/interactive-control.md index 4e97286..24568e2 100644 --- a/docs/tutorials/interactive-control.md +++ b/docs/tutorials/interactive-control.md @@ -120,11 +120,10 @@ For multi-question flows (1 of N, 2 of N), each question appears in sequence aft If none of the options fit, tap **Other (type reply)** and type a custom answer as text. Untether routes your reply back to Claude Code, which reads it and continues. -``` -You: Use snake_case for all variable names -``` +!!! user "You" + Use snake_case for all variable names - +Untether routes your reply back to Claude Code, which reads it and continues. You can also tap **Deny** to dismiss the question if it's not relevant. From 82bbf0030a31651db6ffa27c4f3c6964ed633054 Mon Sep 17 00:00:00 2001 From: Nathan Schram <5553883+nathanschram@users.noreply.github.com> Date: Tue, 10 Mar 2026 09:18:54 +0000 Subject: [PATCH 3/4] docs: replace final 9 screenshot placeholders with CSS button mockups Add .tg-buttons/.tg-btn CSS classes to workflow-preview.css for Telegram inline keyboard button mockups (gray rounded rectangles with blue text, dark mode support). Replace all remaining placeholders across 4 doc files with styled admonitions + CSS button rows. Zero placeholders remain in docs/. Co-Authored-By: Claude Opus 4.6 --- docs/how-to/interactive-approval.md | 35 ++++++++++++++++++++-- docs/how-to/plan-mode.md | 43 +++++++++++++++++++++++++-- docs/how-to/voice-notes.md | 10 ++++++- docs/stylesheets/workflow-preview.css | 26 ++++++++++++++++ docs/tutorials/interactive-control.md | 40 +++++++++++++++++++++++-- 5 files changed, 145 insertions(+), 9 deletions(-) diff --git a/docs/how-to/interactive-approval.md b/docs/how-to/interactive-approval.md index f3312e6..e5376a8 100644 --- a/docs/how-to/interactive-approval.md +++ b/docs/how-to/interactive-approval.md @@ -25,7 +25,24 @@ When a permission request arrives, you see a message with the tool name and a co Buttons clear immediately when you tap them — no waiting for a spinner. - +
+ +!!! untether "Untether" + **Edit** `src/main.py` + + ```diff + - import sys + + import sys + + from pathlib import Path + ``` + +
+Approve +Deny +Pause & Outline Plan +
+ +
## Diff previews @@ -59,7 +76,21 @@ When Claude Code calls `AskUserQuestion`, Untether renders the question with int Toggle ask mode on or off via `/config` → Ask mode. When off, questions are auto-denied and Claude Code proceeds with defaults. - +
+ +!!! untether "Untether" + ❓ Which test framework should I use? + +
+pytest +unittest +
+
+Other (type reply) +Deny +
+ +
## Push notifications diff --git a/docs/how-to/plan-mode.md b/docs/how-to/plan-mode.md index cb3f3dd..913d687 100644 --- a/docs/how-to/plan-mode.md +++ b/docs/how-to/plan-mode.md @@ -39,7 +39,20 @@ When Claude Code tries to exit plan mode (ExitPlanMode), you see three buttons i - **Deny** — block and ask Claude Code to explain - **Pause & Outline Plan** — require a written plan first - +
+ +!!! untether "Untether" + **ExitPlanMode** + + Claude Code wants to start executing the plan. + +
+Approve +Deny +Pause & Outline Plan +
+ +
Tapping "Pause & Outline Plan" tells Claude Code to stop and write a comprehensive plan as a visible message in the chat. The plan must include: @@ -53,7 +66,21 @@ This is useful when you want to review the approach before Claude Code starts ma After Claude Code writes the outline, **Approve Plan / Deny** buttons appear automatically in Telegram. Tap "Approve Plan" to let Claude Code proceed, or "Deny" to stop and provide feedback. You no longer need to type "approved" — the buttons handle it. - +
+ +!!! untether "Untether" + Here's my plan: + + 1. **Read** `src/main.py` to understand current structure + 2. **Edit** `src/main.py` to refactor the `process()` function + 3. **Run** tests to verify no regressions + +
+Approve Plan +Deny +
+ +
## Progressive cooldown @@ -70,7 +97,17 @@ During the cooldown, any ExitPlanMode attempt is automatically denied, but **App This prevents the agent from bulldozing through when you've asked it to slow down and explain its approach, while still giving you a one-tap way to approve once you're satisfied. - +
+ +!!! untether "Untether" + **ExitPlanMode** — auto-denied (cooldown: 28s remaining) + +
+Approve Plan +Deny +
+ +
## Related diff --git a/docs/how-to/voice-notes.md b/docs/how-to/voice-notes.md index 02fc475..26e82d8 100644 --- a/docs/how-to/voice-notes.md +++ b/docs/how-to/voice-notes.md @@ -38,7 +38,15 @@ requires a specific model name, set `voice_transcription_model` (for example, When you send a voice note, Untether transcribes it and runs the result as a normal text message. If transcription fails, you’ll get an error message and the run is skipped. - +!!! user "You" + 🎤 *(voice note — 0:12)* + +!!! untether "Untether" + 📝 *"Add error handling to the upload function and make sure it retries on timeout"* + + working · claude · 0s + + … Read `src/upload.py` ## Related diff --git a/docs/stylesheets/workflow-preview.css b/docs/stylesheets/workflow-preview.css index 6ae7475..b480c57 100644 --- a/docs/stylesheets/workflow-preview.css +++ b/docs/stylesheets/workflow-preview.css @@ -96,3 +96,29 @@ color: rgba(255, 255, 255, 0.85); border-radius: 2px; } + +/* Telegram inline keyboard button mockups */ +.tg-buttons { + display: flex; + gap: 4px; + margin-top: 4px; +} + +.tg-btn { + flex: 1; + text-align: center; + background: #e4e7eb; + color: #3390ec; + font-size: 13px; + font-weight: 500; + padding: 8px 4px; + border-radius: 6px; + cursor: default; + user-select: none; + white-space: nowrap; +} + +[data-md-color-scheme="slate"] .tg-btn { + background: #2b313a; + color: #6ab2f2; +} diff --git a/docs/tutorials/interactive-control.md b/docs/tutorials/interactive-control.md index 24568e2..852bb9f 100644 --- a/docs/tutorials/interactive-control.md +++ b/docs/tutorials/interactive-control.md @@ -46,7 +46,24 @@ Claude Code starts working and you'll see a progress message stream in. When Claude Code wants to modify a file, Untether intercepts the tool call and shows you what's about to happen. You'll see a message like: - +
+ +!!! untether "Untether" + **Edit** `README.md` + + ```diff + - # My Project + + # My Project + + # A tool for managing widgets + ``` + +
+Approve +Deny +Pause & Outline Plan +
+ +
The message includes: @@ -100,7 +117,10 @@ Tap it to require Claude Code to write a comprehensive plan as a visible message After Claude Code writes the outline, **Approve Plan** and **Deny** buttons appear automatically — no need to type "approved": - +
+Approve Plan +Deny +
- Tap **Approve Plan** to let Claude Code proceed with implementation - Tap **Deny** to stop Claude Code and provide different direction @@ -112,7 +132,21 @@ After Claude Code writes the outline, **Approve Plan** and **Deny** buttons appe Sometimes Claude Code needs to ask you something — like which approach to take or what naming convention to use. When Claude Code calls `AskUserQuestion`, you'll see the question in the chat with a ❓ prefix and **option buttons** for each choice: - +
+ +!!! untether "Untether" + ❓ What naming convention should I use for the new variables? + +
+snake_case +camelCase +
+
+Other (type reply) +Deny +
+ +
**Tap an option button** to select your answer. Claude Code receives your choice and continues immediately. From 05042467ee5a332a93e85f0097374c902bcf1f66 Mon Sep 17 00:00:00 2001 From: Nathan Schram <5553883+nathanschram@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:50:16 +1100 Subject: [PATCH 4/4] docs: fix factual errors in screenshot mockups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Running action symbol: … → ▸ (matches STATUS dict in markdown.py) - /planmode show response: "(chat default)" → "(plan mode)" (matches planmode.py) - Resume lines: add backtick wrapping to match format_resume() output - Meta line: remove extra backtick wrapping (rendered as plain text) - Approval messages: match actual Permission Request format with diff preview (📝 prefix, inline - /+ lines) - Cooldown mockup: show actual synthetic "Plan outlined" title Co-Authored-By: Claude Opus 4.6 --- docs/how-to/interactive-approval.md | 32 ++++++++++--------------- docs/how-to/plan-mode.md | 6 ++--- docs/how-to/route-by-chat.md | 2 +- docs/how-to/switch-engines.md | 2 +- docs/how-to/voice-notes.md | 2 +- docs/tutorials/conversation-modes.md | 2 +- docs/tutorials/first-run.md | 4 ++-- docs/tutorials/interactive-control.md | 20 +++++++--------- docs/tutorials/multi-engine.md | 2 +- docs/tutorials/projects-and-branches.md | 4 ++-- 10 files changed, 33 insertions(+), 43 deletions(-) diff --git a/docs/how-to/interactive-approval.md b/docs/how-to/interactive-approval.md index e5376a8..f4532db 100644 --- a/docs/how-to/interactive-approval.md +++ b/docs/how-to/interactive-approval.md @@ -28,13 +28,11 @@ Buttons clear immediately when you tap them — no waiting for a spinner.
!!! untether "Untether" - **Edit** `src/main.py` - - ```diff - - import sys - + import sys - + from pathlib import Path - ``` + ▸ Permission Request [CanUseTool] - tool: Edit (file_path=src/main.py)
+ 📝 src/main.py
+ `- import sys`
+ `+ import sys`
+ `+ from pathlib import Path`
Approve @@ -48,22 +46,18 @@ Buttons clear immediately when you tap them — no waiting for a spinner. For tools that modify files, the approval message includes a compact diff so you can see what's about to change before deciding: -- **Edit**: shows removed lines (`- old`) and added lines (`+ new`), up to 4 lines each -- **Write**: shows the first 8 lines of content to be written -- **Bash**: shows the command to be run (up to 200 characters) +- **Edit**: 📝 file path, removed lines (`- old`) and added lines (`+ new`), up to 4 lines each +- **Write**: 📝 file path, then the first 8 lines of content to be written +- **Bash**: `$ command` (up to 200 characters) This lets you make informed approve/deny decisions without leaving Telegram. !!! untether "Untether" - **Edit** `src/main.py` - - ```diff - - import sys - + import sys - + from pathlib import Path - ``` - - `Approve` · `Deny` + ▸ Permission Request [CanUseTool] - tool: Edit (file_path=src/main.py)
+ 📝 src/main.py
+ `- import sys`
+ `+ import sys`
+ `+ from pathlib import Path` ## Answering questions diff --git a/docs/how-to/plan-mode.md b/docs/how-to/plan-mode.md index 913d687..2ae3591 100644 --- a/docs/how-to/plan-mode.md +++ b/docs/how-to/plan-mode.md @@ -42,9 +42,7 @@ When Claude Code tries to exit plan mode (ExitPlanMode), you see three buttons i
!!! untether "Untether" - **ExitPlanMode** - - Claude Code wants to start executing the plan. + ▸ Permission Request [CanUseTool] - tool: ExitPlanMode
Approve @@ -100,7 +98,7 @@ This prevents the agent from bulldozing through when you've asked it to slow dow
!!! untether "Untether" - **ExitPlanMode** — auto-denied (cooldown: 28s remaining) + ▸ Plan outlined — approve to proceed
Approve Plan diff --git a/docs/how-to/route-by-chat.md b/docs/how-to/route-by-chat.md index 6784348..97de749 100644 --- a/docs/how-to/route-by-chat.md +++ b/docs/how-to/route-by-chat.md @@ -38,7 +38,7 @@ Messages from that chat now default to the project. Fixed the two failing assertions in test_auth.py… dir: happy-gadgets
- codex resume abc123 + `codex resume abc123` ## Rules for chat ids diff --git a/docs/how-to/switch-engines.md b/docs/how-to/switch-engines.md index 8d428d3..733bb76 100644 --- a/docs/how-to/switch-engines.md +++ b/docs/how-to/switch-engines.md @@ -22,7 +22,7 @@ Directives are only parsed at the start of the first non-empty line. ✓ Read `src/timeline.py` - `🏷 codex` + 🏷 codex ## Set a default engine for the current scope diff --git a/docs/how-to/voice-notes.md b/docs/how-to/voice-notes.md index 26e82d8..047b2e9 100644 --- a/docs/how-to/voice-notes.md +++ b/docs/how-to/voice-notes.md @@ -46,7 +46,7 @@ If transcription fails, you’ll get an error message and the run is skipped. working · claude · 0s - … Read `src/upload.py` + ▸ Read `src/upload.py` ## Related diff --git a/docs/tutorials/conversation-modes.md b/docs/tutorials/conversation-modes.md index e43ecf1..6b9a1a0 100644 --- a/docs/tutorials/conversation-modes.md +++ b/docs/tutorials/conversation-modes.md @@ -50,7 +50,7 @@ Tip: set a default engine for this chat with `/agent set claude`. !!! untether "Untether" done · codex · 8s ... - codex resume abc123 + `codex resume abc123` To continue the same session, **reply** to a message with a resume line: diff --git a/docs/tutorials/first-run.md b/docs/tutorials/first-run.md index 1d9d82c..9ee659b 100644 --- a/docs/tutorials/first-run.md +++ b/docs/tutorials/first-run.md @@ -66,7 +66,7 @@ When the agent finishes, Untether sends a new message and replaces the progress Untether is a Telegram bridge for AI coding agents (Codex, Claude Code, OpenCode, Pi). It lets you run agents from chat, manage multiple projects and git worktrees, stream progress (commands, file changes, elapsed time), and resume sessions from either chat or terminal. It also supports file transfer, group topics mapped to repo/branch contexts, and multiple engines via chat commands, with a plugin system for engines/transports/commands. - codex resume 019bb89b-1b0b-7e90-96e4-c33181b49714 + `codex resume 019bb89b-1b0b-7e90-96e4-c33181b49714` That last line is the **resume line**—it's how Untether knows which conversation to continue. @@ -116,7 +116,7 @@ Untether sends `SIGTERM` to the agent process and posts a cancelled status: !!! failure "" cancelled · codex · 12s - codex resume 019bb89b-1b0b-7e90-96e4-c33181b49714 + `codex resume 019bb89b-1b0b-7e90-96e4-c33181b49714` If a resume token was already issued (and resume lines are enabled), it will still be included so you can continue from where it stopped. diff --git a/docs/tutorials/interactive-control.md b/docs/tutorials/interactive-control.md index 852bb9f..586f02a 100644 --- a/docs/tutorials/interactive-control.md +++ b/docs/tutorials/interactive-control.md @@ -49,13 +49,11 @@ When Claude Code wants to modify a file, Untether intercepts the tool call and s
!!! untether "Untether" - **Edit** `README.md` - - ```diff - - # My Project - + # My Project - + # A tool for managing widgets - ``` + ▸ Permission Request [CanUseTool] - tool: Edit (file_path=README.md)
+ 📝 README.md
+ `- # My Project`
+ `+ # My Project`
+ `+ # A tool for managing widgets`
Approve @@ -67,8 +65,8 @@ When Claude Code wants to modify a file, Untether intercepts the tool call and s The message includes: -- **Tool name** (e.g. Edit, Write, Bash) -- **Diff preview** — removed lines (`- old`) and added lines (`+ new`) so you can see what will change +- **Request type and tool name** with key parameters (e.g. file path, command) +- **Diff preview** — 📝 file path, removed lines (`- old`) and added lines (`+ new`) - **Three buttons**: Approve, Deny, and Pause & Outline Plan Your phone will also buzz with a push notification so you don't miss it. @@ -81,7 +79,7 @@ Tap **Approve** to let Claude Code proceed with the action. The button clears in working · claude · 8s · step 2 ✓ Read `README.md`
- … Edit `README.md` + ▸ Edit `README.md` You may see several approval requests in a row as Claude Code works through multiple steps. @@ -194,7 +192,7 @@ To check your current mode at any time: ``` !!! untether "Untether" - plan mode: **on** (chat default) + plan mode: **on** (plan mode) ## What just happened diff --git a/docs/tutorials/multi-engine.md b/docs/tutorials/multi-engine.md index c889839..1e37f2e 100644 --- a/docs/tutorials/multi-engine.md +++ b/docs/tutorials/multi-engine.md @@ -38,7 +38,7 @@ The engine only applies to that message. The response will have a resume line fo !!! untether "Untether" done · claude · 8s
- claude --resume abc123 + `claude --resume abc123` When you reply, Untether sees `claude --resume` and automatically uses Claude Code—you don't need to repeat `/claude`. diff --git a/docs/tutorials/projects-and-branches.md b/docs/tutorials/projects-and-branches.md index 669ff77..510b001 100644 --- a/docs/tutorials/projects-and-branches.md +++ b/docs/tutorials/projects-and-branches.md @@ -67,7 +67,7 @@ The response includes a context footer: !!! untether "Untether" dir: happy-gadgets
- codex resume abc123 + `codex resume abc123` That `dir:` line tells you which project is active. When you reply, Untether automatically uses the same project—you don't need to repeat `/happy-gadgets`. @@ -117,7 +117,7 @@ The response shows both project and branch: !!! untether "Untether" dir: happy-gadgets @feat/new-login
- codex resume xyz789 + `codex resume xyz789` Replies stay on the same branch. Your main checkout is untouched.