PRE_CONSUME_SCRIPT=/path/to/your-script.sh and suchi runs it on
every ingested document before any format-specific processing kicks in
(qpdf, docsplit, blank removal, OCR, ZUGFeRD, …). The script can:
- Rewrite bytes — decrypt with a proprietary tool, unpack a wrapper format, run a custom deskewer, whatever.
- Emit metadata — attach tags or set custom fields via a JSON envelope on stdout.
- Do nothing — a script that fails or produces no output is a no-op; ingest continues with the original bytes.
Contract
The script is invoked as:
Exit codes:
0— success.$SUCHI_OUTPUTis read (only if non-empty). Stdout is parsed as JSON.- non-zero — log at
Warn, treat as “no changes”. Ingest keeps flowing; a failing pre-consume never aborts a doc.
- Timeout: 5 minutes (
sandbox.Opts.Timeout) - Stdout ceiling: 1 MiB (parsed as JSON envelope)
- SUCHI_OUTPUT ceiling: 200 MiB
Example: try candidate passwords from a file
A pre-consume-decrypt pattern for the case where suchi’s native decrypt path isn’t enough (e.g. a non-PDF encrypted format we don’t handle yet):chmod 700, chown to the suchi user, then:
Example: attach a tag by filename pattern
Security
- Runs under the same UID as suchi. Filesystem access is whatever that
UID has — set
chownon secret files defensively. - Runs in
core/sandbox: empty env (beyond the vars above), hard timeout, bounded output, process-group kill on timeout. - No network by default — the sandbox doesn’t drop egress but
suchi’s principle-8 posture assumes your reverse proxy / firewall
blocks per-container outbound. If you need outbound (webhook, remote
KMS), route it via a sidecar service the script
curls to on localhost.
Why not just use plugins?
The plugin surface (plugin-api/) is Go interfaces + Go builds — great
for suchi maintainers, painful for operators. PRE_CONSUME_SCRIPT is
the classic shell-script escape hatch: “here’s a script, run it.”
Meets operators where they are.