Skip to content

fix: 0.35.5rc8 — adopt Claude Code's native auto permission mode (#741), fix the stale/unenforced allowlist (#742), persist private-chat topic sessions (#734) - #744

Merged
Nathan Schram (nathanschram) merged 5 commits into
devfrom
fix/741-742-claude-permission-modes
Aug 12, 2026
Merged

fix: 0.35.5rc8 — adopt Claude Code's native auto permission mode (#741), fix the stale/unenforced allowlist (#742), persist private-chat topic sessions (#734)#744
Nathan Schram (nathanschram) merged 5 commits into
devfrom
fix/741-742-claude-permission-modes

Conversation

@nathanschram

Copy link
Copy Markdown
Member

Claude Code 2.1.228 ships its own auto permission mode, and Untether's same-named sugar shadowed it. Auto mode becomes the CLI default for new Pro/Max/Team sessions on 2026-08-14, two days after this was found.

Issue Root cause Fix Live verification
#741 build_args rewrote auto--permission-mode plan and armed an ExitPlanMode rubber stamp, so the CLI's classifier-gated auto was unreachable Rename the sugar to plan-auto; pass every genuine CLI mode through verbatim. One-shot chat-pref migration; TOML keeps its value + one-shot WARN. /config → Permission mode gains a Plan-auto button Agent read its own /proc/<pid>/cmdline: --permission-mode auto --permission-prompt-tool stdio. plan-auto still spawns plan and rubber-stamps ExitPlanMode
#742 Allowlist stale vs 2.1.228 and enforced only for crons — [engines.claude] was read raw, so a typo died at subprocess spawn Re-derive the set (+manual, +dontAsk); apply the same allowlist in build_runner(); add a drift test that re-derives it from the installed binary permission_mode = "palan"ConfigError at load naming key/value/path; "auto" loads and warns once
#734 _chat_session_key() returned None for any thread_id, but private-chat topics carry one and TopicStateStore declines them — no resume token was ever written Private chats key on (chat_id, thread_id); main thread keeps (chat_id, None); group/supergroup topics still defer to TopicStateStore Group/DM regression path verified live (key shape unchanged, sessions resumed). Private-topic path is unit-tested only — see caveat below

The load-bearing question

#741 asked whether upstream auto swallows the control channel and costs Untether its interactivity. It does not. Probed against CLI 2.1.228 using Untether's exact argv, then confirmed on @untether_dev_bot: AskUserQuestion still raises a can_use_tool control_request under auto, renders option buttons, and round-trips the answer. Classifier fallback after repeated blocks routes through --permission-prompt-tool stdio as an ordinary Telegram approval.

diff_preview is inert under auto — but it has been inert under acceptEdits since it shipped. That is a pre-existing property of any non-prompting mode, not a new regression, and it is documented rather than silently accepted.

auto deliberately does not arm the ExitPlanMode rubber stamp: that mode has no plan gate, and arming it would recreate the blanket downstream bypass tracked by #383 somewhere it means far more.

Two corrections to the issues as filed

  • bug: Claude permission_mode allowlist is stale (CLI 2.1.228) and only enforced for crons, not [engines.claude] #742 claimed default is rejected by the CLI. It is not — claude --help lists manual in its place, but a spawn probe of --permission-mode default exits 0, and the docs confirm manual is a documented alias for default (CLI ≥ 2.1.200). default stays in the allowlist; the drift test excludes it from the comparison rather than dropping it.
  • The first migration attempt was wrong, and integration testing caught it. Migrating stored autoplan-auto on every read is right for a legacy value but wrong the moment auto is a value the user can choose: pressing Auto in /config stored auto, the next read rewrote it, and the run spawned --permission-mode plan. The rewrite is now one-shot, guarded by a persisted permission_mode_migrated flag — a field rather than a STATE_VERSION bump, because JsonStateStore discards state on a version mismatch.

Breaking

permission_mode = "auto" in untether.toml changes meaning: it now selects the CLI's classifier-gated auto mode instead of plan-mode-plus-rubber-stamp. Unattended crons that set it lose the plan ceremony and gain per-action classification with a hard exfiltration deny. Set "plan-auto" to keep the old behaviour; the runner logs claude.permission_mode.auto_semantics_changed once when it sees the ambiguous value.

