Pipeline
Combine model, privacy protocol, preparation, runtime, and deployment choices in one configuration.
A Pipeline records what you intend to run. Profiles provide visible defaults,
and component overrides keep their versions. The configuration digest covers
normalized values, not live connections or provider state.
Creating a pipeline does not run anything. Model lowering, research transforms, compilation, deployment, preparation, and session creation are separate steps. Each step returns a record or a structured error. The parties and offline work overview explains why preparation and live inference remain distinct.
Run pllm config show to inspect
examples/pllm.yaml without loading a model or runtime.
How profiles fit together
A profile is the safest starting point because it fills the protocol, preparation,
role, kernel, and optional verification slots with a compatible set. Choose first
by who owns the transformer weights, then by the protection and checking required
at the deployment boundary. Constructing a profile is still configuration only;
Experiment.resolve() checks the complete
composition, and compilation separately checks operator coverage.
API: Profile objects and signatures
Python SDK example
Each example below is a complete experiment.py for the same generated tiny model,
so the pipeline is the only important difference. Serve any runtime-backed profile
through the trusted local gateway after placing that example in experiment.py:
pllm gateway --local \
--experiment experiment.py:experiment \
--trust-pythonThe gateway resolves the exact experiment, starts the required provider roles, and
serves Responses and Chat Completions requests on http://127.0.0.1:8080/v1 with
the default local API key local. To measure the same file instead, pass it to
pllm benchmark run. Generated tiny weights test
protocol behavior only; use a pinned real checkpoint for quality or performance work.
Prepare public-weight stages with MaskedLinearCpu
Use MaskedLinearCpu when
the transformer body is public but inference must not receive plaintext client
activations. It pairs prepared masking,
offline model-aware corrections, inference placement, and the native CPU kernel.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import MaskedLinearCpu
from pllm.sources import TinyModel
experiment = Experiment(
name="masked-linear",
pipeline=MaskedLinearCpu(TinyModel(model_id="masked-linear-tiny")),
deployment=Deployment.local(root="local://masked-linear"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.profile == "baseline.masked_linear_cpu"
assert resolved.requires_preparationVerify prepared outputs with VerifiedMaskedLinearCpu
Use VerifiedMaskedLinearCpu
when the trusted client must also check bounded integer stage outputs. It adds
FreivaldsVerify
material to the prepared path; it does not reduce online traffic. This is PLLM's
trusted-client adaptation of Slalom, not a TEE
reproduction.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import VerifiedMaskedLinearCpu
from pllm.sources import TinyModel
from pllm.verification import FreivaldsVerify
experiment = Experiment(
name="verified-masked-linear",
pipeline=VerifiedMaskedLinearCpu(
TinyModel(model_id="verified-tiny"),
verification=FreivaldsVerify(target_failure_bits=48),
),
deployment=Deployment.local(root="local://verified-masked-linear"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.verification_component == "pllm/freivalds-verify/v1"
assert resolved.verification_target_failure_bits == 48Encrypt linear inputs with DirectFHEProfile
DirectFHEProfile selects
the separate direct-FHE method.
It uses ciphertext transport rather than the masked-linear correction inventory and
requires the optional HE runtime for live execution.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import DirectFHEProfile
from pllm.sources import TinyModel
experiment = Experiment(
name="direct-fhe",
pipeline=DirectFHEProfile(TinyModel(model_id="direct-fhe-tiny")),
deployment=Deployment.local(root="local://direct-fhe"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.profile == "runtime.direct_fhe"
assert not resolved.requires_preparationGuard provider-owned weights with ProprietaryGuarded
Use ProprietaryGuarded
when the provider owns the weights and explicit request limits match the deployment
policy. GuardedLinear
adds quotas and bounds, not cryptographic activation confidentiality.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import ProprietaryGuarded
from pllm.protocols import GuardedLinear
from pllm.sources import TinyModel
experiment = Experiment(
name="proprietary-guarded",
pipeline=ProprietaryGuarded(
TinyModel(model_id="guarded-tiny"),
linear=GuardedLinear(max_rows_per_request=32),
),
deployment=Deployment.local(root="local://proprietary-guarded"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.profile == "runtime.proprietary_guarded"
assert resolved.proprietary_protocol == "guarded"Blind provider-owned stages with ProprietaryBlinded
ProprietaryBlinded
selects the provider-owned blinded-linear transport.
Its support and leakage claims remain scoped to that runtime arm and deployment.
from pllm import Deployment, ExecutionBudget, Experiment
from pllm.profiles import ProprietaryBlinded
from pllm.sources import TinyModel
experiment = Experiment(
name="proprietary-blinded",
pipeline=ProprietaryBlinded(TinyModel(model_id="blinded-tiny")),
deployment=Deployment.local(root="local://proprietary-blinded"),
budget=ExecutionBudget(requests=1, max_input_tokens=64, max_new_tokens=1),
)
resolved = experiment.resolve()
assert resolved.profile == "runtime.proprietary_blinded"
assert resolved.proprietary_protocol == "blinded"After choosing a profile, use configuration to place it in an experiment and the compiler guide to understand the separate executable-coverage gate.