[BUG] Agent 'tools:' allowlist silently disables --json-schema structured output (success, exit 0, no structured_output key)

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Jul 29, 2026

Environment

  • Claude Code 2.1.220, Linux (Fedora), subscription auth
  • Reproduced with --model sonnet; also observed across 5 independent agent-mode runs in an acceptance harness

Summary

When claude -p --agent <name> runs an agent whose frontmatter declares a tools: allowlist, --json-schema structured output silently breaks: the run completes with "subtype": "success", exit 0, and no structured_output key in the result. The stream shows the model never calls the internal StructuredOutput tool, consistent with the allowlist excluding it from the agent's toolset. The same invocation without the tools: allowlist returns structured_output normally.

The docs (headless → structured outputs) say a success result can lack the key and should be treated as failure, but here the client makes the contract unsatisfiable and still reports success with exit 0 — there is no error_max_structured_output_retries, no warning, and no way to distinguish "model declined" from "tool was never available".

Repro

mkdir -p /tmp/so-repro/.claude/agents && cd /tmp/so-repro
echo "hello" > demo.txt

cat > .claude/agents/toolsonly.md <<'AGENT'
---
name: toolsonly
description: Minimal agent with a tools allowlist
model: sonnet
tools: Read
---
Answer briefly.
AGENT

schema='{"type":"object","properties":{"status":{"type":"string"}},"required":["status"],"additionalProperties":false}'

# BUG: success, exit 0, no structured_output key
claude -p "Read demo.txt, then return status ok" --agent toolsonly \
  --setting-sources project --no-session-persistence --permission-mode dontAsk \
  --output-format json --json-schema "$schema" \
  | jq '{has_key: has("structured_output"), subtype}'
# => { "has_key": false, "subtype": "success" }

# CONTROL: identical agent without the tools: line
sed '/^tools: Read$/d' .claude/agents/toolsonly.md > .claude/agents/notools.md
sed -i 's/^name: toolsonly$/name: notools/' .claude/agents/notools.md
claude -p "Read demo.txt, then return status ok" --agent notools \
  --setting-sources project --no-session-persistence --permission-mode dontAsk \
  --output-format json --json-schema "$schema" \
  | jq '{has_key: has("structured_output"), subtype}'
# => { "has_key": true, "subtype": "success" }

Also verified: plain -p (no --agent) with the same schema always emits the key, and in --output-format stream-json runs of allowlisted agents there are zero StructuredOutput tool events, while non-agent runs of the same task show them.

Expected

Either (a) the implicit StructuredOutput tool is always available when --json-schema is passed, regardless of the agent's tools: allowlist, or (b) the run fails loudly (error_max_structured_output_retries-style subtype, nonzero exit) when the schema cannot be satisfied. Silent success with a missing key breaks any script that trusts exit codes.

Actual

subtype: success, exit 0, no structured_output key.

View original on GitHub ↗