Handlebars Reference

Complete reference for Handlebars syntax and available template variables in Ralph TUI.

Handlebars Basics

Ralph uses Handlebars for template rendering. Handlebars is a logic-less templating language that uses double curly braces for variable substitution.

Variable Substitution

Insert variable values with \{\{variableName\}\}:

HANDLEBARS
**Task ID**: \{\{taskId\}\}
**Title**: \{\{taskTitle\}\}

Renders to:

Markdown
**Task ID**: US-001
**Title**: Add user authentication

Conditional Blocks

Show content only when a variable has a value:

HANDLEBARS
\{\{#if taskDescription\}\}
## Description
\{\{taskDescription\}\}
\{\{/if\}\}

The block renders only if taskDescription is non-empty.

Else Blocks

Provide fallback content:

HANDLEBARS
\{\{#if epicTitle\}\}
**Epic**: \{\{epicTitle\}\}
\{\{else\}\}
*No epic assigned*
\{\{/if\}\}

Unless Blocks

Inverse of if - renders when value is falsy:

HANDLEBARS
\{\{#unless dependsOn\}\}
This task has no dependencies - you can start immediately!
\{\{/unless\}\}

Comments

Add template comments that won't appear in output:

HANDLEBARS
\{\{!-- This is a Handlebars comment --\}\}
\{\{! Short comment syntax \}\}

Available Variables

Ralph provides these variables for template rendering:

Task Information

VariableTypeDescription
taskIdstringUnique task identifier (e.g., "US-001", "beads-abc")
taskTitlestringTask title/summary
taskDescriptionstringFull task description
acceptanceCriteriastringExtracted acceptance criteria (formatted as checklist)
typestringTask type: "feature", "bug", "task", etc.
statusstringCurrent status: "open", "in_progress", "closed"
prioritystringPriority level: "0" (critical) to "4" (backlog)
notesstringAdditional task notes or context

Relationships

VariableTypeDescription
dependsOnstringComma-separated list of dependency task IDs
blocksstringComma-separated list of tasks this blocks
labelsstringComma-separated list of labels
epicIdstringParent epic ID (if part of an epic)
epicTitlestringParent epic title

Context Information

VariableTypeDescription
trackerNamestringActive tracker: "json", "beads", "beads-bv"
agentNamestringActive agent: "claude", "opencode"
modelstringModel being used (if configured)
cwdstringCurrent working directory path
currentDatestringCurrent date in ISO format (YYYY-MM-DD)
currentTimestampstringCurrent timestamp in ISO format
beadsDbPathstringFull path to beads database (for bd --db flag)

PRD Context (Project Requirements)

When using a tracker that supports PRD context (JSON tracker with metadata.sourcePrd), these variables provide full project visibility:

VariableTypeDescription
prdNamestringName of the PRD/project
prdDescriptionstringPRD description
prdContentstringFull PRD markdown content (for agent to study)
prdCompletedCountstringNumber of completed tasks/stories
prdTotalCountstringTotal number of tasks/stories

Progress & Patterns

VariableTypeDescription
recentProgressstringSummary of progress from recent iterations
codebasePatternsstringLearnings and patterns from previous iterations
selectionReasonstringWhy this task was selected (beads-bv tracker)

Variable Details

taskDescription

The full description from your task tracker. For JSON (prd.json), this is the story description. For Beads, it's the issue body.

HANDLEBARS
\{\{#if taskDescription\}\}
## Description
\{\{taskDescription\}\}
\{\{/if\}\}

acceptanceCriteria

Extracted from task metadata or parsed from description. Ralph formats array-based criteria as a markdown checklist:

HANDLEBARS
\{\{#if acceptanceCriteria\}\}
## Acceptance Criteria
\{\{acceptanceCriteria\}\}
\{\{/if\}\}

Renders as:

Markdown
## Acceptance Criteria
- [ ] User can log in with email/password
- [ ] Session persists across page refreshes
- [ ] Invalid credentials show error message

dependsOn and blocks

These show task relationships for dependency-aware workflows:

HANDLEBARS
\{\{#if dependsOn\}\}
**Blocked by**: \{\{dependsOn\}\}
Complete these first before starting.
\{\{/if\}\}
 
\{\{#if blocks\}\}
**Impact**: Completing this unblocks: \{\{blocks\}\}
\{\{/if\}\}

recentProgress

When cross-iteration progress tracking is enabled, this contains a summary of recent work:

HANDLEBARS
\{\{#if recentProgress\}\}
## Previous Progress
\{\{recentProgress\}\}
\{\{/if\}\}

The progress file is managed automatically by Ralph and includes:

  • Notes from previous iterations
  • Insights and learnings
  • Context for the current task

PRD Context Variables

When your tracker provides PRD context (e.g., JSON tracker with metadata.sourcePrd), you can include full project context in your prompts:

HANDLEBARS
\{\{#if prdContent\}\}
## PRD: \{\{prdName\}\}
\{\{#if prdDescription\}\}
\{\{prdDescription\}\}
\{\{/if\}\}
 
### Progress: \{\{prdCompletedCount\}\}/\{\{prdTotalCount\}\} tasks complete
 
<details>
<summary>Full PRD Document (click to expand)</summary>
 
\{\{prdContent\}\}
 
</details>
\{\{/if\}\}

This gives the AI agent full visibility into the project requirements and current progress.

codebasePatterns

Contains learnings and patterns discovered during previous iterations:

HANDLEBARS
\{\{#if codebasePatterns\}\}
## Codebase Patterns (Study These First)
\{\{codebasePatterns\}\}
\{\{/if\}\}

Patterns are typically extracted from .ralph-tui/progress.md and help agents avoid repeating mistakes.

selectionReason (beads-bv)

For the beads-bv tracker with graph-aware selection, this explains why the current task was chosen:

HANDLEBARS
\{\{#if selectionReason\}\}
## Why This Task Was Selected
\{\{selectionReason\}\}
\{\{/if\}\}

This might include information about dependencies, blocking relationships, or priority scores.

priority

Priority as a string, where lower numbers = higher priority:

ValueMeaning
"0"Critical/P0
"1"High/P1
"2"Medium/P2 (default)
"3"Low/P3
"4"Backlog/P4
HANDLEBARS
\{\{#if priority\}\}
**Priority**: P\{\{priority\}\}
\{\{/if\}\}

Advanced Usage

Accessing Raw Objects

For advanced templates, access the full task and config objects:

HANDLEBARS
\{\{!-- Access task metadata --\}\}
\{\{#if task.metadata.branch\}\}
Branch: \{\{task.metadata.branch\}\}
\{\{/if\}\}
 
\{\{!-- Access nested properties --\}\}
\{\{#with task\}\}
  ID: \{\{id\}\}
  Title: \{\{title\}\}
  \{\{#each labels\}\}
    - \{\{this\}\}
  \{\{/each\}\}
\{\{/with\}\}
INFO

Raw object access exposes internal structure that may change. Use documented variables when possible for forward compatibility.

Iterating Over Arrays

When accessing raw arrays (like from task.labels):

HANDLEBARS
\{\{#each task.labels\}\}
- \{\{this\}\}
\{\{/each\}\}

Nested Conditionals

Combine conditions for complex logic:

HANDLEBARS
\{\{#if epicId\}\}
  \{\{#if epicTitle\}\}
**Epic**: \{\{epicId\}\} - \{\{epicTitle\}\}
  \{\{else\}\}
**Epic**: \{\{epicId\}\}
  \{\{/if\}\}
\{\{/if\}\}

Handlebars Syntax Reference

Expression Escaping

By default, Handlebars escapes HTML entities. Ralph disables this (using noEscape: true), so your content renders as-is:

HANDLEBARS
\{\{!-- These render the same in Ralph --\}\}
\{\{taskDescription\}\}
\{\{{taskDescription\}\}}

Block Helpers

HelperUsageDescription
if\{\{#if var\}\}...\{\{/if\}\}Renders block if truthy
unless\{\{#unless var\}\}...\{\{/unless\}\}Renders block if falsy
each\{\{#each array\}\}...\{\{/each\}\}Iterates over array
with\{\{#with object\}\}...\{\{/with\}\}Changes context

Special Variables

VariableContextDescription
thisInside eachCurrent array item
@indexInside eachCurrent index (0-based)
@firstInside eachTrue if first iteration
@lastInside eachTrue if last iteration
@keyInside each (object)Current property key

Path Notation

Access nested properties with dot notation:

HANDLEBARS
\{\{task.metadata.customField\}\}
\{\{config.tracker.plugin\}\}

Common Patterns

Fallback Values

Show a default when variable is empty:

HANDLEBARS
\{\{#if type\}\}
**Type**: \{\{type\}\}
\{\{else\}\}
**Type**: task
\{\{/if\}\}

Conditional Sections

Include entire sections conditionally:

HANDLEBARS
\{\{#if epicId\}\}
## Epic Context
- **Epic**: \{\{epicId\}\}
- **Title**: \{\{epicTitle\}\}
\{\{/if\}\}

Formatted Lists

When you have comma-separated values:

HANDLEBARS
\{\{#if labels\}\}
**Labels**: \{\{labels\}\}
\{\{/if\}\}

Note: labels is already comma-joined by Ralph. For full control, access task.labels array directly.

Date/Time Context

Include temporal context:

HANDLEBARS
\{\{!-- Just the date --\}\}
Started: \{\{currentDate\}\}
 
\{\{!-- Full timestamp --\}\}
Timestamp: \{\{currentTimestamp\}\}

Troubleshooting

Variable Not Rendering

If a variable shows as empty:

  1. Check the variable name spelling
  2. Verify your tracker provides that data
  3. Use ralph-tui template show to see available data

Syntax Errors

Common mistakes:

HANDLEBARS
\{\{!-- Wrong: Missing closing --\}\}
\{\{#if condition}
Content
\{\{/if\}\}
 
\{\{!-- Wrong: Extra spaces in helper --\}\}
\{\{ #if condition \}\}
 
\{\{!-- Correct --\}\}
\{\{#if condition\}\}
Content
\{\{/if\}\}

Conditional Not Working

Handlebars considers these falsy:

  • Empty string ""
  • null or undefined
  • false
  • 0
  • Empty array []

If your variable is an empty string, the \{\{#if\}\} block won't render.

Template Examples by Use Case

Strict Quality Gates

HANDLEBARS
## Task: \{\{taskTitle\}\}
 
\{\{taskDescription\}\}
 
## MANDATORY Quality Gates
Run ALL of these before signaling completion:
 
1. **Type Check**: `bun run typecheck`
   - Must have ZERO errors
 
2. **Lint**: `bun run lint`
   - Must have ZERO warnings
 
3. **Tests**: `bun run test`
   - All tests must pass
 
DO NOT signal completion if any check fails.
 
<promise>COMPLETE</promise>

Minimal Context

HANDLEBARS
\{\{taskTitle\}\}
 
\{\{acceptanceCriteria\}\}
 
Done? <promise>COMPLETE</promise>

Maximum Context

HANDLEBARS
\{\{#if prdContent\}\}
## PRD: \{\{prdName\}\}
\{\{prdDescription\}\}
### Progress: \{\{prdCompletedCount\}\}/\{\{prdTotalCount\}\} complete
<details>
<summary>Full PRD</summary>
\{\{prdContent\}\}
</details>
\{\{/if\}\}
 
\{\{#if codebasePatterns\}\}
## Codebase Patterns
\{\{codebasePatterns\}\}
\{\{/if\}\}
 
# \{\{taskTitle\}\}
 
## Metadata
| Field | Value |
|-------|-------|
| ID | \{\{taskId\}\} |
| Type | \{\{type\}\} |
| Priority | P\{\{priority\}\} |
| Status | \{\{status\}\} |
| Labels | \{\{labels\}\} |
| Tracker | \{\{trackerName\}\} |
| Agent | \{\{agentName\}\} |
| Date | \{\{currentDate\}\} |
 
\{\{#if epicId\}\}
## Epic: \{\{epicId\}\}
\{\{epicTitle\}\}
\{\{/if\}\}
 
## Description
\{\{taskDescription\}\}
 
## Acceptance Criteria
\{\{acceptanceCriteria\}\}
 
\{\{#if dependsOn\}\}
## Dependencies
Depends on: \{\{dependsOn\}\}
\{\{/if\}\}
 
\{\{#if blocks\}\}
## Impact
Unblocks: \{\{blocks\}\}
\{\{/if\}\}
 
\{\{#if recentProgress\}\}
## Previous Progress
\{\{recentProgress\}\}
\{\{/if\}\}
 
\{\{#if selectionReason\}\}
## Selection Reason
\{\{selectionReason\}\}
\{\{/if\}\}
 
## Completion
<promise>COMPLETE</promise>

Next Steps