Default permission mode for new chats: a Settings row, and the latest choice wins
Summary
You can now set your own default permission mode for new agent chats, and it sticks.
Before this, agents.defaultPermissionMode was a key acpmux read from cmux-next.json, with no Settings row, palette entry or schema. A mode picked in any chat (lastPermissionMode) also always beat it. Once you'd picked a mode in a chat, setting your default in the file did nothing.
- First-class key.
agents.defaultPermissionModeis a choice row in Settings > Agents > Agent Chat ("Permission Mode for New Chats": Full Access, Harness Default, Ask Before Changes). The default stays Full Access. Being a schema row, it also shows up in the palette's Set Setting page, incmux config get/set/list, and in the JSON Schema from #21681. It's refused to agents (userOnly), because an agent must not widen its own approvals;cmux config set agents.defaultPermissionMode ask --confirmasks you first. - Latest choice wins. A pick now records the setting as it was at that moment (
lastPermissionModeSettingin acpmuxconfig.json). New chats follow the pick while the setting is unchanged. Once the setting differs, from the Settings row, the palette, the CLI or a hand edit, the setting wins, and a later pick wins again. Switching levels in a chat keeps working as the quick switch it is today. acpmux's ownconfig.jsondefaultPermissionMode(acpmux without the app) still loses to a pick, as before. - Agent-started chats. Sessions an agent starts through acpmux take the same start level, because they go through the same
start_level. #21666's gate still decides whether a no-ask default may apply to a chat a proven caller starts. This PR doesn't change that gate.
Settings schema: adds one row. The fleet settings export ran on 77171cb29ab (cmux-ci step 2ddda98336f85bda0ded571d) and produced settings-schema.json, the MDM docs and the source stamp. After that, defaults_guard.py snapshot (check-fresh passes) and gen-strings.mjs settings were run. All of it is committed in 132bbd4b666.
Testing
cargo test -p acpmux --test start_mode_settings: the extended test checks pick, then setting change, then pick again, then key removal. It failed on 927310c36e4 (the old Ask pick still won after the setting changed) and passes with 2a275181956.cargo test -p acpmux --test start_modestill passes (9 tests).- The independent review found two gaps, both fixed with the red test committed first (a65f5335adf) and the fix in 22c93199bdf:
reload_catalogdidn't copylastPermissionModeSetting, so the two fields drifted after a reload.- A pick saved before this field existed lost to a key the person already had set. A pick now records
""when there's no setting, so an absent field means a legacy pick. That pick wins, and the first start records the setting as it is then. start_mode_settings,start_mode(9),start_defaults(1) andharnesses_changed(8) pass, and clippy is clean.
cargo clippy -p acpmux --all-targetsis clean.- The fleet export step compiled CmuxNext with the row and ran
SettingsSchemaExportTests(5 passed) andManagedPreferencesManifestTests(4 passed). Those include the checks that every key has an explicit agent policy and every text has a catalog key. acpmux/src/config.rswas over its line budget on the base, so the god-file ratchet doesn't let it grow; the twolastPermissionModefields share one doc comment (318d93cc9cb).check-no-godfiles.sh --only rustpasses locally.- Focused hosted cmux-tui runs (
start_mode): run 39141602244 passed on Linux and macOS at 318d93cc9cb; run 39169074785 is dispatched on 22c93199bdf. - The perf gate's one failed check is
drag: a split shows two terminals and a divider, not a counter budget, and it's unrelated to this change. The base gate passed at 0b8bef2840. - Already red on the base, not from this PR:
cmux-next checksfails Main-thread concurrency and Type scale inCmuxNextDesign/Text/TextWeightProbe.swiftandGlyphMask.swift.
Localization: 4 new keys in the CmuxNextSettings catalog, translated in all 21 locales. localization_catalog.py check reports nothing for them. The row's texts go through SettingsText.keyed.
Changelog
Added: Settings > Agents > Permission Mode for New Chats sets the default for every new agent chat; changing it overrides an earlier pick in a chat
Proof
Not checked live in a tagged build yet. The row is drawn by the web Settings page from the schema, like every other choice row.
🤖 Generated with Claude Code