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

@cerebralutopia/tap

v0.1.1

Published

Process supervisor with queryable logs

Readme

tap

A process supervisor with queryable logs. Run your services in the background and query their output through a Unix socket API.

Why tap?

  • Queryable logs: Filter, search, and paginate through output without log files
  • Ring buffer: Keeps recent output in memory with configurable limits
  • Unix socket API: Query logs programmatically from any language
  • Readiness checks: Wait for a pattern in output before considering a service ready
  • Zero dependencies at runtime: Pure Node.js with Unix sockets

Installation

npm install
npm run build

Platform Support: tap requires Unix domain sockets and POSIX signals, so it runs on macOS and Linux. Windows users should use WSL (Windows Subsystem for Linux).

Example Instructions for Coding Agents

The tap command is a process supervisor with queryable logs. Use it to monitor server processes, search logs for errors, and restart services.

# List running processes
tap ls                             # Shows name, state, PID, uptime

# View process status
tap status website --format text

# View logs
tap observe website --last 50           # Last 50 lines
tap observe website --since 5m          # Logs from last 5 minutes
tap observe website --stream stderr     # Only stderr output
tap observe website --show-seq --show-stream  # With sequence numbers and stream labels

# Search logs
tap observe website --grep "error"                    # Substring search
tap observe website --grep "error|warning" --regex    # Regex search
tap observe website --grep "Error" --case-sensitive   # Case-sensitive

# Restart a process (useful for workers that don't hot reload)
tap restart website
tap restart worker          # Worker process requires restart after code changes

When to restart processes:

  • Worker processes: Don't hot reload. After modifying worker code, use tap restart worker.
  • Next.js server: Restart after running npx prisma generate to pick up the regenerated Prisma client. Use tap restart website.

Quick Start

# Start a service
tap run myapp -- node server.js

# View recent logs
tap observe myapp --last 50

# Check status
tap status myapp

# Restart the service
tap restart myapp

# Stop everything
tap stop myapp

Multi-Directory Support

tap automatically discovers services across subdirectories. This is useful for monorepos or projects with multiple components.

Service Naming

Services in subdirectories use a colon-separated prefix:

| Socket Location | Service Name | |-----------------|--------------| | .tap/api.sock | api | | frontend/.tap/web.sock | frontend:web | | backend/.tap/api.sock | backend:api | | services/auth/.tap/main.sock | services/auth:main |

Example: Monorepo Setup

# Start services in different directories
cd ~/myproject
tap run frontend:dev -- npm run dev    # Creates frontend/.tap/dev.sock
tap run backend:api -- node server.js  # Creates backend/.tap/api.sock
tap run worker -- node worker.js       # Creates .tap/worker.sock

# List all services from project root
tap ls
# NAME              STATE       PID       UPTIME
# ------------------------------------------------
# frontend:dev      running     12345     5m 30s
# backend:api       running     12346     5m 28s
# worker            running     12347     5m 25s

# Query any service by name
tap observe frontend:dev --last 20
tap status backend:api
tap restart worker

Disabling Discovery

Use --tap-dir to target a specific directory (disables recursive search):

tap ls --tap-dir ./backend/.tap
tap observe api --tap-dir ./backend/.tap

Commands

tap run

Start a runner server and child process.

tap run <name> [options] -- <command...>

Arguments:

| Argument | Description | |----------|-------------| | <name> | Service name (e.g., "api" or "frontend:api") |

Options:

| Option | Description | Default | |--------|-------------|---------| | --tap-dir <path> | Override .tap directory | ./.tap | | --cwd <path> | Working directory for child | Current directory | | --env <KEY=VAL> | Add/override env var (repeatable) | - | | --env-file <path> | Load env vars from file | - | | --pty | Use PTY for child process | Off | | --no-forward | Don't forward output to stdout | Forward on | | --buffer-lines <N> | Ring buffer max events | 5000 | | --buffer-bytes <N> | Ring buffer max bytes | 10000000 | | --ready <pattern> | Substring to wait for in output | - | | --ready-regex <regex> | Regex to wait for in output | - | | --print-connection | Print socket path and PID on startup | Off |

Examples:

# Basic usage
tap run api -- node server.js

# With environment variables
tap run api --env PORT=3000 --env NODE_ENV=production -- node server.js

# With env file and readiness check
tap run api --env-file .env --ready "listening on port" -- node server.js

# With PTY (for programs that need a terminal)
tap run app --pty -- npm run dev

tap observe

Fetch logs from a running service.

tap observe <name> [options]

Arguments:

| Argument | Description | |----------|-------------| | <name> | Service name (e.g., "api" or "frontend:api") |

Options:

| Option | Description | Default | |--------|-------------|---------| | --tap-dir <path> | Override .tap directory | - | | --since <duration> | Events since duration ago (e.g., 5m, 1h) | - | | --last <N> | Last N events | 80 | | --since-cursor <seq> | Events since cursor sequence | - | | --since-last | Since last observed cursor | - | | --grep <pattern> | Filter by pattern | - | | --regex | Treat grep as regex | Off | | --case-sensitive | Case-sensitive matching | Off | | --invert | Invert match | Off | | --stream <type> | Filter: combined, stdout, stderr | combined | | --max-lines <N> | Max lines to return | 80 | | --max-bytes <N> | Max bytes to return | 32768 | | --format <type> | Output format: text, json | text | | --json | Output JSON | Off | | --show-seq | Prepend sequence number to each line | Off | | --show-ts | Prepend relative timestamp to each line | Off | | --show-stream | Prepend stream (stdout/stderr) to each line | Off |

Examples:

# Get last 100 lines (text format is default)
tap observe api --last 100

# Get logs from the last 5 minutes
tap observe api --since 5m

# Search for errors
tap observe api --grep "error" --case-sensitive

# Get only stderr
tap observe api --stream stderr

# Continuous polling (since last cursor)
tap observe api --since-last

# With sequence numbers and stream info
tap observe api --show-seq --show-stream

# JSON output
tap observe api --json

Sample output (text):

Server started on port 3000
Handling request GET /api/users
---
cursor=25 truncated=false dropped=false matches=2

The --- line separates log content from metadata for easy parsing.

tap restart

Restart the child process without stopping the runner.

tap restart <name> [options]

Arguments:

| Argument | Description | |----------|-------------| | <name> | Service name (e.g., "api" or "frontend:api") |

Options:

| Option | Description | Default | |--------|-------------|---------| | --tap-dir <path> | Override .tap directory | ./.tap | | --timeout <duration> | Readiness wait timeout | 20s | | --ready <pattern> | Substring readiness pattern | - | | --ready-regex <regex> | Regex readiness pattern | - | | --grace <duration> | Grace period before SIGKILL | 2s | | --clear-logs | Clear ring buffer on restart | Off | | --format <type> | Output format: json, text | json |

Examples:

# Simple restart
tap restart api

# Restart with readiness check
tap restart api --ready "listening on port" --timeout 30s

# Clear logs on restart
tap restart api --clear-logs

tap stop

Stop the runner and child process.

tap stop <name> [options]

Arguments:

| Argument | Description | |----------|-------------| | <name> | Service name (e.g., "api" or "frontend:api") |

Options:

| Option | Description | Default | |--------|-------------|---------| | --tap-dir <path> | Override .tap directory | ./.tap | | --timeout <duration> | Request timeout | 5s | | --grace <duration> | Grace period before SIGKILL | 2s | | --format <type> | Output format: json, text | json |

Examples:

# Stop a service
tap stop api

# Stop with longer grace period
tap stop api --grace 10s

tap status

Get runner and child status.

tap status <name> [options]

Arguments:

