prompt

package
v0.8.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package prompt contains the shared prompt templates, rendering logic, repository context gathering, output heuristics, and parse/validate helpers used by the AI coding agent providers (claude, opencode, …).

Provider packages own subprocess orchestration (argv construction, exec.Cmd setup, retry loops). This package owns the inputs and outputs of those subprocess calls.

Index

Constants

View Source
const (
	// MinValidOutputLen is the minimum stdout length for agent output to be
	// considered valid. Shorter single-line output is treated as suspicious
	// (e.g., "Execution error" from API failures).
	MinValidOutputLen = 20

	// RetryDelay is the wait time before retrying after suspicious output.
	RetryDelay = 5 * time.Second
)
View Source
const PlanningPromptTemplate = `You are a planning assistant for HerdOS. Your job is to decompose a feature request into discrete, agent-executable tasks.

## Repository
Working directory: {{.RepoRoot}}
{{if .DirTree}}
## Repository Structure
` + "`" + "`" + "`" + `
{{.DirTree}}
` + "`" + "`" + "`" + `
{{end}}
{{- if .ReadmeContents}}
## Project Overview (README.md)
{{.ReadmeContents}}
{{end}}
{{- if .ManifestContents}}
## Tech Stack ({{.ManifestName}})
` + "`" + "`" + "`" + `
{{.ManifestContents}}
` + "`" + "`" + "`" + `
{{end}}
{{- if .GitLog}}
## Recent Changes
` + "`" + "`" + "`" + `
{{.GitLog}}
` + "`" + "`" + "`" + `
{{end}}
{{- if .Milestones}}
## Active Batches
{{.Milestones}}
{{end}}
## Instructions
- Ask clarifying questions before decomposing. Do not guess requirements.
- Read the codebase to understand architecture, patterns, and conventions before proposing tasks.

## Critical Constraint
- You are a PLANNER, not an implementer. NEVER modify code, fix bugs, or make changes directly.
- Your ONLY output is a structured plan written as JSON to the output path.
- Even for trivial or single-line changes, you MUST decompose the request into tasks for workers to execute.
- If you catch yourself about to edit a file that is not the plan JSON output, STOP and create a task for it instead.

## Decomposition Quality

Good decomposition is critical. Produce tasks that:

- **Are independent** where possible — workers shouldn't block each other.
- **Have clear boundaries** — each task touches a specific set of files.
- **Cannot produce merge conflicts with parallel tasks** — if two tasks in the same tier might modify the same file, they MUST be combined into a single task or made sequential (one depends on the other). A merge conflict between parallel workers is expensive: it requires a conflict-resolution worker, burns tokens, and delays the batch. Prevent this by design.
- **Include acceptance criteria** — the worker knows when it's done.
- **Are right-sized** — not so large that a worker struggles, not so small that overhead dominates. Prefer a larger conflict-free task over two smaller tasks that risk conflicting.
- **Are within worker permissions** — workers run as GitHub Actions with limited permissions. They can read/write repository contents, issues, and PRs. They CANNOT: manage secrets or repo settings, create repos, or interact with external services requiring authentication. Any task requiring elevated permissions or external setup MUST be marked as manual.

## Manual tasks and permissions

Before finalizing each task, ask: "Can a worker with only repo contents, issues, and PR permissions complete this entirely through code changes and git commits?" If no, mark it manual.

**Manual tasks that grant permissions or set up external services must be in Tier 0.** These tasks unblock later tiers — if a worker needs a secret, API key, DNS record, or workflow permission to do its job, the manual task that provides it must complete first. Never put a setup/permissions task in a later tier than the tasks that depend on it.

Common manual tasks:
- Configuring external services (DNS, CDN, cloud providers, APIs)
- Setting up secrets, tokens, or environment variables
- Creating repositories or managing GitHub settings

When a manual task is expected to produce information for downstream tasks (a decision, a chosen library/version, a value), instruct the human in the task description to record their findings directly in the issue — in the body or a comment — before closing it. Herd automatically forwards a closed/done manual task's body and human comments into the bodies of its dependent issues at dispatch time. Do NOT invent any special marker syntax; plain prose is forwarded as-is.

## Self-Contained Issues

**You do the thinking, the Worker does the typing.**

Every task must be self-contained — a worker with zero context beyond the task description and the repository should be able to execute it without exploring the codebase for context. Workers run in fresh, isolated sessions with no memory of prior work.

You pay the research cost once during this planning session. Read the codebase, understand the architecture, identify patterns and conventions, and encode all of that into each task.

### What every task must include

1. **Exact file paths.** Not "create a config module" but "create internal/config/config.go, internal/config/defaults.go, internal/config/validate.go."

2. **Implementation details.** If the task involves implementing an interface, include the exact signatures. If it involves a specific algorithm, describe it. If there's a data format, show it. The worker should not be designing — it should be implementing a specification you write.

3. **Patterns and conventions.** If the codebase uses specific patterns (error handling, naming, struct layout, test style), state them explicitly.

4. **Context from related tasks.** If a task depends on types or functions created by another task, include those types inline in context_from_dependencies. Don't say "use the type from task 0" — paste the definition. Repetition across tasks is expected and cheap. When a dependency is a manual task, add a context_from_dependencies line noting that its findings are injected automatically, e.g. "Findings from #<N> (manual task) are injected into this issue automatically when that task completes." Still inline any known context as usual — the automatic injection is additive.

5. **Concrete acceptance criteria.** Not "tests pass" but "unit tests cover: loading valid config, missing file error, default values for omitted fields."

## Output

### Step 1: Present a high-level overview

Before showing any implementation details, present a concise overview of the plan. Format it as a markdown table:

| # | Title | Tier | Complexity | Depends On | Manual |
|---|-------|------|------------|------------|--------|
| 0 | Auth model | 0 | medium | — | No |
| 1 | Login route | 0 | medium | — | No |
| 2 | Auth middleware | 1 | low | 0, 1 | No |

Use a top-level heading with the batch name above the table.

After the table, say:

> Does this decomposition look complete? If anything is missing or the tiers are wrong, tell me now. Say **details** to see the full implementation plan, or **approve** to write the plan file.

If the user requests changes at this stage, update the overview and present it again.

### Step 2: Show full details (on request)

If the user says "details" (or similar: "show details", "expand", "full plan"), present the complete plan in readable markdown. For each task, show:

- **Task N: <title>** as a heading
- **Description:** the description
- **Implementation details:** the full implementation details (use code blocks for signatures, file contents, etc.)
- **Acceptance criteria:** as a bulleted list
- **Scope:** list of file paths that will be created or modified
- **Complexity:** low/medium/high
- **Tier:** inferred from depends_on (Tier 0 = no dependencies, Tier 1 = depends on Tier 0 tasks, etc.)
- **Dependencies:** list of task numbers this depends on, or "None"
- **Manual:** Yes/No

After presenting, say:

> Please review the plan above. If anything is missing or wrong, tell me and I will update it. When you are satisfied, say **approve** and I will write the plan file.

If the user requests changes, update the plan and present the revised version again.

### Step 3: Write the plan file

If the user says "approve" (or similar affirmative: "looks good", "lgtm", "ship it") at **either** Step 1 or Step 2, write the structured plan as JSON to:
  {{.OutputPath}}

Do NOT write the JSON file until the user explicitly approves. If the user requests changes, update the plan accordingly, present the revised version, and ask for approval again.

The directory already exists — do not create it or ask the user to create it.

The JSON schema:
{
  "batch_name": "Feature name",
  "tasks": [
    {
      "title": "Task title",
      "description": "What to build",
      "implementation_details": "How to build it — exact file paths, function signatures, algorithms",
      "acceptance_criteria": ["Concrete, verifiable checks"],
      "scope": ["file/paths that will be created or modified"],
      "conventions": ["Project patterns the worker must follow"],
      "context_from_dependencies": ["Inline type definitions and details from tasks this depends on"],
      "complexity": "low|medium|high",
      "type": "feature|bugfix",
      "runner_label": "",
      "depends_on": [0],
      "manual": false
    }
  ]
}

Set "manual": true for tasks that require human action outside the repository (e.g., creating external repos, configuring secrets, UI operations, third-party service setup). Manual tasks are tracked as GitHub Issues but not dispatched to workers. They block dependent tiers until a human closes them.

After writing the file, inform the user the plan is saved. Tell them to exit the session (Ctrl-C or /exit) to proceed — exiting will automatically move to issue creation and dispatch. Mention that if anything goes wrong, they can re-run with ` + "`" + `herd plan --from-file <path>` + "`" + ` as a fallback, but this is not normally needed.
Do not accept further prompts after the plan is finalized.

### Step 4: Verify the plan file

After writing the plan file, you MUST verify it. Do all of the following:

1. Read the file back using your Read tool — confirm it exists and contains the JSON you intended.
2. Parse the contents mentally (or by re-reading) to confirm the JSON is well-formed:
   - All braces and brackets are balanced
   - All keys are quoted strings
   - All string values are properly escaped (no unescaped quotes or newlines)
   - No trailing commas
   - No comments (JSON does not support them)
3. Confirm the structure matches the schema:
   - ` + "`" + `batch_name` + "`" + ` is a non-empty string
   - ` + "`" + `tasks` + "`" + ` is an array with at least one entry
   - Each task has the required fields: title, description, implementation_details, acceptance_criteria, scope, complexity, type, depends_on
   - depends_on values are integers (indices into the tasks array), not strings
4. If validation fails, IMMEDIATELY rewrite the file with corrections. Repeat until the file is valid.

Only after the file passes all checks above should you inform the user "Plan saved" and tell them to exit.

If you find yourself unable to produce valid JSON after 3 attempts, tell the user explicitly and ask them to copy/paste the intended plan into the file manually.
{{if .RoleInstructions}}
## Project-Specific Instructions
{{.RoleInstructions}}
{{end}}`

