Skip to content

Runtime Configuration

When applications run on make87, they receive comprehensive configuration data through the MAKE87_CONFIG environment variable. This JSON structure provides everything your application needs to operate within the platform ecosystem.

Configuration Structure

The runtime configuration contains several key sections:

  • interfaces - Communication endpoints and protocol configurations
  • peripherals - Available hardware peripherals on the node
  • config - Custom application configuration from the manifest
  • storage - Blob storage access credentials and endpoints
  • application_info - Metadata about the running application instance

Complete Configuration Example

Here's a comprehensive example showing all configuration sections:

{
  "interfaces": {
    "zenoh": {
      "name": "zenoh",
      "publishers": {
        "outgoing_message": {
          "topic_name": "outgoing_message",
          "topic_key": "685ec1028e2a2f5cf8e34c40/python-publisher-template-84777966108116/zenoh-outgoing_message/make87_messages-text-text_plain-PlainText/n5megd",
          "message_type": "make87_messages.text.text_plain.PlainText:n5megd",
          "interface_name": "zenoh",
          "congestion_control": "DROP",
          "express": true,
          "priority": "DATA",
          "reliability": "RELIABLE",
          "protocol": "zenoh",
          "encoding": "proto"
        }
      },
      "subscribers": {},
      "requesters": {},
      "providers": {
        "message_endpoint": {
          "endpoint_name": "message_endpoint",
          "endpoint_key": "685ec1028e2a2f5cf8e34c40/python-provider-template-811208011711365/zenoh-message_endpoint/make87_messages-text-text_plain-PlainText/n5megd/make87_messages-text-text_plain-PlainText/n5megd",
          "requester_message_type": "make87_messages.text.text_plain.PlainText:n5megd",
          "provider_message_type": "make87_messages.text.text_plain.PlainText:n5megd",
          "interface_name": "zenoh",
          "handler": {
            "handler_type": "RING",
            "capacity": 10
          },
          "protocol": "zenoh",
          "encoding": "proto"
        }
      },
      "clients": {},
      "servers": {}
    }
  },
  "peripherals": {
    "peripherals": []
  },
  "config": {
    "my_list": [""],
    "sensor_sample_rate": 100,
    "debug_enabled": true
  },
  "storage": {
    "url": "/<your_organization>/<system_uuid>",
    "endpoint_url": "https://storage-endpoint.example.com",
    "access_key": "YOUR_ACCESS_KEY_ID",
    "secret_key": "YOUR_SECRET_ACCESS_KEY"
  },
  "application_info": {
    "deployed_application_id": "6888ef5f07c8db725964efff",
    "deployed_application_name": "6888ef5f07c8db725964efff",
    "system_id": "685ec1028e2a2f5cf8e34c40",
    "application_id": "68816aa9bf350616a6a27007",
    "application_name": "rust-dev-sandbox",
    "is_release_version": false
  }
}

Interfaces Configuration

The interfaces section contains all communication endpoints configured for your application. Each interface maps to those defined in your MAKE87.yml manifest and includes runtime-specific details like connection keys and protocol configurations.

Interface Names vs Keys

Understanding the difference between interface name and key is crucial for communication:

  • name - The interface name from your manifest, used for in-code references and manifest configuration
  • key / topic_key / endpoint_key - A unique identifier generated by make87 and shared with all connected parties to create isolated communication channels

Example:

"publishers": {
  "outgoing_message": {
    "topic_name": "outgoing_message",           // Your manifest reference name
    "topic_key": "system-id/app-id/zenoh-outgoing_message/message-type/version",  // make87 generated unique key
    "interface_name": "zenoh",                  // Interface name from manifest
    // ...
  }
}

The topic_key or endpoint_key ensures that only applications within the same system that are configured to communicate can actually exchange messages, providing automatic isolation.

Publishers

Publishers broadcast data to topics and include configuration for protocol-specific settings:

"publishers": {
  "outgoing_message": {
    "topic_name": "outgoing_message",
    "topic_key": "system-id/app-deployment-id/interface-topic/message-type/version",
    "message_type": "make87_messages.text.text_plain.PlainText:n5megd",
    "interface_name": "zenoh",
    "congestion_control": "DROP",
    "express": true,
    "priority": "DATA",
    "reliability": "RELIABLE",
    "protocol": "zenoh",
    "encoding": "proto"
  }
}

