Skip to main content

ARC-AGI Toolkit

Project description

ARG-AGI

ARC-AGI Toolkit is an open-sourced python interface (API) for ARC-AGI-3 interactive environments. It provides a consistent API and tooling layer that lets agents interact with ARC-AGI-3 environments, locally or via API.

QuickStart

Prerequisites

  1. Installation:

    uv add arc-agi
    # or
    pip install arc-agi
    
  2. API Key: You can optionally set the ARC_API_KEY environment variable with your API key. If no key is provided, an anonymous key will be used. However, registering for an API key will give you access to more games at release. Register for an API key at https://three.arcprize.org

    The code supports loading from .env and .env.example files (using python-dotenv), or you can set it directly:

    export ARC_API_KEY="your-api-key-here"
    

    Or create a .env file in your project root:

    echo 'ARC_API_KEY=your-api-key-here' > .env
    

REPL Example

Get up and running with arc-agi in just 4 lines:

import arc_agi
from arcengine import GameAction
arc = arc_agi.Arcade()
env = arc.make("ls20", render_mode="terminal")

See the actions you can take, take one, and check your scorecard:

print(env.action_space)
obs = env.step(GameAction.ACTION1)
print(arc.get_scorecard())

Minimal Example

Here's a minimal example that plays a game and renders it in the terminal:

import random

from arcengine import GameAction, GameState
import arc_agi

# Initialize the ARC-AGI-3 client
arc = arc_agi.Arcade()

# Create an environment with terminal rendering
env = arc.make("ls20", render_mode="terminal")
if env is None:
    print("Failed to create environment")
    exit(1)

# Play the game
for step in range(100):
    # Choose a random action
    action = random.choice(env.action_space)
    action_data = {}
    if action.is_complex():
        action_data = {
            "x": random.randint(0, 63),
            "y": random.randint(0, 63),
        }        
        
    # Perform the action (rendering happens automatically)
    obs = env.step(action, data=action_data)
    
    # Check game state
    if obs and obs.state == GameState.WIN:
        print(f"Game won at step {step}!")
        break
    elif obs and obs.state == GameState.GAME_OVER:
        env.reset()

# Get and display scorecard
scorecard = arc.get_scorecard()
if scorecard:
    print(f"Final Score: {scorecard.score}")

Rendering Options

You can render games in two ways:

  1. Terminal rendering (text-based, default_fps bounded):

    env = arc.make("ls20", render_mode="terminal")
    
  2. Terminal rendering (text-based, unbounded):

    env = arc.make("ls20", render_mode="terminal-fast")
    
  3. Human rendering (matplotlib visualization, default_fps bounded):

    env = arc.make("ls20", render_mode="human")
    
  4. Custom renderer (provide your own function):

    from arcengine import FrameDataRaw
    
    def my_renderer(steps: int, frame_data: FrameDataRaw) -> None:
        print(f"Step {steps}: {frame_data.state.name}")
    
    env = arc.make("ls20", renderer=my_renderer)
    

Changelog

[0.9.3] - 2026-03-09

Added

  • OperationMode.COMPETITION method, see Documentation
  • Official Scoring
    • Average for an individual games is now weighted by the level index (1 indxed)
    • Score for an individual level is now squared. A score of 0.5 now becomes 0.25

Fixed

  • Continued fixes for 404 Scorecard not found

[0.9.2] - 2026-02-26

Added

Fixed

  • 404 Scorecard not found about 50% of the time when in ONLINE mode
  • Game source being downloaded even if local copy already exists

[0.9.1] - 2026-01-29

Initial Release

API Reference

Arcade Class

The Arcade class is the main entry point for interacting with ARC-AGI-3 environments. It handles configuration, environment discovery, and scorecard management.

Constructor Parameters

The Arcade constructor accepts the following parameters. All parameters can be overridden by environment variables, with constructor arguments taking precedence over environment variables.

Parameter Type Default Environment Variable Description
arc_api_key str "" ARC_API_KEY API key for ARC API. If empty and not in offline mode, an anonymous key will be automatically fetched.
arc_base_url str "https://three.arcprize.org" ARC_BASE_URL Base URL for the ARC API.
operation_mode OperationMode OperationMode.NORMAL OPERATION_MODE NORMAL (local + API), ONLINE (API only), OFFLINE (local only), or COMPETITON (API only + compeition scoring).
environments_dir str "environment_files" ENVIRONMENTS_DIR Directory to scan for local metadata.json files.
recordings_dir str "recordings" RECORDINGS_DIR Directory to save game recordings (JSONL format).
logger logging.Logger None - Optional logger instance. If not provided, a default logger logging to STDOUT is created.

Example:

from arc_agi import Arcade, OperationMode

# Use defaults (loads from environment variables or uses defaults)
arc = Arcade()

# Override specific parameters
arc = Arcade(
    arc_api_key="my-key",
    operation_mode=OperationMode.OFFLINE,
    environments_dir="./my_games"
)

Competition Mode

This mode is REQUIRED to show up on the Unverified leaderboard and forces the following behavior.

  • Environments must be interacted with via the API
  • Scoring is against all available environments, even if you choose not to interact with them
  • Only Level Resets are premitted, Game Resets are not allowed and become Level Resets
  • Can only interact (call make) a single time for each environment
  • Can only open a single Scorecard
  • Cannot get scoring of an inflight scorecard, get_scorecard does not work

Note: The Kaggle Compeition is forced into this mode.

Methods

make(game_id, seed=0, scorecard_id=None, save_recording=False, render_mode=None, renderer=None)

Create and initialize an environment wrapper for a specific game.

Parameters:

  • game_id (str): Game identifier in format 'ls20' or 'ls20-1234abcd'. The first 4 characters are the game_id, everything after '-' is the version.
  • seed (int, optional): Random seed for the game. Defaults to 0.
  • scorecard_id (str, optional): Scorecard ID for tracking runs. If None is provided (the default), the system will create and maintain a single default scorecard that is automatically reused across all make() calls. This allows you to track multiple games in the same scorecard without explicitly managing scorecard IDs.
  • save_recording (bool, optional): Whether to save recordings to JSONL file. Defaults to False.
  • render_mode (str, optional): Render mode string ("human", "terminal", "terminal-fast"). If provided, creates a renderer automatically.
  • renderer (Callable[[int, FrameDataRaw], None], optional): Custom renderer function. If both render_mode and renderer are provided, renderer takes precedence.

Returns:

  • EnvironmentWrapper or None: Returns an EnvironmentWrapper instance if successful, None otherwise.

Example:

env = arc.make("ls20", render_mode="terminal")
env = arc.make("ls20-1234abcd", seed=42, save_recording=True)
get_environments()

Get the list of available environments (both local and remote).

Returns:

  • list[EnvironmentInfo]: List of EnvironmentInfo objects representing available environments.

Example:

envs = arc.get_environments()
for env in envs:
    print(f"{env.game_id}: {env.title}")
create_scorecard(source_url=None, tags=None, opaque=None)

Create a new scorecard for tracking game runs.

Parameters:

  • source_url (str, optional): Optional source URL for the scorecard.
  • tags (list[str], optional): Optional list of tags for the scorecard. Defaults to ["wrapper"].
  • opaque (Any, optional): Optional opaque data for the scorecard.

Returns:

  • str: The ID of the newly created scorecard.

Example:

scorecard_id = arc.create_scorecard(
    source_url="https://github.com/my/repo",
    tags=["experiment", "v1"]
)
open_scorecard(source_url=None, tags=None, opaque=None)

Alias for create_scorecard(). Opens a new scorecard.

Parameters: Same as create_scorecard().

Returns:

  • str: The ID of the newly created scorecard.
get_scorecard(scorecard_id=None)

Get a scorecard by ID, converted to EnvironmentScorecard.

Parameters:

  • scorecard_id (str, optional): Scorecard ID. If None is provided (the default), returns the default scorecard that the system is currently using (the same one created automatically when make() is called with scorecard_id=None).

Returns:

  • EnvironmentScorecard or None: Scorecard object if found, None otherwise.

Example:

scorecard = arc.get_scorecard()
if scorecard:
    print(f"Score: {scorecard.score}")
    print(f"Games played: {len(scorecard.games)}")
close_scorecard(scorecard_id=None)

Close a scorecard and return the final scorecard data.

Parameters:

  • scorecard_id (str, optional): Scorecard ID. If None is provided (the default), closes the default scorecard that the system is currently using (the same one created automatically when make() is called with scorecard_id=None). After closing, the default scorecard is cleared and a new one will be created on the next make() call.

Returns:

  • EnvironmentScorecard or None: Final scorecard object if found, None otherwise.

Example:

final_scorecard = arc.close_scorecard()
if final_scorecard:
    print(f"Final score: {final_scorecard.score}")
listen_and_serve

Start a blocking Flask server that exposes the REST API. Uses arc_agi.server.create_app() under the hood. This conforms to the Rest API to allow local execution for interactions with languages other than Python or with this Toolkit running in ONLINE mode.

Parameters:

  • host (str, optional): Bind address. Default "0.0.0.0" to accept connections from any interface.
  • port (int, optional): Port to listen on. Default 8001.
  • competition_mode (bool, optional): If True, enable competition mode. Default False.
  • save_all_recordings (bool, optional): If True, save recordings for all runs. Default False.
  • add_cookie (Callable[[Response, str], Response], optional): Callback to inject a cookie into API responses. Receives (response, api_key); must return the modified response. Use for session stickiness (e.g. ALB app cookies).
  • scorecard_timeout (int, optional): Idle timeout in seconds before scorecards are auto-closed. If set, starts a background cleanup loop.
  • on_scorecard_close (Callable[[EnvironmentScorecard], None], optional): Callback invoked when a scorecard is closed (manually or by timeout).
  • extra_api_routes (Callable[[Arcade, Flask], None], optional): Callback to register custom routes. Receives (arcade, app).
  • renderer (Callable[[int, FrameDataRaw], None], optional): Callback invoked for each frame during gameplay. Receives (step_index, frame_data). Use for logging, visualization, or custom display.
  • **kwargs: Passed through to Flask.run() (e.g. debug=True, threaded=True).

