Substratum personal triangle manifest (v1)
This document defines substratum-triangle.json, the versioned JSON artifact for one device in the Personal Device Triangle (libp2p identity, bootstrap multiaddrs, pinning peer IDs, swarm and JWT root secrets). It replaces ad-hoc triangle .env files for installer and gateway personal layouts.
File locations
| Context | Path |
|---|---|
| macOS (installer local) | ~/.substratum/substratum-triangle.json |
| Windows (installer local) | %ProgramData%\Substratum\substratum-triangle.json |
| Export ZIP (per device) | {sanitized_display_name}.substratum-triangle.json |
| Gateway discovery | Release builds: ./substratum-triangle.json in the process cwd, optional path from SUBSTRATUM_TRIANGLE_CONFIG, then (if those are absent) installer default locations when a file exists: macOS ~/.substratum/substratum-triangle.json, Windows %ProgramData%\Substratum\substratum-triangle.json. Debug builds ignore manifest files for the triangle slice (env only). |
Gateway loading
The gateway is a two-layer config:
Operational (env + optional release JSON):
DATABASE_URL,HOST,PORT,PUBLIC_BASE_URL,CORS_ALLOWED_ORIGINS, storage (S3_*or FlatFS),RUST_LOG, etc. Before reading operational env,bootstrap_dotenvattempts an optional cwd.env(non-fatal if missing). Release may also readsubstratum-gateway.jsonand merge with env (env wins). Compose/systemd still inject operational env as today.Triangle slice (env or manifest by profile): libp2p identity, bootstrap multiaddrs, pinning targets, swarm/JWT secrets.
TriangleConfigFactorychooses: release resolves a manifest path (SUBSTRATUM_TRIANGLE_CONFIG, cwdsubstratum-triangle.json, then installer defaults on macOS/Windows when present), then env; debug uses env only for the triangle so a stray manifest does not override local dev.
substratum-triangle.json does not include DB or HTTP bind settings — use substratum-gateway.json (release) or env for those. See substratum-gateway-application-v1.md, apps/gateway/AGENTS.md, and Config::load.
JSON shape (schema_version 1)
Top-level object:
| Field | Type | Required | Description |
|---|---|---|---|
schema_version | integer | yes | Must be 1 for this revision. |
kind | string | yes | Must be substratum.personal_triangle.device_v1. |
device | object | no | Metadata for operators and UIs. |
device.display_name | string | no | Human-readable device label. |
device.peer_id | string | no | libp2p PeerId string for this device. |
device.storage | object | no | Per-device storage policy (installer Step 3; runtime enforcement is a follow-up). |
device.storage.data_root | string | yes (when device.storage is present) | Absolute or conventional path for node data on this device. |
device.storage.max_bytes | integer | no | Hard cap in bytes (decimal JSON integer; keep within host JSON safe integer range). |
device.storage.warn_bytes | integer | no | Soft warning threshold in bytes; when set, should be ≤ max_bytes if both are present. |
libp2p_identity_key_b64 | string | yes | Base64-encoded protobuf libp2p keypair (same encoding as env LIBP2P_IDENTITY_KEY). |
bootstrap_nodes | string[] | yes | Multiaddr strings (e.g. /ip4/…/tcp/4001/p2p/…). |
pinning_targets | string[] | yes | libp2p PeerId strings for replication targets. |
swarm_master_secret_hex | string | yes | Hex-encoded secret bytes (installer uses 32 random bytes → 64 hex chars). |
jwt_secret_hex | string | yes | Hex-encoded secret bytes (same pattern as swarm). |
Encoding notes
*_hexfields are parsed as hex; the gateway normalizes them to lowercase hex strings internally.- Treat the file like a secret: restrict permissions on Unix (e.g.
0600) where the installer writes it.
Example
{
"schema_version": 1,
"kind": "substratum.personal_triangle.device_v1",
"device": {
"display_name": "My MacBook",
"peer_id": "12D3KooW…",
"storage": {
"data_root": "/var/lib/substratum",
"max_bytes": 34359738368,
"warn_bytes": 25769803776
}
},
"libp2p_identity_key_b64": "…",
"bootstrap_nodes": ["/ip4/100.64.0.2/tcp/4001/p2p/12D3KooW…"],
"pinning_targets": ["12D3KooW…"],
"swarm_master_secret_hex": "010203…",
"jwt_secret_hex": "aabbcc…"
}Related
- ADR 23: Personal Unified Installer
- ADR 24: Installer post-MVP — mesh modes, explicit roles, and cloud relay — optional cloud relay / kit profile beyond this file’s per-device v1 contract.
- ADR 04: Sidecar Design