v0.0.9.2
Build Service / BuildPackage (push) Has been cancelled

This commit is contained in:
2026-05-24 19:10:21 -04:00
parent b308d0ceaa
commit 70b8aab0f3
10 changed files with 169 additions and 45 deletions
+11 -4
View File
@@ -150,7 +150,8 @@ preserved.
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Space-CLI Web UI (gotty terminal) | 8080 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | Basic auth: `admin:<store.password>` | | Space-CLI Web UI (gotty terminal) | 8080 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | Basic auth: `admin:<store.password>` |
| Explorer Web UI | 3000 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | SvelteKit explorer. **TODO** — daemon stubbed pending the prebuilt explorer image; the interface is still registered but nothing listens yet. | | Explorer Web UI | 3000 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | SvelteKit explorer. **TODO** — daemon stubbed pending the prebuilt explorer image; the interface is still registered but nothing listens yet. |
| Subspaces Web UI | 7777 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs` UI. No built-in auth. Only useful while Subspaces is enabled. | | Subspaces Web UI | 7777 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs` daemon (subsd). No built-in auth. Only useful while Subspaces is enabled. |
| Subs API | 7777 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | The subsd REST API (same daemon/port as above), exposed as a distinct `api` interface separate from the prover and registry. Only useful while Subspaces is enabled. |
| Subspaces Prover | 8888 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs-prover` RISC Zero prover server (no GPU). Its own StartOS interface. Only useful while Subspaces is enabled. | | Subspaces Prover | 8888 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `subs-prover` RISC Zero prover server (no GPU). Its own StartOS interface. Only useful while Subspaces is enabled. |
| Subspaces Registry | 8081 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `registry-server` for publishing/resolving handles (remapped from its upstream default 8080 to avoid colliding with the gotty terminal on 8080). Its own StartOS interface. Only useful while Subspaces is enabled. | | Subspaces Registry | 8081 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `registry-server` for publishing/resolving handles (remapped from its upstream default 8080 to avoid colliding with the gotty terminal on 8080). Its own StartOS interface. Only useful while Subspaces is enabled. |
| Certrelay | 7778 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `certrelay` server (always on). Serves cryptographic proofs binding handles to owner keys. **Setup:** run **Configure Certrelay** and set `CERTRELAY_SELF_URL` to the publicly visible URL StartOS exposes for this interface. | | Certrelay | 7778 | HTTP | LAN / `.local` / Tor / clearnet (via StartOS) | `certrelay` server (always on). Serves cryptographic proofs binding handles to owner keys. **Setup:** run **Configure Certrelay** and set `CERTRELAY_SELF_URL` to the publicly visible URL StartOS exposes for this interface. |
@@ -178,6 +179,7 @@ preserved.
| `enable-subspaces` | Enable Subspaces | Enabled (hidden when already on) | Any | Sets `store.enableSubspaces = true` and triggers a service restart so the Subspaces chain (build → wallet → subs-prover → subs) takes effect. | | `enable-subspaces` | Enable Subspaces | Enabled (hidden when already on) | Any | Sets `store.enableSubspaces = true` and triggers a service restart so the Subspaces chain (build → wallet → subs-prover → subs) takes effect. |
| `disable-subspaces` | Disable Subspaces | Enabled (hidden when already off) | Any | Sets `store.enableSubspaces = false` and triggers a service restart so the subs and subs-prover daemons stop. On-disk data at `/data/subspaces` is preserved. | | `disable-subspaces` | Disable Subspaces | Enabled (hidden when already off) | Any | Sets `store.enableSubspaces = false` and triggers a service restart so the subs and subs-prover daemons stop. On-disk data at `/data/subspaces` is preserved. |
| `reset-subspaces-state` | Reset Subspaces State | Enabled | Any | Deletes `/data/subspaces` (runtime data only — binaries ship in the image). Use to wipe local handles/proofs. The spaces wallet on spaced is preserved. Warning-gated. | | `reset-subspaces-state` | Reset Subspaces State | Enabled | Any | Deletes `/data/subspaces` (runtime data only — binaries ship in the image). Use to wipe local handles/proofs. The spaces wallet on spaced is preserved. Warning-gated. |
| `set-subs-prover` | Enable / Disable Subspaces Prover | Enabled | Any | Toggle (`store.enableSubsProver`, default **off**) that starts/stops only the `subs-prover` daemon, independent of the overall Subspaces toggle. When off, the daemon doesn't start but its interface (8888) stays registered. Saving restarts the service. |
| `configure-certrelay` | Configure Certrelay | Enabled | Any | Sets `CERTRELAY_SELF_URL` (text), `CERTRELAY_BOOTSTRAP` (toggle), and `CERTRELAY_HEALTHCHECK_HANDLE` (text) in `store.json`; prefilled with current values. Saving restarts the service so certrelay picks up the new config. | | `configure-certrelay` | Configure Certrelay | Enabled | Any | Sets `CERTRELAY_SELF_URL` (text), `CERTRELAY_BOOTSTRAP` (toggle), and `CERTRELAY_HEALTHCHECK_HANDLE` (text) in `store.json`; prefilled with current values. Saving restarts the service so certrelay picks up the new config. |
## Backups and Restore ## Backups and Restore
@@ -193,7 +195,7 @@ the same idempotent init logic runs and reuses the existing credentials in
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `postgres` (daemon `ready`) | Database | 60 s | TCP listen on `127.0.0.1:5432` | | `postgres` (daemon `ready`) | Database | 60 s | TCP listen on `127.0.0.1:5432` |
| `spaced` (daemon `ready`) | Spaced RPC | 120 s | TCP listen on `127.0.0.1:7225` | | `spaced` (daemon `ready`) | Spaced RPC | 120 s | TCP listen on `127.0.0.1:7225` |
| `subs-prover` (daemon `ready`) | Subspaces Prover | 60 s | TCP listen on `0.0.0.0:8888`. Only present when Subspaces is enabled. | | `subs-prover` (daemon `ready`) | Subspaces Prover | 60 s | TCP listen on `0.0.0.0:8888`. Only present when Subspaces **and** the `set-subs-prover` toggle are enabled (toggle defaults off). Polled every 30 s; nothing depends on it. |
| `subs-registry` (daemon `ready`) | Subspaces Registry | 60 s | TCP listen on `0.0.0.0:8081`. Only present when Subspaces is enabled. | | `subs-registry` (daemon `ready`) | Subspaces Registry | 60 s | TCP listen on `0.0.0.0:8081`. Only present when Subspaces is enabled. |
| `subs` (daemon `ready`) | Subspaces Web UI | 60 s | TCP listen on `0.0.0.0:7777`. Only present when Subspaces is enabled. | | `subs` (daemon `ready`) | Subspaces Web UI | 60 s | TCP listen on `0.0.0.0:7777`. Only present when Subspaces is enabled. |
| `certrelay` (daemon `ready`) | Certrelay | 120 s | TCP listen on `0.0.0.0:7778`. Always on. Polled every 30 s. | | `certrelay` (daemon `ready`) | Certrelay | 120 s | TCP listen on `0.0.0.0:7778`. Always on. Polled every 30 s. |
@@ -240,8 +242,11 @@ the same idempotent init logic runs and reuses the existing credentials in
Subspaces** to start it. It ships as the prebuilt `horologger/subs:v0.1.0` Subspaces** to start it. It ships as the prebuilt `horologger/subs:v0.1.0`
image (no compile step), so enabling is fast — the three daemons start as image (no compile step), so enabling is fast — the three daemons start as
soon as the image is on the box. Enabling runs three daemons, each with its soon as the image is on the box. Enabling runs three daemons, each with its
own StartOS interface: **subs** (Web UI, 7777), **subs-prover** (8888, no own StartOS interface: **subs** (Web UI, 7777), **registry-server** (8081),
GPU), **registry-server** (8081). subs loads the existing `default` spaces and — only if the separate **Enable / Disable Subspaces Prover** toggle is
on (default **off**) — **subs-prover** (8888, no GPU). The prover's
interface is always registered even when its daemon is off. subs loads the
existing `default` spaces
wallet at startup and does **not** create it — create it first from the wallet at startup and does **not** create it — create it first from the
Space-CLI Web UI with `spaces createwallet` if you haven't. Subspaces is Space-CLI Web UI with `spaces createwallet` if you haven't. Subspaces is
independent of the Embedded Explorer toggle — you can run any combination independent of the Embedded Explorer toggle — you can run any combination
@@ -348,6 +353,7 @@ explorer_ui:
subspaces: subspaces:
default_enabled: false # opt-in via Enable Subspaces action default_enabled: false # opt-in via Enable Subspaces action
store_field: enableSubspaces store_field: enableSubspaces
subs_prover_default_enabled: false # separate toggle: set-subs-prover (store.enableSubsProver)
image: horologger/subs:v0.1.0 # prebuilt; no compile step image: horologger/subs:v0.1.0 # prebuilt; no compile step
data_dir: /data/subspaces/data data_dir: /data/subspaces/data
wallet: default # loaded by subs, NOT created (create via space-cli first) wallet: default # loaded by subs, NOT created (create via space-cli first)
@@ -407,6 +413,7 @@ actions:
- reset-explorer-state - reset-explorer-state
- enable-subspaces - enable-subspaces
- disable-subspaces - disable-subspaces
- set-subs-prover
- reset-subspaces-state - reset-subspaces-state
- configure-certrelay - configure-certrelay
``` ```
+2
View File
@@ -13,6 +13,7 @@ import { resetPassword } from './resetPassword'
import { resetSpacedState } from './resetSpacedState' import { resetSpacedState } from './resetSpacedState'
import { resetSubspacesState } from './resetSubspacesState' import { resetSubspacesState } from './resetSubspacesState'
import { setBitcoinRpc } from './setBitcoinRpc' import { setBitcoinRpc } from './setBitcoinRpc'
import { setSubsProver } from './setSubsProver'
import { showCredentials } from './showCredentials' import { showCredentials } from './showCredentials'
import { showDbCredentials } from './showDbCredentials' import { showDbCredentials } from './showDbCredentials'
import { showPassword } from './showPassword' import { showPassword } from './showPassword'
@@ -35,5 +36,6 @@ export const actions = sdk.Actions.of()
.addAction(resetExplorerState) .addAction(resetExplorerState)
.addAction(enableSubspaces) .addAction(enableSubspaces)
.addAction(disableSubspaces) .addAction(disableSubspaces)
.addAction(setSubsProver)
.addAction(resetSubspacesState) .addAction(resetSubspacesState)
.addAction(configureCertrelay) .addAction(configureCertrelay)
+61
View File
@@ -0,0 +1,61 @@
import { storeJson } from '../fileModels/storeJson'
import { i18n } from '../i18n'
import { sdk } from '../sdk'
const { InputSpec, Value } = sdk
const inputSpec = InputSpec.of({
enabled: Value.toggle({
name: i18n('Run Subspaces Prover'),
description: i18n(
'When on, the subs-prover daemon starts (only while Subspaces itself is enabled). It runs lengthy timing tests on boot and can take a long time to become ready. Off by default. The Subspaces Prover interface (port 8888) stays registered either way.',
),
warning: null,
footnote: null,
default: false,
}),
})
export const setSubsProver = sdk.Action.withInput(
// id
'set-subs-prover',
// metadata
async ({ effects }) => ({
name: i18n('Enable / Disable Subspaces Prover'),
description: i18n(
'Independently start or stop the subs-prover daemon, separate from the overall Subspaces toggle. Saving restarts the service.',
),
warning: null,
allowedStatuses: 'any',
group: null,
visibility: 'enabled',
}),
// input
inputSpec,
// prefill — current value
async ({ effects }) => {
const enabled = await storeJson.read((s) => s.enableSubsProver).once()
return { enabled: enabled === true }
},
// run
async ({ effects, input }) => {
await storeJson.merge(effects, { enableSubsProver: input.enabled })
return {
version: '1',
title: i18n('Success'),
message: input.enabled
? i18n(
'Subspaces Prover enabled. The service is restarting; the prover starts after the other Subspaces daemons and may take a while to become ready.',
)
: i18n(
'Subspaces Prover disabled. The service is restarting; the prover daemon will not start. Its interface (8888) remains registered.',
),
result: null,
}
},
)
+1
View File
@@ -27,6 +27,7 @@ const shape = z.object({
.catch(null), .catch(null),
enableExplorer: z.boolean().nullable().catch(null), enableExplorer: z.boolean().nullable().catch(null),
enableSubspaces: z.boolean().nullable().catch(null), enableSubspaces: z.boolean().nullable().catch(null),
enableSubsProver: z.boolean().nullable().catch(null),
certrelaySelfUrl: z.string().nullable().catch(null), certrelaySelfUrl: z.string().nullable().catch(null),
certrelayBootstrap: z.boolean().nullable().catch(null), certrelayBootstrap: z.boolean().nullable().catch(null),
certrelayHealthcheckHandle: z.string().nullable().catch(null), certrelayHealthcheckHandle: z.string().nullable().catch(null),
+13
View File
@@ -128,6 +128,19 @@ const dict = {
133, 133,
'Certrelay configuration saved. The service is restarting to apply the new settings.': 'Certrelay configuration saved. The service is restarting to apply the new settings.':
134, 134,
'Enable / Disable Subspaces Prover': 135,
'Independently start or stop the subs-prover daemon, separate from the overall Subspaces toggle. Saving restarts the service.':
136,
'Run Subspaces Prover': 137,
'When on, the subs-prover daemon starts (only while Subspaces itself is enabled). It runs lengthy timing tests on boot and can take a long time to become ready. Off by default. The Subspaces Prover interface (port 8888) stays registered either way.':
138,
'Subspaces Prover enabled. The service is restarting; the prover starts after the other Subspaces daemons and may take a while to become ready.':
139,
'Subspaces Prover disabled. The service is restarting; the prover daemon will not start. Its interface (8888) remains registered.':
140,
'Subs API': 141,
'REST API of the subs daemon (subsd) for Subspaces operations. Distinct from the Subspaces Prover and Subspaces Registry. Only useful while Subspaces is enabled.':
142,
// interfaces.ts // interfaces.ts
'Space-CLI Web UI': 12, 'Space-CLI Web UI': 12,
+11 -7
View File
@@ -2,12 +2,16 @@ import { storeJson } from '../fileModels/storeJson'
import { sdk } from '../sdk' import { sdk } from '../sdk'
export const taskSeedEnableSubspaces = sdk.setupOnInit(async (effects) => { export const taskSeedEnableSubspaces = sdk.setupOnInit(async (effects) => {
const existing = await storeJson.read((s) => s.enableSubspaces).once() const store = await storeJson.read().once()
if (existing !== null && existing !== undefined) return
await storeJson.merge( const patch: { enableSubspaces?: boolean; enableSubsProver?: boolean } = {}
effects, if (store?.enableSubspaces === null || store?.enableSubspaces === undefined)
{ enableSubspaces: false }, patch.enableSubspaces = false
{ allowWriteAfterConst: true }, // subs-prover is independently gated and defaults OFF.
) if (store?.enableSubsProver === null || store?.enableSubsProver === undefined)
patch.enableSubsProver = false
if (Object.keys(patch).length > 0) {
await storeJson.merge(effects, patch, { allowWriteAfterConst: true })
}
}) })
+21 -1
View File
@@ -68,7 +68,27 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
query: {}, query: {},
}) })
const subspacesReceipt = await subspacesMultiOrigin.export([subspaces]) // The subs daemon ("subsd — HTTP REST API server for subs operations") serves
// its REST API on the same port. Expose it as a distinct `api` interface,
// separate from the prover (8888) and registry (8081) interfaces.
const subsApi = sdk.createInterface(effects, {
name: i18n('Subs API'),
id: 'subs-api',
description: i18n(
'REST API of the subs daemon (subsd) for Subspaces operations. Distinct from the Subspaces Prover and Subspaces Registry. Only useful while Subspaces is enabled.',
),
type: 'api',
masked: false,
schemeOverride: null,
username: null,
path: '',
query: {},
})
const subspacesReceipt = await subspacesMultiOrigin.export([
subspaces,
subsApi,
])
const proverMulti = sdk.MultiHost.of(effects, 'subspaces-prover-multi') const proverMulti = sdk.MultiHost.of(effects, 'subspaces-prover-multi')
const proverMultiOrigin = await proverMulti.bindPort(SUBSPACES_PROVER_PORT, { const proverMultiOrigin = await proverMulti.bindPort(SUBSPACES_PROVER_PORT, {
+42 -28
View File
@@ -56,6 +56,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
const { password: APP_PASSWORD, btcAuth, dbAuth, spacedAuth } = store const { password: APP_PASSWORD, btcAuth, dbAuth, spacedAuth } = store
const enableExplorer = store.enableExplorer === true const enableExplorer = store.enableExplorer === true
const enableSubspaces = store.enableSubspaces === true const enableSubspaces = store.enableSubspaces === true
// subs-prover is independently gated and defaults OFF (null/undefined => false).
const enableSubsProver = store.enableSubsProver === true
const spacedEnv = { const spacedEnv = {
SPACED_CHAIN, SPACED_CHAIN,
@@ -262,8 +264,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
// Appends the Subspaces chain (fetch → build → wallet ensure → subs-prover → // Appends the Subspaces chain (fetch → build → wallet ensure → subs-prover →
// subs daemon) to any existing chain. `as any` because the chain's TS type // subs daemon) to any existing chain. `as any` because the chain's TS type
// depends on prior IDs and we can't easily express the union here. // depends on prior IDs and we can't easily express the union here.
const withSubspaces = (chain: any): any => const withSubspaces = (chain: any): any => {
chain let c = chain
.addOneshot('subspaces-dirs', { .addOneshot('subspaces-dirs', {
subcontainer: subspacesSub, subcontainer: subspacesSub,
exec: { exec: {
@@ -278,32 +280,6 @@ export const main = sdk.setupMain(async ({ effects }) => {
}, },
requires: [], requires: [],
}) })
.addDaemon('subs-prover', {
subcontainer: subspacesSub,
exec: {
command: [
'sh',
'-c',
`cd ${SUBSPACES_PROVER_DIR} && exec ${SUBSPACES_PROVER_BIN} --server --server-port ${SUBSPACES_PROVER_PORT}`,
],
env: proverEnv,
// Run as root: the horologger/subs image declares USER subs, but our
// /data volume + subdirs are root-owned, so the non-root user can't
// traverse/write them. Root sidesteps the ownership mismatch.
user: 'root',
},
ready: {
display: i18n('Subspaces Prover'),
fn: () =>
sdk.healthCheck.checkPortListening(effects, SUBSPACES_PROVER_PORT, {
successMessage: i18n('subs-prover is ready'),
errorMessage: i18n('subs-prover is not ready'),
}),
gracePeriod: 60_000,
trigger: sdk.trigger.cooldownTrigger(30_000),
},
requires: ['subspaces-dirs'],
})
.addDaemon('subs-registry', { .addDaemon('subs-registry', {
subcontainer: subspacesSub, subcontainer: subspacesSub,
exec: { exec: {
@@ -349,6 +325,44 @@ export const main = sdk.setupMain(async ({ effects }) => {
requires: ['subspaces-dirs', 'spaced', 'subs-registry'], requires: ['subspaces-dirs', 'spaced', 'subs-registry'],
}) })
// subs-prover is opt-in and DISABLED BY DEFAULT (toggle via the "Enable
// Subspaces Prover" action). Its interface (8888) stays registered either
// way (see interfaces.ts), but the daemon only starts when enabled. It's
// added LAST and depends on every other subspaces daemon; it runs lengthy
// timing tests on boot and NOTHING depends on it, so its slow startup never
// blocks anything else.
if (enableSubsProver) {
c = c.addDaemon('subs-prover', {
subcontainer: subspacesSub,
exec: {
command: [
'sh',
'-c',
`cd ${SUBSPACES_PROVER_DIR} && exec ${SUBSPACES_PROVER_BIN} --server --server-port ${SUBSPACES_PROVER_PORT}`,
],
env: proverEnv,
// Run as root: the horologger/subs image declares USER subs, but our
// /data volume + subdirs are root-owned, so the non-root user can't
// traverse/write them. Root sidesteps the ownership mismatch.
user: 'root',
},
ready: {
display: i18n('Subspaces Prover'),
fn: () =>
sdk.healthCheck.checkPortListening(effects, SUBSPACES_PROVER_PORT, {
successMessage: i18n('subs-prover is ready'),
errorMessage: i18n('subs-prover is not ready'),
}),
gracePeriod: 60_000,
trigger: sdk.trigger.cooldownTrigger(30_000),
},
requires: ['subspaces-dirs', 'subs-registry', 'subs'],
})
}
return c
}
if (!enableExplorer) { if (!enableExplorer) {
// Spaces-only mode: spaced + gotty terminal. No PostgreSQL, no indexer. // Spaces-only mode: spaced + gotty terminal. No PostgreSQL, no indexer.
// User can flip the toggle via the Enable Embedded Explorer action; // User can flip the toggle via the Enable Embedded Explorer action;
+2 -2
View File
@@ -1,7 +1,7 @@
import { VersionGraph } from '@start9labs/start-sdk' import { VersionGraph } from '@start9labs/start-sdk'
import { v_0_0_9_1 } from './v0.0.9.1' import { v_0_0_9_2 } from './v0.0.9.2'
export const versionGraph = VersionGraph.of({ export const versionGraph = VersionGraph.of({
current: v_0_0_9_1, current: v_0_0_9_2,
other: [], other: [],
}) })
@@ -1,9 +1,11 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk' import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_0_0_9_1 = VersionInfo.of({ export const v_0_0_9_2 = VersionInfo.of({
version: '0.0.9:1', version: '0.0.9:2',
releaseNotes: { releaseNotes: {
en_US: `- Embedded Certrelay (prebuilt \`horologger/certrelay:v0.2.3\` image, static musl binaries). Always on — runs the \`certrelay\` server on port 7778 from service start, as its own StartOS interface. It serves cryptographic proofs binding Bitcoin-anchored handles to owner keys, talking to the local spaced over loopback using the store.spacedAuth credentials. The bundled \`fabric\` CLI is copied to /data/bin/fabric so it's runnable from the Space-CLI Web UI. New "Configure Certrelay" action sets CERTRELAY_SELF_URL, CERTRELAY_BOOTSTRAP, and CERTRELAY_HEALTHCHECK_HANDLE (stored in store.json; saving restarts the service). Set CERTRELAY_SELF_URL to the publicly visible URL StartOS exposes for the Certrelay interface. en_US: `- Added a dedicated "Subs API" interface (type api) on the subs daemon's port (7777), distinct from the Subspaces Prover (8888) and Subspaces Registry (8081) interfaces. The subs daemon is "subsd — an HTTP REST API server"; this surfaces that REST API as its own dashboard entry.
- New "Enable / Disable Subspaces Prover" action independently gates just the subs-prover daemon (store.enableSubsProver), **disabled by default**. When off, subs-prover does not start (it runs lengthy boot-time timing tests), but its interface on 8888 stays registered. It is added last and nothing depends on it, so its slow startup never blocks subs, the registry, or certrelay.
- Embedded Certrelay (prebuilt \`horologger/certrelay:v0.2.3\` image, static musl binaries). Always on — runs the \`certrelay\` server on port 7778 from service start, as its own StartOS interface. It serves cryptographic proofs binding Bitcoin-anchored handles to owner keys, talking to the local spaced over loopback using the store.spacedAuth credentials. The bundled \`fabric\` CLI is copied to /data/bin/fabric so it's runnable from the Space-CLI Web UI. New "Configure Certrelay" action sets CERTRELAY_SELF_URL, CERTRELAY_BOOTSTRAP, and CERTRELAY_HEALTHCHECK_HANDLE (stored in store.json; saving restarts the service). Set CERTRELAY_SELF_URL to the publicly visible URL StartOS exposes for the Certrelay interface.
- Removed the build-from-source chains for the Go indexer and the SvelteKit explorer, and dropped their builder images (\`golang:1.23-alpine\`, \`node:20-alpine\`). This shrinks the .s9pk and removes the multi-minute first-enable compile. The indexer + explorer-UI daemons are now stubbed with TODOs in startos/main.ts pending prebuilt images (indexer image not yet produced; explorer image to be provided). Enabling the embedded explorer currently starts PostgreSQL only. All explorer-indexer actions (show-db-credentials, reset-db-state, reset-indexer-state, reset-explorer-state) are retained. - Removed the build-from-source chains for the Go indexer and the SvelteKit explorer, and dropped their builder images (\`golang:1.23-alpine\`, \`node:20-alpine\`). This shrinks the .s9pk and removes the multi-minute first-enable compile. The indexer + explorer-UI daemons are now stubbed with TODOs in startos/main.ts pending prebuilt images (indexer image not yet produced; explorer image to be provided). Enabling the embedded explorer currently starts PostgreSQL only. All explorer-indexer actions (show-db-credentials, reset-db-state, reset-indexer-state, reset-explorer-state) are retained.
- Embedded Subspaces support (prebuilt \`horologger/subs:v0.1.0\` image). Opt-in via the new "Enable Subspaces" action; "Disable Subspaces" stops it. No compile step — enabling starts three prebuilt daemons, each on its own StartOS interface: **subs** (Web UI, 7777), **subs-prover** (RISC Zero prover, no GPU, 8888), and **registry-server** (handle registry, 8081). subs loads the existing \`default\` spaces wallet at startup (it does not create one). Runtime data persists at /data/subspaces/data across restarts and toggles. New "Reset Subspaces State" action wipes local data. Adds a fifth manifest image (\`horologger/subs:v0.1.0\`, ~84 MB) — switched from building \`spacesops/subs\` from source with \`rust:1-slim\` to shrink the .s9pk and eliminate the multi-minute first-enable compile. - Embedded Subspaces support (prebuilt \`horologger/subs:v0.1.0\` image). Opt-in via the new "Enable Subspaces" action; "Disable Subspaces" stops it. No compile step — enabling starts three prebuilt daemons, each on its own StartOS interface: **subs** (Web UI, 7777), **subs-prover** (RISC Zero prover, no GPU, 8888), and **registry-server** (handle registry, 8081). subs loads the existing \`default\` spaces wallet at startup (it does not create one). Runtime data persists at /data/subspaces/data across restarts and toggles. New "Reset Subspaces State" action wipes local data. Adds a fifth manifest image (\`horologger/subs:v0.1.0\`, ~84 MB) — switched from building \`spacesops/subs\` from source with \`rust:1-slim\` to shrink the .s9pk and eliminate the multi-minute first-enable compile.
- Five distinct interfaces now appear in the dashboard: **Space-CLI Web UI** (gotty terminal, 8080), **Explorer Web UI** (3000, opt-in), **Subspaces Web UI** (7777, opt-in), **Subspaces Prover** (8888, opt-in), **Subspaces Registry** (8081, opt-in). Internal "Web UI" references renamed to **Space-CLI Web UI** for clarity. - Five distinct interfaces now appear in the dashboard: **Space-CLI Web UI** (gotty terminal, 8080), **Explorer Web UI** (3000, opt-in), **Subspaces Web UI** (7777, opt-in), **Subspaces Prover** (8888, opt-in), **Subspaces Registry** (8081, opt-in). Internal "Web UI" references renamed to **Space-CLI Web UI** for clarity.