# Request flow diagram from handler code
> Maintain a current sequence diagram of your flagship endpoint's request lifecycle. The agent walks the handler's async/await calls and external integrations to keep the diagram in sync as the code evolves.
## Metadata
- **Diagram family**: `sequence`
- **Source**: Handler source code (TypeScript / Python / Go)
- **Workflow types**: scan, generate, update, validate, render, diff, ci-cd
- **Audience**: developer, platform, security
- **MCP tools**: `dsp_create_scene`, `dsp_apply_ops`, `dsp_validate_scene`, `dsp_render_scene`, `dsp_diff_scene`
- **HTTP endpoints**:
  - `POST /v1/scenes`
  - `POST /v1/scenes/:id/applyOps`
  - `POST /v1/scenes/:id/render`
  - `GET /v1/scenes/:id/diff`
---
---

## What this example shows

A canonical sequence diagram of an HTTP `/checkout` POST handler - the time-ordered interactions between the Client, the Checkout Service, and every collaborator the handler touches: Auth, Redis Cache, Cart, Inventory, the Stripe Payment Provider, and a Notification Queue. The diagram includes a sequence-fragment alt around the payment retry path, a note explaining Stripe's idempotency-key convention, an async fire-and-forget publish to the notification queue, and a self-message for the response-build step. The "before" scene captures the handler before a recent latency-improvement PR (no Redis cache; synchronous notification HTTP call). The "after" scene reflects the handler post-PR (cache layer added, retry logic around payment, notifications moved to a queue). The diff between revisions is the deliverable a reviewer cares about - they see what the new code does differently without reading the PR diff line by line.

## When to use it

Reach for this pattern when your team has a flagship endpoint (checkout, login, payment, document-upload, anything mission-critical) whose internal call graph is hard to hold in one engineer's head. The diagram becomes the team's authoritative answer to "what happens when a request hits this endpoint" - used in onboarding (new engineers learn the flow without grep-walking the codebase), incident response (on-call sees which collaborator to investigate), architecture reviews (anyone proposing a change can show the structural diff alongside the code diff), and compliance audits (security reviewers see exactly which third parties touch which data, in what order). Sequence diagrams are also the right shape when the AUDIT TRAIL matters as much as the structure - every revision is a snapshot of how the request flowed through the system at that point in time.

## What the agent does

The agent watches the handler source file and its direct dependencies. On each PR that touches them, it walks the handler's `async`/`await` chain, identifies the participants (services called via SDK or HTTP, queues published to, caches read, the database, external APIs), and applies typed operations to the persisted scene: `createNode` for new participants, `createEdge` with `edgeType: "sequence.message"` / `"sequence.reply"` / `"sequence.async"` for new interactions, `createFrame` with `containerType: "fragment"` for branching paths (alt for try/catch retry, opt for conditional calls, loop for iterating), and `sequence.note` nodes for implementation notes worth preserving in the diagram (idempotency keys, retry budgets, timeouts).

The flow is incremental - the persisted scene preserves stable lifeline and edge IDs across PRs, so adding one collaborator doesn't reshuffle the whole diagram. The agent renders the updated scene, diffs the previous revision against the new one, and posts the visual diff (plus a structural-diff bullet list) as a PR comment.

## What the output includes

- A `diagramFamily: "sequence"` scene with one `sequence.actor` per external initiator (the Client) and one `sequence.lifeline` per internal collaborator.
- Messages typed correctly: `sequence.message` for synchronous calls, `sequence.reply` for return values (rendered with dashed open arrows), `sequence.async` for fire-and-forget queue publishes (rendered with open arrowheads), `sequence.create` for object instantiation in OO codebases.
- Combined fragments with `extensions.operator: "alt" | "opt" | "loop" | "par"` and operand dividers for branching paths - the canonical example here is the `[charge succeeded]` / `[retry on 5xx]` alt around the payment block.
- Sequence notes anchored OVER a single lifeline (PlantUML / Mermaid convention) for inline implementation notes - visible in the diagram next to the message they describe.
- Self-messages rendered as rounded U-loops for handler-internal computations the agent thinks are worth surfacing (validation, response building).
- A revision diff showing exactly which lifelines, messages, fragments, or notes changed since the last run - the value-add over a one-shot sequence diagram.

## What this example does not aim to do

