Skip to content

Latest commit

 

History

257 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@pipelex/mthds-ui

Interactive graph visualization for MTHDS method pipelines. Renders execution graphs from GraphSpec data — the canonical format produced by Pipelex when tracing pipeline execution.

Core graph logic (builders, layout, analysis) is pure TypeScript with no React dependency. The React layer provides a drop-in GraphViewer component powered by ReactFlow.

Install

npm install @pipelex/mthds-ui

Released versions are listed on the npm page and the GitHub releases page.

If you render the React components, one setup step follows the install: the form controls that RunPanel and the graph's detail panel render need a stylesheet that your app loads itself. See Styling the form controls.

Peer dependencies

Dependency Required Used by
react, react-dom no React layer (graph/react, form/react)
shiki no Syntax highlighting (shiki)

Bundled dependencies

Dependency License Used by
elkjs EPL-2.0 Graph layout engine
@xyflow/react MIT Graph rendering (graph/react)
@pipelex/mthds-form MIT Run form panel + result view (form/react, graph/react)

elkjs (Eclipse Layout Kernel) is licensed under the Eclipse Public License 2.0. See NOTICE for details.

Quick start (React)

import { GraphViewer } from "@pipelex/mthds-ui/graph/react";

function MethodGraph({ graphspec }) {
  return <GraphViewer graphspec={graphspec} />;
}

That's it. GraphViewer handles layout, styling, CSS variables, and all ReactFlow internals. All props except graphspec are optional with sensible defaults. The one exception to "styling" is the detail panel's data view, which shows a result through the form kernel's controls; those are styled by your app, as Styling the form controls describes.

Next.js (App Router)

ReactFlow accesses browser globals at module-evaluation time, so it cannot be server-side rendered. Use next/dynamic with ssr: false:

"use client";

import dynamic from "next/dynamic";
import type { GraphViewerProps } from "@pipelex/mthds-ui/graph/react";
import React from "react";

const GraphViewer = dynamic(
  () =>
    import("@pipelex/mthds-ui/graph/react").then((mod) => ({
      default: mod.GraphViewer,
    })),
  { ssr: false },
) as React.ComponentType<GraphViewerProps>;

export function MyGraph({ graphspec }) {
  return <GraphViewer graphspec={graphspec} />;
}

GraphViewer props

Prop Type Default Description
graphspec GraphSpec | null — Graph data (nodes + edges)
config GraphConfig DEFAULT_GRAPH_CONFIG Layout and visual configuration
direction GraphDirection "LR" Layout direction: TB, LR, RL, BT
showControllers boolean false Show controller group outlines
onNavigateToPipe (pipeCode: string, status?: PipeStatus) => void — Callback when a pipe node is clicked
onReactFlowInit (instance: AppRFInstance) => void — Access the underlying ReactFlow instance

Container sizing

The graph container uses position: absolute; inset: 0 to fill its parent. Make sure the parent element has position: relative and a defined height (e.g. h-full, flex-1, or an explicit height).

GraphSpec

GraphSpec is the data format that describes a pipeline execution graph. It's generated by Pipelex when running or validating MTHDS method bundles.

Generating a GraphSpec

# From a .mthds bundle file
pipelex-agent validate bundle my-method.mthds --view

# The output JSON contains a graphspec field

Or programmatically via the Pipelex Python SDK:

from pipelex import Pipelex

px = Pipelex()
result = px.validate_bundle("my-method.mthds", view=True)
graphspec = result.graphspec  # dict ready for JSON serialization

Static GraphSpec from .mthds

For authored-structure previews that should not run Pipelex, use the pure TypeScript static builder:

import { buildStaticGraphSpecFromToml } from "@pipelex/mthds-ui/static-graph";

const { spec, diagnostics } = buildStaticGraphSpecFromToml(tomlText);

The returned spec has meta: { format: "mthds", mode: "static" } and can be passed directly to GraphViewer. Static graphs hide runtime status/timing chrome and are best-effort: diagnostics report incomplete or unresolved authored content without preventing rendering.

See docs/static-graph.md for the full contract.

Structure

interface GraphSpec {
  nodes: GraphSpecNode[];
  edges: GraphSpecEdge[];
  meta: {
    format: "mthds";
    mode?: "dry" | "live" | "static";
  };
}

interface GraphSpecNode {
  id: string;
  pipe_code?: string; // e.g. "analyze_match"
  pipe_type?: string; // e.g. "PipeLLM", "PipeSequence", "PipeExtract"
  status?: string; // "succeeded", "failed", "running", "scheduled", "skipped"
  io?: {
    inputs?: IOItem[];
    outputs?: IOItem[];
  };
}

