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.