Inline settings menu

May 26, 2026 Β· View on GitHub

Adjust Untether's behaviour without editing config files or restarting β€” tap buttons right in Telegram. The /config command opens an interactive settings menu with inline keyboard buttons, similar to BotFather's settings style. Navigate sub-pages, toggle settings, and return to the overview, all within a single message that edits in place.

Open the menu

Send /config in any chat:

/config

The home page shows current values for all settings, with buttons arranged in pairs (max 2 per row) for comfortable mobile tap targets:

πŸ• Untether settings

Agent controls (Claude Code)
Plan mode: on  Β· approve actions
Ask mode: on  Β· interactive questions
Diff preview: off  Β· buttons only

Verbose: off
Cost & usage: cost on, sub off
Resume line: on
Engine: claude (global)
Model: default
Listen: all

[πŸ“‹ Plan mode]     [❓ Ask mode]
[πŸ“ Diff preview]  [πŸ” Verbose]
[πŸ’° Cost & usage]  [↩️ Resume line]
[πŸ“‘ Listen]        [βš™οΈ Engine & model]
[🧠 Reasoning]     [ℹ️ About]

πŸ“– Help guides Β· πŸ› Report a bug

!!! note "Engine-specific controls" The home page adapts to the current engine. Claude Code shows Plan mode, Ask mode, and Diff preview under "Agent controls". Codex CLI shows Approval policy (full auto / safe). Gemini CLI shows Approval mode (read-only / edit files / full access). Engines without interactive controls (OpenCode, Pi, Amp) skip the agent controls section entirely.

Tap any button to open that setting's page. Each sub-page shows:

  • A description of the setting
  • The current effective value (resolved from override or default β€” never shows a bare "default" label)
  • Buttons to change the value
  • A Clear override button to revert to the global/engine default
  • A ← Back button to return to the home page

Toggle behaviour

Most settings use a two-button selection pattern: [On] [Off] [Clear] with a βœ“ on the active option. Tap either button to set the value. Tapping Clear removes the per-chat override and falls back to the global setting.

When you tap a setting button:

  1. Confirmation toast β€” a brief popup appears confirming the change (e.g. "Plan mode: off", "Verbose: on"). This uses the same toast mechanism as Claude Code approval buttons.
  2. Auto-return β€” the menu automatically navigates back to the home page, showing the updated value across all settings. No need to tap "Back" manually.

Multi-state settings

Some settings have more than two states and use a different layout:

  • Plan mode β€” three options (off / on / auto) shown as separate buttons in a 2+1 split: [Off] [On] on the first row, [Auto] [Clear override] on the second
  • Approval mode (Gemini) β€” three options (read-only / edit files / full access)
  • Effort (Claude Code) β€” low / medium / high / xhigh / max
  • Reasoning (Codex) β€” minimal / low / medium / high / xhigh

The active option is marked with a βœ“ prefix. Tap a different option to switch.

Engine-aware visibility

Settings are engine-specific and only appear when relevant:

  • Plan mode β€” Claude Code only. Codex and Gemini have their own pre-run policies instead.
  • Approval policy β€” Codex CLI only. Toggle between "full auto" (default, all tools approved) and "safe" (untrusted tools blocked via --ask-for-approval untrusted). This is a pre-run policy β€” not interactive mid-run approval.
  • Approval mode β€” Gemini CLI only. Toggle between "read-only" (default, write tools blocked), "edit files" (file reads/writes OK, shell commands blocked via --approval-mode auto_edit), and "full access" (all tools approved via --approval-mode yolo). This is a pre-run policy.
  • Ask mode and Diff preview β€” Claude Code only. Hidden for other engines.
  • Reasoning β€” Claude Code and Codex only. Hidden for OpenCode, Pi, Gemini, and Amp.
  • Engine & model β€” always visible. Engine and model are merged into a single page. Shows the current engine and model override; to set a model, use /model set <name>.

When you switch engines via the Engine & model page, the home page automatically shows or hides the relevant controls.

Available settings

