Stop Claude Code from running rm -rf, force push, and DROP TABLE: a PreToolUse hook you can ship today

Stop Claude Code from running rm -rf, force push, and DROP TABLE: a PreToolUse hook you can ship today

A 150-line Python PreToolUse hook for Claude Code that blocks destructive Bash commands (rm -rf, force push, DROP TABLE, kubectl delete, curl exfil) before they run. One-liner install, team rollout via just up.

claude-codesecuritydevopspython

Claude Code is an agent. Agents run shell commands. Sooner or later one of them will try rm -rf, git push --force, or DROP TABLE on something you care about. CLAUDE.md rules are soft, the model ignores them when it’s confident. A PreToolUse hook is hard: the command never runs.

TL;DR: wire a Python script into ~/.claude/settings.json under PreToolUseBash. The script reads the command from stdin, regex-matches it against a blocklist, prints {"decision": "block"} if any rule fires. Ship the hook and an installer with your repo. Call the installer from the command your team runs every morning (just up, make dev, whatever) and it auto-updates across every dev machine. Full hook source is at the bottom of this post.

One-liner install

Generic blocklist on your machine, right now:

curl -fsSL https://simion.cv/scripts/secure-claude.sh | bash

Idempotent. Writes ~/.claude/hooks/prevent-destructive-commands.py, patches ~/.claude/settings.json, preserves any other hooks you already have. Restart Claude Code after running. Read the script first if you don’t trust random curl-bashers: simion.cv/scripts/secure-claude.sh.

The rest of this post is the story, the rules, and how to ship this to your whole team without anyone having to remember anything.

Why you want this

Claude Code can run any shell command. CLAUDE.md rules are advisory, the model ignores them under confidence. Approval dialogs fail to approval fatigue, you approve fifty commands a session and by the thirtieth you are not reading them. One missed kubectl delete, one ./manage.py flush against the wrong DB, one git reset --hard on the wrong branch, and you spend the afternoon restoring from a dump.

Design brief: allow reads, block writes. Let the agent debug freely (pod logs, SELECT, kubectl get, git status). Don’t let it mutate anything (kubectl apply/delete, DROP TABLE, rm -rf, force push). Plus kill the prompt-injection exfil path (curl writes to non-local URLs), which is a real attack surface Simon Willison has been documenting for two years.

Two failure modes it catches:

  1. Confused agent. Claude globs the wrong directory, resets the wrong branch, drops what it thinks is the test DB. Fast, confident, wrong.
  2. Prompt injection. Untrusted content (README, issue comment, scraped page) instructs the model to exfil secrets. Hook blocks the outbound write.

CLAUDE.md is soft. A PreToolUse hook is hard: runs before the tool, says no, the tool call never dispatches.

What a Claude Code PreToolUse hook actually is

This is the part Anthropic’s docs underbill. Hooks are shell commands that run before or after any tool call. They are configured in ~/.claude/settings.json (user scope) or .claude/settings.json (project scope). The useful hook type for safety is PreToolUse.

The shape:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /Users/you/.claude/hooks/prevent-destructive-commands.py"
          }
        ]
      }
    ]
  }
}

matcher: "Bash" means “run this before every Bash tool call”. The command receives JSON on stdin with the full tool call payload. The useful field is tool_input.command, the string Claude wants to run. The hook prints JSON on stdout. {"decision": "block", "reason": "..."} aborts the call and shows the reason to Claude. {"decision": "approve"} lets it through.

That’s the entire protocol. Any language works. I picked Python because it ships with macOS, no deps, one file.

Other matchers exist (Write, Edit, Read, WebFetch, MCP tool names). This post is about Bash specifically because that’s where destructive actions live. Writing a hook for Write to prevent clobbering .env is a future post.

The hook, readable

Single Python file, no dependencies. The structure I landed on after two rewrites: config at the top as plain data, logic at the bottom, zero cleverness in between. Anyone on the team can add a rule without reading my regex brain.

#!/usr/bin/env python3
"""Claude Code PreToolUse hook: blocks destructive Bash commands."""

