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

trail-sh

v0.1.0

Published

The flight recorder for agent runs. A durable, multi-writer, append-only run log that is just a URL.

Readme

The one-liner

curl -d "migration started" https://trail.legible.sh/swift-otter-9921

That topic now exists. Open https://trail.legible.sh/swift-otter-9921 in a browser and it is a live journal — dark, monospace, auto-following. curl it and it is plain text. Tomorrow it is still there. Paste it into the PR.

The hosted API at trail.legible.sh is in soft launch. To run the identical API yourself, npx trail-sh serve starts it locally; every example below works with http://127.0.0.1:4182 in place of https://trail.legible.sh.

Why

You kick off a long agent run — a migration, a fleet of workers, a Claude Code session on a box you are about to walk away from — and the record of what happened lives in a scrollback buffer that dies with the terminal. Screen-sharing tools mirror the session but can't be handed to a teammate, don't merge five workers into one story, and vanish when the session does. trail is the other thing: not a window into the terminal, but a paper trail. Any process appends with one curl. Everyone reads from the same URL. It is still there tomorrow.

The whole API

| Request | What it does | | --- | --- | | POST /{topic} | Append. Each newline-separated line in the body becomes an entry. Optional headers X-Level: info\|warn\|error\|done, X-Actor: worker-3 (or ?level=&actor=). Returns {"seq": 7} — the last assigned sequence number. | | GET /{topic} | The journal. Browsers get the live HTML page (SSE follow, auto-scroll, level colors, actor labels). curl gets plain text, one line per entry: at level actor \| text. Accept: application/json gets JSON. | | GET /{topic}.txt | Always plain text, for piping. | | GET /{topic}.json | Always JSON: {"topic", "entries": [{seq, at, actor, level, text}]}. | | GET /{topic}/sse?since=SEQ | SSE stream: named entry events (JSON data, id: = seq), a deleted event if the journal is removed, heartbeat comments every 25s. since=0 replays the full backlog, then follows. Also served on GET /{topic} with Accept: text/event-stream. | | DELETE /{topic} | Delete the journal (needs the token if the server has one). | | GET /README.md, GET /llms.txt | This document (text/markdown) and a machine-readable index — never token-gated. GET / with Accept: text/markdown also returns the README. |

Query params on reads: ?n=100 (last N), ?since=SEQ (entries after SEQ), ?wait=30 (long-poll: hold up to 30s for the next entry). Topics match [a-zA-Z0-9_-]{1,64} and are created by first write. Errors are JSON: {"error": "...", "code": "...", "hint": "..."} — the hint spells out the correct next request.

Teach your agent

Paste this into your CLAUDE.md / AGENTS.md and your agent knows the whole tool:

# trail — append-only run journal, plain HTTP (https://trail.legible.sh, or self-hosted; set base URL accordingly)
# Append one or more lines (topic is created on first use; pick an unguessable name):
curl -d "build started" https://trail.legible.sh/TOPIC
# Optional headers: X-Level: info|warn|error|done and X-Actor: worker-3
curl -d "tests red" -H "X-Level: error" -H "X-Actor: ci" https://trail.legible.sh/TOPIC
# Read back: plain text, last N, or JSON:
curl https://trail.legible.sh/TOPIC.txt?n=100
curl https://trail.legible.sh/TOPIC.json
# Follow live (SSE), or long-poll for entries after seq 42:
curl -N https://trail.legible.sh/TOPIC/sse?since=0
curl "https://trail.legible.sh/TOPIC.json?since=42&wait=30"
# Humans watch the same URL in a browser. Log key events, not every token.
# Finish runs with: curl -d "exit 0" -H "X-Level: done" https://trail.legible.sh/TOPIC

Watch a Claude Code session from your phone

examples/claude-hooks.sh wires Claude Code's PostToolUse and Stop hooks to a topic — one line per tool call, a done line when the session ends. Open the topic URL on your phone; that's the whole integration. No account, no app, no tunnel. Run ./examples/claude-hooks.sh demo against a local server to see the page with fake data first.

Self-hosting

npx trail-sh serve                  # http://0.0.0.0:4182, in-memory
trail serve --data-dir ./trail-data # durable: JSONL per topic, replayed on boot
trail serve --token s3cr3t          # writes/deletes need Authorization: Bearer s3cr3t
trail serve --port 8080 --host 127.0.0.1 --base-url https://trail.example.com

Or clone and run: git clone https://github.com/legible-sh/trail && cd trail && npm start. There is nothing to install — zero dependencies, Node 20+.

Without --data-dir, journals live in memory and die with the process. With it, every entry is appended to <data-dir>/<topic>.jsonl and replayed on boot. Either way the last 10,000 entries per topic are served; older ones are evicted from memory (all limits are constants in src/limits.mjs).

CLI

The CLI is sugar over the same HTTP API — curl remains the contract. It targets --url, else $TRAIL_URL, else https://trail.legible.sh; --token / $TRAIL_TOKEN add the bearer token.

trail log deploy-7 "smoke tests green" --level done --actor ci
trail tail deploy-7                    # follow live in the terminal (--since SEQ)
trail pipe deploy-7 -- npm test        # run a command, tee every output line into the journal
make build 2>&1 | trail pipe deploy-7  # or tee stdin
trail serve                            # run a server

trail pipe records stdout as info, stderr as warn, and finishes with an exit N entry — done for zero, error otherwise — while passing everything through, so it drops into existing pipelines.

Pro

Planned for the hosted instance, never gating the core verbs (self-host stays complete):

  • Retention beyond 7 days / 10,000 lines per topic.
  • Read tokens for genuinely private journals (today privacy = unguessable names).
  • Full-text search across your topics — "which run touched users.sql?"
  • Orgs: reserved topic prefixes, per-seat pricing, one bill.

Straight talk

  • Unguessable names are the access model. Anyone with the URL can read, and (without --token) write. That is capability-by-obscurity — the same honest deal as ntfy.sh. Don't log secrets; use --token and a private network when it matters.
  • Reads are never token-gated. The shareable journal URL is the product, so --token protects writes and deletes only. If your logs themselves are sensitive, self-host somewhere private — read tokens are on the Pro path.
  • --data-dir files grow until you DELETE. Memory serves the last 10,000 entries per topic; the JSONL file underneath keeps everything until the journal is deleted. Rotate by deleting or by starting a new topic per run (recommended anyway).
  • Ordering is per-server arrival order. Sequence numbers are assigned on arrival at one server; there is no distributed clock and no cross-topic ordering.
  • No WebSocket. SSE, long-poll, and one-shot GET cover every client we've met, and the zero-dependency constraint is worth more than a fourth transport.

The family

trail is one of the legible primitives, each a single npm package honoring the same principles: the URL is the API, curl is the SDK, zero ceremony.

| | port | | | --- | --- | --- | | gate | 4180 | ntfy tells you things. gate asks you things. | | bigred | 4181 | The big red button for your agent fleet. | | trail | 4182 | The flight recorder for agent runs. | | slate | 4183 | The blackboard from the multi-agent papers, as a URL. | | relay | 4184 | The work queue your agents can provision themselves. | | mutex | 4185 | flock(1) for agents that live on different machines. | | quorum | 4186 | Coordination for agents that do not share a parent process. | | meter | 4187 | The kill-brake for agent spend. 429-as-a-service. | | stash | 4188 | ntfy moves signals. stash moves bytes. | | tally | 4189 | StatHat reborn as ntfy. Three months too late — or right on time. |

License

MIT