Build a hello-world blueprint | Diaphora Docs | Diaphora
Build a hello-world blueprint
A blueprint is a Frags program written in FML — the Frags Modeling Language. A blueprint decomposes a task into one or more sessions, each an isolated LLM interaction with its own output schema, so every session returns typed, validated JSON instead of freeform text. This guide builds the smallest possible blueprint and grows it one concept at a time.
Golden rule: FML looks imperative, but it's a description language. There's no branching, no loops (except
iterate), and no return statements — every construct is declarative. You describe the sessions and their shapes; the runtime schedules and executes them.
Prerequisites
A working local Frags runtime. If you haven't set one up yet, start with Running Frags Locally — you'll need the frags CLI and a configured AI engine.
Your first blueprint
The smallest blueprint is a single session with one prompt and an output schema. Save this as hello.fml:
session("hello") {
- Say hello to the world in one friendly sentence.
schema {
greeting: string
}
}
Run it with the CLI:
frags run hello.fml
Frags executes the hello session and returns an object keyed by the session name, matching the schema:
{
"hello": {
"greeting": "Hello, world — it's a great day to build something."
}
}
Three pieces are doing the work:
session("hello") { … }— a session is one isolated LLM task. Sessions are the core units of a blueprint. Every blueprint has at least one, and its name becomes the key in the output.- …— the prompt (the-line). It's the main instruction and produces the structured output. There's exactly one per session.schema { greeting: string }— the output schema. Frags validates the model's response against it, so you always get agreetingstring back.
Add a system prompt and a parameter
Real blueprints take input and set the assistant's persona. system(...) sets a global system prompt, one system prompt is allowed per blueprint and it takes in a plain string as the argument. parameter(...) declares a typed input, the type is a bare keyword (no quotes), and a default makes it optional. Reference a parameter anywhere with Go template syntax, {{ .params.<name> }}:
system("You are a friendly assistant who keeps things short.")
parameter("name", type=string, default="Rayna", title="Name to greet")
session("hello") {
- Write a short, friendly one-sentence greeting to {{ .params.name }}.
schema {
greeting: string # The greeting to return
}
}
Because name has a default, frags run hello.fml runs as-is and greets "World". Inline schema comments like # The greeting to return aren't just for you as the LLM reads them as field descriptions, so add them whenever a field name isn't self-explanatory.
Prompt phases: prepare, then answer
A session can run in phases. A + line is a prePrompt: it runs first, enriches the context, and is the only place allowed to call tools (MCP servers, collections, search). The - line is the main prompt that turns everything gathered into the schema — prompts themselves never call tools.
session("hello") {
+ Consider what makes a greeting feel warm and personal.
- Using that, write a short, friendly greeting to {{ .params.name }}.
schema {
greeting: string
}
}
You can have several + prePrompts in a session, but only one - prompt. So the pattern is always: gather with prePrompts, then produce the output with the single prompt.
Connect sessions together
Blueprints get powerful when sessions build on one another. Add after="<session>" so a session waits for another to finish, then pull the earlier session's output into a prompt with {{ .context.<session>.<field> }}:
parameter("name", type=string, default="Rayna")
parameter("language", type=string, default="Italian")
session("greet") {
- Write a one-sentence greeting to {{ .params.name }}.
schema {
greeting: string
}
}
session("translate", after="greet") {
- Translate this greeting into {{ .params.language }}: "{{ .context.greet.greeting }}"
schema {
greeting_fr: string
}
}
Frags runs greet first, then translate, wiring the output of one session into the next. Each session contributes its key to the final object:
{
"greet": { "greeting": "Hello, World!" },
"translate": { "greeting_fr": "Bonjour, World !" }
}
From here, a session can also depend on a condition (expect="..."), run once per item in a list (iterate="..."), or publish under a different key (target="...") — all declared as session arguments.
Next steps
- Explore ready-made blueprints in the blueprint marketplace.
- Read the Frags reference on Blueprints, Sessions, and Flow Control.
- Run a finished blueprint over HTTP with the API reference, or call it from your app with the Python or TypeScript SDK.
Write your first FML blueprint from scratch — a single session with a schema — then grow it with parameters, prompt phases, and connected sessions.