Skip to main content

Policy ABI

One fixed factory, one action method, and a bounded value surface visible to submitted code.

Program entry point

Every Program directory must contain policy.py. The fixed entry point is policy.py:make_policy:

from evopolicygym.policy import PolicyContext, PolicyValue


class MyPolicy:
def __init__(self, context: PolicyContext):
self._seed = context.policy_seed

def act(self, observation: PolicyValue) -> PolicyValue:
return 0


def make_policy(context: PolicyContext) -> MyPolicy:
return MyPolicy(context)

make_policy(context) runs once for each Episode. The returned object must provide act(observation).

There is no Policy-visible learn(), reset(), update(), Submission, or Feedback method.

PolicyContext

FieldMeaning
observation_spacePublic description of Policy-visible observations.
action_spacePublic description of admissible Actions.
metadataString-keyed, Case-independent Benchmark metadata.
environment_parametersPublic, Case-independent values bound to the configured Environment.
policy_seedAn unsigned 64-bit seed for this fresh Policy instance.

PolicyContext never contains Case identity, Environment seed, Host paths, file descriptors, credentials, pool identity, scores, runtime evidence, or scorer objects.

PolicyValue

Values crossing the Policy boundary must be composed only from:

None | bool | int | float | str | bytes
| TensorValue
| list[PolicyValue]
| tuple[PolicyValue, ...]
| dict[str, PolicyValue]

The rules are strict:

  • floats must be finite;
  • integers must fit signed or unsigned 64-bit;
  • mapping keys must be exact strings;
  • containers are validated and detached recursively;
  • custom Python objects and pickle graphs are rejected.

TensorValue

TensorValue carries a canonical dense tensor:

from evopolicygym.policy import TensorValue

pixels = TensorValue(
dtype="uint8",
shape=(84, 84, 3),
data=raw_rgb_bytes,
)

Supported dtypes are bool, unsigned and signed integers from 8 to 64 bits, and float16, float32, and float64. Multibyte values are little-endian, floating values must be finite, and the byte length must exactly match the shape and dtype.

Episode-local state

Episode 0 new process → make_policy() → act() × N → destroy
Episode 1 new process → make_policy() → act() × N → destroy
Episode N new process → make_policy() → act() × N → destroy

A Policy may retain history, recurrent state, search trees, caches, or temporary parameters between act() calls in the same Episode. No state crosses into another Episode.

Cross-Episode learning belongs to the outer Coding Agent, which authors and submits a new immutable Program.

Action semantics

The Environment receives the complete, unmodified Action returned by Policy.act().

Policy.act(observation)

PolicyValue validation

Environment.step(action)
├── valid → trusted Step
└── invalid → InvalidAction
Policy failure; no fallback step

Invalid Actions are never clipped, repaired, sampled, or replaced.

Policy failures

The public Policy failure codes are:

CodeMeaning
exceptionmake_policy() or act() raised.
timeoutThe Policy exceeded its Episode operation timeout.
invalid_actionThe Environment rejected the complete Action.
protocol_errorThe Policy process returned a malformed or unencodable value.

After Policy failure, the evaluator does not call Environment.step() again. Trusted Environment and execution faults remain separate and abort Evaluation.

Next