| name | cliwant-approval-queue |
| description | Human-in-the-loop approval queue for tool-using agents. The agent enqueues an action it wants to take (send email, push commit, file return, charge card); a human reviews and approves/rejects/modifies; the agent picks up the verdict on the next turn. Backed by the @cliwant/mcp-approval-queue MCP server. Triggers on phrases like "queue this for approval", "review this before sending", "wait for human approval", "검토해줘", "승인", "確認して", "承認", or whenever Claude is about to take a real-world action that should not happen unsupervised. |
cliwant-approval-queue
A Claude Code skill that wraps the @cliwant/mcp-approval-queue Model Context Protocol server. Provides a stable approval queue accessible from any Claude / Codex / Gemini session — agents enqueue side-effecting actions, humans review them, agents pick up the verdict.
When to use this skill
Use this skill (and call its underlying MCP tools) whenever:
- The agent is about to take a real-world action with non-trivial cost (sending email, pushing a commit, filing a tax return, charging a card, creating a calendar event on someone else's behalf).
- The user asks for a review step explicitly — "queue this for approval", "review before sending", "검토해줘", "승인 먼저", "確認して送って".
- The agent has prepared a deliverable (email draft, financial statement, code change) and the user's role is to review + approve, not to author from scratch — this is the
AI-Native Agent workflow.
- The user wants to see what the agent has prepared overnight — "show me what's pending", "대기 항목 보여줘", "保留中の項目を見せて".
Do not use this skill for read-only actions (reads, queries, search) or for things the user has already approved verbatim earlier in the same session.
Prerequisite: install the MCP server
The skill calls into MCP tools provided by @cliwant/mcp-approval-queue. Make sure the MCP server is configured in your host (Claude Desktop, Claude Code, Codex CLI, Gemini CLI, Cursor, Cline, etc.).
Quick install (Claude Desktop / Claude Code)
Add to ~/.claude/claude_desktop_config.json (macOS / Linux) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"approval-queue": {
"command": "npx",
"args": ["-y", "@cliwant/mcp-approval-queue"]
}
}
}
Restart the host. The eight tools (queue_for_approval, get_pending, get_decision, approve, reject, modify, wait_for_decision, list_history) become available.
Workflow patterns
1. Agent prepares, then waits for human
This is the canonical AI-Native Agent flow. The agent does the work in advance, queues the deliverable, and blocks on the human's verdict.
Step A — Enqueue:
Call: queue_for_approval
Args: {
"topic": "<scope key — user/<id>, client/<id>, project/<id>>",
"kind": "<one of: email_send | commit_push | tax_filing | charge | … your taxonomy>",
"title": "<short label rendered in the reviewer's dashboard>",
"content": { /* the actual deliverable as JSON — to/subject/body for an email,
diff for a commit, form payload for a filing, etc. */ },
"metadata": { "severity": "high|medium|low", "caller_weight": 0..100 },
"deadline": "<ISO 8601 — when the action loses value>"
}
→ returns { item: { id, priority, status: "pending", … } }
Step B — Wait:
Call: wait_for_decision
Args: { "topic": "<same topic>", "id": "<id from step A>", "timeout_seconds": 30 }
→ returns { item: { status: "approved" | "rejected" | "modified", … }, timed_out: false }
Step C — Act:
if status == "approved" or "modified":
use item.content (which already includes any reviewer patch)
perform the action for real
if status == "rejected":
do nothing; surface the reviewer_note back to the user
if timed_out == true:
re-queue, escalate, or fall back to a default — never silently retry
2. Reviewer dashboard ("show pending")
When the user asks "what's pending?" / "대기 항목 보여줘" / "保留中の項目を見せて":
Call: get_pending
Args: { "topic": "<same scope>", "limit": 32 }
→ returns { items: [{ id, kind, title, priority, deadline, content, metadata, … }, …] }
Render the list in priority order, surfacing the title, priority, deadline, and a one-line summary of content. Offer the user one-click approve / reject / modify shortcuts on each row.
3. Modify (approve with inline edit)
When the reviewer wants to fix a small thing and approve in one shot — for example, tightening an email subject before sending:
Call: modify
Args: {
"topic": "<scope>",
"id": "<item id>",
"patch": { "subject": "Reviewed: …" },
"reviewer_note": "Tighter subject; marked priority=high so ops opens it first."
}
The patch is shallow-merged into content (top-level keys in patch overwrite top-level keys in content; nested objects are replaced wholesale, not deep-merged). was_modified=true is set on the item, and the patch is recorded verbatim on the audit event so a regulator can replay the exact diff.
4. Audit replay ("what did we approve last quarter?")
Call: list_history
Args: {
"topic": "<scope>",
"status_filter": ["approved", "modified", "rejected"],
"since": "2026-01-01T00:00:00Z",
"limit": 100,
"offset": 0
}
→ returns { items, total, limit, offset }
For per-item replay (every transition with timestamps), use get_decision on the id; in embedded hosts you can also reach into store.listEvents(topic, id) directly.
Topic naming convention
Pick a stable identifier that scopes the queue cleanly:
- Per-user:
user/<email or id> — one queue across all that user's projects.
- Per-client (B2B):
client/<id> — used in CRM / accounting agents where the reviewer toggles between client queues.
- Per-project:
project/<repo-name> — useful for IDE / coding agents.
- Per-workflow:
workflow/<name> — when a single user has separate review queues for, say, email vs. commits.
The topic is the isolation boundary. Cross-topic reads are impossible by API construction — request a different topic only when you need that explicit guarantee.
Multi-language
This skill responds to approval-related triggers in English, Korean (한국어), and Japanese (日本語). The MCP server itself is language-agnostic — title, content, and reviewer_note accept any UTF-8 string.
| English | Korean | Japanese |
|---|
| "queue this for review" / "queue for approval" | "이거 검토 큐에 올려줘" / "승인 큐에" | "これを承認待ちにして" / "確認して" |
| "approve" | "승인" | "承認" |
| "reject" | "반려" / "거부" | "却下" |
| "approve with edits" | "수정해서 승인" | "編集して承認" |
| "show pending" / "what's pending" | "대기 항목 보여줘" / "검토할 거 뭐 있어" | "保留中の項目を見せて" |
| "wait for the human" | "사람 결정 기다려" | "人間の判断を待つ" |
| "review this before sending" | "보내기 전에 검토해줘" | "送る前に確認して" |
Priority + sorting
Default priority blend (port of the production scoring used in practiq.dev's approval queue):
priority = clamp(0..100,
deadline_proximity * 0.4
+ severity * 0.35
+ caller_weight * 0.25
)
deadline_proximity — derived from deadline if provided. Today / past-due = 100, 14 days out = 0. Linear interpolation between.
severity — from metadata.severity. Accepts "high" (80), "medium" (40), "low" (20), or a raw 0..100 number. Default 20.
caller_weight — from metadata.caller_weight. Raw 0..100. Default 50.
Pass an explicit priority to skip the computation when the host already has its own scorer. The value is clamped to [0, 100] and used as-is.
Rules of thumb
- Never act without a verdict. If
wait_for_decision returns timed_out: true, do not retry the action silently. Surface the timeout to the user, re-queue with a fresh deadline, or fall back to a clearly safer default (e.g. save as draft instead of send).
- Idempotent verdicts.
approve / reject / modify are idempotent — calling them on an already-settled item returns the existing row unchanged. Use this property to make agent retries safe.
- Preserve the audit trail. Every state transition appends to a per-topic
events table with timestamps. Don't disable it; that's how you replay history for a regulator (or for yourself when something looks wrong).
- Topic isolation is the security boundary. Pick a topic key the reviewer trusts. Cross-topic reads are impossible by API construction — but only if
topic is itself trustworthy. Don't accept topic from arbitrary user input without validation.
Privacy
- All queue state lives on the user's machine by default (
~/.cliwant/approvals.db).
- Postgres mode points at the user's own DB — nothing is sent to cliwant servers.
- Topic isolation is enforced at the storage layer; cross-topic queries don't exist in the API.
License
MIT — same as the underlying npm package. See @cliwant/mcp-approval-queue.