Skip to content
Runner · Understand the runtime

Two boundaries, two planes

The off-chain engine/plugins split, mirrored by the on-chain container/plug floor.

Derived from thesis §5

When you build a strategy you write code on two planes at once, and each plane has the same shape: a small surface you own, hemmed in by a larger surface you don't. Once you see one boundary, you've seen both.

Off-chain: engine and plugins

The runner is split in two. The engine is the part you trust: the runtime core, the trigger adapter, the executor that builds the moveCall, signs with the operator_address key, submits, and records the digest. The plugin is the part you write: a decide(ctx) that returns Action[] and nothing more.

Your plugin returns declarative intent. The engine decides how and when it touches the chain.

The boundary is load-bearing. A plugin never holds a key, never calls RPC directly, never builds a tx. So a buggy plugin can't escape the engine: at worst it returns a bad Action[]. See Runner architecture for the four layers.

On-chain: container and plug

The same split is cut into the contract. The container (the vault primitive) holds the capital, the risk limits, the NAV, and the permissions, and it validates every operation. The plug (your strategy module) only decides. It custodies nothing, carries no stored authorization, and can only propose operations the container checks first.

The container holds and enforces. The plug only decides.

This is the same shape one layer down. A bad plug, like a bad plugin, can only propose. The proposal still has to clear the container's anti-rug caps before anything happens on-chain. See Plug-and-socket for the architecture.

Why the analogy holds

Both planes answer the same question: how much can the code you write put at risk? The answer is the same on each plane, because the structure is the same. You own the decision; the surface around it owns the consequences.

  • Off-chain, the engine is a software boundary. It keeps keys and tx-building out of your hands, so a crash or a bad Action[] stays contained.
  • On-chain, the container is the hard floor. It's immutable and enforced by the contract, so a misbehaving plug is bounded no matter what bytecode you ship.

The off-chain boundary is a convenience and a safety rail; the on-chain boundary is the guarantee. A bad Action[] that slips past your engine still hits the vault's caps. That's the floor the depositor actually relies on, and it's the third question in the three layers of protection: the contract decides whether an operation is allowed, no matter what runs above it.