ClawedBack oc-approve
Approval gate for dangerous operations. Use internally before executing destructive commands, file deletions, git pushes, or external API calls from the web chat. Do NOT invoke directly.
git clone https://github.com/reedmayhew18/ClawedBack
T=$(mktemp -d) && git clone --depth=1 https://github.com/reedmayhew18/ClawedBack "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/oc-approve" ~/.claude/skills/reedmayhew18-clawedback-oc-approve && rm -rf "$T"
.claude/skills/oc-approve/SKILL.mdApproval Gate
Human-in-the-loop safety gate for dangerous operations requested through the web chat.
When to Require Approval
Always require approval before:
- Running shell commands that modify or delete files
- Running
,git push
, or destructive git operationsgit reset - Making external API calls or sending data to third parties
- Installing packages or modifying system state
- Any operation the user didn't explicitly request
How It Works
Step 1: Request Approval
Write an approval request to the outgoing queue:
cd $PROJECT_ROOT/.claude/skills/oc-poll/scripts && python queue_manager.py write '{ "content": "I need your approval to run:\n\n```\nrm -rf old_backups/\n```\n\nThis will permanently delete the old_backups directory. Reply **yes** to approve or **no** to deny.", "type": "approval_request", "metadata": {"action_id": "<unique_id>", "action": "bash", "command": "rm -rf old_backups/"} }'
Step 2: Record Pending Approval
Add the pending approval to the session file (
data/sessions/conversation.json):
{ "pending_approvals": [ { "id": "<unique_id>", "action": "bash", "command": "rm -rf old_backups/", "requested": 1700000000.0, "description": "Delete old_backups directory" } ] }
Step 3: Wait
Do NOT execute the operation. The next poll cycle will pick up the user's response.
Step 4: Resolve (handled by oc-router)
When the router sees a "yes"/"approve" or "no"/"deny" message and there's a pending approval:
- Approved: Execute the operation, remove from pending, confirm completion
- Denied: Remove from pending, acknowledge the denial
- Expired: Approvals older than 1 hour are auto-denied
Pre-Approved Operations (Allowlist)
These operations do NOT require approval:
- Reading files anywhere on the system
- Writing files within
$PROJECT_ROOT/ - Running Python scripts within
$PROJECT_ROOT/ - Web searches and web fetches
- Creating/listing cron jobs within the session
Approval Message Format
Be clear and specific:
- State exactly what will happen
- Show the exact command
- Mention if it's irreversible
- Ask for yes/no
Multi-Step Approval Chains
For tasks that need multiple sequential human approvals (e.g., migrate → test → deploy), use a workflow chain instead of individual gates.
Creating a Chain
Define all steps upfront, persist them to
data/sessions/workflows.json, then queue only step 1's approval.
Step 1: Write the workflow to disk
# Read existing workflows (or start fresh) cat $PROJECT_ROOT/data/sessions/workflows.json 2>/dev/null || echo '{"workflows":{}}'
Add the new workflow:
{ "workflow_id": "<unique-id>", "workflow_name": "Human-readable name", "total_steps": 3, "current_step": 1, "status": "in_progress", "steps": [ {"step": 1, "description": "What step 1 does", "action": "bash", "command": "the command", "status": "pending", "approved_at": null, "executed_at": null}, {"step": 2, "description": "What step 2 does", "action": "bash", "command": "the command", "status": "waiting", "approved_at": null, "executed_at": null}, {"step": 3, "description": "What step 3 does", "action": "bash", "command": "the command", "status": "waiting", "approved_at": null, "executed_at": null} ], "created": 1700000000.0, "cancelled_at": null, "completed_at": null }
Write to
data/sessions/workflows.json. This file survives crashes and restarts.
Step 2: Queue the first step's approval
cd $PROJECT_ROOT/.claude/skills/oc-poll/scripts && python queue_manager.py write '{ "content": "**Workflow: Deploy v2** (Step 1/3)\n\nI need to run database migrations:\n```\npython manage.py migrate\n```\n\nApprove? Reply **yes** to proceed or **no** to cancel the workflow.", "type": "approval_request", "metadata": {"workflow_id": "<id>", "step": 1, "total_steps": 3} }'
Step 3: Record in pending_approvals
Add to session's
pending_approvals with the workflow fields:
{ "id": "<id>-step1", "workflow_id": "<id>", "workflow_name": "Deploy v2", "step": 1, "total_steps": 3, "action": "bash", "command": "python manage.py migrate", "description": "Run database migrations", "requested": 1700000000.0 }
Chain Resolution (handled by oc-router)
When an approval with
workflow_id is resolved:
Approved:
- Execute the action
- Update
: current step →workflows.json
, setstatus: "executed"
andapproved_atexecuted_at - If there's a next step: set it to
, incrementstatus: "pending"
, queue its approval requestcurrent_step - If it was the last step: set workflow
,status: "completed"
timestamp. Send: "Workflow 'name' complete — all N steps approved and executed."completed_at
Denied:
- Do NOT execute
- Update
: workflowworkflows.json
,status: "cancelled"
timestampcancelled_at - Send: "Workflow 'name' cancelled at step N/M."
Expired (>1 hour):
- Same as denied — cancel the entire workflow
Approval Message Format for Chains
Always show progress:
**Workflow: Deploy v2** (Step 2/3) Step 1 ✅ Run database migrations — completed Step 2 ➡️ Run full test suite — awaiting approval Step 3 ⏳ Deploy to production — waiting I need to run: ```pytest``` Approve? Reply **yes** to proceed or **no** to cancel the workflow.
Single Gates vs Chains
- No
→ single gate, works exactly as beforeworkflow_id - Has
→ part of a chain, follows the workflow lifecycle aboveworkflow_id
Both types coexist in
pending_approvals. They don't interfere with each other.