Multi-pattern PCRE search for files, directory trees, and stdin — all patterns matched in a single pass.
hprscript is a command-line search tool built on Vectorscan, the portable open-source fork of Intel's Hyperscan regex engine. It scans any input — files, recursive globs, or arbitrary data piped on stdin — and matches all patterns simultaneously. One invocation of hprscript replaces N sequential grep/rg calls.
It is a single self-contained binary with no runtime dependencies beyond the platform C library. Builds for Linux (x86-64, ARM64) and macOS (Apple Silicon / Intel).
| Need | grep / rg | hprscript |
|---|---|---|
| Search for one regex | ✅ | ✅ |
| Search for N regexes in one scan | ❌ (run N times) | ✅ (one DFA, one walk) |
| Pattern-per-file output (JSON Lines) | ❌ | ✅ default |
| Cross-line block extraction (function bodies, JSON objects, JSX subtrees) | ❌ | ✅ |
| Multi-pass workflows in one process (collect → resolve) | ❌ | ✅ via phases |
| Per-file aggregation (counts, ranking, grouping) in one process | ❌ | ✅ via scripts |
| Files missing a pattern | grep -L |
-absent (also works inside scripts) |
| Pattern compile cost scales with N patterns | linear | constant — patterns share one DFA |
If you find yourself piping grep into grep, running ripgrep in a loop over a list of patterns, or writing throwaway Python to aggregate match counts per file, those are the workloads hprscript is designed for.
# Single pattern (default JSON Lines output)
hprscript -p "TODO" -glob "**/*.go"
# Multi-pattern in one pass — adding patterns is virtually free
hprscript -p "TODO" -p "FIXME" -p "XXX" -glob "**/*.go"
# Mix case-sensitive and case-insensitive in the same scan
hprscript -p '\bError\b' -pi 'todo|fixme' -glob '**/*.go'
# Pipeline use — content from stdin, no glob/files needed
curl -s https://example.com | hprscript -p 'href="[^"]+"' -o
kubectl logs my-pod | hprscript -p 'ERROR|panic' -C 2
# Extract every Go function body (signature + braces, balanced)
hprscript -p 'func \w+\(' -block-open '{' -block-close '}' -o '**/*.go'
# Files missing a license header (one pass, no scripting)
hprscript -p 'Copyright|SPDX-License-Identifier' -absent -glob '**/*.go'Default per-match record:
{"file":"main.go","pat":"p0","line":42,"col":5,"from":1023,"to":1027,"match":"TODO","context":"// TODO: refactor"}- Multi-pattern in one pass. Hyperscan compiles all patterns into a single DFA — adding patterns has near-zero cost.
- PCRE syntax (the subset Hyperscan accepts — see Regex syntax). Most everyday patterns work unchanged.
- JSON Lines output by default — pipe-friendly, easy for scripts and AI agents to parse.
- stdin-friendly. With no files/globs given, content is read from stdin — slots into any bash pipeline.
- Block extraction. Pair every match with the balanced delimiter block that follows it (function bodies, JSON objects, JSX subtrees, SQL
BEGIN/END). - Script mode (JSON DSL). Variables, lifecycle hooks, sub-pattern matching, conditionals, grouping, ranking, and multi-phase scans — all in one invocation. See Script mode.
-piper-pattern case-insensitivity. Mix case-sensitive and case-insensitive patterns in the same scan.-absentmode. Find files where a pattern is not found (likegrep -L, but also works inside scripts).- Unicode by default. UTF-8 mode is on;
-pifolds across scripts (CAFÉ↔café,ПРИВЕТ↔привет). See UTF-8 / Unicode. - grep-compatible output modes:
-f(file list),-c(per-file counts),-o(matched text only),-format(custom template),-A/-B/-C(context lines). - Single static binary — no runtime dependencies beyond
libc/libm/libpthread. - Guarded edit/apply workflow.
hprscript edit -plan-outdiscovers exact byte edits once;hprscript applyverifies file identity and commits that immutable plan. Plain search and script modes remain read-only. See below.
hprscript edit and hprscript apply are separate write-capable commands;
plain search and script modes stay strictly read-only. The
pattern (and every filter: -glob, -git-added-lines, -near/-far,
-file-where, …) that finds the sites is exactly what edits them.
# Discover once, persist exact byte ranges/content plus file hashes, review,
# then apply those stored edits without rescanning.
hprscript edit -F 'retry(3)' -content 'retry(5)' -expect 1 \
-plan-out retry.plan.json src/worker.go
hprscript apply retry.plan.json
# Replace a whole function BY NAME — no signature regex, no brace flags; the
# scope packs know the language (anchorless: no -p at all):
hprscript -list-scopes src/data.go # outline: name, kind, line range per function
hprscript edit -in-scope '^LoadData$' -span scope \
-content-file new_loaddata.go -expect 1 -plan-out loaddata.plan.json src/data.go
hprscript apply loaddata.plan.json
# Bump a constant only inside one function (-in-scope also filters search):
hprscript edit -F 'retry(3)' -content 'retry(5)' -in-scope 'ProcessBatch' \
-expect 1 -plan-out retry.plan.json src/worker.go
# Rename, but only on lines this branch added:
hprscript edit -p '\bOldName\b' -content 'NewName' \
-git-changed -git-added-lines -expect 14 -plan-out rename.plan.jsonSafety model: -expect guards the planning scan. The plan stores the
normalized root, command metadata, file size/SHA-256, exact old bytes, and
replacement bytes. apply validates every target before staging any write;
preflight refusals exit 3 with files untouched. Changed files are all staged
before the rename phase. A failure after renames begin exits 4 and returns a
partial-commit receipt. Each individual replacement is atomic (temp + rename),
but multi-file application is not a filesystem transaction. CRLF and missing
trailing newlines survive byte-exactly, and permission bits are restored;
ownership, timestamps, xattrs, and ACLs are not preserved across the staged
inode replacement.
Full reference: Edit mode.
Use investigation when the seed is known but the likely follow-up symbols, tests, configuration, or impact area are not:
hprscript investigate -F validateToken -profile symbol -llm \
-evidence-budget 65536 -glob '**/*.go'It returns a deterministic, budgeted package of ranked files and scopes, probable lexical definitions/references, path-heuristic file roles, related identifiers, representative evidence, and explicit scan/truncation accounting. It runs one seed stage and at most one internally batched related-identifier follow-up stage. See Investigation mode.
Use query when the match sets and their value/location relationship are known:
hprscript query -query unresolved-functions.json -explain-plan -summaryVersion 1 provides named match sets, typed capture/scope rows, inner/left/semi/ anti joins, value and location predicates, structured filtering, projection, grouping/aggregation, ordering, strict resource limits, and adaptive derived-pattern stages. Compatible sets share one matcher/traversal; equality joins use hash indexes. See Declarative query mode.
Prebuilt binaries for Linux (x86-64, ARM64) and macOS (Apple Silicon) are attached to every tagged release:
Mark the binary executable and drop it in your PATH:
# Linux x86-64
curl -L -o hprscript https://github.com/pinkhasn/hprscript/releases/latest/download/hprscript
# Linux ARM64 (aarch64)
curl -L -o hprscript https://github.com/pinkhasn/hprscript/releases/latest/download/hprscript-linux-arm64
# macOS Apple Silicon (arm64)
curl -L -o hprscript https://github.com/pinkhasn/hprscript/releases/latest/download/hprscript-macos-arm64
chmod +x hprscript
mv hprscript ~/.local/bin/On macOS, Gatekeeper quarantines downloaded binaries. If the OS blocks it, clear the quarantine attribute with
xattr -d com.apple.quarantine hprscript(or build from source).
Requires a C++17 compiler (g++ or clang), make, and a Vectorscan install at /opt/vectorscan (override with VECTORSCAN_PREFIX=...).
Neither most Linux distros nor Homebrew package Vectorscan, so build it once from source. Install the build dependencies for your platform:
# Linux (Debian/Ubuntu)
sudo apt install -y build-essential cmake ragel pkg-config libboost-dev libsimde-dev
# macOS (Homebrew)
brew install cmake ragel pkg-config boost simdeThen build and install Vectorscan:
git clone --depth 1 --recurse-submodules https://github.com/VectorCamp/vectorscan.git
cmake -S vectorscan -B vectorscan/build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF \
-DBUILD_TOOLS=OFF -DBUILD_UNIT=OFF \
-DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARKS=OFF \
-DCMAKE_INSTALL_PREFIX=/opt/vectorscan
cmake --build vectorscan/build -j"$(getconf _NPROCESSORS_ONLN)"
sudo cmake --install vectorscan/buildThen build hprscript:
make # builds ./hprscript
make install # copies to ~/.local/bin/hprscriptThe build statically links Vectorscan so the binary needs no Vectorscan package at runtime. On Linux it also statically links libstdc++/libgcc (verify with ldd hprscript — only libc, libm, libpthread, and ld-linux should appear); on macOS libc++ is part of the OS and links dynamically (inspect with otool -L hprscript). The Makefile auto-detects the platform via uname.
The same recipe works on Linux x86-64 (SSE/AVX2), Linux/macOS ARM64 (NEON/SVE), and Intel macOS — Vectorscan auto-targets the host's SIMD.
make testhprscript ships two portable agent skills:
skills/hprscript-search/SKILL.mdteaches read-only quick search, investigation, query, ranking, and context packing.skills/hprscript-edit/SKILL.mdteaches persistent edit plans, guarded application, and the boundary with localized semantic patching.
Each is a single Markdown file with YAML frontmatter and focused instructions. Install either skill independently or install both for the complete workflow. They drive the CLI binary directly, carry inline cheat sheets, and point at HPRSCRIPT.md / COOKBOOK.md for depth.
Both follow the standard SKILL.md convention — filename in caps, with name and description frontmatter — that a growing number of agents discover automatically. The only requirement on your side: the hprscript binary must be on the agent's PATH (see Install).
Copy the skills into your skills directory — globally (every project) or per-project:
# Global — applies everywhere
mkdir -p ~/.claude/skills/hprscript-search ~/.claude/skills/hprscript-edit
cp skills/hprscript-search/SKILL.md ~/.claude/skills/hprscript-search/
cp skills/hprscript-edit/SKILL.md ~/.claude/skills/hprscript-edit/
# Or per-project — commit it with your repo
mkdir -p .claude/skills/hprscript-search .claude/skills/hprscript-edit
cp skills/hprscript-search/SKILL.md .claude/skills/hprscript-search/
cp skills/hprscript-edit/SKILL.md .claude/skills/hprscript-edit/Start a new claude session and it reaches for hprscript whenever you ask it to search code. See the Claude Code skills docs.
opencode loads skills automatically via its native skill tool — and it scans the same .claude/skills/ and ~/.claude/skills/ paths as Claude Code, so if you installed it above, opencode already sees it. To install it only for opencode:
# Global
mkdir -p ~/.config/opencode/skills/hprscript-search ~/.config/opencode/skills/hprscript-edit
cp skills/hprscript-search/SKILL.md ~/.config/opencode/skills/hprscript-search/
cp skills/hprscript-edit/SKILL.md ~/.config/opencode/skills/hprscript-edit/
# Or per-project
mkdir -p .opencode/skills/hprscript-search .opencode/skills/hprscript-edit
cp skills/hprscript-search/SKILL.md .opencode/skills/hprscript-search/
cp skills/hprscript-edit/SKILL.md .opencode/skills/hprscript-edit/No config required. See the opencode skills docs.
SKILL.md is just Markdown, so any agent can use it one of two ways:
-
Native skill discovery — agents that scan skill directories typically also read
.agents/skills/and~/.agents/skills/(alongside the Claude/opencode paths above). Drop either or bothhprscript-search/andhprscript-edit/folders wherever your agent looks. -
Instructions / rules file — for agents driven by an instructions file (
AGENTS.md, Cursor rules, OpenAI Codex, …), point that file at the skill or paste its contents. opencode'sopencode.json, for example, can reference it directly (local path or remote URL):{ "$schema": "https://opencode.ai/config.json", "instructions": ["skills/hprscript-search/SKILL.md", "skills/hprscript-edit/SKILL.md"] }
- HPRSCRIPT.md — full reference: every CLI flag, the script-mode JSON DSL, Unicode handling, regex quirks, and exit codes.
- COOKBOOK.md — task-oriented recipes organized by problem domain (logs, source code, configs, pipelines). Copy-paste invocations with explanations of which hprscript features make each one work.
See LICENSE.