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

@factor-i-o/light-tools-darwin-arm64

v0.5.0

Published

Native light-tools binary for darwin/arm64.

Readme

light-tools

Better file and shell tools for coding agents. Read less, write less, waste fewer turns.

Your coding agent should not need to read a 2,000-line file to change 5 lines. It should not need five separate tool calls to read five files it already knows it needs. And it should not dump thousands of log lines into context just because a command was noisy.

light-tools replaces the basic file and shell tools used by coding agents with versions designed for AI work. It speaks MCP, runs as one Go binary, and needs no daemon or database.

Install

npm install --global @factor-i-o/light-tools

Requires Node 18.17+ and npm 10+. Or build it directly:

go install -tags treesitter github.com/icediceice/light-tools/cmd/light-tools@latest

Then register it with your agent and restart:

light-tools init --client claude

--client antigravity and --client print are also supported. light-tools is a stdio server started with the session, so there is no daemon to manage. Full procedure: AGENT-SETUP.md.

Important: do not disable your agent's native file and terminal tools until you have confirmed light-tools starts correctly and you have a fallback. An agent with no native tools may be unable to repair its own setup.

What changes?

Read several files in one go

If the agent needs code from several files, it can read the relevant parts together in one call instead of fetching them one by one. Large files are paged, with an exact [CONTINUE] cursor when more content exists. A single-path read — one file window or one named-symbol read — arrives in whichever shape is smaller: plain text with a one-line summary (hash, next page, size), or the JSON envelope when that wins, and it carries the full declaration — signature, doc comment and exact source span. Multi-file batch reads use a compact plain grammar and skip that comparison.

Change only the code that changed

Many old/new replacement tools make the model output both the code being replaced and the replacement. light_file can edit by span: point at the lines or symbol, then send only the new content — roughly half the edit payload when the two blocks are a similar size, on the more expensive output side.

Every file mutation is snapshotted first, so a bad edit can be restored.

Do not send the same file twice

If the agent reads a file again and the content has not changed, light_file returns a short dedup notice instead of the same bytes — and the notice names force:true, the one-call way back to the bytes if the agent no longer holds them. If the file changed, it is sent normally.

Collapse repetitive command output

Sixteen service restarts, buried in lines that differ only by a counter:

… systemd[2158]: light-edge.service: Scheduled restart job, restart counter is at 599.
… systemd[2158]: light-edge.service: Scheduled restart job, restart counter is at 600.
(14 more, each identical but for the number)

becomes:

[L1-16]       light-edge.service: Scheduled restart job, restart counter is at ▪1.  ×16
    ▪1: 599..614  (16 values, +1 each)

No two of those lines are byte-identical, so deduplication collapses nothing. Grouping by shape is what turns sixteen buried restarts into a stated range.

Whatever occurred only once is still there. 500 compile lines and a verdict:

[L1-500]      compiling module ▪1 of 500  ×500
    ▪1: 0..499  (500 values, +1 each)
[L501]        BUILD FAILED

A verdict is a singleton by nature — it is the line you came for, and it survives verbatim.

light_bash, light_ssh, light_ops and light_file (file read windows) all do this. Both samples above are generated by go test ./internal/logs/, not written by hand.

Keep oversized output out of context

When a stream is compacted, or is too large to return whole, the exact bytes go to an indexed spill and the result carries a ready-made read_block call to recover them.

Elision always implies recovery: if no spill can back a view, the exact output comes back instead. LIGHT_NO_COMPACT=1 restores the pre-compaction result shape exactly.

The goal is not to hide information. It is to stop paying the context cost before the agent knows whether it needs that information.

The tools

| Tool | What it does | | --- | --- | | light_file | Read, search, inspect symbols and edit files without unnecessary full-file traffic | | light_bash | Run local commands with bounded, searchable output | | light_ssh | Run commands on a remote host through a named profile | | light_scp | Copy files to or from a remote host through a named profile | | light_ops | Read-only service, port and log inspection |

All five register by default. You can withhold tools completely:

light-tools --disable-tool light_ssh --disable-tool light_scp

A disabled tool is not registered, so the model cannot call it.

Works with your existing code intelligence

light-tools is not a replacement for code search, indexing, language servers or repository intelligence. Use whatever code-intelligence layer you prefer.

light-tools handles a different part of the problem: how the agent reads, writes and operates on the machine after it knows what it wants to do.

Safety and reliability

Coding agents make ordinary mistakes: wrong field names, misspelled verbs, malformed values and overly broad shell commands. light-tools tries to make those mistakes cheap without silently guessing about dangerous mutations.

  • obvious argument mistakes can be repaired and reported back to the model
  • ambiguous or dangerous mutations are refused instead of guessed
  • file writes are snapshotted before mutation
  • disabled tools are not registered at all
  • errors point at the failing field or payload location and tell the caller what to fix
  • filesystem access can be limited with allowed_roots

Mutation safety

Modeled mutations are enumerated before execution whether they name explicit paths (rm a.tmp b.tmp) or an unquoted glob (rm *.tmp). When the whole surface can be durably captured, the command runs on first contact and returns a working vault_restore handle. A surface that cannot be protected still runs but reports why — except an unprotectable unquoted glob, the one case that refuses outright, naming the blocker and binding an unbacked retry to that exact expanded surface with a digest.

Confinement is not a shell sandbox. allowed_roots bounds light_file paths, local SCP endpoints and caller-supplied light_ops paths. light_bash has its working directory bounded, but the commands it runs can still reach outside that directory.

Read SECURITY.md before treating confinement as a security boundary. Exact argument-repair, continuation, spill, snapshot and confinement semantics live in docs/REFERENCE.md.

Measurement

There is a reproducible benchmark in this repository. It measures one thing: for a fixed question, how many bytes have to be delivered into a model's context to answer it — with light-tools, and without.

go test -tags treesitter ./internal/bench/ -run TestBenchmarkReport -update

Ten scenarios across two tracks, three arms each: native-naive (return the whole file, the whole stream), native-skilled (grep first, then read a window), and light-tools as it ships. Every scenario carries one pattern per clause of its questionwhich file broke, and what was the error is two facts, and both must survive in what the arm delivered. An unmarked row that loses a clause fails the suite rather than becoming a headline. Two exceptions are named explicitly: a row marked a known loss must keep failing to answer and must still carry a pointer to the exact bytes, and a repeat-read row proves the first read carried the answer instead.

Against a naive baseline the reductions are large: a 2.0 MB access log to 570 B, a 339.9 KB journal to 606 B, a 19.3 KB source file to a 704 B symbol.

Against a skilled baseline the picture is mixed, and that is the honest number:

| | Log reading | Code reading | | --- | :---: | :---: | | Rows where both arms answered | 2 of 5 | 4 of 5 | | ├ light-tools delivered less | 1 | 2 | | └ light-tools delivered more | 1 | 2 | | Skilled baseline did not answer | 2 | 0 | | light-tools did not answer | 1 | 0 | | Held out (repeat read, different baseline) | 0 | 1 |

Only rows where both arms answered are compared on bytes. A baseline that missed the question is not counted as a byte win for light-tools — being answered by one tool and not the other is a capability difference, and inflating the byte tally with it would be the same trick this benchmark exists to avoid.

Where a question already names the string it is looking for, grep is the right tool and wins. Compaction earns its place in the other case — when you cannot name the string yet, because you do not know what is in the log. Round trips are counted separately: several rows where light-tools sends more bytes still answer in one call where the baseline needs two, or six.

The benchmark also reports a case light-tools loses. Template collapse summarises each variable slot independently, so a rare correlation across two slots is lost: shown 20,000 access-log lines, the view states that a 500 occurred and that several paths exist, but not which path returned it. That row is in the table, marked, with the mechanism explained, and its assertion is inverted so the limitation cannot go stale unnoticed.

Full results, methodology and limitations — including that the corpora are synthetic and that this measures delivered context, not task success — are in docs/BENCHMARK.md.

Local counters

Separately, light-tools counts its own savings locally: terse output tokens, read-dedup bytes, write bytes versus a full rewrite, and — new in v0.4.0 — the bytes handed to output compaction against the bytes handed back.

A local sample over 45 tool calls in three throwaway sessions on this repository recorded 12,194 terse-output tokens, 164,087 B of read dedup and 116,363 B saved against a full rewrite. Those are self-reported one-sided counters with no baseline arm: they say what was saved relative to this tool's own alternative path, and they cannot support a with/without claim. The benchmark above is the measurement to quote. A small sample is not a benchmark or an extrapolated rate.

For scale, the broader Light stack — a larger, separate deployment using the same targeting and output-reduction approach — delivered about 84% less of its considered corpus into model context across 319K tool calls, with partial instrumentation: corpus size measured on 36.8% of calls and delivered size on 15.2%. That is a Light-stack measurement, not a light-tools one.

Local telemetry is aggregate-only: no paths, arguments, commands, hostnames or usernames are sent anywhere. Disable it with DO_NOT_TRACK=1 or a non-empty LIGHT_NO_TELEMETRY.

Platforms

| OS | amd64 | arm64 | Symbol extraction | | --- | --- | --- | --- | | Linux | native | native | tree-sitter | | macOS | native | native | tree-sitter | | Windows | native | native | tree-sitter on amd64; no-symbol fallback on arm64 |

Windows ARM64 is built without CGo. All five tools still work; only symbol and outline extraction degrade.

Other install options

Checksum-verifying installers are also available from published GitHub releases:

curl -fsSL https://raw.githubusercontent.com/icediceice/light-tools/main/install.sh | sh
Invoke-WebRequest https://raw.githubusercontent.com/icediceice/light-tools/main/install.ps1 -OutFile install.ps1
./install.ps1

Pin or relocate with -Version / -Destination on PowerShell or LIGHT_TOOLS_VERSION / LIGHT_TOOLS_INSTALL_DIR on POSIX. Both require an exact asset entry in checksums.txt.

More


Created by Factor I/O Studio. light-tools is one component of the Light stack, extracted to stand alone.

GPL-3.0-or-later.