> For the index of every page in Orbital's docs, read https://docs.runorbital.dev/llms.txt.

# Implementer with a local step

> An implementer checked by a command step, routing on what the machine observed

In this example you put a shell command between the implementing agent and the end of the run, so the run routes on what the machine observed rather than on what the agent said. An agent that reports success is not evidence of success.

About five minutes to set up.

```toml title="local-step.toml"
version = 3
entry = "steps.implement"
description = "Implement a change and prove it with a local command before finishing"
max_visits = 40

[inputs.work]
label = "Work"
hint = "The change to make, in plain words or as a ticket URL"

[budgets.local_check]
rounds = 5

[steps.implement]
prompt = "Implement the change described by {{ inputs.work }}. Change the files the work needs. Do not commit."
outputs.implementation_summary = "text"
next = "steps.observe"

[steps.observe]
kind = "command"
repeat_safety = "idempotent"
timeout = "2m"
facts.change.present = "bool"
facts.change.summary = "text"
script = '''
if git status --porcelain | grep -q .; then
  echo '{"change.present":true,"change.summary":"the working folder has uncommitted changes"}'
else
  echo '{"change.present":false,"change.summary":"the working folder is unchanged"}'
fi
'''
routes = [
  { if = "outcome == 'failed'",     to = "steps.broken" },
  { if = "change.present",          to = "steps.observed",  resets = "budgets.local_check" },
  { if = "change.present == false", to = "steps.repair",    spends = "budgets.local_check" },
  { if = "change.present == false", to = "steps.unchanged" },
]
next = "steps.broken"

[steps.repair]
prompt = "A local command observed that {{ context.change.summary }}. The reported work was: {{ context.implementation_summary }}. Change the files the work actually needs."
outputs.repair_summary = "text"
next = "steps.observe"

[steps.observed]
kind = "terminal"

[steps.unchanged]
kind = "terminal"
outcome = "failed"
label = "No change after five repairs"

[steps.broken]
kind = "terminal"
outcome = "failed"
label = "The local command itself failed"
```

![implement → observe. The command routes an unchanged folder into repair and a changed one into a successful terminal.](/local-step.svg?v=251b65e802)

## Before you start

You need:

- a signed-in harness;
- a project whose primary folder is a Git repository. It needs no remote. It must be a Git repository because the check asks `git status` whether the folder changed;
- the workflow: [download the archive](/local-step.zip), or just [local-step.toml](/examples/local-step/local-step.toml).

:::caution
The workflow makes no worktree, so the agent changes files in the project's folder itself. Use a practice repository.
:::

## 1. Add the workflow

1. Unpack the archive into your workflow library, `~/.orbital/workflows/`. Keep every relative path.

2. Check it:

   ```sh
   orbital validate ~/.orbital/workflows/local-step.toml
   ```

![The workflow editor showing a workflow as steps joined by arrows, with an Inspector panel on the right and a Problems bar.](/screenshots/workflow-editor.webp?v=85a9c6275a)

*The editor draws the workflow's steps; the Problems bar lists what validation rejects.*

## 2. Read how it works

`observe` is a `command` step with a `script`. The script runs once through `bash -c` in the primary working folder, inherits the server environment, and prints one JSON object as its final stdout line. `facts.change.present = "bool"` and `facts.change.summary = "text"` declare exactly the keys that object contains, and Orbital rejects a final line that does not match.

The check here asks git whether the working folder has uncommitted changes. Replace it with your project's own check, such as its test or lint command, and declare whatever facts that command can report. Keep the script read-only when it only inspects something, and give it a `timeout` shorter than the default ten minutes when the command is quick.

Four routes leave `observe`, tried in order, and `next` catches anything else:

| Route | What it does |
| --- | --- |
| `outcome == 'failed'` | Catches the script itself failing on a timeout, a non-zero exit or a malformed final line. |
| `change.present` | Succeeds and resets the `local_check` budget. |
| `change.present == false`, spending `budgets.local_check` | Starts a repair round. Once the five rounds are spent, this route is skipped. |
| `change.present == false` | Ends the run Failed once the budget is empty. |
| `next` | Required, because a command step's facts are not a choice whose routes answer every option. |

## 3. Make a practice repository

Run `git init ~/orbital-practice` and add that folder as a project.

## 4. Start the run

Choose **New task** and pick the project. Choose the `local-step` workflow, set work to what you want changed, and write the goal.

## What you get

An agent that changes a file reaches the successful terminal on the first observation. An agent that changes nothing is sent to repair and observed again, up to five rounds, before the run ends Failed. A script that cannot run at all ends the run Failed at a separate terminal, so you can tell the two causes apart in the transcript.

## Related

- [Context](/reference/context/): how to declare the facts a command reports
- [Error handling](/reference/error-handling/#bounded-repair): how budgets bound a loop
- [One-shot implementation](/examples/workflows/one-shot-implementation/): the smallest workflow that delivers a pull request
