Prompt Asset Pattern¶
This content was migrated from
Documentation/prompt_asset_management_pattern.mdand verified against the current codebase. Review for accuracy.
What This Pattern Is¶
The Prompt Asset Management (PAM) pattern separates prompt content (what we ask the LLM) from prompt logic (how we format and deliver it). Every LLM-powered node in the Global Supervisor pipeline follows this pattern.
Structure¶
{node}_helpers/
├── prompts/ # Content Layer (Markdown files)
│ └── {use_case}.md # Human-readable prompt templates
└── prompt_builder.py # Logic Layer (Python)
# Loads templates, injects variables
Where It's Used¶
The pattern is used in 10 helper modules across the supervisor pipeline (verified from codebase):
| Helper Module | Prompt Files | Builder |
|---|---|---|
intent_classification_helpers/ |
intent_classification.md |
Static/dynamic split with [SYSTEM]/[DEVELOPER]/[USER] markers |
entity_resolution_helpers/ |
context_resolution.md, entity_resolution.md |
Context-aware candidate resolution |
disambiguation_blocking_helpers/ |
disambiguation_blocking.md |
Ask-only HITL question generation |
disambiguation_helpers/ |
disambiguation_simple.md, disambiguation_complex.md, disambiguation_voice.md |
Answer + "by the way" flows |
disambiguation_resolution_helpers/ |
disambiguation_matching.md, ask_entity_details.md |
Response matching, entity detail questions |
create_new_entity_helpers/ |
extract_entity_details.md |
New entity detail extraction |
fact_extraction_helpers/ |
fact_extraction.md |
Fact extraction from messages |
planner_helpers/ |
(planner prompts) | Complex query planning |
summarization_helpers/ |
(summarization prompts) | Conversation summarization |
ui_helpers/ |
greeting.md, greeting_simple.md, greeting_voice.md, simple_btw.md, + more |
UI response generation with variants |
How It Works¶
1. Prompt templates use {{PLACEHOLDER}} variables¶
# File: prompts/intent_classification.md
# [SYSTEM]
You classify user messages for routing...
# [DEVELOPER]
## Decision Rules
...
# [USER]
**Previous conversation:**
{{CONVERSATION_CONTEXT}}
**Current message to classify:**
{{USER_MESSAGE}}
2. Builder loads template and injects values¶
# File: prompt_builder.py
def build_dynamic_user_content(user_message, conversation_context, ...):
template = _load_prompt_template("intent_classification.md")
_, dynamic_template = _split_static_dynamic(template)
content = dynamic_template.replace("{{USER_MESSAGE}}", user_message)
content = content.replace("{{CONVERSATION_CONTEXT}}", context_str)
return content
3. Some builders use static/dynamic split for LLM cache efficiency¶
The intent classification builder splits the prompt at the [USER] marker. The static portion ([SYSTEM] + [DEVELOPER]) is identical across all requests and cached in memory. Only the dynamic portion ([USER] section with message-specific content) changes per request. This enables LLM provider-side prompt caching.
Why This Matters¶
| Benefit | Before (embedded strings) | After (PAM pattern) |
|---|---|---|
| Reviewability | Prompts hidden in 500-line Python files | Prompts in readable .md files with clear git diffs |
| Non-dev contribution | Product owner must edit Python code | Product owner edits .md directly — no Python needed |
| Testability | Can't test prompt content separately | Test loading, test variable injection, test content independently |
| A/B testing | Requires code change | Swap template file or select variant at runtime |
| Variant management | Multiple f-strings in same file | Separate files: greeting.md, greeting_simple.md, greeting_voice.md |
Conventions¶
Do:
- Use semantic filenames (
intent_classification.md, notprompt1.md) - One prompt per
.mdfile - Use
{{PLACEHOLDER}}for variables (mustache-style, double braces) - Use
[SYSTEM],[DEVELOPER],[USER]section markers for prompts that need static/dynamic split - Version-control prompts like code — review changes in PRs
Don't:
- Embed multi-line prompts in Python string literals
- Mix multiple prompts in one
.mdfile - Put business logic in
.mdfiles (content only — logic goes in the builder) - Hard-code the same prompt text in multiple places