Example (basic):

arc = Arcade()
arc.listen_and_serve(port=8001)

Example (with add_cookie for session stickiness):

from flask import Response

def add_session_cookie(resp: Response, api_key: str) -> Response:
    resp.set_cookie("APPLICATION_COOKIE", api_key, path="/", httponly=True)
    return resp

arc.listen_and_serve(add_cookie=add_session_cookie)

Example (with on_scorecard_close):

def on_close(scorecard):
    print(f"Scorecard closed: {scorecard.score}")

arc.listen_and_serve(on_scorecard_close=on_close)

Example (with extra_api_routes):

def register_custom(arcade, app):
    @app.route("/custom")
    def custom():
        return {"environments": len(arcade.available_environments)}

arc.listen_and_serve(extra_api_routes=register_custom)

Example (with renderer for logging):

def log_frame(step: int, frame_data):
    print(f"Step {step}: state={frame_data.state}, levels_completed={frame_data.levels_completed}")

arc.listen_and_serve(renderer=log_frame)

EnvironmentWrapper Class

The EnvironmentWrapper class provides a common interface for interacting with environments, whether they are local (LocalEnvironmentWrapper) or remote (RemoteEnvironmentWrapper).

Properties

observation_space

Get the observation space (last response data).

Returns:

  • FrameDataRaw or None: The FrameDataRaw object from the last response, or None if no response has been set yet.

Example:

obs = env.observation_space
if obs:
    print(f"Game state: {obs.state}")
    print(f"Levels completed: {obs.levels_completed}")
action_space

Get the action space (available actions).

Returns:

  • list[GameAction]: A list of GameAction objects representing available actions. Returns an empty list if no response has been set yet.

Example:

actions = env.action_space
print(f"Available actions: {[a.name for a in actions]}")
info

Get the environment information.

Returns:

  • EnvironmentInfo: The EnvironmentInfo object for this environment.

Example:

info = env.info
print(f"Game ID: {info.game_id}")
print(f"Title: {info.title}")
print(f"Tags: {info.tags}")

Methods

reset()

Reset the environment and return the initial frame data.

Returns:

  • FrameDataRaw or None: FrameDataRaw object with initial game state, or None if reset failed.

Example:

obs = env.reset()
if obs:
    print("Environment reset successfully")
step(action, data=None, reasoning=None)

Perform a step in the environment.

Parameters:

  • action (GameAction): The game action to perform (e.g., GameAction.ACTION1, GameAction.ACTION2).
  • data (dict[str, Any], optional): Optional action data dictionary. For complex actions, should contain "x" and "y" coordinates.
  • reasoning (dict[str, Any], optional): Optional reasoning dictionary to include in recordings.

Returns:

  • FrameDataRaw or None: FrameDataRaw object with updated game state, or None if step failed.

Example:

from arcengine import GameAction

# Simple action
obs = env.step(GameAction.ACTION1)

# Complex action with coordinates
obs = env.step(
    GameAction.ACTION6,
    data={"x": 32, "y": 32},
    reasoning={"thought": "clicking center of screen"}
)

# Check game state after step
if obs and obs.state == GameState.WIN:
    print("Game won!")

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines on how to contribute to this project.

Citation

If you use this project in your research, please cite it as:

@software{arc_agi,
  author       = {ARC Prize Foundation},
  title        = {ARC-AGI Toolkit},
  year         = {2026},
  url          = {https://github.com/arcprize/ARC-AGI},
  version      = {0.9.1}
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arc_agi-0.9.3.tar.gz (33.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arc_agi-0.9.3-py3-none-any.whl (38.2 kB view details)

Uploaded Python 3

File details

Details for the file arc_agi-0.9.3.tar.gz.

File metadata

  • Download URL: arc_agi-0.9.3.tar.gz
  • Upload date:
  • Size: 33.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for arc_agi-0.9.3.tar.gz
Algorithm Hash digest
SHA256 7af78f9453dec871183528eda8dcff892786ed55d52fea2f8458691505a645d3
MD5 5301d5178e0405ce768b409f5e8151e3
BLAKE2b-256 7c9a024c58f04e668c52f838b145afd0983d5fc411171c96d4688913ade50773

See more details on using hashes here.

File details

Details for the file arc_agi-0.9.3-py3-none-any.whl.

File metadata

  • Download URL: arc_agi-0.9.3-py3-none-any.whl
  • Upload date:
  • Size: 38.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for arc_agi-0.9.3-py3-none-any.whl
Algorithm Hash digest
SHA256 48a4222c8bf8392ad8f4f0cc5734577648e803a398f7a1892bdf8190839a6bdb
MD5 9b1f1c129783219666e8a29141069f21
BLAKE2b-256 9b9841df75d5e6d5d10531cb3b1b3662fff8c180430e16d984587b552312adda

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page