Skip to content

EN Course 05 System Prompt Builder

lloydzhou edited this page May 29, 2026 · 1 revision

System Prompt Builder

The system prompt is a cache-sensitive protocol surface. Small byte differences can reduce provider KV-cache reuse, so sections are appended through a common helper.

util_append_section() {
    local __outvar="$1" tag="$2" content="$3" name="${4:-}" wrapped
    [[ -n "$content" ]] || return 0
    if [[ -n "$name" ]]; then
        wrapped=$(printf '<%s name="%s">\n%s\n</%s>' "$tag" "$(util_json_escape "$name")" "$content" "$tag")
    else
        wrapped=$(printf '<%s>\n%s\n</%s>' "$tag" "$content" "$tag")
    fi
    printf -v "$__outvar" '%s%s\n' "${!__outvar}" "$wrapped"
}

Actual Section Order

agent_build_prompt appends sections in a fixed order:

util_append_section output "agent-identity" "$agent_identity"
util_append_section output "environment" "$environment"
util_append_section output "rules" "$core_rules"
util_append_section output "using-your-tools" "$tool_guidance"
util_append_section output "sub-agent-guidance" "$sub_agent_guidance"
util_append_section output "todo-guidance" "$todo_guidance"
util_append_section output "plan-lifecycle-guidance" "$plan_lifecycle_guidance"
util_append_section output "instruction-files" "$instruction_files"
util_append_section output "skill-index" "$skill_index"
util_append_section output "selected-skills" "$selected_skills"
util_append_section output "current-plan" "$plan" "${PLAN_FILE:-}"
util_append_section output "context-snapshot" "$stable_context"
util_append_section output "output-language" "$output_language_reaffirm"

That means the actual top-level prompt sections are:

Section Purpose
agent-identity runtime identity, localized by locale
environment language, cwd, home, platform, shell
rules concise behavior and failure-reporting rules
using-your-tools general tool-use guidance
sub-agent-guidance delegation, fork mode, and result handling
todo-guidance when and how to use TodoWrite
plan-lifecycle-guidance draft/confirm/execute plan protocol
instruction-files global and project instruction-file sections
skill-index available skill names and summaries
selected-skills full content for explicitly selected skills
current-plan locked plan, named by PLAN_FILE
context-snapshot compacted long-session summary
output-language locale reaffirmation

The order and formatting are part of the contract. Bash, C, Go, and Rust must produce the same prompt bytes for the same session state.

Nested Instruction and Skill Sections

Some top-level sections contain nested sections. Instruction files are collected as instruction-file entries:

util_build_instructions_section() {
    local output="" global_file project_file global_content project_content
    global_file=$(util_find_instruction_file "${HOME}/.bash-agent" 2>/dev/null || true)
    project_file=$(util_find_instruction_file "${PWD:-$(pwd)}" 2>/dev/null || true)

    if [[ -n "$global_file" ]]; then
        global_content=$(<"$global_file") || return 1
        util_append_section output "instruction-file" "$global_content" "global"
    fi
    if [[ -n "$project_file" ]]; then
        project_content=$(<"$project_file") || return 1
        util_append_section output "instruction-file" "$project_content" "project"
    fi
    printf '%s' "${output%$'\n'}"
}

Selected skills are also nested as individual skill sections inside selected-skills.

Plan Drafts and Cache

plan.draft exists because editing a locked plan changes the system prompt. Drafting keeps intermediate planning text out of the prompt until it is confirmed.

store_plan_confirm() {
    [[ -n "$PLAN_DRAFT_FILE" && -s "$PLAN_DRAFT_FILE" ]] && {
        mv "$PLAN_DRAFT_FILE" "$PLAN_FILE"
        : > "$PLAN_DRAFT_FILE"
        return 0
    }
    return 1
}

This makes plan confirmation a deliberate cache boundary.

Next

Compaction and Long Sessions explains how stable prompt structure and session stats support long-running conversations.

Clone this wiki locally