This is not a tracing-driven recipe. It works from source code, not OpenTelemetry / Jaeger / Honeycomb spans. A trace-driven variant would identify the canonical request flow from real production traffic - useful for catching drift between the documented flow and what actually happens in production - but is a separate recipe with its own observability-stack dependencies. Build whichever fits your team; the source-code recipe is the lower-friction starting point.
## Agent workflow
Maintain a current sequence diagram of an HTTP endpoint's request flow by walking the handler's async/await chain and external integrations, then patching the persisted Zindex scene each time a relevant code path changes.
**Inputs**

- Handler file path (e.g. apps/api/src/routes/checkout.ts) plus its directly-imported service modules
- Optional: monorepo paths to client SDK definitions for external integrations (Stripe, Twilio, etc.) so the agent emits accurate provider-side lifelines
- Existing Zindex scene id (stored as a repo secret)
- Zindex API key with scene-write scope
**Outputs**

- Updated persisted scene with one lifeline per participant, one message per service interaction, and combined-fragment frames for branching paths
- Rendered SVG showing the canonical request flow at the current revision
- Revision diff highlighting added/removed lifelines, new fragments, message-type changes (sync→async, etc.)
- PR comment summarising the structural change and linking to the rendered SVG
**Steps**

1. **Create or fetch the persisted scene** - On first run, create a scene with diagramFamily: "sequence". On subsequent runs, fetch the existing scene by id to read the current revision and elements.
   _MCP: `dsp_create_scene` · HTTP: `POST /v1/scenes`_

2. **Walk the handler's call graph** - Parse the handler source file (TypeScript via the TS compiler API, Python via ast, Go via go/parser). Identify every awaited service call, queue publish, cache read/write, DB query, and external API request - each becomes a (caller, callee, operationName, kind) tuple. Distinguish synchronous calls (await response) from asynchronous publishes (fire-and-forget queue/topic). Branching constructs (try/catch with retry, if/else with parallel paths) become fragment metadata. Self-message candidates: handler-internal helpers that are visually meaningful (validation, response shaping).

3. **Diff parsed flow against the persisted scene** - Compare parsed lifelines + messages + fragments against the current scene. New participants → createNode (sequence.lifeline / sequence.actor). New interactions → createEdge with appropriate edgeType. New branching paths → createFrame with containerType: "fragment" and the right operator (alt | opt | loop | par). Use stable element ids derived from service names so a renamed lifeline stays the same element.
   _MCP: `dsp_get_scene` · HTTP: `GET /v1/scenes/${SCENE_ID}`_

4. **Apply the operation batch** - Send the diff as one applyOps batch with errorPolicy=allOrNothing. The agent uses stable lifeline ids (service.kebab-case) so a renamed service updates the existing lifeline rather than creating a duplicate. Set a meaningful revisionMessage (e.g. "add Redis cache lifeline; move notifications to async publish").
   _MCP: `dsp_apply_ops` · HTTP: `POST /v1/scenes/${SCENE_ID}/applyOps`_

5. **Validate the updated scene** - Resolve any LABEL_DUPLICATION_DETECTED diagnostics - sequence diagrams allow same-label messages (different timestamps), but suspicious duplicates (e.g. two replies labelled the same on the same source) are usually mis-typed. CANVAS_AUTO_EXTENDED is informational; the engine sizes the canvas as the flow grows.
   _MCP: `dsp_validate_scene` · HTTP: `POST /v1/scenes/validate`_

6. **Render to SVG** - Render the updated scene at the new revision. The watermark stamps scene-id + revision + date so the rendered artifact is traceable back to the persisted scene. Theme defaults to clean; pass theme: "dark" if your docs site uses a dark canvas.
   _MCP: `dsp_render_scene` · HTTP: `POST /v1/scenes/${SCENE_ID}/render`_

7. **Diff against the previous revision** - Get a structural summary of what changed between PREV_REVISION and the new revision: added/removed/modified lifelines and messages. Drives the PR comment.
   _MCP: `dsp_diff_scene` · HTTP: `GET /v1/scenes/${SCENE_ID}/diff?from=${PREV_REVISION}&to=${NEW_REVISION}`_

8. **Post PR comment** - Post a structural-diff summary as a PR comment with the rendered SVG attached as a workflow artifact. The reviewer sees what the new code does differently without reading the full code diff.
## Agent prompt

Drop this into a system prompt for an MCP-connected agent.

