plgg-foundry
Most experimental package
plgg-foundry is early study work — APIs may change, some tests are skipped, and every run calls an LLM. Calibrate expectations accordingly; the value here is the model, not production stability.
AI-powered workflow orchestration, built on plgg and plgg-kit. You define a set of operations (a Foundry); an LLM composes them into an execution plan (an Alignment) from a natural-language request, and a register machine runs it.
The model
- Foundry — your "factory spec": the operations available for the AI to compose. Its apparatuses are:
- Processors — transform data (
makeProcessor). - Switchers — validate or branch, enabling retry/validation loops (
makeSwitcher). - Packers — declare the expected outputs (
makePacker).
- Processors — transform data (
- Order — the user request (
{ text, files? }). - Alignment — the AI-generated sequence of operations.
- Medium — the execution environment passed to your functions:
{ alignment, params }, whereparamsare the numbered registers (r0,r1, …).
Internally, runFoundry is a proc chain: blueprint(foundry) asks the LLM for an Alignment, then operate(foundry)(order) runs it on the register machine — so the whole flow is errors-as-values, not exceptions.
Defining and running a foundry
The current API is makeFoundry / makeProcessor / makeSwitcher / makePacker, run with runFoundry(foundry)(input) where input is a prompt string or an OrderSpec:
import { makeFoundry, makeProcessor, runFoundry } from "plgg-foundry";
import { proc, matchResult } from "plgg";
const profileFoundry = makeFoundry({
description: "Greets users based on their profile.",
apparatuses: [
makeProcessor({
name: "greet",
description: "Generates a personalized greeting.",
arguments: {
profile: { type: '{ "name": string, "interests": string[] }' },
},
fn: ({ params }) =>
proc(
params["profile"],
asProfile, // a cast-based decoder → InvalidError on bad shape
(p) => ({
greeting: `Hello ${p.name}! You like: ${p.interests.join(", ")}.`,
}),
),
}),
],
});
const result = await runFoundry(profileFoundry)(
"Greet a user named Ada who likes math and engines",
);
matchResult(
(e) => console.error("failed", e),
(medium) => console.log(medium.params),
)(result);A makeFoundry spec accepts description, apparatuses, an optional provider (defaults to openai("gpt-5.1")), and maxOperationLimit (default 10, a loop guard). Operation fns return data — decode untrusted register values with a cast-based guard so a bad shape becomes an InvalidError rather than a throw, consistent with the core error model.
The LLM provider boundary
The model is vendor-neutral: the adapter is the point. A provider comes from plgg-kit — openai(model), anthropic(model), or google(model) (each also accepts { model, apiKey? }) — so switching LLM vendors is a one-line change to the foundry's provider, not a rewrite of the operations.