Skip to main content
One object entering the system, through every layer, to a decision and a queryable index. Written extractor-agnostic: the extractor is a variable, and this page shows where that variable is resolved and what it changes. The primary walk is customer-hosted (BYOC), because that is the shape where “what runs where” matters. Mixpeek Cloud is the same pipeline with every plane in Mixpeek’s account.
Nodes are execution environments and artifacts are what runs on them, so this view answers “what is deployed where” rather than “what happens next”.
PlantUML source, so the next editor regenerates rather than redraws:

The boundary, first

BYOC splits on one line: you provide the substrate, Mixpeek provides and operates the software.
Where the control plane sits is an install-time choice. The diagrams above draw the managed shape.Six collections are control-plane by definition: API keys, organizations, users, tenant routing, the Canvas app registry, and an internal repair queue. On a managed install those resolve to a Mixpeek-operated database and your namespace egresses to it, which is the egress the install kit’s network policy opens. On a fully self-hosted install the control-plane database is left unset, the same six resolve to the database in your own namespace, and no pipeline stage needs outbound to Mixpeek.The eight stages below are identical in both shapes. Two things outside the pipeline differ, and both are worth knowing before you design around self-hosted:
  • Canvas apps. The build worker, the bundle store and the app runtime all operate on one shared registry. A registry sitting in your own namespace is not reachable by them, so Canvas apps are unavailable on that shape.
  • Usage reporting. Your organization record and your usage records both sit in your namespace, so nothing reports consumption back to Mixpeek. Metering becomes a commercial arrangement rather than something the platform does for you.
Which shape you get is set at install time, so tell us which one your environment requires and it is configured that way from the first deploy.
The eight stages below each answer the same four questions: input, work, output, resources.

Stage by stage

① Arrival

Sync providers today: google_drive, s3, snowflake, sharepoint, tigris, iconik. Modes are initial_only or continuous with a polling_interval_seconds. Continuous sync is polling, not an event subscription, which sets your latency expectation for “a video arrives”.

② Object

A video is one object with blobs, not many objects. Decomposition into chunks, frames and scenes happens in stage ⑤, which is what makes tiers necessary.

③ Batch

dedup_strategy is the cost-multiplying knob: a re-run with the wrong value re-pays full extraction. Tier 0 is bucket to collection; tier N above 0 is collection to collection. A pipeline that turns a video into chunks, chunks into frames, and frames into embeddings is three tiers, each independently tracked and retryable.

④ Schedule

This is where the extractor stops being a name and becomes a machine. Profile resolution is a six-rule ladder: Only 6 of 12 built-in extractors declare a profile. For the rest, requires_gpu decides the hardware, not anything named in the definition. Choosing an extractor chooses a node pool and therefore a bill. Sizing is object_count ÷ objects_per_worker → replicas, clamped by the tenancy slice and a 350Gi ceiling. Shared tenancy gets gpu 2 / cpu 32 / api 4; DEDICATED_GPU rises to gpu 8 / api 12.

⑤ Execute

Two Ray shapes, and confusing them is the usual mistake. The RayService is long-lived and holds the models. The RayJob is ephemeral, one per batch, and holds no models at all for Serve-backed extractors. A cpu-only worker’s real peak is about 0.27 core and 0.77 GiB, which is why its requests are 1 cpu / 2Gi and why one node holds seven or eight concurrent batches instead of three. Two mechanics worth carrying:
  • Kubernetes cpu_req is not Ray num-cpus. cpu_workers.ray_num_cpus decouples them, so a worker can advertise 2 schedulable CPU to Ray for placement groups while requesting 1 from Kubernetes. Without it, multi-step streaming placement cannot schedule and the job orphans.
  • Requests drive the autoscaler; limits are the OOM gate. Limits stay generous so a decode or frame burst is absorbed rather than OOMKilled.

⑥ Persist

The knobs that decide cost and recall: Durability, stated plainly: the recovery source is object storage. A rescheduled primary replays the sealed WAL plus snapshot, so RPO is bounded by the flush interval rather than by zero. Replicas serve reads and do not shorten that gap.
Replica counts vary by namespace, and a namespace under maintenance can run a shape that does not match the steady state above. Treat this section as the design, and read the actual pod counts in your own namespace before depending on them.

⑦ Enrich and classify

Flat taxonomy enrichment calls no language model. It matches against a reference collection and writes labels back. Hierarchy inference has three methods, and only the LLM-based one calls a provider. Taxonomy is a small part of the egress picture, and the section below is the whole of it.

⑧ Decide

This stage composes primitives; there is no moderation resource in the API.
The platform computes the verdict and fires the trigger, but writing that decision back out as a destination object with lineage is the weak link. If moderation must end with “a file lands in a reviewed/ bucket”, treat that as integration work today rather than a primitive.