Caveat

#734's private-chat-topic path could not be driven live — the dev bot has no private-chat-topic binding and the feature can't be created through the test tooling. It is covered by 8 unit tests, and the group/DM paths it touches were verified live.

Tests

3226 passing (+65), ruff clean, coverage 83.5%. New tests/test_claude_permission_modes.py (46) covers mode mapping, allowlist contents, cron↔engine-config accept/reject parity, the one-shot migration and its regression guard, and a drift test that re-derives the mode set from the installed CLI so this rots loudly. Attestation marker written for 0.35.5rc8, SHA-bound to 815eb90.

🤖 Generated with Claude Code

), fix the stale/unenforced allowlist (#742), persist private-chat topic sessions (#734)

Claude Code 2.1.228 ships its own `auto` permission mode, which Untether's
same-named sugar shadowed: `build_args` rewrote `auto` to `--permission-mode
plan` and rubber-stamped the ExitPlanMode control request, so the CLI's
classifier-gated mode was unreachable. Auto mode becomes the CLI default for
new Pro/Max/Team sessions on 2026-08-14.

- #741 rename the sugar to `plan-auto`; pass every genuine CLI mode through
  verbatim. Chat prefs migrate on read (Claude-only); TOML keeps its value and
  gets a one-shot WARN. `/config → Permission mode` gains a `plan-auto` button.
- #742 re-derive the allowlist against CLI 2.1.228 (+`manual`, +`dontAsk`;
  `default` retained — the CLI still accepts it, contrary to the issue) and
  apply it to `[engines.claude]`, which was read raw. Adds a drift test that
  re-derives the set from the installed binary.
- #734 private-chat topics key on `(chat_id, thread_id)` instead of being
  dropped, so each topic resumes independently.

Verified against CLI 2.1.228 with Untether's exact argv: AskUserQuestion still
raises a can_use_tool control_request under `auto`, so Telegram interactivity
survives the adoption.

3222 tests pass, ruff clean, coverage 83.5%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Caught by integration testing on @untether_dev_bot: the first attempt
migrated stored `auto` -> `plan-auto` on every read. That is right for a
legacy value but wrong the moment `auto` becomes a value the user can
choose — pressing Auto in /config stored `auto`, the next read rewrote it
to `plan-auto`, and the run spawned `--permission-mode plan`. The new mode
was unreachable through its own UI.

The rewrite now runs once per state file, guarded by a persisted
`permission_mode_migrated` flag. It is a field rather than a STATE_VERSION
bump because JsonStateStore discards state on a version mismatch, so
bumping would wipe every chat's prefs to migrate one value.

4 new tests covering the legacy rewrite, the marker, and the regression
guard that a deliberately chosen `auto` survives a reload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a0f3f274-ec50-47c8-bc13-f6448100b1c6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Three advisories published after dev's last CI run; pip-audit failed on this
batch's PR. aiohttp is a direct dependency (webhook server), so the bump ships
here rather than as a follow-up. Full suite green on the new pin.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@socket-security

socket-security Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedaiohttp@​3.14.1 ⏵ 3.14.397 +1100 +19100100100

View full report

…e /config page (#741)

Guides: plan-mode.md gains the four-mode table and a renamed-in-v0.35.5 note;
the per-cron override sections in plan-mode / schedule-tasks / webhooks-and-cron
gain a semantics-change warning, and their valid-value lists were stale anyway
(missing manual/dontAsk/plan-auto). README, glossary, commands reference,
triggers reference, interactive-control tutorial, inline-settings and FAQ Q6
brought into agreement.

/config: the Claude section is retitled "Permission mode" on both the home page
and the sub-page — with Claude Code's own auto mode in the list, "Plan mode" no
longer describes what the setting controls. Verified live on @untether_dev_bot.

Audited and found to need no change: the onboarding wizard and shipped config
templates write no permission_mode (fresh installs unaffected), and
/model + /reasoning only pass the stored value through.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nathanschram
Nathan Schram (nathanschram) merged commit f7f6abf into dev Aug 12, 2026
21 checks passed
@nathanschram
Nathan Schram (nathanschram) deleted the fix/741-742-claude-permission-modes branch August 12, 2026 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant