PromptABCD
FeaturesLearnGuideBlogContext Blocks
Sign inGet started free
Sign inSign up
PromptABCD

A calm home for your best AI prompts. Save them once, find them in seconds, reuse them forever.

Product

  • Features
  • Chrome Extension
  • Free Courses
  • How it works
  • Use cases
  • Blog
  • Context Blocks
  • Export Anywhere
  • FAQ

Resources

  • User guide
  • Learn prompting
  • Sign in
  • Get started free

© 2026 PromptABCD. All rights reserved.

AboutPrivacy PolicyTerms and Conditions
Home/Blog/CLI AI Agents/Building a Confirmation Step Into Your CLI Agent
CLI AI Agents

Building a Confirmation Step Into Your CLI Agent

How do you stop an AI agent from doing something irreversible? A well-built cli agent confirmation prompt gates risky actions, shows a preview of the change, and waits for a deliberate yes.

September 16, 2026·9 min read
ShareShare
⚡Featured Prompt— copy and use right now
RISK = {
    "read_file": "safe", "list_dir": "safe", "grep": "safe",
    "write_file": "write", "run_shell": "write",
    "delete_file": "danger", "deploy": "danger", "drop_table": "danger",
}

def confirm(tool, args):
    level = RISK.get(tool, "danger")   # unknown tools default to danger
    if level == "safe":
        return True
    print(f"\n  Agent wants to run: {tool}({args})")
    prompt = "  Proceed? [y/N] " if level == "write" else "  ⚠ DESTRUCTIVE. Type 'yes' to confirm: "
    reply = input(prompt).strip().lower()
    return reply == "y" if level == "write" else reply == "yes"

How do you stop an AI agent from doing something you can't undo? That's the question that keeps people from giving their terminal agents any real power — and it's the right question to ask. The answer is a well-designed cli agent confirmation prompt: a gate that pauses before consequential actions, shows the user exactly what's about to happen, and waits for a deliberate yes. Get this one pattern right and you can safely hand an agent capabilities you'd never otherwise trust it with.

This guide gives you a copy-paste confirmation gate, then shows how to make it smart enough that it protects users without nagging them into turning it off.

Quick-Start (Copy This Right Now)

Here's a confirmation gate you can drop into any agent loop today. It classifies each tool call by risk and prompts only when the action is consequential.

python
RISK = {
    ,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],,
    ,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],,
    ,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],,
}

,[object Object], ,[object Object],(,[object Object],):
    level = RISK.get(tool, ,[object Object],)   ,[object Object],
    ,[object Object], level == ,[object Object],:
        ,[object Object], ,[object Object],
    ,[object Object],(,[object Object],)
    prompt = ,[object Object], ,[object Object], level == ,[object Object], ,[object Object], ,[object Object],
    reply = ,[object Object],(prompt).strip().lower()
    ,[object Object], reply == ,[object Object], ,[object Object], level == ,[object Object], ,[object Object], reply == ,[object Object],

What this does: Maps each tool to a risk tier, auto-approves safe reads, asks a quick y/N for writes, and demands the full word "yes" for destructive actions. Unknown tools default to the danger tier, so a new capability can't slip through unguarded.

Wire this into your dispatch step so nothing runs without clearing the gate, and you've closed the scariest hole in an agent: the irreversible action taken without a human in the loop.

Understanding the Variables

The risk tiers are the heart of the design. Three levels cover almost everything: safe (reads that change nothing), write (modifies state but is recoverable), and danger (irreversible or high-blast-radius). The point of tiering is friction that matches stakes — you don't want a y/N in front of every cat, and you don't want a bare y/N in front of DROP TABLE.

The default-to-danger rule is deliberate and worth keeping. When a tool isn't in your risk map, treating it as dangerous means adding a capability fails closed — the worst case is an unnecessary prompt, not an unguarded destructive action. Flip that default and every new tool is a latent incident.

The escalation from "y" to "yes" for destructive actions is small but effective. A single keystroke is muscle memory; typing three letters forces a half-second of actual attention, which is exactly when someone catches "wait, that's the production database."

⚡ Pro tip: Make the default answer No. Notice the capital N in [y/N] — an empty Enter press should decline, not proceed. Users mash Enter to clear prompts; if blank means yes, your gate becomes a rubber stamp the first time someone's not paying attention.

Why Does a cli agent confirmation prompt Need a Preview?

Because "Proceed? [y/N]" with no context is a question the user can't answer well. A confirmation is only as good as the information it shows. For write and destructive actions, render what will change — a diff, a file list, the exact command — not just the tool name.

python
[object Object], ,[object Object],(,[object Object],):
    ,[object Object], tool == ,[object Object],:
        old = read_if_exists(args[,[object Object],])
        ,[object Object], unified_diff(old, args[,[object Object],], args[,[object Object],])
    ,[object Object], tool == ,[object Object],:
        ,[object Object], ,[object Object],
    ,[object Object], tool == ,[object Object],:
        ,[object Object], ,[object Object],
    ,[object Object], ,[object Object],

What this does: Produces a human-readable preview of the pending action — a real diff for file writes, the literal command for shell, an explicit warning for deletes. The user confirms a concrete change they can see, not an abstract tool name they have to imagine.

This is the difference between a confirmation that protects people and one that trains them to ignore it. Show a diff and users actually catch the agent about to overwrite the wrong file. Show only "write_file? [y/N]" and they approve on faith, which defeats the entire point of asking.

⚠️ Common mistake: Prompting without showing the change. A confirmation the user can't evaluate is worse than none — it adds friction while providing false assurance, and it conditions people to approve reflexively. Always pair the prompt with a preview of exactly what happens if they say yes.

Step-by-Step: Adding Session-Scoped Approvals

The fastest way to get users to disable your confirmation gate is to ask the same question forty times. A good gate remembers. When a user approves a class of action, offer to stop asking for the rest of the session.

python
session_allow = ,[object Object],()

,[object Object], ,[object Object],(,[object Object],):
    level = RISK.get(tool, ,[object Object],)
    ,[object Object], level == ,[object Object], ,[object Object], tool ,[object Object], session_allow:
        ,[object Object], ,[object Object],
    ,[object Object],(preview(tool, args))
    reply = ,[object Object],(,[object Object],).strip().lower()
    ,[object Object], reply == ,[object Object], ,[object Object], level != ,[object Object],:   ,[object Object],
        session_allow.add(tool)
        ,[object Object], ,[object Object],
    ,[object Object], reply == ,[object Object],

What this does: Adds an "always this session" option that suppresses future prompts for that tool — but refuses to blanket-approve destructive actions, which always re-prompt. Frequent, recoverable actions stop nagging; irreversible ones never get a free pass.

The step-by-step to adopt this: start with everything gated, watch which prompts users approve every single time, offer session-scoped approval for exactly those, and keep destructive actions always-confirm no matter what. You're tuning friction toward the actions that actually warrant a human's attention.

⚡ Pro tip: Log every confirmation decision — approved, declined, and which tier. The tools users always approve are candidates for the safe tier; the ones they often decline are telling you the agent is proposing bad actions, which is a prompt-quality signal you'd otherwise miss.

Pro-Level Variations

Teams adapt the gate to their risk profile in ways worth stealing.

A site reliability engineer ties the danger tier to environment: the same restart_service tool is a y/N in staging and a type-the-service-name confirmation in production, because blast radius depends on where you're pointed.

A database administrator adds a row-count preview to any destructive query — "this DELETE affects 4,182 rows" — so a missing WHERE clause is caught by the number being absurdly large before anything runs.

A machine learning engineer running expensive training jobs gates on cost, not just danger: any action estimated over a dollar threshold shows the projected spend and requires explicit approval, turning surprise bills into deliberate decisions.

Each is the same gate with a richer preview and a context-aware tier. The skeleton doesn't change; the judgment about what deserves friction does.

⚡ Pro tip: Never put a timeout on a confirmation prompt that auto-approves when it expires. It sounds convenient — "proceed if no answer in 10 seconds" — but it's the worst possible default, because a distracted user's inaction becomes a yes to something irreversible. If you must time out, time out to No.

Confirming a Multi-Step Plan at Once

Per-action prompts break down when an agent proposes a plan — five actions to accomplish one goal. Confirming each one separately is exhausting and, worse, robs the user of the big picture: they approve step three without seeing that step five deletes something. The better pattern confirms the whole plan up front, as a reviewable list, before executing any of it.