# ══════════════════════════════════════════════════════════════════════
#  CONFIG — edit this section
# ══════════════════════════════════════════════════════════════════════
#
# Each BLOCK rule is a tuple: (name, regex, reason).
# If the regex matches the command, the command is blocked and "reason"
# is shown to Claude. First match wins.
#
# Each ALLOW rule is a tuple: (name, regex). ALLOW wins over BLOCK.
# Use it to whitelist safe variants, e.g. rm -rf under ./tmp.

BLOCK = [
    # ── File destruction ─────────────────────────────────────────────
    ("rm -rf",           r"\brm\s+(-[a-z]*[rf]\s+)*-[a-z]*[rf][rf]",  "rm -rf blocked"),
    ("rm --recursive",   r"\brm\s+--recursive\b",                      "rm --recursive blocked"),

    # ── Git footguns ─────────────────────────────────────────────────
    ("git push --force", r"\bgit\s+push\b.*(--force|-[a-z]*f)",        "git force push blocked"),
    ("git reset --hard", r"\bgit\s+reset\s+--hard\b",                  "git reset --hard blocked"),
    ("git clean -f",     r"\bgit\s+clean\s+-[a-z]*f",                  "git clean -f blocked"),
    ("git add -A/--all", r"\bgit\s+add\s+(-[a-zA-Z]*A\b|--all\b)",    "git add -A blocked — stage files explicitly"),

    # ── Remote access ────────────────────────────────────────────────
    ("ssh",              r"\bssh\s+\S",                                "ssh blocked"),
    ("scp",              r"\bscp\s+\S",                                "scp blocked"),
    ("sftp",             r"\bsftp\b",                                  "sftp blocked"),
    ("telnet",           r"\btelnet\b",                                "telnet blocked"),
    ("netcat",           r"\b(?:netcat|nc)\s+-",                       "netcat blocked"),
    ("rsync remote",     r"\brsync\b.*:",                              "rsync to remote blocked"),

    # ── Infra / deploy ───────────────────────────────────────────────
    ("terraform write",  r"\bterraform\s+(?:apply|destroy)\b",         "terraform write blocked"),
    ("pulumi write",     r"\bpulumi\s+(?:up|destroy)\b",               "pulumi write blocked"),
    ("docker push",      r"\bdocker\s+push\b",                         "docker push blocked"),
    ("docker exec",      r"\bdocker\s+exec\b",                         "docker exec blocked"),
    ("ansible",          r"\bansible(?:-playbook|-pull)?\b",           "ansible blocked"),

    # ── kubectl mutations ────────────────────────────────────────────
    ("kubectl mutate",
     r"\b(?:kubectl|k|ksys)\s+"
     r"(?:delete|drain|cordon|uncordon|taint|patch|edit|apply|create|exec|run|set|annotate|label|cp)\b",
     "kubectl mutation blocked"),
    ("kubectl rollout write", r"\b(?:kubectl|k|ksys)\s+rollout\s+(?:undo|restart)\b",
     "kubectl rollout write blocked"),
    ("kubectl scale to 0", r"\b(?:kubectl|k|ksys)\s+scale\s+.*--replicas=0\b",
     "kubectl scale to 0 blocked"),

    # ── Helm writes ──────────────────────────────────────────────────
    ("helm write", r"\bhelm\s+(?:install|upgrade|uninstall|delete|rollback)\b", "helm write blocked"),

    # ── Django / framework ───────────────────────────────────────────
    ("manage.py flush", r"\bmanage\.py\s+flush\b", "manage.py flush blocked"),

    # ── Destructive SQL ──────────────────────────────────────────────
    ("DROP",          r"(?i)\bDROP\s+(?:TABLE|DATABASE|SCHEMA)\b", "destructive SQL blocked"),
    ("TRUNCATE",      r"(?i)\bTRUNCATE\s+TABLE\b",                  "destructive SQL blocked"),
    ("DELETE no WHERE", r"(?i)\bDELETE\s+FROM\b(?!.*\bWHERE\b)",    "DELETE without WHERE blocked"),
]

ALLOW = [
    # ("rm in ./tmp", r"\brm\s+-[rf]+\s+\.?/?tmp/"),
]

LOCAL_HOSTS      = ["localhost", "127.0.0.1", "::1"]
DB_CLIS          = ["mysql", "mysqldump", "psql", "redis-cli", "mongo", "mongosh"]
CURL_LOCAL_HOSTS = LOCAL_HOSTS + ["0.0.0.0"]

