# 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](/content/docs/guides/frags-runtime-locally/index.html) — 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`:

```FML
session("hello") {
    - Say hello to the world in one friendly sentence.

schema {
        greeting: string
    }
}
```

Run it with the CLI:

```Shell
frags run hello.fml
```

Frags executes the `hello` session and returns an object keyed by the session name, matching the schema:

```JSON
{
  "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 a `greeting` string 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> }}`:

```FML
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.

```FML
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> }}`:

```FML
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:

```JSON
{
  "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](/content/blueprints/index.html).
- Read the Frags reference on [Blueprints](https://github.com/FragsHQ/frags/wiki/Plans), [Sessions](https://github.com/FragsHQ/frags/wiki/Sessions), and [Flow Control](https://github.com/FragsHQ/frags/wiki/FlowControl).
- Run a finished blueprint over HTTP with the [API reference](/content/docs/api/index.html), or call it from your app with the [Python or TypeScript SDK](/content/docs/sdk/index.html).

Write your first FML blueprint from scratch — a single session with a schema — then grow it with parameters, prompt phases, and connected sessions.
