Skip to main content
Glama

flowlens

See every user flow of your app, how well your E2E tests cover it, and the Playwright evidence behind it. All in one local viewer.

CI License: MIT Node >= 20 MCP plugin

English · Español

Galaxy view of a synthetic project: 67 flows, 667 nodes, 749 edges. Bigger stars are the nodes shared by more flows.


flowlens maps a repository's user flows (UI action → API call → database → decision), shows which of them your end-to-end tests actually cover, and embeds the Playwright video, trace and steps next to the graph. It also ships an MCP plugin, so a local AI agent (opencode, Claude Code, ...) can map the flows, stand up a local test environment and write the tests that are missing.

flowlens is generic and non-invasive: it stores nothing about the repository it analyzes. Config, flows, labels, environment and build output live outside the target repo, in a data dir you control (default ~/.flowlens/projects/<project>/). Nothing lands in your commits.

Highlights

  • Flow graph that scales: hundreds of nodes stay readable. Friendly names, coverage colors, coverage filter, search, shared nodes rendered once.

  • Four layouts: Graphify (force graph), Galaxy (constellation with starfield), Org chart (top-down tree) and 3D (interactive Three.js).

  • Evidence per flow: video, Playwright trace viewer, step list and a Mermaid sequence diagram, synced with the graph while the test plays.

  • Coverage from facts: derived from your Playwright results, not from guesses.

  • Local test environment declared once in env.json and driven with Docker.

  • MCP plugin (flowlens mcp) that exposes the whole pipeline as tools for a local agent, plus an Implement test panel that launches your agent to write the missing spec.

  • English and Spanish UI, light / dark / system themes, works fully offline.

  • Plain Node.js, a single tiny runtime dependency (cross-spawn).

Related MCP server: Assert

All big-graph screenshots come from the synthetic project in examples/large (no real project data); you can regenerate and explore it yourself, see below.

Quick start

Requirements: Node.js >= 20. Docker is optional (only for flowlens env). A local agent (opencode, Claude Code, ...) is needed only for the AI features.

1. Try it in 30 seconds

git clone https://github.com/jlaguna553/flowlens
cd flowlens
npm install
npm run demo          # builds and serves the 667-node synthetic project

Open http://127.0.0.1:8017, then switch between Graphify / Galaxy / Org chart / 3D in the top-left corner. (The warnings about a missing Playwright report are expected: the demo has no test run.)

2. Point it at your own repository

npm install -g github:jlaguna553/flowlens      # provides the `flowlens` command
flowlens init --suite /path/to/target-repo --project my-app
flowlens serve --project my-app

init scaffolds the project data, scans the repo and launches your local agent to map the flows automatically. The viewer shows the result. No installation inside the target repo.

flowlens is not published on the npm registry yet, so install it from GitHub. You can also run it without installing: npx -y github:jlaguna553/flowlens init --suite ... --project .... The binary is always called flowlens.

How it works

 target repo ──scan──▶ agent maps flows ──▶ flows.json ──┐
                                                         ├──▶ build ──▶ graph.json + viewer
 Playwright run ──flowlens reporter──▶ run.json ─────────┘          (coverage, video, trace)

A flow is a small graph of nodes:

Kind

Meaning

interaction

a user action in the UI

backend

an API call / endpoint

db

a database step

decision

a branch or outcome

Each flow has a coverage state: covered, partial or uncovered. Coverage is derived from the Playwright results at build time.

The agent workflow (3 capabilities)

  1. Map the flows. init (or flowlens map later) lets the agent read specs, frontend routes and backend controllers, write a draft, and flowlens validates and persists it.

  2. Stand up the local test env. Declare it once in env.json; the agent previews with flowlens_env_up { dryRun: true }, then brings it up with Docker, waits for health checks and runs seeds.

  3. Implement the missing tests. For every uncovered / partial flow the agent gets a task (suggested spec, reporter command, acceptance criteria), writes the spec, runs it and ingests the results.

The full reference (every MCP tool, payloads, env block, agent block, endpoints) is in docs/agent-plugin.md (Español).

Configure it in another repo

init writes everything outside the target repo:

~/.flowlens/projects/my-app/
  flowlens.config.json   suite path + flows pointer (+ optional agent/env blocks)
  flows.json             the flow graph the agent authors
  labels.json            optional friendly-name patterns for backend/db labels
  env.json               optional local E2E environment declaration
  out/                   built graph.json + viewer (index.html, vendor, trace assets)
  env/                   generated compose override, logs, notes, state

init flag

Meaning

--suite <path>

Required. Target repo or its E2E suite root.

--project <name>

Project name. Defaults to the suite directory name.

--data-dir <dir>

Data dir. Defaults to ~/.flowlens/projects or FLOWLENS_DATA_DIR.

--agent opencode|claude

Agent used to map flows. Defaults to the agent that launched init, else the first installed one.

--model <provider/model>

Preferred AI model. flowlens probes it and falls back to another reachable model.

--tests-dir <dir>

Project-relative folder for generated specs (default tests).

--isolated-tests

Generate specs under <dataDir>/<project>/tests instead of the target repo.

--no-map

Skip the automatic flow mapping.

--timeout <ms>

Kill the mapping agent after this many milliseconds.

--force

Overwrite an existing config / flows / AGENTS skeleton.

Every other command accepts --project <name> or --config <path>, plus --data-dir <dir>. With neither, flowlens looks for flowlens.config.json in the current directory, then for <dataDir>/<cwd-name>/flowlens.config.json.

Commands

Command

What it does

flowlens init

Scaffold a project and map its flows with your agent.

flowlens map [--dry-run] [--agent ...] [--model ...]

(Re)map the flows. --dry-run prints the prompt only.

flowlens write-flows --file <draft.json>

Validate a draft against schemaVersion 1 and persist it.

flowlens build [--run <path>] [--report <dir>] [--out <dir>] [--lang en|es]

Build graph.json and the viewer. --lang picks the language of generated friendly names (default en; also "language" in the config).

flowlens serve [--port 8017]

Serve the viewer.

flowlens env up|status|down [--dry-run]

Manage the local E2E environment.

flowlens mcp

Start the MCP server over stdio.

flowlens reporter-path

Print the path of the bundled Playwright reporter.

Wire the MCP plugin

flowlens speaks MCP over stdio. Add it to your agent:

opencode (opencode.json)

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "flowlens": {
      "type": "local",
      "enabled": true,
      "command": ["npx", "-y", "github:jlaguna553/flowlens", "mcp", "--project", "my-app"]
    }
  }
}

Claude Desktop (claude_desktop_config.json) and Claude Code (.mcp.json)

{
  "mcpServers": {
    "flowlens": {
      "command": "npx",
      "args": ["-y", "github:jlaguna553/flowlens", "mcp", "--project", "my-app"]
    }
  }
}

If you installed it globally you can use "command": "flowlens" with "args": ["mcp", "--project", "my-app"]. Add --config <path> or --data-dir <dir> to keep project data elsewhere.

Tool

Inputs

flowlens_status

none

flowlens_build

none

flowlens_serve

{ port?, host? } (default port 8020)

flowlens_scan

{ repoPath }

flowlens_scaffold_flows

{ repoPath, suite?, project? }

flowlens_write_flows

{ flows, configPath? }

flowlens_coverage

none

flowlens_uncovered_tasks

none

flowlens_implement_test

{ flowId, dryRun? }

flowlens_ingest_results

{ runPath?, reportDir?, configPath? }

flowlens_env_up

{ dryRun?, configPath?, envPath?, port? }

flowlens_env_down

{ configPath?, envPath? }

flowlens_env_status

{ configPath?, envPath? }

flowlens_scan, flowlens_scaffold_flows and the repoPath they receive are read-only. All writes go under the project data dir. The one exception is flowlens_implement_test, which launches your configured local agent in the suite directory, so that agent may write the suggested spec inside the target repo (that is the point).

Evidence: the reporter

Coverage and evidence come from Playwright runs. Point Playwright at the bundled reporter and a run JSON inside the data dir:

cd /path/to/target-repo/e2e
REPORTER=$(flowlens reporter-path)
FLOWLENS_RUN_OUTPUT=~/.flowlens/projects/my-app/out/run.json \
  npx playwright test \
  --reporter="$REPORTER" \
  --output=~/.flowlens/projects/my-app/out/test-results

flowlens build --project my-app --run ~/.flowlens/projects/my-app/out/run.json

The reporter refuses to run unless FLOWLENS_RUN_OUTPUT is set. Enable trace: 'on' and video: 'on' in your Playwright config to get the Trace and Video tabs. With no --run and no playwright-report/, build emits the flow graph without test results.

The viewer

flowlens serve --project my-app --port 8017
  • Graph colored by flow and by node kind (Front, Back, BD, Decision) in four layouts: Graphify, Galaxy, Org chart and 3D. In Galaxy, labels appear as you zoom in so large graphs stay readable.

  • Collapsible, resizable sections: Node Info, Evidence, Kinds, Flows. The state is remembered.

  • Node Info: label, endpoint, kind, coverage, payload, response, neighbors and type-specific details (frontend file/line/component/selector, backend source and payload example, database table and fields). Shared nodes list every flow that uses them.

  • Flows legend with a coverage filter (All / Covered / Partial / Uncovered). Hover a flow for its Mermaid sequence preview; click it to zoom and highlight the flow (Clear resets focus).

  • Hover a node for a compact info card; click a node to focus its flow and jump the video to that step. Hover an edge for a large sequence preview.

  • Playback bar with speed from 0.1x to 2x; a cursor animates along the flow while the test plays.

  • Evidence tabs: Video, Trace, Steps, Sequence (Mermaid, zoom and full screen) and Implement (spec, command, acceptance criteria and the Run agent button with a live log).

  • Search across nodes, light / dark / system themes, English / Spanish.

flows.json (schemaVersion 1)

{
  "schemaVersion": 1,
  "project": "my-app",
  "suite": { "root": "e2e", "projectName": "chromium" },
  "flows": [
    {
      "id": "F1",
      "title": "Sign in",
      "coverage": "covered",
      "actors": ["user"],
      "nodes": [
        { "id": "login", "label": "Login", "kind": "interaction", "sharedKey": "auth.login" },
        { "id": "auth", "label": "POST /auth/login", "kind": "backend", "endpoint": "POST /auth/login" }
      ],
      "edges": [["login", "auth"]],
      "tests": [{ "spec": "auth.spec.ts", "title": "signs in" }],
      "mermaid": "sequenceDiagram\n  actor User\n  participant UI\n  participant API\n  User->>UI: Login\n  UI->>API: POST /auth/login\n  API-->>UI: 200 + token"
    }
  ],
  "moduleEdges": []
}
  • coverage is covered|partial|uncovered; node kind is interaction|backend|db|decision.

  • edges are [from,to] pairs of existing node ids; tests are { spec, title } join keys.

  • Node ids only need to be unique inside a flow. Reuse the same id or sharedKey for a step shared by several flows; backend/db nodes with the same endpoint merge automatically.

  • mermaid is optional but recommended (powers the Sequence tab). Nodes can carry source metadata (file, line, component, selector, payloadExample, table, dbFields); omit what you cannot verify.

Agent and test settings

The agent is configured in flowlens.config.json (an agent block) or agent.json:

{
  "suite": "/absolute/path/to/target-repo/e2e",
  "projectName": "my-app",
  "flows": "flows.json",
  "language": "en",
  "agent": { "command": "claude", "argsTemplate": ["-p", "{{prompt}}"] },
  "tests": { "mode": "project", "dir": "tests" }
}
  • Default: { "command": "opencode", "argsTemplate": ["run", "{{prompt}}"] }. For Claude Code use { "command": "claude", "argsTemplate": ["-p", "{{prompt}}"] }.

  • An array argsTemplate is spawned with shell: false through cross-spawn, so the prompt is a single argv element and nothing is shell-interpreted. A string is a shell command line (POSIX only). agent.env adds environment variables to the child; never store secrets there.

  • tests.mode is project (specs inside the target repo) or isolated (specs under the flowlens data dir, with a generated playwright.isolated.config.ts).

  • With opencode, init / map / serve probe the configured model (--model, FLOWLENS_MODEL or agent.model) and persist the first reachable one in agent.argsTemplate.

  • suite is resolved relative to the config file; init writes it as an absolute path. Use an absolute path if you write the config by hand.

  • Windows: use the array form. flowlens resolves opencode.cmd / claude.cmd through cross-spawn and builds test commands with cd /d and set "VAR=...".

Troubleshooting

  • Browser dependencies missing. init warns when libnspr4.so / libnss3.so are absent. If you run Playwright on the host: sudo apt-get install -y libnspr4 libnss3 libasound2. Suites that run in Docker can ignore it.

  • Docker not available. flowlens env up needs the docker CLI. Use --dry-run to inspect the commands.

  • Port in use. Pass another --port to serve / mcp, or { port } to flowlens_serve.

  • MCP not loading. Run the exact command from your config by hand. If it exits immediately, check Node >= 20 and that --project / --config points to an existing flowlens.config.json.

  • Implement test fails. The panel log prints [flowlens] agent command and agent cwd. Typical causes: the agent is not installed where flowlens serve runs, suite is not absolute, the flow id is wrong (ids are case-sensitive; rebuild first), or the viewer was opened as a file instead of through flowlens serve. If a pinned model fails, test it by hand with opencode run "Reply with exactly: OK".

  • Automatic mapping failed. init keeps the scaffolded files and warns. Retry with flowlens map (--dry-run shows the prompt, --agent claude switches agent, --model provider/model picks a model).

  • Model not reachable. Run opencode models, then pass --model, FLOWLENS_MODEL or agent.model.

  • Generated labels in the wrong language. Friendly names for API/DB nodes are generated at build time: flowlens build --lang es (or "language": "es" in the config).

Privacy

The flowlens repository contains no project data. Config, flows, labels, env and build output live under <dataDir>/<project>/. The only committed examples are synthetic: examples/demo and examples/large. If something must live inside the target repo, flowlens records it in .git/info/exclude, never in the tracked .gitignore. The viewer binds to 127.0.0.1 and loads nothing from the network.

Credits and licenses

flowlens stands on the shoulders of other open-source projects:

  • Graphify (Apache-2.0, by Safi Shamsi and contributors): the flowlens viewer template is ported and modified from Graphify's HTML exporter. Thank you!

  • Playwright (Apache-2.0, Microsoft): flowlens reads its results and traces, ships a reporter for it and embeds its trace viewer. Playwright is not bundled in this repository.

  • vis-network, Mermaid, 3d-force-graph / three.js and cross-spawn.

flowlens itself is released under the MIT License. Third-party code keeps its own license; see NOTICE and THIRD_PARTY_NOTICES.md for the full list, versions and license texts. flowlens is an independent project, not affiliated with or endorsed by Microsoft or Graphify; "Playwright" is a trademark of Microsoft Corporation.

Development

git clone https://github.com/jlaguna553/flowlens && cd flowlens
npm install
npm test                                   # node --test, runs on Linux and Windows in CI
node src/cli.mjs init --suite /path/to/repo --project my-app
npm run build:viewer                       # regenerate src/viewer/render.mjs (needs Node >= 22.13)
npm run demo:generate                      # regenerate examples/large/flows.json (deterministic)

Edit src/viewer/render.ts, never render.mjs (generated). Contributions are welcome: open an issue or a pull request.

License

MIT © 2026 Javier Laguna. Includes third-party components under their own licenses, see NOTICE.

Related MCP Connectors

Related MCP Servers