Skip to main content
Set 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.
The CAS original is never handed to the script. Its argument is a private, mode-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:
Environment (nothing else — the sandbox strips the parent’s env): Exit codes:
  • 0 — success. $SUCHI_OUTPUT is 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.
A timeout or output-size violation is a pipeline error and follows normal job retry handling. Malformed stdout metadata is logged and ignored. Stdout JSON envelope (optional):
Tags are resolved or created in the document’s filing system. Custom-field names resolve only there; unknown names are logged and skipped, so create the definition in that system first through the admin surface. The envelope cannot select a system or transfer the document. Actorless document-link fields may refer only to live documents in the same system. Limits (all configurable via environment, defaults shown):
  • Timeout: 5 minutes (SUCHI_PRECONSUME_TIMEOUT)
  • Stdout ceiling: 1 MiB (SUCHI_PRECONSUME_MAX_STDOUT)
  • SUCHI_OUTPUT ceiling: 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 chown on 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.