```
You are an automated code-documentation agent. Your job is to keep a sequence diagram of an HTTP endpoint's request flow in sync with the actual handler code, by parsing the handler source on every PR that touches the relevant paths.

The persisted Zindex scene id is `${SCENE_ID}`; it already exists. Treat it as the canonical, immutable-revisioned source of truth for the request flow. Each run computes the smallest valid set of typed operations that move the scene from its current revision to one that matches the current code.

Workflow on every run:

1. Parse the handler source file at `${HANDLER_PATH}`. Walk the function's `async`/`await` chain (TypeScript via the TS compiler API, Python via `ast`, Go via `go/parser`). For each awaited call, identify the callee (service / collaborator) and the kind: synchronous (the handler waits on a response - emit `sequence.message` + `sequence.reply`), asynchronous (the handler does not await a response - emit `sequence.async`), or self-handler (an internal helper worth surfacing - emit a self-`sequence.message` from the handler back to itself).

2. Identify branching paths. A `try { primary() } catch { retry() }` becomes an `alt` fragment with two operands ("primary" / "retry"). An `if (cond) { sometimes() }` becomes an `opt` fragment. A `for (item of items) { process(item) }` becomes a `loop` fragment. `Promise.all([a(), b()])` becomes a `par` fragment.

3. Annotate non-obvious behaviour with `sequence.note` nodes anchored OVER the relevant lifeline. Idempotency keys, retry budgets, timeouts, side-effect ordering - anything a future engineer or auditor would want to read alongside the code. Notes are NOT a substitute for code comments; use them for structural facts the diagram alone wouldn't convey.

4. Call `dsp_get_scene({ sceneId: "${SCENE_ID}" })` to read the current revision and elements. Diff what you parsed against what is persisted: new lifelines → `createNode`, removed lifelines → `deleteElement`, new messages → `createEdge`, message-kind changes (sync → async) → `updateEdge`. Keep stable lifeline ids (kebab-case service name) so renames update the existing lifeline rather than producing a delete + create.

5. Call `dsp_apply_ops` with one batch. Set `errorPolicy: "allOrNothing"`. Pass a meaningful `revisionMessage` like "add Redis cache layer; move notifications to async publish" - this surfaces in the revision history.

6. Call `dsp_validate_scene` and resolve any `LABEL_DUPLICATION_DETECTED` warnings (sequence diagrams allow same-label messages temporally, but a duplicate at the same source is usually mis-typed). `CANVAS_AUTO_EXTENDED` is informational - let the layout engine size the canvas as the flow grows.

7. Call `dsp_render_scene({ format: "svg" })` and publish the rendered SVG to the docs site (or commit it to `docs/architecture/${ENDPOINT}-flow.svg`). The watermark stamps scene-id + revision + date so the published artifact is traceable.

8. Call `dsp_diff_scene({ from: PREV_REVISION, to: NEW_REVISION })`. Post a PR comment summarising the structural diff: which lifelines were added/removed, which messages changed kind, which fragments were introduced. Reviewers see what the new code does differently before reading the code diff.

Hard rules: never hand-edit the rendered SVG; always edit the scene with `dsp_apply_ops` and re-render. Never regenerate the scene from scratch on each run; always patch with stable ids - the request flow is a long-lived, evolving graph and stable ids are what make revision history meaningful. Treat the handler source as the source of truth; if a comment in the code contradicts the actual call, follow the actual call.
```
## Validation

Captured `POST /v1/scenes/validate` response: **valid** (1 diagnostic)

- `warning` `SELF_LOOP_EDGE_WARNING` (/elements/m_self_validate): Edge 'm_self_validate' is a self-loop on element 'checkout'.
## Resources
- **Canonical scene**: [/examples/request-flow-from-handler.scene.json](/examples/request-flow-from-handler.scene.json)
- **Operations envelope**: [/examples/request-flow-from-handler.ops.json](/examples/request-flow-from-handler.ops.json)
- **Workflow recipe**: [/examples/request-flow-from-handler.workflow.json](/examples/request-flow-from-handler.workflow.json)
- **Revision diff**: [/examples/request-flow-from-handler.diff.json](/examples/request-flow-from-handler.diff.json)
- **GitHub Actions workflow**: [/examples/request-flow-from-handler.github-actions.yml](/examples/request-flow-from-handler.github-actions.yml)
- **Rendered SVG**: [/examples/request-flow-from-handler.svg](/examples/request-flow-from-handler.svg)
- **Human page**: [/examples/request-flow-from-handler](/examples/request-flow-from-handler)
- **Manifest**: [/examples/index.json](/examples/index.json)
## Related examples

- [/examples/api-dependency-map](/examples/api-dependency-map)
- [/examples/living-architecture-docs](/examples/living-architecture-docs)
- [/examples/compliance-pii-flow](/examples/compliance-pii-flow)