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 exits successfully without output leaves the working bytes and metadata unchanged.
0600 scratch copy of the current working bytes, so rewriting or deleting
that path cannot damage the stored original.
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, ignore the script’s output, and continue with the unchanged working bytes.
- Timeout: 5 minutes (
SUCHI_PRECONSUME_TIMEOUT) - Stdout ceiling: 1 MiB (
SUCHI_PRECONSUME_MAX_STDOUT) SUCHI_OUTPUTceiling: 200 MiB (SUCHI_PRECONSUME_MAX_OUTPUT)
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. - The sandbox does not isolate network access. Deny container or host egress when the script must be offline; expose intentional services explicitly.
- This is an instance-wide operator hook, not a per-system security sandbox. Its operating-system access can span all systems; the operator remains trusted.
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 hook: “here’s a script, run it.” Meets
operators where they are.
This hook runs before text extraction. It can call an external model itself,
but it is not a typed post-extraction LLM step and Suchi cannot validate or
apply arbitrary model output from it. The built-in classifier owns v0.1 LLM
classification. Typed custom extractors are post-v0.1 work.