Export and serving¶
The problem. A trained policy that cannot leave the process it was trained in is not a deliverable. Weights alone are not enough to run one: acting needs the shapes it was trained against, judging needs the reward it was trained under, and none of that is in a checkpoint — while nothing stops a checkpoint being loaded against the wrong task and producing numbers that look fine. What is missing is a record: this policy, these schemas, this reward, this environment.
The shape here. A bundle — a directory holding a manifest beside the weights — and a
runner that drives an environment with one, inference only, writing the same trace a training
run writes, so skyfall-crl eval scores a served policy with no special case. A bundle is
self-contained by default (weights copied inside, referenced relatively — movable, archivable,
handable as one object), and everything the environment supplies is optional: an environment
that declares no spaces and reports no reward specification still produces a useful record,
because absence is written down rather than invented.
What you implement: nothing, usually. An array policy that wants to be servable implements
load_weights(path); everything else is recorded automatically.
Exporting¶
Export happens during a run — the only moment the environment and the trained algorithm are both in hand:
A matrix gives every cell its own subdirectory; --export-external DIR records an absolute
weights path instead of copying (smaller, machine-bound, and the manifest says so). From Python,
export_bundle takes the environment and algorithm directly, and run_experiment(...,
export_dir=...) is the hook the CLI uses. Name the policy in the document — the bundle
records how to rebuild it, and a backend's internal default policy cannot be recorded.
The complete manifest field specification, with a real produced example, is in the
file-formats reference. Two details matter most in
practice: the reward specification is stored by value, because a world can declare one inline
and a name would not survive the trip; and the spaces are encoded losslessly — infinite bounds,
dtypes, Discrete.start, Text alphabets and zero minimum lengths all round-trip, none of which
a naive encoding preserves.
Serving¶
skyfall-crl serve --bundle bundles/my-policy --steps 200 --seed 7 --traces served/traces.jsonl
skyfall-crl eval --traces served
The bundle names the environment and the configuration schedule, so serving needs nothing else —
and the recorded schedule is replayed by default, so a served trace segments exactly as the
training trace did and the two are comparable; --stationary declines it deliberately. --env
and --env-kwargs override the environment, because serving a policy against a world it was not
trained on is legitimate and should be something you asked for. Name --seed on any serve you
intend to score, and --auto-reset for an environment with genuine terminal states — the same
rule training follows. Serving means inference against a live environment, not a web server;
nothing starts a process or opens a port.
Two ways a policy is put back¶
The manifest's format selects one, because there genuinely are two: a language model is rebuilt
from its checkpoint, while an array policy is built and then filled.
format |
The recorded factory receives | Who this is |
|---|---|---|
checkpoint |
the checkpoint directory, as its first argument | a language policy |
weights |
nothing; the rebuilt policy's own load_weights(path) is handed the file |
an array policy |
| absent | no weights were recorded | a backend that cannot checkpoint |
A policy whose bundle records weights but which has no way to take them is refused, not built fresh and left empty — a partially restored policy still acts, like something that was never trained, while every log line reports success.
Limits¶
No server, as above. A backend's auxiliary state is not saved: checkpointing writes the policy, so a reloaded EWC policy has no consolidation memory and a reloaded LCM policy has no context encoder — the policy without the algorithm's memory (Fidelity records what each loses). And nothing validates that a bundle's environment is the one you serve it against beyond what you pass — overriding is deliberate, and whether the schemas still fit is your call.
API: every public symbol, with signatures — Export and serving — API reference.