So I changed the behavior after the first approved action in a chat conversation.
Once the user approves the first execution tool for the task, CliGate flips a conversation flag that lets later steps continue without another approval roundtrip. The assistant still feeds the real tool result back into the continuation run, so it can keep working from what actually happened instead of pretending the approval itself completed the task.
The escape hatch matters too:
/safe
That turns the conversation back into explicit confirmation mode.
The continuation had to carry the real result
There was another subtle part.
When a user approves a pending action, the system cannot just say "confirmed" and stop. It has to continue the original job.
The continuation prompt now tells the assistant that the previous tool call was approved, already executed, and produced a real result. That stops the assistant from asking for the same approval again or forgetting why the tool ran in the first place.
This made the assistant feel much less like a form with a chatbot attached to it. The flow became:
- ask once for the risky boundary
- execute the first step
- continue the task with real observations
- only interrupt again when the user explicitly returns to safe mode or a genuinely different boundary appears
The interesting part is that the fix is not "disable approvals." It is "remember what approval was for."
I also hit a language bug
This same continuation path exposed a smaller but very visible bug.
The continuation message was system-generated and written in English. When the original user task was Chinese, the assistant sometimes detected the system continuation as the latest "user" text and switched the next confirmation prompt to English.
That produced an ugly mixed-language workflow: first approval in Chinese, later approval prompts in English.
The fix was simple in principle: system-authored continuation turns should not decide the reply language. The assistant now looks back to the latest genuine user message in the conversation before choosing the response language.
That is the kind of detail that seems minor until you use the tool for a multi-step task. Then it is the difference between "this assistant is tracking me" and "this assistant is reacting to its own plumbing."
The rule I am keeping
I do not think agent approval should be all-or-nothing.
For local tools, the useful middle ground is task-scoped trust:
- ask before crossing a meaningful boundary
- remember that approval for the current task
- keep an obvious way to return to strict mode
- do not let system continuation messages masquerade as user intent
That is now how I am shaping approvals in CliGate, the local control plane I use for Claude Code, Codex CLI, Gemini CLI, desktop automation, channels, and model routing.
The project is open source here: CliGate.
If you are building local agents, how are you handling approval fatigue: per tool call, per task, per session, or something more granular?