Key fields: - topic_key - Unique identifier for the communication channel - message_type - Specification of the data structure being published - Protocol-specific settings - Configuration options like congestion control, priority, reliability

Subscribers

Subscribers receive data from published topics and include configuration for protocol-specific settings:

"subscribers": {
  "incoming_data": {
    "topic_name": "incoming_data",
    "topic_key": "system-id/app-deployment-id/interface-topic/message-type/version",
    "message_type": "make87_messages.sensor.Temperature:v1",
    "interface_name": "zenoh",
    "handler": {
      "handler_type": "RING",
      "capacity": 50
    },
    "protocol": "zenoh",
    "encoding": "proto"
  }
}

Key fields: - topic_key - Unique identifier for the communication channel to subscribe to - message_type - Specification of the data structure being received - Protocol-specific settings - Configuration options like handler type and capacity

Requesters

Requesters make service calls to providers and include configuration for request handling:

"requesters": {
  "object_detection": {
    "endpoint_name": "object_detection",
    "endpoint_key": "system-id/app-deployment-id/interface-endpoint/request-type/response-type",
    "requester_message_type": "make87_messages.image.compressed.ImagePNG:v1",
    "provider_message_type": "make87_messages.detection.box.Box2DAxisAligned:v1",
    "interface_name": "zenoh",
    "timeout_ms": 5000,
    "protocol": "zenoh",
    "encoding": "proto"
  }
}

Key fields: - endpoint_key - Unique identifier for the service endpoint to call - requester_message_type - Type of outgoing request messages - provider_message_type - Type of expected response messages - Protocol-specific settings - Configuration options like timeout values

Clients

Clients connect to persistent services and include connection configuration:

"clients": {
  "camera_viewer": {
    "name": "camera_viewer",
    "spec": "rtsp",
    "key": "system-id/app-deployment-id/interface-service/spec",
    "interface_name": "video_client",
    "connection_timeout": 10000,
    "retry_attempts": 3,
    "protocol": "rtsp"
  }
}

Key fields: - key - Unique identifier for the service connection - spec - Service specification or API definition - Protocol-specific settings - Configuration options like timeouts and retry behavior

Servers

Servers provide persistent services and include service configuration:

"servers": {
  "api_endpoint": {
    "name": "api_endpoint",
    "key": "system-id/app-deployment-id/interface-service/spec",
    "spec": "my_api:v1.0",
    "interface_name": "config_api",
    "port": 8080,
    "enable_cors": true,
    "max_connections": 100,
    "protocol": "http"
  }
}

Key fields: - key - Unique identifier for the service instance - spec - Service specification or API definition - Protocol-specific settings - Configuration options like port, CORS, connection limits

Providers

Providers handle request-response services and include handler configuration:

"providers": {
  "message_endpoint": {
    "endpoint_name": "message_endpoint",
    "endpoint_key": "system-id/app-deployment-id/interface-endpoint/request-type/response-type",
    "requester_message_type": "make87_messages.text.text_plain.PlainText:n5megd",
    "provider_message_type": "make87_messages.text.text_plain.PlainText:n5megd",
    "interface_name": "zenoh",
    "handler": {
      "handler_type": "RING",
      "capacity": 10
    },
    "protocol": "zenoh",
    "encoding": "proto"
  }
}

Key fields: - endpoint_key - Unique identifier for the service endpoint - requester_message_type - Type of incoming request messages - provider_message_type - Type of outgoing response messages - handler - Configuration for request queuing and processing

Peripherals Configuration

The peripherals section lists hardware peripherals available on the current node:

"peripherals": {
  "peripherals": [
    {
      "id": "camera-0",
      "type": "camera",
      "name": "USB Camera",
      "device_path": "/dev/video0",
      "capabilities": ["capture", "streaming"]
    }
  ]
}

This allows applications to discover and access hardware resources dynamically.

Custom Configuration

The config section contains custom application configuration from your manifest's config field:

"config": {
  "my_list": ["item1", "item2"],
  "sensor_settings": {
    "sample_rate": 100,
    "calibration_offset": 0.5
  },
  "debug_mode": true
}

This provides a way to pass application-specific settings at runtime.

Storage Configuration

The storage section provides credentials and endpoints for the integrated blob storage service:

"storage": {
  "url": "/<your_organization>/<system_uuid>",
  "endpoint_url": "https://nyc3.digitaloceanspaces.com",
  "access_key": "YOUR_ACCESS_KEY_ID",
  "secret_key": "YOUR_SECRET_ACCESS_KEY"
}

Use these credentials to store and retrieve application data, model files, images, and other assets. The URL follows the pattern /<organization>/<system_uuid> to provide automatic namespacing for your system's data.

Application Info

The application_info section provides metadata about the running application instance:

"application_info": {
  "deployed_application_id": "unique-deployment-id",
  "deployed_application_name": "deployment-instance-name",
  "system_id": "system-id",
  "application_id": "application-id",
  "application_name": "my-application",
  "is_release_version": true
}

Key fields: - deployed_application_id - Unique ID for this specific deployment instance - system_id - ID of the parent system containing this application - application_id - Base application ID (shared across all deployments) - is_release_version - Whether this is a release version or development deployment

Accessing Configuration

You can access the runtime configuration in any programming language by reading the MAKE87_CONFIG environment variable:

import make87

# Load configuration using the SDK
config = make87.config.load_config_from_env()

# Access interface endpoints
publisher = config.interfaces.get("zenoh").publishers.get("outgoing_message")

# Access custom configuration
my_setting = config.config.get("my_list")
use make87;

// Load configuration using the SDK
let config = make87::config::load_config_from_env()?;

// Access interface endpoints
if let Some(interface) = config.interfaces.get("zenoh") {
    if let Some(publisher) = interface.publishers.get("outgoing_message") {
        // Use publisher configuration
    }
}
import json
import os

# Parse configuration manually
config = json.loads(os.environ["MAKE87_CONFIG"])

# Access interface endpoints
publisher = config["interfaces"]["zenoh"]["publishers"]["outgoing_message"]
topic_key = publisher["topic_key"]

# Access storage credentials
storage_url = config["storage"]["url"]
access_key = config["storage"]["access_key"]

# Access custom configuration
my_list = config["config"]["my_list"]

# Access application metadata
app_name = config["application_info"]["application_name"]
is_release = config["application_info"]["is_release_version"]
use std::env;
use serde_json::Value;

// Parse configuration manually
let config_str = env::var("MAKE87_CONFIG").expect("MAKE87_CONFIG not found");
let config: Value = serde_json::from_str(&config_str)?;

// Access interface endpoints
let publisher = &config["interfaces"]["zenoh"]["publishers"]["outgoing_message"];
let topic_key = publisher["topic_key"].as_str().unwrap();

// Access storage credentials
let storage_url = config["storage"]["url"].as_str().unwrap();

// Access custom configuration
let my_list = &config["config"]["my_list"];
// Parse configuration
const config = JSON.parse(process.env.MAKE87_CONFIG);

// Access interface endpoints
const publisher = config.interfaces.zenoh.publishers.outgoing_message;
const topicKey = publisher.topic_key;

// Access storage credentials
const storageUrl = config.storage.url;
const accessKey = config.storage.access_key;

// Access custom configuration
const myList = config.config.my_list;

// Access application metadata
const appName = config.application_info.application_name;
#include <nlohmann/json.hpp>
#include <cstdlib>
#include <string>

// Parse configuration
auto config_str = std::getenv("MAKE87_CONFIG");
auto config = nlohmann::json::parse(config_str);

// Access interface endpoints
auto publisher = config["interfaces"]["zenoh"]["publishers"]["outgoing_message"];
std::string topic_key = publisher["topic_key"];

// Access storage credentials
std::string storage_url = config["storage"]["url"];

// Access custom configuration
auto my_list = config["config"]["my_list"];

Best Practices

Configuration Validation

Always validate that required configuration sections are present before using them:

import os
import json

config = json.loads(os.environ.get("MAKE87_CONFIG", "{}"))

# Validate required sections
if "interfaces" not in config:
    raise ValueError("No interfaces configured")

if "storage" not in config:
    print("Warning: No storage access configured")

Environment-Aware Code

Use the application info to adapt behavior based on deployment context:

config = json.loads(os.environ["MAKE87_CONFIG"])
app_info = config["application_info"]

if app_info["is_release_version"]:
    # Production behavior
    log_level = "INFO"
else:
    # Development behavior  
    log_level = "DEBUG"