SettingOptionsPersisted
Plan modeoff, on, autoYes (chat prefs)
Approval policyfull auto, safeYes (chat prefs)
Approval moderead-only, edit files, full accessYes (chat prefs)
Ask modeoff, onYes (chat prefs)
Verboseoff, onYes (chat prefs)
Diff previewoff, onYes (chat prefs)
Engine & modelany configured engine + modelYes (chat prefs)
Effort / ReasoningClaude: low, medium, high, xhigh, max; Codex: minimal, low, medium, high, xhighYes (chat prefs)
Cost & usageAPI cost, subscription usage, budget, auto-cancelYes (chat prefs)
Resume lineoff, onYes (chat prefs)
Listenall, mentionsYes (chat prefs)
Budget enabledoff, onYes (chat prefs)
Budget auto-canceloff, onYes (chat prefs)

Approval policy appears instead of Plan mode when the engine is Codex CLI. Approval mode appears instead of Plan mode when the engine is Gemini CLI.

Triggers page {#triggers-page}

When [triggers] is enabled and at least one cron or webhook is configured, the home page gains a one-button toggle row at the bottom and a dedicated πŸ“‘ Triggers button that opens the Triggers page (config:tg) (#271 Tier 2 + #294).

The Triggers page shows:

  • State and counts β€” running / paused, plus per-chat cron and webhook totals.
  • Master pause/resume toggle β€” tap Pause to suspend all cron firing and webhook dispatch globally without editing config; tap Resume to clear it. While paused, webhooks return 503 triggers paused (with Retry-After: 60), /health reports paused: true, and /ping shows ⏸ triggers paused: … (suspended). Pause is in-memory only β€” restart auto-resumes (the safe default).
  • Per-chat cron list β€” each line shows the cron id, human-readable schedule via describe_cron(schedule, timezone), project, engine, and last-fired relative time.
  • Per-chat webhook list β€” each line shows the webhook id, path, auth scheme, project, engine, and last-fired.

Lists are scoped to the current chat (crons_for_chat() / webhooks_for_chat() with the bridge default_chat_id fallback), capped at 10 entries with a …and N more (see untether.toml) overflow marker. The pause/resume controls remain visible even when the chat has no triggers configured.

See Schedule tasks for the pause flow end-to-end.

Loop mode page {#loop-mode}

When the active engine is Claude Code, the home page gains a πŸ” Loop mode button that opens the Loop sub-page (#289). Loop mode is off by default β€” turning it on enables Untether's observation of Claude's session-scoped scheduling tools (CronCreate, ScheduleWakeup) so iterations keep firing after the subprocess exits.

The page shows:

  • State β€” Loop mode: on / off for the current chat (per-chat override over the global [loop] enabled default).
  • Cost + quota warning β€” explicit reminder before turning ON: every loop fire counts against [cost_budget], and the runaway caps in [loop] (max_iterations, max_total_duration_hours, expiry_days) are the safety net.
  • πŸ’° Set a budget β€” deep-link to the Cost & Usage page (config:cu) for one-tap budget setup.
  • Toggle row β€” [On] [Off] [Clear] with βœ“ on the active option.

/cancel and /new both drop pending loop iterations for the current session and write a do-not-resume sentinel so a subsequent loop_scheduler resume can't replay them. /continue is unaffected (it doesn't trigger loop replay).

Loop mode is Claude-only (LOOP_SUPPORTED_ENGINES = frozenset({"claude"})); the button is hidden for other engines. See Schedule tasks β†’ Loop mode for the full architecture and cost guidance.

Cost & Usage page

The Cost & Usage sub-page merges cost display and budget controls into a unified page with toggle rows:

  • API cost β€” per-run cost in the message footer (requires engine cost reporting)
  • Subscription usage β€” 5h/weekly subscription usage in the footer (Claude Code only)
  • Budget enabled β€” turn budget tracking on or off for this chat (overrides global [cost_budget] setting)
  • Budget auto-cancel β€” enable or disable automatic run cancellation when a budget is exceeded

Each toggle uses the [βœ“ Label: on] [Label: off] [Clear] compact pattern (labels distinguish the four toggles). Clear removes the per-chat override and falls back to the global config.

For historical cost data across sessions, use the /stats command.

Callbacks vs commands

  • Text command (/config): sends a new message with the menu.
  • Button tap: edits the existing message in place β€” no message spam.

All button interactions use early callback answering for instant feedback.