OpenProgram Docs

Invariants the Framework Must Enforce Itself#

Rules are something you write, and they change; but there are a few invariants that the framework core must enforce forever — no rule, written by anyone, may break them. There are two, and both are straightforward. Read overview.md before reading this one.

(Note: a few further invariants concerning adversarial safety and tamper resistance belong to the research/production level. They are out of scope here and are documented in _research_archive/threat-model.md, which is where security hardening would start.)

Invariant 1: The framework must not trigger itself and spiral into an infinite loop#

This is the most important one — bad things happen if it isn't enforced.

What the problem looks like#

Recall: when the framework acts on its own, it also produces events (mentioned in overview concept 1, origin=proactive). For example, an observer rule kicks off a Prepare background task, and when that task finishes it produces a "ready" event.

If we ignore where this event came from, it gets seen by some rule, triggers another Prepare, produces another "ready" event...

infinite loop vs. the one allowed two-hop

Every Prepare is a real, costly background task (possibly an LLM call). Spiraling into an infinite loop = burning money endlessly and spamming the user.

How it's enforced#

Events the framework produces itself (origin=proactive) must not trigger any action that "produces a new event" or "interrupts the user."

Concretely, we define a very short chain that is allowed to run only once:

normal event (caused by user/agent/tool)
   → an observer rule may kick off one Prepare (do its homework)
   → Prepare completes and produces a "ready" event
   → this event is allowed to do exactly one thing: decide whether to Notify (alert the user)
   → and that's it: no more Prepare, no more injection

The implementation is simple: every event carries a flag recording "whether this causal chain was started by the framework itself." Before letting a rule act, the framework checks this flag — if the framework started the chain, the event is only allowed to reach "notify once" and is not allowed to propagate any further.

def allow_action(event, action):
    if event.started_by_framework:
        # On the framework's own chain, only one user notification is allowed — no more background tasks / no more injection
        return action is Notify and chain_within_one_hop
    return True   # normal event, act freely

This invariant is framework-level: rules cannot disable it or work around it. It is part of the foundation.

Invariant 2: Blocking rules must not be auto-silenced because the user "got tired of" them#

This invariant constrains a capability the framework does not yet have, so it reads as a rule for whoever adds that capability.

Logic like "if the user keeps ignoring some alert, automatically alert less" (auto-silencing) must exclude blocking rules — safety guardrails (e.g. intercepting dangerous commands) must not auto-disable just because they "got rejected too many times."

Picture the counterexample: someone (or injected malicious content) lures the agent into repeatedly triggering dangerous-command confirmations and repeatedly clicking reject. If that could make the guardrail "think it's useless" and auto-silence itself, then the next genuinely dangerous command would have no one to intercept it.

So the principle is: auto-silencing applies only to "observer alerts" and never touches "blocking guardrails." The framework's only interruption control is the simple cooldown_s; any silencing mechanism added on top of it inherits this constraint.

Summary#

Invariant In one sentence Why
No self-triggered infinite loop Events the framework produces itself reach "notify once" at most, and may not propagate further Otherwise: endless money burn and spam
Guardrails not auto-disabled Future auto-silencing applies only to alerts, never to blocking guardrails Otherwise the safety guardrail can be rejection-spammed into uselessness

These two are guaranteed by the framework core; rule authors don't need to worry about them and can't change them.

Last updated · 2026-08-13