CCA · Foundations

รัน Claude Code ใน CI: -p, --output-format json, --json-schema

แนวคิด

ใน pipeline อัตโนมัติไม่มีคนคอยตอบ prompt ดังนั้นการรัน claude "..." เฉย ๆ จะค้างเพราะ Claude Code รอ input แบบ interactive คำตอบคือ flag -p หรือ --print ที่สั่งให้รันแบบ non-interactive คือประมวล prompt พ่นผลออก stdout แล้วออกโดยไม่รอ input นี่คือสิ่งที่ CI/CD ต้องการพอดี

พิจารณาโจทย์ตรง ๆ ว่า job รัน claude "วิเคราะห์ PR นี้หาช่องโหว่ความปลอดภัย" แล้วค้างไม่จบ log บอกว่ากำลังรอ interactive input ทางแก้ที่ถูกคือเติม -p เป็น claude -p "..." ส่วนตัวเลือกอื่นอย่าง environment variable CLAUDE_HEADLESS=true หรือ flag --batch เป็นฟีเจอร์ที่ไม่มีจริง และการ redirect stdin จาก /dev/null เป็น workaround ที่ไม่ตรงกับ syntax ของ Claude Code

ทำไมสำคัญ

เมื่อ CI ต้องเอาผลไป parse ต่อ เช่นโพสต์เป็น inline PR comment ผลที่เป็นข้อความอิสระใช้ยาก จึงมี flag คุมรูปแบบ output --output-format รับสามค่า คือ text (ค่าเริ่มต้น), json (มี result, session id, และ metadata), และ stream-json (JSON ต่อบรรทัดแบบ streaming) การใช้ --output-format json ทำให้ script ดึงฟิลด์ที่ต้องการได้แน่นอนด้วยเครื่องมืออย่าง jq

เมื่อต้องการให้ output ตรงตาม schema ที่กำหนด ใช้ --output-format json คู่กับ --json-schema แล้วใส่ JSON Schema เข้าไป Claude Code จะ validate ผลให้ตรง schema และวางผลที่มีโครงสร้างไว้ในฟิลด์ structured_output ของ response นี่คือกลไกที่ทำให้ CI ได้ machine-parseable structured finding ที่เชื่อถือได้ เอาไปโพสต์เป็น comment อัตโนมัติได้โดยไม่ต้องเดา format นอกจากนี้ยังใช้ --append-system-prompt เพื่อเสริมบทบาท เช่นสั่งให้ทำตัวเป็น security engineer โดยยังคงพฤติกรรมพื้นฐานของ Claude Code ไว้

ตัวอย่าง

# non-interactive กัน job ค้างเพราะรอ input
claude -p "วิเคราะห์ PR นี้หาช่องโหว่ความปลอดภัย"

# output เป็น JSON แล้วดึงฟิลด์ result ด้วย jq
claude -p "สรุปโปรเจกต์นี้" --output-format json | jq -r '.result'

# บังคับ structured output ให้ตรง schema → อยู่ในฟิลด์ structured_output
claude -p "ดึงชื่อฟังก์ชันหลักจาก auth.py" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
  | jq '.structured_output'

# เสริมบทบาทใน CI review
gh pr diff "$1" | claude -p \
  --append-system-prompt "คุณคือ security engineer ตรวจหาช่องโหว่" \
  --output-format json

เช็คความเข้าใจ

job รัน claude แล้วค้างเพราะรอ interactive input ควรแก้อย่างไร และทำไมตัวเลือกอื่นไม่ถูก

จะให้ CI ได้ output ที่ machine-parseable ตรงตาม schema ต้องใช้ flag ใด และผลอยู่ที่ไหน

อ่านต่อ