Decision 02
Three products, one catalogue
Cloud, Serverless and Self-Host are separate products with different engines — and the duplication between them has to be governed.
The three products
Different engines, different buyers, one plugin catalogue between them.
Documentize Cloud
hosted · multi-tenantWorkspace, file library, recipes and runs. The pipeline product.
- DAG orchestrator
- 49 manifest plugins
- Resource governor
- Checkpointed resume
Documentize Serverless
AWS Marketplace · single-tenantScale-to-zero document processing inside the customer's own account.
- Fn control plane
- 32 auto-discovered workers
- Per-plugin instances, 0 to N
- Gigabyte-second cost model
Documentize Self-Host
licensed binary · air-gapped capableOne binary, no external dependencies, entitlement by signed key.
- Local file storage
- No broker, no Redis
- Nothing leaves the network
MCP is not a fourth product — it is a caller, and it ships against Cloud and Self-Host both. That portability is already demonstrated: moving the MCP tool surface from the hosted Kafka path to a local queue changed the dispatch call and nothing else about the 37 tools.
Why two engines, deliberately
This reverses an earlier working assumption, and the reason matters.
The first instinct was to converge: pick the DAG engine for cloud and retire the worker tree plugin by plugin. That is the right call when there is one product. It is the wrong call once Serverless is its own Marketplace SKU, because the worker tree and the Fn control plane are that product — scale-to-zero is its whole proposition, and the DAG engine does not offer it.
So both trees stay. The duplication stops being technical debt and becomes a product boundary — but only if the boundary is drawn on purpose.
Where the boundary belongs
Some layers should be shared and are not. Some are correctly separate.
| Layer | Should be | Today |
|---|---|---|
| Document logic conversion, OCR, page operations | Shared library referenced by both trees | duplicated two implementations per operation |
| Invocation contract how a unit of work is called | Separate — they genuinely differ | correct |
| Scheduling what runs when | Separate — DAG versus scale-to-zero is the product difference | correct |
| Parameter schema | One declaration, both trees | one side only declared parameters exist in the plugin tree |
Operations including compress, rotate, merge, OCR, parse, split, flatten and resize currently exist as separate implementations on both sides. With two products shipping, every document-processing fix has to be made twice, and the two will drift in output — which is exactly the difference a customer comparing the products would notice.
New document logic lands in a shared library, and each tree keeps only its invocation wrapper. This should be done opportunistically — whenever an operation is touched for another reason — rather than as a scheduled extraction. The immediate cost is close to zero; the cost of not deciding is two diverging engines a year from now.