Multi-engine workflows
This tutorial shows you how to use different engines for different tasks and set up defaults so you don't have to think about it. Swap between Claude Code, C...
This tutorial shows you how to use different engines for different tasks and set up defaults so you don’t have to think about it. Swap between Claude Code, Codex, OpenCode, Pi, Gemini CLI, and Amp with a single prefix — from your phone, laptop, or any device with Telegram.
What you’ll learn: Engine directives, persistent defaults, and when to use which engine.
Why multiple engines?
Different engines have different strengths:
| Engine | Good at | Unique features |
|---|---|---|
| Claude Code | Complex refactors, architecture, long context | Interactive permissions, plan mode, ask mode, diff preview |
| Codex | Fast edits, shell commands, quick fixes | Reasoning levels, device re-auth (/auth) |
| OpenCode | 75+ providers via Models.dev, local models | Broadest provider support |
| Pi | Multi-provider auth, conversational | Context compaction |
| Gemini CLI | Google models, plan mode, model routing | Auto Pro/Flash routing, sandboxing, extensions |
| AMP | Sourcegraph integration, thread sharing | Mode selection (deep/rush/smart), rich permissions |
See the engine compatibility matrix in the README for a full feature-by-feature breakdown.
You might want Codex for quick tasks and Claude Code for deep work—without manually specifying every time.
1. One-off engine selection
Prefix any message with /<engine>:
You /claude refactor this module to use dependency injection
You /codex add a —verbose flag to the CLI
You /pi explain how the event loop works in this codebase
The engine only applies to that message. The response will have a resume line for that engine:
Untether done · claude · 8s
claude --resume abc123
When you reply, Untether sees claude --resume and automatically uses Claude Code—you don’t need to repeat /claude.
2. Engine + project + branch
Directives combine. Order doesn’t matter:
You /claude /happy-gadgets @feat/di refactor to use dependency injection
Or:
You /happy-gadgets @feat/di /claude refactor to use dependency injection
Both do the same thing: run Claude Code in the happy-gadgets project on the feat/di branch.
Directives are only parsed at the start Everything after the first non-directive word is the prompt.
/claude fix /this/pathuses Claude Code with prompt “fix /this/path”—it doesn’t try to parse/thisas a directive.
3. Set a default engine for a chat
Use /agent set to change the default for the current scope:
You /agent set claude
Response:
Untether chat default engine set to claude
Now all new conversations in this chat use Claude Code (unless you explicitly override with /codex).
Check the current default:
You /agent
Example response:
Untether engine: claude (chat default)
defaults: topic: none, chat: claude, project: none, global: codex
available: codex, claude, opencode, pi, gemini, amp
Clear it:
You /agent clear
Response:
Untether chat default engine cleared.
4. Defaults in topics
If you use Telegram forum topics, /agent set applies per-topic:
You topic: Backend work
/agent set claude
You topic: Quick fixes
/agent set codex
Each topic remembers its own default.
5. Per-project defaults
Set a default engine in your project config:
=== “untether config”
```sh
untether config set projects.happy-gadgets.path "~/dev/happy-gadgets"
untether config set projects.happy-gadgets.default_engine "claude"
```
=== “toml”
```toml
[projects.happy-gadgets]
path = "~/dev/happy-gadgets"
default_engine = "claude"
```
Now /happy-gadgets tasks default to Claude Code, even if your global default is Codex.
6. Selection precedence
When Untether picks an engine, it checks (highest to lowest):
- Resume line — replying to
claude --resume ...uses Claude Code - Explicit directive —
/codex ...uses Codex - Topic default —
/agent setin this forum topic - Chat default —
/agent setin this chat - Project default —
default_enginein project config - Global default —
default_engineat the top ofuntether.toml
This means: resume lines always win, then explicit directives, then the most specific default applies.
With
session_mode = "chat", stored sessions are per engine. Replying to a resume line for another engine runs that engine and updates its stored session without overwriting other engines.
Example Chat sessions with two engines (assume default engine is
codex):
1. You send: `fix the failing tests` -> bot replies with `codex resume A` (stores Codex session A).
2. You reply to an older Claude Code message containing `claude --resume B` -> runs Claude Code and stores Claude Code session B.
3. You send a new message (not a reply) -> auto-resumes Codex session A (default engine), Claude Code session B remains stored for future replies or defaults.
7. Practical patterns
Pattern: Quick questions vs. deep work
=== “untether config”
```sh
# Global default for quick stuff
untether config set default_engine "codex"
# Project default for complex codebase
untether config set projects.backend.path "~/dev/backend"
untether config set projects.backend.default_engine "claude"
```
=== “toml”
```toml
# Global default for quick stuff
default_engine = "codex"
# Project default for complex codebase
[projects.backend]
path = "~/dev/backend"
default_engine = "claude"
```
Simple messages go to Codex. /backend messages go to Claude Code.
Pattern: Topic per engine
Create forum topics like “Claude Code work” and “Codex tasks”, then /agent set in each:
You topic: Claude Code deep-dives
/agent set claude
You topic: Quick Codex fixes
/agent set codex
Drag tasks to the right topic and the engine follows.
Pattern: Override for specific tasks
Even with defaults, you can always override:
You /codex just add a print statement here
Works regardless of what the default is.
Recap
| Want to… | Do this |
|---|---|
| Use an engine once | /claude ... or /codex ... |
| Set default for chat | /agent set claude |
| Set default for topic | /agent set ... in the topic |
| Set default for project | default_engine = "..." in config |
| Set global default | default_engine = "..." at top of config |
| Check current default | /agent |
| Clear default | /agent clear |
You’re done!
That’s the end of the tutorials. You now know how to:
- ✅ Install and configure Untether
- ✅ Send tasks and continue conversations
- ✅ Cancel runs mid-flight
- ✅ Control agent actions with approval buttons
- ✅ Target repos and branches from chat
- ✅ Use multiple engines effectively
Where to go next
Want to do something specific?
- Enable forum topics for organized threads
- Transfer files between Telegram and your repo
- Use voice notes to dictate tasks
- Schedule tasks to run later
Want to understand the internals?
- Architecture — how the pieces fit together
- Routing and sessions — how context resolution works
- Specification — normative behavior contracts
Need exact syntax?