| Argument | Description | |----------|-------------| | <name> | Service name (e.g., "api" or "frontend:api") |

Options:

| Option | Description | Default | |--------|-------------|---------| | --tap-dir <path> | Override .tap directory | ./.tap | | --timeout <duration> | Request timeout | 5s | | --format <type> | Output format: json, text | json |

Examples:

# Get status as JSON
tap status api

# Get human-readable status
tap status api --format text

Sample output (text):

Name: api
State: running
Runner PID: 12345
Child PID: 12346
Uptime: 2h 15m 30s
PTY: false
Forward: true
Buffer: 1234/5000 lines, 256KB/9765KB

tap ls

List all known services. Recursively discovers services in subdirectories.

tap ls [options]

Options:

| Option | Description | Default | |--------|-------------|---------| | --tap-dir <path> | Override .tap directory (disables recursive search) | - | | --format <type> | Output format: json, text | text |

Examples:

# List all services (recursive)
tap ls

# List as JSON
tap ls --json

# List only services in a specific directory
tap ls --tap-dir ./backend/.tap

Sample output:

NAME                STATE       PID       UPTIME
----------------------------------------------------
api                 running     12345     2h 15m 30s
frontend:web        running     12348     1h 20m 15s
backend:worker      running     12350     1h 45m 12s

How It Works

┌─────────────────────────────────────────────────────────┐
│                     tap run                             │
│  ┌─────────────────────────────────────────────────┐   │
│  │              Runner Server                       │   │
│  │  ┌──────────┐    ┌──────────────────────────┐   │   │
│  │  │  Child   │───▶│      Ring Buffer         │   │   │
│  │  │ Process  │    │  (stdout/stderr lines)   │   │   │
│  │  └──────────┘    └──────────────────────────┘   │   │
│  │       │                        │                │   │
│  │       ▼                        ▼                │   │
│  │   [forward]              Unix Socket            │   │
│  │       │                   (.tap/name.sock)      │   │
│  └───────│────────────────────────│────────────────┘   │
│          ▼                        │                    │
│       stdout                      │                    │
└───────────────────────────────────│────────────────────┘
                                    │
                                    ▼
                    ┌───────────────────────────────┐
                    │   tap observe / status / ...  │
                    │        (HTTP over UDS)        │
                    └───────────────────────────────┘
  1. Runner: The tap run command starts a runner process that:

    • Spawns and manages a child process
    • Captures stdout/stderr into a ring buffer
    • Exposes a Unix socket HTTP API
  2. Ring Buffer: Keeps the last N lines (default 5000) or N bytes (default 10MB) of output in memory. Old entries are evicted when limits are reached.

  3. Unix Socket API: All commands except run communicate with the runner over HTTP via Unix domain sockets at .tap/<name>.sock.

  4. Readiness: The runner can watch for a pattern in output to determine when the child is ready, useful for deployment scripts.

Security Model

The trust boundary is filesystem access to the .tap/ directory.

Anyone who can read/write to the .tap directory can fully control all tap processes in that directory:

  • Query logs from any service
  • Restart any child process
  • Stop any runner

Protections

  • The .tap/ directory is created with mode 0700 (owner-only access)
  • Service names are validated to prevent path traversal attacks
  • Regex patterns are validated to prevent ReDoS attacks
  • Request body sizes are limited to prevent memory exhaustion

Implications

| Environment | Security | |-------------|----------| | Single-user machine | Secure - only you can access your .tap/ directory | | Multi-user, separate working dirs | Secure - each user has their own .tap/ | | Shared directory (e.g., /tmp) | Not secure - anyone with directory access controls your processes |

Not Protected Against

  • Root: By design, root can access anything
  • Same-user processes: Other processes running as your user can access the socket
  • Parent directory access: Users with write access to the parent of .tap/ could potentially manipulate it

This follows the standard Unix security model used by SSH agent sockets, Docker sockets, and tmux.

License

MIT