Bug Description
The headless runner documents exit code 2 for reaching --max-turns, but the command exits 0 when the limit is reached before the agent reaches a final text answer.
Steps to Reproduce
- Run a local fake OpenAI-compatible HTTP server that always returns a
list_files tool call with finish_reason: "tool_calls".
- Run:
export IAC_CODE_CONFIG_DIR="$(mktemp -d)"
export IAC_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
export IAC_CODE_PROVIDER=OpenAPICompatible
export IAC_CODE_MODEL=fake-model
export IAC_CODE_API_KEY=test-key
export IAC_CODE_BASE_URL="http://127.0.0.1:<fake-server-port>/v1"
uv run iac-code --prompt loop --output-format json --max-turns 1
A related edge case:
uv run iac-code --prompt loop --output-format json --max-turns 0
Expected Behavior
When the turn limit is reached, the command should return exit code 2, consistent with the documented headless exit codes:
2 — reached max-turns limit
Actual Behavior
For --max-turns 1, the command exits with code 0 and returns only the tool result, with no final assistant text:
{
"text": "",
"tool_uses": [
{
"name": "list_files",
"is_error": false
}
]
}
For --max-turns 0, the command exits with code 0 and makes no LLM request.
Operating System
macOS
Python Version
Python 3.14.2
iac-code Version
0.3.0 (uv run iac-code --version output: iac-code v0.3.0)
LLM Provider
Other
IaC Type
Not applicable
Additional Context
Tested from a local source checkout with uv run iac-code on 2026-05-29. A local fake OpenAI-compatible HTTP server was used; no real LLM or cloud credentials were used.
Likely related code:
src/iac_code/cli/headless.py: documents EXIT_MAX_TURNS = 2 and only sets hit_max_turns when a MessageEndEvent has stop_reason == "max_turns".
src/iac_code/agent/agent_loop.py: the main loop iterates over range(self._max_turns) but appears to exhaust the loop without emitting a max-turns event.
Bug Description
The headless runner documents exit code 2 for reaching
--max-turns, but the command exits 0 when the limit is reached before the agent reaches a final text answer.Steps to Reproduce
list_filestool call withfinish_reason: "tool_calls".A related edge case:
Expected Behavior
When the turn limit is reached, the command should return exit code 2, consistent with the documented headless exit codes:
Actual Behavior
For
--max-turns 1, the command exits with code 0 and returns only the tool result, with no final assistant text:{ "text": "", "tool_uses": [ { "name": "list_files", "is_error": false } ] }For
--max-turns 0, the command exits with code 0 and makes no LLM request.Operating System
macOS
Python Version
Python 3.14.2
iac-code Version
0.3.0 (
uv run iac-code --versionoutput:iac-code v0.3.0)LLM Provider
Other
IaC Type
Not applicable
Additional Context
Tested from a local source checkout with
uv run iac-codeon 2026-05-29. A local fake OpenAI-compatible HTTP server was used; no real LLM or cloud credentials were used.Likely related code:
src/iac_code/cli/headless.py: documentsEXIT_MAX_TURNS = 2and only setshit_max_turnswhen aMessageEndEventhasstop_reason == "max_turns".src/iac_code/agent/agent_loop.py: the main loop iterates overrange(self._max_turns)but appears to exhaust the loop without emitting a max-turns event.