Skip to content

feat(cli): add 'dimos graph' subcommand#2213

Open
jeff-hykin wants to merge 56 commits into
mainfrom
jeff/feat/dimos-graph
Open

feat(cli): add 'dimos graph' subcommand#2213
jeff-hykin wants to merge 56 commits into
mainfrom
jeff/feat/dimos-graph

Conversation

@jeff-hykin

@jeff-hykin jeff-hykin commented May 21, 2026

Copy link
Copy Markdown
Member

Adds dimos graph <python_file> to render Blueprint flowchart diagrams as interactive Mermaid in the browser, designed for debugging.

Example

# Open an interactive Mermaid view in the browser
dimos graph dimos/manipulation/blueprints.py

# Print Mermaid markdown to stdout instead
dimos graph dimos/manipulation/blueprints.py --markdown
Screenshot 2026-05-30 at 5 54 06 PM

Options

  • --no-disconnected — hide disconnected streams
  • --markdown — print Mermaid markdown to stdout instead of serving
  • --port — pick HTTP port (default: random)

@codecov

codecov Bot commented May 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.02870% with 95 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
dimos/utils/cli/graph.py 64.24% 51 Missing and 8 partials ⚠️
dimos/core/introspection/mermaid.py 84.82% 7 Missing and 15 partials ⚠️
dimos/robot/cli/dimos.py 18.18% 9 Missing ⚠️
dimos/utils/cli/test_graph.py 94.04% 3 Missing and 2 partials ⚠️
@@            Coverage Diff             @@
##             main    #2213      +/-   ##
==========================================
- Coverage   70.09%   70.02%   -0.08%     
==========================================
  Files         838      843       +5     
  Lines       74337    74801     +464     
  Branches     6667     6732      +65     
==========================================
+ Hits        52110    52381     +271     
- Misses      20552    20691     +139     
- Partials     1675     1729      +54     
Flag Coverage Δ
OS-ubuntu-24.04-arm 63.93% <79.02%> (+0.09%) ⬆️
OS-ubuntu-latest 64.76% <79.02%> (+0.09%) ⬆️
Py-3.10 64.75% <79.02%> (+0.09%) ⬆️
Py-3.11 64.75% <79.02%> (+0.08%) ⬆️
Py-3.12 64.75% <79.02%> (+0.09%) ⬆️
Py-3.13 64.75% <79.02%> (+0.08%) ⬆️
Py-3.14 64.76% <79.02%> (+0.09%) ⬆️
Py-3.14t 64.76% <79.02%> (+0.09%) ⬆️
SelfHosted-Large 30.35% <67.83%> (+<0.01%) ⬆️
SelfHosted-Linux 38.27% <67.83%> (+0.06%) ⬆️
SelfHosted-macOS 37.00% <67.83%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dimos/utils/cli/test_graph_blueprints.py 100.00% <100.00%> (ø)
dimos/utils/cli/test_graph.py 94.04% <94.04%> (ø)
dimos/robot/cli/dimos.py 62.06% <18.18%> (-1.17%) ⬇️
dimos/core/introspection/mermaid.py 84.82% <84.82%> (ø)
dimos/utils/cli/graph.py 64.24% <64.24%> (ø)

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jeff-hykin jeff-hykin marked this pull request as ready for review May 21, 2026 19:35
@jeff-hykin jeff-hykin enabled auto-merge (squash) May 21, 2026 19:35
@greptile-apps

greptile-apps Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces dimos graph <python_file> — a developer debugging tool that loads Blueprint instances from a Python file and renders them as interactive Mermaid flowcharts in the browser, with optional --markdown and --html output modes.

  • dimos/core/introspection/mermaid.py generates Mermaid graph LR diagrams from Blueprint objects, including remapping support, disconnected-stream rendering, and per-module/edge color assignment from configurable palettes.
  • dimos/utils/cli/graph.py handles file loading, conflict and typo detection, Jinja2 HTML rendering, and a single-shot HTTP server; graph.html.jinja provides the interactive viewer with tab switching, pan/zoom, and overlay warnings.
  • dimos/robot/cli/dimos.py wires the new graph subcommand into the Typer CLI with lazy imports so mermaid.js is not read at startup.

Confidence Score: 5/5

Safe to merge — this is an additive developer tool with no changes to core runtime paths, and all previously discussed concerns were either resolved or confirmed intentional.

The feature is self-contained: it adds a new CLI subcommand behind a lazy import, a standalone Mermaid renderer, and a single-shot HTTP server that binds to loopback. The logic that loads and inspects Blueprint objects is read-only with respect to the rest of the system. No existing behavior is modified.

dimos/core/introspection/mermaid.py (list-vs-set in disconnected detection) and dimos/utils/cli/graph.html.jinja (window listener accumulation per tab) have minor improvements worth a follow-up but nothing blocking.

Important Files Changed

Filename Overview
dimos/core/introspection/mermaid.py New Mermaid renderer — correct flow with remapping, color assignment, and disconnected-stream handling; active_keys uses a list instead of a set, causing O(n²) membership checks in the disconnected detection path.
dimos/utils/cli/graph.py Blueprint loader, HTML builder, and server. Previous concerns (stdout pollution, interface binding) are resolved; server correctly serves favicon separately and binds to 127.0.0.1.
dimos/utils/cli/graph.html.jinja Interactive Mermaid viewer with tabs, pan/zoom, and warning overlays; zoom button listeners are correctly placed outside setupViewport, but window-level mousemove/mouseup listeners still accumulate once per tab.
dimos/robot/cli/dimos.py Adds graph CLI subcommand with --markdown, --html, --port, and --theme options; uses lazy import to avoid loading mermaid.js at startup.
dimos/utils/cli/test_graph.py Snapshot test for HTML output and HTTP round-trip; silently creates snapshot on first run without failing, which can mask regressions if snapshot is deleted.
dimos/utils/cli/test_graph_blueprints.py Blueprint fixtures covering connected streams, intentional typo (color_img vs color_image), and multiple-producer conflict; good breadth for testing the renderer.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CLI as dimos graph CLI
    participant Loader as _load_blueprints
    participant Renderer as render_mermaid
    participant Builder as _build_html
    participant Jinja as Jinja2 Template
    participant Server as HTTPServer (127.0.0.1)
    participant Browser as Browser

    CLI->>Loader: load python_file
    Loader->>Loader: spec_from_file_location("_render_target")
    Loader->>Loader: collect Blueprint globals
    Loader-->>CLI: [(name, Blueprint), ...]

    CLI->>Builder: _build_html(blueprints)
    loop per Blueprint
        Builder->>Renderer: render_mermaid(bp, theme)
        Renderer-->>Builder: mermaid_code, label_colors, disconnected, node_colors
        Builder->>Builder: detect conflicts and typos
    end
    Builder->>Jinja: render template with all data + mermaid.js inline
    Jinja-->>Builder: HTML string

    alt --markdown
        CLI->>CLI: print Mermaid blocks to stdout
    else --html
        CLI->>CLI: write HTML to file
    else serve (default)
        CLI->>Server: bind random port
        CLI->>Browser: webbrowser.open(url)
        Browser->>Server: GET /favicon.ico
        Server-->>Browser: SVG favicon
        Browser->>Server: GET /
        Server-->>Browser: full HTML page
        Server->>CLI: handle_request() returns (exit)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CLI as dimos graph CLI
    participant Loader as _load_blueprints
    participant Renderer as render_mermaid
    participant Builder as _build_html
    participant Jinja as Jinja2 Template
    participant Server as HTTPServer (127.0.0.1)
    participant Browser as Browser

    CLI->>Loader: load python_file
    Loader->>Loader: spec_from_file_location("_render_target")
    Loader->>Loader: collect Blueprint globals
    Loader-->>CLI: [(name, Blueprint), ...]

    CLI->>Builder: _build_html(blueprints)
    loop per Blueprint
        Builder->>Renderer: render_mermaid(bp, theme)
        Renderer-->>Builder: mermaid_code, label_colors, disconnected, node_colors
        Builder->>Builder: detect conflicts and typos
    end
    Builder->>Jinja: render template with all data + mermaid.js inline
    Jinja-->>Builder: HTML string

    alt --markdown
        CLI->>CLI: print Mermaid blocks to stdout
    else --html
        CLI->>CLI: write HTML to file
    else serve (default)
        CLI->>Server: bind random port
        CLI->>Browser: webbrowser.open(url)
        Browser->>Server: GET /favicon.ico
        Server-->>Browser: SVG favicon
        Browser->>Server: GET /
        Server-->>Browser: full HTML page
        Server->>CLI: handle_request() returns (exit)
    end
Loading

Reviews (47): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment thread dimos/utils/cli/graph.py Outdated
Comment thread dimos/utils/cli/graph.py
Comment thread dimos/utils/cli/graph.py Outdated
Comment thread dimos/utils/cli/graph.py Outdated
Non-root requests (e.g. /favicon.ico) now return 204 instead of
terminating the single-request server with the HTML payload.
Comment thread dimos/utils/cli/graph.py Outdated
Route the diagnostic 'Found N blueprint(s)' message to stderr so piping
'--markdown' output to a file doesn't get the message injected into the
markdown stream.
jeff-hykin added a commit that referenced this pull request May 22, 2026
Records the 5 greptile review comments on jeff/feat/dimos-graph:
- 3283875847, 3283875929, 3284014771: already addressed in upstream
  commits 482d7ad, f87845e, ddb6856
- 3283876031: fixed in autofix commit f62f2f5 (_mermaid_id)
- 3283875688: skipped (JS refactor in embedded template, exceeds easy
  threshold; symptom is mild)
@jeff-hykin jeff-hykin force-pushed the jeff/feat/dimos-graph branch from 6c2ea2c to f87845e Compare May 22, 2026 08:17
Comment thread dimos/utils/cli/graph.py
@leshy

