Skip to main content

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_prompt for single-turn responses.
  • Use stop_schema or fail_schema for 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: default for planning, summaries, and non-code tasks.
  • extends: coding for code changes and tests.
  • extends: pull_request for 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 }}."