Often you will want to start your devboxes with your own customizations. For example, you may want to always boot with a specific version of a language or framework or set up a specific repository. Rather than running these commands every time you launch a devbox, you can use a blueprint to optimize boot time by saving the state of your devbox after these commands have been run. By building a blueprint, you get:
  1. Standardization: Define tools, binaries, and configurations your AI agent needs at runtime.
  2. Consistency: Ensure reproducible AI behavior across environments.
  3. Efficiency: Reduce Devbox startup time by pre-installing necessary tools.
  4. Customization: Tailor environments to specific AI-assisted development needs.
When should I use a Blueprint vs. a Snapshot?Snapshots and Blueprints both allow you to run devboxes with customizations. Blueprints are fast to boot and cacheable using Docker layers, while Snapshots are a bit slower on boot (reproducing each step taken in the devbox) but can be created quickly from an existing devbox.Examples:
  • Blueprint: You have a coding agent that is performing a task that requires installing a specific tool. Create a blueprint with set-up steps for the tool and future devboxes will cache the installation to speed up boot and execution time.
  • Snapshot: You have a coding agent in a devbox considering 3 different ways to complete a task. Create a snapshot of the initial state of the devbox, create 3 parallel devboxes from that snapshot, collate the results, and then choose the best option to continue.

Creating a Blueprint

One use case for a blueprint is preinstalling tools your AI agent may want to use. For example, let’s create a simple Blueprint that installs jq, a lightweight command-line JSON processor:
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
  "name": "docs-template",
  "system_setup_commands": ["sudo apt install -y jq"]
}'
Use the Debian package manager (apt) for installing system packages on the Runloop base image.

Using Your Blueprint

Once your Blueprint’s status is build_complete, create a Devbox using it:
curl -X POST 'https://api.runloop.ai/v1/devboxes' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "blueprint_name": "fe-bot",
    "setup_commands": [
      "cd /home/user/runloop-fe && git pull",
      "npm install"
    ]
  }'

Custom files and folders

Basic Configuration with file mounts

To add individual files to your Blueprint, you can use the file_mounts parameter. The key of the file_mounts object is the path to the file in the devbox and the value is the content of the file. By default, blueprints are constructed by user and /home/user/ is where files are allowed to be mounted.
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "python-filemount",
    "file_mounts": {
      "/home/user/script.py": "print(\"Hello, world!\")"
    }
  }'
If you want to mount files to root, you will need to specify building the blueprint as root via launch_parameters
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "python-root-filemount",
    "file_mounts": {
      "/script.py": "print(\"Hello, world!\")"
    },
    "launch_parameters": {
      "user_parameters": {
        "username": "root",
        "uid": 0
      }
    }
  }'

Basic Configuration with CodeMounts

To add a CodeMount to your Blueprint:
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "fe-bot",
    "code_mounts": [{
      "repo_name": "runloop-fe",
      "repo_owner": "runloop"
    }]
  }'
This creates a Blueprint named “fe-bot” that includes the “runloop-fe” repository.

Private Repository Authentication

For private repositories, include a GitHub Personal Access Token (PAT):
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "fe-bot",
    "code_mounts": [{
      "repo_name": "runloop-fe",
      "repo_owner": "runloop",
      "token": "'"${GH_TOKEN}"'"
    }]
  }'
This sets up the necessary environment for immediate use of Git and GitHub tools.

The Blueprint Build Process

When you create a Blueprint, Runloop builds a custom image containing all specified tools and configurations.

Checking Build Status

After creating a Blueprint, check its status:
curl -X GET 'https://api.runloop.ai/v1/blueprints/{blueprint_id}' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY"
Replace {blueprint_id} with the ID returned when you created the Blueprint. Example response:
{
  "id": "bpt_123",
  "name": "docs-template",
  "status": "build_complete",
  "create_time_ms": 1722264065963,
  "parameters": {
    ...
  }
}
The status field indicates the current state of your Blueprint:

Keeping Blueprints Updated

Periodically update Blueprints by building a new blueprint with the same name. This ensures that your AI agents always work with the latest code and dependencies.
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "fe-bot",
    "code_mounts": [{
      "repo_name": "runloop-fe",
      "repo_owner": "runloop",
      "token": "'"${GH_TOKEN}"'"
    }]
  }'
This creates a new Blueprint version with the same name, allowing for faster updates and efficient resource use.

Advanced Usage: Creating a Blueprint from a Public Image Registry

Runloop supports creating Blueprints from public image registries. This is useful when you want to use a specific version of a tool or framework.

Example: Docker Hub Image (wordpress)

This process works with any image that is available on Docker Hub. The following example creates a Blueprint from the wordpress image at https://hub.docker.com/_/wordpress
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "wordpress-bpt",
    "dockerfile": "FROM wordpress"
  }'

Example: Public ECR Image (runloop-dnd-image)

For more information about Docker-in-Docker support and available images, see Running Docker on a Devbox.
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "runloop-dnd-bpt",
    "dockerfile": "FROM public.ecr.aws/f7m5a7m8/devbox:prod-dnd"
  }'

Advanced Usage: Custom Dockerfiles

For more complex environments, you can use a full Dockerfile as the basis for your Blueprint. This is useful when you need to install multiple tools or perform complex setup operations.
  1. Base your Dockerfile on the Runloop base image:
    FROM public.ecr.aws/f7m5a7m8/devbox:prod
    
  2. Runloop will:
    • Use your Dockerfile as the base
    • Apply any system_setup_commands specified
    • Set up any defined CodeMounts
The Runloop base image is public and can be downloaded for local testing.

Advanced Usage: Composable Blueprints

You can create a Blueprint using another Blueprint as the base. This is useful when you want to create a Blueprint that builds upon other Blueprints.
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "composed-blueprint",
    "base_blueprint_id": "bpt_123"
  }'
Alternatively, you can achieve the same result by including a base blueprint using the standard FROM instruction via the Dockerfile parameter to specify the composable Blueprint for building
FROM runloop:bpt_123456789

# Rest of Dockerfile

Advanced Usage: Customizing the Base user

You can customize the base user of a Blueprint. SSH and execs to devboxes created from this blueprint will be via the custom user.
curl -X POST 'https://api.runloop.ai/v1/blueprints' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RUNLOOP_API_KEY" \
  -d '{
    "name": "bp_custom_user",
    "system_setup_commands": [],
    "dockerfile": "FROM ubuntu:22.04\n\nUSER root\nWORKDIR /root\n\nRUN adduser -uid 9999 newdevboxuser\n\nUSER newdevboxuser",
    "launch_parameters": {
      "user_parameters": {
        "username": "newdevboxuser",
        "uid": 9999
      }
    }
  }'

Advanced Usage: Customization via Launch Parameters

Because Blueprints map to images that launch devboxes, we share some of the same launch parameters as devboxes. See these pages for more customizable parameters:

Deleting Blueprints

By default, Blueprints persist indefinitely and continue to incur storage costs. To optimize resource usage and costs, you can delete Blueprints that are no longer needed.

Deleting a Single Blueprint

To delete a specific Blueprint, use its ID:
curl --request POST \
  --url https://api.runloop.ai/v1/blueprints/{id}/delete \
  --header 'Authorization: Bearer <token>'

Cleaning Up Old Blueprint Versions

When you create multiple versions of a Blueprint with the same name, you may want to delete older versions to reduce storage costs. Here’s how to keep only the latest version:

# Create a new blueprint
new_blueprint = client.blueprints.create(
    name="my_blueprint_name",
    system_setup_commands=["sudo apt install -y jq"]
)

# Get all blueprints with the same name
blueprint_results = client.blueprints.list(name='my_blueprint_name')

# Delete all older blueprints, keeping only the newest one
for blueprint in blueprint_results.blueprints:
    if blueprint.id != new_blueprint.id:
        client.blueprints.delete(blueprint.id)
        print(f"Deleted old blueprint: {blueprint.id}")
Be careful when deleting Blueprints, as this action cannot be undone. Ensure you’re not deleting Blueprints that you may need later.

Best Practices

  1. Start Simple: Begin with basic Blueprints and gradually add complexity.
  2. Test Manually Using SSH: You can create a devbox and SSH into it and manually install tools to make sure the commands are correct before layering them into Blueprints.
  3. Always use blueprint_name instead of blueprint_id to ensure you’re using the latest version. Use specific Blueprint IDs only when you need version control for particular setups.
  4. Implement setup_commands in your Devbox creation to keep code and dependencies up-to-date.
  5. Regularly update your Blueprints with the latest repository changes.
  6. Delete unused / deprecated Blueprints.
By leveraging Blueprints effectively, you can create optimized, consistent environments for your AI-assisted software engineering tasks, enhancing productivity and reliability in your development process.

Upcoming Features

Future releases plan to include:
  • Multiple repository support in a single Blueprint
  • Specific branch specifications
  • Git submodules support
  • Advanced multi-step build processes
If any of these features are critical for your use case, please let us know.