# What a step sees

> Running and debugging · https://spoletta.com/docs/step-contracts

You never write the plumbing between steps, but the prompts and scripts you write sit inside it. This page shows exactly what each kind of step is given and what it must hand back.

## An agent's prompt

The engine builds every agent's prompt from these parts, in order:

1

Your prompt

What to do and how well, in plain words, naming the inputs and outputs as the board names them.

2

The flow, in OPL (optional)

With **Tell it about the flow it works in, in OPL** ticked: *You carry out the process “Name” of the flow described below in OPL…*, then the flow's sentences.

3

The inputs

One `<input>` element per object it takes, with the object's name, its state, and a role: `instrument` for a reference not to change, `affected` for one the agent changes and hands back. An object it looks up through a [query](https://spoletta.com/docs/procedural-links.md#looking-up-stored-records) holds the stored records it picked, as a JSON array.

4

A change request (for a revision)

The reviewer’s name and decision, the work they reviewed, and their instructions.

5

The output contract

The agent hands in through a `submit_output` tool, given the contract of what it yields. A reply that doesn't fit is sent back once with what was wrong; failing again fails the step.

Inputs as the agent sees them:

```xml
<input name="Ticket" state="bug">{"key":"SHOP-12","summary":"Checkout fails on Safari"}</input>
<input name="Style guide" role="instrument">{"data":"Prefer small functions…"}</input>
<input name="Notes" role="affected">{"data":"…"}</input>
```

A change request:

```text
The reviewer "Critic" marked the work below as "weak". Act on it following their instructions.
<reviewed name="Post" state="weak">…</reviewed>
<change_request>Cut the intro to two sentences.</change_request>
```

> **Writing good prompts:** Name the inputs as the board does (“Fix the exception in **Exception** following the **Style guide**”) and say what a good output is. Don't describe JSON shapes: attribute definitions do that.

## The output contract

| The step yields | It hands in |
| --- | --- |
| One object without attributes | `{"data": …}`, any JSON |
| One object with attributes | `{"attr1": …, "attr2": …}`, exactly those keys |
| A list | A JSON array of such items |
| Several objects | One JSON object holding each under the object's name |
| An object whose state it decides | Its output next to its decisions: for each decided object, the chosen state and optional instructions for whoever takes it in that state. An object it reviews keeps its content, so only the decision goes in. |

## A script

-   Each object it takes is a file in `$INPUTS`, named after the object with unsafe characters made underscores (*Jira Ticket* → `$INPUTS/Jira_Ticket`), holding the object's JSON.
-   It **prints** its output to stdout, in the same contract as an agent's.
-   Files go in `$OUTPUTS`, with their paths in file attributes.
-   An object it looks up through a [query](https://spoletta.com/docs/procedural-links.md#looking-up-stored-records) is a file too, holding the stored records it picked as a JSON array, which may be empty.
-   In a workspace, `$WORKSPACE` is the checkouts' directory and `$BRANCH` the run's branch.
-   In a run a schedule started, `$SINCE` (or `$LAST_RUN`) is when the schedule's last run that ended done started, as a Unix timestamp. It is empty on the schedule's first run and in runs started by hand. See [Fetching only what changed](https://spoletta.com/docs/schedules.md#fetching-only-what-changed).
-   A non-zero exit fails it, with stderr as the error.
-   A script can't decide states: route its output with [state rules](https://spoletta.com/docs/states.md#rules).

Fetch a Jira ticket into an object with key, summary and priority:

```bash
key=$(jq -r .data "$INPUTS/Ticket_key")
curl -fsS "https://jira.example.com/rest/api/2/issue/$key" \
  -H "Authorization: Bearer $JIRA_TOKEN" |
  jq '{key: .key, summary: .fields.summary, priority: .fields.priority.id | tonumber}'
```

## A person

-   **A review**: the human process takes X and yields X with states. The person sees X and picks a state, with instructions.
-   **An entry**: the human process yields Y without taking it. The person fills Y in, as JSON with exactly Y's attributes (an array for a list), or as text if Y has none.
-   Both at once: a person can review one object and fill in another in the same step.

See [People in the loop](https://spoletta.com/docs/people.md) for the dialog they use.