What leaves your account

Egress is not a property of one stage. It is a property of which extractors and which retriever stages a pipeline is configured with, and it exists at both ingest and query time. Enumerated from the call sites rather than characterised, because every attempt to describe this as a category has been wrong: At ingest, a model-backed extractor sends the content itself. gemini_multifile_extractor builds Gemini parts with Part.from_bytes(data=content, mime_type=...), so for an image or a PDF the media goes to the provider, not a label derived from it. The same holds for multimodal_extractor v2 Gemini embedding, universal_extractor, scrolling_text_extractor, document_graph_extractor’s VLM corrector, and web_scraper’s semantic router. Cluster labelling calls a model too. At query time, seven retriever stages call providers: enrich/llm, enrich/agentic, filter/llm, filter/agent_search, filter/attribute, filter/query_expand and reduce/summarize. The enrich family is the volume path, once per result, so an enrich stage over 100 results is 100 calls. Those same seven also run at ingest, whenever a taxonomy or a collection’s retriever_enrichments points at a retriever. That path fires once per document rather than once per result, which makes it the larger volume of the two on a bulk load. Reading the collection will not tell you, because its config carries only a retriever_id; you have to follow the reference to the retriever and read its stages. Which of these are in your pipeline is configuration. A pipeline built on self-hosted models in your own Serve deployments makes none of these calls. One built on gemini_multifile_extractor sends every object’s bytes to Google at ingest. Both are supported, and the difference is a choice you make per collection and per retriever rather than a property of the platform. Three things change the answer, and all three are available today:
  • Your own provider credentials. Organization-default LLM credentials resolve per request, so these calls can run on your OpenAI, Anthropic or Vertex account. The egress becomes your contract with the provider rather than ours.
  • Self-hosted models. Anything served from your own Ray Serve deployments stays inside your VPC end to end.
  • Replace the path. A custom plugin can take over the enrich batch entirely, so the built-in provider call is never made.
If a reviewer needs the exhaustive list for a given namespace, derive it from that namespace’s own configuration rather than from this page. Ask us to run the namespace egress check against it: the check reads your collections, taxonomies, clusters and retrievers, names every configured component that reaches a provider, and refuses to report a clean result when it hits a reference it could not follow. The set above grows whenever an extractor or a stage is added, so a page cannot stay exhaustive.

Model weights are a different kind of egress

No customer content leaves on a self-hosted-model pipeline, which is the commitment above. The weights do arrive from outside, carrying nothing of yours, from HuggingFace and similar hosts. Two of the six model sets are baked into the engine image and need no network at all. The other four are fetched the first time each replica loads them, not at image build: It matters operationally rather than for a privacy review, and the failure is easy to misread. A namespace with no outbound to the public internet brings the Ray cluster up healthy and then leaves those four applications unable to load, which reads as a slow install for as long as it takes someone to look at the Serve status. Decide it before the first deploy. Either allow egress to huggingface.co on first start, or ask us for an image with all six baked.

Query path

Retrieval reuses the index the ingest path built. Read mechanics: coordinator → SearchDense RPC (fan-out across the hash ring for multi-shard namespaces) → shard probes nprobe partitions via PQ codes → re-ranks top-N against raw vectors → returns point id, score and payload. Filter predicates are evaluated coordinator-side, after the shard returns. That is known waste, and it is what compute pushdown is for.

Resource map

Where it breaks

Back-pressure and failure points, in the order they bite: One correctness note, because it is invisible otherwise: a batch that finishes with a failed tier reports COMPLETED_WITH_ERRORS, not COMPLETED. If you build a gate that polls batch status, poll for the honest values.

What this page does not establish

  • Where the control plane sits. The section above states the disagreement rather than picking a side. The install kit deploys no API, so it is the permission grant rather than the workload and does not settle it either.
  • A live BYOC deployment. Stage-by-stage resource numbers are read from the shared production cluster, which is the same software on Mixpeek’s substrate. Your pools, quotas and storage classes are yours and will differ.
  • Networking and egress detail. VPC layout, private-link options and per-provider network paths are untraced. What is enumerated is the set of call sites that reach a model provider, listed above. That list was wrong three times before it was right, each time by describing the category instead of counting: treat it as accurate on its date and derive the live set from a namespace’s own configured extractors and stages.
  • Moderation as a product surface. It does not exist as a resource. Stage ⑧ is a composition, and the destination-write gap is real.
  • Continuous sync latency. Sync polls on polling_interval_seconds. End-to-end arrival latency is unmeasured for every provider.

Deployment models

The shapes Mixpeek runs in, and which planes sit where.

Single tenant

Dedicated tenancy, and what changes about the numbers above.