# ══════════════════════════════════════════════════════════════════════
#  LOGIC — you probably don't need to edit below this line
# ══════════════════════════════════════════════════════════════════════

import json, os, re, sys


def main():
    command = json.loads(sys.stdin.read()).get("tool_input", {}).get("command", "")

    for _name, pattern in ALLOW:
        if re.search(pattern, command):
            return approve()

    # CLAUDE_ALLOW_SSH=host1,host2 lets ssh/scp target those hosts.
    ssh_hosts = [h.strip() for h in os.environ.get("CLAUDE_ALLOW_SSH", "").split(",") if h.strip()]
    if ssh_hosts:
        hosts = "|".join(re.escape(h) for h in ssh_hosts)
        ssh_pat = rf"\bssh\s+(?:-\S+(?:\s+\S+)?\s+)*(?:\S+@)?(?:{hosts})(?:\s|$)"
        scp_pat = rf"\bscp\s+.*(?:^|\s)(?:\S+@)?(?:{hosts}):"
        if re.search(ssh_pat, command) or re.search(scp_pat, command):
            return approve()

    for _name, pattern, reason in BLOCK:
        if re.search(pattern, command):
            return block(reason)

    local = "|".join(re.escape(h) for h in LOCAL_HOSTS)
    non_local = rf"(?:-h\s*|--host[=\s])(?!(?:{local})\b)\S+"
    for cli in DB_CLIS:
        if re.search(rf"\b{cli}\b", command) and re.search(non_local, command):
            return block(f"{cli} targeting non-local host blocked")

    if re.search(r"\b(?:mongo|mongosh)\b", command) and re.search(rf"mongodb://(?!(?:{local})\b)", command):
        return block("mongo targeting non-local host blocked")

    curl_local = "|".join(re.escape(h) for h in CURL_LOCAL_HOSTS)
    if (re.search(r"\bcurl\b", command)
        and re.search(r"-X\s*(?:POST|PUT|DELETE|PATCH)\b", command)
        and not re.search(rf"(?:{curl_local})", command)):
        return block("curl write to non-local target blocked")

    approve()


def block(reason):
    print(json.dumps({"decision": "block", "reason": reason}))
    sys.exit(0)


def approve():
    print(json.dumps({"decision": "approve"}))
    sys.exit(0)


if __name__ == "__main__":
    main()

Adding a rule is a one-line append to BLOCK. Whitelisting a false positive is a one-line entry in ALLOW. No regex composition buried in function bodies.

What gets blocked, in plain English

File destruction. rm -rf, rm -fr, rm --recursive. The original sin.

Git footguns. git push --force, git push -f, git reset --hard, git clean -f, git add -A, git add --all. Things that silently destroy uncommitted or unpushed work, or stage files you didn’t mean to include.

Remote access. ssh, scp, sftp, telnet, netcat, rsync host:path. Claude has no business touching remote machines from my dev box. Blocking these also kills the “exfiltrate via SSH tunnel” injection variant. Escape hatch: CLAUDE_ALLOW_SSH=host1,host2 lets ssh/scp target listed hosts when you actually need them (jump box, lab VM).

Infrastructure writes. terraform apply|destroy, pulumi up|destroy, docker push, docker exec, any ansible subcommand. If it deploys, it’s not an agent’s call. That’s a human’s call.

kubectl mutations. delete, drain, cordon, taint, patch, edit, apply, create, exec, run, set, annotate, label, cp, plus replace --force, rollout undo|restart, scale --replicas=0. Reads (get, describe, logs) still work. Also catches the short aliases from ~/.kubectl_aliases (ka, kex, krun, ksysa, ksysex, ksysrun, ksysrm*) because muscle memory.

Helm writes. install, upgrade, uninstall, delete, rollback.

SQL destructives. DROP TABLE, DROP DATABASE, DROP SCHEMA, TRUNCATE TABLE. Case-insensitive because SQL. Also DELETE FROM without a WHERE clause, because “delete all rows” is rarely what you meant.

Database CLIs pointed at non-localhost. mysql, mysqldump, psql, redis-cli, mongo, mongosh. If -h or --host is anything other than localhost, 127.0.0.1, or ::1, the command is blocked. Local dev is fine. Prod connections from an agent are not.

