Writing great prompts
Prompts are the contract between you and the agent. Clear prompts reduce retries and keep workflows predictable.
Start with a concrete outcome
- State what should exist when the step finishes.
- Include exact file paths, patterns, or outputs.
- Call out what must not change.
- Describe the scope in one sentence before the details.
Example outcome statement:
Update `src/api/client.ts` to use the new `ApiClient` helper. Do not change unrelated files.
Be deterministic and unambiguous
- Use short sentences with specific verbs: "rename", "move", "add", "remove".
- Avoid words that leave room for interpretation, like "clean up" or "improve".
- Tell the agent which source of truth to follow (README, style guide, or existing patterns).
Use instructions, role, and constraints on purpose
- Instructions explain the task and the order of work.
- Role sets the point of view for decisions.
- Constraints are non-negotiable rules.
Keep constraints short and testable. Do not include two constraints that conflict.
- name: Update the auth client
agent:
extends: Coding
role: "You are a backend engineer focused on API stability."
instructions: |
Replace direct HTTP calls with the new ApiClient.
Update any related tests.
constraints:
- "Do not change public method names."
- "Keep changes inside src/api/."
Prefer structured outputs when you need reliability
If a step needs machine-readable results, require a schema. If you notice the agent is not producing consistent / desired outputs, a simple schema with a description can also help.
- Use
structured_promptfor single-turn responses. - Use
stop_schemaorfail_schemafor agents.
- name: Assess migration readiness
structured_prompt:
prompt: |
Review the repo and list the files that must be migrated.
schema:
type: object
required: [files]
properties:
files:
type: array
description: "List of file paths that need migration."
items:
type: string
Extend tuned agents when possible
Bosun ships agents tuned for common tasks. Start with the closest fit and then add constraints.
extends: defaultfor planning, summaries, and non-code tasks.extends: codingfor code changes and tests.extends: pull_requestfor PR creation and updates.
Template carefully
Templates should resolve to a single, concrete value. When looping, reference for_each.value directly.
- name: Fix file by file
for_each:
from: '{{ outputs.scan_files | split(pat="\n") | filter(value) | json_encode() }}'
agent:
extends: Coding
instructions: "Apply the lint fixes to {{ for_each.value }}."