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 configurationsperipherals
- Available hardware peripherals on the nodeconfig
- Custom application configuration from the manifeststorage
- Blob storage access credentials and endpointsapplication_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 configurationkey
/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 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: