Saída Estruturada
--output-format json com um esquema para análise.
Saída Estruturada é uma aula grátis de Claude Architect no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Claude Architect, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Claude Architect inclui 4 aulas no total.
Partes desta aula ainda não foram traduzidas e aparecem em inglês.
Why Structured Output in CI/CD
When you run Claude Code inside a pipeline, a human is not reading the result — a script is. A CI job needs a stable, machine-parseable answer so it can fail the build, post a comment, or gate a merge.
Two flags make this possible:
-p(or--print) runs Claude Code non-interactively — required in any pipeline.--output-format jsonreturns a parseable result instead of free-form text.
This lesson is Domain 4 (Prompt Engineering & Structured Output) meeting Scenario 5 (Claude Code for CI/CD).
claude -p "Review the staged diff for security bugs" \
--output-format jsonThe Problem With Free-Form Text
If you let the model answer in prose, your pipeline has to scrape that prose with regexes — counting words, hunting for phrases like "looks good" or "found issues". That is brittle and a classic anti-pattern.
The same rule applies to the agentic loop: you terminate on a stop_reason, never by parsing text for words like "done". In CI, you decide pass/fail from structured fields, never from free text.
Structured output replaces fragile text-scraping with a contract your script can trust.
Adding a Schema
--output-format json gives you JSON, but plain JSON can still vary in shape. Pair it with a JSON Schema so the output always has the exact fields your pipeline expects.
A schema delivers two guarantees:
- It eliminates syntax errors — no half-formed JSON to crash your parser.
- It enforces required fields — the fields you mark required are always present.
Schema-constrained output is the same mechanism that powers tool use: tool_use + JSON Schema is how Claude returns reliable structured data.
{
"type": "object",
"properties": {
"verdict": { "type": "string", "enum": ["pass", "fail"] },
"issues": {
"type": "array",
"items": { "type": "object" }
}
},
"required": ["verdict", "issues"]
}Designing the Issue Object
Make each finding a precise object the pipeline can act on. A good review schema gives every issue a location, a severity, and an explanation — so the job can annotate the exact line.
Use an enum for severity to keep values consistent across runs. Free-text severities like "kinda bad" are unparseable.
{
"type": "object",
"properties": {
"file": { "type": "string" },
"line": { "type": "integer" },
"severity": { "type": "string",
"enum": ["blocker", "major", "minor"] },
"message": { "type": "string" }
},
"required": ["file", "severity", "message"]
}Required Fields: The Golden Rule
Mark a field required only if it is always present. This is the single most-tested structured-output rule.
If you require a field that may be absent — say line for a project-wide finding that has no specific line — the model will fabricate a value to satisfy the schema. That hallucinated line number then drives a wrong CI annotation.
In the previous scene, line was deliberately left out of required: not every issue maps to one line.
Enums + an "other" Escape Hatch
Enums keep values clean, but a rigid enum can box the model in when reality doesn't fit any category. The extensible pattern: add an "other" enum value plus a free-text detail field.
Now the model can stay in-schema for the common cases and still report the unexpected one without fabricating a wrong category.
{
"category": {
"type": "string",
"enum": ["security", "performance",
"style", "other"]
},
"category_detail": {
"type": "string",
"description": "Free text when category is 'other'"
}
}Guaranteeing Structure With tool_choice
When you call Claude through the SDK rather than the CLI, you guarantee structured output by combining a tool whose input_schema is your JSON Schema with the right tool_choice:
"auto"— the model may answer in text OR call a tool (no guarantee)."any"— the model MUST call some tool, which guarantees structured output.{"type":"tool","name":"X"}— forces one specific tool.
For a CI review where you always need the report object, force the exact tool by name.
resp = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
tools=[review_report_tool], # input_schema = your JSON Schema
tool_choice={"type": "tool", "name": "emit_review"},
messages=[{"role": "user", "content": diff_text}],
)Parsing the CI Result
In the pipeline you read the JSON, then branch on a field — never on the prose. Pull the structured payload and let the verdict decide the exit code.
Because the schema marked verdict and issues as required, this code never has to guess whether the keys exist.
import json, subprocess, sys
out = subprocess.run(
["claude", "-p", PROMPT, "--output-format", "json"],
capture_output=True, text=True,
).stdout
report = json.loads(out)
if report["verdict"] == "fail":
for i in report["issues"]:
print(f"{i['file']}:{i.get('line','-')} {i['message']}")
sys.exit(1)Validate, Then Retry With Feedback
Even with a schema, a value can be semantically wrong (a bad arithmetic total, a malformed reference). Validate the parsed object with Pydantic-style checks, and on a structural/format error use retry-with-feedback.
Send the model three things: the original input, the wrong output it produced, and the exact validation error. This fixes format, structural, and arithmetic mistakes.
Key limit: retry does NOT help when the information is simply absent from the source — no amount of re-prompting invents data that isn't there.
from pydantic import BaseModel, ValidationError
class Review(BaseModel):
verdict: str
issues: list[dict]
try:
review = Review.model_validate_json(out)
except ValidationError as e:
retry(original=diff_text, bad_output=out, error=str(e))Review in an Isolated Session
If the same conversation that generated code also reviews it, the reviewer keeps its own reasoning and won't challenge itself — same-session self-review is an anti-pattern.
Run the structured review in an isolated, fresh session. An independent instance is far better at catching real defects. This pairs naturally with structured output: a clean session in, a clean JSON report out.
Tune the prompt with explicit criteria ("flag a comment only when it contradicts the code") to minimize false positives that would block good merges.
Blocking Checks vs. Overnight Audits
A pre-merge CI gate is blocking and time-sensitive — run it synchronously with -p --output-format json. Using the Message Batches API here is wrong: batches are 50% cheaper but have no latency SLA, up to a 24h window, and don't support multi-turn tool calling.
Reserve the Batch API for non-blocking jobs — an overnight audit of the whole repo, a nightly report — where custom_id correlates each request and you re-submit only failures.
Quick Check
Apply the structured-output rules to a real pipeline decision.
Recap: Structured Output in CI/CD
Key takeaways:
- In pipelines run Claude Code with
-p(non-interactive) and--output-format jsonplus a schema; branch on fields, never on prose. - A JSON Schema eliminates syntax errors and enforces required fields.
- Mark a field required ONLY if it is always present — requiring a possibly-absent field causes fabrication.
- Use enums with an
"other"value + a detail field for extensibility. - Via the SDK,
tool_choice"any"or a forced tool guarantees structured output;"auto"does not. - Validate (Pydantic-style) and retry-with-feedback (original + wrong output + exact error) for format errors — but retries can't supply absent data.
- Review in an isolated/fresh session, not the generating one; minimize false positives with explicit criteria.
- Blocking gate = synchronous; Batch API only for non-blocking overnight jobs.
Perguntas Frequentes
A aula “Saída Estruturada” é grátis?
Sim — o texto completo de “Saída Estruturada” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Claude Architect, atualize para CoddyKit PRO. O curso de Claude Architect inclui 4 aulas no total.
O que vou aprender em “Saída Estruturada”?
--output-format json com um esquema para análise. Você pratica Claude Architect com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Claude Architect?
Nenhuma experiência prévia é necessária. Claude Architect no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Saída Estruturada”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Claude Architect?
Sim. Cada aula de Claude Architect inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.