Prompt Builder¶
Purpose¶
Single entry point for all prompt assembly in the system. Replaces scattered string concatenation across orchestrator, [[specs/platforms/claude_sdk]], chat agent, and agent_prompting.
Concepts¶
Five Layers¶
Every prompt is assembled from up to 5 ordered layers:
- Identity — Who is the LLM acting as? Loaded from a prompt template file in
src/prompts/. supervisor— the Discord-facing [[specs/supervisor|Supervisor]] (fromchat_agent_system.md)task-agent— a Claude Code agent executing a task-
hook-executor— the [[specs/supervisor|Supervisor]] reasoning about a hook result (fromhook_context.md) -
Project Context — What project is this for? Pulled from the memory system:
- Project profile (from
profile.md) - Project documentation (CLAUDE.md, README.md)
-
Falls back to empty string if memory unavailable
-
Relevant Rules — Deprecated. Previously loaded from
RuleManagerviaload_relevant_rules(query). Rules have been replaced by playbooks and vault memory.load_relevant_rules()is now a no-op. -
Specific Context — What is the LLM doing right now? Arbitrary named context blocks:
task— task descriptionupstream— completed dependency summariestask_depth— depth-aware execution rules (plan generation, controlled splitting, execution focus)hook— hook trigger data and context step resultssystem_metadata— workspace path, project name, branch-
role_instructions— agent profile system_prompt_suffix -
Tools — What tools are available? A list of JSON Schema tool definitions.
Template Loading¶
PromptBuilder loads templates from src/prompts/*.md files with YAML frontmatter. It parses frontmatter for metadata (name, variables, category) and renders the body with {{variable}} substitution. This absorbs the functionality of prompt_registry.py and prompt_manager.py.
Templates are cached after first load. reload() forces re-read from disk.
Output¶
build() returns a tuple of (system_prompt: str, tools: list[dict]).
system_promptis the concatenation of all non-empty layers in order, separated by\n\n---\n\ntoolsis the list of tool definitions set viaset_core_tools()orset_tools()
For task execution prompts (identity="task-agent"), the output is a single prompt string (no separate system prompt), since it goes to the Claude Code CLI as a flat prompt. build_task_prompt() returns str instead.
Interfaces¶
Constructor¶
PromptBuilder(project_id: str | None = None, memory_manager: Any | None = None, rule_manager: Any | None = None)
project_idscopes project context and rule loadingmemory_manageris optional; if None, layer 2 is emptyrule_manageris optional; if None, layer 3 is empty
Methods¶
set_identity(name: str, variables: dict | None = None)— Load identity template, render with variablesload_project_context()— async, pulls from memory_manager if availableload_relevant_rules(query: str)— async, queries RuleManager for applicable rules (project + globals). Without memsearch, loads all rules. Gracefully degrades to empty on errors.add_context(name: str, content: str)— Add a named context block to layer 4add_context_section(name: str, data: dict)— Add structured context rendered as markdown. Whenname="task_depth", dispatches to depth-aware template selection (see below)set_core_tools(tools: list[dict])— Set the tool definitions for layer 5set_tools(tools: list[dict])— Alias for set_core_toolsbuild() -> tuple[str, list[dict]]— Assemble and return (system_prompt, tools)build_task_prompt() -> str— Assemble and return flat prompt string for task executionget_template(name: str) -> str | None— Load and return raw template body (for backward compat)render_template(name: str, variables: dict | None = None) -> str— Load, render, return templatereload()— Force re-read templates from disk
Depth-Aware Task Prompting¶
When add_context_section("task_depth", data) is called, PromptBuilder selects the appropriate execution rules template based on the depth and max_depth values in data:
- Root depth (0): loads
plan-structure-guidetemplate withmax_stepsvariable - Intermediate depths (0 < depth < max_depth): loads
controlled-splittingtemplate withcurrent_depthandmax_depthvariables - Max depth (depth >= max_depth): loads
execution-focustemplate (no variables)
The rendered template is added as an execution_rules context block.
Template Rendering¶
- Loads
.mdfiles fromsrc/prompts/directory - Parses YAML frontmatter (between
---delimiters) - Substitutes
{{variable_name}}with provided values - Missing required variables raise
ValueErrorin strict mode, use empty string in non-strict - Templates are cached per PromptBuilder instance
Invariants¶
- Layer order is always 1 → 2 → 3 → 4 → 5
- Empty layers are omitted (no blank sections in output)
- Multiple
add_context()calls append in call order within layer 4 build()can be called multiple times (idempotent)- Template loading never raises on missing files — returns None
- PromptBuilder is not thread-safe (single-use per prompt assembly)