ASK KNOX
beta
LESSON 199

Hard Blocks: The Absolute No List

22 blocked actions across 6 categories that no agent can take regardless of authority, approval, or directive. The append-only rule — why this list can never shrink.

11 min read·Agent Authority & Safety Systems

Every safety system has two layers. The first layer is conditional — authority ceilings, approval requirements, escalation chains. Actions in this layer might be allowed under the right circumstances with the right authorization.

The second layer is unconditional. These are the things that are never allowed. Not under pressure. Not under urgency. Not with a good reason. Not with explicit approval. Not ever.

In the Principal Broker, this is HARD_BLOCKS.

The Full List

HARD_BLOCKS = [
    # Financial — wallet security
    "wallet.private_key",
    "wallet.seed_phrase",
    "wallet.pk",
    "wallet.privateKey",
    "wallet.transfer.unauthorized",

    # Database — production destruction
    "database.production.delete",
    "database.production.drop",
    "database.production.truncate",
    "database.production.wipe",

    # Code — isolation rules (CRITICAL ISOLATION RULE)
    "foresight.shared_modules.modify",
    "foresight.shared_modules.write",
    "foresight.shared_modules.delete",
    "production.deploy.unreviewed",
    "production.deploy.without_tests",

    # Identity — impersonation
    "impersonate.",
    "auth.token.create_without_broker",
    "auth.token.forge",

    # Infrastructure — unauthorized modification
    "env.production.overwrite",
    "env_file.modify.unauthorized",
    "launchd.daemon.create_unknown",
    "launchd.daemon.modify_unknown",
    "ssh.key.export",
    "ssh.key.create_without_approval",

    # Communication — external misrepresentation
    "external.email.send_as_knox",
    "external.social.post_as_knox",
    "external.api.call_with_knox_credentials",
]

22 actions across 6 categories. Every one of them is there because a real scenario exists where an agent could plausibly attempt it, and the consequences of allowing it even once would be severe enough that no approval process is adequate mitigation.

The Check Function

def is_hard_blocked(action: str) -> bool:
    action_lower = action.lower()
    for block in HARD_BLOCKS:
        if action_lower.startswith(block.lower()):
            return True
    return False

Prefix matching. This is the key design choice. Notice impersonate. has a trailing dot — it is a prefix pattern, not a specific action. impersonate.knox, impersonate.openclaw, impersonate.cfo — all blocked by a single entry. You do not need to enumerate every possible impersonation target.

The same pattern applies to wallet fields: wallet.private_key blocks wallet.private_key.export, wallet.private_key.log, any sub-action that starts with that prefix.

When you add a new entry to HARD_BLOCKS, think about whether you're blocking a specific action or a category of actions. If it's a category, end the prefix with a dot to signal that intent.

Understanding Each Category

Financial — Wallet Security

Private keys and seed phrases are the highest-value secrets in the system. There is no operational scenario where an agent needs to access them. Trading bots sign transactions using configured credentials that are loaded at startup — they do not need to read raw key material at runtime.

wallet.transfer.unauthorized catches any attempt to initiate a transfer that has not been explicitly directed by Knox. Note "unauthorized" in the action name — legitimate transfer flows use different action names that go through the authority ceiling system.

Database — Production Destruction

Delete, drop, truncate, wipe. These are irreversible. There is no recovery path that makes the downside acceptable. Production database modification follows a separate controlled process: migration scripts, reviewed PRs, explicit approval, tested rollback paths. An agent cannot shortcut this no matter what it's trying to accomplish.

Code — The Isolation Rule

This is the most operationally specific category. Foresight, the prediction markets trading bot, shares module code with the perpetuals trading bot. Foresight is live revenue. It has been running for years. It has 1,970+ tests and a track record.

The rule: never modify Foresight's shared modules to fix a perpetuals trading bot problem. The perpetuals trading bot is in v2 rebuild. Its problems are its own. Breaking Foresight to fix the perpetuals trading bot is unacceptable — and this has been formalized as a hard block so it cannot happen even accidentally.

