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

@aip-tech/braid

v0.5.0

Published

Runs multiple long-lived processes as one unit, as a background daemon or attached to your terminal — PID tracking, watch-triggered restarts, kill-everything-on-crash, and persistent rotated per-process logs.

Readme

braid

Runs multiple long-lived processes as one unit, as a background daemon by default (or attached to your terminal with --foreground): PID tracking, watch-triggered restarts, kill-everything-on-crash, and persistent rotated per-process logs.

Published on npm as @aip-tech/braid. See CHANGELOG.md for release notes.

Install

npm install @aip-tech/braid

Config

braid.config.ts:

import { defineConfig } from "@aip-tech/braid";

export default defineConfig({
	processes: [
		{ name: "api", command: "pnpm", args: ["--filter", "./api", "run", "dev"], watch: ["api/src"] },
		{ name: "client", command: "pnpm", args: ["--filter", "./client", "run", "dev"] },
	],
});
  • watch: restart this process when these paths change. Omit it for a command that manages its own reload.
  • dependsOn: { processes, run? } — restart this process whenever any of processes restarts, optionally running a command first (e.g. codegen) and waiting for it to finish. See Dependent restarts.
  • onRestart: run a command after this process itself restarts, e.g. rebuilding a shared workspace package. See Post-restart hooks.
  • beforeRestart: run a command after this process's own watched files change and it's stopped, but before it restarts, e.g. regenerating something the fresh process needs on disk. Requires watch. See Pre-restart hooks.
  • readyPattern: hold off onRestart/dependsOn until this regex matches the process's own output after a restart. See Waiting for readiness.
  • plugins: external plugins to load, by package name/path (or a [name, options] tuple).
  • logs: { dir, maxSizeBytes, timestamps } — see Logs.
  • foreground: run start attached to the terminal instead of forking a background daemon. Overridable per invocation with --foreground/--daemon. @default false

Full field list and defaults: src/types.ts (ProcessConfig, BraidConfig).

CLI

npx @aip-tech/braid start                    # start every configured process as a background daemon
npx @aip-tech/braid start --foreground       # ...or attached to this terminal (Ctrl-C stops everything)
npx @aip-tech/braid start --daemon           # force the background daemon, overriding a config's foreground: true
npx @aip-tech/braid status                   # list each process's name/pid/alive state
npx @aip-tech/braid logs [name]              # print a process's log (every process, interleaved, if no name)
npx @aip-tech/braid logs [name] --follow     # keep streaming new output
npx @aip-tech/braid logs [name] --lines 50   # only the last 50 lines
npx @aip-tech/braid stop                     # kill everything
npx @aip-tech/braid start --config ./other.config.ts

In --foreground mode, start blocks until every process stops (Ctrl-C, or braid stop from another terminal), streaming their combined output straight here instead of only to the log files.

Dependent restarts

A process can restart whenever another one does — e.g. a client that needs to regenerate its GraphQL SDK once the API it talks to restarts:

{ name: "api", command: "pnpm", args: ["--filter", "./api", "run", "dev"], watch: ["api/src"] },
{
	name: "client",
	command: "pnpm",
	args: ["--filter", "./client", "run", "dev"],
	dependsOn: {
		processes: ["api"],
		run: { command: "pnpm", args: ["--filter", "./client", "run", "generate"] },
	},
},

When api restarts: client stops once api has actually re-spawned (not the instant it decides to restart), run executes (retried on failure — retries/retryDelayMs, default 5× / 1s apart, since api may still be starting back up), then client restarts. Left stopped with a logged reason if run never succeeds. A dependsOn chain that loops back on its own trigger is rejected at startup.

Post-restart hooks

For a shared workspace package other processes just read from (no process of its own to restart), run a command directly after the process that changed it restarts:

{
	name: "api",
	command: "pnpm",
	args: ["--filter", "./api", "run", "dev"],
	watch: ["api/src"],
	onRestart: { command: "pnpm", args: ["--filter", "./types", "run", "generate"] },
},

Same shape and retry behavior as dependsOn.run, but scoped to api restarting itself — no dependent process is stopped or restarted. If api also has dependents (via dependsOn), they're notified only once this hook succeeds, and not at all if it never does.

Pre-restart hooks

For a process that needs to regenerate its own on-disk dependencies (e.g. a GraphQL SDK generated from a schema it also watches) before it restarts on that same change, beforeRestart runs after the process is stopped and before a fresh one starts:

{
	name: "client",
	command: "pnpm",
	args: ["vike", "dev"],
	watch: ["server", "lib/sdk"],
	beforeRestart: { command: "pnpm", args: ["--filter", "lib/sdk", "run", "generate"] },
},

client is fully stopped, generate runs to completion (retried like onRestart/dependsOn.run), and only then does client restart — the fresh process never boots against stale or half-regenerated code. Requires watch; rejected at startup otherwise. If the hook keeps failing past its retries, client is left stopped, but the watcher stays active — the next matching file change retries the whole cycle, rather than requiring a manual restart.

Waiting for readiness

Re-spawning a process isn't the same as it being ready — an API might take a moment after restarting before it's actually serving. readyPattern holds off onRestart and any dependsOn cascades until a regex matches that process's own stdout/stderr:

{
	name: "api",
	command: "pnpm",
	args: ["--filter", "./api", "run", "dev"],
	watch: ["api/src"],
	readyPattern: "Server listening",
	readyTimeoutMs: 15000, // @default 10000
},

Without readyPattern, dependents are held off only until api has re-spawned (not exited/killed while restarting, but not necessarily done starting up either) — a run/onRestart hook's own retry is what bridges the rest of that gap. If readyPattern never matches within readyTimeoutMs, braid logs why and proceeds anyway rather than holding dependents off forever on a misconfigured pattern.

Logs

Each process gets a rotated log file at .braid/logs/<name>.log. Rotated (one backup kept) on every start, on a watch-triggered restart, and past logs.maxSizeBytes (default 5MB). Braid's own diagnostics (plugin failures, crash notices) go to .braid/daemon.log; a dependsOn/onRestart/beforeRestart hook that keeps failing, or a readyPattern that never matches, is also logged into the relevant process's own log. A process also gets a braid: stopping line right before braid stops it for a dependsOn cascade or a watch-triggered restart (not yet for a plain braid stop).

Set logs.timestamps: true to prepend a dimmed HH:MM:SS.mmm to every line, before the [name] tag. It's the same bytes wherever that line shows up — the log file, braid logs, the web UI, and the terminal during braid start all get it together. @default false

Plugins

start runs a loopback-only, token-guarded control server that plugins register routes on. List a plugin by package name/path in plugins to load it — see PluginContext in src/types.ts. No external plugins ship yet.

Scripts

pnpm build        # tsc -> dist/
pnpm typecheck    # tsc --noEmit
pnpm test         # vitest run
pnpm coverage     # vitest run --coverage