# Debugging Tool Loops

> Loads when a session shows many tool calls (often the same name repeated) with no terminal text, no `complete` call, and either hits `stopWhen: stepCountIs(...)` (default 10) OR exhausts max output tokens. The LLM is in a tool loop without producing a final message. Distinguish from `debugging-empty-output` — that's about contract exits being absent; this is about the LLM never deciding to stop. Required: the agent prompt needs an explicit termination criterion.

- Skill: `friday-platform/debugging-tool-loops` (Agent Skill)
- Install (CLI): `npx skillmds@latest add friday-platform/debugging-tool-loops`
- Raw SKILL.md: https://api.skillmd.com/api/skills/friday-platform/debugging-tool-loops/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: friday-platform (https://skillmd.com/u/friday-platform)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/friday-platform/debugging-tool-loops

---


# Debugging tool loops

Symptom: agent makes 8+ tool calls (often repeating searches with
slight variations), eventually hits `stepCountIs(10)` cap or runs out
of output tokens, ends with `output: {response: ""}` or empty
`complete` args.

## Diagnostic checklist

### 1. Confirm the loop signature

```
describe_session(sessionId) → session.agentBlocks[].toolCalls
```

Look for:
- 6+ tool calls in a single agent block.
- Repeated calls to similar tools (`search_issues` × 3,
  `search_pull_requests` × 3, then more search variations).
- No `complete` or `failStep` toolName in the list.
- Final assistant text is empty.

If the agent IS calling `complete` but with empty args, that's
`@friday/debugging-empty-output` step 2, not this skill.

### 2. Check the agent prompt's termination criterion

A loop usually means the agent doesn't know when to stop searching.
Look for prompts like:

```
"Search for all stale issues across all repos."
```

The LLM keeps searching because "all" is open-ended. Add an explicit
stop condition:

```
"Search exactly these 6 queries (3 issue queries × 3 PR queries).
After all 6 return, stop and call `complete` with the report. Do not
search again."
```

### 3. Check whether the agent has the right *terminal* tool

If `outputTo` is set, the runtime auto-injects `complete` and stops
the LLM when complete is called (`stopWhen: hasToolCall("complete")`).
If `outputTo` is NOT set, the LLM stops only on `stepCountIs(...)` or
max output tokens. Without an `outputTo`, you're at the mercy of the
LLM's own sense of when to stop.

Consider adding `outputTo: response` to the FSM action to give the LLM
a clear exit hatch.

### 4. Bump `max_steps` only as a last resort

The default `max_steps: 10` is generous for most agents. If you
genuinely need more (e.g., a job that fans out to 20 repos), bump it
in the action's `config.max_steps`. But: if you're hitting 20 steps
and still not done, the prompt is wrong, not the budget.

## What NOT to do

- **Do NOT bump `max_output_tokens` to "fix" the loop.** Token budget
  isn't the issue — the agent isn't producing tokens, it's producing
  tool calls. More budget = more loops.
- **Do NOT swap to a more capable model.** Tool loops aren't a model
  capability problem; they're a prompt instruction problem.

## Cross-references

- `@friday/debugging-broken-jobs` — the triage entry point.
- `@friday/debugging-empty-output` — sibling for "complete present but
  empty" cases.
- `@friday/agent-action-handshake` — the `outputTo` + `complete`
  injection contract that gives a terminal exit.