production.deploy.unreviewed and production.deploy.without_tests are enforcement points for the quality gate. No agent can trigger a production deployment that bypassed code review or test coverage. This is not about trust — it is about maintaining a chain of custody for production changes that cannot be broken under time pressure.

Identity — Impersonation

An agent impersonating Knox or another agent in external communication is a trust-destroying event. The consequences are social and reputational, not just technical. Even a single instance of an AI sending email as Knox without authorization would be damaging in ways that cannot be cleaned up programmatically.

auth.token.create_without_broker and auth.token.forge prevent agents from creating their own authentication credentials outside the broker's oversight. Every agent identity in the system flows through the broker's registry. An agent that can mint its own tokens can claim any identity.

Infrastructure — Unauthorized Modification

Env files contain API keys, database credentials, and configuration that defines system behavior. An agent that can overwrite production env files can reconfigure the entire system. launchd.daemon.create_unknown and launchd.daemon.modify_unknown prevent agents from installing persistent processes that the watchdog service doesn't know about.

SSH key operations require explicit approval because SSH keys are the mechanism through which any machine in the network can be accessed. An exported SSH key is a durable credential that persists beyond the current session and can be used to access the trading server and any other machine in the infrastructure.

Communication — External Misrepresentation

This category is about what the outside world sees. Agents can post content. They can send messages. They can call external APIs. But they cannot do any of these things while representing themselves as Knox. The brand, the identity, and the relationships Knox has built are not resources for agents to use autonomously.

external.api.call_with_knox_credentials specifically prevents an agent from using Knox's personal API keys for external services. Agents have their own credentials or use system-level keys within defined scopes. Knox's personal keys are not in scope.

The get_block_reason() Function

When a hard block fires, you want to know which specific block triggered it:

def get_block_reason(action: str) -> str | None:
    action_lower = action.lower()
    for block in HARD_BLOCKS:
        if action_lower.startswith(block.lower()):
            return block
    return None

This returns the matching pattern, not just a boolean. The audit log entry for a hard block includes the specific block that triggered — wallet.private_key, foresight.shared_modules.modify — so you can understand what was attempted and what stopped it.

The Append-Only Rule

The file header says it plainly:

"""
Hard-blocked actions. These are NEVER allowed regardless of authority or approval.

This list can ONLY be extended, NEVER shortened.
verify_hard_blocks.py enforces this at CI time.

Last reviewed: 2026-03-23
"""

The CI enforcement (verify_hard_blocks.py) checks that the list at merge time is a strict superset of the list in the base branch. You cannot remove an entry. You can only add.

This rule exists because safety guarantees erode incrementally. Every removal feels justified in isolation:

  • "We need to remove wallet.private_key temporarily for the key rotation script"
  • "The deploy pipeline legitimately needs to bypass the test check in this one case"
  • "The perpetuals trading bot fix is urgent and the shared modules change is small"

Each of these sounds reasonable under pressure. All of them are the beginning of a process that ends with the safety system becoming a suggestion rather than a constraint.

The append-only rule removes the option. If you think something on the list is wrong, the answer is not to remove it — the answer is to redesign the process that's triggering it so it doesn't need to.

Last Reviewed Date

The comment at the top of the file includes Last reviewed: 2026-03-23. This is not decoration. It is an operational checkpoint. The hard blocks list should be reviewed quarterly by whoever is responsible for the system's safety posture.

The review questions are:

  • Are there new action categories that should be added based on what agents have attempted?
  • Has the operational context changed in a way that requires new blocks?
  • Are any existing blocks worded ambiguously in a way that creates false positives?

The last question is the only one that can lead to a list change — and the change is a rewrite (tightening the wording to reduce false positives), not a removal.

What Hard Blocks Are Not

Hard blocks are not the full safety story. They cover the absolute floor. Everything above that floor — authority ceilings, escalation routing, approval workflows — is the rest of the safety architecture.

An agent that never triggers a hard block but repeatedly generates escalations is worth investigating. The pattern of what an agent tries to do is as informative as whether any individual action was blocked.

Hard blocks are a last resort, not a first line of defense. A well-designed agent should never approach them. If your agents are frequently hitting hard blocks, the problem is upstream in how the agents are prompted or what they're being asked to do — not in the block list.