@factor-i-o/light-tools-linux-x64
v0.5.0
Published
Native light-tools binary for linux/x64.
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-toolsRequires Node 18.17+ and npm 10+. Or build it directly:
go install -tags treesitter github.com/icediceice/light-tools/cmd/light-tools@latestThen 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-toolsstarts 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 FAILEDA 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_scpA 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 -updateTen 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 question — which 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 | shInvoke-WebRequest https://raw.githubusercontent.com/icediceice/light-tools/main/install.ps1 -OutFile install.ps1
./install.ps1Pin 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
- AGENT-SETUP.md — full setup procedure
- SECURITY.md — what is and is not protected
- docs/REFERENCE.md — exact tool and verb semantics
- RELEASING.md — release process
Created by Factor I/O Studio. light-tools is one component of the Light stack, extracted to stand alone.
GPL-3.0-or-later.
