Share what a Claude Agent SDK run produced
The SDK gives an agent real tools — file access, bash, whatever you allow — so it produces real artifacts. A migration plan, an audit, a rendered summary of what it changed and why.
Then query() returns, the process exits, and the artifact is in a directory
that existed for the length of the run.
Attach Comma as an MCP server
The SDK speaks MCP, and Comma is a remote server, so this is configuration rather than code:
from claude_agent_sdk import query, ClaudeAgentOptions
options = ClaudeAgentOptions(
mcp_servers={
"comma": {
"type": "http",
"url": "https://commareports.com/api/mcp",
"headers": {"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
}
},
system_prompt=(
"When you finish work that someone needs to read, render it as a "
"self-contained HTML report, publish it to Comma, and return the URL. "
"Do not paste the HTML into your reply."
),
)
async for message in query(prompt=task, options=options):
...
The standing instruction in the system prompt is the part that makes this stick. Without it the agent will publish when asked and write a local file when not, which is the same inconsistency the project-level rule for Claude Code exists to remove.
Headless is the whole reason
An interactive run has a human at a terminal who can open a local file. A
scheduled or triggered run does not. The agent that reconciles yesterday's
data at 06:00 and writes reconciliation.html into its container has produced
nothing — the file and the container disappear together.
A URL survives the process. It is the same argument as publishing from CI, and the same reason routines exist for the schedule itself.
Subagents publish once
If your run fans out — a researcher, a checker, a writer — publish from the top-level agent after the subagents report back, not from each subagent. Five subagents with publish access produce five reports and no agreement about which one to read.
The revision loop
Because comments are readable over the same MCP server, the second run is better-informed than the first:
Read the open comment threads on report
<id>. Address each one, update the same report, and reply in each thread describing the change.
Updating rather than re-creating keeps every reviewer's thread attached to the document it was about — see letting an agent respond to comments.
Worth knowing
- Give the agent
reports:writeand nothing more until you need the comment loop — see scoped tokens for AI agents. - Return the URL, not the document. A rendered report in the final message is context you pay for on every subsequent turn.
- 5 MB per report body.
- Report HTML renders sandboxed —
allow-scripts, noallow-same-origin.
Try it
Free — unlimited reports, commenters and revisions.