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

@kstackz/devtools

v0.0.0

Published

Local DevTools server for telemetry and architecture analysis, with Client Commands for reading it back

Readme

@kstackz/devtools

Local DevTools server for telemetry and architecture analysis, with Client Commands for reading it back

Big picture

Local development produces traces, logs, and Flow Journals, and a project's architecture lives in a laymos.config.json. DevTools gives all of that one place. devtools starts a loopback server that bundles the browser UI, a typed RPC endpoint, and OTLP/HTTP ingestion. devtools snapshot draws a Project's changed Modules to a PNG in a headless browser without any server, so a review or a CI job can show what a change did to the architecture. Every other subcommand is a Client Command that reads Traces and Flows back from a running server as JSON or text, so a shell or a coding agent can query telemetry without a browser.

The server hosts four Tools. Lotel stores and shows OpenTelemetry data using @kstackz/lotel. Flow stores Journal Entries from @kstackz/flow and draws them as swim lanes. Laymos and Monoverse analyze one project or one pnpm monorepo through laymos. Applications send telemetry with @kstackz/effect-tracer.

Terms are defined in CONTEXT.md and, for Monoverse, docs/monoverse.md. Decisions are in docs/adr/. The agent skill shipped with the package is in skills/devtools/SKILL.md.

Install

npm i -g @kstackz/devtools

Or run it without installing: npx @kstackz/devtools.

The optional peer playwright-core is needed only by devtools snapshot, which drives a headless Chromium through it. The @kstackz/devtools/rpc subpath is source TypeScript and needs effect in the consuming project.

Exports

@kstackz/devtools/rpc

The RPC contract the server fulfils and the browser and Client Commands call. It merges the Lotel, Flow, Laymos, git, Monoverse, and Project registry groups.

| Export | What it does | | ---------------------------------- | ---------------------------------------------------------------------------------- | | DevtoolsRpc | The full RPC group served at /rpc. | | DevtoolsToolRpc | The Laymos procedures: analyze, module source, source files, docs, stories. | | GitRpc | Branches, changes, file diffs, and known files for any folder in a git repository. | | MonoverseRpc | The AnalyzeMonorepo, GetPackageReadme, and GetPackageFiles procedures. | | ProjectRegistryRpc | List, add, update, remove registered Projects and resolve their Worktrees. | | InvalidProjectPath | Error for a relative, missing, or non-directory project path. | | ConfigReadError | Error when laymos.config.json could not be read. | | ConfigParseError | Error when the config is not valid JSON. | | ConfigSchemaError | Error when the config does not match the schema. | | ConfigValidationError | Error carrying the config's validation issues. | | SourceAnalysisError | Error when the source tree could not be analyzed. | | ModuleSourceNotFoundError | Error for an unknown Configured Module. | | ModuleSourceReadError | Error when a Module's file could not be read. | | SourceFileReadError | Error when a requested source file could not be read. | | DocumentationScopeNotFoundError | Error for a documentation scope the config does not declare. | | DocumentationReadError | Error when a docs markdown file could not be read. | | StoriesUnavailableError | Error when the Story tree could not be loaded, with the reason. | | InvalidFolderPath | Error for a relative, missing, or non-directory folder given to a git procedure. | | GitUnavailableError | Error when the folder is not in a repository or git failed. | | InvalidMonorepoPathError | Error for a relative, missing, or non-directory monorepo path. | | NotPnpmWorkspaceError | Error when the folder has no pnpm-workspace.yaml. | | MonorepoReadFailure | Error when workspace or manifest files could not be read or parsed. | | PackageReadmeNotFoundError | Error when the requested markdown file does not exist in the Package. | | PackageReadmeOutsidePackageError | Error when the relative path escapes the Package folder. | | PackageReadmeReadError | Error when the markdown file could not be read. | | PackageFileReadError | Error when one of a Package's files could not be read. | | ProjectRegistryError | Error for a missing entry, an invalid path, or a store failure. | | RegistryToolSchema | monoverse or laymos: which Tool a registry entry belongs to. | | ProjectEntrySchema | One registered Project with its Worktree resolution. | | ProjectEntryEntitySchema | The stored form of a registry entry. | | WorktreeSchema | One git Worktree of a repository. | | WorktreeResolutionSchema | Every Worktree of the Project's repository and which one it is in. | | FlowEntryEntitySchema | How the Flow Store keeps one Entry, keyed by id and indexed by Flow id. | | FlowEntryListSchema | A page of stored Flow Entries. |

CLI

| Command | What it does | | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | | devtools [--port] [--db] [--open] | Runs the DevTools Server: UI, RPC, and OTLP ingestion on 127.0.0.1:14400. | | devtools list-traces [--limit 20] | Lists recent Trace Summaries, newest first. | | devtools get-trace <trace-id> | Returns one Trace: spans in start order with their Log Records. | | devtools list-flows [--limit 20] | Lists recent Flows, newest first. | | devtools get-flow <flow-id> | Returns one Flow Projection in recorded order. | | devtools skills [<name>] [--install <dir>] | Lists, prints, or installs the shipped agent skill. | | devtools snapshot [--project] [--base] [--out] | Draws a Project's changed Modules to a PNG with headless Chromium, no server. --all draws every changed Project. |