leshy commented May 22, 2026

Copy link
Copy Markdown
Member

we already have a very detailed renderer for dimos blueprints used in our documentation, as well as rerun blueprint graph view tab

https://github.com/dimensionalOS/dimos/blob/main/docs/usage/modules.md

is there a reason to introduce a new one?

from dimos.core.introspection.svg import to_svg
from dimos.robot.unitree_webrtc.unitree_go2_blueprints import agentic

to_svg(agentic, "assets/go2_agentic.svg")

I don't super mind this if someone prefers to above, but can add to core.introspection.mermaid perhaps

jeff-hykin added a commit that referenced this pull request May 22, 2026
…, leshy)

Adds an entry for greptile P1 review #3286995045 (relative-imports fix
above), records leshy's design question about merging this renderer with
core.introspection.svg as a discussion-only entry, and standardizes the
existing _mermaid_id entry on a full 40-char commit SHA.
Comment thread dimos/utils/cli/graph.py Outdated
mustafab0
mustafab0 previously approved these changes May 23, 2026
jeff-hykin added a commit that referenced this pull request May 23, 2026
Record pr_responses.yaml entry for mustafab0's 2026-05-23 review comment on
PR #2213 (#3292493576) suggesting the 242-line embedded HTML f-string in
_build_html become a separate graph.html file. Marked skipped — the choice
of templating mechanism (str.format vs string.Template vs marker .replace
vs Jinja2) is an architectural call that needs Jeff's input, and there are
no unit tests covering _build_html so a silent rendering regression would
not be caught by CI.
Stream names with characters like [ ] ( ) . would produce invalid
Mermaid syntax and break diagram rendering.
@jeff-hykin

jeff-hykin commented May 30, 2026

Copy link
Copy Markdown
Member Author

we already have a very detailed renderer for dimos blueprints used in our documentation, as well as rerun blueprint graph view tab

@leshy

Yeah I know. For context, I never planned to PR this, I've been using it since February - Mustafa and Andrew just saw me using it and asked if I could add it to dimos.

I don't find the existing tools useful for debugging blueprint streams, so I end up using this a lot.

Main differences:

  • Doesn't hide anything (need to see disconnected edges and show all modules for debugging)
  • Easy one-off invoke; no blueprint/rerun launching, no writing python code to import a blueprint, just cli command pointed at a python file
  • Lighter weight (e.g. no graphviz)
  • Different layout (each node owns its output)

…nt.mermaid

Move render_mermaid, themes, and color logic out of the CLI module into
a reusable location. Add ocean/ember/forest/light themes with per-theme
background colors, wire --theme through the CLI, and fix stream
resolution for files using `from __future__ import annotations`.
…ering

Snapshot test builds HTML from a complex blueprint with dangling streams,
serves it over HTTP, and compares to a cached file. Snapshot auto-updates
on mismatch so the next run passes.
@github-actions github-actions Bot removed the ready-to-merge Required CI checks have passed on this PR label Jun 11, 2026
Comment thread dimos/utils/cli/graph.py
Comment on lines +141 to +146
producers: dict[str, list[str]] = {}
for atom in bp.blueprints:
for stream in atom.streams:
if stream.direction == "out":
topic = f"{stream.name}:{stream.type.__name__}"
producers.setdefault(topic, []).append(atom.module.__name__)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Conflict detection ignores remapping_map, diverging from the rendered graph

render_mermaid applies blueprint_set.remapping_map.get((atom.module, stream.name), stream.name) before computing stream keys, so the graph shows remapped names. This conflict-detection block uses the raw stream.name, so when any remapping is in use, the "stream fighting" warning operates on a different view of the blueprint than what is drawn. A producer whose stream is remapped to name X will appear under its original name here but under X in the graph — causing false-positive conflicts (two modules mapped to the same raw name that differ after remapping) and false-negatives (two modules both mapping to the same final name that started with different raw names).

Suggested change
producers: dict[str, list[str]] = {}
for atom in bp.blueprints:
for stream in atom.streams:
if stream.direction == "out":
topic = f"{stream.name}:{stream.type.__name__}"
producers.setdefault(topic, []).append(atom.module.__name__)
producers: dict[str, list[str]] = {}
for atom in bp.blueprints:
for stream in atom.streams:
if stream.direction == "out":
remapped = bp.remapping_map.get((atom.module, stream.name), stream.name)
if not isinstance(remapped, str):
continue
topic = f"{remapped}:{stream.type.__name__}"
producers.setdefault(topic, []).append(atom.module.__name__)

@github-actions github-actions Bot added the ready-to-merge Required CI checks have passed on this PR label Jun 11, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 11, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 11, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 11, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 11, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 12, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 12, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 15, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 16, 2026
@github-actions github-actions Bot added ready-to-merge Required CI checks have passed on this PR and removed ready-to-merge Required CI checks have passed on this PR labels Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Required CI checks have passed on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants