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

@fasaled/muin

v0.3.0

Published

Explore a PDF’s internals from the terminal — objects, streams, page tree, and cross-references — as a navigable graph. Interactive TUI, one-shot commands, and an MCP server for agents.

Readme

Muin

Explore a PDF’s internals from the terminal — indirect objects, streams, page tree, and cross-references — as a navigable graph.

npm install -g @fasaled/muin
# or
bun add -g @fasaled/muin

muin document.pdf
muin document.pdf check
muin document.pdf ls 3 0 R
muin document.pdf find --type Stream --where "/Filter == /FlateDecode"
muin --mcp
muin --mcp document.pdf          # optional: pre-open this file
muin --mcp --events live.jsonl  # journal every operation; watch it with `muin --follow live.jsonl`
muin --follow live.jsonl        # read-only observer of a journaled agent session
muin --max-bytes 10485760 document.pdf
muin help
muin --help

Requires Node.js 18+. Encrypted PDFs are not supported.

The package is @fasaled/muin; the command is still muin.

TUI

muin document.pdf opens a full-screen explorer: the current object’s neighborhood (incoming / current / outgoing refs), the object itself, and a command box. Those panes redraw in place on cd / back and never scroll.

  • Tab completes and cycles command, flag, and reference candidates. Shift+Tab changes focus between the prompt, graph, and object.
  • With the graph focused, ←/→ pick a pane, ↑/↓ pick a neighbor, Enter is cd <ref>.
  • Any other command (find, tree, check, help, history, cat, stream, …) opens a dismissible overlay. If it is taller than the screen, ↑/↓/PageUp/PageDown scroll it; Esc closes it.
  • The command panel shows the initial command list, file, cwd, active operation, queue, and last executed command (last:). History is persistent in ~/.config/muin/history.json; commands submitted while busy are queued and run in order.

If stdin is not a TTY, Muin uses a line-oriented REPL instead of the TUI.

One-shot commands (muin file.pdf check) open the file, run one verb, and exit. They do not keep cd state.

MCP

muin --mcp is a long-lived server. The agent calls open with a PDF path, then ls / cd / find / … on that session, then close. muin --mcp document.pdf pre-opens that file.

Observing an agent session

muin --mcp --events live.jsonl appends one JSON line per operation (tool, args, outcome, cwd snapshot, truncated preview) to the journal file — 0600, best-effort, never in the agent's way. Configure it once in the agent's MCP server args; the agent itself never sees it. Every successful open rotates a non-empty journal aside (live-<timestamp>.jsonl next to it) and starts fresh, so each opened PDF gets its own file; restarts and probes without an open never rotate. The follower detects the rotation and restarts its timeline. Backups are kept — delete them when done, or replay one with muin --follow <backup>.

muin --follow live.jsonl opens a read-only TUI on that journal: it opens its own session on the PDF and mirrors the agent's navigation, showing each operation as a scrubbable timeline. There is no prompt and no history — commands cannot be typed. ←/→ step through operations, Space auto-plays at a human pace (default 1 op/s, +/- adjust between 100 ms and 5 s), g/G jump to the first/last, overlay scrolling and Esc/Ctrl+C behave like the TUI. The header badge always shows the mode: ▶ play (green), ■ paused (yellow), … waiting (dim), ! diverged (red, mirror disagrees with the journal). Without a TTY, --follow prints operations line-by-line instead.

Shell completion

# bash (current session)
eval "$(muin completion bash)"

# zsh
mkdir -p ~/.zfunc
muin completion zsh > ~/.zfunc/_muin
# then in ~/.zshrc: fpath=(~/.zfunc $fpath) && autoload -Uz compinit && compinit

# fish
mkdir -p ~/.config/fish/completions
muin completion fish > ~/.config/fish/completions/muin.fish
# PowerShell 5.1+ / pwsh — current session
muin completion powershell | Out-String | Invoke-Expression

Completes flags, *.pdf files, and one-shot command names. The interactive TUI also completes multi-token object references from the current neighborhood without opening another PDF.

Commands

| Command | TUI | MCP | One-shot | |---|---|---|---| | ls cd pwd back refs neighbors cat stream find tree check help | yes | yes | yes | | open / close | no | yes | no | | export_graph | JSON text | yes | yes | | quit / exit | yes | no | no |

cd accepts O G R, O,G, a dictionary key (/Pages), or an array index.

Use Cases

  • Batch integrity checking: Run muin file.pdf check across files in scripts or invoke check via MCP. Powered by QPDF's validation engine in WebAssembly, it detects xref table corruption, stream syntax errors, format anomalies, and dangling object references.
  • Debugging PDF generators: Inspect documents generated by PDFKit, Typst, WeasyPrint, ReportLab, or custom engines. Navigate the internal object tree (/Catalog -> /Pages -> /Contents) like a directory hierarchy to inspect keys, dictionaries, and resource dictionaries.
  • Resource and stream diagnostics: Query objects and stream attributes (e.g. find --type Stream --where "/Length > 1000000") to inspect uncompressed payloads, font descriptors, and image XObjects (/Width, /Height, /Filter).
  • Metadata and structure inspection: Inspect document info dictionaries, XMP metadata streams, accessibility trees (/StructTreeRoot), and dictionary action entries (/JavaScript, /Launch, /URI) without rendering the document.
  • Agent-assisted analysis (MCP): Provide LLM agents with structured, targeted access to navigate the object graph, inspect subgraphs (export_graph), and extract specific streams on demand without loading raw binary files into the context window.

Limits (defaults)

  • Max input file: 200 MiB (--max-bytes). Size is checked with stat before the file is read.
  • Max objects: 200_000
  • Max structure JSON: 512 MiB (object graph only; stream bodies are not loaded at open)
  • export_graph: default depth 2, max depth 8, max 5_000 nodes

License

MIT. Source: github.com/fasaled/muin