Skip to content

Getting Started

theirish81 edited this page Sep 3, 2026 · 2 revisions

Getting Started with FML

This guide introduces the core concepts of FML (Frags Modeling Language) and walks you through authoring and structuring your first agentic execution plan.


What is FML?

FML is a declarative, domain-specific programming language designed to orchestrate complex, multi-stage LLM agent pipelines. While traditional agent prompts often mix tool calling, reasoning, context formatting, and output structuring into a single massive, fragile prompt, FML breaks the workflow into a deterministic directed acyclic graph (DAG) of sessions.

The Core Problem FML Solves

When prompting frontier models like Gemini 3 Pro to execute complex tasks:

  1. Tool Pollution & Hallucination: Asking an LLM to call tools while simultaneously producing a strict JSON schema frequently results in malformed JSON or unnecessary tool calls.
  2. Context Bloat: Dumping massive API payloads directly into the model context window wastes tokens and degrades reasoning quality.
  3. Lack of Determinism: Pure LLM chains can fail unpredictably when simple transformations (such as array filtering, ID extraction, or API piping) could be executed deterministically.

FML solves these issues by providing:

  • Phased Execution: Enforces tool calls strictly during Pre-Prompts (+), and disables tools completely during Prompts (-) for flawless schema formatting.
  • Deterministic PreCalls: Allows running native tools and sandboxed JavaScript transformations before the LLM ever sees the data.
  • Rigid Namespace Scoping: Keeps parameter declarations (params), runtime variables (vars), and session outputs (context) isolated.

Core Mental Model

An FML file consists of two primary layers:

┌─────────────────────────────────────────────────────────┐
│ Global Scope                                            │
│   • System Prompt (`system`)                            │
│   • Parameters (`parameter`)                            │
│   • Global Variables (`set`)                            │
│   • External Tool Dependencies (`require`)              │
│   • Reusable Components (`components`)                  │
│   • Global PreCalls (`call`)                            │
└────────────────────────────┬────────────────────────────┘
                             │
                             ▼
┌─────────────────────────────────────────────────────────┐
│ Session DAG (Execution Graph)                           │
│                                                         │
│   ┌─────────────────────────────────────────────────┐   │
│   │ session("ingest")                               │   │
│   │   1. PreCall: Fetch external data               │   │
│   │   2. Pre-Prompt (+): Tool use & information gathering│
│   │   3. Prompt (-): JSON structuring               │   │
│   │   4. Schema validation                          │   │
│   └────────────────────────┬────────────────────────┘   │
│                            │ context.ingest             │
│                            ▼                            │
│   ┌─────────────────────────────────────────────────┐   │
│   │ session("analyze", after="ingest")              │   │
│   │   1. Context Injection                          │   │
│   │   2. Prompt (-): Evaluation & Analysis          │   │
│   │   3. Schema validation                          │   │
│   └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
  1. Global Configuration: Defines the environment, system persona, global input parameters, and required tool integrations (such as Model Context Protocol / MCP servers).
  2. Sessions: Independent execution units that run either sequentially or as part of a dependency graph defined by after="upstream_session".

Step-by-Step: Your First FML Plan

Let's build a practical FML plan: An Automated Competitive Intelligence Pipeline.

Step 1: Declare the System Persona & Parameters

Every plan can declare a global system prompt and typed parameter inputs that users supply at runtime:

# Set global instruction for all sessions
system(`You are a senior tech analyst. Provide concise, fact-checked analysis.`)

# Declare input parameters with type and defaults
parameter("competitor", type="string", default="Acme Corp")
parameter("depth", type="string", default="standard", enum=brief|standard|deep)

Note

parameter supports types string, int, and bool. The enum=val1|val2 attribute restricts allowable values.

Step 2: Declare External Tool Requirements

Tools such as MCP servers or internal databases are declared at the root level using require:

# Declare external tool integrations
require mcp market_feed

Important

Global require statements are strictly single-line declarations. Never provide configuration bodies or allowlists at the root level.

Step 3: Define Reusable Output Schemas

In the components block, define schemas that can be referenced across multiple sessions using $ComponentName:

components {
    schema("NewsItem") {
        headline: string        # Article headline
        source: string          # Publication name
        impact: low|medium|high # Assessed business impact
    }
}

Step 4: Write Session 1 (Data Gathering)

Session 1 uses tools to find information. Notice the use of + (Pre-prompt) where tool calling is permitted:

session("gather_news", target="news_data") {
    # Activate tools specifically needed for this session
    use mcp market_feed { allowlist = ["search_headlines", "get_article"] }

    # Phase 2: Pre-prompt (Tool use ENABLED)
    + Search market feeds for recent developments regarding {{ .params.competitor }}.
      Collect the top 3 most impactful news items.

    # Phase 3: Prompt (Tool use DISABLED - Schema mapping only)
    - Structure the gathered news items into the output schema.

    # Phase 4: Schema validation
    schema {
        company: string
        items: $NewsItem[]
    }
}

Step 5: Write Session 2 (Synthesis & Analysis)

Session 2 depends on Session 1. It declares after="gather_news", accesses context.news_data, and produces the final report:

session("synthesize_report", after="gather_news") {
    # Inject context from Session 1 formatted as JSON
    context "News gathered: {{ .context.news_data | json }}"

    # Prompt (No tool calling needed, pure analytical synthesis)
    - Based strictly on the gathered news items, summarize the competitor's
      strategic trajectory and assign an overall threat level.

    schema {
        summary: string # Analytical summary
        threat_level: low|medium|high # Competitive threat level
        recommended_countermeasures: string[]
    }
}

How Plans Execute

When the FML runtime executes this plan:

  1. Parameter Resolution: Verifies that "competitor" and "depth" match their declared types and constraints.
  2. Session Graph Construction: Identifies that synthesize_report depends on gather_news via after.
  3. Execution of gather_news:
    • Pre-execution phase runs any deterministic call statements (none in this session).
    • Phase 2 executes the + pre-prompt. Gemini 3 Pro receives the tool definitions from use mcp market_feed and executes tool calls until it has gathered the necessary headlines.
    • Phase 3 strips all tool definitions from the LLM and runs the - prompt. Gemini structures the raw data into JSON.
    • Phase 4 validates the JSON against schema { company: string, items: $NewsItem[] }.
    • The validated JSON is published under context.news_data.
  4. Execution of synthesize_report:
    • The context block interpolates context.news_data using Go template JSON serialization (| json).
    • The prompt is evaluated and validated against the schema.
    • Plan terminates with the final output.

Key Takeaways

  • + vs -: Use + for doing work (calling tools, researching, drafting). Use - for formatting into JSON.
  • Dependencies: Always specify after="upstream_session" when referencing context.upstream_session.
  • Namespaces: Reference parameters via {{ .params.name }} in templates and params.name in expressions.
  • Safety: The runtime strictly validates types and prevents tool calling during final schema generation.

Next Steps

Clone this wiki locally