Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Hotbar sources for MCP tools and skills: MCP tool slots prefill the
composer (execution stays behind the normal tool-approval flow) and skill
slots activate through the existing `$skill` alias (#2068, #2069).
- Mode & permission surface: Tab cycles Plan → Act → Multitask → Operate;
Shift+Tab cycles the Agent permission posture (Ask / Auto-Review / Full
Access) with a footer permission chip; Ctrl+T cycles reasoning effort and
Ctrl+Shift+T opens the live transcript overlay. Multitask raises the
default sub-agent fan-out and focuses the Agents sidebar; Operate is a
thin Fleet-operator mode wired to `/setup` readiness.
- Mode & permission surface: Tab cycles Plan → Act → Operate; Shift+Tab
cycles the Agent permission posture (Ask / Auto-Review / Full Access) with
a footer permission chip; Ctrl+T cycles reasoning effort and Ctrl+Shift+T
opens the live transcript overlay. Operate is the orchestration mode
(delegate, wait, inspect, dispatch) and raises sub-agent fan-out while
focusing the Agents sidebar.
- Provider lake facade: the provider/model pickers, hotbar, and model
inventory now enumerate configured providers' models from the bundled
catalog (with an `A` toggle to browse the full catalog), replacing the
Expand All @@ -39,6 +39,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Sub-agent waiting no longer peek→sleep polls: `agent(action="wait")` joins
children, unchanged peeks are throttled (~30s) with an anti-polling nudge,
and mode prompts teach the join primitive (#4097). Harvested from PR #4098
by [@Mr-Moon121](https://github.com/Mr-Moon121) (Jeffrey Luna).
- `/provider` picker remembers catalog/configured view and highlighted row
across reopen, matching `/model` picker memory.
- Mode picker roster is exactly Act / Plan / Operate (no Multitask, no
numeric `4`/`5` gaps). Legacy `yolo`/`4` remain invisible one-way
permission shorthand for Act + Bypass.

- Fleet setup is a role/profile roster editor, not a provider-scoped model
picker: the Model step lists routes from every configured provider (not
only the active one), a picked route's provider is persisted explicitly in
Expand Down
2 changes: 1 addition & 1 deletion config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ check_for_updates = true
# Optional 1-8 sidebar hotbar bindings. When no [[hotbar]] tables are present,
# the TUI uses built-in defaults:
# 1 voice.toggle 2 session.compact 3 mode.plan 4 mode.agent
# 5 mode.yolo 6 palette.open 7 sidebar.toggle 8 trust.toggle
# 5 mode.operate 6 palette.open 7 sidebar.toggle 8 trust.toggle
#
# Invalid slots are skipped with a warning, duplicate slots use the last entry,
# and unknown actions are preserved so the UI can show a disabled entry.
Expand Down
2 changes: 1 addition & 1 deletion crates/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ pub const DEFAULT_HOTBAR_ACTIONS: [&str; HOTBAR_SLOT_COUNT as usize] = [
"session.compact",
"mode.plan",
"mode.agent",
"mode.yolo",
"mode.operate",
"palette.open",
"sidebar.toggle",
"trust.toggle",
Expand Down
22 changes: 16 additions & 6 deletions crates/tui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Hotbar sources for MCP tools and skills: MCP tool slots prefill the
composer (execution stays behind the normal tool-approval flow) and skill
slots activate through the existing `$skill` alias (#2068, #2069).
- Mode & permission surface: Tab cycles Plan → Act → Multitask → Operate;
Shift+Tab cycles the Agent permission posture (Ask / Auto-Review / Full
Access) with a footer permission chip; Ctrl+T cycles reasoning effort and
Ctrl+Shift+T opens the live transcript overlay. Multitask raises the
default sub-agent fan-out and focuses the Agents sidebar; Operate is a
thin Fleet-operator mode wired to `/setup` readiness.
- Mode & permission surface: Tab cycles Plan → Act → Operate; Shift+Tab
cycles the Agent permission posture (Ask / Auto-Review / Full Access) with
a footer permission chip; Ctrl+T cycles reasoning effort and Ctrl+Shift+T
opens the live transcript overlay. Operate is the orchestration mode
(delegate, wait, inspect, dispatch) and raises sub-agent fan-out while
focusing the Agents sidebar.
- Provider lake facade: the provider/model pickers, hotbar, and model
inventory now enumerate configured providers' models from the bundled
catalog (with an `A` toggle to browse the full catalog), replacing the
Expand All @@ -39,6 +39,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Sub-agent waiting no longer peek→sleep polls: `agent(action="wait")` joins
children, unchanged peeks are throttled (~30s) with an anti-polling nudge,
and mode prompts teach the join primitive (#4097). Harvested from PR #4098
by [@Mr-Moon121](https://github.com/Mr-Moon121) (Jeffrey Luna).
- `/provider` picker remembers catalog/configured view and highlighted row
across reopen, matching `/model` picker memory.
- Mode picker roster is exactly Act / Plan / Operate (no Multitask, no
numeric `4`/`5` gaps). Legacy `yolo`/`4` remain invisible one-way
permission shorthand for Act + Bypass.

- Fleet setup is a role/profile roster editor, not a provider-scoped model
picker: the Model step lists routes from every configured provider (not
only the active one), a picked route's provider is persisted explicitly in
Expand Down
6 changes: 2 additions & 4 deletions crates/tui/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
"KbThinkingPager": "Open Turn Inspector",
"KbLiveTranscript": "Open live transcript overlay (Ctrl+Shift+T; sticky-tail auto-scroll)",
"KbBacktrackMessage": "Backtrack to a previous user message (Left/Right step, Enter to rewind)",
"KbCompleteCycleModes": "Complete /command, queue running-turn follow-up, cycle modes (Plan → Act → Multitask → Operate)",
"KbCompleteCycleModes": "Complete /command, queue running-turn follow-up, cycle modes (Plan → Act → Operate)",
"KbCycleThinking": "Cycle reasoning effort for the active provider (Ctrl+T)",
"KbCyclePermissions": "Cycle permission posture: Ask → Auto-Review → Full Access (Shift+Tab)",
"KbJumpPlanAgentYolo": "Trigger hotbar slots",
Expand Down Expand Up @@ -531,14 +531,12 @@
"AppModeAuto": "Auto",
"AppModeYolo": "YOLO (deprecated)",
"AppModePlan": "Plan",
"AppModeMultitask": "Multitask",
"AppModeOperate": "Operate",
"AppModeAgentHint": "Execute directly — edits and shell ask for approval",
"AppModeAutoHint": "Shell enabled with automatic risk review",
"AppModePlanHint": "Read-only research first — present a plan before acting",
"AppModeYoloHint": "Deprecated — maps to Act + Full Access",
"AppModeMultitaskHint": "Stay responsive — fan quick work out to background agents",
"AppModeOperateHint": "Conduct an agent fleet — decompose, delegate, verify, synthesize",
"AppModeOperateHint": "Coordinate workflows, spawn workers, wait, and dispatch more work",
"VimModeNormal": "-- NORMAL --",
"VimModeInsert": "-- INSERT --",
"VimModeVisual": "-- VISUAL --",
Expand Down
24 changes: 11 additions & 13 deletions crates/tui/src/commands/groups/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,7 @@ pub fn set_config_value(app: &mut App, key: &str, value: &str, persist: bool) ->
" (session only, add --save to persist)".to_string()
};
let mode_hint = if enabled {
" Agent mode will expose shell on the next turn with approval gating. YOLO also enables shell and auto-approves."
" Agent mode will expose shell on the next turn with approval gating. Bypass permissions (Shift+Tab) also enables shell and auto-approves."
} else {
" Shell tools will be hidden on the next turn. Re-enable with `/config allow_shell true`."
};
Expand Down Expand Up @@ -1853,9 +1853,7 @@ pub fn mode(app: &mut App, arg: Option<&str>) -> CommandResult {
CommandResult::message(message)
}
}
None => {
CommandResult::error("Usage: /mode [act|agent|plan|multitask|operate|yolo|1|2|3|5|4]")
}
None => CommandResult::error("Usage: /mode [act|agent|plan|operate|1|2|3]"),
}
}

Expand Down Expand Up @@ -2521,7 +2519,8 @@ Parse error: permissions.toml at permissions.toml could not be parsed: expected
// user settings on the host machine.
let _ = mode(&mut app, Some("agent"));
let result = mode(&mut app, Some("yolo"));
assert!(result.message.unwrap().contains("Switched to YOLO mode"));
// YOLO is invisible Act+Bypass shorthand — user-facing copy says Act.
assert!(result.message.unwrap().contains("Switched to Act mode"));
assert_eq!(result.action, Some(AppAction::ModeChanged(AppMode::Yolo)));
assert!(app.allow_shell);
assert!(app.trust_mode);
Expand All @@ -2545,17 +2544,14 @@ Parse error: permissions.toml at permissions.toml could not be parsed: expected
let _ = mode(&mut app, Some("plan"));
assert_eq!(app.mode, AppMode::Plan);
let result = mode(&mut app, Some("3"));
assert_eq!(
result.action,
Some(AppAction::ModeChanged(AppMode::Multitask))
);
assert_eq!(app.mode, AppMode::Multitask);
let result = mode(&mut app, Some("5"));
assert_eq!(
result.action,
Some(AppAction::ModeChanged(AppMode::Operate))
);
assert_eq!(app.mode, AppMode::Operate);
let result = mode(&mut app, Some("5"));
assert!(result.is_error);
assert_eq!(app.mode, AppMode::Operate);
let result = mode(&mut app, Some("9"));
assert!(result.is_error);
assert_eq!(app.mode, AppMode::Operate);
Expand Down Expand Up @@ -2853,7 +2849,9 @@ Parse error: permissions.toml at permissions.toml could not be parsed: expected
assert!(msg.contains("Agent mode"));
assert!(msg.contains("approval gating"));
assert!(msg.contains("next turn"));
assert!(msg.contains("YOLO also enables shell and auto-approves"));
assert!(
msg.contains("Bypass permissions (Shift+Tab) also enables shell and auto-approves")
);
}

#[test]
Expand All @@ -2876,7 +2874,7 @@ Parse error: permissions.toml at permissions.toml could not be parsed: expected
assert_eq!(
msg,
format!(
"allow_shell = true (saved to {}). Agent mode will expose shell on the next turn with approval gating. YOLO also enables shell and auto-approves.",
"allow_shell = true (saved to {}). Agent mode will expose shell on the next turn with approval gating. Bypass permissions (Shift+Tab) also enables shell and auto-approves.",
config_path.display()
)
);
Expand Down
4 changes: 1 addition & 3 deletions crates/tui/src/commands/groups/config/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@ fn permission_summary(app: &App) -> String {
fn safety_summary(app: &App) -> &'static str {
match app.mode {
AppMode::Plan => "sandbox read-only, network off",
AppMode::Agent | AppMode::Auto | AppMode::Multitask | AppMode::Operate => {
"sandbox workspace-write, network on"
}
AppMode::Agent | AppMode::Auto | AppMode::Operate => "sandbox workspace-write, network on",
AppMode::Yolo => "sandbox disabled, network unrestricted",
}
}
Expand Down
10 changes: 1 addition & 9 deletions crates/tui/src/commands/groups/core/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,17 +610,10 @@ pub fn home_dashboard(app: &mut App) -> CommandResult {
let _ = writeln!(stats, "{}", tr(locale, MessageId::HomeYoloModeTip));
let _ = writeln!(stats, "{}", tr(locale, MessageId::HomeYoloModeCaution));
}
AppMode::Multitask => {
let _ = writeln!(stats, "{}", tr(locale, MessageId::HomeAgentModeTip));
let _ = writeln!(
stats,
" Multitask: light delegation — session model is operator; background workers"
);
}
AppMode::Operate => {
let _ = writeln!(
stats,
" Operate: Fleet operator — /model route; decompose into workflow/Fleet; monitor"
" Operate: coordinate workflows, spawn workers, wait on results, dispatch more work"
);
}
AppMode::Plan => {
Expand Down Expand Up @@ -1383,7 +1376,6 @@ mod tests {
AppMode::Auto,
AppMode::Yolo,
AppMode::Plan,
AppMode::Multitask,
AppMode::Operate,
];
for mode in modes {
Expand Down
2 changes: 1 addition & 1 deletion crates/tui/src/config_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ impl From<&str> for TranscriptSpacingValue {
impl From<&str> for DefaultModeValue {
fn from(value: &str) -> Self {
match AppMode::from_setting(value) {
AppMode::Agent | AppMode::Multitask | AppMode::Operate => Self::Agent,
AppMode::Agent | AppMode::Operate => Self::Agent,
AppMode::Plan => Self::Plan,
AppMode::Auto => Self::Agent,
AppMode::Yolo => Self::Yolo,
Expand Down
34 changes: 14 additions & 20 deletions crates/tui/src/core/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub(crate) struct EffectiveModePolicy {
/// - `Plan` -> read-only: no shell, no trust, `Suggest` approvals.
/// - `Agent` -> the user's durable baseline (`prefs`).
/// - `Auto` -> compatibility alias for Agent; not a separate behavior.
/// - `Multitask` / `Operate` -> Agent baseline plus orchestration posture in prompts.
/// - `Operate` -> Agent baseline plus orchestration posture in prompts.
/// - `Yolo` -> legacy compat; full authority: shell + trust + `Bypass` approvals.
#[must_use]
pub(crate) fn base_policy_for_mode(mode: AppMode, prefs: &ModeSessionPrefs) -> EffectiveModePolicy {
Expand All @@ -53,14 +53,12 @@ pub(crate) fn base_policy_for_mode(mode: AppMode, prefs: &ModeSessionPrefs) -> E
trust_mode: false,
approval_mode: ApprovalMode::Suggest,
},
AppMode::Agent | AppMode::Auto | AppMode::Multitask | AppMode::Operate => {
EffectiveModePolicy {
mode,
allow_shell: prefs.agent_allow_shell,
trust_mode: prefs.agent_trust_mode,
approval_mode: prefs.agent_approval_mode,
}
}
AppMode::Agent | AppMode::Auto | AppMode::Operate => EffectiveModePolicy {
mode,
allow_shell: prefs.agent_allow_shell,
trust_mode: prefs.agent_trust_mode,
approval_mode: prefs.agent_approval_mode,
},
AppMode::Yolo => EffectiveModePolicy {
mode,
allow_shell: true,
Expand Down Expand Up @@ -195,14 +193,12 @@ pub(crate) fn agent_approval_mode_for_turn(
pub(crate) fn sandbox_policy_for_mode(mode: AppMode, workspace: &Path) -> SandboxPolicy {
match mode {
AppMode::Plan => SandboxPolicy::ReadOnly,
AppMode::Agent | AppMode::Auto | AppMode::Multitask | AppMode::Operate => {
SandboxPolicy::WorkspaceWrite {
writable_roots: vec![workspace.to_path_buf()],
network_access: true,
exclude_tmpdir: false,
exclude_slash_tmp: false,
}
}
AppMode::Agent | AppMode::Auto | AppMode::Operate => SandboxPolicy::WorkspaceWrite {
writable_roots: vec![workspace.to_path_buf()],
network_access: true,
exclude_tmpdir: false,
exclude_slash_tmp: false,
},
AppMode::Yolo => SandboxPolicy::DangerFullAccess,
}
}
Expand All @@ -215,8 +211,6 @@ pub(crate) fn shell_policy_for_mode(mode: AppMode, allow_shell: bool) -> ShellPo
}
match mode {
AppMode::Plan => ShellPolicy::None,
AppMode::Agent | AppMode::Auto | AppMode::Multitask | AppMode::Operate | AppMode::Yolo => {
ShellPolicy::Full
}
AppMode::Agent | AppMode::Auto | AppMode::Operate | AppMode::Yolo => ShellPolicy::Full,
}
}
4 changes: 1 addition & 3 deletions crates/tui/src/core/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,11 +674,9 @@ fn subagent_mailbox_best_effort_send_permitted(
impl Engine {
fn mode_runtime_instructions(mode: AppMode) -> &'static str {
match mode {
AppMode::Agent | AppMode::Auto => prompts::AGENT_MODE,
AppMode::Agent | AppMode::Auto | AppMode::Yolo => prompts::AGENT_MODE,
AppMode::Plan => prompts::PLAN_MODE,
AppMode::Multitask => prompts::MULTITASK_MODE,
AppMode::Operate => prompts::OPERATE_MODE,
AppMode::Yolo => prompts::YOLO_MODE,
}
.trim()
}
Expand Down
6 changes: 4 additions & 2 deletions crates/tui/src/core/engine/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3696,10 +3696,12 @@ fn mode_invariant_matrix_covers_context_catalog_subagents_and_prompt_metadata()
plan_hint: false,
},
ModeCase {
// YOLO remains an elevated-permission alias, but prompt/setting
// surfaces now speak Act (invisible one-way permission shorthand).
name: "yolo",
mode: AppMode::Yolo,
setting: "yolo",
prompt_marker: "##### Mode: YOLO",
setting: "agent",
prompt_marker: "##### Mode: Agent",
shell_policy: ShellPolicy::Full,
sandbox: ExpectedSandbox::DangerFullAccess,
trust_mode: true,
Expand Down
4 changes: 0 additions & 4 deletions crates/tui/src/localization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,13 +621,11 @@ pub enum MessageId {
AppModeAuto,
AppModeYolo,
AppModePlan,
AppModeMultitask,
AppModeOperate,
AppModeAgentHint,
AppModeAutoHint,
AppModePlanHint,
AppModeYoloHint,
AppModeMultitaskHint,
AppModeOperateHint,
VimModeNormal,
VimModeInsert,
Expand Down Expand Up @@ -1375,13 +1373,11 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[
MessageId::AppModeAuto,
MessageId::AppModeYolo,
MessageId::AppModePlan,
MessageId::AppModeMultitask,
MessageId::AppModeOperate,
MessageId::AppModeAgentHint,
MessageId::AppModeAutoHint,
MessageId::AppModePlanHint,
MessageId::AppModeYoloHint,
MessageId::AppModeMultitaskHint,
MessageId::AppModeOperateHint,
MessageId::VimModeNormal,
MessageId::VimModeInsert,
Expand Down
Loading
Loading