Agentic Covenants

Respond (RS) · Approval gating

Approval gating at the client side layer

deterministic · Outside the model's reasoning

How do I stop the bleeding now?

What this cell does

Replace approval hook with deny-all, disable Auto Mode classifier, disable judgment-query escalation channel, force out-of-band on every action.

Artifacts (1)

agent-approval-lockdown-localview on GitHub
#!/usr/bin/env bash
# ABOUTME: Local approval-gating lockdown runbook. Deny-all hook, Auto Mode off, OOB required, escalation disabled.
# ABOUTME: Re-uses the deny-all hook from interventions/authorization/client-side/. Pre-stage that and BREAK_GLASS_TOKEN.

set -euo pipefail

if [[ $# -lt 1 ]]; then
  echo "Usage: agent-approval-lockdown-local <AGENT_NAME>" >&2
  exit 64
fi

AGENT_NAME="$1"
INCIDENT_ID="$(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')"
EMERGENCY_DIR="${EMERGENCY_DIR:-/etc/agents/emergency}"
SETTINGS_PATH="/etc/agents/${AGENT_NAME}/settings.json"
ESCALATE_URL="${ESCALATE_URL:-https://escalate.example.com}"

if [[ ! -r "$EMERGENCY_DIR/deny-all-hook.sh" ]]; then
  echo "REFUSING: $EMERGENCY_DIR/deny-all-hook.sh not pre-staged" >&2
  exit 1
fi

# 1. Replace approval hook with deny-all (shared with authorization lockdown).
chattr -i /etc/agents/hooks/pre_tool_use.sh 2>/dev/null || true
cp "$EMERGENCY_DIR/deny-all-hook.sh" /etc/agents/hooks/pre_tool_use.sh
chmod 0755 /etc/agents/hooks/pre_tool_use.sh
chattr +i /etc/agents/hooks/pre_tool_use.sh 2>/dev/null || true

# 2. Disable Auto Mode classifier and force out-of-band on every action.
if [[ -r "$SETTINGS_PATH" ]]; then
  TMPFILE="$(mktemp)"
  jq '.permissions.autoMode = false
      | .permissions.requireOutOfBand = true
      | .permissions.judgmentQueryEscalation = false' \
      "$SETTINGS_PATH" > "$TMPFILE"
  mv "$TMPFILE" "$SETTINGS_PATH"
  chmod 0644 "$SETTINGS_PATH"
fi

# 3. Disable judgment-query escalation channel via the service API.
if [[ -n "${BREAK_GLASS_TOKEN:-}" ]]; then
  curl -sS -X POST "$ESCALATE_URL/api/disable" \
    -H "Authorization: Bearer $BREAK_GLASS_TOKEN" \
    -H "Content-Type: application/json" \
    -d "$(jq -n --arg agent "$AGENT_NAME" --arg incident "$INCIDENT_ID" \
            '{agent:$agent, incident:$incident}')" \
    >/dev/null || echo "WARN: escalation-channel disable API call failed" >&2
else
  echo "WARN: BREAK_GLASS_TOKEN unset; escalation channel not disabled" >&2
fi

# 4. Kill the agent so the new state applies on next launch.
pkill -KILL -f "claude.*$AGENT_NAME" 2>/dev/null || true

logger -t agent-incident -p user.warning \
  "$(jq -n \
      --arg event "approval_locked_local" \
      --arg agent "$AGENT_NAME" \
      --arg incident "$INCIDENT_ID" \
      --arg actor "$(whoami)" \
      --arg ts "$(date -Iseconds)" \
      '{event:$event, agent:$agent, incident:$incident, actor:$actor, ts:$ts}')"

echo "Local approval gating locked down for $AGENT_NAME (incident $INCIDENT_ID)"

Cell notes

Interventions, Approval gating / Client-side

Trigger. Sentinels detected approval bypass, fatigue pattern saturation (mean response under 2s across 50+ approvals), judgment-query escalation channel compromise.

Authority. On-call.

Speed target. Under 10 seconds.

Tooling

  • - The hook layout from ../../authorization/client-side/ (this runbook re-uses the deny-all hook).
  • - jq for editing settings.json in place.
  • - API access to your judgment-query escalation service to disable it.

Files in this directory

  • - agent-approval-lockdown-local, runbook script. Replaces the approval hook with the deny-all hook (shared with authorization client-side), disables Auto Mode in settings.json, sets requireOutOfBand: true, disables the judgment-query escalation channel, kills the agent.

Verification


# 1. Auto Mode disabled
jq '.permissions.autoMode' /etc/agents/claude-code-prod/settings.json
# expected: false

# 2. Hook is deny-all
md5sum /etc/agents/hooks/pre_tool_use.sh /etc/agents/emergency/deny-all-hook.sh
# expected: identical

# 3. Escalation channel disabled
curl -sS https://escalate.example.com/api/status?agent=claude-code-prod
# expected: disabled: true

Common mistakes

  • - Disabling Auto Mode but not replacing the hook. Auto Mode disabled means more prompts; the agent still proceeds on the prompts.
  • - Not disabling the escalation channel, the agent escalates to a compromised channel and gets fake approvals.
  • - Settings JSON edited in place; if the original was JSON5 (with comments), the standard jq rewrite breaks it. Use a JSON-comment-aware tool if your config is JSON5.

Citation

NIST CSF 2.0 RS.MI-01. NIST AI RMF MANAGE 4.1. OWASP ASI09. EU AI Act Art. 14 (response dimension).

Primary failure modes

Documented, not hypothetical. A control whose bypass is undocumented is worse than no control, because somebody trusted it.

  • Auto Mode disabled but hook still permissive
  • JSON5 settings broken by jq rewrite

Crosswalk

NIST CSF 2 0RS.MI-01
NIST AI RMFMANAGE 4.1
OWASP AGENTICASI09
OTHEREU AI Act Art. 14 (response dimension)