Problem
The host agent's validate_service_id() at bin/dream-host-agent.py:291-305 rejects any service in CORE_SERVICE_IDS with HTTP 403 "Cannot manage core service".
The problem: CORE_SERVICE_IDS (loaded from config/core-service-ids.json) contains all 20 built-in services, including optional extensions like tts, whisper, comfyui, n8n, qdrant, embeddings, searxng, privacy-shield, perplexica, litellm, token-spy, ape, dreamforge, langfuse, openclaw, opencode.
Only 4 of these are truly "always on" base-compose services: llama-server, open-webui, dashboard, dashboard-api. The other 16 are built-in extensions that users should be able to enable/disable/start/stop via the API.
Impact
The dashboard API cannot manage 16 built-in extensions that it knows about:
- Cannot start them via `POST /v1/extension/start`
- Cannot stop them via `POST /v1/extension/stop`
- Cannot get logs via `POST /v1/extension/logs`
This blocks:
Reproduction
- Fresh DreamServer install
- Disable a built-in extension via CLI: `dream disable tts`
- From the dashboard, try to re-enable it (if it appears in the catalog)
- Expected: extension starts
- Actual: Host agent returns 403 "Cannot manage core service: tts"
Root Cause
The JSON file is misnamed. core-service-ids.json was originally a whitelist of "valid service IDs the agent knows about" but got repurposed as a blocklist of "services the API is not allowed to touch". These are different concepts:
- Whitelist for input validation: all known built-in service IDs
- Blocklist for protection: only truly-always-on base-compose services
Suggested Fix
Introduce two separate constants:
```python
Whitelist: all known built-in service IDs (for input validation)
KNOWN_BUILTIN_SERVICES = load_known_services("config/core-service-ids.json")
Blocklist: services that should never be managed via API (always on)
ALWAYS_ON_SERVICES = frozenset({"llama-server", "open-webui", "dashboard", "dashboard-api"})
```
Then in `validate_service_id()`:
```python
if sid in ALWAYS_ON_SERVICES:
json_response(handler, 403, {"error": f"Cannot manage always-on service: {sid}"})
return None
Valid service: either a known built-in OR a user extension with a manifest
if sid not in KNOWN_BUILTIN_SERVICES and not (USER_EXTENSIONS_DIR / sid).is_dir():
json_response(handler, 404, {"error": f"Extension not found: {sid}"})
return None
```
Also update the extension dir check to support built-in extensions (currently only checks `USER_EXTENSIONS_DIR`):
```python
ext_dir = USER_EXTENSIONS_DIR / sid
if not ext_dir.is_dir():
ext_dir = EXTENSIONS_DIR / sid
manifest_exists = any((ext_dir / n).exists() for n in ("manifest.yaml", "manifest.yml", "manifest.json"))
```
Files Affected
- `dream-server/bin/dream-host-agent.py` — `validate_service_id` function
- `dream-server/config/core-service-ids.json` — consider renaming to `known-service-ids.json` for clarity
- `dream-server/extensions/services/dashboard-api/routers/extensions.py` — may also need updates for consistency
Priority
High — blocks multiple in-flight features (PR Light-Heart-Labs#877 deps+hooks, PR 2 templates, any future API-driven extension management).
Problem
The host agent's
validate_service_id()atbin/dream-host-agent.py:291-305rejects any service inCORE_SERVICE_IDSwith HTTP 403 "Cannot manage core service".The problem:
CORE_SERVICE_IDS(loaded fromconfig/core-service-ids.json) contains all 20 built-in services, including optional extensions liketts,whisper,comfyui,n8n,qdrant,embeddings,searxng,privacy-shield,perplexica,litellm,token-spy,ape,dreamforge,langfuse,openclaw,opencode.Only 4 of these are truly "always on" base-compose services:
llama-server,open-webui,dashboard,dashboard-api. The other 16 are built-in extensions that users should be able to enable/disable/start/stop via the API.Impact
The dashboard API cannot manage 16 built-in extensions that it knows about:
This blocks:
auto_enable_deps=Truecan't enable built-in depsReproduction
Root Cause
The JSON file is misnamed.
core-service-ids.jsonwas originally a whitelist of "valid service IDs the agent knows about" but got repurposed as a blocklist of "services the API is not allowed to touch". These are different concepts:Suggested Fix
Introduce two separate constants:
```python
Whitelist: all known built-in service IDs (for input validation)
KNOWN_BUILTIN_SERVICES = load_known_services("config/core-service-ids.json")
Blocklist: services that should never be managed via API (always on)
ALWAYS_ON_SERVICES = frozenset({"llama-server", "open-webui", "dashboard", "dashboard-api"})
```
Then in `validate_service_id()`:
```python
if sid in ALWAYS_ON_SERVICES:
json_response(handler, 403, {"error": f"Cannot manage always-on service: {sid}"})
return None
Valid service: either a known built-in OR a user extension with a manifest
if sid not in KNOWN_BUILTIN_SERVICES and not (USER_EXTENSIONS_DIR / sid).is_dir():
json_response(handler, 404, {"error": f"Extension not found: {sid}"})
return None
```
Also update the extension dir check to support built-in extensions (currently only checks `USER_EXTENSIONS_DIR`):
```python
ext_dir = USER_EXTENSIONS_DIR / sid
if not ext_dir.is_dir():
ext_dir = EXTENSIONS_DIR / sid
manifest_exists = any((ext_dir / n).exists() for n in ("manifest.yaml", "manifest.yml", "manifest.json"))
```
Files Affected
Priority
High — blocks multiple in-flight features (PR Light-Heart-Labs#877 deps+hooks, PR 2 templates, any future API-driven extension management).