Skip to content

Run a managed bounded task

Basic use records the tool calls reported by an existing agent. Normal use limits those calls. Advanced use normally applies a writ to that same agent with writ sessions and writ start --session.

This task needs model cost, verified worktree effects, and completion events. A native hook does not supply all of that evidence. This page therefore uses the optional managed adapter through writ issue.

Suppose one test fails. You want an agent to fix the source code. You do not want it to edit the tests. You also want a cost limit and proof that the fix works.

This page runs that task from start to finish.

The task has six rules:

Need Rule
Result Make tests/test_sync.py::test_retry pass.
Allowed reading Read and search the repository.
Allowed changes Edit files under src/**.
Protected files Do not change tests/**.
Limits Stop after 40 model turns, $2.50, 20 minutes, 5 files, or 200 changed lines.
Completion Run the failed test and the full test suite. Both commands must pass.

Writ gives these rules to the model. It checks each requested action before it runs the action. It counts model turns and cost. It checks the worktree after a tool changes it. It runs the completion commands before it accepts the work.

This mode needs a model and a sandbox. Set up managed runs once on each machine.

Basic and normal use through writ connect do not need a model configuration.

Create bug-fixer.yaml in the project root:

writ: bug-fixer
mandate: "Make tests/test_sync.py::test_retry pass without breaking other tests."
grants:
- read: { paths: ["**/*"] }
- search: { scope: repo }
- shell: { commands: ["pytest *", "git diff"] }
- edit: { paths: ["src/**"] }
bounds:
iterations: 40
cost: $2.50
wall_clock: 20m
edits: { max_files: 5, max_changed_lines: 200 }
invariants:
- { layer: letter, untouched: "tests/**" }
satisfaction:
all:
- { layer: letter, run: "pytest tests/test_sync.py::test_retry -x -q", exit: 0 }
- { layer: letter, run: "pytest -q", exit: 0 }
remedies:
on_bound_breach: { do: halt }
on_invariant_breach: { do: inform, inform: holder, strikes: 3 }

Each section answers one question:

Section Question
mandate What result must the model produce?
grants Which actions may run?
bounds How much may the run use or change?
invariants What must remain unchanged?
satisfaction Which commands prove completion?
remedies What must Writ do after a rule fails?

Run this command before you spend model tokens:

Terminal window
writ check bug-fixer.yaml
writ plan bug-fixer.yaml --target managed

writ check prints this line when the file is valid:

bug-fixer.yaml: valid

The check finds invalid fields and invalid values. The plan checks every authored clause against the managed adapter. Fix each unsupported clause before you run the work.

Run this command:

Terminal window
writ issue bug-fixer.yaml

Writ now calls the configured model. The model selects each action. Writ checks and records the action before it runs the tool.

This managed run uses each bound in the file. If you omit iterations, cost, or wall_clock, writ issue adds an operational limit of 25 iterations, $1.00, or 15 minutes. An omitted bound is not an authored clause.

If the model requests an edit to tests/**, Writ stops that edit and tells the model which rule failed. The model can choose another action. The run continues while it remains within its limits.

The run can end in these ways:

Event Result
The model requests an action outside the grants. Writ stops the action and returns the failed rule to the model.
A protected file changes. Writ reverts the change and informs the model.
A turn, cost, time, file, or line limit is reached. Writ halts the run.
A completion command fails. Writ returns the failure to the model while the run has budget left.
Both completion commands pass. Writ marks the run as satisfied.

A completed run has output with this shape. The meter values depend on the run.

bug-fixer · satisfied · holder default
cost $0.84 / $2.50 · iterations 7 / 40 · wall clock 3m12s / 20m0s
...
✓ satisfaction pytest tests/test_sync.py::test_retry -x -q · exit 0
✓ satisfaction pytest -q · exit 0
✓ writ satisfied

The final line means that the declared completion checks passed. It does not mean that Writ proved a result that the checks do not cover.

Run this command:

Terminal window
writ review bug-fixer

The record shows:

  • Each model turn and its cost.
  • Each requested action and its arguments.
  • Each rule that Writ checked.
  • Each blocked action and the reason.
  • Each completion command and its result.
  • The final state of the run.

Open the same record in a browser when you need to inspect more lines:

Terminal window
writ review bug-fixer --web

The writ file defines the task rules. The enforcement adapter defines which events and evidence Writ receives.

With writ start, your agent owns the model loop and tool execution. Select a recently observed session with writ sessions --agent <agent>. Writ applies the writ only to that session. Other sessions keep their normal connection policy. The command stops before activation when a clause is unsupported.

With writ issue, Writ runs the model loop and tools. It can count turns and cost, check managed worktree changes, apply run limits, and run completion commands. Read the worktree effect boundary before a task can change ignored files or Git state.

Use writ plan <file> --agent <agent> before attached use. The attached mode supports only the clauses that this plan marks as enforced. Choose writ issue only when the task needs the managed adapter.

  • Change the result in the mandate.
  • Change the allowed actions in grants.
  • Change the spending and change limits in bounds.
  • Change protected files in invariants.
  • Change the proof of completion in satisfaction.