From d68ea7ba74a66f95896f7d216316a4f5f908b999 Mon Sep 17 00:00:00 2001 From: Tisha Chawla Date: Wed, 12 Aug 2026 15:42:49 +0530 Subject: [PATCH 1/4] Add dev.to-ready markdown for the trace-attribution post - blog/bug-report-to-exact-trace.devto.md: dev.to-specific front matter (published: false draft, description, tags: ai/llm/python/opensource picked by actual dev.to tag post-counts for reach: ai 348k, python 118k, opensource 89k, llm 26k, all genuinely on-topic, not tag-stuffed; cover_image; canonical_url pointing at the site so SEO authority stays with theagentplane.github.io regardless of which account publishes it). Plain markdown images (dev.to doesn't reliably render raw ), a GitHub repo embed for the Chronicle CTA, and @mentions of both dev.to handles (@susheem-k, @tisha) in the byline. - Documented in add-media-item/SKILL.md why dev.to can't do real co-authored posts on personal accounts (no theagentplane org exists) and what the practical alternative is: one account publishes, mentions the other, canonical_url keeps the site as the real source of truth. Co-Authored-By: Claude Sonnet 5 --- blog/bug-report-to-exact-trace.devto.md | 180 ++++++++++++++++++++++++ claude-skills/add-media-item/SKILL.md | 27 +++- 2 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 blog/bug-report-to-exact-trace.devto.md diff --git a/blog/bug-report-to-exact-trace.devto.md b/blog/bug-report-to-exact-trace.devto.md new file mode 100644 index 0000000..a8848c1 --- /dev/null +++ b/blog/bug-report-to-exact-trace.devto.md @@ -0,0 +1,180 @@ +--- +title: Debugging Multi-Agent Systems: Your Trace Tree Is Lying +published: false +description: How to debug multi-agent AI systems, trace attribution, OpenTelemetry span nesting, and session, message, and trace ids for LLM agent observability, from first principles with Chronicle. +tags: ai, llm, python, opensource +cover_image: https://theagentplane.github.io/assets/blog/waterfall.svg +canonical_url: https://theagentplane.github.io/blog/bug-report-to-exact-trace.html +--- + +*Co-written with [@susheem-k](https://dev.to/susheem-k) / [@tisha](https://dev.to/tisha). We build [Chronicle](https://github.com/theagentplane/chronicle) in the open at [AgentPlane](https://theagentplane.github.io).* + +It's Tuesday. Someone on support forwards you a message: *"priya@acmecorp.com says the assistant told her something false, sometime yesterday afternoon."* No conversation id. No message id. Just a name and a rough window of time. Maybe it's quieter than that: a thumbs-down on your own feedback button, or an alert your monitoring auto-files. Either way, what lands on your desk is never "here is the broken function." At best, it's a person and roughly when. + +Your agent, meanwhile, is not one function call. A single user message might fan out into an orchestrator calling a researcher, which calls a model, which calls a search tool, twice, with a retry in the middle. That one bad reply the user saw was produced by one specific call, three levels deep, somewhere inside a tree of a dozen calls made sometime in a two-hour window. You have a name and a time range. You need a call stack. + +This post closes that gap, from first principles, with the actual mechanism, not a hand-wave. By the end you'll know how to go from "a name and roughly when" down to a session, a message, and the exact call that misfired; the specific attribution bug that quietly breaks naive tracing in any system with parallel or repeated sub-agents (you have this bug right now if you haven't specifically fixed it); and the one-line change that fixes it, drawn from [Chronicle](https://github.com/theagentplane/chronicle) (`chronicle#41`, open for review as we write this). + +## First principles: the four IDs + +Before you can go from "a name and roughly when" to "here's the exact call that misfired," you need to know what identifies what, and where you actually start. There are four levels, and conflating any two of them is where most homegrown tracing setups go wrong. + +![Session contains messages, one message maps to one trace, one trace contains many envelopes](https://theagentplane.github.io/assets/blog/id-hierarchy.svg) + +- **Session** (`session_id`). One conversation. A user might send you ten messages over an hour; they all share one session. +- **Message**. One user turn inside that session. This is what a precise bug report gives you, when you're lucky enough to get one: "in this message, the agent said something wrong." +- **Trace** (`trace_id`). One agent *run*. In practice, one message turn produces one trace: the user sends a message, the agent does whatever it does (one call or twenty), and produces a reply. +- **Envelope** (`envelope_id`, OTel calls it a *span*). One LLM call, one tool call, or one routing decision inside that run. A trace is an ordered tree of these. + +Resolving "yesterday afternoon" into a `session_id` is ordinary application code, not Chronicle's job: look up the account, find the sessions active in that window. Chronicle's job starts once you have that `session_id`. Single-shot service-to-service calls collapse the next two (no multi-turn session, just a `session_id` and maybe a `caller_id`). Multi-turn chat keeps `session_id` constant across the conversation and mints a new `message_id` (and a new `trace_id`) on every turn. Either way, the shape is the same: **you start with almost nothing, resolve down to a session and a message, and Chronicle gets you the rest of the way to the exact call.** + +This is exactly the mapping problem we'd sketched out on a whiteboard before writing a line of code: name and time → session → message → trace, with the open question of how you ever get from "roughly yesterday afternoon" to "the actual execution graph." The rest of this post is the answer. + +## Why "just add tracing" doesn't get you there + +Say you've done the obvious thing: wrapped your LLM and tool calls so each one records an envelope with a `parent_envelope_id`, and you build a tree out of that after the fact. This works in every demo. It works in your first three fixtures. Then it breaks silently, on the one trace you actually needed, because you have **two branches of the same shape running in the same trace**, which in a multi-agent system is the common case, not the edge case. + +And if you already run OpenTelemetry against this agent, you are not exempt. The failure mode here isn't "we have no tracing." It's "our tracing is confidently wrong," which is worse, because a tree that renders cleanly is a tree you trust. You stop looking anywhere else. You spend the debugging session inside the wrong subtree, close the ticket with a fix that doesn't touch the actual bug, and it comes back a week later with a slightly different repro. + +Here's the concrete scenario: an orchestrator calls the same sub-agent twice, once per source it needs to research. Each call does an LLM planning step and a tool call: + +```python +from chronicle import boundary + +@boundary("planner", kind="llm") +def planner(task: str) -> dict: + ... + +@boundary("web_search", kind="tool") +def web_search(query: str) -> dict: + ... + +def researcher(task: str) -> dict: # plain code, not a boundary + plan = planner(task) + return web_search(plan["query"]) + +def orchestrator(task: str) -> dict: # plain code, not a boundary + first = researcher(task + " (source A)") + second = researcher(task + " (source B)") + return [first, second] +``` + +Notice `researcher` and `orchestrator` aren't boundaries themselves. That's deliberate: you mark **decision nodes** (an LLM call, a tool call, a routing choice), not the whole call stack. This keeps recording overhead near zero and keeps your orchestration as plain code Chronicle never has to know about. The question is how those decision nodes learn who their parent is if nobody wrapped `researcher` or `orchestrator`. + +The naive answer is "attribute a new envelope to whichever envelope finished most recently." It's the simplest thing that could work, and it's wrong the moment two sibling subtrees are in flight or interleaved: + +![Before: last-finished attribution misattributes researcher number 2's calls to researcher number 1. After: context-stack attribution nests them correctly.](https://theagentplane.github.io/assets/blog/attribution-before-after.svg) + +When `researcher`'s second call starts its `planner` call, the "most recently finished" envelope is `web_search#1` from the *first* call, not anything belonging to the second `researcher`. The tree you reconstruct silently welds the second research branch onto the first one. You go looking for why researcher #2 produced a bad answer, and every log line in front of you belongs to researcher #1. Nothing crashes. Nothing throws. The trace just quietly points you at the wrong code for an hour. + +## The fix: open the span before the body runs + +The fix is one sentence: **a boundary opens its span when it's entered, before the wrapped function runs, not after it returns.** That single change is the difference between "attribute by whatever happened to finish last" and "attribute by what's actually on the call stack right now," and that is precisely what OpenTelemetry's `Context` does, and precisely what was missing. + +```python +# Simplified: what @boundary now does around your function +span_id, parent_id = session.start_span() # push onto the active-span stack +try: + result = fn(*args, **kwargs) # anything this calls sees `span_id` as parent +finally: + session.end_span() # pop back to the caller's span +``` + +Because `start_span()` runs before `fn`, any boundary invoked *while this one is still on the stack* correctly parents to it, no matter what else happens to finish in between. Rerun the two-branch scenario above and the tree comes out right every time, regardless of timing: + +![Animated waterfall: orchestrator, two researcher branches each with a correctly nested llm and tool call](https://theagentplane.github.io/assets/blog/waterfall.svg) + +``` +Trace: trace-9f2a1 + total: 164.5ms resource/dims: message_id=msg_042 session_id=sess_abc + +orchestrator#1 ████████████████████████████████████████████ 164.5ms custom + researcher#1 ██████████████████████ 74.8ms custom + llm#1 ██████████████ 42.3ms llm + web_search#1 ██████████ 31.7ms tool + researcher#2 ████████████████████ 72.3ms custom + llm#2 ████████████ 40.5ms llm + web_search#2 ██████ 30.9ms tool +``` + +This is what `graph.to_otel_waterfall()` prints (there's also `graph.to_otel_tree()`, which prints the same tree as indented lines instead of a timeline). Both are debug helpers you run locally or pipe into a log line, not a hosted product; if you want a shared dashboard your whole team browses, that's a separate concern from what a recording library should own. + +## The other half: getting `session_id` and `message_id` onto the trace + +Correct nesting gets you a trustworthy tree once you're looking at the right trace. It doesn't yet tell you *which* trace, out of everything your agent ran today. For that, Chronicle added `dims`: a flat `dict[str, str]` you pass once, that gets copied onto every envelope in the run. + +```python +import chronicle + +with chronicle.record( + "trace-9f2a1", + store=".chronicle/runs/prod.jsonl", + dims={ + "session_id": "sess_abc", # constant for the whole conversation + "message_id": "msg_042", # new value every turn + }, +): + orchestrator(user_message) +``` + +That's it. Chronicle doesn't store your chat history and doesn't own a "look up trace by message ID" index; that's a product concern for whatever's on the other end (your logging pipeline, your control plane, a support tool). We're building a complementing dashboard for exactly this lookup next (more on that in a future post). Until then, what Chronicle guarantees is that once you have a `session_id` and a `message_id`, every envelope in the matching trace carries them, so any store you point it at can build that index trivially: `grep`, a SQL `WHERE`, or a dashboard query, your choice. + +## Try it yourself + +```bash +pip install agent-chronicle +``` + +1. **Mark your decision nodes.** Wrap the LLM calls, tool calls, and routing choices you'd actually want to assert on in a test, not the whole orchestrator function. + + ```python + from chronicle import boundary + + @boundary("planner", kind="llm") + def planner(task: str) -> dict: ... + + @boundary("web_search", kind="tool") + def web_search(query: str) -> dict: ... + ``` + +2. **Record a run with the ids you'll get back from a ticket.** + + ```python + import chronicle + + with chronicle.record( + "trace-9f2a1", + store=".chronicle/runs/prod.jsonl", + dims={"session_id": "sess_abc", "message_id": "msg_042"}, + ) as session: + orchestrator(user_message) + ``` + +3. **When a ticket comes in, pull the trace and print the tree.** + + ```python + graph = chronicle.ExecutionGraph.from_envelopes(session.trace_id, session.envelopes) + print(graph.to_otel_waterfall()) + ``` + +4. **Turn the bad run into a regression test.** Add `export="fixtures/traces/incident-001/"` to the `record(...)` call and the exact trace gets committed to git as a fixture. Replay it (`chronicle.replay_trace`) with your fix applied and no live model calls, so "did this actually fix it" becomes a test you run in CI, not a hope. + +If your agent is instrumented with OpenTelemetry already, `chronicle.instrument_otel()` emits the same nested spans to your existing collector (`pip install agent-chronicle[otel]`), so this isn't an either/or with the observability stack you already run. + +## What this doesn't solve, on purpose + +We'd rather tell you the edges than let you find them the hard way: + +- **Chronicle doesn't store your session or message history.** It stamps the ids you give it onto envelopes. Owning "what messages exist in this session" is your app's job, not a recording library's. +- **There's no hosted lookup UI yet.** `to_otel_tree()` / `to_otel_waterfall()` are local debug output. A dashboard where a support ticket resolves straight to a trace view is a control-plane concern we're building next, not something bolted into this library. +- **Replay proves control flow, not answer quality.** Replaying a trace with your fix tells you the agent takes the right *path* and calls the right tools with the right arguments, deterministically, with no live model calls. It won't tell you a subjectively "better" answer is actually better; that's a model-quality eval, a different tool for a different question. + +## If this is a problem you have + +Star [theagentplane/chronicle](https://github.com/theagentplane/chronicle) if this is useful, it's the fastest way to tell us to keep going, and it's genuinely how a two-person OSS project gets found by the next person with this exact problem. Try it on one flaky agent, tell us where the API gets in your way, or open an issue with the trace that broke you. We're building this in public specifically so the next fix is shaped by a real incident, not a guess. + +--- + +*We're [@susheem-k](https://dev.to/susheem-k) and [@tisha](https://dev.to/tisha), building agent infrastructure in the open at [AgentPlane](https://theagentplane.github.io). Chronicle is one piece; [TokenOps](https://github.com/theagentplane/tokenops) (run-aware token governance) is the other. Follow along or [browse the org](https://github.com/theagentplane).* + +{% embed https://github.com/theagentplane/chronicle %} diff --git a/claude-skills/add-media-item/SKILL.md b/claude-skills/add-media-item/SKILL.md index a68cb7e..9d4e97b 100644 --- a/claude-skills/add-media-item/SKILL.md +++ b/claude-skills/add-media-item/SKILL.md @@ -107,10 +107,29 @@ one level down. `source: "AgentPlane"` gets its own badge (`.source-agentplane` in `css/style.css`) and is what `blog.html` filters on (`renderMediaList('blog-list', null, null, 'AgentPlane')`) to show only native posts. -Write the post in two files: `blog/slug.html` (uses `.article-header` / -`.article-body` from `css/style.css`, nav + footer like every other page) and -`blog/slug.md` (plain GitHub-flavored markdown, same content, absolute image URLs) -as the source you cross-post to dev.to / Substack. Add images under `assets/blog/`. +Write the post in **three** files: +- `blog/slug.html`: uses `.article-header` / `.article-body` from `css/style.css`, + nav + footer like every other page. +- `blog/slug.md`: plain GitHub-flavored markdown, same content, absolute image + URLs, `canonical:` front-matter key. This is the site-canonical copy, byline + links to LinkedIn (matches the HTML). +- `blog/slug.devto.md`: dev.to-specific front matter (`published: false` so it + lands as a draft, `description`, `tags` as a plain comma-separated string, max + 4, lowercase single words, `cover_image` pointing at one of the post's own + `assets/blog/*.svg` diagrams, `canonical_url`, not `canonical`, dev.to's + literal expected key). Images are plain `![alt](url)`, not ``, since + dev.to's markdown renderer doesn't reliably pass through raw HTML. + +dev.to has no true multi-author posts on personal accounts (no org exists for +theagentplane as of 2026-08). The real "collaborate" mechanism there is: +publish from **one** account, `@mention` the other author by their dev.to +handle in the byline (creates a real profile link + notifies them), and point +`canonical_url` at the site so the site stays the SEO source of truth +regardless of which account posted it. A dev.to Organization would enable true +shared publishing, but someone has to create that account by hand +(`dev.to/settings/organization`), not something to set up unprompted. + +Add images under `assets/blog/`. Give each `blog/slug.html` a unique-reader badge near the byline (not in the `.md`, it's a page-only widget, no custom JS needed): From c92303711b639758e8fa3ab1fd042530429cce76 Mon Sep 17 00:00:00 2001 From: Tisha Chawla Date: Wed, 12 Aug 2026 15:48:54 +0530 Subject: [PATCH 2/4] Add a visible "originally published at" link to the dev.to byline canonical_url in front matter handles SEO, but readers never see front matter; add the same link visibly in the byline so it's obvious on the rendered page too. Co-Authored-By: Claude Sonnet 5 --- blog/bug-report-to-exact-trace.devto.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blog/bug-report-to-exact-trace.devto.md b/blog/bug-report-to-exact-trace.devto.md index a8848c1..58b9a22 100644 --- a/blog/bug-report-to-exact-trace.devto.md +++ b/blog/bug-report-to-exact-trace.devto.md @@ -7,7 +7,7 @@ cover_image: https://theagentplane.github.io/assets/blog/waterfall.svg canonical_url: https://theagentplane.github.io/blog/bug-report-to-exact-trace.html --- -*Co-written with [@susheem-k](https://dev.to/susheem-k) / [@tisha](https://dev.to/tisha). We build [Chronicle](https://github.com/theagentplane/chronicle) in the open at [AgentPlane](https://theagentplane.github.io).* +*Co-written with [@susheem-k](https://dev.to/susheem-k) / [@tisha](https://dev.to/tisha). We build [Chronicle](https://github.com/theagentplane/chronicle) in the open at [AgentPlane](https://theagentplane.github.io). Originally published at [theagentplane.github.io](https://theagentplane.github.io/blog/bug-report-to-exact-trace.html).* It's Tuesday. Someone on support forwards you a message: *"priya@acmecorp.com says the assistant told her something false, sometime yesterday afternoon."* No conversation id. No message id. Just a name and a rough window of time. Maybe it's quieter than that: a thumbs-down on your own feedback button, or an alert your monitoring auto-files. Either way, what lands on your desk is never "here is the broken function." At best, it's a person and roughly when. From b31d409bce0ed65dbc00e1d612a85bcbbfb99870 Mon Sep 17 00:00:00 2001 From: Tisha Chawla Date: Wed, 12 Aug 2026 15:54:30 +0530 Subject: [PATCH 3/4] Fix id-hierarchy.svg: canvas was 50px too narrow for its own content The Envelope box sat at x=780 width=190 (spans to x=970), but the SVG canvas/viewBox was only 920 wide, clipping the box border and "One LLM/tool call" text on the right edge. Widened canvas to 1000 and recentered the caption. Found this while rendering a static PNG export for dev.to and comparing against the live diagram, the site itself has been showing this clipped for as long as the post has been up. Co-Authored-By: Claude Sonnet 5 --- assets/blog/id-hierarchy.svg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/blog/id-hierarchy.svg b/assets/blog/id-hierarchy.svg index 8ac30f0..ea440bb 100644 --- a/assets/blog/id-hierarchy.svg +++ b/assets/blog/id-hierarchy.svg @@ -1,5 +1,5 @@ - - + + @@ -47,7 +47,7 @@ env-004 - A ticket gives you the left two. Chronicle gets you from there to the exact call on the right. + A ticket gives you the left two. Chronicle gets you from there to the exact call on the right. From 2d70dc2a26e1f9af0e62ef60fe3aea63fb95319c Mon Sep 17 00:00:00 2001 From: Tisha Chawla Date: Wed, 12 Aug 2026 15:55:35 +0530 Subject: [PATCH 4/4] Use PNG diagrams in the dev.to post, not SVG dev.to proxies external images through Cloudinary, and SVG support through that pipeline isn't reliably documented, better not to risk broken images on publish. Rendered all three diagrams to PNG via headless Edge and pointed cover_image + the three inline images at those instead. Documented the render command (with the animation-settling flag for the waterfall) in add-media-item/SKILL.md for future posts. Co-Authored-By: Claude Sonnet 5 --- assets/blog/attribution-before-after.png | Bin 0 -> 36760 bytes assets/blog/id-hierarchy.png | Bin 0 -> 16016 bytes assets/blog/waterfall.png | Bin 0 -> 15553 bytes blog/bug-report-to-exact-trace.devto.md | 8 +++---- claude-skills/add-media-item/SKILL.md | 26 +++++++++++++++++++---- 5 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 assets/blog/attribution-before-after.png create mode 100644 assets/blog/id-hierarchy.png create mode 100644 assets/blog/waterfall.png diff --git a/assets/blog/attribution-before-after.png b/assets/blog/attribution-before-after.png new file mode 100644 index 0000000000000000000000000000000000000000..1e49f07fe50f1f718e0c25393ec6ca959a17f670 GIT binary patch literal 36760 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%0DX+~KR@I6na=~PU%jd(bNcoVsGJ4DC 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%0DJQd&SIM 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 Nz&F^3@k7Ghe*mQwldJ#$ literal 0 HcmV?d00001 diff --git a/assets/blog/id-hierarchy.png b/assets/blog/id-hierarchy.png new file mode 100644 index 0000000000000000000000000000000000000000..2a44371cedfdfbe2c5e9af6af2c480e66f080280 GIT binary patch literal 16016 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 A9smFU literal 0 HcmV?d00001 diff --git a/assets/blog/waterfall.png b/assets/blog/waterfall.png new file mode 100644 index 0000000000000000000000000000000000000000..3fec1c69a8b84bcb873b40302d08349886c2f51e GIT binary patch literal 15553 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
ma#zqT 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 literal 0 HcmV?d00001 diff --git a/blog/bug-report-to-exact-trace.devto.md b/blog/bug-report-to-exact-trace.devto.md index 58b9a22..973106b 100644 --- a/blog/bug-report-to-exact-trace.devto.md +++ b/blog/bug-report-to-exact-trace.devto.md @@ -3,7 +3,7 @@ title: Debugging Multi-Agent Systems: Your Trace Tree Is Lying published: false description: How to debug multi-agent AI systems, trace attribution, OpenTelemetry span nesting, and session, message, and trace ids for LLM agent observability, from first principles with Chronicle. tags: ai, llm, python, opensource -cover_image: https://theagentplane.github.io/assets/blog/waterfall.svg +cover_image: https://theagentplane.github.io/assets/blog/waterfall.png canonical_url: https://theagentplane.github.io/blog/bug-report-to-exact-trace.html --- @@ -19,7 +19,7 @@ This post closes that gap, from first principles, with the actual mechanism, not Before you can go from "a name and roughly when" to "here's the exact call that misfired," you need to know what identifies what, and where you actually start. There are four levels, and conflating any two of them is where most homegrown tracing setups go wrong. -![Session contains messages, one message maps to one trace, one trace contains many envelopes](https://theagentplane.github.io/assets/blog/id-hierarchy.svg) +![Session contains messages, one message maps to one trace, one trace contains many envelopes](https://theagentplane.github.io/assets/blog/id-hierarchy.png) - **Session** (`session_id`). One conversation. A user might send you ten messages over an hour; they all share one session. - **Message**. One user turn inside that session. This is what a precise bug report gives you, when you're lucky enough to get one: "in this message, the agent said something wrong." @@ -63,7 +63,7 @@ Notice `researcher` and `orchestrator` aren't boundaries themselves. That's deli The naive answer is "attribute a new envelope to whichever envelope finished most recently." It's the simplest thing that could work, and it's wrong the moment two sibling subtrees are in flight or interleaved: -![Before: last-finished attribution misattributes researcher number 2's calls to researcher number 1. After: context-stack attribution nests them correctly.](https://theagentplane.github.io/assets/blog/attribution-before-after.svg) +![Before: last-finished attribution misattributes researcher number 2's calls to researcher number 1. After: context-stack attribution nests them correctly.](https://theagentplane.github.io/assets/blog/attribution-before-after.png) When `researcher`'s second call starts its `planner` call, the "most recently finished" envelope is `web_search#1` from the *first* call, not anything belonging to the second `researcher`. The tree you reconstruct silently welds the second research branch onto the first one. You go looking for why researcher #2 produced a bad answer, and every log line in front of you belongs to researcher #1. Nothing crashes. Nothing throws. The trace just quietly points you at the wrong code for an hour. @@ -82,7 +82,7 @@ finally: Because `start_span()` runs before `fn`, any boundary invoked *while this one is still on the stack* correctly parents to it, no matter what else happens to finish in between. Rerun the two-branch scenario above and the tree comes out right every time, regardless of timing: -![Animated waterfall: orchestrator, two researcher branches each with a correctly nested llm and tool call](https://theagentplane.github.io/assets/blog/waterfall.svg) +![Animated waterfall: orchestrator, two researcher branches each with a correctly nested llm and tool call](https://theagentplane.github.io/assets/blog/waterfall.png) ``` Trace: trace-9f2a1 diff --git a/claude-skills/add-media-item/SKILL.md b/claude-skills/add-media-item/SKILL.md index 9d4e97b..6d83ebb 100644 --- a/claude-skills/add-media-item/SKILL.md +++ b/claude-skills/add-media-item/SKILL.md @@ -115,10 +115,28 @@ Write the post in **three** files: links to LinkedIn (matches the HTML). - `blog/slug.devto.md`: dev.to-specific front matter (`published: false` so it lands as a draft, `description`, `tags` as a plain comma-separated string, max - 4, lowercase single words, `cover_image` pointing at one of the post's own - `assets/blog/*.svg` diagrams, `canonical_url`, not `canonical`, dev.to's - literal expected key). Images are plain `![alt](url)`, not ``, since - dev.to's markdown renderer doesn't reliably pass through raw HTML. + 4, lowercase single words, `cover_image`, `canonical_url`, not `canonical`, + dev.to's literal expected key). Images are plain `![alt](url)`, not ``, + since dev.to's markdown renderer doesn't reliably pass through raw HTML. + +Diagrams live as `assets/blog/slug-name.svg` for the site (crisp, tiny, and the +site's CSS/theme can style them), but dev.to proxies external images through +its own Cloudinary pipeline and SVG support through that path isn't reliably +documented, so **the `.devto.md` file should reference `.png` versions of the +same diagrams**, not the `.svg`. Generate them with a headless Chromium +screenshot rather than guessing a converter is installed: + +```powershell +$edge = "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" +& $edge --headless --disable-gpu --screenshot="assets\blog\name.png" ` + --window-size=, ` + "file:///\assets\blog\name.svg" +``` + +Pad the window size well past the SVG's own `viewBox` (Edge can otherwise clip +the right/bottom edge), and if the SVG has SMIL `` elements, add +`--virtual-time-budget=2500` so it captures a settled frame instead of +whatever was mid-draw at t=0. dev.to has no true multi-author posts on personal accounts (no org exists for theagentplane as of 2026-08). The real "collaborate" mechanism there is: