Installation
Install pompelmi globally to get the pompelmi command available anywhere in your terminal:
npm install -g pompelmiyarn
yarn global add pompelmipnpm
pnpm add -g pompelmi
You can also run it without installing using npx — no global install required:
npx pompelmi scan ./uploads/document.pdf
brew install clamav on macOS,
apt-get install clamav on Debian/Ubuntu). For TCP mode, start a
clamd instance — the fastest way is docker run -d -p 3310:3310 clamav/clamav:stable.
Quick start
Scan a file
npx pompelmi scan ./uploads/document.pdf
Scan a directory recursively
npx pompelmi scan ./uploads --recursive
Output as JSON for scripting
npx pompelmi scan ./uploads --json
Commands reference
| Command | Description |
|---|---|
pompelmi scan <file|dir> |
Scan a file or directory for viruses. Exits with code 1 if a virus is found. |
pompelmi watch <dir> |
Watch a directory and auto-scan files as they are created or modified. Runs until interrupted with Ctrl+C. |
pompelmi version |
Print the installed version number and exit. |
pompelmi help |
Print usage with all commands, options, and examples. |
Options reference
| Option | Default | Description |
|---|---|---|
--recursive, -r |
true | Scan directory recursively (all subdirectories). |
--host <host> |
none | Connect to clamd at this hostname or IP. If omitted, uses local clamscan. |
--port <port> |
3310 | TCP port for clamd connection. |
--socket <path> |
none | UNIX socket path (e.g. /run/clamav/clamd.sock). Takes priority over --host/--port. |
--timeout <ms> |
15000 | Connection timeout in milliseconds. |
--retries <n> |
0 | Number of auto-retries on connection failure before giving up. |
--json |
false | Output results as a JSON object. Suppresses logo, colors, and progress bar. Ideal for scripting. |
--quiet, -q |
false | Only print infected files and the summary. Clean results are hidden. |
--delete |
false | After scanning, prompt for confirmation and delete infected files. |
--report |
false | Generate a self-contained HTML security dashboard after scanning. See Dashboard Demo Comparison. |
--share-card |
false | Generate a shareable SVG scan result card after scanning. See Share card. |
--output <file> |
see note | Output path for --report (default: pompelmi-report.html) or --share-card (default: pompelmi-scan-card.svg). File extension determines which output it applies to. |
--host, --port, nor --socket
is provided, pompelmi spawns a local clamscan child process. This requires ClamAV to be installed
on the machine. For Docker or CI environments, use --host / --port to point at a
running clamd container.
Default output format
By default, results are printed using box-drawing characters with ANSI colours. Each file shows one of three states: CLEAN, INFECTED, or ERROR. For infected files the matched virus name is shown below:
┌──────────────────────────────────────────────┐ │ 🍊 pompelmi scan results │ ├──────────────────────────────────────────────┤ │ ✅ CLEAN /uploads/document.pdf │ │ 🚨 INFECTED /uploads/malware.exe │ │ └─ Win.Malware.Agent-1234 │ │ ⚠️ ERROR /uploads/encrypted.zip │ ├──────────────────────────────────────────────┤ │ Scanned: 3 • Infected: 1 • Time: 1.2s │ └──────────────────────────────────────────────┘
For directory scans, a live progress bar is displayed on a single line (overwritten with
\r) while scanning is in progress:
Scanning... [████████░░░░░░░░░░░░] 40% • 20/50 files • 1 infected
JSON output (--json)
When --json is passed, pompelmi prints a single JSON object to stdout and
exits. No logo, no colours, no progress bar — ideal for piping into jq or
other tools.
{
"scanned": 3,
"infected": 1,
"errors": 0,
"time": 1.2,
"results": [
{ "file": "/uploads/document.pdf", "verdict": "clean" },
{ "file": "/uploads/malware.exe", "verdict": "infected",
"viruses": ["Win.Malware.Agent-1234"] },
{ "file": "/uploads/encrypted.zip", "verdict": "error" }
]
}
| Field | Type | Description |
|---|---|---|
scanned |
number | Total number of files scanned. |
infected |
number | Number of files with a virus detected. |
errors |
number | Number of files that could not be scanned. |
time |
number | Total scan time in seconds (rounded to 1 decimal place). |
results[].file |
string | Absolute path to the scanned file. |
results[].verdict |
"clean" | "infected" | "error" |
Scan result for this file. |
results[].viruses |
string[] (optional) | List of matched virus names. Present only when verdict is "infected". |
Exit codes
| Code | Meaning |
|---|---|
| 0 | All files are clean. No threats detected. |
| 1 | At least one virus was found. |
| 2 | At least one file could not be scanned (error). |
| 3 | clamd was unreachable (connection refused or timeout). |
Exit codes make it easy to integrate pompelmi into shell scripts and CI pipelines.
A non-zero exit causes set -e scripts and most CI systems to fail the step automatically.
HTML report (--report)
The --report flag generates a self-contained HTML security dashboard after
scanning. The file contains no external dependencies and can be opened in any browser,
archived, or attached to a ticket.
npx pompelmi scan ./uploads --report
Saves pompelmi-report.html in the current directory. Use --output to change the path:
npx pompelmi scan ./uploads --report --output /tmp/security-$(date +%Y%m%d).html
The report includes summary stats, a colour-coded status banner, a full file table with
verdict badges, an infected files section, and scan metadata. It supports dark mode via
prefers-color-scheme and is print-friendly.
See the Dashboard documentation for the full API reference.
Examples
1. Scan a single file (local clamscan)
pompelmi scan ./uploads/resume.pdf
2. Scan a directory recursively
pompelmi scan ./uploads --recursive
3. Scan via clamd over TCP (Docker sidecar)
pompelmi scan ./uploads \ --host 127.0.0.1 \ --port 3310 \ --recursive
4. Scan via UNIX socket (lower latency)
pompelmi scan ./uploads --socket /run/clamav/clamd.sock
5. JSON output — pipe into jq
pompelmi scan ./uploads --json | jq '.infected'
6. Quiet mode — only show infected files
pompelmi scan ./uploads --quiet
7. Delete infected files interactively
pompelmi scan ./uploads --recursive --delete
8. Watch a directory for incoming uploads
pompelmi watch ./uploads --host 127.0.0.1 --port 3310
npx pompelmi instead of pompelmi if you have not installed it globally.
npx downloads the latest version on the fly — no global install needed.
Shell script integration
Because pompelmi uses standard exit codes, it integrates cleanly into any shell script. The following example scans an incoming upload directory, posts a Slack message if a virus is found, and exits non-zero so the calling CI job fails:
#!/usr/bin/env bash
set -euo pipefail
UPLOAD_DIR="${1:?Usage: scan-uploads.sh <dir>}"
CLAMD_HOST="${CLAMAV_HOST:-127.0.0.1}"
CLAMD_PORT="${CLAMAV_PORT:-3310}"
echo "Scanning $UPLOAD_DIR..."
RESULT=$(pompelmi scan "$UPLOAD_DIR" \
--host "$CLAMD_HOST" \
--port "$CLAMD_PORT" \
--recursive \
--json)
INFECTED=$(echo "$RESULT" | jq -r '.infected')
SCANNED=$(echo "$RESULT" | jq -r '.scanned')
echo "Scanned: $SCANNED — Infected: $INFECTED"
if [ "$INFECTED" -gt 0 ]; then
echo "VIRUS DETECTED — failing build."
# Post a Slack message, open a ticket, etc.
exit 1
fi
echo "All files clean."
GitHub Actions example
Scan your repository on every pull request. Uses the pompelmi
GitHub Action
GitHub App under the hood, but you can also call the
CLI directly in a run step:
- name: Scan uploads with pompelmi
run: |
npx pompelmi scan ./uploads \
--host localhost \
--port 3310 \
--json \
| tee scan-results.json
jq -e '.infected == 0' scan-results.json
--json with jq -e to fail the CI step when any virus is
found, while still capturing the full results in an artifact.