Anatomy of a session
A session is the core unit of an FML plan. Each one runs its own LLM interaction — with its own isolated context — and produces a single typed JSON object stored under context.<session_name>. A plan is just a set of sessions plus the declarations that wire them together.
This guide walks through every part of a session, in the order they appear in the body, and explains the one rule that trips people up most: the difference between a prePrompt and a prompt.
Prerequisites
- The hello-world plan guide — you should have written at least one session and seen its output.
The shape of a session
Only two parts are strictly required: the name and a prompt. Everything else is optional and depends on what the session needs to do.
1. The name
The first positional argument is the session's name:
That name is doing double duty. It's the key the session's output appears under in both the context namespace (context.overview) and the plan's final output object. It's also what other sessions reference in after, expect, and iterate. Use target if you want to publish under a different key — see Control the flow of a plan.
2. Each session has its own context
This is the mental model that makes the rest click: a session does not automatically see other sessions' work. Every session starts with a fresh LLM context. It only knows about:
params,vars, and anything you explicitly pull in,- the output of its own PreCalls and prePrompts,
- and whatever you transfer in with a
contextdirective (which requiresafter).
That isolation is a feature — it keeps each session focused on one job with a small, relevant context, which is far more reliable than one giant prompt trying to do everything. To hand one session's result to another, you route it explicitly (covered in Data flow: params, vars & context).
3. use — declaring tools
Before a prePrompt can call a tool, the session has to declare it:
This mirrors the root-level require, but scoped to the session. search is the one exception: it's declared only as use search, never with require.
4. prePrompt (+) vs prompt (-) — the key distinction
Every session ends with instructions to the model, and there are two kinds. Getting them straight is the single most important thing about a session.
A prePrompt starts with +. It enriches the context and runs with tools available — this is where the model searches, fetches, and gathers. You can have as many as you need.
The prompt starts with -. It's the single final instruction that turns the gathered context into the structured output. A prompt is tool-free — it does not call tools, it only produces the JSON the schema describes. There is exactly one prompt per session.
prePrompt + | prompt - | |
|---|---|---|
| Purpose | Gather / enrich context | Produce the final output |
| Tools | Allowed | Never |
| How many | Zero or more | Exactly one |
| Produces | Context for the prompt | The session's typed JSON |
The most common beginner mistake is asking the - prompt to "search for X and summarize it." Split it: a + prePrompt searches, the - prompt summarizes. (See Call MCP servers and databases for tool-driven prePrompts.)
Both + and - support Go text templates ({{ .params.x }}, {{ .context.y | json }}) and span multiple lines via indentation.
5. The schema
The schema declares the JSON shape the prompt must produce:
The session name is already the outer wrapper, so keep fields flat at the root rather than re-nesting them under an object named after the session. Schemas have their own depth — optional fields, arrays, nested objects, reusable $Component refs, and scalar shorthand like schema string[] — all covered in Design your output schemas.
6. The supporting cast
Three more optional directives round out a session:
context— transfers prior session output into this session's context, either wholesale (context true) or formatted (context "Overview: {{ .context.overview | json }}"). Requiresafter.set— a session-scoped variable, merged with globals and read asvars.<name>.call— a PreCall: a deterministic tool or code invocation that runs before the prompts fire. Use it when you know the exact tool signature; otherwise let a prePrompt call the tool. See PreCalls deep-dive.
Putting it together
A complete, realistic session using most of the parts:
Read top to bottom: declare tools, fetch deterministically, gather with a prePrompt, then produce the typed output with the one prompt.
Next steps
- Learn how data moves between sessions in Data flow: params, vars & context.
- Shape richer output in Design your output schemas.
- Sequence and gate sessions in Control the flow of a plan.
- Full reference: Sessions on the Frags wiki.
Every part of a session, top to bottom — name, tools, PreCalls, context, and the key prePrompt (+) vs prompt (-) distinction that turns gathered context into typed output.