python
[object Object], ,[object Object],(,[object Object],):
    ,[object Object],(,[object Object],)
    ,[object Object], i, (tool, args) ,[object Object], ,[object Object],(steps, ,[object Object],):
        marker = ,[object Object], ,[object Object], RISK.get(tool) == ,[object Object], ,[object Object], ,[object Object],
        ,[object Object],(,[object Object],)
    reply = ,[object Object],(,[object Object],).strip().lower()
    ,[object Object], reply == ,[object Object],:
        drop = ,[object Object],(,[object Object],)
        skip = {,[object Object],(x) ,[object Object], x ,[object Object], drop.replace(,[object Object],, ,[object Object],).split(,[object Object],) ,[object Object], x}
        ,[object Object], [s ,[object Object], i, s ,[object Object], ,[object Object],(steps, ,[object Object],) ,[object Object], i ,[object Object], ,[object Object], skip]
    ,[object Object], steps ,[object Object], reply == ,[object Object], ,[object Object], []

What this does: Renders the full sequence of proposed actions with danger steps flagged, then lets the user approve, edit (drop specific steps), or reject the whole plan. The user reviews the entire blast radius before anything runs, and can surgically remove the one step they don't like.

Plan-level confirmation matches how people actually reason about risk. Nobody evaluates a deploy one command at a time — they want to see "pull, migrate, restart, verify" as a unit and judge it whole. Showing the plan also surfaces a bad idea earlier: a user spots "step 4: drop_table" in the list and cancels before step one, instead of discovering it three prompts deep.

⚡ Pro tip: Keep destructive steps as inline confirmations even inside an approved plan. Approving a five-step plan shouldn't silently green-light a drop_table buried at step four — re-confirm the danger-tier action when you actually reach it. Plan approval handles the routine steps; irreversible ones still earn their own moment.

Troubleshooting Common Issues

If users complain the agent is slow to use, you're probably gating safe reads — audit your risk map and demote anything that only inspects state. If a destructive action ever slips through, check that unknown tools default to danger and that your dispatch actually calls the gate before every execution, not just some.

If people have started reflexively approving everything, your previews are too thin — add diffs and row counts so each prompt carries real information. And if an automated pipeline needs to run the agent unattended, don't remove the gate; add an explicit --yes flag that auto-approves write-tier actions while still refusing danger-tier ones, so scripts run smoothly but a drop_table still can't happen silently.

Watch out for the non-interactive edge case too. If your agent runs somewhere with no attached terminal — a cron job, a CI step, a piped invocation — a blocking input() call will either hang or throw, because there's no keyboard to read from. Detect that early: check sys.stdin.isatty() at startup, and in a non-interactive context, treat the absence of an explicit --yes as a hard stop for anything above the safe tier rather than silently prompting into the void. Failing closed here means an unattended agent that hits a write action stops and reports "confirmation required" instead of freezing forever or, worse, finding some default that runs the action unreviewed.

Finally, keep a record. Every confirmation the user approves or declines is worth logging with a timestamp, because the first time someone asks "did the agent really do that," an audit trail of who confirmed what turns an argument into a lookup.

Your Turn

Take your agent's tool list, assign each tool a risk tier, add previews for the write and danger tiers, and make blank-Enter mean No. You'll have a gate that lets you safely expand what the agent can do, because every consequential action now passes through a human who can actually see what's coming.

The previews and confirmation wording you write — the diff format, the "type yes to confirm" phrasing, the tier definitions — are reusable assets that encode your team's safety norms. Keeping them in a prompt library like PromptABCD means your next agent starts with the same well-tuned cli agent confirmation prompt instead of a naked y/N, and your safety bar carries forward by default.

cli agentsconfirmationsafetyai agentsterminalguardrails

Continue Reading

Managing Reusable Prompts for Terminal Workflows
CLI AI Agents

Managing Reusable Prompts for Terminal Workflows

Retyping your best prompt from memory loses its refinements every time. Managing cli agent reusable prompts as named, parameterized, versioned assets keeps the prompt quality you earned — and lets you share it.

September 19, 2026·9 min read
Distributing System Prompts With Your CLI Tool
CLI AI Agents

Distributing System Prompts With Your CLI Tool

Hardcoding your agent's system prompt as a string is the wrong place for it. Treating cli agent system prompt distribution as content — versioned, overridable, updatable — is how prompts evolve independently of code.

September 19, 2026·9 min read
Building a Plugin System for Your CLI Agent
CLI AI Agents

Building a Plugin System for Your CLI Agent

How do you let people add tools to your agent without forking it? A cli agent plugin system lets users extend the agent with their own tools. Here's how to rebuild a hardcoded tool list into a real plugin system.

September 19, 2026·8 min read

Save the prompts from this post

PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.

Start free →
← PreviousHandling Interactive Prompts in a CLI AgentNext →How to Add MCP Servers to a CLI Agent
Share this post:
ShareShare