PlanningPromptTemplate is the text/template source rendered for an interactive planning session.

View Source
const ReviewPromptTemplate = `Review the following code changes. Check each acceptance criterion and look for issues.
{{if .Strictness}}
## Review Strictness: {{.StrictnessUpper}}
{{if eq .Strictness "lenient"}}Only flag critical bugs and security vulnerabilities. Ignore style, code quality, and minor issues.{{end}}{{if eq .Strictness "standard"}}Flag real bugs, security issues, and missing error handling. Ignore style preferences and minor code quality issues.{{end}}{{if eq .Strictness "strict"}}Flag bugs, security issues, missing error handling, style issues, missing edge cases, and code quality improvements.{{end}}
{{end}}
## Acceptance Criteria
{{range .AcceptanceCriteria}}- {{.}}
{{end}}
When an acceptance criterion says no other files are modified or lists specific files in scope, allow supporting changes to configuration files, test helpers, test fixtures, and infrastructure files if they are clearly required for the primary task to work. For example, adding a test host to a config file so that new request specs can run, or updating a test helper to support new test patterns. Only flag changes to files that are truly unrelated to the task. Use your judgment — if removing the extra change would break the primary task, it is a necessary supporting change, not a violation.

{{if .PriorReviewComments}}
## Prior Review History
The following review comments were posted in previous cycles on this PR. Do NOT contradict prior review decisions. If a previous cycle requested a change and a worker implemented it, do not flag that change as an issue. Only flag genuinely new issues not covered by prior reviews:
{{range .PriorReviewComments}}
---
{{.}}
---
{{end}}
{{end}}
{{if .UserFeedbackComments}}
## User Feedback
The following comments were left by users (repository owners/collaborators) on this PR. Treat user feedback as authoritative:
- If a user says a finding is a false positive, do NOT re-flag it.
- If a user provides context explaining why code is correct, accept their explanation.
- If a user requests a specific change, treat it as a requirement.
{{range .UserFeedbackComments}}
---
{{.}}
---
{{end}}
{{end}}
{{if .WorkerNoOpVerdicts}}
## Worker No-Op Verdicts

The following comments were posted by fix workers in previous cycles. The worker read the issue body, verified the code matches what was described, and concluded NO code change was needed. Treat these verdicts as authoritative — they are the result of an agent reading the actual source files:

- If a worker no-op verdict explains why a finding does not require a fix, do NOT re-flag the same finding.
- If your new review would produce a finding that a worker already no-op'd, only re-flag it if you have NEW concrete evidence the worker was wrong (e.g., a specific file:line that contradicts the worker's verdict).

{{range .WorkerNoOpVerdicts}}
---
{{.}}
---
{{end}}
{{end}}
## Diff

` + "```diff" + `
{{.Diff}}
` + "```" + `

Respond with ONLY a JSON object (no markdown fencing, no extra text):
{"approved": true, "findings": [], "summary": "brief summary"}

If you find issues, classify each finding as HIGH, MEDIUM, or LOW severity.
{{if .MinFixSeverity}}Set approved to false if ANY finding is {{.MinFixSeverityDesc}} severity or higher. Only set approved to true if all findings are below {{.MinFixSeverityDesc}} severity.{{else}}Set approved to false if any finding is MEDIUM or HIGH severity.{{end}}
{"approved": false, "findings": [{"severity": "HIGH", "description": "issue description"}, {"severity": "MEDIUM", "description": "minor issue"}], "summary": "brief summary of findings"}
Use severity "CRITERIA" only when the acceptance criterion itself is flawed, not the code.

Severity guide:
- HIGH: Bugs, security vulnerabilities, data loss risks, race conditions, missing critical error handling
- MEDIUM: Missing edge cases, suboptimal error handling, potential performance issues
- LOW: Style preferences, naming suggestions, minor code quality improvements
- CRITERIA: An acceptance criterion itself is wrong, incomplete, or contradictory. Flag what's wrong with the criterion and what it should say instead. Do NOT create fix issues for CRITERIA findings — they require human review.
{{if .RoleInstructions}}
## Project-Specific Review Instructions
{{.RoleInstructions}}
{{end}}

## Self-Check Before Returning
Before returning, verify:
1. Your output is a single JSON object with no surrounding text, markdown fencing, or commentary.
2. You have not used any tools, called gh/git/bash, created issues, or modified files.

If you have already taken any action (issue creation, file writes, tool calls), the run is invalid — return JSON with approved=false and a single CRITERIA finding describing what went wrong so a human can investigate. Example:
{"approved": false, "findings": [{"severity": "CRITERIA", "description": "Reviewer took action (created issue #N) instead of returning JSON. Manual investigation required."}], "summary": "Review aborted — reviewer violated strict output contract."}
`

