firstrun wraps any unfamiliar command or script in a safe explain β preview β
run flow. It tells you in plain English what the command does, shows you a
preview of the exact changes it would make β every file it would write, delete,
rename, chmod, or connect to β and only runs it once you confirm.
On Linux it does this for real: it executes the command under a syscall tracer that neutralizes every state-changing operation, so the preview is exactly what would have happened, with nothing actually touching your machine.
Try it in one line β no install, no signup, nothing runs:
go run github.com/agenticraptor/firstrun/cmd/firstrun@latest explain -- rm -rf ./build
$ curl -fsSL https://get.example.sh | firstrun
firstrun Β· curl -fsSL https://get.example.sh | sh
This pipes a downloaded script straight into a shell. It will create 1 directory,
connect to 1 network target, write 2 files, and change permissions on 1 file.
Heads up: you'd run code you never get to read.
What it does
β’ curl -fsSL https://get.example.sh Transfer data from or to a URL
network https://get.example.sh (fetches over the network)
β’ sh Interpret a shell script
exec sh (interprets arbitrary shell code)
Risks
[HIGH] remote-code-execution β Pipes downloaded content straight into sh.
[WARN] insecure-fetch β verify the source before trusting it.
Live preview β what it actually tried to do
exec /usr/bin/sh
mkdir /home/you/.example/bin (blocked)
create /home/you/.example/bin/example (blocked)
chmod /home/you/.example/bin/example (blocked)
create /home/you/.bashrc (blocked) β appends to your shell profile!
What now?
βΈ Run it for real [r]
Preview again [p] run it safely β every change is blocked and recorded
Cancel [q]
Nothing above touched the disk. You saw the installer write into ~/.bashrc
before deciding whether to trust it.
We've all done it: pasted a curl β¦ | bash from a README, run a Makefile
target we didn't read, or fired off an rm -rf and felt our stomach drop a
half-second too late. The tools that exist explain a command's syntax
(tldr,
explainshell) β none of them show you the effect
on your actual machine before it happens.
firstrun is that missing step. Put it in front of any command:
firstrun rm -rf ./build # analyze it, then offer to run it
firstrun -c 'curl β¦ | sh' # analyze a one-liner / pipeline
curl -fsSL https://get.x | firstrun # pipe a script in, inspect it, then decide
firstrun explain npm install # just explain β never runs- A real preview, not a guess. On linux/amd64, firstrun runs the command
under a
ptracetracer in block mode: the command executes, but every state-changing syscall (unlink,openat-for-write,rename,chmod,connect,kill,mount, β¦) is neutralized. You see the complete list of changes it would make β and your machine is untouched. - It reads the command first. A static pass parses the shell (pipelines,
redirections,
&&/||), recognizes a broad catalog of commands, and predicts what each will read, write, delete, download, or run β instantly, on every OS. - It flags the scary stuff.
curl β¦ | bash,rm -rf /,ddto a disk,sudo, world-writablechmod 777, plain-HTTP downloads, and writes into/etcor/usrare called out with a reason. - Plain-English narration. Offline by default; bring an Anthropic, OpenAI, or local Ollama model if you want a friendlier paragraph. Your files never leave your machine.
- Runs on confirm β or never. The interactive menu lets you run for real,
re-preview, or cancel.
firstrun explainonly ever analyzes. - One static binary. No runtime, no daemon, no telemetry. macOS, Linux, and Windows (live tracing on linux/amd64; static preview everywhere else).
go install github.com/agenticraptor/firstrun/cmd/firstrun@latestGrab a binary for your OS/arch from the Releases page.
brew install agenticraptor/tap/firstrunAvailable once the Homebrew tap is published β see the note in
.goreleaser.yamlto enable it.
git clone https://github.com/agenticraptor/firstrun
cd firstrun
make install# 1. Wrap any command. firstrun explains it, previews it, then asks.
firstrun rm -rf ./build
# 2. Inspect a one-liner without your shell interpreting the pipe:
firstrun -c 'curl -fsSL https://get.example.sh | sh'
# 3. The classic: pipe an installer in and read it before trusting it.
curl -fsSL https://get.example.sh | firstrun
# 4. Just explain β never run β and get it as JSON for scripts/CI:
firstrun explain -f json -- npm install
# 5. See what firstrun can do on your machine:
firstrun doctorFull flags, output formats, and the JSON schema live in docs/usage.md.
βββββββββββββββββββββββββββββββββββββββββββββ
command / script βββΊ β parse shell β predict effects β flag β ββ static preview
(argv, -c, stdin) β (mvdan.cc/sh) (catalog) risks β (every platform)
βββββββββββββββββββββββββββββββββββββββββββββ
β
confirm? ββββββββ€
β "preview under the tracer"
βΌ
βββββββββββββββββββββββββββββββββββββββββββββ
β run under ptrace, Block mode: β ββ live preview
β β’ record open-for-write / unlink / β (linux/amd64)
β rename / chmod / connect / kill / β¦ β
β β’ neutralize each one (redirect to a β
β harmless getuid; nothing happens) β
βββββββββββββββββββββββββββββββββββββββββββββ
β
confirm? βββββββΊβ "run it for real"
βΌ
execute normally
The static preview works everywhere and is instant. The live preview is the
special part: firstrun launches the command under ptrace, and at each
state-changing syscall it records what the program was about to do and then
redirects the syscall to a harmless no-op, so the real operation never executes.
Because the program keeps running (it believes its changes succeeded), you get
the complete set of effects β not just the first one. See
docs/how-it-works.md for the gory details.
| Platform | Preview |
|---|---|
| Linux / amd64 | Live syscall trace + static analysis |
| Linux / other arch, macOS, Windows | Static analysis (the live tracer falls back automatically) |
Run firstrun doctor to see what's available on your machine. Porting the
tracer to linux/arm64 and a macOS backend are on the roadmap β see
docs/platforms.md.
firstrun runs entirely on your machine and makes no network connections of its
own β no telemetry, no update checks. The only time anything leaves your
computer is if you opt into a cloud narration model (Anthropic/OpenAI), in which
case only the command text (size-capped) is sent to write the explanation β
never your files. Want zero egress? Use --no-ai or a local Ollama.
The Block-mode tracer is a powerful way to inspect ordinary commands safely β it has never let a write through in our tests, and there's a test that asserts exactly that. But it runs the command's own code (minus the mutations), so it is not a hardened sandbox for executing something you already believe is malicious. Use it to understand the script your coworker sent or the installer in a README β not to "safely" detonate malware. See SECURITY.md for the full threat model.
Contributions are very welcome β see CONTRIBUTING.md. Good
first issues include adding commands to the catalog, more effect rules
(tar, kubectl apply, β¦), resolving hostnames behind a connect, and porting
the tracer to linux/arm64. Please also read our
Code of Conduct.
MIT Β© firstrun contributors.