interface GraphSpecEdge {
  id?: string;
  source: string; // Source node ID
  target: string; // Target node ID
  kind: GraphSpecEdgeKind; // "data", "contains", "batch_item", etc.
  label?: string;
}

Node types

Nodes represent pipes (operations) and stuffs (data artifacts) in the pipeline:

  • Pipe nodes — operations like PipeLLM, PipeSequence, PipeExtract, PipeSearch
  • Stuff nodes — data flowing between pipes, typed by concepts (e.g. CandidateProfile, Document)

Edge kinds

Kind Description
data Data flow — stuff produced by one pipe, consumed by another
contains Containment — a controller pipe wraps child pipes
batch_item Batch processing — items fanned out from a collection
batch_aggregate Batch aggregation — items collected back
parallel_combine Parallel results combined

Example GraphSpec (minimal)

{
  "nodes": [
    {
      "id": "extract_text",
      "pipe_code": "extract_text",
      "pipe_type": "PipeExtract",
      "io": {
        "inputs": [{ "digest": "input_doc", "name": "document", "concept": "Document" }],
        "outputs": [{ "digest": "pages", "name": "pages", "concept": "TextPages" }]
      }
    },
    {
      "id": "summarize",
      "pipe_code": "summarize",
      "pipe_type": "PipeLLM",
      "io": {
        "inputs": [{ "digest": "pages", "name": "pages", "concept": "TextPages" }],
        "outputs": [{ "digest": "summary", "name": "summary", "concept": "Summary" }]
      }
    }
  ],
  "edges": []
}

Full specification: docs.pipelex.com — Execution Graph Tracing

Configuration

GraphConfig

Controls layout and visual behavior. All fields are optional — DEFAULT_GRAPH_CONFIG provides sensible defaults.

import { DEFAULT_GRAPH_CONFIG } from "@pipelex/mthds-ui";

// Override specific settings
const myConfig = {
  ...DEFAULT_GRAPH_CONFIG,
  direction: "LR",
  nodesep: 80,
  ranksep: 50,
};
Field Type Default Description
direction GraphDirection "LR" Layout direction
showControllers boolean false Show controller group boxes
nodesep number 50 Horizontal spacing between nodes
ranksep number 100 Vertical spacing between ranks
edgeType EdgeType "bezier" Edge curve style
initialZoom number | null null Override fit-view zoom (null = auto)
panToTop boolean true Pan viewport to top after layout
paletteColors Record<string, string> (see below) CSS variable overrides for theming

Theming with palette colors

GraphViewer applies CSS custom properties from paletteColors on mount. Override colors by passing a custom config:

<GraphViewer
  graphspec={graphspec}
  config={{
    ...DEFAULT_GRAPH_CONFIG,
    paletteColors: {
      ...DEFAULT_GRAPH_CONFIG.paletteColors,
      "--color-pipe": "#e06c75",
      "--color-stuff": "#61afef",
      "--color-bg": "#282c34",
    },
  }}
/>

Default palette colors include:

Variable Purpose
--color-pipe Pipe node border/accent
--color-pipe-bg Pipe node background
--color-stuff Stuff node border/accent
--color-stuff-bg Stuff node background
--color-edge Edge line color
--color-batch-item Batch item edge color
--color-batch-aggregate Batch aggregate edge color
--color-bg Graph background
--color-bg-dots Background dot pattern
--font-sans Node font family
--font-mono Code/controller font

See graphConfig.ts for the full default palette.

Entry points

Import path Content
@pipelex/mthds-ui Pure-TS graph logic — types, builders, layout, controllers, config
@pipelex/mthds-ui/graph/react React components — GraphViewer, label helpers, type converters
@pipelex/mthds-ui/form The form kernel's React-free surface, re-exported
@pipelex/mthds-ui/form/react RunPanel — a pipe's input form — and the kernel's controls
@pipelex/mthds-ui/shiki MTHDS syntax highlighting with shiki
@pipelex/mthds-ui/tailwind.css Where the kernel's classes are, for a Tailwind 4 host
@pipelex/mthds-ui/form-kernel.css The kernel's prebuilt stylesheet, for a host without Tailwind

Pure TypeScript usage

Use the graph logic without React — build nodes/edges, run layout, and feed the result to your own renderer:

import {
  buildGraph,
  getLayoutedElements,
  applyControllers,
  DEFAULT_GRAPH_CONFIG,
} from "@pipelex/mthds-ui";

