How Fabro constructs and delivers prompts to agents
When a workflow reaches an agent or prompt node, Fabro assembles the full prompt from multiple sources: the node’s prompt attribute, a fidelity-based preamble summarizing prior stages, a system prompt with tool guidance and environment context, project docs, and user instructions. Understanding this assembly helps you write effective prompts and control what context each node receives.
For longer prompts, use the @ prefix to load from a Markdown file relative to the DOT file:
Copy
Ask AI
plan [label="Plan Implementation", prompt="@prompts/implement/plan.md"]implement [label="Implement", prompt="@prompts/implement/implement.md"]review [label="Review", prompt="@prompts/implement/review.md"]
The @ prefix tells the engine to read the file contents and use them as the prompt text. This keeps DOT files concise and lets you version prompts as standalone Markdown.
Prompts support $variable placeholders that expand at runtime. Currently the only built-in variable is $goal, which resolves to the graph-level goal attribute:
pipeline.fabro
Copy
Ask AI
digraph Pipeline { graph [goal="Add a /health endpoint to the API server"] implement [prompt="Implement the following: $goal"]}
At runtime, $goal becomes Add a /health endpoint to the API server.
Variable
Resolves to
$goal
The graph-level goal attribute
A $ not followed by an identifier character (e.g. $5) is left as-is. An undefined variable like $foo produces a runtime error, catching typos early.
The prompt the agent receives is not just the prompt attribute. Fabro prepends a preamble (unless fidelity is full) that summarizes what happened in prior stages:
The preamble is controlled by the fidelity setting. See Context: Fidelity for the full reference.
Example assembled prompt
Given a plan-then-implement workflow where the plan stage completed, the implement node with fidelity="compact" would receive:
Copy
Ask AI
Goal: Add a /health endpoint to the API server## Completed stages- **plan**: success - Model: claude-sonnet-4-5, 12.4k tokens in / 3.2k out - Files: docs/plan.md## Context- tests_passed: falseRead plan.md and implement every step.
The last line is the node’s prompt attribute. Everything above it is the preamble.
Each agent session has a system prompt that provides foundational instructions. The system prompt is built once per session and includes:
Section
Contents
Identity and role
What the agent is and how it should approach tasks
Environment context
Working directory, platform, OS, git branch, model, date
Tool guidance
Per-tool usage instructions (when to use read_file vs shell, etc.)
Coding best practices
Guidelines for clean, minimal, focused changes
Project docs
Contents of AGENTS.md, CLAUDE.md, GEMINI.md, or .codex/instructions.md
Skills
Available skill templates the agent can invoke
The system prompt is separate from the preamble. The preamble is prepended to the user-facing prompt message, while the system prompt is set as the LLM’s system message.The system prompt varies by LLM provider. Each provider has its own identity text, tool guidance, and coding conventions tuned to the model’s strengths. The assembled prompt follows this structure:
This is the full system prompt sent to Claude as the LLM system message. The <environment> block is filled in at runtime.
Copy
Ask AI
You are Claude, an AI coding assistant made by Anthropic. You help users withsoftware engineering tasks including solving bugs, adding new functionality,refactoring code, explaining code, and more.You are an interactive agent that helps users with software engineering tasks.Use the instructions below and the tools available to you to assist the user.<environment>Working directory: /home/user/projectIs git repository: trueGit branch: mainPlatform: linuxOS version: Linux 6.1.0Today's date: 2026-03-05Model: claude-sonnet-4-5</environment># Doing Tasks- The user will primarily request you to perform software engineering tasks. These may include solving bugs, adding new functionality, refactoring code, explaining code, and more.- In general, do not propose changes to code you have not read. If a user asks about or wants you to modify a file, read it first. Understand existing code before suggesting modifications.- Do not create files unless they are absolutely necessary for achieving your goal. Generally prefer editing an existing file to creating a new one, as this prevents file bloat and builds on existing work more effectively.- If your approach is blocked, do not attempt to brute force your way to the outcome. Consider alternative approaches or other ways you might unblock yourself.- Avoid over-engineering. Only make changes that are directly requested or clearly necessary. Keep solutions simple and focused.- Do not add features, refactor code, or make improvements beyond what was asked.- Do not add error handling, fallbacks, or validation for scenarios that cannot happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs).- Avoid backwards-compatibility hacks. If you are certain something is unused, delete it completely.# ToolsUse the provided tools to interact with the codebase and environment. Do NOTuse the shell tool to run commands when a relevant dedicated tool is provided:- To read files use read_file instead of cat, head, tail, or sed.- To edit files use edit_file instead of sed or awk.- To create files use write_file instead of cat with heredoc or echo redirection.- To search for files use glob instead of find or ls.- To search the content of files use grep instead of grep or rg.## read_fileRead files before editing them. Always read a file before attempting to editit. Use offset/limit for large files. Reading a file you have not read beforeis always appropriate.## edit_filePerforms exact string replacements in files. The old_string must be an exactmatch of existing text and must be unique in the file. If old_string matchesmultiple locations, provide more surrounding context to make it unique. Preferediting existing files over creating new ones. When editing text, ensure youpreserve the exact indentation as it appears in the file.## write_fileUse write_file only when creating new files. Prefer edit_file for modifyingexisting files. Always prefer editing existing files in the codebase overcreating new ones.## shellUse for running commands, tests, and builds. Default timeout is 120 seconds.Use timeout_ms parameter for longer-running commands.## grepSearch file contents with regex patterns. Supports output modes:content, files_with_matches, count. Use this for searching the content offiles rather than using shell grep or rg.## globFind files by name pattern. Results sorted by modification time (newestfirst). Use this for finding files rather than using shell find or lscommands.## web_searchSearch the web using Brave Search. Returns titles, URLs, and descriptions.## web_fetchFetch content from a URL and optionally summarize it. Pass a prompt toextract specific information instead of returning the full page. URLs muststart with http:// or https://.# Coding Best PracticesWrite clean, maintainable code. Handle errors appropriately. Follow existingcode conventions in the project. Keep changes minimal and focused on the task.# Project Docs<contents of AGENTS.md and CLAUDE.md from the project># Available SkillsWhen the user's request matches a skill below, call the `use_skill` toolto load its instructions, then follow them.- `commit`: Create a git commit following best practices- `review`: Review code changes for issues and improvements
OpenAI and Gemini providers have their own system prompts with different identity text, tool guidance (e.g. apply_patch instead of edit_file for OpenAI), and coding conventions. The overall structure is the same.
Fabro automatically discovers project instruction files by walking the directory hierarchy from the git root to the working directory. Which files are loaded depends on the provider:
Provider
Files
Anthropic
AGENTS.md, CLAUDE.md
OpenAI
AGENTS.md, .codex/instructions.md
Gemini
AGENTS.md, GEMINI.md
Files are loaded in directory order (root first, deepest last) with a total budget of 32KB. If the combined content exceeds this budget, later files are truncated.
Both agent nodes (shape=box) and prompt nodes (shape=tab) go through the same prompt assembly pipeline: variable expansion, preamble prepending, and system prompt construction. The difference is execution:
Agent node
Prompt node
Shape
box (default)
tab
Tool access
Yes (agentic loop)
No (single LLM call)
Prompt assembly
Preamble + prompt
Preamble + prompt
Routing directives
Extracted from response
Extracted from response
Context updates
response.{node_id}, last_response
response.{node_id}, last_response
Use prompt nodes for analysis, classification, and summarization tasks where tools are not needed.
Fabro writes the assembled prompt to {run_dir}/nodes/{node_id}/prompt.md for every agent and prompt stage. This includes the preamble (if any) and the expanded prompt text. Use these files for debugging when an agent behaves unexpectedly.