Skip to content
Prompting Press v0.5

Loading prompts

A PromptLoader is a pluggable source of raw prompt text looked up by a logical key. Its single operation load(key) returns the raw text of a prompt definition — never a parsed Prompt. Loading and construction are always separate, composable steps:

raw = loader.load("greet") ← I/O leaf (caller-invoked)
prompt = Prompt.from_yaml(raw) ← construction (I/O-free)

The engine kernel stays I/O-free at all times; only the loader the caller passes in performs I/O.

MemoryLoader holds a key → text mapping in memory. Its primary use case is dependency injection in tests: production code uses a FileSystemLoader or a custom loader; tests substitute a MemoryLoader with hard-coded prompt text. No filesystem access is performed.

guides_loader_memory.rs
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Loader guide — MemoryLoader: load raw text by key, then construct a Prompt.
//! The kernel stays I/O-free; the loader is a separate, caller-invoked I/O leaf.
//! Standalone — `cargo run --example guides_loader_memory`.
use std::collections::HashMap;
use prompting_press::loader::{MemoryLoader, PromptLoader};
use prompting_press::Prompt;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut map = HashMap::new();
map.insert(
"greet".to_string(),
r#"name: greet
role: user
body: "Hello {{ name }}"
variables:
name: { type: string, trusted: true }
"#
.to_string(),
);
let loader = MemoryLoader::new(map);
// load() returns raw text — parsing is a separate step.
let raw = loader.load("greet")?;
let prompt = Prompt::from_yaml(&raw)?;
assert_eq!(prompt.name(), "greet");
Ok(())
}

FileSystemLoader maps a logical key to {base}/{key}{suffix} on disk. The default suffix is .yaml; pass a custom suffix or max_bytes cap via the full constructor. The base directory is canonicalized at construction time (Rust/Python) or at each load() call (TypeScript).

guides_loader_filesystem.rs
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Loader guide — FileSystemLoader: map a key to a file in a base directory.
//! Uses the `assistant.yaml` fixture that lives next to this program.
//! Standalone — `cargo run --example guides_loader_filesystem`.
use prompting_press::loader::{FileSystemLoader, PromptLoader};
use prompting_press::Prompt;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let dir = concat!(env!("CARGO_MANIFEST_DIR"), "/examples");
// Construct from an existing directory (canonicalized at construction time).
let loader = FileSystemLoader::with_base(dir)?;
// "assistant" maps to {dir}/assistant.yaml (default suffix ".yaml").
let raw = loader.load("assistant")?;
let prompt = Prompt::from_yaml(&raw)?;
assert_eq!(prompt.name(), "assistant");
Ok(())
}

A loader is format-agnostic: it returns raw text and never parses. You choose the format at the parse step — from_yaml / from_json / from_toml (Rust & Python) or fromYaml / fromJson / fromToml (TypeScript) — independently of how the loader found the text. So JSON and TOML work exactly like YAML; only two things change: the FileSystemLoader suffix and which from_* you call. MemoryLoader needs no suffix at all (it is a direct key→text map); the format is decided solely by which from_* you parse with.

guides_loader_formats.rs
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Loader guide — loading JSON and TOML: the loader is format-agnostic (returns raw
//! text), so only the FileSystemLoader suffix and the `from_*` parser change.
//! Uses the `assistant.json` / `assistant.toml` fixtures next to this program.
//! Standalone — `cargo run --example guides_loader_formats`.
use prompting_press::loader::{FileSystemLoader, PromptLoader};
use prompting_press::Prompt;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let dir = concat!(env!("CARGO_MANIFEST_DIR"), "/examples");
// JSON: suffix ".json" → loads {dir}/assistant.json, parsed with from_json.
let json_loader = FileSystemLoader::new(dir, ".json", FileSystemLoader::DEFAULT_MAX_BYTES)?;
let json_raw = json_loader.load("assistant")?;
let from_json = Prompt::from_json(&json_raw)?;
assert_eq!(from_json.name(), "assistant");
// TOML: suffix ".toml" → loads {dir}/assistant.toml, parsed with from_toml.
let toml_loader = FileSystemLoader::new(dir, ".toml", FileSystemLoader::DEFAULT_MAX_BYTES)?;
let toml_raw = toml_loader.load("assistant")?;
let from_toml = Prompt::from_toml(&toml_raw)?;
assert_eq!(from_toml.name(), "assistant");
// Empty suffix → the extension lives in the key instead (same file either way).
let bare_loader = FileSystemLoader::new(dir, "", FileSystemLoader::DEFAULT_MAX_BYTES)?;
let bare_raw = bare_loader.load("assistant.json")?;
assert_eq!(Prompt::from_json(&bare_raw)?.name(), "assistant");
Ok(())
}

Any callable or struct that maps a key to raw text works as a loader. In Rust, a Fn(&str) -> Result<String, PromptLoadError> closure is a loader directly, with no struct required. In Python, any callable (key: str) -> str satisfies the protocol. In TypeScript, implement the PromptLoader interface (load(key): Promise<string>).

guides_loader_custom.rs
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Loader guide — custom loaders: a closure or a struct implementing PromptLoader.
//! No struct is required — any `Fn(&str) -> Result<String, PromptLoadError>` closure works.
//! Standalone — `cargo run --example guides_loader_custom`.
use prompting_press::loader::PromptLoader;
use prompting_press::{Prompt, PromptLoadError};
const GREET_YAML: &str = r#"name: greet
role: user
body: "Hello {{ name }}"
variables:
name: { type: string, trusted: true }
"#;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// A closure is a loader — no struct needed.
let loader = |key: &str| -> Result<String, PromptLoadError> {
match key {
"greet" => Ok(GREET_YAML.to_string()),
_ => Err(PromptLoadError::NotFound {
key: key.to_string(),
}),
}
};
let raw = loader.load("greet")?;
let prompt = Prompt::from_yaml(&raw)?;
assert_eq!(prompt.name(), "greet");
// A missing key returns NotFound.
assert!(loader.load("missing").is_err());
Ok(())
}

PromptLoadError is distinct from LoadError (the parse/shape error). except PromptLoadError / catch (e instanceof PromptLoadError) does NOT catch a malformed-YAML LoadError. The two error codes are:

CodeWhen raised
load_not_foundKey absent from the backing store; also used for traversal-rejected keys.
load_ioI/O failure, or file exceeds max_bytes.
guides_loader_miss.rs
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Loader guide — a missing key raises PromptLoadError (load_not_found),
//! distinct from ConsumerError (the parse/shape error raised on malformed YAML).
//! Standalone — `cargo run --example guides_loader_miss`.
use std::collections::HashMap;
use prompting_press::error::code;
use prompting_press::loader::{MemoryLoader, PromptLoader};
use prompting_press::{Prompt, PromptLoadError};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let loader = MemoryLoader::new(HashMap::new());
// A missing key returns PromptLoadError::NotFound — not a parse error.
let err = loader.load("missing").unwrap_err();
match &err {
PromptLoadError::NotFound { key } => assert_eq!(key, "missing"),
other => panic!("unexpected variant: {other:?}"),
}
// The normalized error row carries code "load_not_found".
assert_eq!(err.to_field_error().code, code::LOAD_NOT_FOUND);
// PromptLoadError is distinct from ConsumerError.
// Parsing bad YAML raises ConsumerError::Load — a different type on a different path.
let parse_result = Prompt::from_yaml("not: valid: yaml: [");
assert!(parse_result.is_err());
Ok(())
}
RustPythonTypeScript
In-memory loaderMemoryLoader::new(HashMap)MemoryLoader(dict)new MemoryLoader(record|map)
Filesystem loaderFileSystemLoader::with_base(path)?FileSystemLoader(base)new FileSystemLoader(base)
Custom loaderclosure |key| -> Result<_, PromptLoadError>callable (key) -> strclass with async load(key): Promise<string>
Error typePromptLoadErrorPromptLoadErrorPromptLoadError
load() sync?syncsyncasync (Promise<string>)

docs current as of 0.5.0