Compiled, stateless deployment prelude artifact.
A deployment loads curated PTC-Lisp prelude source that declares protected
namespaces (e.g. crm) and exports functions/constants. The compiler
(PtcRunner.Lisp.Prelude.Compiler) turns that source into one of these
artifacts, which is then attached to a run and consulted — unchanged —
across direct Lisp execution, Kernel execution, and the REPL.
Fields
namespaces— sorted list of declared namespace-name strings. These are the prelude-protected namespaces (host-boundary string-backed).exports— list of%PtcRunner.Lisp.Prelude.Export{}public export records (:prompt+:discoverable). Private helpers are NOT here.private_env— the captured private prelude environment, keyed by namespace then bare symbol:%{namespace => %{symbol => callable}}({:closure, ...}fordefn). Namespace-scoping keeps same-named definitions in different namespaces distinct (e.g.crm/whovshr/who). Public exports call their own namespace's private helpers through this env; user code cannot resolve private helpers by qualified symbol. The CALLABLE values are what evaluator threading depends on.source_hash— sha256 hex digest of the prelude source, for traceability.source_index— precomputed%{full-ref => rendered-source}map for(source ns/name). Keyed by full ref for public exports plus private helpers transitively reachable from a public export; values are a labeled effective-metadata header plus the Formatter-rendered defining form (no closures or raw AST). Reveals implementation, not just contract — keep secrets out of prelude bodies.form_graph—%{namespace => %{symbol => entry}}, the compiled per-namespace sibling call graph. Each entry carriesvisibility(:public/:private, this form's own definition kind — distinct fromExport.visibility's:prompt/:discoverable),kind,arity,doc, directcalls(sibling symbol references only), andrequires/tool_refseach split intodirect(this form's own body) andtransitive(the closure over the siblings it calls). Includes BOTH public and private definitions — unlike public export list. It carries no callables or captured env, only string/atom/list facts.metadata— small map of namespace-level facts for traces/debugging, e.g. per-namespace docstring and default visibility.
Private-env capture seam
defn/defn- in the prelude desugar through the existing analyze+eval
pipeline to {:closure, params, body, captured_env, turn_history, meta}
tuples stored under their bare symbol in a user_ns-shaped map. The
compiler captures that whole map as private_env. Sibling helpers are NOT
folded into each closure's captured_env — they resolve by name through
user_ns at call time, and private_env is exactly that namespace. The
runtime therefore threads private_env as the user_ns layer (resolver position
between the mutable user namespace and built-ins) when invoking exports:
a public export resolves qualified (crm/get-user) to
private_env[symbol] and runs its body against private_env, so private
helpers resolve, while private symbols stay absent from exports and so
are unreachable by qualified user calls.
Validation errors
Compile-time failures are returned as
{:error, %PtcRunner.Lisp.Prelude.ValidationError{}}, never raised.
Summary
Types
Trace/debug summary of a compiled prelude, for traceability.
A form_graph entry: one compiled top-level definition.
Functions
The typed-tool names a public export invokes (transitively over same-namespace
helpers), or [] when ref is not a public export.
Looks up a public export by its Lisp-facing ref (e.g. "crm/get-user").
The declared (protected) namespace names, sorted.
Public export records visible in the prompt inventory (:prompt only).
Builds the trace/debug summary for prelude.
Types
@type export_summary() :: %{ ref: String.t(), namespace: String.t(), symbol: String.t(), arity: non_neg_integer() | :variadic, params: [String.t()], visibility: PtcRunner.Lisp.Prelude.Export.visibility(), effect: PtcRunner.Lisp.Prelude.Export.effect(), requires: [String.t()], signature: String.t() | nil, type: String.t() | nil }
Trace/debug summary of a compiled prelude, for traceability.
String/atom/list-only, JSON-serializable, and credential-free: it carries enough to identify the capability environment without leaking captured closures, the private prelude env, or any host secret.
source_hash— sha256 hex of the prelude source.artifact_hash— sha256 hex over the compiled artifact's protected facts (namespaces + public export records). Lets a trace consumer tell whether two runs used the same compiled prelude even when source text is unavailable.protected_namespaces— the selected protected namespace names (sorted).exports— oneexport_summaryper PUBLIC export (no callables/env).components— selected source component provenance when the artifact was produced byPtcRunner.Lisp.Prelude.Bundle; otherwise[].
@type form_graph() :: %{ required(String.t()) => %{required(String.t()) => form_graph_entry()} }
@type form_graph_entry() :: %{ visibility: :public | :private, kind: PtcRunner.Lisp.Prelude.Export.kind(), arity: PtcRunner.Lisp.Prelude.Export.export_arity(), doc: String.t() | nil, calls: [String.t()], requires: %{direct: [String.t()], transitive: [String.t()]}, tool_refs: %{direct: [String.t()], transitive: [String.t()]}, effects: %{ direct: [PtcRunner.Lisp.Prelude.Export.effect()], transitive: [PtcRunner.Lisp.Prelude.Export.effect()] } }
A form_graph entry: one compiled top-level definition.
calls is DIRECT same-namespace references only; requires/tool_refs/effects
split direct (this form's own body) from transitive (the closure over
the siblings it calls) — both sorted and deduped.
@type t() :: %PtcRunner.Lisp.Prelude{ exports: [PtcRunner.Lisp.Prelude.Export.t()], form_graph: form_graph(), metadata: map(), namespaces: [String.t()], private_env: %{required(String.t()) => %{required(String.t()) => term()}}, source_hash: String.t(), source_index: %{required(String.t()) => String.t()} }
@type trace_summary() :: %{ source_hash: String.t(), artifact_hash: String.t(), protected_namespaces: [String.t()], exports: [export_summary()], components: [map()] }
Functions
The typed-tool names a public export invokes (transitively over same-namespace
helpers), or [] when ref is not a public export.
The pre-execution tool guard unions these in so a prelude-wrapped
(tool/call ...) is validated before any side effect runs.
@spec fetch_export(t(), String.t()) :: {:ok, PtcRunner.Lisp.Prelude.Export.t()} | :error
Looks up a public export by its Lisp-facing ref (e.g. "crm/get-user").
The declared (protected) namespace names, sorted.
@spec prompt_exports(t()) :: [PtcRunner.Lisp.Prelude.Export.t()]
Public export records visible in the prompt inventory (:prompt only).
@spec trace_summary(t() | nil) :: trace_summary() | nil
Builds the trace/debug summary for prelude.
Returns nil for nil (no prelude attached). The result is JSON-serializable
and contains NO captured closures, private prelude env, or credentials — only
the protected facts needed to reproduce the capability environment.