From 99d8493008bf70e1e20d305928b236c317bb980e Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Fri, 25 Sep 2026 09:54:29 -0700 Subject: [PATCH] Warn that Auto falls back to prompting when unavailable Claude Code starts in its prompting mode when auto isn't available for the session's model or backend, so a headless Auto task can still stall. Say so in the task editor, the task runner comment, and HOW-TO-USE. Co-Authored-By: Claude Opus 5.5 (1M context) --- HOW-TO-USE.md | 8 +++++--- app/src/components/projects/home/TaskEditorModal.test.tsx | 3 ++- app/src/components/projects/home/TaskEditorModal.tsx | 7 ++++--- container/triple-c-task-runner | 7 ++++--- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/HOW-TO-USE.md b/HOW-TO-USE.md index ce29584..d2b97ab 100644 --- a/HOW-TO-USE.md +++ b/HOW-TO-USE.md @@ -484,7 +484,8 @@ the way they did: one that had Full Permissions on becomes **Bypass**, one that **Auto** sits between Accept Edits and Bypass: Claude Code's own classifier reviews each action, lets routine work through and blocks things that look risky (such as destructive or exfiltrating commands) — no prompts either way. Whether it is available depends on your Claude -Code account and model; see Claude Code's documentation on permission modes. +Code account, model and backend (local and OpenAI-compatible backends won't qualify). When it +isn't available, Claude Code quietly starts in its normal prompting mode instead. ### When a change takes effect @@ -502,7 +503,8 @@ Code account and model; see Claude Code's documentation on permission modes. > Scheduled tasks run headless (`claude -p`) and cannot answer a permission prompt. In any mode > other than **Auto** or **Bypass**, a task may simply stop early when Claude Code asks for > approval. In **Auto**, actions the classifier blocks are denied and the run carries on without -> them. Its run log records which mode it used. +> them — but if Auto isn't available for the project's model or backend, Claude Code falls back +> to prompting and the task can stall the same way. Its run log records which mode it used. --- @@ -1357,7 +1359,7 @@ with `--dangerously-skip-permissions`. Because the mode travels into the contain environment variable, **stop and start the project** after changing it for the scheduler to see the change. Remember that a headless run cannot answer a permission prompt, so in any mode other than **Auto** or **Bypass** a task may stop early when Claude Code asks for approval (in Auto, blocked -actions are denied instead); the run log records the mode +actions are denied instead, unless Auto is unavailable and Claude Code falls back to prompting); the run log records the mode that was used. ### Creating Tasks diff --git a/app/src/components/projects/home/TaskEditorModal.test.tsx b/app/src/components/projects/home/TaskEditorModal.test.tsx index 68336e7..62e942e 100644 --- a/app/src/components/projects/home/TaskEditorModal.test.tsx +++ b/app/src/components/projects/home/TaskEditorModal.test.tsx @@ -165,10 +165,11 @@ describe("TaskEditorModal", () => { expect(screen.queryByText(/cannot answer a permission prompt/i)).toBeNull(); }); - it("tells Auto mode that blocked actions are denied, not prompted", async () => { + it("tells Auto mode that blocked actions are denied, and warns of the fallback", async () => { await renderEditor(null, { ...baseProject, permission_mode: "auto" }); expect(screen.queryByText(/cannot answer a permission prompt/i)).toBeNull(); expect(screen.getByText(/blocks are denied/i)).toBeInTheDocument(); + expect(screen.getByText(/falls back to prompting/i)).toBeInTheDocument(); }); it("spells out the stall risk in any non-Bypass mode", async () => { diff --git a/app/src/components/projects/home/TaskEditorModal.tsx b/app/src/components/projects/home/TaskEditorModal.tsx index 4bed6cc..90dc845 100644 --- a/app/src/components/projects/home/TaskEditorModal.tsx +++ b/app/src/components/projects/home/TaskEditorModal.tsx @@ -302,9 +302,10 @@ export default function TaskEditorModal({ project, task, onClose, onSaved }: Pro {modeLabel}).

{mode === "auto" && ( -

- In Auto mode nothing prompts: actions the safety classifier blocks are denied and the - run carries on without them, so check the log if a task seems to have skipped a step. +

+ In Auto mode, actions the safety classifier blocks are denied and the run carries on + without them. If Auto isn’t available for this project’s model or backend, + Claude Code falls back to prompting and the task may stall.

)} {mode !== "bypass" && mode !== "auto" && ( diff --git a/container/triple-c-task-runner b/container/triple-c-task-runner index ceae1e8..ac5922a 100644 --- a/container/triple-c-task-runner +++ b/container/triple-c-task-runner @@ -61,9 +61,10 @@ TASK_TYPE=$(jq -r '.type' "$TASK_FILE") # project's permission setting. Keep this mapping in sync with # PermissionMode::cli_args() in app/src-tauri/src/models/project.rs. # NOTE: headless `claude -p` runs cannot answer a permission prompt, so any -# mode other than "bypass" or "auto" means the task may stop early when Claude -# Code asks for permission. In "auto", actions the classifier blocks are -# denied rather than prompted, so the run continues without them. Unset or unrecognized values pass no flag (Claude's default). +# mode other than "bypass" means the task may stop early when Claude Code asks +# for permission. In "auto", classifier-blocked actions are denied instead of +# prompted, but if auto mode is unavailable for the session's model/backend, +# Claude Code falls back to prompting and the same stall applies. Unset or unrecognized values pass no flag (Claude's default). PERMISSION_ARGS=() case "${TRIPLE_C_PERMISSION_MODE:-}" in plan) PERMISSION_ARGS=(--permission-mode plan) ;;