// Build graph data from a GraphSpec
const { graphData, analysis } = buildGraph(graphspec, "bezier");

// Apply ELK layout
const { nodes, edges } = getLayoutedElements(graphData.nodes, graphData.edges, "TB");

// Optionally wrap nodes in controller groups
const final = applyControllers(nodes, edges, graphspec, analysis, true);

Run form panel

RunPanel renders a pipe's input form from its IO contract: the fields, the readiness verdict on the Run button, and the wire-ready payload a run receives.

The form kernel ships as a dependency of this package, so there is nothing extra to install. Reach it through @pipelex/mthds-ui/form rather than importing it directly — a second declaration puts a second copy in your tree, and the kernel ships React contexts, so a provider you mount above the panel would stop resolving inside it.

import { getPipeIOContract } from "@pipelex/mthds-ui/form";
import { RunPanel } from "@pipelex/mthds-ui/form/react";
import "@pipelex/mthds-ui/form/react/RunPanel.css";

// Note the argument order — the kernel's README currently shows it wrong.
const contract = getPipeIOContract(pipeIoContracts, domain, pipeCode);

<RunPanel
  contract={contract}
  values={values}
  onValuesChange={setValues}
  onRun={(apiInputs) => execute(pipeCode, apiInputs)}
  title={pipeCode}
  theme="dark"
/>;

onRun fires only once the kernel's run gate passes. This library renders and never executes: no API client, no upload, no storage resolution — the host injects all three.

Styling the form controls

The controls inside RunPanel, and inside the graph's detail panel, are the form kernel's, styled with Tailwind classes over the shadcn tokens. No entry of this package imports a stylesheet for them: your app loads one, and which one depends on whether it runs Tailwind. Load one of the two, never both.

A host with Tailwind 4 follows the kernel's documented setup, A host that runs Tailwind, and imports this package's tailwind.css in place of that setup's @source line:

@import "tailwindcss";
@import "tw-animate-css";
@import "@pipelex/mthds-ui/tailwind.css";

@custom-variant dark (&:is(.dark *));

/* …and the @theme inline mapping of the shadcn tokens the kernel's setup lists. */

tailwind.css points Tailwind at the copy of the kernel this package depends on, wherever pnpm or npm put it beside or under this package, so you write no path into node_modules and do not declare @pipelex/mthds-form yourself. One layout escapes it: when your tree holds two versions of this package, npm can nest one below a kernel hoisted further up, and the controls then render unstyled without a warning; docs/run-form-panel.md gives the one-line remedy. The rest of the kernel's setup stays yours: tw-animate-css animates the select popover and the tooltip, without the token mapping a class such as bg-background compiles to nothing, and the @custom-variant line, which a shadcn/ui codebase already has, keys dark: to the .dark class the kernel follows rather than to the operating system's preference.

A host without Tailwind imports the prebuilt stylesheet once, from its entry:

import "@pipelex/mthds-ui/form-kernel.css";

It carries Tailwind's preflight, which resets the browser's default styles across your whole page (heading sizes, list markers, margins), and a cascade layer that lets every rule you write yourself win a tie against it.

Tailwind 3 hosts and Tailwind 4 hosts that configure a prefix are not supported: their builds cannot generate the kernel's unprefixed Tailwind 4 classes, and the prebuilt sheet cannot sit in their cascade, because its preflight must rank below their base styles while its utilities must rank above them.

Either way, the shadcn token values are yours to supply, and each must be a complete colour — hsl(240 10% 3.9%), #0a0711, oklch(…) — never a bare HSL triplet. Since kernel 0.8.0 the sheet emits background-color: var(--background) rather than hsl(var(--background)), so a triplet computes to something that is not a colour and the browser discards the declaration instead of overriding with it: green build, token inspectable, style silently absent.

Full contract, why this package stopped loading the kernel's stylesheet itself, the .dark bridge and the mthds-run-panel token hook: docs/run-form-panel.md.

Shiki integration

Syntax-highlight MTHDS code with the bundled grammar and themes:

import { highlightMthds, getAvailableThemes } from "@pipelex/mthds-ui/shiki";

const html = await highlightMthds(mthdsSource, "pipelex-dark");

Development

npm install
make check    # lint + format-check + typecheck
make test     # unit tests (vitest)
make build    # build to dist/

License

MIT — see LICENSE.

This project depends on elkjs which is licensed under EPL-2.0. See NOTICE for third-party license details.

About

React components and utilities for visualizing and interacting with MTHDS methods — graph viewer, layout engine, and building blocks for method-aware web applications.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages