Predictable agents should be as easy as writing Markdown.

Margarita introduces a deterministic scripting extension to Markdown that keeps your agents predictable. No more fighting with your prompt to make it follow your workflow steps.

review.mgx
// These are variables @state score = 3 @state feedback = "" // This is Markdown. It is added to the Context Window // score gets substituted and score/feedback are set by the llm. << The current score is ${score}. Review this code snippet and set `score` to a number from 0–10 and `feedback` to a one-sentence summary of the quality. ```python def add(a, b): return a+b ``` >> // This runs the agent // score is set to 72 // feedback is set to Simple and correct... @effect run // This adds more to the context. << Explain the score of ${score} in more detail and tell me about the feedback. >> // We run the agent and get the final response. @effect run
margarita run review.mgx
Run 1 completed 5.2s
This code appears correct however it could use some improvements. Setting the score and feedback.
↳ set score    = 72
↳ set feedback = "Simple and correct..."
Response:
Set the score to 72 and feedback to "Simple and correct,
but missing type hints and a docstring."
Tokens:    11,430 in   198 out
Requests:  1
Run 2 completed 4.8s
The score is 72 and I need to fetch the feedback from state.
↳ get feedback
Response:
A score of 72 reflects functional code that does the job,
but leaves room for improvement. The feedback — "Simple
and correct, but missing type hints" — points to gaps
in readability and long-term maintainability.
Tokens:    11,628 in   312 out
Requests:  2
 All turns completed  q to quit

We can create workflows in a prompt, but should we?

Margarita is for people that are looking for repeatable scripts that add in the dynamic abilities of LLMs where it makes sense.

Use the right tool for the job. Write code-like logic where you need consistency. Bring in a code agent where you need complexity/ and dynamic responses.

Why Margarita

01

Use determinism where it makes sense

The syntax is a very minimal extension to markdown and will always run the same. No more having the llm skip a step in your workflow every 3rd time you run it. No more inventing properties your JSON objects. Keep control when you need control.

02

Prune your context, keep costs low

Most AI code harnesses hide the context from you. Margarita gives you complete control. Turf data you don't need. Add the specific tools you need and no more. Run Python functions locally instead of burning tokens on tool calls. All of these methods can keep your contexts focused and tight.

@effect context clear
@effect func summarize("A really long text input") => summary
03

Compose prompts from reusable .mg files

Remember React? Compose prompts together just like it. Use conditional logic and parameter passing. Render fragments in a loop. All the things you wished Markdown shipped with.

[[ snippets/role.mg is_admin=True permission="view" ]]

What can you build?

02

Tools to summarize your emails

Create a Margarita script that loads your inbox from Apple Mail, injects the results into a prompt, and gets a categorized summary with action items.

from src.applemail import load_emails

@effect func load_emails(limit=20) => result

<<
Summarize the last 20 emails I've gotten.

- Categorize them.
- Give me an action item list.
- Ignore spam type emails.

Here are the emails: ${result}
>>

@effect run
See full guide: Summarize Your Emails →
01

A custom agent loop

Want to build a custom ralph loop? Create a custom agent that has all the steps you want.

@effect input "What do you want to build?:" => userInput

// We have a prompt in this file to break input into tasks
// This is an example of an include
[[ break_down_input_into_tasks.mg input=userInput ]]

// Also tell the llm to store into the tasks var
<< Store the tasks into a json array in the variable `tasks`>>

@effect run

// The agent broke the tasks down now we implement each task
for task in tasks:
    @state isDone = false
    for i in range(MAX_ITERATIONS):
        // Use the code agent to implement the task
        @effect run

        if isDone:
          break
See full guide: Build a Custom Ralph Wiggum Loop →
03

Build an LLM enabled Game

Want to build an LLM enabled game? Create a game loop that prompts the model for the next move, then feeds the result back into the next turn's context.

if type == "mage":
    [[ src/mage.mg ]]
elif type == "fighter":
    [[ src/fighter.mg ]]

@state health = 100
@state isFree = false

for i in range(0, 100):
    @effect input "What do you do?" => action
    @effect run
    if health <= 0: break
    if isFree: break
See full guide: Build Dungeon Quest →
···

And much more.

Automated code review pipelines. Scheduled reports. Data enrichment workflows. Slack bots. Anything that benefits from a repeatable, readable script driving an LLM.

.mgx Tour

Check out some of the other things you can do with Margarita

Hello World

Your first .mgx file. Log a message, declare a state variable, write a prompt block, and run the agent — that's all it takes to get started with Margarita.

---
description: Hello World!
---

// Log a message before the agent starts
@effect log "Welcome to Margarita, let's get started!"

// Declare a state variable
@state variableA = "Hello World"

// Build the prompt
<< Why do we create ${variableA} programs? >>

// Run the agent
@effect run

Running the Agent

Use @effect run to execute the agent at any point in your .mgx file. Run it multiple times — Margarita renders all accumulated << >> blocks into the prompt before each call.

# assistant.mgx
---
description: A simple Margarita agent that answers a question.
---

// 1. Add this to the context
<< You are a helpful assistant. What is the answer to life the universe and everything? >>

// 2. Run the agent
@effect run

// 3. Add more to the context
<< You need to think harder this time? >>

// 4. Run the agent again!
@effect run

Conditionals & Loops

Use if var == value: / else: to include or exclude sections of your prompt based on context. Use for item in list: to loop over data.

# access.mg
---
parameter: level (string): Access level of the user, e.g. "admin" or "user".
---
<< Access level: ${level} >>
if level == "admin":
  << You have full access. >>
else:
  << Read-only mode. >>

# tasks.mg
---
description: A template that demonstrates looping over a list of tasks.
---
<< ## My Tasks >>
for task in tasks:
  << - ${task} >>

Includes

React-like composability with includes. Write a .mg fragment once and drop it into any script or template.

# components/greeting.mg
---
description: A simple greeting component that can be included in other templates.
parameters: user (string): The name of the person to greet.
---
<< Hello, ${user}! >>

# report.mg
---
description: A report template that includes a greeting component.
---
[[ components/greeting.mg user="Batman" ]]

State

Values stored by the agent, @effect func, or @effect tools persist for the lifetime of the run — any prompt block can read from state at any point.

# stateful.mgx
---
description: Show how the agent state works.
---
@state count = 5
@state user = "Batman"

<<
The agent can get/set state variables using markdown.

Update the count variable to 10 and print out the user variable.
>>

@effect run

User Input

Use @effect input to pause execution and prompt the user for a value. The response is stored in state and available to the rest of the script.

# build-assistant.mgx
---
description: Prompt the user, then run the agent with their input.
---

// Pause and ask the user a question
@effect input "What do you want to build?:" => userInput

// Use the captured input in context
<<
You are a helpful build assistant.
Help the user build: ${userInput}
>>

@effect run

Memory

Use @memory var to declare a persistent variable that survives across runs. Values are read on startup and written back at the end — letting you build workflows that remember what happened last time.

# memory-example.mgx
---
description: Test Memory
---

// Declare a memory variable — loaded from persistent storage
@memory var valueA

<<
If valueA is not set, Set `valueA` to "This is a test of memory."
Otherwise write out it's set!
>>

@effect run

Files

The agent has built-in tools — read_file, write_file, search_files, and ask_user. Just tell it what to read or write in your prompt and it handles the rest.

# file-example.mgx
---
description: Read notes and write a summary
---

// The agent reads and writes files on its own — no boilerplate needed
<<
Read the file at ./data/notes.txt

Summarize the key points and write the result to ./output/summary.md
>>

@effect run