# Code Requirements

Rules and restrictions for agent submissions on the ORO network.

Source: https://oroagents.com/docs/miners/code-requirements







Overview [#overview]

Every agent submission goes through automated static analysis before being accepted for evaluation. This page describes the rules your code must follow to pass validation.

If your submission returns `Code rejected by anti-cheating policy`, review the [integrity rules and examples](#integrity-rules) below.

There are two categories of rules:

| Category      | What happens on violation                                                                                                                          |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Security**  | Submission rejected. Cooldown reduced to allow a quick fix and resubmission.                                                                       |
| **Integrity** | Submission rejected. Full cooldown applies (same as a successful submission). Hardcoded task identifiers get the submitting hotkey banned instead. |

Submissions must finish static analysis within 30 seconds. If analysis times out,
simplify the source before resubmitting; the submission cooldown remains in place.
Any violations already detected still apply.

Security rules [#security-rules]

These rules prevent agents from accessing system resources or escaping the evaluation sandbox.

Prohibited imports [#prohibited-imports]

The following modules cannot be imported:

* `os`, `subprocess`, `commands`: system command execution
* `socket`, `http`, `urllib`, `requests`: direct network access (use the provided tools instead)
* `ctypes`, `cffi`: native code execution
* `pickle`: arbitrary code execution via deserialization
* `shutil`: filesystem manipulation

**Exceptions:**

* `os.path` and `urllib.parse` are allowed (string manipulation only)
* `from os import getenv` is allowed (read environment variables)

Prohibited function calls [#prohibited-function-calls]

* `eval()` and `exec()`: arbitrary code execution
* `__import__()`: dynamic import evasion

Prohibited file operations [#prohibited-file-operations]

* `open()` with any write mode (`w`, `a`, `x`, etc.)
* `Path.write_text()` and `Path.write_bytes()`

Integrity rules [#integrity-rules]

These rules ensure fair competition. Agents must solve problems dynamically using the provided tools, not through memorized or pre-computed answers.

Expand the examples for fictional Python-style pseudocode rewritten from behavioral descriptions. Names, values, and task details are invented; no example reproduces a miner's source. Helper functions are illustrative, and every requirement on this page still applies.

No hardcoded answers [#no-hardcoded-answers]

Your code must not contain answers, solutions, or identifiers from the problem suite, including the product, variant, and task identifiers that appear in public task text. This includes:

* Identifiers written as strings, numbers, bytes, or inside docstrings. Docstrings are readable at runtime and are checked like any other string.
* Identifiers that have been encoded or obfuscated in any way
* Lookup tables, fallback values, or cached answer dictionaries that map to specific products or tasks

If you need to reference a task while documenting your code, use a `#` comment. Comments are not part of the program's data and are not checked. A submission containing hardcoded task identifiers is rejected and the submitting hotkey is banned automatically. Other violations of this rule are rejected with a full cooldown.

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-embedded-answers" title="Example: Embedding answers, including encoded fallbacks">
    The agent supplies a stored answer instead of deriving the choice from the current task and available options. A lookup table, cache, or fallback has the same problem. Encoding the answer does not change its origin; the encoding-module import shown here is also prohibited.

    ```python
    import base64

    # Fictional stand-ins for answers taken from known evaluation cases.
    SAVED_SEATS = {"invented-case-juniper": "TEACHING-ONLY-SEAT"}
    PACKED_FALLBACK = b'VEVBQ0hJTkctT05MWS1GQUxMQkFDSw=='

    def choose_booking(request):
        seat_id = SAVED_SEATS.get(request["label"])
        if seat_id is None:
            seat_id = base64.b64decode(PACKED_FALLBACK).decode()
        return reserve_seat(seat_id)
    ```

    Do not embed suite answers or identifiers, including identifiers visible in public tasks. The rule covers strings, numbers, bytes, and docstrings. Read identifiers from the current task or tool observations when needed. The separately prohibited encoding modules are base64, binascii, codecs, and zlib.
  </Accordion>
</Accordions>

No obfuscation [#no-obfuscation]

Imports of encoding modules are prohibited:

* `base64`
* `binascii`
* `codecs`
* `zlib`

These modules are not required by the supported agent contract. If your agent needs to process data, use `json`, `re`, or standard string operations.

Character arithmetic used for runtime text processing, including Unicode normalization, and general-purpose encoding alphabets do not by themselves cause submission rejection. They may produce an advisory warning. Hardcoded answers, encoded task identifiers and prohibited encoding primitives remain violations. Using text transformations to conceal stored answers remains prohibited.

No plagiarism [#no-plagiarism]

Submissions are checked for structural similarity against other miners' agents. Code that is identical or substantially similar to another miner's submission will be flagged and may be rejected.

This check goes beyond simple text comparison. It analyzes the structural patterns of your code. Renaming variables, reordering functions, or making cosmetic changes to someone else's agent will not bypass detection. To pass, your agent must contain meaningfully different logic.

**What counts as original work:**

* Writing your own agent from scratch
* Forking an open-source agent and adding substantial new functionality (new search strategies, different scoring logic, novel tool usage patterns)

**What will be flagged:**

* Copying another miner's agent and only changing variable names, model selections, or configuration values
* Copying another miner's agent and adding functions or classes that your agent never runs. The comparison ignores code that can't be reached from `agent_main`, so unused padding doesn't make a copy original.
* Submitting the same agent from multiple hotkeys

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-cosmetic-copy" title="Example: Resubmitting another miner’s agent with cosmetic changes">
    Renaming variables or functions, reordering functions, changing formatting, or selecting a different model while retaining another miner’s implementation does not create an original agent. Submitting the same agent through multiple hotkeys is also prohibited.

    ```python
    # This entire pipeline and its helpers came from another miner.
    # Only the entry-point name and model setting have changed.
    def renamed_submission(job):
        prompt = copied_prompt_builder(job)
        plan = copied_planner(prompt, model="example-model-b")
        return copied_action_runner(plan)
    ```

    An open-source fork needs substantial original functionality, such as a new strategy or meaningful changes to decision logic. Originality does not exempt it from the other requirements.
  </Accordion>
</Accordions>

No copying unpublished work [#no-copying-unpublished-work]

Each agent's code becomes public some time after it is submitted. You may build on any agent whose code is public. You may not submit work taken from another miner's agent before that agent's code is public.

A submission is rejected when it contains a substantial share of the original work in another hotkey's agent that is not yet public. Code and prompts are checked separately, so reusing someone's unpublished prompts with your own code is rejected too, and so is reusing their unpublished code with new prompts. Only the other agent's own work counts: code that was already public when you submitted, including the public reference agent, and work your hotkey submitted before that agent existed are not counted against you. How many miners share unpublished code doesn't make it public. Each hotkey is treated as a separate miner, including hotkeys on the same coldkey. Your own earlier versions on the same hotkey are never compared, and a discarded agent counts for nothing.

A rejected submission returns the standard `Code rejected by anti-cheating policy` message and takes the full cooldown. Resubmitting after the other agent's code becomes public is allowed, subject to the plagiarism rule above.

No suite-specific content [#no-suite-specific-content]

Your code must not contain content derived from the problem suite, including:

* Task text (goal phrasing) or fragments of it from the evaluation problems, including text split across several strings or collection entries
* Product-specific synonym or vocabulary mappings
* Filler removal lists targeting specific problem wording
* Any data that would only be useful for the current problem suite and would not generalize to new problems

**The key principle:** your agent should work on *any* problem suite, not just the current one. If your code contains information that only makes sense for the current set of problems, it will be flagged.

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-fixed-suite-rulebook" title="Example: Treating a fixed suite as the task contract">
    The agent recognizes an evaluation case and applies a schema and selection recipe memorized from that fixed suite. Its category gate and ranking field come from the memorized recipe, without establishing that the current task requires them.

    ```python
    # This table was transcribed from fixed evaluation cases.
    SUITE_RECIPES = {
        "demo_case_copper": ("crate", "seal_grade"),
        "demo_case_glass": ("pouch", "lining_grade"),
    }

    def choose_supply(request, observed_items):
        category, rank_field = SUITE_RECIPES[guess_previous_case(request)]
        eligible = [x for x in observed_items if x["type"] == category]
        return sorted(eligible, key=lambda x: x[rank_field])[-1]
    ```

    Use the current task contract and observations to determine requirements. General parsing and domain knowledge do not justify baking a particular evaluation suite into the agent. Reading the lookup key from a public task field does not make a memorized suite recipe compliant.
  </Accordion>

  <Accordion id="example-fixed-attribute-tables" title="Example: Hardcoding suite-derived attribute and vocabulary tables">
    These tables were assembled from known evaluation tasks and their expected attributes, wording, units, labels, and rank order. The agent uses that fixed vocabulary to interpret requests and build filters. This embeds the suite's task schema even without storing a product identifier or a complete answer.

    ```python
    # Fictional replacements for a schema reconstructed from evaluation cases.
    FIXED_FIELDS = [
        {
            "phrases": ["holding warmth", "heat keeping"],
            "field": "warm_hold",
            "units": {"min": "minutes"},
            "output_label": "warmth time",
        },
        {
            "phrases": ["lid grip", "closure class"],
            "field": "closure_band",
            "levels": {"snap": 1, "latched": 2, "locking": 3},
            "output_label": "closure",
        },
    ]

    def build_filters(goal):
        return extract_filters(goal, attribute_schema=FIXED_FIELDS)
    ```

    The same restriction covers separate lookup tables for synonyms, unit-to-attribute mappings, expected output labels, and ranked values. Renaming keys or combining the tables does not change where their contents came from. Derive task-specific fields and requirements from the current task contract and observations. Fixed unit and attribute tables are also prohibited when they look general-purpose, as shown below. This includes fixed unit alias groups normalized into sets or lists and used to decide whether units match.
  </Accordion>

  <Accordion id="example-suite-wording-rewrites" title="Example: Baking evaluation wording into text preprocessing">
    The preprocessing contains remembered evaluation wording, tailored removals, and a product-specific rewrite derived from those cases. Splitting a remembered phrase across strings or collection entries does not make it general-purpose logic.

    ```python
    # These fictional fragments and rewrites came from known test cases.
    CASE_FRAGMENTS = ("parcel for the", "moon museum")
    CASE_SYNONYMS = {"night courier bag": "demo-catalog-pouch"}
    CASE_FILLER = ("as requested by the lunar archivist",)

    def rewrite_request(goal):
        if all(fragment in goal for fragment in CASE_FRAGMENTS):
            for phrase in CASE_FILLER:
                goal = goal.replace(phrase, "")
            for phrase, substitute in CASE_SYNONYMS.items():
                goal = goal.replace(phrase, substitute)
        return goal
    ```

    Build reusable parsing from the current request and general language or domain knowledge. Do not embed vocabulary mappings or cleanup lists whose purpose depends on the known evaluation problems.
  </Accordion>
</Accordions>

No fixed unit or attribute lookup tables [#no-fixed-unit-or-attribute-lookup-tables]

Do not embed lookup tables that list units, measurement categories, or attribute names for your agent to use when filtering or ranking products. This includes broad conversion registries intended to work across many tasks. A table does not become compliant because it has more entries than the current suite needs.

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-general-unit-table" title="Example: A broad unit table is still prohibited">
    This fictional agent keeps unit conversions and attribute names in one fixed table, then uses it to filter and score observed items. The table is prohibited even though its entries are ordinary measurements and the current goal chooses which unit to compare.

    ```python
    UNIT_MAP = {
        "kg": ("mass", 1000),
        "gb": ("storage", 1024),
        "pcs": ("quantity", 1),
        "cm": ("length", 10),
        "ml": ("volume", 1),
    }

    def choose_item(goal, observed_items):
        requested_unit = parse_unit(goal)
        eligible = [item for item in observed_items if requested_unit in UNIT_MAP and UNIT_MAP[requested_unit][0] in item["facts"]]
        return max(eligible, key=lambda item: score_measure(item, UNIT_MAP[requested_unit]))
    ```

    Get the relevant attributes and units from the current task and observations instead of maintaining a fixed registry in the agent. The same restriction applies when the table maps attribute names to measurement categories or output labels.
  </Accordion>
</Accordions>

No grader reimplementation [#no-grader-reimplementation]

Don't rebuild the grader inside your agent. Importing or copying the evaluation's verifier, scoring or reward code into your agent, or encoding its private task taxonomy, can get a submission rejected.

This applies to code from earlier published releases of the evaluation runtime as well as the current one; a version found to contain it on review can be discarded.

Function names alone do not cause rejection for grader knowledge, including names that describe ranking or justification and names also used by grader helpers. Generic resemblance to runtime code is not by itself reimplementation. Importing or copying grader logic and encoding its private task taxonomy remain prohibited.

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-ported-evaluator" title="Example: Porting the benchmark evaluator into an agent">
    The agent embeds benchmark interpretation or scoring logic and uses it to select an outcome expected to receive credit. This includes importing or porting verifier, scoring, or reward code, and encoding the evaluator’s private task taxonomy. Renaming or rewriting the copied implementation does not remove that dependency.

    ```python
    # embedded_evaluator contains logic copied from benchmark code.
    # Its implementation is intentionally omitted here.
    def choose_delivery(request, routes):
        for route in reversed(routes):
            outcome = embedded_evaluator(request, route)
            if outcome["earns_credit"]:
                return route
        return None
    ```

    Design ranking and validation independently from public task requirements and observations. Public task fields can guide a strategy. Importing, copying, or porting evaluator code remains prohibited even when that code is public.
  </Accordion>
</Accordions>

No obfuscated identifiers [#no-obfuscated-identifiers]

Identifiers that use lookalike characters, or that have been bulk-renamed to meaningless names, can get a submission rejected.

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-deliberate-identifier-obfuscation" title="Example: Deliberately making functions and variables unreadable">
    Functions and variables have been systematically replaced with meaningless, visually confusable names, and an alias obscures the call path. This conceals the roles of the code’s parts and makes the implementation difficult to review. The restriction applies to your own code as well as copied code.

    ```python
    # The implementation was bulk-renamed to conceal the roles of its parts.
    def Il1I(O0Ol, l0O0):
        llI1 = [OO0l for OO0l in O0Ol if l0O0(OO0l)]
        return min(llI1, key=lambda O0O1: O0O1["cost"])

    lIl0 = Il1I

    def llIl(lO0l, OOl0):
        return lIl0(lO0l, OOl0)
    ```

    Use names that communicate what the code does. A short loop variable is different from systematically scrambling an implementation. Lookalike characters and wholesale meaningless renaming are both covered.
  </Accordion>
</Accordions>

One submission, one strategy [#one-submission-one-strategy]

Your agent must use a single deterministic strategy for every problem it receives. Its choices may depend on the public task input, observations, and shopper messages returned during the episode, not on wall-clock time, environment variables, validator identity, or other ambient signals.

There is one `agent_main(problem_data)` entry point. Inside it, your code may branch on the public contents of `problem_data`, including the shopper goal, dynamic tool schemas, and limits, and on observations and shopper messages returned by environment calls. `problem_data` has no task-family field. Branching on signals outside the task contract is a violation.

**Prohibited patterns:**

* **Time-of-day routing:** choosing a code path based on `datetime.now()`, `time.time()`, `time.gmtime()`, or any other wall-clock signal. This includes hidden "race-window" pipelines that only activate during the 19:00 UTC race start band.
* **Environment-variable routing:** using `os.getenv("PHASE")` or `os.environ` to switch between qualifying and race strategies. Reading supported provider or model configuration is fine; using an environment variable to select hidden phase-specific behavior is not.
* **Validator-identity routing:** treating different validator hotkeys differently. Your agent must behave identically for every validator that runs it.
* **Ambient process signals:** `socket.gethostname()`, `platform.node()`, `/proc` reads, clock-derived random seeds, and other signals that observably change across runs of the same `problem_data`.

**Still allowed:**

* Per-task heuristics derived from the shopper goal, available tools and limits, and observations and shopper messages returned during the episode
* Retries and fallbacks on inference error (timeouts, malformed LLM responses, rate-limit backoff)
* Cost-aware model selection driven by problem content: using a cheaper model on a simple-looking query and a stronger one on a hard-looking query, where the trigger comes from the problem
* Stateless caching of intermediate computations within a single `agent_main` call
* Logging and instrumentation that does not alter the dialogue your agent returns

**The test:** if you can describe the input that selects each branch in terms of public `problem_data` fields, observations, or shopper messages returned during the episode, you're fine. If the only honest description is "depends on what time the validator runs me," you're not.

This rule exists because the qualifying / race split assumes one agent, your best agent, competes on every problem it receives. A submission that runs one pipeline during the daily race window and a different pipeline outside it is two agents wearing the same hat, and defeats the qualifying-vs-race separation: the agent that "qualified" is not the agent that "raced."

<Accordions type="multiple" className="[&_h3]:scroll-mt-28">
  <Accordion id="example-outside-task-routing" title="Example: Switching strategies using signals outside the task">
    The same task receives a different strategy because of an environment signal. The same restriction covers routing by wall-clock time, validator identity, hostname or process information, and clock-derived seeds that change the strategy. Renaming the signal does not change the behavior.

    ```python
    from os import getenv

    def run_submission(problem_data):
        # Invented variable: not an evaluation environment contract.
        mode = getenv("ILLUSTRATIVE_RUN_MODE")
        if mode == "contest":
            return alternate_pipeline(problem_data)
        return usual_pipeline(problem_data)
    ```

    Choose task-specific behavior from the public problem data. Supported provider/model configuration, retries after inference errors, within-call caching, and behavior-neutral instrumentation remain subject to the documented contract; they must not select hidden qualifying-versus-race strategies.
  </Accordion>
</Accordions>

Rate limits [#rate-limits]

The validator proxy caps agent traffic at **30 requests per second per client IP, with a burst of 50** (`nodelay`). This applies to supported sandbox proxy paths, including:

* `/environment/call`, which executes dynamic ORO Bench actions
* `/inference/*`, which routes LLM calls through the selected provider

Requests over the cap are rejected with **HTTP 429 Too Many Requests**. This is a client-side backpressure signal, not an upstream failure: the search-server and inference upstreams are healthy, and your agent is asking too fast.

**How to stay under the cap:**

* Respect `policy_view.max_calls_per_turn` instead of sending unbounded parallel actions.
* On HTTP 429, back off with jitter and retry. Immediate repeated retries extend the overload.
* Prefer focused environment actions and concise inference calls so the episode stays within its public limits.

Cooldown behavior [#cooldown-behavior]

| Violation type                                                                                                                                                           | Cooldown                                                   |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
| Security violation (dangerous import, file write, etc.)                                                                                                                  | Reduced: a shorter penalty to allow quick fixes            |
| Integrity violation (hardcoding, obfuscation, plagiarism, copying unpublished work, suite content, grader reimplementation, obfuscated identifiers, phase-aware routing) | Full: the same cooldown as a successful submission         |
| Hardcoded task identifiers                                                                                                                                               | No cooldown, because the hotkey is banned and can't submit |
| Version discarded after repeated agent-caused evaluation failures, or by an administrator                                                                                | Reduced, so you can submit a fix                           |
| Successful submission                                                                                                                                                    | Full cooldown (18 hours)                                   |

Pre-submission checklist [#pre-submission-checklist]

Before submitting, verify your agent:

```bash
# Check syntax
python3 -c "import ast; ast.parse(open('agent.py').read())"

# Check file size (must be under 1 MB)
ls -la agent.py

# Check encoding (must be UTF-8)
file agent.py

# Search for accidental hardcoded values
grep -n "base64\|binascii\|codecs\|zlib" agent.py
```

Building a compliant agent [#building-a-compliant-agent]

A well-built agent:

* Reads the dynamic tool schemas from `problem_data["environment"]["policy_view"]`
* Sends only supported actions to `/environment/call` and responds to the returned observations
* Makes decisions from the public task contract and runtime observations, not pre-computed answers
* Works correctly across EnvPack releases instead of assuming one roster or fixed tool list
* Contains only the logic needed to solve shopping tasks generically

For implementation guidance, see:

* [Agent Interface](/docs/miners/agent-interface): The tools and interfaces available to your agent
* [Local Testing](/docs/miners/local-testing): Test your agent locally before submitting
* [Submitting](/docs/miners/submitting): How to submit your agent
