Examples
Patterns and recipes for common workflows.
Task Orchestration
Plan, build, and verify
A task that makes the LLM plan first (read-only mode), then implement (edit mode with auto), and keeps iterating until the build and linter pass.
# .aura/config/tasks/build-app.yaml
build-app:
agent: high
timeout: 60m
commands:
- /mode plan
- Read SPEC.md and generate a plan.
- /until not todo_empty "You MUST call TodoCreate to create the plan"
- /export logs/plan.log
- /mode edit
- /auto on
- Execute the plan.
- /until bash:"go build ./..." "Build is failing. Fix the errors."
- /until bash:"golangci-lint run" "Linting is failing. Fix the errors."
- /export logs/result.log
- /stats
Key points:
/mode planrestricts tools to read-only. The LLM can explore but not modify files./until not todo_emptyloops until the LLM creates a todo list. It won’t proceed without a plan./mode editunlocks file modification tools./auto onlets the LLM run continuously without waiting for user input./until bash:"go build ./..."keeps the LLM working until the build passes (exit 0)./exportsnapshots the conversation at each phase for review.
Run it:
aura tasks run build-app --now
Iterate over repositories
test-all-repos:
timeout: 30m
agent: high
mode: edit
foreach:
shell: "find ~/projects -maxdepth 1 -name 'go.mod' -exec dirname {} \\;"
continue_on_error: true
retries: 1
commands:
- |
Run `go test ./...` in $[[ .Item ]].
If any tests fail, investigate and report the failures.
finally:
- Summarize test results across all $[[ .Total ]] repositories.
foreach.shellgenerates the item list from a shell command.$[[ .Item ]],$[[ .Index ]],$[[ .Total ]]are runtime template variables.continue_on_errorlogs failures and moves to the next item.retriesretries each failed item before giving up.finallyruns once after the loop completes.
Scheduled daily review
daily-review:
schedule: "daily: 09:00"
timeout: 15m
agent: high
mode: ask
session: daily-review
workdir: /home/user/projects/myapp
commands:
- |
Review the git changes from the last 24 hours:
git log --since="24 hours ago" --oneline --stat
Summarize what changed and flag any concerns.
Write the report to reports/review-$[[ .Date ]].md
post:
- cat reports/review-$[[ .Date ]].md
session: daily-reviewresumes the same session across runs, preserving context.postshell hooks run after the LLM session completes.
Condition Gates
/assert — run actions once when a condition is true
# Celebrate if the build passes
aura run '/assert bash:"go build ./..." "Build passed!"'
# Save the session if all todos are done
aura run '/assert todo_done "/save"'
# Warn if context is getting large
aura run '/assert context_above:80 "Context is filling up. Consider /compact."'
/until — loop until a condition is met
# Keep fixing until tests pass
aura run '/until bash:"go test ./..." "Tests are failing. Fix them."'
# Wait for a file to appear
aura run '/until exists:output.json "Generate output.json from the input data."'
# Bounded retries
aura run '/until --max 5 bash:"curl -sf http://localhost:8080/health" "Service is not healthy yet. Check logs."'
Condition types
| Condition | True when |
|---|---|
todo_empty | No todo items |
todo_done | All items completed |
todo_pending | Pending or in-progress items exist |
auto | Auto mode is enabled |
context_above:N / context_below:N | Token usage percentage |
history_gt:N / history_lt:N | Message count |
tool_errors_gt:N / tool_errors_lt:N | Tool error count |
turns_gt:N / turns_lt:N | LLM turn count |
model_has:vision | Model capability check |
model_is:name | Model name match |
exists:path | File or directory exists |
bash:cmd | Shell command exits 0 |
All conditions support not for negation and and for composition.
Auto Mode Patterns
Guarded auto mode
- /auto on
- /done
- Implement the feature described in SPEC.md
- /assert not todo_done "There are still incomplete items. Finish them all."
- /assert todo_done "/save"
/doneenforces that the LLM must explicitly call the Done tool to exit. Without it, the LLM can stop by simply not making tool calls.- The
/assertlines act as post-conditions after auto mode completes.
Auto mode with budget
tools:
max_steps: 100
token_budget: 500000
max_steps caps tool-use iterations. token_budget caps cumulative tokens (input + output) across the session. The built-in max-steps injector disables tools when the limit is reached.
Custom Slash Commands
Markdown files with YAML frontmatter in .aura/config/commands/:
---
name: review
description: Review a file for quality issues
hints: <file>
---
Review $1 for:
- Code quality and best practices
- Potential bugs or edge cases
- Readability and maintainability
Provide specific, actionable feedback with code examples where appropriate.
Usage: /review internal/assistant/loop.go
The body is rendered as a Go template with $1, $2, … for positional arguments and $ARGUMENTS for the full argument string. All custom commands forward their output to the LLM as a user message.
Bash Rewrite
Every Bash tool command passes through tools.bash.rewrite before execution. The template receives `` (the original command) and all sprig functions.
Token-optimized output with rtk
tools:
bash:
rewrite: |
if command -v rtk >/dev/null 2>&1 && REWRITTEN=$(rtk rewrite 2>/dev/null); then
eval "${REWRITTEN}"
else
fi
Activate a virtualenv
tools:
bash:
rewrite: |
source .venv/bin/activate &&
Run inside a container
tools:
bash:
rewrite: |
docker exec -w /app mycontainer sh -c ''
Hooks
Shell commands that run before or after tool execution. Defined in .aura/config/hooks/:
# .aura/config/hooks/format.yaml
format-on-write:
tool: Patch
post: |
goimports -w $FILE
files:
- "*.go"
toolmatches the tool name.postruns after successful tool execution.$FILEis the path of the affected file.filesfilters by glob pattern.
Hooks support depends: for DAG ordering, inherit: for config reuse, and disabled: for toggling.
Go Plugins
Plugins are Go packages under .aura/plugins/ interpreted by Yaegi at runtime.
Lifecycle hook
package myplugin
import (
"context"
"github.com/idelchi/aura/sdk"
)
func AfterToolExecution(ctx context.Context, c sdk.AfterToolContext) (sdk.Result, error) {
if c.Tool.Error != "" && c.Tool.Name == "Bash" {
return sdk.Result{
Message: "Bash command failed. Try a different approach.",
}, nil
}
return sdk.Result{}, nil
}
Custom tool
package mytool
import (
"context"
"github.com/idelchi/aura/sdk"
)
func Schema() sdk.ToolSchema {
return sdk.ToolSchema{
Name: "Greet",
Description: "Say hello",
Parameters: sdk.ToolParameters{
Type: "object",
Properties: map[string]sdk.ToolProperty{
"name": {Type: "string", Description: "Who to greet"},
},
Required: []string{"name"},
},
}
}
func Execute(ctx context.Context, sc sdk.Context, args map[string]any) (string, error) {
return "Hello, " + args["name"].(string) + "!", nil
}
Custom slash command
package mycommand
import (
"context"
"github.com/idelchi/aura/sdk"
)
func Command() sdk.CommandSchema {
return sdk.CommandSchema{
Name: "ping",
Description: "Check if the assistant is alive",
}
}
func ExecuteCommand(ctx context.Context, args string, sctx sdk.Context) (sdk.CommandResult, error) {
return sdk.CommandResult{Output: "pong"}, nil
}
Install plugins from git:
aura plugins add https://github.com/user/my-plugin
Config Inheritance
Agents, modes, prompts, hooks, and tasks support inherit: with DAG-based resolution.
# .aura/config/agents/base.md frontmatter
---
provider: ollama
model: llama3:8b
mode: ask
---
# .aura/config/agents/advanced.md frontmatter
---
inherit: base
model: qwen3:32b
mode: edit
---
advanced inherits provider: ollama from base but overrides the model and mode. Multi-parent inheritance is supported: inherit: [base, restricted].
Template Variables
--set KEY=value injects variables available everywhere: system prompts, task commands, agent file paths, thinking/compaction prompts.
aura --set PROJECT=myapp --set ENV=staging run "Deploy $PROJECT to $ENV"
In tasks:
deploy:
vars:
TARGET: staging
commands:
- Deploy the application to $[[ .TARGET ]]
vars: provides defaults. --set overrides them.
Prompt Templating
System prompts, agent prompts, and mode prompts are Go templates with access to runtime state. All fields on TemplateData are available — hooks, model capabilities, sandbox state, tools, and user-defined variables.
Active hooks
{{- if .Hooks.Active }}
These hooks run after your tool calls and may modify files:
{{ range .Hooks.Active -}}
- {{ .Name }}: {{ .Description }}
{{ end -}}
{{- end }}
The default agentic prompt already includes this. Add description: to your hooks and the LLM will know to expect automated file changes.
Model-aware prompts
{{- if .Model.Vision }}
You can analyze images. Use the Vision tool when the user provides screenshots.
{{- end }}
{{- if not .Model.Thinking }}
Break complex problems into explicit steps — this model does not have extended reasoning.
{{- end }}
{{- if lt .Model.ContextLength 32000 }}
Keep responses concise. Context window is limited to {{ .Model.ContextLength }} tokens.
{{- end }}
Sandbox-aware instructions
{{- if .Sandbox.Enabled }}
You are running in a sandboxed environment.
{{ .Sandbox.Display }}
{{- end }}
Tool-aware behavior
Available tools: {{ join .Tools.Eager ", " }}
{{- if .Tools.Deferred }}
Some tools are deferred. Use LoadTools to discover and load them when needed.
{{- end }}
User-defined variables
Pass variables with --set KEY=value and access them in prompts:
Project: {{ index .Vars "PROJECT" }}
Environment: {{ index .Vars "ENV" }}
Input Directives
Embed files, images, and command output directly in prompts:
@File[config.yaml] # Inline file contents
@Image[screenshot.png] # Attach image for vision models
@Path[~/projects] # Resolve path with env expansion
@Bash[git log -5] # Inline shell command output
Skills
LLM-invocable capabilities. The LLM sees skill names and descriptions, and calls them via the Skill tool when relevant.
---
name: commit
description: Create a well-formatted git commit
---
Review the staged changes with `git diff --cached`.
Write a commit message following conventional commits.
Run `git commit -m "<message>"`.
aura skills add https://github.com/user/my-skills --subpath skills