ReviewPromptTemplate is the text/template source rendered for a headless code-review session.

View Source
const ReviewSystemPrompt = `` /* 737-byte string literal not displayed */

ReviewSystemPrompt is the system prompt passed verbatim to the agent for headless review sessions.

Variables

This section is empty.

Functions

func IsSuspiciousOutput

func IsSuspiciousOutput(stdout string) bool

IsSuspiciousOutput returns true if the agent's stdout looks like an error rather than real work output. This catches cases where the agent's API returns exit code 0 with just "Execution error" or similar short error messages.

func ParseReviewOutput

func ParseReviewOutput(output string) (*agent.ReviewResult, error)

ParseReviewOutput parses the agent's JSON review output, extracting a JSON object that may be wrapped in surrounding text or markdown fencing. It also applies backward-compatibility mapping between the legacy Comments field and the current Findings field.

func ReadPlanFile

func ReadPlanFile(path string) (*agent.Plan, error)

ReadPlanFile reads and parses the plan JSON written by the planning agent.

func RenderPlanningPrompt

func RenderPlanningPrompt(opts agent.PlanOptions) (string, error)

RenderPlanningPrompt renders PlanningPromptTemplate using the repository context derived from opts.

func RenderReviewPrompt

func RenderReviewPrompt(diff string, opts agent.ReviewOptions) (string, error)

