From 6350a7361f03d0dbe640ccc8843cb44628a5f38d Mon Sep 17 00:00:00 2001 From: bradAGI <46579244+bradAGI@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:39:39 -0400 Subject: [PATCH] feat(claude_sdk): add CSDK-019, tool prints to stdout for diagnostics Claude SDK and MCP were the two mature packs with no observability rule; OpenAI ships OAI-010 and ADK ships ADK-009 for the same pattern. Two Claude-SDK-specific consequences go beyond the lost log line OAI-010 describes. A tool defined in a Python SDK server is commonly served to the agent over an MCP stdio transport, where stdout carries the JSON-RPC frames and a loose print makes the client hit a parse error on a line that is not JSON. And when the SDK is driven programmatically, the host application is already reading the SDK's own message stream, so tool prints land interleaved with it rather than in the application's logs, attributable to no particular turn or tool call. --- claude_sdk/observability.yaml | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 claude_sdk/observability.yaml diff --git a/claude_sdk/observability.yaml b/claude_sdk/observability.yaml new file mode 100644 index 0000000..42e5d36 --- /dev/null +++ b/claude_sdk/observability.yaml @@ -0,0 +1,41 @@ +policy: + id: claude_sdk_observability + name: Claude Agent SDK tool observability hygiene + category: claude_sdk + description: > + Rules covering how a Claude Agent SDK tool emits diagnostics. A tool body + that prints to stdout writes somewhere neither the model nor the + application's log sink reads, and can corrupt a transport that uses stdout + as a protocol channel. + +rules: + - id: CSDK-019 + title: Tool prints to stdout for diagnostics + severity: low + confidence: 0.65 + language: python + applies_to: + - claude_sdk_tool + scope: tool + match: + has_print_call: true + explanation: > + The tool body calls print(), which writes diagnostics to the process's + stdout. The model never sees that output — only the tool's return value + flows back into the agent loop — so the print silently disappears in any + deployment that captures structured records rather than raw stdout. Two + Claude-SDK-specific consequences make it worse than a lost log line. A + tool defined in a Python SDK server is commonly served to the agent over + an MCP stdio transport, where stdout carries the JSON-RPC frames: a loose + print interleaves with them and the client hits a parse error on a line + that is not JSON. And when the SDK is driven programmatically, the host + application is reading the SDK's own message stream, so tool prints land + interleaved with it rather than in the application's logs, attributable to + no particular turn or tool call. + fix: > + Remove the print(). For operator diagnostics, emit through a module logger + (logging.getLogger(__name__).info(...)) so the record carries its module + and level and lands in the application's log sink; where the tool may be + served over a stdio transport, make sure that handler writes to stderr, + which the transport leaves alone. If the information needs to reach the + model, include it in the tool's return value instead.