Generate a Sequence Diagram from Code
diagrams_generate_sequenceDraft a PlantUML or Mermaid sequence diagram from the message-call patterns in a slice of the codebase, returning source text to review and then save with diagrams_create.
Instructions
Draft a PlantUML or Mermaid sequence diagram from the message-call patterns in a slice of the codebase, returning source text to review and then save with diagrams_create.
Static call-site order is not runtime order. This tool reads call sites in the order a reader meets them and says so in every result: a call inside a callback, promise, or listener is counted in deferred_count and excluded from the messages, because its real position in the conversation is unknowable from source.
It is the generative flip side of the consistency checker's ordered call graph: the same caller-to-callee evidence, turned into a starter diagram instead of a verdict. It never writes: nothing lands in the diagrams directory without an explicit diagrams_create call.
Each sender is the file containing the call site even when another file declares the same caller name. Callee mapping uses case-insensitive declared-identifier equality and the first declaring participant in file order. A callee that no file in the scope declares is reported in unresolved_callees, never attached to an invented participant. Which class owns a method is a type question, and out of scope.
ambiguous_callees lists bare names from emitted messages whose case-insensitive declaration occurs in several distinct participants after same-basename merging. Exact spellings are deduplicated in first emitted order after both caps. Deferred and unresolved calls and calls dropped by caps do not contribute. Competing declarations anywhere in the scanned scope count even when their participant is not emitted. The existing first-declaring-participant choice remains unchanged.
callee_evidence carries one entry per distinct emitted message spelling, in first emitted order after both caps, explaining how that choice was made: candidate_participants lists the distinct logical participants declaring the callee case-insensitively, in registry order after same-basename merging and before the participant cap, cut at candidate_limit (20) with the exact count in candidates_available and candidates_capped flagging the cut. selected_participant is the existing first match, every emitted spelling gets an entry even when only one participant declares it, and deferred, unresolved, and capped calls contribute none. Entry names are logical file basenames, never the sanitized identifiers Mermaid renames participants to. This is static declaration evidence only: it never claims which receiver runs at runtime.
Args:
scope (string, default "."): Relative path under the project root pointing at a file or a directory. Absolute paths and anything resolving outside the project root are refused
format ('puml' | 'mermaid', default 'puml'): Output dialect
max_participants (integer 1-20, default 8): Hard cap on declared participants
max_messages (integer 1-50, default 20): Hard cap on emitted messages
include_call_parentheses (boolean, default false): When true, emitted message labels append '()' in both dialects; structured messages.message values stay bare
Returns: JSON with schema: { "scope": string, // POSIX path as resolved, "." for the project root "format": "puml" | "mermaid", "source": string, // the generated sequence; identical to the text block (message labels carry '()' when include_call_parentheses is true) "participants": string[], // participant names as emitted, in first-conversation order, capped "participants_included": number, // length of "participants" "participants_available": number,// distinct participants in candidate messages, may exceed the cap "participants_capped": boolean, // true when participants were dropped by the cap "participant_limit": number, // the applied cap (max_participants, at most 20) "messages": [ // ordered call sites, one per sequenced call (message stays bare when include_call_parentheses is true) { "from": string, "to": string, "message": string, "line": number, "via_callback": false } ], "messages_included": number, "messages_available": number, // candidate messages, may exceed the cap "messages_capped": boolean, // true when messages were dropped by either cap "message_limit": number, // the applied cap (max_messages, at most 50) "deferred_count": number, // call sites inside callbacks/promises: counted, never sequenced "unresolved_callees": string[], // callees no participant in the scope declares "ambiguous_callees": string[], // emitted bare names with multiple declaring participants; exact spelling and first emitted order "callee_evidence": [ // one entry per distinct emitted message spelling, first emitted order after both caps { "callee": string, "selected_participant": string, "candidate_participants": string[], "candidates_available": number, "candidates_capped": boolean, "candidate_limit": number, "resolution_basis": "case-insensitive-declaration" } ], "files_scanned": number, "truncated": boolean, // true when the 5,000-file scan cap was reached "scan_limit": number, // 5,000 "scan_warning": string | null, // human-readable warning when truncated, otherwise null "confidence": "heuristic", "heuristic_warning": string, // what static call order can and cannot tell you "written": false // always false; save with diagrams_create }
Every cap reports itself in-band, so a truncated or capped result is never silent.
Examples:
Use when: "Show the call flow between the checkout and payment modules" -> scope="src/checkout"
Use when: "Draft a Mermaid sequence for this service layer" -> scope="src/services", format="mermaid"
Don't use when: You need runtime ordering, async semantics, or which class a method belongs to (out of scope; deferred and unresolved calls are reported instead)
Don't use when: You want a class diagram (use diagrams_generate) or a hand-written skeleton (write the source directly)
Error Handling:
Returns "Error: Refused to resolve scope outside the project root: ''" when scope is absolute or resolves outside the project root; no file is read
A scope with no code files is not an error: participants and messages are empty, and the emitted source is a valid empty diagram
Emitted source always passes the same syntax gate diagrams_create enforces; an emission that cannot is reported as an unexpected internal error
Unexpected internal failures return a generic "Error: Unexpected internal error ..." with isError:true and are logged to stderr without source, paths, or secrets
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| scope | No | Relative path under the project root pointing at a file or a directory to read (default: '.', the whole project root). Absolute paths and anything that resolves outside the project root are refused. | . |
| format | No | Output dialect for the generated sequence diagram (default: 'puml'). | puml |
| max_messages | No | Hard cap on emitted messages, an integer between 1 and 50 (default: 20). The applied cap is reported as message_limit; messages past it, or to a participant the participant cap removed, are counted in messages_available and flagged by messages_capped. | |
| max_participants | No | Hard cap on declared participants, an integer between 1 and 20 (default: 8). The applied cap is reported as participant_limit; anything past it is counted in participants_available and flagged by participants_capped. | |
| include_call_parentheses | No | When true, emitted message labels append '()' in both dialects (default: false). Structured messages.message values stay bare. |