Docs/Guides/Anatomy of a session
Plans7 min read

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

FML
session("overview") {
    use search                       # 1. tools this session may use
    call("searchDocuments") -> docs  # 2. deterministic PreCall(s)
    context "..."                    # 3. context transferred in from other sessions
    set threshold = 10               # 4. session-scoped variables
    + Search for background on the topic.   # 5. prePrompt(s) — may call tools
    - Summarize what you found.              # 6. exactly one prompt — produces output
    schema {                          # 7. the typed output shape
        summary: string
    }
}

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:

FML
session("overview") { ... }

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 context directive (which requires after).

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:

FML
use mcp salesforce
use collection postgres
use search              # special — no name follows

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.

FML
+ Search for recent information about {{ .params.topic }}.
  Focus on the most relevant sources.

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.

FML
- Using the information above, extract the summary and key points
  required by the schema.
prePrompt +prompt -
PurposeGather / enrich contextProduce the final output
ToolsAllowedNever
How manyZero or moreExactly one
ProducesContext for the promptThe 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:

FML
schema {
    summary:   string    # a concise paragraph
    keyPoints: string[]  # the most important points
}

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 }}"). Requires after.
  • set — a session-scoped variable, merged with globals and read as vars.<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:

FML
require mcp knowledge_base

session("gather") {
    use search
    use mcp knowledge_base

    # Deterministic fetch before the model runs
    call("searchDocuments") -> rawDocs {
        query = "{{ .params.topic }}"
        limit = 5
    }

    + Search the web and the knowledge base for {{ .params.topic }}.
      Prefer recent, primary sources.

    - Using the results above, extract the summary and key points
      required by the schema.

    schema {
        summary:   string    # concise paragraph summarising the topic
        keyPoints: string[]  # the most important points
        sources:   string[]  # URLs or titles used
    }
}

Read top to bottom: declare tools, fetch deterministically, gather with a prePrompt, then produce the typed output with the one prompt.

Next steps

← All guides

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.