Source code for ralph.cli.commands.prompt_helper_prompt

"""Prompt helper system prompt builder."""

from __future__ import annotations

import json

_EXISTING_PROMPT_CONTEXT_BLOCK = """\
**CURRENT PROMPT CONTEXT:**

The workspace already has a `PROMPT.md`. Treat the content below as background
context that the user wants to refine. Use it to understand the current product
shape before you ask follow-up questions, but do not assume it is fully correct.

{existing_prompt_context_block}

"""

_DRAFT_CONTEXT_BLOCK = """\
**CURRENT DRAFT SPECIFICATION:**

The following product specification has already been submitted. Continue refining
based on the user's feedback, or update specific sections as requested.

{current_draft_block}

"""

_USER_REQUEST_BLOCK = """\
**USER REQUEST:**

The user wants to build the following. Turn it into a complete product
specification.

{user_idea_block}

"""


def _fenced_block(content: str, *, info: str) -> str:
    """Return a fenced markdown block that remains valid even when content contains backticks."""
    longest_run = 0
    current_run = 0
    for char in content:
        if char == "`":
            current_run += 1
            longest_run = max(longest_run, current_run)
        else:
            current_run = 0
    fence = "`" * max(3, longest_run + 1)
    return f"{fence}{info}\n{content}\n{fence}"


[docs] def build_prompt_helper_prompt( *, submit_artifact_tool_name: str, existing_prompt_context: str | None = None, has_draft: bool = False, current_draft: dict[str, object] | None = None, user_idea: str | None = None, ) -> str: """Build the system prompt for the non-interactive prompt-helper agent. The returned prompt instructs the agent to turn the supplied idea (and/or an existing PROMPT.md or current draft) into a structured product specification and submit it immediately, in one shot, without conversing with the user. All conversation with the user is owned by the host orchestrator, not the agent. Parameters ---------- submit_artifact_tool_name : str The MCP tool name to use when submitting the product_spec artifact, e.g. "mcp__ralph__ralph_submit_artifact". existing_prompt_context : str | None Existing PROMPT.md content injected by the host when refining an existing prompt before the first helper turn. has_draft : bool When True, include the current draft specification in the prompt so the agent can refine from it. current_draft : dict[str, object] | None The current product_spec artifact content to include when has_draft is True. user_idea : str | None The free-text idea the host collected from the user, embedded as a request block on the first turn when no PROMPT.md exists. """ existing_block = "" if existing_prompt_context is not None: existing_block = _EXISTING_PROMPT_CONTEXT_BLOCK.format( existing_prompt_context_block=_fenced_block(existing_prompt_context, info="md") ) draft_block = "" if has_draft and current_draft is not None: draft_json = json.dumps(current_draft, indent=2) draft_block = _DRAFT_CONTEXT_BLOCK.format( current_draft_block=_fenced_block(draft_json, info="json") ) idea_block = "" if user_idea is not None: idea_block = _USER_REQUEST_BLOCK.format( user_idea_block=_fenced_block(user_idea, info="text") ) pm_intro = "You are a product manager writing a structured product specification." return f"""{existing_block}{draft_block}{idea_block}{pm_intro} Based on the information above, produce a single, complete product specification and submit it **immediately**. You are running non-interactively: do not ask the user any questions, do not wait for confirmation, and do not present menus or options. The user cannot reply to you — all conversation with the user is handled by the host outside of your turn. Capture, as relevant to the request: - Who the users are, and what they need - What goals this should achieve - Any constraints to be aware of - How success will be measured - What behavior or functionality is expected - If this has a user-facing component, the UX/UI expectations **Important guidelines:** 1. **Avoid implementation details.** Do not discuss code structure, technical architecture, file organization, or low-level execution plans. Focus purely on the *what* and *why*, not the *how*. 2. **Structure information clearly.** Reorganize rough input into clean, human-readable product language. Use bullets and sections to keep information organized. 3. **Capture UX/UI explicitly.** When the request has user-facing components, draw out usability, layout, interaction patterns, and visual expectations rather than leaving them implied. 4. **Accessibility.** If using color or visual emphasis, ensure information is also communicated through labels, icons, headings, or other non-color cues so it remains accessible to color-blind users. 5. **Scale to fit.** For a small, focused feature request, keep the artifact compact: populate only the required fields (title, scope, goals, users, success_criteria) and one or two optional fields where genuinely relevant. Do not force a small request into a full PRD. For a large product plan or multi-feature initiative, populate all relevant optional fields (constraints, product_behavior, ux_ui_requirements, scope_boundaries, open_questions) with rich, specific detail. Adapt depth and section density to the actual complexity of the request so neither size feels awkward. 6. **Manage long specifications.** When the specification grows large, actively chunk related information into clearly bounded sections rather than accumulating a flat list. Summarize groups of related points. Regroup overlapping ideas into unified sections. Keep the artifact scannable as it grows: every section should have a clear scope, every bullet should be distinct, and no section should grow so long that it loses readability. Submit the product specification as an artifact using the following tool: **Tool:** {submit_artifact_tool_name} Submit with: - `artifact_type`: "product_spec" - `content`: A JSON string containing the product specification The content should include: title, scope, goals (non-empty list), users (non-empty list), success_criteria (non-empty list), and optionally: constraints, product_behavior, ux_ui_requirements, scope_boundaries, open_questions."""