Client Commands take --url and --format json|text. The server URL comes from --url, then DEVTOOLS_URL, then DEVTOOLS_PORT on 127.0.0.1, then http://127.0.0.1:14400. The server reads DEVTOOLS_PORT and DEVTOOLS_DB when the flags are absent.

Usage

Start the server and send telemetry to it

Run the server, then point an application's telemetry layer at it. Traces, logs, and Flow Entries from every process land in one SQLite file.

devtools --open
# devtools running on http://127.0.0.1:14400
import { Effect, Layer, ManagedRuntime } from 'effect';
import { makeDevTelemetryLayer } from '@kstackz/effect-tracer/telemetry/dev-telemetry';
import { FlowTelemetry } from '@kstackz/flow';

const endpoint = 'http://127.0.0.1:14400';

// One runtime per process; each names itself so lanes stay apart.
const runtimeFor = (origin: string) =>
  ManagedRuntime.make(
    Layer.merge(
      FlowTelemetry.layer({ endpoint, origin }),
      makeDevTelemetryLayer({ endpoint, serviceName: origin }),
    ),
  );

const server = runtimeFor('server:api-1');

await server.runPromise(
  Effect.log('order accepted').pipe(Effect.withSpan('handle-order')),
);

// Disposing drains the last batch.
await server.dispose();

How it works:

  • The server listens on loopback only and serves /, /lotel, /flow, /laymos, /monoverse, /rpc, /health, /v1/traces, and /v1/logs.
  • makeDevTelemetryLayer posts OTLP/HTTP JSON to /v1/traces and /v1/logs.
  • FlowTelemetry.layer posts Flow Entries to /rpc; Entries recorded inside a span carry its trace id, so the Flow view links to the trace.

Read telemetry back from a shell

Client Commands query the running server. JSON is the default so output can be piped; --format text renders a Trace as its Narrative and a Flow as one line per Entry.

devtools list-traces --limit 5
devtools get-trace 4bf92f3577b34da6a3ce929d0e0e4736 --format text
devtools list-flows
devtools get-flow order:42 --format text

# Install the agent skill so a coding agent knows these commands.
devtools skills devtools --install .claude/skills

How it works:

  • Each command opens an Effect RPC client over NDJSON against DevtoolsRpc at <url>/rpc.
  • A missing Trace or Flow, or an unreachable server, is written to stderr with a nonzero exit.
  • Laymos is not covered by Client Commands; use the laymos CLI.

Draw the changed architecture to a PNG

devtools snapshot analyzes one Project, marks what changed since a Base ref, and draws only the changed Modules and their Layers. It opens the bundled Snapshot page from disk in headless Chromium, so nothing listens on a port.

# The branch is checked out; compare it with main.
devtools snapshot --project toolkits/ui-toolkit --base origin/main \
  --out .snapshots/ui-toolkit.png --only-changed
# {
#   "project": "toolkits/ui-toolkit",
#   "title": "ui-toolkit",
#   "baseRef": "c08fd1c…",
#   "modules": 132,
#   "changedModules": 4,
#   "drawn": "changed",
#   "scale": 2,
#   "images": [
#     { "theme": "dark", "out": "/…/.snapshots/ui-toolkit.png", "width": 512, "height": 806 }
#   ]
# }

# Every Project under this folder that the branch changed, in both themes.
devtools snapshot --all --base origin/main --only-changed --theme both \
  --out-dir .snapshots
# [ { "project": "toolkits/ui-toolkit", …, "images": [
#     { "theme": "dark", "out": "/…/.snapshots/toolkits%2Fui-toolkit-dark.png", … },
#     { "theme": "light", "out": "/…/.snapshots/toolkits%2Fui-toolkit-light.png", … } ] } ]

How it works:

  • analyzeProject and loadChangeSet from laymos run in-process. Only commits since the merge-base of --base (default main) and HEAD are marked; uncommitted work is left out, so fetch the base first.
  • The page measures the drawing once, then redraws it at the size the content needs, capped at --max-width by --max-height (1600 CSS pixels each) and captured at --scale device pixels per CSS pixel (2).
  • --only-changed writes nothing when no Module changed; otherwise a Project with no changed Module is drawn in full. --include-unchanged always draws every Module. The drawing is dark like DevTools; --theme light or DEVTOOLS_THEME=light draws it light, and --theme both writes a -dark and a -light file.
  • --all finds every laymos.config.json under the current folder, skipping fixtures/ and git-ignored folders, keeps the Projects the commits touched, and writes one PNG per Project into --out-dir (default .snapshots), named after its folder. It cannot be combined with --project, --out, or --title. The pictures share one browser, and a Project that fails is reported with an error while the rest are still drawn; the exit code is then 1.
  • Chromium comes from Playwright's own install when present, else the system Chrome, Chromium, or Edge; --browser or DEVTOOLS_BROWSER names an executable directly. GitHub's Ubuntu runners ship Chrome, so CI installs nothing.