A powerful template engine for AI prompt engineering with type-safe variable interpolation and conditional logic.
go install github.com/omniaura/agentflow/cmd/af@latest
As of go 1.24 you can now use af as a go tool:
go get -tool github.com/omniaura/agentflow/cmd/af@latest
This installs af scoped to your go project and you call it using go tool af
Create a simple prompt template:
.title Greeting
Hello <!name>! Welcome to <!platform>.
.title Personalized Message
<?premium bool>
Thanks for being a premium user! You have access to all features.
<else>
Consider upgrading to premium for additional features.
</premium>
Generate Go code:
af gen prompts examples/
AgentFlow uses a simple but powerful syntax for creating dynamic prompt templates with type-safe variable interpolation.
Titles define distinct prompt sections within a file. Each title becomes a separate Go function.
.title System Prompt
You are a helpful assistant.
.title User Greeting
Hello <!user_name>, how can I help you today?
Generated Go:
type SystemPrompt struct{}
func (input *SystemPrompt) String() string { /* ... */ }
type UserGreeting struct {
UserName string
}
func (input *UserGreeting) String() string { /* ... */ }Variables are interpolated using the <!variable_name> syntax:
Hello <!name>! You have <!count> messages.
Variables support dot notation for nested structures:
Welcome <!user.name>! Your email is <!user.email>.
AgentFlow supports a rich type system with explicit type annotations and intelligent type caching.
string(default)intboolfloat32float64
Variables can be declared with explicit types on first use:
User <!username> has <!count int> messages and is <!active bool> status.
Message Count: <!count>
Active Status: <!active>
Key Features:
- Type Declaration:
<!count int>- declares variable with type - Type Caching:
<!count>- subsequent references reuse the cached type - Automatic Conversion: Generates appropriate
strconv.Itoa()andstrconv.FormatBool()calls
Generated Go:
type Example struct {
Username string
Count int // ✅ Correctly typed
Active bool // ✅ Correctly typed
}
func (input *Example) String() string {
var b strings.Builder
var0 := strconv.Itoa(input.Count) // ✅ Efficient reuse
// ... both references use var0
}Conditional blocks allow content to be included based on variable values:
<?user.premium bool>
Welcome premium user! You have access to all features.
Your tier: <!user.subscription.tier int>.
<else>
Welcome! Upgrade to premium for more features.
</user.premium>
Syntax:
<?variable_name>- Start conditional block<else>- Alternative content (optional)</variable_name>- End conditional block
Conditional Logic:
stringvariables: included if not empty (!= "")intvariables: included if not zero (!= 0)boolvariables: included if true
AgentFlow supports complex nested data structures:
<?memory.long>
## Long Term Memory
<!memory.long>
</memory.long>
<?script.name>
Working on: <!script.name> (<!script.type> project)
</script.name>
Generated Go struct:
type Template struct {
Memory struct {
Long string
Short string
}
Script struct {
Name string
Type string
}
}All text outside of special syntax is treated as literal content. AgentFlow preserves whitespace and formatting exactly as written.
This is literal text that will be included as-is.
Variables like <!name> are interpolated.
But this <text> is just literal text.
.title Simple Greeting
Hello <!name>! Today is <!date>.
.title User Stats
User <!username> has <!message_count int> messages.
Premium status: <!is_premium bool>
Account balance: $<!balance float64>
.title Welcome Message
<?user.premium bool>
🌟 Welcome back, premium user <!user.name>!
You have access to all premium features.
<else>
Hello <!user.name>! Consider upgrading to premium.
</user.premium>
<?notifications int>
You have <!notifications> new notifications.
</notifications>
.title AI Assistant
You are <!ai.name>, an AI assistant.
<?user.preferences.language>
Respond in <!user.preferences.language>.
</user.preferences.language>
<?context.previous_messages>
Previous conversation:
<!context.previous_messages>
</context.previous_messages>
Current user: <!user.name>
Timestamp: <!timestamp>
AgentFlow generates efficient, type-safe Go code with:
- Two-pass string building for optimal performance
- Proper type handling with automatic conversions
- Conditional logic that mirrors your template structure
- Variable reuse to minimize allocations
Example generated code:
func (input *Template) String() string {
var b strings.Builder
var0 := strconv.Itoa(input.Count)
length := 0
length += 5 // "User "
length += len(input.Username)
length += 5 // " has "
length += len(var0)
length += 10 // " messages."
b.Grow(length)
b.WriteString(`User `)
b.WriteString(input.Username)
b.WriteString(` has `)
b.WriteString(var0)
b.WriteString(` messages.`)
return b.String()
}Generate Go code from .af templates:
af gen prompts <directory>
Options:
-d, --dir: Directory containing .af files (default: current directory)-l, --lang: Target language (currently only 'go' supported)
Example: af gen prompts examples/simple