Hi all,
I’m releasing probex, a small dependency-free CLI built for one purpose: coding agents working on Elixir burn a meaningful share of their tokens — and their wall-clock — just re-reading code by guesswork. probex removes that tax. The same task completes in fewer calls, with smaller payloads, and without the re-reads.
Where the tokens actually go
Watch an agent work on a large Elixir codebase and a pattern repeats all day:
grep -nto find where a function starts — grep can’t say where it ends;- guess a window:
sed -n '148,200p'; - the window clips the block (or drags in three neighbours), so read again, wider;
- repeat per function, per file, per task.
Every guessed window is paid for in tokens whether or not it was the right window, every miss is paid for twice, and every one of those calls is a full agent round-trip. Mining one week of our agent transcripts found 2,369 windowed reads with a median window of 54 lines — for answers that are usually a dozen lines, exactly bounded, and known to the parser all along.
probex asks the parser instead:
$ probex body lib/accounts.ex register_user/2
lib/accounts.ex:148-163 def register_user/2 [defmodule MyApp.Accounts]
def register_user(attrs, opts \\ []) do
...
end
Exact boundaries, so a heredoc containing end, a sigil containing a fake def, or a keyword-form body can’t produce a clipped read. And one call takes many files × many selectors, so what used to be a shell loop of N reads is one round-trip:
probex body lib/a.ex lib/b.ex changeset/2 valid?/1 # both blocks, in both files
probex body lib/ handle_info/2 # every match under a directory
probex outline big_test.exs --kind describe,test # exact TOC, no bodies
probex cover my_app --fun register_user/2 --body # did my new test go green?
The same economics drove every command: outline replaces “read the first 200 lines to orient”; directives replaces the header-window read; cover replaces the most reinvented wheel in our transcripts (agents writing one-off coverage-HTML parsers) with uncovered lines attributed to the functions that contain them, reconciling with mix test.coverage including :ignore_modules. Errors are budgeted too: a miss returns the corrected command or the list of what does exist, so the next call is the answer instead of another probe.
Reading commands parse, never compile — no mix, no deps, no app boot — so they work mid-refactor on files that don’t currently build.
How it was built (the part I find fun)
No feature came from a human wishlist. It started with me being annoyed at the token bill; the ask was one sentence — this is wasteful, improve it. Every decision after that was the agents’:
- The feature set was mined from the agents’ own shell transcripts — the most repeated waste became the founding commands.
- Nothing ships without measured demand: invocations are logged (opt-in,
PROBEX_LOGFILE),probex statsreports which commands and options get used and which never do, and an end-of-day skill mined each day’s sessions for gaps and proposed extensions. An early intuition-ranked roadmap got its top pick wrong; evidence has decided ever since. - Agents improve it for agents: feedback filed by the agents using it, fixes made by agents with the test suite as the north star, and
probex prompt --writeinstalls the instructions intoAGENTS.md/CLAUDE.mdfrom the binary itself — a test fails if a flag exists that the prompt doesn’t teach.
My role: ask once, run the loop, and pay for the tokens.
Install
git clone https://github.com/pnezis/probex.git
ln -s "$PWD/probex/probex" /usr/local/bin/probex
probex prompt --write # teach it to your agents
Status: alpha, but not experimental — extracted from an internal tool used daily by a fleet of agents against a production monorepo.
License: MIT
If you run agents against elixir projects, try it and bring back your usage log: the entire project is an argument that agent tooling should be chosen by the agents’ measured usage, and your evidence makes it better. ![]()






















