Problem
idun_agent_engine.prompts.helpers.get_prompt() resolves through YAML file → Manager API only. The DB-backed EngineConfig.prompts assembled by idun_agent_standalone.services.engine_config.assemble_engine_config() on every boot and reload is never consulted by user agent code that calls get_prompt("system_prompt").
Symptoms:
- Editing a prompt via
/admin/api/v1/prompts mutates the DB, but user code keeps reading YAML values.
- User code that calls
get_prompt(...) at module import time snapshots the YAML value forever — even /reload doesn't update it.
- The constitution says "DB is steady-state truth in standalone. YAML seeds at first boot only." Today's helper violates that for prompts.
Direction
Follow the MCP registry pattern that already exists in the codebase. See libs/idun_agent_engine/src/idun_agent_engine/mcp/registry.py:
```python
_active_registry: MCPClientRegistry | None = None
def set_active_registry(registry: MCPClientRegistry | None) -> None: ...
def get_active_registry() -> MCPClientRegistry | None: ...
```
Mirror for prompts:
```python
libs/idun_agent_engine/src/idun_agent_engine/prompts/registry.py
_active_prompts: list[PromptConfig] | None = None
def set_active_prompts(prompts: list[PromptConfig] | None) -> None: ...
def get_active_prompts() -> list[PromptConfig] | None: ...
```
Wire-up:
- Boot —
libs/idun_agent_standalone/src/idun_agent_standalone/app.py: after assemble_engine_config(session) returns, call set_active_prompts(engine_config.prompts).
- Reload —
libs/idun_agent_standalone/src/idun_agent_standalone/services/reload.py:commit_with_reload: in the success branch after reload_callable(assembled) returns, call set_active_prompts(assembled.prompts). Never in the failure branch (rollback preserves the prior prompts).
Resolution order in get_prompt() (and get_prompts()):
- Explicit
config_path= arg (tests, scripts).
get_active_prompts() if not None — standalone path (new).
IDUN_CONFIG_PATH YAML (bare engine + YAML, unchanged).
- Manager API (SaaS / Manager path, unchanged).
This keeps all three deployment shapes working, adds the in-process snapshot for standalone, and matches the MCP precedent so the next contributor reads it as a familiar pattern rather than a new abstraction.
Acceptance criteria
Out of scope
- Prompt versioning / labels (Langfuse-style `label='production'` semantics). Track separately if wanted.
- HTTP self-call to
/admin/api/v1/prompts — explicitly rejected, see design discussion.
- DB-direct access from a sync sessionmaker in standalone — rejected in favor of in-memory snapshot.
Problem
idun_agent_engine.prompts.helpers.get_prompt()resolves throughYAML file → Manager APIonly. The DB-backedEngineConfig.promptsassembled byidun_agent_standalone.services.engine_config.assemble_engine_config()on every boot and reload is never consulted by user agent code that callsget_prompt("system_prompt").Symptoms:
/admin/api/v1/promptsmutates the DB, but user code keeps reading YAML values.get_prompt(...)at module import time snapshots the YAML value forever — even/reloaddoesn't update it.Direction
Follow the MCP registry pattern that already exists in the codebase. See
libs/idun_agent_engine/src/idun_agent_engine/mcp/registry.py:```python
_active_registry: MCPClientRegistry | None = None
def set_active_registry(registry: MCPClientRegistry | None) -> None: ...
def get_active_registry() -> MCPClientRegistry | None: ...
```
Mirror for prompts:
```python
libs/idun_agent_engine/src/idun_agent_engine/prompts/registry.py
_active_prompts: list[PromptConfig] | None = None
def set_active_prompts(prompts: list[PromptConfig] | None) -> None: ...
def get_active_prompts() -> list[PromptConfig] | None: ...
```
Wire-up:
libs/idun_agent_standalone/src/idun_agent_standalone/app.py: afterassemble_engine_config(session)returns, callset_active_prompts(engine_config.prompts).libs/idun_agent_standalone/src/idun_agent_standalone/services/reload.py:commit_with_reload: in the success branch afterreload_callable(assembled)returns, callset_active_prompts(assembled.prompts). Never in the failure branch (rollback preserves the prior prompts).Resolution order in
get_prompt()(andget_prompts()):config_path=arg (tests, scripts).get_active_prompts()if not None — standalone path (new).IDUN_CONFIG_PATHYAML (bare engine + YAML, unchanged).This keeps all three deployment shapes working, adds the in-process snapshot for standalone, and matches the MCP precedent so the next contributor reads it as a familiar pattern rather than a new abstraction.
Acceptance criteria
prompts/registry.pyships withset_active_prompts+get_active_prompts, mirroringmcp/registry.pyshape.get_prompt()resolution order updated; YAML/Manager paths untouched for non-standalone deployments.set_active_prompts(engine_config.prompts)after assembly.commit_with_reloadwritesset_active_prompts(assembled.prompts)in the success branch only.get_prompt(...)and observes the new value (no `/reload` needed beyond the normal admin pipeline).IDUN_CONFIG_PATH.get_prompts_from_api()._active_promptsbetween tests so state doesn't bleed.Out of scope
/admin/api/v1/prompts— explicitly rejected, see design discussion.