promptdojo_

The tool contract — make the dangerous call a validation error — step 1 of 7

The feature you ship today

Here's the ticket, same shape it would land in your queue:

feat: CI triage agent. When a job goes red, the agent reads the log tail and does one of three things: rerun (flake), open an issue (real failure), or page on-call (prod is involved). Should stop paging humans for npm 503s.

Sounds like an afternoon. It is an afternoon — if you build it in the right order. Built in the wrong order, it's the feature that reruns a prod deploy mid-incident and you spend the next sprint explaining what "agentic" means to your EM.

The wrong order is the one everyone tries first: wire up the model, hand it some tools, watch the demo work, ship, then bolt on safety after the first incident. The right order is the one this studio runs:

  1. Tool contract — this lesson. What the agent can call, expressed as data, enforced by a validator.
  2. The loop with a meter — lesson 2. Step caps, cost caps, a trace line per step.
  3. Evals before it works — lesson 3. Golden cases from real incidents, wired before the router is finished, plus the ratchet that keeps every fix fixed.

Why the tool contract goes first

Because it's the blast radius decision. Everything else in an agent feature is recoverable: a bad prompt wastes tokens, a bad route wastes a code review. A bad tool call reruns a deploy, force-pushes a branch, pages the wrong on-call at 3 a.m. The contract is where you decide, before any model gets involved, which calls are cheap, which are destructive, and which need a human's thumbprint.

Your agent gets five tools:

toolwhat it doesrisk
get_failing_jobslist red jobsnone — read-only
read_log_taillast N lines of a job lognone — read-only
open_issuefile an issue with a severitylow — noisy at worst
rerun_jobre-queue a jobcosts compute, masks real failures
escalatepage the on-callwakes a human

Two of those five get a confirm flag. By the end of this lesson, calling either one without it won't be a judgment call the model gets to make — it'll be a string that says reject: needs confirm, returned before anything runs.