npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@workglow/cli

v0.6.10

Published

Command-line interface example for Workglow, demonstrating how to build and run AI task pipelines from the terminal.

Readme

Workglow CLI Example

A command-line interface for running Workglow AI tasks and workflows.

Overview

The Workglow CLI provides a terminal-based interface for creating, managing, and executing AI task pipelines. It features an interactive task runner with real-time progress visualization, making it easy to run AI workflows from the command line.

A run renders as the graph it is: one row per task, with its status glyph, whatever detail the task is reporting, a progress bar and — once it settles — how long it took, over a bar for the run as a whole and a status line counting completed tasks.

A workflow running in the terminal

The same commands are also available in a browser, served by this CLI itself with workglow web. It is the same graph, the same forms, and the same run — see below.

The web console running the same workflow

Features

  • Real-time Visualization: Live updates of task execution progress
  • Multi-Provider Support: Works with HuggingFace Transformers and TensorFlow MediaPipe
  • Local AI Models: Run AI models locally without external API calls
  • JSON Configuration: Define workflows using JSON configuration files

Getting Started

Prerequisites

  • Bun runtime (recommended) or Node.js 18+
  • Terminal with Unicode support for best experience

Installation

bun install @workglow/cli

Running

bun src/workglow.ts

Usage

Basic Commands

# Show help
workglow --help

# Run one task by type, passing its config with a single dash
workglow task run Delay -delay 2000

# Run a saved workflow, and list what is saved
workglow workflow list
workglow workflow run my-pipeline

# Serve the same commands in a browser
workglow web

# Serve the registered tasks to MCP clients
workglow mcp serve

Example Workflows

Text Generation

workglow generate \
  --text "The future of AI is" \
  --model "onnx:Xenova/LaMini-Flan-T5-783M:q8" \
  --max-length 100

Workflow from JSON

Create a workflow.json file:

[
  {
    "type": "ModelDownload",
    "config": {
      "model": ["onnx:Xenova/LaMini-Flan-T5-783M:q8"]
    }
  },
  {
    "type": "TextRewriter",
    "config": {
      "text": "The quick brown fox jumps over the lazy dog.",
      "prompt": "Rewrite this text to sound like a pirate:"
    }
  },
  {
    "type": "DebugLog",
    "config": {
      "log_level": "info"
    }
  }
]

Then run:

cat workflow.json | workglow json

Command Reference

Global Options

  • --version, -v: Show version information
  • --help, -h: Show help information

Commands

Run workglow --help for the current list; each group has its own --help.

  • init — create the configuration and directories
  • model — list, search and manage models
  • mcp — manage MCP servers, and mcp serve this CLI's tasks to MCP clients
  • workflow — list, add, edit and run saved workflows
  • agent — the same, for agents
  • task — list task types and run one by type
  • credential — manage encrypted credentials
  • web — serve the web console described below

Web console

workglow web serves a local page for the same commands the terminal runs: pick one, fill in its options, press Run, and watch the task graph execute live. Nothing is duplicated — the command tree is read off the commander program, the form fields come from the same schemas the terminal prompts from, and the line at the bottom of the form is exactly what gets executed.

workglow web                 # http://127.0.0.1:8787/?t=<session token>
workglow web --port 9000

The console binds loopback and has no authentication beyond a per-process session token printed in the URL. Its buttons start runs that spend model and API quota, so exposing it to a network has to be said out loud (--host), and the command warns when you do.

How a run works

Each run is a child process of the same binary, spawned with the argv the page shows you, and handed two extra descriptors: fd 3 for a stream of run events (NDJSON — one line per task added, status, progress, token usage, stream chunk) and fd 4 for answers to anything the run asks its operator. The server replays that stream over SSE, so the page mounts once and is patched per event, and a reconnect resumes from Last-Event-ID rather than starting over.

That shape is why the console works for commands nobody wrote it for: the reporting branch lives in withCli, which every command in this package — and in every CLI built on it — already runs its graphs through. It also means a per-run environment override belongs to that run rather than to the server, and that aborting is the same SIGINT Ctrl-C sends.

Adding the console to your own CLI

import { registerWebCommand } from "@workglow/cli";

registerWebCommand(program, { binaryName: "sec" });

Your commands, however deeply nested, appear with nothing to keep in sync.

Contributing UI from a package

Data crosses this seam, never code — a package registers what to show, and the console renders it. There is no client bundle to ship and no plugin loader to keep stable.

import { registerWebPanel, registerWebFieldWidget, registerWebStatusWidget } from "@workglow/cli";

// An extra panel on a finished run's Result tab.
registerWebPanel({
  id: "sec:extractions",
  title: "Extraction rows",
  source: "@workglow/sec",
  appliesTo: (invocation) => invocation.path[0] === "spac",
  load: async ({ invocation }) => ({
    kind: "table",
    columns: ["table", "rows"],
    rows: await countRowsForIssuer(invocation.args[0]),
  }),
});

// A picker for any field whose schema says `format: "sec:cik"`.
registerWebFieldWidget({
  format: "sec:cik",
  source: "@workglow/sec",
  search: async (query) => findIssuers(query),
});

// A meter in the rail.
registerWebStatusWidget({
  id: "sec:edgar",
  title: "EDGAR fetch budget",
  source: "@workglow/sec",
  read: async () => [{ label: "req/s", value: currentRate(), max: 8 }],
});

A panel that throws is reported as a panel rather than taking the page down, and a status widget that cannot answer is dropped from the rail.

A command whose real input lives in a schema can say so, which is how task run and workflow run get their forms:

import { registerCommandSchemaProvider } from "@workglow/cli";

registerCommandSchemaProvider({
  path: ["spac", "process"],
  resolve: async (args) => ({ input: schemaForIssuer(args[0]), config: undefined }),
});

MCP server

workglow mcp serve offers this CLI's registered tasks to MCP clients as tools, over Streamable HTTP. One tool per task type, named for the registered type itself — TextGenerationTask, which is what task list prints with the Task suffix trimmed — with the task's own input schema as the tool's arguments and its output as the result. Nothing is duplicated: a task registered through registerTasks is a tool for the same reason it is a task run argument.

workglow mcp serve                       # http://127.0.0.1:8788/mcp
workglow mcp serve --port 9100 --path /
workglow mcp serve --task TextGeneration --task Delay

It binds loopback and requires a bearer token, generated per process and printed at startup along with a ready-made client config:

mcp server listening on http://127.0.0.1:8788/mcp — 114 tasks offered as tools
bearer token: 3nS2...
client config: {"type":"http","url":"http://127.0.0.1:8788/mcp","headers":{"Authorization":"Bearer 3nS2..."}}

A client config has to hold the same token across restarts, so pin one with WORKGLOW_MCP_TOKEN (preferred — an argument that never changes is one every other process can read out of ps) or --token. --no-auth drops the gate entirely, which anything that can reach the port can then walk through; exposing the server with --host warns for the same reason the web console does.

Flow-control and hidden tasks are left out — a MapTask with no subgraph around it is not a tool anyone can call, and "Hidden" is what a class that named no category gets, which covers JsonTask (it runs a graph handed to it, so publishing it would put every excluded task back within reach) and LambdaTask (its config is a function, which no client can send). --task narrows the list to exactly what you name, that filter included.

A task that asks a person asks the client driving the call, through MCP elicitation, rather than the terminal nobody is sitting at: each tool call runs against its own registry carrying an McpElicitationConnector bound to that call. A client that did not advertise elicitation gets a tool error saying so instead of a call that never returns.

Serving MCP from your own host

The parts worth sharing live in @workglow/mcp/server, not here: createTaskMcpServer builds the tool surface over any transport, startMcpHttpServer hosts it from node:http, McpSessionRouter holds the Streamable HTTP sessions for a host that already has its own web framework, and authorizeBearer is the token check.

import { createTaskMcpServer, generateBearerToken, startMcpHttpServer } from "@workglow/mcp/server";

const handle = await startMcpHttpServer({
  port: 8788,
  host: "127.0.0.1",
  token: generateBearerToken(),
  createServer: () => createTaskMcpServer({ name: "my-app", version: "1.0.0" }),
});

Configuration

Model Configuration

The CLI automatically downloads and caches AI models. You can configure model settings:

Development

Project Structure

src/
├── workglow.ts              # Main CLI entry point
├── TaskCLI.ts             # CLI command definitions
├── TaskGraphToUI.ts       # Terminal UI components
├── components/            # Reusable CLI components
├── lib.ts                 # Library exports
└── worker_hft.ts          # HuggingFace worker

Adding New Commands

  1. Define the command in TaskCLI.ts:
program
  .command("my-command")
  .description("My custom command")
  .option("-t, --text <text>", "Input text")
  .action(async (options) => {
    // Command implementation
  });
  1. Implement the command logic using Workglow workflows:
const workflow = new Workflow();
workflow.MyCustomTask(options);
await workflow.run();

Available Models

HuggingFace Transformers (ONNX)

  • Text Generation:

    • onnx:Xenova/LaMini-Flan-T5-783M:q8
    • onnx:Xenova/distilgpt2:q8
  • Translation:

    • onnx:Xenova/m2m100_418M:q8
    • onnx:Xenova/opus-mt-en-de:q8
  • Classification:

    • onnx:Xenova/distilbert-base-uncased:q8
    • onnx:Xenova/roberta-base-sentiment:q8

TensorFlow MediaPipe

  • Text Embeddings:
    • mediapipe:universal-sentence-encoder

Performance

  • Model Caching: Models are cached after first download
  • Quantized Models: Use quantized models (q8) for better performance

Troubleshooting

Common Issues

  1. Model Download Failures:

    # Clear model cache
    rm -rf ~/.cache/
  2. Memory Issues:

    # Use smaller models or increase system memory
    workglow generate --model "onnx:Xenova/distilgpt2:q8"

Examples

Batch Processing

Process multiple files:

for file in *.txt; do
  workglow generate "$(cat $file)" > "${file%.txt}_generated.txt"
done

Pipeline Processing

Chain multiple operations:

# Generate text, then translate it
workglow generate --text "Write about AI" | \
workglow rewrite --prompt "Rewrite this text to sound like a pirate:"

License

Apache 2.0 - See LICENSE for details.