Curl writes to non-local targets. curl -X POST|PUT|DELETE|PATCH where the URL is not localhost. This is the single highest-ROI rule. It kills the entire “exfiltrate secrets via curl” class of prompt injection for 95% of attacks, because the bad prompt tells Claude to POST your env to an attacker URL, and that URL is not localhost.

Reads are unblocked. curl https://foo, git pull, kubectl get, SELECT *, all fine. The heuristic: if it changes state on a machine that isn’t mine, block it. If it reads, allow.

Distributing it across the team via your dev bootstrap command

This is the part I actually care about. A security hook only matters if every engineer has it installed. Not “68% of engineers”. Every single one. No Slack announcement gets you that. No onboarding checklist gets you that. Only piggybacking on something people already run every day gets you that.

Quick glossary for the examples below: my team uses a justfile (like a Makefile, but with nicer syntax), and our bootstrap command is just up. It boots the dev Docker services (databases, queues, workers) and is what every engineer runs as the first thing in the morning. If your stack uses make dev, npm start, pnpm dev, docker-compose up, bin/dev, a shell script, or anything else — same idea, different verb. Wherever you see just up below, mentally replace it with your team’s equivalent. The mechanism does not care.

So I hung the hook installer off that bootstrap command:

# Install Claude Code destructive-command blocker hook
secure-claude:
    @{{ root_dir }}/.claude/install-hooks.sh

# One-time setup targets call it on clone
use_system:
    ...
    just secure-claude

use_docker:
    ...
    just secure-claude

# The important one: every dev boot calls it
up: _check_env _check_before_up
    @just _up_{{ env_type }}
    @just secure-claude

Same thing as a Makefile, if that’s what you have:

.PHONY: secure-claude up

secure-claude:
	@./.claude/install-hooks.sh

up: secure-claude
	docker-compose up -d
	@./.claude/install-hooks.sh   # re-verify after services are up

Same thing as an npm script in package.json:

{
  "scripts": {
    "secure-claude": "./.claude/install-hooks.sh",
    "dev": "npm run secure-claude && docker-compose up -d && npm run secure-claude"
  }
}

Pick whichever matches your stack. The key is: call the installer from the target people already invoke daily.

The payoff: every git pull + just up cycle re-verifies the hook is present, matches the repo copy, and is wired into ~/.claude/settings.json correctly. Blocklist updated in the repo Monday? Tuesday morning every engineer pulls, runs just up, and the new rules are live on their machine. Zero ceremony.

The installer is aggressively silent. If the hook is already installed and unchanged, it prints nothing. If the hook content changed (team bumped rules), one colored line. Only on first install does it print the full banner. Nobody learns to tune out the output because there usually isn’t any.

Self-healing falls out for free. Engineer deletes ~/.claude/hooks/prevent-destructive-commands.py by accident? Next just up puts it back. Engineer moves the repo from ~/Work/backend/ to ~/src/backend/ and settings.json has a stale absolute path pointing at the old location? Next just up strips the stale entry and writes the correct one. The repo is the source of truth, just up is the sync command.

Doesn’t use justfiles? Same idea with a different verb. Hang it off make dev, npm run setup, pnpm bootstrap, docker-compose up wrapped in a shell script, or a pre-commit hook. Pick the target your team runs most often. Security that depends on manual installation reaches 60% of machines. Security piggybacked on a daily command reaches 100%.

The installer, in 90 lines

Hand-editing ~/.claude/settings.json across a team doesn’t scale. The installer has to be idempotent, preserve other hooks, and survive re-runs forever without corrupting state.

What it does, in order:

  1. Copies .claude/hooks/prevent-destructive-commands.py from the repo to ~/.claude/hooks/.
  2. Creates ~/.claude/settings.json as {} if missing.
  3. Checks if our hook entry is already present with the correct absolute path. If yes and the hook file hasn’t changed, exits silently.
  4. Strips any stale entries pointing at old repo-local paths. Happens when engineers move the repo or when the path format changes.
  5. Appends our entry under PreToolUse[matcher=Bash], preserving every other hook in the file.
  6. Writes back with indent=2.

The merge logic, the only interesting part:

hooks = settings.setdefault("hooks", {})
pre_tool = hooks.setdefault("PreToolUse", [])

already_installed = any(
    h.get("command") == hook_cmd
    for entry in pre_tool if entry.get("matcher") == "Bash"
    for h in entry.get("hooks", [])
)
if already_installed:
    sys.exit(0)

# strip stale entries pointing at old paths of this hook
for entry in pre_tool:
    if entry.get("matcher") == "Bash":
        entry["hooks"] = [
            h for h in entry.get("hooks", [])
            if "prevent-destructive-commands.py" not in h.get("command", "")
        ]
pre_tool[:] = [e for e in pre_tool if e.get("hooks")]

pre_tool.append({
    "matcher": "Bash",
    "hooks": [{"type": "command", "command": hook_cmd}],
})

Naive approach: echo '{"hooks": ...}' > ~/.claude/settings.json. Nukes every other hook. The correct approach is the one above: load JSON, mutate in place, write back.

Why not just use project-local .claude/settings.json?

Claude Code supports project-local settings. That would avoid touching ~/.claude/. I don’t use it for this because:

  • Hooks in project settings only fire when Claude runs inside that project. For a generic “don’t let it rm -rf” rule, I want it active in every Claude session on my machine, not just when I’m in one repo.
  • The project settings file is checked into the repo, so any path it references has to work on every teammate’s machine. Home-dir install gives everyone the same absolute path via $HOME. Clean.
  • Project-level settings are the right answer for project-specific rules (e.g. “this repo never touches the billing DB”). You can layer them on top. The generic blocklist stays at user scope.

Trade-off: the hook is active even when Claude runs outside the project. For a blocklist that’s generic, that’s a feature.

The regexes are not bulletproof

Obvious, but worth saying out loud.

rm$'\x20'-rf with shell-escape tricks gets through. eval "$(echo cm0gLXJm | base64 -d)" gets through. A determined attacker with a shell bypasses regex filtering in ten ways. Hand-crafted malicious commands designed to evade this hook will evade this hook.

This is not an adversarial sandbox. It’s a guardrail. It catches the 95% case: Claude confidently running the obvious dangerous command because the user asked for it, or because an injected instruction in a README told it to. It raises the bar for prompt injection from “trivially exploitable” to “requires bypass craft”.

The remaining 5%, the adversarial case, needs a real sandbox. Firejail, Bubblewrap, macOS Sandbox, a VM, a container with no network and a read-only filesystem. That is a different post and different amount of work.

Also: a hook only sees commands that go through the Bash tool. Claude can also Write files. If the attack is “write malicious code to a file then have the user run it”, this hook does not help. Code review does.

FAQ

Does this work with Claude Code on Linux? Yes. Hooks are a Claude Code feature, not a shell feature. ~/.claude/settings.json works on macOS and Linux identically. Windows path is %USERPROFILE%\.claude\.

Does it slow Claude Code down? No measurable latency. The Python startup is ~30ms, regex match is microseconds. You will not notice.

Will it break when Anthropic updates Claude Code? The hook protocol is stable. The PreToolUse + stdin JSON + stdout JSON contract has been in place since hooks shipped. If Anthropic changes it, the failure mode is “hook stops firing”, and commands run unchecked. Worth re-checking after major Claude Code upgrades.

What if I genuinely need ssh to one specific host? Set CLAUDE_ALLOW_SSH in the env before launching Claude Code:

export CLAUDE_ALLOW_SSH=jump.example.com,lab-vm

Comma-separated. The hook approves ssh and scp when the target host (with or without user@ prefix) matches one of the entries. Everything else still blocked. Keep the list short — every entry you add is one more hostname Claude can reach.

What if I want to allow rm -rf in a specific directory? Add it to the ALLOW list:

ALLOW = [
    ("rm in ./tmp", r"\brm\s+-[rf]+\s+\.?/?tmp/"),
]

ALLOW is evaluated before BLOCK, so a match here skips the block entirely.

Can Claude see that a command was blocked? Yes. The reason field in {"decision": "block", "reason": "..."} is shown to the model. Claude reads it and usually picks a safer alternative, or tells you it’s blocked and asks.

How do I test the hook locally without breaking my real Claude setup? Install it under a temp HOME:

TMP=$(mktemp -d)
HOME=$TMP bash /path/to/secure-claude.sh
echo '{"tool_input":{"command":"rm -rf /"}}' | python3 $TMP/.claude/hooks/prevent-destructive-commands.py
# → {"decision": "block", "reason": "rm -rf blocked"}

Does this replace sandboxing? No. It’s a cheap guardrail, not an isolation boundary. If your threat model includes a malicious agent actively trying to escape, run Claude Code in a VM or container with no credential access.

What about the Write / Edit tools? Out of scope for this hook. A separate PreToolUse[matcher="Write"] hook can check target paths and refuse writes to .env, ~/.ssh/, etc. Future post.

Does this cover MCP tool calls? Only Bash-backed MCP tools go through the Bash matcher. Other MCP tools have their own matcher name (mcp__servername__toolname). You can add matchers for those separately if you want.

Does this work inside Cursor / VSCode Cline / other agents? No. It’s a Claude Code feature specifically. Cursor has its own rules system. Cline has its own. The concept is portable, the config format isn’t.

Is the curl-bash installer safe? It’s as safe as me. If my site gets compromised, the installer gets compromised. For team use, vendor the hook into your repo instead of curling mine. The whole point is to commit it alongside your justfile, not to depend on my domain.

Install it in your project, in 4 steps

This is the copy-paste recipe. Ten minutes of work, no dependencies beyond Python 3.

Step 1. Drop two files into your repo

Create .claude/hooks/prevent-destructive-commands.py — paste the full hook from the hook source section above, or grab the latest from simion.cv/scripts/secure-claude.sh (the PYEOF-bounded block).

Create .claude/install-hooks.sh:

#!/usr/bin/env bash
set -euo pipefail

REPO="$(cd "$(dirname "$0")/.." && pwd)"
SRC="$REPO/.claude/hooks/prevent-destructive-commands.py"
DST="$HOME/.claude/hooks/prevent-destructive-commands.py"
SETTINGS="$HOME/.claude/settings.json"
CMD="python3 $DST"

mkdir -p "$HOME/.claude/hooks"
cp "$SRC" "$DST"
[[ -f "$SETTINGS" ]] || echo '{}' > "$SETTINGS"

CMD="$CMD" SETTINGS="$SETTINGS" python3 - <<'PY'
import json, os, sys
cmd, path = os.environ["CMD"], os.environ["SETTINGS"]
s = json.load(open(path))
pt = s.setdefault("hooks", {}).setdefault("PreToolUse", [])
for e in pt:
    if e.get("matcher") == "Bash":
        e["hooks"] = [h for h in e.get("hooks", [])
                      if "prevent-destructive-commands.py" not in h.get("command", "")]
pt[:] = [e for e in pt if e.get("hooks")]
pt.append({"matcher": "Bash", "hooks": [{"type": "command", "command": cmd}]})
json.dump(s, open(path, "w"), indent=2)
PY

chmod +x "$DST"
echo "Claude Code hook installed."

chmod +x .claude/install-hooks.sh. Commit both files.

Step 2. Wire it into your daily bootstrap command

Pick the command your team runs every morning to start dev. Call .claude/install-hooks.sh from it.

Justfile:

up:
    docker compose up -d
    @./.claude/install-hooks.sh

Makefile:

.PHONY: up
up:
	docker compose up -d
	./.claude/install-hooks.sh

package.json:

{
  "scripts": {
    "dev": "docker compose up -d && ./.claude/install-hooks.sh"
  }
}

Don’t create a separate install-hook target for people to run manually. Nobody runs those. Hang it off the command they already type.

Step 3. Test it

Run the bootstrap command once yourself. You should see Claude Code hook installed. printed.

Restart Claude Code (the first install only — subsequent updates are hot). Then ask it to run a destructive command in a scratch directory:

Please run: rm -rf /tmp/does-not-matter

Claude should refuse with “rm -rf blocked”. If it runs the command, either your hook isn’t wired (check ~/.claude/settings.json) or your blocklist regex is off.

Step 4. Commit, push, tell the team once

Commit the two .claude/ files and the bootstrap change. Push. Tell the team once, in one Slack message: “run <your bootstrap cmd> again”. From then on the hook auto-installs for anyone who pulls and runs the bootstrap. New hires get it on day one through the onboarding script.

To update the blocklist later: edit .claude/hooks/prevent-destructive-commands.py, open a PR, merge. Next git pull + bootstrap across the team picks up the new rules. No coordination, no announcement.

That’s it. Ten minutes. Go.