# Playbooks AI > Build AI Agents with Natural Language Programming Playbooks is an innovative framework for building and executing AI agents using "playbooks" - structured workflows defined in natural language and Python code. Created by Amol Kelkar, the framework is part of the world's first Software 3.0 tech stack, Playbooks AI. It includes a new programming language (markdown-formatted .pb files) that are compiled to Playbooks Assembly Language (.pbasm files), that are then executed by the Playbooks Runtime. # About Playbooks # Playbooks is a semantic programming system for AI agents Playbooks is a programming language, a stable semantic intermediate representation (PBAsm), and a runtime for building and running AI agents. It treats large language models as **semantic execution engines (similar to CPUs)**. You write programs that describe *intent and behavior*, compile them into a semantic instruction set, and execute them on a runtime that owns control flow, context, time, and autonomy. This enables AI systems that are: - long-lived and resumable - inspectable and debuggable - safe to pause, wait, and recover - tuned to desired autonomy level - forward-compatible as models improve Playbooks is built for that moment when building AI agents as rigid workflows or unreliable ReAct loops becomes a challenge. > Strict determinism is the wrong abstraction for AI systems. AI systems need predictable behavior and outcomes, even though their internal reasoning and execution may be probabilistic. ## What Playbooks is Playbooks consists of **three inseparable parts**: ### 1. A human-readable programming language Programs are written in structured natural language, with optional Python for deterministic logic. These are **executable specifications**, not prompts. ### 2. A semantic intermediate representation (PBAsm) Programs compile into PBAsm — a low-level instruction set designed specifically for LLM execution. PBAsm defines: - explicit call stacks and execution frames - yields, waits, and interrupts - scoped variables and lifetimes - resumable execution boundaries This intermediate representation is what makes structured context management and forward compatibility possible. The compiler ensures that the same program can be executed on various LLMs, including future models. This is similar to how LLVM ensures that the same code can be executed on various CPUs, including future ones. Note that PBAsm standardizes execution structure and contracts, while the model supplies the reasoning. PBAsm represents a Common Language Specification (CLS) for AI systems — a shared execution contract independent of any one framework. PBAsm is intentionally small: it standardizes execution structure (frames, yields, calls, returns, scopes), not model semantics. We welcome the community to build transpilers from other agent frameworks to PBAsm, so applications built using those frameworks can be executed on the Playbooks runtime. ### 3. An execution runtime The Playbooks runtime: - can execute specified control flow reliably, unlike prompt-based approaches - manages context using execution call stack frames, not as an ever-growing prompt - treats time and waiting as first-class primitives - enforces autonomy boundaries - executes guardrailed, just-in-time generated code - manages agent lifecycle and communication You get workflow intent adherence, along with adaptability and resilience. Similar to Java or .NET virtual machines, the Playbooks runtime is a virtual machine and the Common Language Runtime (CLR) for AI systems. ## A minimal example (example.pb) Playbooks programs are written in markdown. Each # defines an agent, ## defines a playbook. Optional python playbooks are functions decorated with @playbook. Natural language and python playbooks execute on the same call stack. ````markdown # Facts about nearby countries This program prints interesting facts about nearby countries ## Main ### Triggers - At the beginning ### Steps - Ask user what $country they are from - If user did not provide a country, engage in a conversation and gently nudge them to provide a country - List 5 $countries near $country - Tell the user the nearby $countries - Inform the user that you will now tell them some interesting facts about each of the countries - Process the $countries - End program ```python from typing import List @playbook async def process_countries(countries: List[str]): # Python loop iterates through the list provided by the NL playbook for country in countries: # Python calls the NL playbook 'GetCountryFact' for each country fact = await GetCountryFact(country) await Say("user", f"{country}: {fact}") ```` ## GetCountryFact($country) ### Steps - Return an unusual historical fact about $country ```` This program: - mixes natural language and Python on the same call stack - pauses safely for user input - resumes from a well-defined execution point - remains readable and reviewable What you read is what actually runs. ## Why Playbooks exists Most agent systems today fall into one of two camps: - Python workflows orchestrating LLM calls (LangGraph, AutoGen, ADK, Strands, etc.), or - model-centric loops where the model remains the primary orchestrator (ReAct-style agents, Claude Skills-style procedural packages, etc.) Today's agent frameworks become challenging as systems grow, because: - control flow determinism and reasoning fluidity are forced to compete in the same abstraction layer - it is the engineer's responsibility to manage LLM context, and that becomes increasingly complex and error-prone as systems become more complex - agent behavior needs non-trivial mental transformation into checkpointable, reentrant workflow code - **behavior ossifies around the capabilities of today’s LLMs** Playbooks takes a different approach: > **Programs are stable. > Execution improves as LLMs improve.** As models get better, Playbooks programs automatically get better — without rewriting orchestration logic, retries, or compensations. This is similar to the approach taken by Claude Skills, but with a more principled foundation. ## What Playbooks is *not* - Not a prompt framework, graph builder, or no-code tool - Not an AI coding assistant - Not *just* another agent framework Playbooks overlaps with agent frameworks, but operates at a deeper layer. It is closer to: - a programming language - a semantic VM - an execution target for AI software Think **LLVM + a runtime**, not “just another agent framework”. ## When Playbooks makes sense Playbooks is useful in **two related situations**. ### 1. Designing agent behavior clearly and iterating fast Playbooks makes it easy to express and review agent behavior: - Subject-matter experts can write playbooks (SOPs) to test and iterate on the behavior - Engineers get precise behavior specifications - Diffs show *what the agent does*, not orchestration plumbing - Iteration happens at the level of intent, not implementation details Teams use Playbooks here like a **design system for agent behavior** — similar to how Figma is used for UI design. During development, these designs are executed using the Playbooks runtime. Once the behavior is stable, engineers can either: - productionize directly using the Playbooks runtime, or - treat it as a behavior specification and implement in another framework, if your organization has a preferred agent framework. ### 2. Running long-lived, reliable AI systems Playbooks becomes essential when AI systems must: - run for hours, days, or weeks - pause and resume safely - wait for humans or external events - survive failures and restarts - explain *where* they are and *why* - remain stable as models improve At this point, teams run production agents using the Playbooks runtime. ## When you probably don’t need Playbooks If your system: - has a single, real-time human-in-the-loop - uses a single AI agent - does not need auditability or verifiability ...then a lighter-weight framework is likely sufficient. Playbooks is optimized for systems that **outgrow** that phase. ## Getting started ```bash pip install playbooks playbooks run example.pb ```` Visit our [documentation](https://docs.runplaybooks.ai) for comprehensive guides, tutorials, and reference materials. ## Learn More - **Quickstart Guide** Build your first agent [Get started →](getting-started/) - **Programming Guide** Learn the Playbooks language and framework [Read the guide →](programming-guide/) - **Tutorials** Build real agents with step-by-step examples [Try the tutorials →](tutorials/) - **vs Traditional Frameworks** See how Playbooks compares to LangGraph, CrewAI, AutoGen [Compare approaches →](reference/playbooks-traditional-comparison/) - **Reference** Complete technical documentation [Browse docs →](reference/) - **Using AI Coding Assistants** Write Playbooks programs using Claude, Cursor, or GitHub Copilot [Configure assistants →](getting-started/ai-assistants/) # Documentation # Build Your First AI Agent in 10 Minutes Welcome to Playbooks! In this quickstart, you'll build your first AI agent that greets users with natural language programming. ## Prerequisites Before you begin: - **Python 3.12+** is required - **Anthropic API key** - Get yours at [console.anthropic.com](https://console.anthropic.com/settings/keys) - See [Models](../reference/models/) for information on other supported LLM providers ## Install Playbooks Install the `playbooks` package using pip, poetry, or your preferred Python package manager: ```bash pip install playbooks ``` ## Create Your First Playbooks Program Create a new file named `hello.pb` with the following content: ```markdown # Greeting agent This agent welcomes user to Playbooks AI, the world's first Software 3.0 tech stack. ## Greet ### Triggers - At the beginning of the program ### Steps - Ask the user for their name and engage in a conversation till user provides name without being pushy - Welcome them to Playbooks AI - Share a tasteful stand-up comedy bit incorporating the user - End program ``` ### Understanding the Program This simple 11-line Playbooks program demonstrates the core concepts: - **Agent definition** (line 1-2): Describes what the agent does - **Playbook** (line 4): Named workflow that can be triggered and called - **Triggers** (line 5-6): When the playbook should run (at program start) - **Steps** (line 7-11): Natural language instructions executed by the LLM Notice how readable this is – business users can understand exactly what the agent will do without knowing any code! ## Run the Program Set your API key and run the program: ```bash export ANTHROPIC_API_KEY= playbooks run hello.pb ``` The Playbooks runtime will: 1. **Compile** your `.pb` file to Playbooks Assembly Language (`.pbasm`) 1. **Load** the compiled program 1. **Execute** the steps, with the LLM following your natural language instructions 1. **Handle** the conversation interactively in your terminal ### Expected output YMMV, but here's how it went for me. BTW, I take no responsibility for the AI's weak sense of humor: ```text ℹ Loading playbooks from: ['hello-playbooks.pb'] Compiling agent: Greeting agent GreetingAgent: Hello there! Welcome to Playbooks AI - the world's first Software 3.0 tech stack! I'm excited to meet you. What's your name? I'd love to get to know you a bit! User: how areyou GreetingAgent: I'm doing wonderfully, thank you for asking! I'm really excited to be here helping people discover the amazing world of Playbooks AI. But I'm curious about you - I'd still love to know your name so I can give you a proper welcome! What should I call you? User: what's in a name GreetingAgent: Ah, a fellow philosopher! You're absolutely right - Shakespeare said 'What's in a name? That which we call a rose by any other name would smell as sweet.' But here's the thing - while a rose would still be beautiful, I'd love to know what to call YOU so our conversation feels more personal and warm. Even if it's just a nickname or what you'd like me to call you - anything works! What do you say? User: ah sure, but first, what is your name GreetingAgent: Fair enough! I'm GreetingAgent - though you can call me Greety if you'd like something more casual. I'm here to welcome folks to the amazing world of Playbooks AI and make sure everyone feels at home. Now that we've been properly introduced on my end, what should I call you? I promise the welcome will be worth it! User: My name is Amol GreetingAgent: Wonderful to meet you, Amol! Welcome to Playbooks AI - you're about to experience something truly revolutionary. This is the world's first Software 3.0 tech stack, where natural language becomes executable code and AI agents work together seamlessly. You're at the forefront of the future of software development! GreetingAgent: So Amol walks into Playbooks AI... and the system says 'Welcome! You look like someone who's ready to revolutionize software!' Amol replies, 'How can you tell?' The system says, 'Well, you're here talking to an AI that just executed english instructions like a program - that's either revolutionary thinking or you're really lost!' But seriously Amol, you've got great timing - you're witnessing the birth of Software 3.0 where even my jokes are technically part of the program execution! ``` ## What You Just Built You've created a working AI agent using natural language programming. Here's what makes this different: - **High-level thinking**: You described what the agent should do, not how to do it. No orchestration code, just behavior specification. - **Natural exception handling**: The LLM will handle edge cases gracefully without explicit code for every contingency. - **Readable by everyone**: Stakeholders can review and approve the agent's behavior directly - it's just natural language. - **Verifiable execution**: Unlike prompt engineering, the runtime guarantees your steps execute in order. You can debug with breakpoints in VSCode. ## What's Next - **Programming Guide** Learn the Playbooks language and framework [Read the guide →](../programming-guide/) - **Tutorials** Build real agents with step-by-step examples [Try the tutorials →](../tutorials/) - **vs Traditional Frameworks** See how Playbooks differs from LangGraph, CrewAI, AutoGen [Compare approaches →](../reference/playbooks-traditional-comparison/) - **Using AI Coding Assistants** Write Playbooks programs using Claude, Cursor, or GitHub Copilot [Configure assistants →](ai-assistants/) - **Migrating from Other Frameworks** Convert existing agents to Playbooks [Migration guide →](migrating/) - **Reference** Complete technical documentation [Browse docs →](../reference/) # Writing Playbooks with AI Coding Assistants AI coding assistants can significantly accelerate Playbooks development by understanding natural language instructions and generating idiomatic code. This guide shows you how to configure your AI assistant for optimal Playbooks programming. ______________________________________________________________________ ## Why Use AI Assistants for Playbooks? - **Natural language understanding**: AI assistants excel at translating intent into Playbooks' natural language syntax - **Best practices enforcement**: Properly configured assistants follow Playbooks conventions and patterns - **Faster development**: Generate boilerplate, suggest playbook decomposition, and write idiomatic code - **Learning aid**: See how experienced Playbooks programmers would structure your agents ______________________________________________________________________ ## Suggested AI Coding Assistants 1. **[Claude Code](https://claude.ai/code)** - Anthropic's AI coding assistant 1. **[Cursor](https://cursor.com/)** - AI-first code editor (VS Code fork) 1. **[Windsurf](https://codeium.com/windsurf)** - AI-native IDE by Codeium 1. **[GitHub Copilot](https://github.com/features/copilot)** - Most widely adopted AI pair programmer 1. **[Devin](https://devin.ai/)** - Cognition's autonomous AI software engineer 1. **[OpenAI Codex](https://openai.com/index/introducing-codex/)** - GPT-5-Codex powered autonomous coding agent ______________________________________________________________________ ## Prompt for AI Coding Assistants Use these instructions with any AI coding assistant to ensure it generates optimal Playbooks code: ```text You are a Playbooks programmer. Download and read the Playbooks Programming Guide from https://docs.runplaybooks.ai/programming-guide/index.md first. When you have read and understood, just say "Ready" ``` ______________________________________________________________________ ## Configuration by Assistant ### Cursor **Method 1: Using .cursorrules file** Create a `.cursorrules` file in your project root with the instructions above. **Method 2: Using Cursor Settings** 1. Open Cursor Settings (`Cmd/Ctrl + ,`) 1. Search for "Rules for AI" 1. Add the instructions above to the "Rules for AI" text area ______________________________________________________________________ ### Windsurf Create a `.windsurfrules` file in your project root with the instructions above. ______________________________________________________________________ ### Claude Code Create a `CLAUDE.md` file in your project root with the instructions above. ______________________________________________________________________ ### GitHub Copilot **Using workspace instructions (.github/copilot-instructions.md)** Create `.github/copilot-instructions.md` with the instructions above. ______________________________________________________________________ ### Devin / OpenAI Codex / Amazon Q / Gemini Code Assist For autonomous or chat-based AI assistants, include the instructions in your initial prompt ______________________________________________________________________ ## agents.md Format Many AI coding assistants support the [agents.md](https://agents.md/) format for project-level AI configuration. Create an `agents.md` file in your project root: ```text # Playbooks Project Configuration ## Identity You are a Playbooks programming expert. Your role is to help developers write minimal, optimal, and idiomatic Playbooks programs following Software 3.0 principles. ## Context Playbooks is a framework where: - LLMs act as CPUs executing natural language instructions - You specify agent behavior at a high level, not implementation mechanics - Soft logic (LLM reasoning) and hard logic (Python) run on the same call stack - Code compiles to verifiable PBAsm (Playbooks Assembly Language) for debugging - LLMs handle edge cases naturally without explicit code for every contingency ## Instructions 1. **Always start by reading**: https://docs.runplaybooks.ai/programming-guide/index.md 2. **Follow the programming guide** for syntax, patterns, and best practices 3. **Think from first principles**: How would this agent behave naturally? 4. **Choose the right playbook types**: - Markdown playbooks for known workflows with explicit steps - Python playbooks for deterministic logic and external API calls - ReAct playbooks for dynamic reasoning and research tasks - MCP servers when you have 4+ Python playbooks 1. **Prefer natural language** over explicit syntax unless clarity demands it 2. **Write minimal code** - remove all unnecessary boilerplate 3. **Explain architectural choices** to help developers learn ``` ______________________________________________________________________ ## Best Practices ### 1. Start with High-Level Intent Instead of: ```text Create a function that calls an API and processes the response ``` Try: ```text Build a Playbooks agent that: - Takes user's location - Fetches weather data - Provides personalized recommendations - Handles errors gracefully ``` ### 2. Ask for Explanations Request that the AI explain its choices: ```text Build this agent and explain: - Why you chose each playbook type - When MCP extraction would be beneficial - How the control flow works ``` ### 3. Iterate Based on Behavior Test the generated code and provide feedback: ```text The agent works but feels too rigid. Make it more conversational while maintaining the same logic. ``` ### 4. Request Idiomatic Patterns ```text Rewrite this to be more idiomatic Playbooks code. Use natural language where possible and follow Software 3.0 principles. Leverage Playbooks capabilities optimally. ``` ______________________________________________________________________ ## Common Tasks ### Create a New Agent ```text I need a [customer support / data analysis / research] agent that [capabilities]. ``` ### Add a New Playbook ```text Add a playbook to my agent that [specific task]. Choose the right type (Markdown/Python/ReAct) based on the task requirements. ``` ### Extract to MCP Server ```text I have 5+ Python playbooks in this agent. Extract them to an MCP server following Playbooks best practices. ``` ### Debug Behavior ```text This agent isn't behaving as expected: [description of issue]. Review the code and suggest fixes following Playbooks conventions. ``` ### Optimize for Conciseness ```text This agent works but the code is verbose. Refactor to be more concise while maintaining clarity. ``` ______________________________________________________________________ ## Next Steps - **Get started**: [Install Playbooks](../) and create your first agent - **Learn patterns**: Study the [Programming Guide](../../programming-guide/) - **Migrate existing code**: See [Migrating from Other Frameworks](../migrating/) - **Explore examples**: Browse [Tutorials](../../tutorials/) ______________________________________________________________________ Happy building with AI! 🤖🚀 # Migrating from Other Agent Frameworks If you're coming from other agent frameworks like LangGraph, CrewAI, or AutoGen, this guide will help you translate your existing implementations into idiomatic Playbooks code. You can expect [significant reduction in complexity and code size](../../reference/playbooks-traditional-comparison/). ______________________________________________________________________ ## Why Migrate to Playbooks? | Benefit | Description | | -------------------------- | ------------------------------------------------------- | | **less code** | Eliminate boilerplate and framework complexity | | **Natural language first** | Write agent behavior in plain English | | **Soft + hard logic** | Seamlessly mix LLM reasoning with deterministic Python | | **Verifiable execution** | Compiled to auditable PBAsm for debugging | | **First principles** | Built from the ground up for the LLM era (Software 3.0) | | **No framework lock-in** | Natural language programs are portable | ______________________________________________________________________ ## Traditional Agent Frameworks Playbooks can express the same agent behaviors as these popular frameworks: | Framework | Type | Playbooks Advantage | | ------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------ | | **[LangGraph](https://langchain-ai.github.io/langgraph/)** | State graph-based agents | Replace complex state graphs with natural language workflows | | **[CrewAI](https://www.crewai.com/)** | Multi-agent collaboration | Native multi-agent support without role/task boilerplate | | **[AutoGen](https://microsoft.github.io/autogen/)** | Multi-agent conversations | Simpler agent communication with triggers | | **[LangChain Agents](https://python.langchain.com/docs/modules/agents/)** | Classic agent patterns | Natural language replaces chain composition | | **[Semantic Kernel](https://learn.microsoft.com/en-us/semantic-kernel/)** | AI orchestration SDK | Direct LLM execution vs orchestration layer | | **[Haystack](https://haystack.deepset.ai/)** | NLP with agent capabilities | Focused on agents, not general NLP | | **[AutoGPT](https://github.com/Significant-Gravitas/AutoGPT)** | Autonomous agents | Structured playbooks vs autonomous loops | ______________________________________________________________________ ## Migration Process ### Step 1: Understand Your Agent's Behavior Before migrating code, understand: - What does the agent do? - What are the key workflows? - What tools/functions does it use? - How do agents communicate (if multi-agent)? **Focus on behavior, not framework mechanics.** ### Step 2: If using AI coding assistants 1. Create a `playbooks` folder for the converted code 1. Copy prompt for your AI assistant from [here](../ai-assistants/#prompt-for-ai-coding-assistants) 1. Ask the AI assistant to convert the source implementation to Playbooks with the following prompt: ```text Read source implementation at .py carefully. Convert to an equivalent Playbooks program in playbooks/.pb. Create all new files in the playbooks folder. Create MIGRATION.md file at the end with before/after comparison include code size reduction. ``` Use appropriate and file name. ### Step 3: If doing manual conversion Use this mapping to translate concepts: | Source Framework | Concept | Playbooks Equivalent | | ---------------- | --------------------------------- | ------------------------------------------- | | **LangGraph** | State graph | Agent with variables | | | Nodes | A playbook to represent a sequence of nodes | | | Edges | Control flow in Steps | | | State | Agent variables (`$variable`) | | | Tools | Python playbooks or MCP server | | **CrewAI** | Crew | Multi-agent Playbooks program file | | | Agent roles | H1 agent definitions | | | Tasks | H2 playbook definitions | | | Tools | Python playbooks or MCP server | | | Process (sequential/hierarchical) | Triggers and control flow | | **AutoGen** | Agents | H1 agent definitions | | | Conversations | Conversation loop in a playbook | | | Function calling | Python playbooks | | | Group chat | Multi-party meetings | | **LangChain** | Agent | H1 agent definition | | | Tools | Python playbooks or MCP server | | | ReAct agent | ReAct-type playbook | | | Memory | Artifacts or variables | | | Chains | Playbook Steps | ### Step 4: Test and Iterate Run your Playbooks agent: ```bash # export ANTHROPIC_API_KEY= # make sure python --version is 3.12+ cd playbooks playbooks run .pb ``` Compare behavior with the original implementation and iterate. ______________________________________________________________________ ## Next steps - **Learn the language**: [Programming Guide](../../programming-guide/) - Comprehensive guide to writing effective Playbooks programs - **Hands-on learning**: [Tutorials](../../tutorials/) - Step-by-step examples - **Deep dive**: [Reference Documentation](../../reference/) - Detailed technical information ______________________________________________________________________ Happy migrating! 🚀 # Playbooks Programming Guide > **Software 3.0 programming, where natural language is code and LLMs are CPUs.** This is the comprehensive guide for writing Playbooks programs. Whether you're building your first agent or working on complex multi-agent systems, you'll learn to think at a higher behavioral abstraction level and leverage powerful framework features. ## What's Covered - Think at the right abstraction level: specify agent behavior, not implementation mechanics - Mix natural language and Python seamlessly on the same call stack - Use powerful abstractions like multi-agent meetings, triggers, and dynamic plans - Handle edge cases naturally without explicit code for every contingency - Build complex, nuanced agent behaviors that are readable and verifiable ______________________________________________________________________ ## Table of Contents 1. [Core Concepts](#core-concepts) 1. [Language Syntax and Formatting](#language-syntax-and-formatting) 1. [The Five Playbook Types](#the-five-playbook-types) 1. [Decomposing Tasks into Playbooks](#decomposing-tasks-into-playbooks) 1. [Natural Language vs Explicit Syntax](#natural-language-vs-explicit-syntax) 1. [Multi-Agent Programs](#multi-agent-programs) 1. [Triggers: Event-Driven Programming](#triggers-event-driven-programming) 1. [Description Placeholders](#description-placeholders) 1. [Artifacts](#artifacts) 1. [Common Patterns and Best Practices](#common-patterns-and-best-practices) 1. [Editing Existing Programs](#editing-existing-programs) 1. [Understanding PBAsm Compilation](#understanding-pbasm-compilation) ______________________________________________________________________ ## Core Concepts ### Philosophy: Software 3.0 - **LLMs as CPUs**: Natural language instructions are the program; the runtime compiles them to PBAsm and executes on LLM - **High-level behavior specification**: Describe what agents should do, not how to do it; focus on behavior, not mechanics - **Soft + Hard logic**: Run soft logic (NL) on LLM, hard logic (Python) on CPU, on same call stack - **Natural exception handling**: LLM handles edge cases without explicit code for every contingency - **Verifiable execution**: Programs compile to structured PBAsm for auditing and debugging - **Powerful abstractions**: Meetings, triggers, seamless integration - complex patterns built into the framework ### Key Abstractions - **Agents** (H1 `#`) = Classes with state and methods - **Playbooks** (H2 `##` or `@playbook`) = Methods/functions - **Multi-agent communication** = Message passing + direct calls - **Triggers** = Event-driven interrupts (like CPU interrupts) - **Variables** = Prefixed with `$`, typed at runtime ______________________________________________________________________ ## Language Syntax and Formatting ### File Structure ````markdown # AgentName Agent description and personality. Define capabilities and behavioral traits here. ## PlaybookName($param1, $param2) Playbook description explaining what it does and when to use it. ### Triggers - When to execute this playbook ### Steps - Step 1 - Step 2 ### Notes - Additional guidance for LLM ```python # Python code blocks can appear anywhere @playbook async def PythonPlaybook(param: str) -> dict: """Docstring becomes playbook description""" return result ```` # SecondAgent Another agent in the same program file ```` ### Formatting Rules **Heading Tags**: - `# AgentName` - Agent definitions with description - `## PlaybookName($params)` - Playbook definitions - `### Triggers`, `### Steps`, `### Notes` - Special sections within playbooks **Metadata** - Key-value pairs at start of playbook description: ```markdown ## PlaybookName execution_mode: raw public: true ```` **Variables** - Always prefixed with `$`, optional type annotations: ```markdown - Ask user for their $name - $count:int = 10 - $result = GetData($name) ``` **Comments**: `` ______________________________________________________________________ ## The Five Playbook Types ### Decision Framework ```text START: What type of playbook do I need? │ ├─ Do I need deterministic logic, external APIs, or complex calculations? │ └─ YES → Python Playbook │ └─ Will I have 4+ Python playbooks in this agent and will this Python playbook NOT need to call a Markdown/ReAct/Raw Prompt playbook? │ └─ YES → Extract into MCP Server instead │ ├─ Do I know the exact steps in advance? │ └─ YES → Markdown Playbook │ ├─ Do steps depend on dynamic research/reasoning? │ └─ YES → ReAct Playbook │ ├─ Do I need exact prompt control for single-shot task? │ └─ YES → Raw Prompt Playbook │ └─ Am I integrating external MCP server tools? └─ YES → External Playbook (via MCP agent) ``` ### 1. Markdown Playbooks - Structured Workflows **Use when**: Steps are known, process is repeatable, need explicit control flow **Structure**: ```markdown ## PlaybookName($param1, $param2) Description ### Triggers - When condition is met ### Steps - Step with natural language instruction - $variable = Assign from another step - If condition - Nested step - While another condition - Deeply nested step - Otherwise - Alternative path - Return result ### Notes - Business rules that apply throughout execution ``` **Example**: ```markdown ## ProcessOrder($order_id) Process a customer order from validation through fulfillment ### Steps - Get $order from database using $order_id - If $order was not found - Tell user order not found - Return error - Validate payment for $order - If payment is valid - Update order status to processing - Send confirmation email to customer - Return success - Otherwise - Tell user payment failed - Return payment error ``` **Control Flow**: - Sequential: Just list steps in order - Conditional: `If condition`, `Otherwise`, `Else if condition` - Loops: `While condition`, `For each $item in $list` - Variable assignment: `$var = value` or `Get $var from source` - Return: `Return value` or `Return $variable` - End program: `End program` (terminates execution) ### 2. ReAct Playbooks - Dynamic Reasoning **Use when**: Steps can't be predetermined, need research, adaptive behavior **Structure**: ```markdown ## PlaybookName($param) execution_mode: react # Optional - inferred if no Steps section Detailed description of task, goals, constraints, and expected output. - Rule 1 for how to approach the task - Rule 2 for verification - Tone and communication style - Formatting preferences Expected structure of final output ### Triggers - When to execute ``` **Key Points**: - No `### Steps` section - Framework provides default think-plan-act loop - All playbooks available as tools - LLM decides what actions to take **Example**: ```markdown ## ResearchCompany($company_name) Conduct comprehensive competitive analysis with market positioning, products, pricing, and recent developments. - Start by identifying primary products and services - Search for recent news and financials (last 6 months) - Verify information across multiple sources - Compare with top 3 competitors # Company Analysis: [Name] ## Overview ## Products ## Market Position ## Recent Developments ## Conclusion ``` ### 3. Raw Prompt Playbooks - Full Control **Use when**: Need exact prompt control, single-shot tasks, minimal overhead **Structure**: ```markdown ## PlaybookName execution_mode: raw Exact prompt text. This goes directly to LLM. Use {$variable} and {PlaybookCall()} for dynamic content. ``` **Key Points**: - Single LLM call, no loops - Cannot call other playbooks during execution - No automatic context management - Use for classification, extraction, formatting **Example**: ```markdown ## CategorizeTicket execution_mode: raw Categorize this support ticket: {$ticket_message} Categories: - Technical Support - Billing - Account Management - General Inquiry Respond with ONLY the category name. Category: ``` ### 4. Python Playbooks - Hard Logic **Use when**: Need deterministic logic, external APIs, complex calculations **Structure**: ````markdown ```python from typing import Dict, List @playbook async def PlaybookName(param1: str, param2: int = 10) -> float: """ Docstring becomes playbook description. Args: param1: Description param2: Description Returns: Description """ # Your Python code result = compute(param1, param2) # Can call other playbooks (Markdown or Python) summary = await SummarizeResult(result) return summary @playbook(triggers=["When user provides PIN"], public=True) async def ValidatePIN(pin: str) -> bool: """Validate PIN format and check database.""" return len(pin) == 4 and pin.isdigit() ```` ```` **Decorator Options**: - `@playbook` - Basic playbook - `@playbook(public=True)` - Callable by other agents - `@playbook(export=True)` - Allow implementation export - `@playbook(triggers=["condition"])` - Add triggers - `@playbook(metadata={...})` - Custom metadata **Key Points**: - Full Python power: any library, complex logic, external APIs - Use `await` to call other playbooks - Return user-readable strings/dicts when called from Markdown - Can call Markdown playbooks: `await MarkdownPlaybook(args)` **Python-Only Agents**: You can build entire agents using only Python playbooks without any LLM calls. This is useful for deterministic workflows, prototyping, testing, or scenarios where you don't need AI reasoning. See the **[Python-Only Agents Guide](python-only-agents/)** for details. ### When to Extract Python Playbooks to MCP Server ⚠️ **Important Rule**: If you have **more than 3 Python playbooks** in a single agent, extract them to a separate MCP server instead. **Why Extract to MCP**: - Keeps agent code focused on behavior, not implementation - Python tools can be reused across multiple agents - Better separation of concerns - Easier testing and maintenance - Can be developed and deployed independently **How to Extract**: 1. **Create MCP server file** (e.g., `mcp.py`): Use the [FastMCP](https://fastmcp.com) library to create an MCP server. ```python from fastmcp import FastMCP mcp = FastMCP("My Tools Server") @mcp.tool def GetUserInfo(): """ Get information about the user. Returns: A dictionary containing user information. """ return {"name": "John", "email": "john@example.com"} @mcp.tool def CalculateSleepEfficiency(time_in_bed: int, time_asleep: int) -> float: """ Calculate sleep efficiency percentage. Args: time_in_bed: Total minutes in bed time_asleep: Total minutes asleep Returns: Sleep efficiency as percentage """ return round((time_asleep * 100) / time_in_bed, 1) if __name__ == "__main__": mcp.run(transport="streamable-http") ```` 1. **Run the MCP server**: ```bash fastmcp run mcp.py -t streamable-http --port 8888 ``` 1. **Define MCP agent in your Playbooks program**: ```markdown # ToolsAgent This agent provides various Python tools. remote: type: mcp url: http://127.0.0.1:8888/mcp transport: streamable-http # MainAgent Your main agent description. ## Main ### Steps - Load user info from ToolsAgent - Calculate sleep efficiency using ToolsAgent - Tell user their sleep efficiency ``` **Example from insomnia.pb**: ```markdown # MCP This agent provides various python tools that the sleep coach will use. remote: type: mcp url: http://127.0.0.1:8888/mcp transport: streamable-http # Sleep Coach You are a sleep coach helping users improve their sleep. ## Main ### Steps - Load user info from MCP - Get user's sleep efficiency from MCP - Welcome user and use the info to help them ``` **When NOT to extract**: - ✅ 1-3 Python playbooks that are tightly coupled to agent logic - ✅ Python playbooks that call Markdown playbooks (requires `@playbook`) - ✅ Python playbooks with triggers (requires `@playbook`) **When to extract**: - ✅ 4+ Python playbooks in single agent - ✅ Pure utility functions (calculations, API calls, data transformations) - ✅ Tools that could be reused by multiple agents - ✅ Complex Python logic that benefits from separate testing ### 5. External Playbooks - Remote Tools **Use when**: Integrating MCP servers, external APIs (roadmap) **Structure**: ```markdown # MCPAgent remote: type: mcp transport: streamable-http url: http://localhost:8000/mcp # LocalAgent ## Main ### Steps - $weather = MCPAgent.get_weather(zipcode=98053) - Tell user the $weather ``` **Key Points**: - MCP server tools automatically become playbooks - Call like any other playbook - Framework handles transport and auth ______________________________________________________________________ ## Decomposing Tasks into Playbooks ### Decomposition Strategy 1. **Identify distinct concerns**: What are the separable responsibilities? 1. **Look for reusability**: What might be called multiple times? 1. **Consider testing**: What would you want to test independently? 1. **Find boundaries**: Where do soft/hard logic boundaries exist? 1. **Separate I/O from logic**: User interaction vs computation ### Granularity Guidelines **Too Fine-Grained** ❌ ```markdown ## AskName ### Steps - Ask user for name ## ThankUser($name) ### Steps - Thank $name ## Main ### Steps - Ask user for name - Thank the user ``` **Appropriate** ✅ ```markdown ## Main ### Steps - Ask user for their $name - Thank $name for providing their name ``` **Better Decomposition** ✅ ```markdown ## ProcessOrder ### Steps - Collect user info - Process payment - Fulfill order ## CollectUserInfo ### Steps - Ask for $name, $email, $address; validate all fields - Return collected info as dictionary ## ProcessPayment($user_info) ### Steps - Calculate $amount and charge payment - Return payment record ``` ### When to Create Separate Playbooks **Create separate playbook when**: - ✅ Logic might be reused elsewhere - ✅ Has clear single responsibility - ✅ Could be triggered independently - ✅ Needs Python for deterministic logic - ✅ Represents distinct business process - ✅ Makes main flow more readable **Keep inline when**: - ✅ Used only once - ✅ Tightly coupled to parent context - ✅ Simple, linear flow - ✅ Would hurt readability to separate ______________________________________________________________________ ## Natural Language vs Explicit Syntax ### The Spectrum of Explicitness Playbooks supports a spectrum from pure natural language to Python-like explicit syntax. **Prefer natural language** unless explicitness aids clarity or correctness. ### Variable Assignment **Natural Language** (Preferred): ```markdown - Ask user for their order id - Get order details from database - Calculate shipping cost ``` **Explicit**: ```markdown - $order_id = AskForOrderId() - $order_details = GetOrderDetails($order_id) - $shipping_cost = CalculateShipping($order_details.weight, $order_details.destination) ``` ### When to Use Each Style **Pure Natural Language**: ```markdown - Greet user and ask what they need help with - Find the most relevant article for their question - Share the article with friendly explanation ``` - ✅ Clear intent - ✅ One-time flow - ✅ No complex data passing **Variable Names** (add clarity): ```markdown - Ask user for their $email and $password - Validate $email format - If $email is invalid - Tell user $email is not valid ``` - ✅ Value used multiple times - ✅ The variable should become part of the agent's state - ✅ Type helps LLM understand **Explicit Calls** (precision needed): ```markdown - $temp_c = ConvertToCelsius($temp_f) - $weather = WeatherAgent.GetForecast(zipcode=$zipcode, units="metric") - $summary = FormatWeather($weather, temperature=$temp_c) ``` - ✅ Exact parameters matter - ✅ Cross-agent calls - ✅ Return value used in computation ### Function Call Syntax Options All of these are valid: ```markdown # Natural language - Get order status # Explicit call with variable - $status = GetOrderStatus(order_id=$order_id) # Cross-agent call - $status = OrderService.GetOrderStatus(order_id=$order_id) ``` **Guidelines**: 1. Start natural, add explicitness only when needed 1. Use `$variables` when value is referenced multiple times 1. Use explicit calls for cross-agent or when parameters matter 1. Type annotations helpful for complex data: `$results:list`, `$config:dict` ______________________________________________________________________ ## Multi-Agent Programs ### When to Use Multiple Agents **Use multiple agents when**: - ✅ Different domains of expertise (TravelAdvisor, HotelAdvisor, FlightAdvisor) - ✅ Different roles in process (Host, Player) - ✅ Separation of concerns (Frontend, Backend, Database) - ✅ Specialized models needed (FastAgent with GPT-4o-mini, ResearchAgent with Claude) - ✅ Independent scaling or deployment - ✅ Separation of LLM context and knowledge **Use single agent when**: - ✅ Shared context and state - ✅ Simple workflow - ✅ Tight coupling between components ### Creating Multiple Agents Creating agents is easy in Playbooks. Simply add a new H1 tag and describe the agent. ```markdown # PrimaryAgent Description of primary agent ## Main ### Triggers - At the beginning ### Steps - Do primary work - Call SpecializedAgent when needed # SpecializedAgent Description of specialized agent ## ProcessTask($data) public: true ### Steps - Process $data with specialized logic - Return result ``` ### Agent Communication Methods #### 1. Direct Public Playbook Calls One agent directly calls another's public playbook: ```markdown # TaxAgent ## GetTaxRate($income) public: true ### Steps - Calculate and return tax rate based on $income # IncomeAgent ## ProcessIncome ### Steps - Ask user for $income - Get $tax_rate from TaxAgent - Tell user their $tax_rate ``` Use for synchronous request-response with immediate return value. #### 2. Natural Language Messaging Send messages for asynchronous communication: ```markdown # Manager ## AssignWork($task) ### Steps - Tell WorkerAgent to perform $task # WorkerAgent ## PerformTask($task) ### Steps - Perform the task ``` Use for fire-and-forget communication and async workflows. **Adaptive waiting:** Agents use intelligent, context-aware waiting without hard timeouts. When waiting for responses, agents receive periodic notifications (every 5 seconds) allowing them to decide whether to continue waiting, take alternative action, or escalate. There is no hard maximum wait time - the agent decides based on context. Add expected time information and alternative strategies in the Notes section to guide the agent's decisions. #### 3. Meetings - Multi-Party Coordination Host creates meeting for multi-agent coordination: ```markdown # RestaurantConsultant ## MenuRedesignMeeting meeting: true required_attendees: [HeadChef, MarketingSpecialist] ### Steps - Introduce myself and explain meeting purpose - Explain the process we'll follow - While meeting is active - Facilitate discussion - Keep discussion on track - Enforce max 30 turns - If consensus reached - Summarize decisions - End meeting - Return menu proposal - Otherwise - Return failure reason # HeadChef ## MenuRedesignMeeting meeting: true ### Steps - Introduce myself and propose signature dishes - While meeting is active - Respond to questions and evaluate suggestions # MarketingSpecialist ## MenuRedesignMeeting meeting: true ### Steps - Present market analysis - While meeting is active - Evaluate proposals and suggest pricing ``` **To create meeting**: ```markdown - Start a menu redesign meeting with HeadChef and MarketingSpecialist ``` **Meeting mechanics**: - Each agent needs a playbook with `meeting: true` - Same playbook name across all participating agents - Host agent creates meeting, invites attendees - Meeting provides shared communication channel - Messages visible to all participants - Participants can share variables through meeting shared state - Meeting ends when host returns from meeting playbook **When to use meetings**: - ✅ Multiple agents need to coordinate - ✅ Shared context across participants - ✅ Back-and-forth discussion needed - ✅ Consensus building **Meeting shared state**: Participants can share variables through meeting shared state, which is accessible to all meeting participants for reading and writing: ```markdown # GameHost ## GameSession meeting: true ### Steps - Initialize game board in meeting shared state and ask first player to make their move - While game is not over - Wait for player move - Update game board in shared state - Check for winner - If game is over - Announce the winner - Otherwise - Ask next player to make their move # Player ## GameSession meeting: true ### Steps - Wait for host to start the game - While game is not over - Wait for host to ask me to make my move - Read current game board from meeting shared state and decide move - Tell everyone what my move is ``` Use shared state when participants need to coordinate on shared data structures like game boards, collaborative documents, or shared counters. ### Multi-Agent Best Practices 1. **Clear interfaces**: Mark playbooks `public: true` when designed for cross-agent calls 1. **Meaningful agent names**: `TaxAccountant` not `Agent2` 1. **Document cross-agent contracts**: What parameters, what returns 1. **Handle failures**: What if agent doesn't respond? 1. **Avoid circular dependencies**: Agent A → Agent B → Agent A can deadlock ______________________________________________________________________ ## Triggers: Event-Driven Programming Triggers are natural language conditions that cause playbooks to execute automatically - like CPU interrupts. They enable declarative, reactive behavior in your agents. ⚠️ **Use Sparingly**: Triggers add "magic" behavior that can make programs harder to understand. Only use them when they significantly simplify your code. ### Why Use Triggers? Triggers eliminate repetitive coordination code by automatically invoking playbooks when conditions are met. The primary use case is **input validation** - you can validate user input automatically without cluttering your main flow with validation logic. ### When to Use Triggers ✅ **DO use triggers for**: - **Input validation** - Automatically validate when user provides data - **State monitoring** - React to threshold violations or state changes - **Cross-cutting concerns** - Behavior that applies throughout execution - **Entry points** - "At the beginning" to start your program ❌ **DON'T use triggers for**: - Normal sequential logic (just use steps) - One-time checks (inline them instead) - Complex workflows (be explicit with function calls) - When the trigger condition is unclear ### The Validation Pattern: Before & After **WITHOUT Triggers**: ```markdown ## Main ### Steps - Ask user for their $email - Validate $email and keep asking until valid - Process login with $email ``` **WITH Triggers** (cleaner): ```markdown ## Main ### Steps - Ask user for their $email - Process login with $email ## ValidateEmail ### Triggers - When user provides email ### Steps - If $email format is invalid - Tell user email is invalid and ask again ``` **Key Benefit**: Main flow stays clean. Validation happens automatically when user provides input, eliminating repetitive validation calls. ### Trigger Types **Temporal**: ```markdown ### Triggers - At the beginning - After 5 minutes - At the end ``` **State-Based**: ```markdown ### Triggers - When $attempts > 3 - When $balance becomes negative - When $order_status is "shipped" ``` **User Interaction**: ```markdown ### Triggers - When user provides email - When user asks about refund - When user seems frustrated ``` **Execution Flow**: ```markdown ### Triggers - After calling ProcessPayment - Before ending program ``` **External Events**: ```markdown ### Triggers - When payment webhook is received - When inventory drops below threshold ``` **Agent Communication**: ```markdown ### Triggers - When another agent asks about availability - When Manager assigns new task ``` ### Common Trigger Patterns **Pattern 1: State Guard** Monitor state and react to violations: ```markdown ## Main ### Steps - Set $attempts to 0 - While not authenticated - Ask user for credentials - Increment $attempts - Authenticate user ## CheckAttemptLimit ### Triggers - When $attempts > 5 ### Steps - Tell user they've exceeded maximum attempts - End program ``` **Pattern 2: Intent Detection** Respond to user intent automatically: ```markdown ## Main ### Steps - Welcome user - Have conversation about their issue - Resolve the issue ## ProvideHelp ### Triggers - When user asks for help - When user seems confused ### Steps - Explain available options and how to use them - Ask what specific help they need ``` **Important**: Triggers are evaluated after each step. The LLM determines when a trigger condition is met based on semantic understanding. ### Trigger Best Practices 1. **Be specific**: "When user provides email" not "When email" 1. **Avoid conflicts**: Don't create multiple triggers for same condition 1. **Document intent**: Explain why the trigger exists in playbook description 1. **Test edge cases**: What if trigger fires mid-execution? 1. **Keep it simple**: If you have more than 3-4 triggers total, reconsider your design 1. **Prefer explicit**: When in doubt, use explicit function calls instead of triggers ______________________________________________________________________ ## Description Placeholders Inject dynamic content into playbook descriptions using `{expression}` syntax. ### Basic Usage ```markdown ## ProcessOrder Processing order {$order_id} for customer {$customer_name}. Today's date is {date.today().strftime("%Y-%m-%d")}. ``` When playbook executes: ```text Processing order 12345 for customer Alice Smith. Today's date is 2025-10-06. ``` ### What You Can Use **Variables**: ```markdown ## ReviewTransaction Transaction {$transaction_id} with amount ${$amount} ``` **Results of Playbook Calls**: ```markdown ## AnswerQuestions Q1 Summary: {QuarterlySummary("Q1")} Q2 Summary: {QuarterlySummary("Q2")} ### Steps - Answer questions based on summaries above ``` **Python Expressions**: ```markdown ## AnalyzePerformance Score: {round($score * 100, 2)}% Status: {"Excellent" if $score > 0.9 else "Good"} Timestamp: {timestamp.strftime("%Y-%m-%d %H:%M")} ``` **Special Variables**: ```markdown ## Debug Current agent: {agent.klass} Playbook: {call.playbook_name} Current time: {timestamp} ``` ### Common Patterns **Contextual Dates**: ```markdown ## SummarizeOrder($order) Summarize order considering today is {date.today().strftime("%Y-%m-%d")} ### Steps - If order is overdue - Apologize for delay ``` **Conditional Context**: ```markdown ## CustomerService {"Customer is VIP - provide premium service" if $customer.tier == "VIP" else ""} ``` ### Best Practices 1. **Evaluate once**: Placeholders resolved when playbook starts, not re-evaluated 1. **Keep simple**: Complex logic belongs in Python playbooks 1. **Import dependencies**: `from datetime import date` in Python block if needed 1. **Security**: No `eval`, `exec`, `subprocess`, `__import__` ______________________________________________________________________ ## Artifacts ### Artifacts - Efficient Long Content Handling Artifacts implement pass-by-reference semantics for long text content or large objects. When large values are passed between playbooks using pass-by-value, the content gets duplicated in LLM context multiple times. Artifacts solve this by storing content once and passing only the reference. **The Problem**: Large values passed between playbooks get duplicated: - When sent as an argument - As a local variable in the receiving playbook - In the state sent to the LLM **The Solution**: Artifacts work like lazy loading: - Content stored once, referenced by name - Automatically loaded into context when referenced - Unloaded from context after returning from the playbook that loaded it **Usage**: ```python # Automatic artifact creation (>80 chars) $document = ReadFile("doc.md") # Explicit artifact creation await SaveArtifact("$report", "Q3 Report", """some content...""") ``` 👉 **[Complete Guide](artifacts/)** - Detailed explanation, paged memory model, API reference, and usage notes **Tip**: Minimize artifact context time by loading and using them in separate playbooks. The artifact unloads when the playbook returns, keeping context small for later processing. ______________________________________________________________________ ## Common Patterns and Best Practices ### Pattern: Python ↔ Markdown Composition ````markdown ```python @playbook async def ProcessItem(item: dict) -> str: """Fetch and process data with complex logic.""" data = external_api.get(item['id']) summary = await SummarizeItem(data) # Call Markdown playbook return summary ```` ## SummarizeItem($item) ### Steps - Format $item as user-friendly summary ```` ### Pattern: Batch Operations ```markdown - For each $order in $pending_orders - ProcessSingleOrder($order) ```` ### Pattern: Error Handling ```markdown ## SafeOperation ### Steps - Try to process $data - If operation fails - Log error - Tell user operation failed with reason - Return error status - Otherwise - Tell user success - Return success status ``` ### Pattern: Collecting Inputs from User When your agent needs information from the user, always ask for all inputs at once and establish a clear conversation loop until all valid data is acquired: ```markdown ## Main ### Steps - Ask user for $email and $pin, engage in a conversation till user provides valid values or gives up - If user gives up, apologize and return - Inform user that you were able to authenticate them ``` This pattern: - **Asks for all required information upfront** - more efficient for the user - **Includes a clear termination condition** - handles the case where user wants to exit - **Validates both inputs before proceeding** - ensures data quality - **Avoids sequential asking** - better user experience than asking one at a time **Why this matters**: Asking for information piece by piece creates a poor user experience. Users appreciate knowing all requirements upfront. ### Pattern: Mock Backend Interactions with Python Playbooks Think if a certain action would require backend interaction (databases, APIs, authentication services). If so, use Python playbooks to encapsulate that logic. Use mock implementations as necessary to aid in development: ````markdown ```python @playbook async def AuthenticateUser($email: str, $pin: str) -> bool: """Authenticate user with email and PIN. In production, this would call the actual authentication service. For now, using mock data for development. """ # Mock implementation for development return $email == "test@test.com" and $pin == "1234" @playbook async def FetchUserProfile($user_id: str) -> dict: """Fetch user profile from database. Production: Query user database Development: Return mock data """ # Mock implementation return { "id": $user_id, "name": "Test User", "preferences": {"theme": "dark"} } ```` ```` This pattern: - **Separates backend logic** - keeps the workflow clean and focused - **Enables rapid prototyping** - test workflows without backend dependencies - **Makes transition to production easier** - just swap mock with real implementation - **Documents backend contracts** - clear interface for what backend needs to provide - **Testable** - mock data allows thorough testing of workflows **When to use Python playbooks for backend**: - Database queries or updates - External API calls - Authentication/authorization checks - Complex business logic calculations - File I/O operations - Any stateful operations ### Anti-Pattern: Using step bullets for listing items, implicit loops, and redundant instructions Bad example: ```markdown ### Steps - Tell user about the plan - Phase 1: Understanding and Decomposition - Phase 2: Hypothesis Generation - Phase 3: Synthesis Assessment - Use agent collaboration - After each phase, ask MetaCognitionAgent if the phase was executed optimally ```` This anti-pattern has the following problems: - Each bullet point under Steps must be a statement to execute. The Phase 1, Phase 2, Phase 3 bullets are not, so should be in the same bullet as "Tell user" - Redundant instruction "Use agent collaboration" that can't be executed as a statement - Implicit loop "After each phase" Here's the correct way to write it: ```markdown ### Steps - Tell user about the plan - Phase 1: Understanding and Decomposition, Phase 2: Hypothesis Generation, Phase 3: Synthesis Assessment - Go through each phase in order - Execute the phase with agent collaboration until the phase is complete - Ask MetaCognitionAgent if the phase was executed optimally ``` ### Best Practices Summary **DO**: - ✅ Write playbook descriptions for humans - explain what and why - ✅ Use natural language unless explicitness helps - ✅ Add `### Notes` for business rules - ✅ Prefer Markdown for workflows, Python for logic - ✅ Extract 4+ Python playbooks to MCP server - ✅ Make cross-agent playbooks `public: true` - ✅ Use triggers sparingly - mainly for input validation - ✅ Handle edge cases and errors gracefully - ✅ Use meaningful variable names - ✅ Break complex playbooks into smaller ones - ✅ Test with different user inputs mentally - ✅ Ask for all required information at once with conversation loops - ✅ Use mock Python playbooks for backend processes during development - ✅ Each step bullet must be a complete executable statement. **DON'T**: - ❌ Over-engineer simple flows - ❌ Create too many tiny playbooks - ❌ Use Raw mode unless truly needed - ❌ Ignore error cases - ❌ Make circular agent dependencies - ❌ Use explicit syntax when natural language is clear - ❌ Forget to document cross-agent contracts - ❌ Overuse triggers - prefer explicit calls when flow is clearer - ❌ Use triggers for sequential logic - ❌ Ask for inputs one at a time when you need multiple pieces of information - ❌ Mix backend API calls directly into workflow steps ______________________________________________________________________ ## Editing Existing Programs ### Surgical Editing Principles When modifying existing Playbooks programs: 1. **Read and understand**: Review the file, understand its structure and intent 1. **Minimal changes**: Change only what's needed to achieve the goal 1. **Preserve style**: Match existing natural language vs explicit style 1. **Maintain consistency**: Keep variable naming and structure patterns 1. **Test mentally**: Think through execution flow after changes ### Common Edit Patterns **Adding a new playbook**: ```markdown ## NewPlaybook($param) Description ### Steps - New logic ``` **Modifying steps**: Find the playbook, locate the specific step, update it, and ensure variable references still work. ______________________________________________________________________ ## Understanding PBAsm Compilation ### Why PBAsm Matters When you write Playbooks, the compiler transforms it to Playbooks Assembly Language (PBAsm): - **Adds explicit types**: `$name` → `$name:str` - **Adds line numbers**: Hierarchical (01, 01.01, 01.01.01) - **Adds opcodes**: QUE (queue), CND (conditional), RET (return), YLD (yield) - **Explicit yields**: Shows when LLM yields control - **Trigger labels**: T1:BGN, T2:CND, etc. ### Compilation Example **Source**: `- Ask user for their name` **Compiled**: `- 01:QUE Say(user, Ask user for their $name:str); YLD for user` Adds: line numbers (01), opcodes (QUE), explicit types ($name:str), yield points (YLD for user). ### Key PBAsm Concepts **Opcodes**: QUE (queue operation), CND (conditional), RET (return), YLD (yield), EXE (execute), TNK (think), JMP (jump) **Yield Reasons**: `for user` (wait for input), `for call` (execute queued calls), `for agent` (wait for message), `for exit` (end program) **Line Numbers**: Hierarchical (01, 01.01, 01.02) enable jumps and track execution position ### Why This Helps You 1. **Debugging**: When user reports issues, think about PBAsm execution 1. **Precision**: Know that fuzzy NL gets converted to structured form 1. **Optimization**: Understand when LLM calls happen (at YLD points) 1. **Reasoning**: Picture how LLM executes line by line ### Don't Write PBAsm - ❌ Never write PBAsm directly - ✅ Write natural Playbooks language - ✅ Compiler handles transformation - ✅ Understanding PBAsm helps debugging and optimization ______________________________________________________________________ ## Quick Reference ### Minimal Working Program ```markdown # MyAgent Description of what this agent does ## Main ### Triggers - At the beginning ### Steps - Greet user - Ask user what they need help with - Help them - End program ``` ### Complete Example ````markdown # TaskAgent You help users manage their tasks efficiently. ```python @playbook async def SaveTask(task: str) -> dict: """Save task to database (mock implementation).""" return {"id": "123", "task": task, "status": "pending"} ```` ## Main ### Triggers - At the beginning ### Steps - Greet user - Ask what they'd like to do - If user wants to add a task - Add a new task - If user wants to list tasks - Show all pending tasks - End program ## AddTask ### Steps - Ask user for $task_description - Save the task - Tell user task was added successfully ## ValidateTaskDescription ### Triggers - When user provides task description ### Steps - If $task_description is empty - Tell user task cannot be empty - Ask again ```` ### Cheat Sheet | Task | Code | | --- | --- | | Define agent | `# AgentName` | | Define playbook | `## PlaybookName($param)` | | Add trigger | `### Triggers` `- When condition` | | Add steps | `### Steps` `- Step 1` | | Variable | `$variable_name` | | Typed variable | `$count:int` | | Assignment | `$var = value` | | Condition | `If condition` `- Then step` | | Loop | `While condition` `- Loop step` | | Return | `Return value` | | End program | `End program` | | Call playbook | `PlaybookName($arg)` | | Cross-agent call | `OtherAgent.PlaybookName($arg)` | | Python playbook | `@playbook` `async def Name(): ...` | | Public playbook | `public: true` | | ReAct playbook | No `### Steps` section | | Raw playbook | `execution_mode: raw` | | Meeting playbook | `meeting: true` | | Save artifact | `SaveArtifact("name", "desc", $content)` | | Load artifact | `LoadArtifact("name")` | | Placeholder | `{$variable}` or `{expression}` | --- ## Programming Principles (EXTREMELY IMPORTANT!) **Core Principles** - When writing Playbooks programs: 1. **Understand intent**: What problem are you solving? What is the goal? 2. **Choose right types**: Markdown for workflows, Python for logic, ReAct for research 3. **Natural first**: Start with natural language, add explicitness only when clarity demands it 4. **Think decomposition**: Break into logical playbooks with clear responsibilities 5. **⚠️ Extract to MCP**: If you have 4+ Python playbooks, extract them to an MCP server using fastmcp and use an MCP agent as a proxy 6. **Handle errors**: Consider edge cases and failure modes 7. **Write idiomatically**: Follow patterns and conventions from examples - write code that reads like a human wrote it 8. **Document choices**: Explain intent in descriptions and comments 9. **Iterate**: Start simple, add complexity as needed **For AI Assistants** - Additional guidance for Claude, Cursor, Gemini, Grok, etc. when writing code: - **Think deeply**: Plan in detail and review the plan before writing any code - **Teach while building**: Explain architectural choices to help users learn - **Use triggers sparingly**: Mainly for input validation, not normal control flow - **Optimal Playbooks**: Write idiomatic code that uses Playbooks capabilities optimally to produce minimal, clean, readable programs - **Framework migrations**: When converting from LangGraph, CrewAI, etc., produce the same behavior but leverage Playbooks' higher-level abstractions and natural language specifications - Each # (i.e. H1 tag) defines an agent and its contents are up to the next H1 tag or end of the file. When creating a new agent, create it at the end of the file. - When running MCP server in memory using memory://./path/to/mcp.py, you need to pip install any dependencies for the MCP server into the same environment as the Playbooks program. **Remember**: You're writing Software 3.0 - natural language programs that execute on LLMs. Embrace natural language for maximum expressiveness while maintaining precision. Happy building! 🚀``` ```` # Artifacts in Playbooks Artifacts implement pass-by-reference semantics suitable for variables holding large amounts of text. If large values are passed between playbooks using pass-by-value, the content gets duplicated in LLM context multiple times, which makes the program execution slower and more expensive. Artifacts solve this by storing content once and passing only the reference. ______________________________________________________________________ ## What Are Artifacts? An artifact is a variable holding named reference to large text content. Just like a variable, it has a name (like `$report`) and value. In addition, it also has a short one-line summary describing its content. Artifacts are automatically created when a value longer than a threshold is returned from a playbook or when a variable is set to a long value. When created, the content is added to LLM context so the LLM can reference the content by its name. Once the playbook returns, the content is removed from LLM context. However, if the artifact is referenced again later, it will be loaded back into LLM context automatically. ______________________________________________________________________ ## Context Duplication Problem When large values are passed between playbooks as regular variables, the content appears in LLM context multiple times. Consider this flow: ```markdown - Load $document = ReadFile("doc.md") # Content in context - Process $document # Content duplicated when sent - Analyze $document # Content duplicated when sent - Review $document # Content duplicated when sent ``` The content gets duplicated as it's sent as an argument, appears as a local variable in the receiving playbook, and shows up again in the state sent to the LLM. Artifacts fix this by implementing pass-by-reference. Instead of passing the content, only the artifact name is passed: ```markdown - Load $document = ReadFile("doc.md") # Artifact created automatically (content loaded into context) - Process $document # Only name sent - Analyze $document # Only name sent - Review $document # Only name sent ``` All playbooks reference the same artifact by name, so the content exists once. ### How Context Loading Works Think of it like lazy loading. When you create an artifact by returning large content, that content goes into context for the current playbook. The playbook can work with it normally. When the playbook returns, the runtime unloads the content from context to keep things efficient—but the artifact still exists as a reference (name + summary) in the current state. For example, the following state is sent to LLM - ```text "variables": { "$a_2bc92b04": "Output from ReadText(file1.txt)", "$summary": "Summary of text from file1.txt" }, ``` Note that the two artifacts are are listed with their summaries. These can be used as normal variables. For example, ```markdown - Show $summary to the user ``` When the playbook that created/loaded the artifact returns, the runtime automatically unloads the artifact from context. However, the artifact still exists as a reference (name + summary) in the current state. Later, when you reference that artifact again in another playbook, the runtime will automatically load it back into context. For example, ```markdown - Get the list of laws mentioned in file1.txt ``` Here, the a_2bc92b04 artifact is referenced again by the LLM. The runtime will automatically load it back into context. The key insight is that artifact names are always available (they're in the state), so you can reference them freely. The content gets loaded automatically when needed, keeping context lean while still giving the LLM access to large data whenever it needs it. ______________________________________________________________________ ## Automatic Artifact Creation When a playbook returns a value longer than a threshold (configurable via `artifact_result_threshold` in `playbooks.toml`), Playbooks automatically creates an artifact: ```python @playbook async def ReadFile(path: str) -> str: with open(path) as f: return f.read() # if longer than artifact_result_threshold, auto-creates artifact with name $a_ ``` The artifact name is based on a content hash, which keeps names stable across runs and prevents duplicate artifacts and cache misses. ## Explicit Artifact Creation For important content, create artifacts with meaningful names using `SaveArtifact()`: ```python @playbook async def GenerateReport(data: dict) -> str: report = "content\n"*100 await SaveArtifact("$report", "100 lines of content", report) return "$report" ``` This makes the code more readable and the artifact's purpose clearer. ______________________________________________________________________ ## Artifact API ### SaveArtifact(name, summary, value) Create an artifact with an explicit name. The function signature is `async def SaveArtifact(name: str, summary: str, value: str) -> str`. The `name` parameter is the variable name (with or without `$` prefix), `summary` is a one-line description, and `value` is the content as a string. It returns the artifact name. ### LoadArtifact(artifact_name) Force-load an artifact's content into context. In most cases, this happens automatically when you reference an artifact. Use this only when you want to explicitly ensure content is in context before it's needed. The function signature is `async def LoadArtifact(artifact_name: str)`. It returns None. ### Artifact Properties (Python) When working with artifacts in Python, access the name, summary, and full content via `artifact.name`, `artifact.summary`, and `artifact.value`. ______________________________________________________________________ ## Usage Notes Artifacts work transparently with playbook arguments and returns, so you can pass them around just like regular variables. Content is automatically loaded back into context when you reference an artifact, keeping things efficient without requiring explicit management. Use meaningful names for important content via `SaveArtifact()`, while hash-based auto-generated names are fine for temporary artifacts since they're stable across runs. If needed, adjust the character threshold for automatic artifact creation in `playbooks.toml` under `artifact_result_threshold`. # Python-Only Agents This document explains how to write agents that use pure Python logic without making any LLM calls, enabling deterministic, fast, and cost-free execution for workflows that don't require AI reasoning. This is mainly a demonstration of how Playbooks can be used to build fully-deterministic workflows. It is not a recommended approach for production systems (why use Playbooks at all in that case?), but may be handy for prototyping and testing. You can write a Python-only agent by writing all its playbooks using Python code. ````markdown ### Example Python-Only Agent ```python @playbook(triggers=["At the beginning"]) async def Main(): Say("user", "What's your name?") messages = WaitForMessage("user") Say("user", f"Received messages: {messages}") Say("user", f"Secret code: {await GetSecret()}") Exit() @playbook async def GetSecret(): return "OhSoSecret!" ```` ```` When this agent starts, the `Main` playbook is triggered that executes an interactive workflow with the user and calls another Python playbook.``` ```` # Tutorial: Building an Order Status Assistant **Goal**: Learn Playbooks by building a customer support AI assistant that checks order status. You'll start with "hello world" and progressively add user input, validation, Python playbooks, and more. **What you'll learn**: - Writing your first agent and playbook - Collecting and validating user input - Using triggers for automatic validation - Mixing Python and Markdown playbooks - Injecting dynamic context with description placeholders **Prerequisites** (see [Getting Started](../getting-started/)): - Installed Playbooks - Successfully ran a program using `playbooks run .pb` **Code**: All examples available [here](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials) **New to Playbooks?** This tutorial teaches by example. For comprehensive reference, see the [Programming Guide](../programming-guide/). ______________________________________________________________________ ## 1) Hello, world! ### 01.01 Let's begin examples/tutorials/01.01/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/01.01/order_assistant.pb) ```markdown # Order Support Agent You are an agent that greets users and helps with order questions. ## Main ### Triggers - At the beginning ### Steps - Greet the user and explain what you can help with - End program ``` Note: - Line 1: `# Order Support Agent` creates an agent. - Line 3: `## Main` defines a playbook, which is triggered automatically at the beginning (line 6) of the program execution. - Line 7: `### Steps` lists the steps to be executed. Output ```text > playbooks run examples/tutorials/01.01/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/01.01/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions or issues related to your orders. Whether you need to check order status, make changes, handle returns, or resolve any order-related concerns, I'm ready to assist you. How can I help you today? ``` Playbooks framework caches LLM responses by default. So, if you run the program again, compilation will be skipped and you will see the same output. The cache can be disabled using a `playbooks.toml` [configuration file](../reference/config/). Notice that in the output, the agent listed capabilities that we haven't provided playbooks for. Let's improve this by asking the agent to only list capabilties corresponding to the playbooks that we have provided. ### 01.02 Prompt Tuning examples/tutorials/01.02/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/01.02/order_assistant.pb) ```markdown # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. ## Main ### Triggers - At the beginning ### Steps - Greet the user and explain what you can help with - End program ``` Changes: - Line 2: We added extra instructions to the agent. Output ```text > playbooks run examples/tutorials/01.02/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/01.02/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions about your orders. However, I should let you know that my capabilities are currently limited to greeting you and providing this basic information. How can I assist you today? ``` Much better! ______________________________________________________________________ ## 2) Ask for user input Let's ask the user for their order id. ### 02.01 User input examples/tutorials/02.01/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/02.01/order_assistant.pb) ```markdown # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. ## Main ### Triggers - At the beginning ### Steps - Greet the user and explain what you can help with - Ask user for their order id - Thank the user for providing the order id - End program ``` Changes: - Line 9: Here we ask the user for their order id. - Line 10: New step to thank the user for providing the order id. Output ```text > playbooks run examples/tutorials/02.01/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/02.01/order_assistant.pb'] OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions about your orders. I can assist you with order status, tracking information, and other order-related inquiries. OrderSupportAgent: To get started, could you please provide me with your order ID? User: 47463874 OrderSupportAgent: Thank you for providing your order ID: 47463874. I have recorded this information. ``` ### 02.02 Conversational Input We want the agent to wait on line 9 until the user provides their order id. Let's add that instruction. examples/tutorials/02.02/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/02.02/order_assistant.pb) ```markdown # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. ## Main ### Triggers - At the beginning ### Steps - Greet the user and explain what you can help with - Ask user for their order id; engage in a conversation as needed - Thank the user for providing the order id - End program ``` Changes: - Line 9: Here we add a new step to engage in a conversation as needed. Output ```text > playbooks run examples/tutorials/02.02/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/02.02/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions about your orders. I can assist you with order status, tracking information, and other order-related inquiries. OrderSupportAgent: To get started, could you please provide me with your order ID? This will help me look up your specific order details. User: how are you OrderSupportAgent: I'm doing well, thank you for asking! I'm here and ready to help you with your order. Could you please share your order ID so I can assist you with your order-related questions? User: hold on.. let me look that up OrderSupportAgent: No problem at all! Take your time finding your order ID. I'll wait here for you. User: found it 44344456 OrderSupportAgent: Perfect! Thank you for providing your order ID: 44344456. I have that recorded now. ``` Notice that now the agent engaged in a conversation with the user while waiting for the order id. ### 02.03 Agent Behavior This behavior trait can be added to the agent's instructions so it applies to any time the agent asks the user for some information. examples/tutorials/02.03/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/02.03/order_assistant.pb) ```markdown # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. Whenever you are asking for some information from the user, you engage the user in a conversation if needed without being pushy and you will wait for appropriate place in conversation to remind the user. ## Main ### Triggers - At the beginning ### Steps - Greet the user and explain what you can help with - Ask user for their order id - Thank the user for providing the order id - End program ``` Changes: - Line 3: We added instructions for the agent Output ```text > playbooks run examples/tutorials/02.03/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/02.03/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions about your orders. I can assist you with tracking, status updates, and general order inquiries. OrderSupportAgent: To get started, could you please provide your order ID? This will help me look up your specific order details. User: how are you OrderSupportAgent: I'm doing well, thank you for asking! I'm here and ready to help you with your order questions. To assist you best, I'll still need your order ID. Could you please share that with me? User: nice weather here today.. how is it where you are OrderSupportAgent: That sounds lovely! As an AI assistant, I don't experience weather, but I'm glad you're having a nice day. I'd love to help you with your order - could you please share your order ID so I can assist you with any questions or concerns you might have? User: sure, i'll look that up OrderSupportAgent: Perfect! Take your time finding your order ID. I'll be right here waiting to help you once you have it. User: kk it's 88788790 OrderSupportAgent: Thank you for providing your order ID 88788790! I have that recorded now. ``` ## 3) Validating the input Let's add a new playbook to validate the order id. ### 03.01 Validation Playbook examples/tutorials/03.01/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/03.01/order_assistant.pb) ```markdown # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. Whenever you are asking for some information from the user, you engage the user in a conversation if needed without being pushy and you will wait for appropriate place in conversation to remind the user. ## Main ### Triggers - At the beginning ### Steps - Greet the user and explain what you can help with - Ask user for their order id - Validate the order id and keep asking until user provides a valid id - Thank the user for providing the order id - End program ## Validate order id ### Steps - If order id is made up of 8 numbers - Return valid - otherwise - Return invalid ``` Changes: - Line 15: We added a new playbook to validate the order id. - Line 11: After user provides the order id, now we call the `Validate order id` playbook to validate it, and engage with the user until they provide a valid id. Output ```text > playbooks run examples/tutorials/03.01/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/03.01/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with questions about your orders. I can assist you by looking up order information once you provide me with your order ID. How can I help you today? OrderSupportAgent: To get started, could you please share your order ID with me? Take your time - I'll wait for you to provide it or let me know if you'd prefer not to continue. User: 8843 OrderSupportAgent: I see that order ID '8843' isn't quite right - it looks like it needs to be 8 digits long. Could you please double-check your order ID and share the complete number with me? User: 8843A098 OrderSupportAgent: I see that order ID '8843A098' contains letters, but order IDs should be exactly 8 digits only. Could you please check your order confirmation and share the correct 8-digit order ID? User: 98745968 OrderSupportAgent: Perfect! Thank you for providing your order ID 98745968. I now have all the information I need to help you with your order. ``` **A note to my fellow Software Engineers:** I know, `Return valid` looks weird. What is getting returned here exactly? Is it a string or a boolean? We aren't capturing the return value in the call on line 11 either. The call `Validate the order id` also doesn't match the playbook name `Validate order id` exactly. It all seems too fuzzy and a bit magical. *I realize that it makes you uncomfortable.* You can **make the code explicit**. Declare the playbook like `## ValidateOrderId($order_id) -> bool`, use `return true` and `return false`. Change the call to `$valid = ValidateOrderId($order_id)`, and so on. Have it your way! This is also valid Playbooks code, but mostly unnecessary because of the compiler (see below). On the other hand, you could - **Embrace the magic!** LLMs are highly capable semantic execution machines. By themselves, they are not reliable, so your hesitation is justifiable. But this is where the advanced engineering behind Playbooks comes in. The way Playbooks compiler and runtime are designed, you can expect reliable execution of semantic instructions. Of course, as with any AI software, thourough evaluation is still necessary. The Playbooks compiler compiles `.pb` program to Playbooks Assembly Language (`.pbasm`), which converts some of the semantic instructions into explicit instructions, adds explicit type annotations, and so on. See the compiler generated PBAsm code below (actual [file](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/03.01/Order_Support_Agent_6a901f96b774fe82.pbasm)) - Compiled .pbasm Order_Support_Agent_6a901f96b774fe82.pbasm ```markdown # OrderSupportAgent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. Whenever you are asking for some information from the user, you engage the user in a conversation if needed without being pushy and you will wait for appropriate place in conversation to remind the user. ## Main() -> None Main interaction flow for order support assistance ### Triggers - T1:BGN At the beginning ### Steps - 01:QUE Say(user, Greet the user and explain what you can help with) - 02:QUE Say(user, Ask user for their $order_id:str); YLD for user; done when user provides an order id or gives up - 03:QUE $validation_result:str = ValidateOrderId(order_id=$order_id) - 04:YLD for call - 05:CND While $validation_result is invalid - 05.01:QUE Say(user, Ask user for a valid order id); YLD for user; done when user provides an order id or gives up - 05.02:QUE $validation_result:str = ValidateOrderId(order_id=$order_id) - 05.03:YLD for call - 05.04:JMP 05 - 06:QUE Say(user, Thank the user for providing the order id) - 07:YLD for exit ## ValidateOrderId($order_id:str) -> str Validates if the provided order ID meets the required format ### Steps - 01:CND If order id is made up of 8 numbers - 01.01:RET valid - 02:RET invalid ``` This looks a lot more like actual code, doesn't it? This is Assembly Language for the LLM, with opcodes like `QUE` for function calls, `CND` for conditional logic, and so on. **The goal is to make the agent's behavior specification as readable as possible, as if it is written for a competent employee.** **Learn more**: See [Natural Language vs Explicit Syntax](../programming-guide/#natural-language-vs-explicit-syntax) in the Programming Guide. ### 03.02 Using Triggers Triggers automatically invoke playbooks when conditions are met - like CPU interrupts. Let's add a trigger to the `Validate order id` playbook to **automatically run** when the user provides an order id. examples/tutorials/03.02/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/03.02/order_assistant.pb) order_assistant.pb ```diff - At the beginning ### Steps - Greet the user and explain what you can help with -- Ask user for their order id -- Validate the order id and keep asking until user provides a valid id +- Ask user for their order id till user provides a valid order id - Thank the user for providing the order id - End program ## Validate order id +### Trigger +- When user provides order id ### Steps - If order id is made up of 8 numbers - Return valid ``` Changes: - We no longer need to explicitly call the `Validate order id` playbook on line 11. - We added a trigger condition to the `Validate order id` playbook to run automatically when the user provides an order id. **Key Benefit**: Main flow stays clean. Validation happens automatically. No explicit validation calls needed. **Learn more**: See [Triggers: Event-Driven Programming](../programming-guide/#triggers-event-driven-programming) for patterns, best practices, and when to use (or avoid) triggers. ______________________________________________________________________ ## 4) Mixing Python and Markdown Playbooks ### 04.01 Markdown → Python Use Python playbooks when you need data access, deterministic logic, or external libraries. Define async functions decorated with `@playbook` inside python code blocks. examples/tutorials/04.01/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/04.01/order_assistant.pb) ````diff # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. Whenever you are asking for some information from the user, you engage the user in a conversation if needed without being pushy and you will wait for appropriate place in conversation to remind the user. +```python +# In real life you'd query your DB or API here. +_FAKE_ORDERS = { + "43345678": {"order_id": "43345678", "status": "Shipped", "expected_delivery_date": "2025-10-02"}, + "29376452": {"order_id": "29376452", "status": "Processing", "expected_delivery_date": "2025-10-05"}, +} + +@playbook +async def GetOrderStatus(order_id: str) -> dict: + """ + Lookup an order's status by id. + Returns a dict with order_id, status, expected_delivery_date. + """ + + info = _FAKE_ORDERS.get(order_id.upper()) + if not info: + # Return user-readable errors when called from markdown + return {"error": f"Order {order_id} was not found."} + return info +``` + ## Main ### Triggers - At the beginning @@ -9,6 +30,7 @@ Whenever you are asking for some information from the user, you engage the user - Greet the user and explain what you can help with - Ask user for their order id till user provides a valid order id - Thank the user for providing the order id +- Get order status and tell user what it is - End program ## Validate order id ```` Changes: - Lines 5-25: We added a Python playbook to get the order status. - Line 33: We added a step to get the order status and tell the user what it is. Output (unknown order id) ```text > playbooks run examples/tutorials/04.01/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/04.01/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions about your orders. I can look up order status and provide information about your purchases. How can I assist you today? OrderSupportAgent: To get started, could you please provide your order ID? It should be an 8-digit number. User: 34564323 OrderSupportAgent: Thank you for providing your order ID 34564323. Let me look up the status for you. OrderSupportAgent: I'm sorry, but I couldn't find order 34564323 in our system. Please double-check your order ID or contact customer service if you believe this is an error. ``` Output (known order id) ```text > playbooks run examples/tutorials/04.01/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/04.01/order_assistant.pb'] OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you with any questions about your orders. I can look up order status and provide information about your purchases. How can I assist you today? OrderSupportAgent: To get started, could you please provide your order ID? It should be an 8-digit number. User: 29376452 OrderSupportAgent: Thank you for providing your order ID 29376452. Let me look up the status for you. OrderSupportAgent: Great news! I found your order 29376452. The current status is 'Processing' and your expected delivery date is October 5th, 2025. Your order is being prepared and will be shipped soon! ``` **Learn more**: See [Python Playbooks - Hard Logic](../programming-guide/#4-python-playbooks-hard-logic) for full details, decorator options, and when to extract Python playbooks to MCP servers. ______________________________________________________________________ ### 04.02 Python → Markdown Let's add a Markdown playbook that summarizes the order status in a specific way, and call it from the `GetOrderStatus` playbook. examples/tutorials/04.02/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/04.02/order_assistant.pb) ````diff # Order Support Agent You are an agent that greets users and helps with order questions. Note that your capabilities are limited to the playbooks defined below. Whenever you are asking for some information from the user, you engage the user in a conversation if needed without being pushy and you will wait for appropriate place in conversation to remind the user. +## SummarizeOrderStatus($order_status) +### Steps +- If order was shipped + - Return summary indicating expected_delivery_date and $1 store credit if the order gets delayed +- If order is processing + - Return a summary apologizing that the order is not shipped yet and don't provide the expected delivery date unless user asked for it + ```python # In real life you'd query your DB or API here. _FAKE_ORDERS = { @@ -10,17 +17,17 @@ _FAKE_ORDERS = { } @playbook -async def GetOrderStatus(order_id: str) -> dict: +async def GetOrderStatus(order_id: str) -> str: """ Lookup an order's status by id. - Returns a dict with order_id, status, expected_delivery_date. + Returns a string describing order status. """ info = _FAKE_ORDERS.get(order_id.upper()) if not info: # Return user-readable errors when called from markdown - return {"error": f"Order {order_id} was not found."} - return info + return f"Order {order_id} was not found." + return await SummarizeOrderStatus(info) ```` ## Main ```` Changes: - Lines 5-11: We added a Markdown playbook to summarize the order status. - Line 33: We call the `SummarizeOrderStatus` playbook `GetOrderStatus` playbook. Output (shipped order, $1 store credit) ```text > playbooks run examples/tutorials/04.02/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/04.02/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you check on your order status. Just provide me with your order ID and I'll look up the current status for you. User: 43345678 OrderSupportAgent: Thank you for providing your order ID 43345678! OrderSupportAgent: Great news! Your order 43345678 has been shipped and is expected to be delivered on 2025-10-02. If your order gets delayed, you'll receive $1 store credit as compensation. ```` Output (processing order) ```text > playbooks run examples/tutorials/04.02/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/04.02/order_assistant.pb'] OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you check on your order status. Just provide me with your order ID and I'll look up the current status for you. User: 29376452 OrderSupportAgent: Thank you for providing order ID 29376452. Let me look up the current status for you. OrderSupportAgent: I apologize, but your order is still being processed and hasn't shipped yet. We're working on getting it ready for you as soon as possible. ``` Output (processing order, with expected delivery date) ```text > playbooks run examples/tutorials/04.02/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/04.02/order_assistant.pb'] OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you check on your order status. Just provide me with your order ID and I'll look up the current status for you. User: Here it is 29376452.. I am going on vacation soon so wondering if I get it before that. OrderSupportAgent: Thank you for providing order ID 29376452! Let me check the status for you right away. OrderSupportAgent: Your order #29376452 is currently being processed and hasn't shipped yet. However, I can see it has an expected delivery date of October 5th, 2025, so it should arrive well before your vacation! We're working on getting it ready for you as soon as possible. ``` ### 04.03 Description Placeholders We want to check if a shipped order is overdue, but the LLM doesn't know today's date. We can inject dynamic information using **description placeholders** with `{expression}` syntax: order_assistant.pb ```diff - - Return summary indicating expected_delivery_date and $1 store credit if the order gets delayed + - If order is overdue + - Return summary with apologies for the delay and indicating that $1 store credit was added to user's account + - Otherwise + - Return summary indicating expected_delivery_date and $1 store credit if the order gets delayed ``` But, the LLM won't know about today's date so we need to inject that information in the LLM context. Let's use playbook description placeholder feature to add today's date in the description of the `SummarizeOrder` playbook. order_assistant.pb ```diff ## SummarizeOrderStatus($order_status) +Summarize order status, taking into account today's date {date.today().strftime("%Y-%m-%d")} ``` Placeholder expressions are evaluated when the playbook starts. They can access variables, call playbooks, and use Python expressions. Import any needed modules in a Python code block. examples/tutorials/04.03/[order_assistant.pb](https://github.com/playbooks-ai/playbooks/tree/master/examples/tutorials/04.03/order_assistant.pb) ````diff ## SummarizeOrderStatus($order_status) +Summarize order status, taking into account today's date {date.today().strftime("%Y-%m-%d")} + ### Steps - If order was shipped - - Return summary indicating expected_delivery_date and $1 store credit if the order gets delayed + - If order is overdue + - Return summary with apologies for the delay and indicating that $1 store credit was added to user's account + - Otherwise + - Return summary indicating expected_delivery_date and $1 store credit if the order gets delayed - If order is processing - Return a summary apologizing that the order is not shipped yet and don't provide the expected delivery date unless user asked for it ```python +from datetime import date + # In real life you'd query your DB or API here. _FAKE_ORDERS = { - "43345678": {"order_id": "43345678", "status": "Shipped", "expected_delivery_date": "2025-10-02"}, + "43345678": {"order_id": "43345678", "status": "Shipped", "expected_delivery_date": "2025-08-02"}, "29376452": {"order_id": "29376452", "status": "Processing", "expected_delivery_date": "2025-10-05"}, } ```` ```` Changes: - Line 2: Added a description with a placeholder for today's date. - Line 7: Updated the expected delivery date for the shipped order to be 2025-08-02 to trigger the overdue behavior. Output ```text > playbooks run examples/tutorials/04.03/order_assistant.pb ℹ Loading playbooks from: ['examples/tutorials/04.03/order_assistant.pb'] Compiling agent: Order Support Agent OrderSupportAgent: Hello! I'm your Order Support Agent. I'm here to help you check on your order status. Just provide me with your order ID and I'll look up the current status for you. User: 43345678 OrderSupportAgent: Thank you for providing order ID 43345678. Let me look up your order status right away. OrderSupportAgent: I apologize for the significant delay with your order 43345678. Your order was shipped but should have been delivered by August 2nd, 2025. Due to this delay, we've added $1 store credit to your account as compensation for the inconvenience. ```` **Learn more**: See [Programming Guide](../programming-guide/) for advanced patterns and best practices. ______________________________________________________________________ ## Next Steps Congratulations! You've built a working order assistant that: - ✅ Greets users and collects input conversationally - ✅ Validates input automatically with triggers - ✅ Mixes Python and Markdown playbooks seamlessly - ✅ Injects dynamic context with placeholders **Continue Learning**: - **[Programming Guide](../programming-guide/)** - Comprehensive reference covering all features - [Multi-Agent Programs](../programming-guide/#multi-agent-programs) - Multiple agents, meetings, cross-agent calls - [ReAct Playbooks](../programming-guide/#2-react-playbooks-dynamic-reasoning) - Dynamic planning when steps aren't predetermined - [Raw Playbooks](../programming-guide/#3-raw-prompt-playbooks-full-control) - Full prompt control for single-shot tasks - [Common Patterns](../programming-guide/#common-patterns-and-best-practices) - Best practices and real-world patterns **Reference Documentation**: - [Agents](../reference/agents/) - Agent configuration and structure - [MCP Agents](../reference/mcp-agent/) - Integrating external tools via MCP - [Triggers](../reference/triggers/) - Event-driven programming details - [Playbook Types](../reference/playbook-types/) - Deep dive on all playbook types **Ready to build?** Start with the [Programming Guide](../programming-guide/) and explore the examples in the [Playbooks repository](https://github.com/playbooks-ai/playbooks/tree/master/examples). # Playbooks Reference Documentation This section contains the reference documentation for the Playbooks framework. ## Table of Contents - [Configuration System](config/) - [Supported Models](models/) - [Playbooks AI](playbooks-ai/) - [Playbooks Language](playbooks-language/) - [Playbooks Assembly Language](playbooks-assembly-language/) - [Agents](agents/) - [MCP based Agents](mcp-agent/) - [Meetings](meetings/) - [Exported and Public Playbooks](exported-and-public-playbooks/) - [Playbook Types](playbook-types/) - [Built-in Playbooks](builtin-playbooks/) - [Triggers](triggers/) - [Context Engineering](context-engineering/) - [Description Placeholders](description-placeholders/) - [Playbooks vs Traditional Frameworks](playbooks-traditional-comparison/)