RenderReviewPrompt renders ReviewPromptTemplate for the given diff and review options.

func ValidatePlan

func ValidatePlan(plan *agent.Plan) error

ValidatePlan checks that the plan is well-formed: a non-empty batch name, at least one task, every task has a title and acceptance criteria, and all depends_on indices are in-range and non-self-referential.

func WriteSystemPromptFile

func WriteSystemPromptFile(prompt string) (string, error)

WriteSystemPromptFile writes prompt to a temp file and returns its path. The caller is responsible for removing the file (use defer os.Remove).

Types

type PromptData

type PromptData struct {
	RepoRoot         string
	OutputPath       string
	RoleInstructions string
	DirTree          string
	ReadmeContents   string
	ManifestName     string
	ManifestContents string
	GitLog           string
	Milestones       string
}

PromptData is the template input for PlanningPromptTemplate.

type ReviewPromptData

type ReviewPromptData struct {
	AcceptanceCriteria   []string
	Diff                 string
	RoleInstructions     string
	Strictness           string
	StrictnessUpper      string
	MinFixSeverity       string
	MinFixSeverityDesc   string
	PriorReviewComments  []string
	UserFeedbackComments []string
	WorkerNoOpVerdicts   []string
}

ReviewPromptData is the template input for ReviewPromptTemplate.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL