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

poly-weaver

v0.3.2

Published

Orchestrates pluggable AI coding agents in an iterative plan-review loop

Readme

poly-weaver

Orchestrates pluggable AI coding agents in iterative plan-review loops.

poly-weaver spawns AI CLI tools (Claude Code, Codex CLI, GitHub Copilot CLI) via PTY and drives them through a declarative Flow DSL that defines the workflow as composable steps. A planner agent drafts a plan, a reviewer agent evaluates it, and the user can intervene at each checkpoint. Once approved, an implementor agent executes the plan with its own review cycle. A simplifier agent can optionally refine the result after implementation. All inter-step data flows through an artifact-based system — steps declare what they read and write, and data is exchanged via a shared artifact store.

How it works

The default flow uses a two-layered loop structure:

 Task
  │
  ▼
┌─── Outer loop (user feedback) ──────────────────────────────────┐
│                                                                 │
│  ┌──────────┐   ┌──────────────┐                                │
│  │ Planner  │──▶│ User review  │──▶ accept / give feedback      │
│  └──────────┘   └──────────────┘         │                      │
│   ▲                  │ feedback          │ accept                │
│   └──────────────────┘                   ▼                      │
│                                ┌─── Inner loop ──────────┐      │
│                                │ Plan ──▶ Review          │      │
│                                │  ▲   rejected  │         │      │
│                                │  └──────────────┘        │      │
│                                │         │ approved       │      │
│                                └─────────┼────────────────┘      │
│                                          ▼                      │
│                                ┌──────────────┐                 │
│                                │ User approve │──▶ restart / ok │
│                                └──────────────┘                 │
└─────────────────────────────────────────────────────────────────┘
                                           │ ok
                                           ▼
                              ┌─── Impl loop ──────────────┐
                              │ Implement ──▶ Review        │
                              │   ▲     rejected  │         │
                              │   └───────────────┘         │
                              │          │ approved          │
                              └──────────┼──────────────────┘
                                         ▼
                                       Done

In auto mode (--auto), user review steps are skipped — the reviewer loop alone decides approval. The startup TUI renders a live ASCII flow diagram reflecting the configured mode.

"Why So Serious" workflow

The why-so-serious workflow (selectable via Shift+Tab in the TUI) extends the default flow with two additions:

  1. Conditional re-planning — if the implementation reviewer finds more than 2 issues, a planner step runs before the next implementation attempt to draft a targeted fix plan. When issues are within threshold, the implementor revises normally.
  2. Simplification pass — after the implementation loop is approved, a simplifier agent reviews the codebase and produces a simplification plan, which the implementor then applies.
  Default impl loop               Why-so-serious impl loop
  ────────────────                 ────────────────────────
  Implement → Review              issues > 2 ? → Planner (fix plan)
    ↑ rejected  │                 Implement → Review
    └────────────┘                   ↑ rejected  │
         │ approved                  └────────────┘
         ▼                                │ approved
       Done                               ▼
                                    Simplifier → Implement
                                          ▼
                                        Done

Custom flows

Custom flows live in ~/.poly-weaver/flows/ as .mjs files. Each file exports a factory function that receives the DSL toolkit and returns a flow template:

// ~/.poly-weaver/flows/my-flow.mjs
export default function (dsl) {
  const { defineFlow, loop, artifactData, plan, review, TASK } = dsl;

  return {
    name: "my-flow",
    params: [
      { key: "planner", type: "driver", role: "planner", label: "Planner", default: "claude" },
      { key: "reviewer", type: "driver", role: "reviewer", label: "Reviewer", default: "codex" },
      { key: "maxIterations", type: "number", label: "Max Iterations", default: 5, min: 1, max: 50 },
    ],
    build(values) {
      return defineFlow("my-flow", [
        loop(values.maxIterations, artifactData("verdict", "approved"), [
          plan({ driver: values.planner, reads: { task: TASK, verdict: "verdict" }, writes: { plan: "plan" } }),
          review({ driver: values.reviewer, variant: "plan", reads: { task: TASK, plan: "plan" }, writes: { verdict: "verdict" } }),
        ]),
      ]);
    },
  };
}

The DSL toolkit is imported via poly-weaver/dsl and includes all step builders (plan, review, implement, simplify, user), loop/predicate helpers, and the TASK constant. Use create-flow and modify-flow subcommands for LLM-assisted authoring. See src/flow/custom/AUTHORING.md for the full DSL reference.

Each agent is a real CLI process (Claude Code, Codex, or GitHub Copilot) running in a pseudo-terminal. poly-weaver reads their session files to detect completion, extract responses, and feed feedback.

Installation

Prerequisites

  • Node.js 18+
  • A C++ toolchain for node-pty:
    • Windows — Visual Studio Build Tools
    • macOS — Xcode Command Line Tools
    • Linuxbuild-essential
  • At least one supported AI CLI installed and authenticated:

Install from GitHub Packages

npm install -g poly-weaver

Install from source

git clone https://github.com/gim-home/poly-weaver.git
cd poly-weaver
npm install   # installs dependencies and builds automatically
npm link      # registers the `poly-weaver` command globally

Uninstall

npm uninstall -g poly-weaver
# or if installed from source:
npm unlink -g poly-weaver

Usage

poly-weaver

This opens an interactive TUI to configure the task, select providers for each role, and set options before starting the orchestration loop.

You can also pass arguments directly:

# Pass a task directly
poly-weaver "Refactor the auth module to use JWT"

# Read task from a file
poly-weaver task.md

# Choose providers for each role
poly-weaver "Add unit tests" --planner claude --reviewer copilot --implementor claude

# Plan only (skip implementation)
poly-weaver "Design a caching layer" --plan-only

# Fully automated (no user checkpoints)
poly-weaver "Fix the login bug" --auto

# Opinionless mode — minimal prompts, agent decides the approach
poly-weaver "Refactor the auth module" --opinionless

CLI options

| Option | Description | Default | |---|---|---| | [task] | Task description or path to a .md/.txt file | (interactive) | | --planner <cli> | Provider for planning (claude | codex | copilot) | claude | | --reviewer <cli> | Provider for reviewing (claude | codex | copilot) | codex | | --implementor <cli> | Provider for implementation (claude | codex | copilot) | claude | | --simplifier <cli> | Provider for simplification (claude | codex | copilot) | claude | | --max-iterations <n> | Max plan-review cycles | 5 (range: 1–50) | | --max-impl-iterations <n> | Max implementation-review cycles | 5 (range: 1–50) | | --auto | Skip user review phases | false | | --plan-only | Stop after plan approval, skip implementation | false | | --workdir <path> | Working directory for agent CLIs | current directory | | --opinionless | Use minimal prompts; let agents decide how to plan/review/implement | false | | --no-yolo | Run agents without auto-approving permissions | false (agents run with permission-skipping) | | --whip-mode / --no-whip-mode | Enable/disable neighbor awareness hints between agents | false | | --workflow <name> | Workflow template to use | default | | --config <path> | Path to a JSON config file | (none) | | --verbose | Preserve session files for debugging | false |

Workflow is selected via --workflow <name> or Shift+Tab in the TUI. Built-in workflows: default, why-so-serious. Custom flows are also available (see below).

Subcommands

poly-weaver create-flow    # LLM-assisted custom flow creation
poly-weaver modify-flow    # Modify an existing custom flow

Architecture

src/
├── cli.ts                 # Entry point, argument parsing (Commander)
├── orchestrator.ts        # Builds flow from template, runs executor
├── config.ts              # Config file loading, user config persistence
├── dsl.ts                 # DSL toolkit barrel for custom flows (poly-weaver/dsl)
├── prompts.ts             # Shared prompt utilities (verdict schema, feedback derivation)
├── preflight.ts           # CLI availability checks
├── startup-tui.ts         # Interactive startup TUI with live flow diagram
├── preview-panel.ts       # Shared TUI panel rendering (config fields, flow diagram)
├── status-bar.ts          # Persistent status bar rendering
├── terminal-input.ts      # Terminal input utilities
├── git-info.ts            # Git branch/status detection
├── ansi.ts                # Shared ANSI helpers
├── version.ts             # App version constant
├── dump/
│   ├── types.ts           # Dump manifest, step record, artifact snapshot types
│   ├── hotkey.ts          # DumpHotkeyDetector — dual-path Ctrl+] detector (VT byte 0x1D + passive kitty CSI)
│   ├── collector.ts       # collectDump() — writes artifacts + sessions + manifest
│   ├── service.ts         # DumpService — debounce, mutex, flash feedback
│   └── DUMP-STRUCTURE.md  # Dump directory layout reference
├── flow/
│   ├── types.ts           # FlowStep, ArtifactStore, FlowTemplate, FlowParam
│   ├── dsl.ts             # DSL helpers: defineFlow, loop, predicates
│   ├── executor.ts        # Walks a FlowDefinition, runs steps
│   ├── neighbors.ts       # Data-flow consumer map computation
│   ├── artifacts.ts       # MapArtifactStore implementation
│   ├── params.ts          # Flow param resolution (CLI > file > user > default)
│   ├── diagram.ts         # ASCII flow diagram renderer for TUI
│   ├── inspect.ts         # Flow definition introspection utilities
│   ├── index.ts           # Re-exports
│   ├── built-in/
│   │   ├── default.ts     # Default two-layered flow template
│   │   └── why-so-serious.ts # Why-so-serious flow template (conditional replan + simplify)
│   └── custom/
│       ├── load.ts        # Custom flow loader (discovers ~/.poly-weaver/flows/*.mjs)
│       ├── index.ts       # Re-exports
│       └── AUTHORING.md   # Full DSL reference for custom flow authors
├── flow-editor/
│   ├── tui.ts             # Flow editor TUI (create/modify modes)
│   ├── llm.ts             # LLM prompt builders and code generation
│   ├── validate.ts        # Flow code validation pipeline
│   ├── save.ts            # Flow file persistence with backup
│   ├── names.ts           # Random flow name generator
│   └── index.ts           # Re-exports
├── agents/
│   ├── registry.ts        # Role registry: registerRole, createHandler
│   ├── runner.ts          # AgentRunner — shared spawn→detect→exit lifecycle
│   ├── whip-hint.ts       # Whip mode hint builder
│   ├── index.ts           # Registers built-in providers, re-exports DSL helpers
│   ├── planners/
│   │   ├── prompts.ts     # Planner prompt builders and prompt sets
│   │   ├── dsl.ts         # plan() DSL helper
│   │   ├── handler.ts     # PlannerRoleHandler (artifact ↔ driver bridge)
│   │   ├── adapter.ts     # PlannerAdapter (driver ↔ provider bridge)
│   │   ├── types.ts       # PlannerDriver interface
│   │   └── index.ts       # Self-registers into role registry
│   ├── reviewers/         # Same structure + prompts.ts
│   ├── implementors/      # Same structure + prompts.ts
│   └── simplifiers/       # Same structure + prompts.ts
├── user/
│   ├── dsl.ts             # user() DSL helper for user-review steps
│   ├── handler.ts         # User checkpoint handler
│   ├── prompt.ts          # User prompt rendering
│   └── index.ts           # Re-exports
├── providers/
│   ├── types.ts           # ProviderStrategy, SessionHandler, CompletionDetector
│   ├── registry.ts        # Built-in provider registry (name → strategy)
│   ├── invoke.ts          # Non-interactive provider invocation
│   ├── base-completion.ts # Shared completion detection logic
│   ├── prompt-file.ts     # Prompt file writing utilities
│   ├── path-utils.ts      # Path helpers
│   ├── index.ts           # Re-exports all provider strategies
│   ├── claude/
│   │   ├── strategy.ts    # ClaudeStrategy
│   │   ├── session.ts     # Claude session file handling
│   │   ├── completion.ts  # Claude completion detection
│   │   └── index.ts
│   ├── codex/
│   │   ├── strategy.ts    # CodexStrategy
│   │   ├── session.ts     # Codex session file handling
│   │   ├── completion.ts  # Codex completion detection
│   │   └── index.ts
│   └── copilot/
│       ├── strategy.ts    # CopilotStrategy
│       ├── session.ts     # Copilot session file handling
│       ├── completion.ts  # Copilot completion detection
│       └── index.ts
├── session/
│   ├── dir.ts             # Session temp directory lifecycle
│   ├── reader.ts          # JSONL session file parser
│   └── locator.ts         # Session file discovery
└── pty/
    ├── spawn.ts           # PTY spawning (node-pty)
    ├── exit.ts            # Exit signal handling
    └── types.ts           # PTY-related types

Opinionless mode

By default, poly-weaver prompts include prescriptive criteria for each role — evaluation rubrics for reviewers, structural requirements for planners, step-by-step instructions for implementors.

With --opinionless, prompts are stripped to the structural minimum: file path references and the verdict output schema. The agent decides how to approach its role. The verdict schema is also simplified — each issue only requires a description, with category and severity left to the agent's discretion.

This is useful when the AI agent has its own strong conventions, or when you want to compare agent behavior with and without prescriptive guidance.

Whip mode

With --whip-mode, each agent receives a hint describing who produced its input and who will consume its output. For example, a planner might see:

The previous step was performed by Claude. Codex will review your plan.

Hints are suppressed when neighbors use the same provider — telling Claude that Claude produced the input is not actionable. This means whip mode only adds value in mixed-provider workflows where agents benefit from knowing their neighbors' capabilities and conventions.

Toggle it in the TUI or pass --whip-mode / --no-whip-mode on the command line.

Troubleshooting dump

Press Ctrl+] at any time during an interactive session to capture a full snapshot of the current session state. The dump is written to:

~/.poly-weaver/troubleshooting/{timestamp}/

It includes:

  • Step artifacts — inputs and outputs for every executed step, copied into per-step directories
  • Session JSONLs — the raw provider session files for each agent invocation
  • manifest.json — metadata including flow name, parameters, execution counters, and a map of all step entries with relative paths to their artifacts and sessions

The hotkey works both during agent execution (intercepted at the PTY byte level) and during user-review prompts. A status bar flash confirms the dump location. The hotkey uses VT byte 0x1D (Ctrl+]) which works on all terminals; passive kitty keyboard protocol encoding is also recognized for terminals that enable it independently.

See src/dump/DUMP-STRUCTURE.md for the full directory layout reference.

Registry + Handler + Adapter + Runner

The agent system has four layers:

  • Role Registry (src/agents/registry.ts) — maps role names (planner, reviewer, implementor) to role modules. Each module self-registers on import and exposes createHandler() and availableDrivers().
  • Role Handlers (e.g. PlannerRoleHandler) — bridge the artifact store and the driver interface. They read artifacts declared in the step's reads, call the driver, and write results to the step's writes.
  • Role Adapters (e.g. PlannerAdapter) — implement the driver interface by translating role-specific calls into generic agent runs with the appropriate prompts and file routing. Each adapter wraps a ProviderStrategy.
  • AgentRunner — executes the shared lifecycle: snapshot session files → spawn PTY → detect completion → extract response → exit. Accepts any ProviderStrategy.

DSL helpers (plan(), review(), implement(), simplify(), user()) create flow step definitions. The executor walks the flow and uses the registry to instantiate handlers, which delegate to adapters, which delegate to the runner.

For programmatic use outside flows, invoke(provider, prompt, workdir) in src/providers/invoke.ts offers one-shot non-interactive provider invocation — resolve provider, spawn PTY, detect completion, return response text.

Artifact system

Steps declare what they read and write via reads and writes mappings (e.g. reads: { task: "task", verdict: "verdict" }). Data flows through a shared in-memory ArtifactStore — a Map<string, Artifact> where each artifact can carry:

  • file — path to an artifact file on disk (in the session temp directory)
  • text — human-readable content
  • data — parsed structured data (for predicates to inspect programmatically)
  • meta — metadata (e.g. source, version)

Adding a provider

  1. Implement ProviderStrategy, SessionHandler, and CompletionDetector (see src/providers/types.ts)
  2. Register the provider strategy with each role module:
import * as planners from "./agents/planners/index.js";
import * as reviewers from "./agents/reviewers/index.js";
import * as implementors from "./agents/implementors/index.js";
import * as simplifiers from "./agents/simplifiers/index.js";

const myProvider = new MyStrategy();
planners.registerProvider("my-cli", myProvider);
reviewers.registerProvider("my-cli", myProvider);
implementors.registerProvider("my-cli", myProvider);
simplifiers.registerProvider("my-cli", myProvider);

Adding a role

  1. Create six files in src/agents/<role>/:

| File | Purpose | |------|---------| | types.ts | Driver interface, run options, and result types | | prompts.ts | Role-specific prompt builders and prompt sets | | adapter.ts | Extends BaseAdapter; bridges the driver to AgentRunner via prompt selection | | handler.ts | Implements RoleHandler; orchestrates artifacts, retry, and session state | | dsl.ts | DSL helper (e.g. myRole()) that wraps agentStep() with role defaults | | index.ts | Module entry — calls createRoleModule(), exports DSL helper and registerProvider |

  1. Wire the role into the system (2 edits):

    • src/agents/index.ts — add a side-effect import (import "./<role>/index.js") and re-export the DSL helper
    • src/flow/types.ts — add the role name to the BuiltinRole union
  2. Use the DSL helper in a flow:

import { myRole } from "./agents/index.js";

const steps = [
  myRole({ driver: "claude", reads: { task: "task" }, writes: { output: "result" } }),
];

Development

npm run build        # Compile TypeScript
npm run dev          # Run via tsx (no build step)
npm test             # Run unit tests (vitest)
npm run test:e2e     # Run end-to-end tests
npm run typecheck    # Type-check without emitting

License

MIT