Define the finish before the first action.
Imagine asking an agent to inspect a fictional project note and prepare a draft status summary. The useful finish is a draft with its source and any uncertainty. Sending the draft is a separate action. Reading the same note over and over is activity, not a better result.
Write a short operating brief before you choose a framework:
- Deliverable: a draft summary and the source note it used.
- Allowed scope: read approved notes; keep external sending outside this task.
- Return control: on completion, a denied action, repeated identical calls, or the chosen decision limit.
- Handoff: return the stop reason and available evidence, then review whether the result actually meets the brief.
A sentence in a prompt communicates intent. The code that runs the model and dispatches tools must enforce the boundaries. Our example focuses on that code, using deterministic stand-ins so you can see each branch.
Download a lab you can read.
You need Python 3.13 and PowerShell for the commands below. We ran the exercise on Windows with Python 3.13.15. Get Python from its official downloads page if needed, and confirm your interpreter:
python --versionUse a new working folder so extraction does not overwrite existing files. The practice ZIP contains the runner, ten tests, a README, and observed local reports. It has no dependencies to install, model weights, or API credentials. Read the code before executing it.
Invoke-WebRequest -Uri 'https://jabsystems.io/ai-anonymous/Social/agent-stop-rule-exercise.zip' -OutFile .\agent-stop-rule-exercise.zip
Expand-Archive -LiteralPath .\agent-stop-rule-exercise.zip -DestinationPath .\stop-rule-lab
Set-Location .\stop-rule-lab
Get-Content -LiteralPath .\stop-rule-readme.txt
Get-Content -LiteralPath .\stop_rule.pyThe only fake tool, read_note, looks up a string in a dictionary. The decider returns authored choices. It does not call an AI service, read your files, or send email. Running Python code still gives that process your usual local permissions; the lab is not a sandbox.
Make it stop in four different ways.
From the extracted folder, run each scenario separately. A controlled stop returns exit code 2, so PowerShell may show $LASTEXITCODE as 2 for the last three commands. That is the demonstration’s intended result.
python .\stop_rule.py complete
python .\stop_rule.py step-limit
python .\stop_rule.py repeat
python .\stop_rule.py deniedThese are the actual local counts, using authored scripted decisions:
complete: 2 decisions, 1 fake tool call; statuscomplete, exit 0. It reads Harbor once, then returns done.step-limit: 3 decisions, 3 fake tool calls; statusstep_limit, exit 2. Each key differs, so a fourth decision attempt is prevented by the overall cap.repeat: 3 decisions, 2 fake tool calls; statusrepeat_limit, exit 2. The third identical read is stopped before tool dispatch.denied: 1 decision, 0 tool calls; statusdenied_action, exit 2. A scripted send request is rejected; there is no sending implementation.
Inspect the complete observed JSON to see the retained fake tool events. A decision count includes the choice that gets blocked. It is different from a count of executed tools, API requests, or billed tokens.
Put the check around the decision.
This exact excerpt from the full runner shows the decision cap and elapsed-time checks. Read the complete file for validation, the action gate, repeat tracking, and the final step_limit report.
for _ in range(max_steps):
if clock() >= deadline:
return report('time_limit')
decisions += 1
choice = decide([dict(event) for event in events])
if clock() >= deadline:
return report('time_limit')The full runner checks the action before dispatch. It counts exact (action, key) pairs and refuses the third execution of an identical pair. Changing a key can bypass that repeat check; the overall step cap still applies. This is a deliberately narrow repetition rule, not detection of every kind of loop.
The elapsed-time check uses Python’s monotonic clock, which does not move backward with system clock adjustments. It checks again after the decider and fake tool return. It cannot interrupt a stuck model request or tool. Real integrations need their own request timeouts and a cancellation design. A five-second cooperative deadline is not a hard five-second kill switch.
The defaults of three decisions, two identical calls, and five seconds make this lab easy to inspect. Choose real limits from the task and its failure modes; these numbers are not universal recommendations. A step cap alone does not establish a dollar cap, especially with retries, variable token use, or concurrent work.
Test the stop paths, then review the result.
Run the included checks:
python -m unittest -v test_stop_rule.pyOur local run passed all 10 tests: completion with retained evidence; stopping before a fourth decision; a repeat rejected before dispatch; a send rejected before dispatch; completion on the last permitted decision; invalid limits; malformed decisions; and deadline checks before and after a decider call. The deadline tests use an injected fake clock. They are control-flow tests, not a timed network experiment.
Now read the events in each report. The complete case retains the fictional Harbor note. A complete status means the decider said done; this teaching runner does not verify a generated summary against that note. In an actual application, check the deliverable and its source before accepting completion.
To explore one change, edit max_steps=3 to max_steps=2 in your local copy and rerun step-limit. Predict the counts first. Restore the original before rerunning the supplied tests, whose expectations use the published defaults. This variation is a suggested follow-on exercise, not an additional published measurement.
Carry the rule into a real runner carefully.
Map the exercise to the framework you actually use. Anthropic’s Building effective agents guidance, published in December 2024, describes environmental feedback, checkpoints, and stopping conditions such as maximum iterations. This is an established design principle, not an announcement of a new release.
Current LangGraph recursion-limit documentation describes reaching a step limit before a stop condition. It also notes that legitimate complex graphs can hit a limit. Inspect the graph’s logic before increasing it. Framework graph steps have their own semantics; do not copy this lab’s number as a LangGraph setting. We did not install or run LangGraph here.
- Keep trusted limits and tool dispatch outside model-generated instructions.
- Define completion evidence separately from a model saying it is done.
- Apply per-request timeouts, input validation, and narrow permissions at each real boundary.
- Include retries and parallel work when accounting for requests and spend.
- Return a minimal report that helps a human continue, while avoiding secrets in logs.
For a first integration, use fictional data and read-only tools. Explicitly authorize consequential actions within the intended scope. Neither this prompt nor this Python function establishes production security, prompt-injection resistance, real service permissions, or hard cancellation.
Verification boundary: we executed the four scripted scenarios and the ten local tests. No language model output, external tool call, model quality, performance improvement, cost saving, billing limit, or production agent was tested. The poster is original AI-generated conceptual artwork.
Keep the guide, evidence, and downloads together.
Primary sources reviewed October 16, 2026: Anthropic agent-design guidance, LangGraph step-limit diagnostic, Python monotonic-clock documentation, and Python downloads.
Practice ZIP · Runner source · Ten checks · README · Observed reports · Original graphic · Caption · Alt text · Article URL · Posting ZIP
Manual social delivery: the posting ZIP contains the portrait graphic, incomplete teaser, alt text, and full article URL for the user to post. Nothing is scheduled or published to social media. No Instagram profile-link change is claimed.
