# Anatomy of a session

A **session** is the core unit of an FML blueprint. 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 blueprint 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 blueprint](/content/docs/guides/hello-world-plan/index.html) 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 blueprint'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 blueprint](/content/docs/guides/control-plan-flow#rename-the-output-key-with-target/index.html).

## 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,
- whatever you transfer in with a `context` directive (which requires `after`).

That isolation 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](/content/docs/guides/data-flow-in-a-plan/index.html)).

## 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 `-` |
| --- | --- | --- |
| 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](/content/docs/guides/call-tools-from-a-plan/index.html) 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](/content/docs/guides/design-output-schemas/index.html).

## 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](/content/docs/guides/precalls-deep-dive/index.html).

## 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

- Learn how data moves between sessions in [Data flow: params, vars & context](/content/docs/guides/data-flow-in-a-plan/index.html).
- Shape richer output in [Design your output schemas](/content/docs/guides/design-output-schemas/index.html).
- Sequence and gate sessions in [Control the flow of a blueprint](/content/docs/guides/control-plan-flow/index.html).
- Full reference: [Sessions](https://github.com/FragsHQ/frags/wiki/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.
