Template variables
AICR renders every published problem and summary through a Handlebars template
before dispatch. Built-in templates live in templates/builtin/*.hbs in the
deployment directory and cover the problem-comment and summary variants for
every built-in channel kind. You can override them per workspace without
forking the built-ins.
See Output channels for how rendered templates are dispatched to each channel kind, and Configuration fields for the channel-level fields referenced below.
Candidate template filename resolution
Section titled “Candidate template filename resolution”Override templates are loaded from the workspace template directory:
workspaces/<workspace_id>/templates/For a given channel and template kind (typically summary or problem),
AICR resolves the candidate file name in this order, using the first match:
<channel_name>.<kind>.md.hbs(for examplefeishu-code-review.summary.md.hbs)<channel_name>.<kind>.hbs<channel_kind>.<kind>.md.hbs(for examplefeishu_bot.summary.md.hbs)<channel_kind>.<kind>.hbs<kind>.md.hbs(for examplesummary.md.hbs)<kind>.hbs
<channel_name> is the name you set on the channel in outputs.channels[];
<channel_kind> is the channel kind (such as feishu_bot or
gitea_pr_review). A more specific channel-name override always wins over a
channel-kind fallback, which in turn wins over a generic kind-only fallback.
If no override is found, the built-in template for that channel kind and kind is used.
Variable tree
Section titled “Variable tree”All variables are passed as a single context object. The most useful fields are listed below. Fields marked when available are optional and depend on the trigger kind and event payload (PR/MR, push, commit, P4 changelist, SVN revision, scheduled, manual).
| Variable | Meaning |
|---|---|
{{event.author}} |
Normalized event author username, when available |
{{event.email}} |
Author email, when available |
{{event.displayName}} |
Author display name, when available |
{{event.url}} |
Raw event URL, when available; templates must not assume this is always a PR/MR URL |
{{event.title}} |
Event title (PR/MR title, commit message subject, changelist description), when available |
{{target.kind}} |
Target kind (pull_request, push, commit, issue, manual, scheduled) |
{{target.displayText}} |
Safe plain-text target label for any event kind |
{{target.markdownLink}} |
Safe Markdown target link; use this instead of hard-coding [View PR] |
{{target.url}} |
Target URL, when available |
{{repo.name}} |
Short repository name |
{{repo.fullName}} |
Full repository reference (owner/repo, depot path, or repository URL) |
{{vcs.branch}} |
Git branch name, when available |
{{vcs.sourcePath}} |
Provider-specific source namespace/path (depot or repository subpath), when available |
{{vcs.workspace}} |
Submitter client/workspace name captured from the event (P4 %client%/payload client), when available; this is the submitter’s workspace, not AICR’s analysis client |
{{vcs.repositoryPath}} |
Repository/depot reference path, when available |
{{run.id}} |
Review run ID, when available |
{{atMentions}} |
Pre-rendered, channel-specific mention string (already in the platform’s native mention syntax) |
{{summaryTitle}} |
Optional short summary title supplied via aicr.publish_summary.title |
{{summary}} |
Summary Markdown body |
{{problems}} |
Problem list (used in summary templates); iterate with {{#each problems}} |
{{problem.file}} |
Repository-relative path of one reported problem (problem templates) |
{{problem.line}} |
Primary anchor line number |
{{problem.location}} |
Pre-rendered location label (file:line) |
{{problem.severity}} |
info / low / medium / high / critical |
{{problem.category}} |
Short problem family (for example correctness, security) |
{{problem.message}} |
Problem analysis: what is wrong, trigger scenario, impact |
{{problem.suggestion}} |
Optional fix direction; may include a fenced diff patch |
{{problem.codeSnippet}} |
Optional AICR-derived code reference snippet (Git-based channels) |
{{problem.codeLanguage}} |
Detected language for the snippet |
{{{problem.codeFence}}} |
Pre-built fenced code block (use triple braces — already-escaped HTML) |
Author rendering
Section titled “Author rendering”For Git-based channels (gitea_*, github_*, gitlab_mr_review), built-in
templates prefer @username when a provider username is available. If a
display name is also available, they render @username (Display Name) so the
platform can still resolve the mention while humans see the nickname. IM bot
summary templates (feishu_bot, wecom_bot) use the same human-readable
@username (Display Name) convention for event authors; native bot mentions
flow through the separate {{atMentions}} path when enabled.
Removed variables
Section titled “Removed variables”Templates must use {{problems}} and {{problem.*}}. The legacy
{{findings}} and {{finding.*}} variables are not provided. Likewise, do
not render [View PR] for non-PR/MR events — use target.markdownLink or
target.displayText instead.
URL template variables
Section titled “URL template variables”Triggers and channels accept URL templates (commit_url_template,
revision_url_template, change_url_template) for providers that do not
expose a derivable commit/revision URL (P4 Swarm, ViewVC, custom review UIs).
Values are URL-encoded before substitution. Supported variables:
{{revision}}, {{commit}}, {{commit_id}}, {{headSha}},
{{head_sha}}, {{baseSha}}, {{base_sha}}, {{repo}}, {{repo_ref}},
{{provider}}, {{trigger}}, {{workspace_id}}.
triggers: - name: p4-main kind: p4 change_url_template: "https://swarm.example.com/changes/{{revision}}"
outputs: channels: - name: feishu-code-review kind: feishu_bot revision_url_template: "https://review.example.com/revisions/{{revision}}"work_path template variables
Section titled “work_path template variables”Multi-project instances (match[]) render their directory from
workspaces.instances.<id>.work_path — a restricted Handlebars path template.
Only the segment, default, hash, and lower helpers are allowed, the
output must be a relative / path, and the default is {{workspace.id}}.
The catalog below comes from the runtime variable registry; unknown roots,
registered-but-unextracted scheduled.* fields, and the forbidden event.*
namespace all fail validation when the configuration is published. Nullable
variables (marked *) can be null for some event kinds — wrap them in
default with a literal fallback inside segment/hash.
| Root | Variables (* = nullable) |
Notes |
|---|---|---|
trigger.* |
name, kind, host* |
Trigger profile identity |
source.* |
vcs, repo_ref, repository*, namespace*, project_key, branch*, ref* |
Normalized source fields |
workspace.* |
id, instance_id |
Definition and matched instance |
git.* |
owner*, repository, full_name, namespace*, branch*, ref*, base_branch*, head_branch*, head_repository*, head_owner*, default_branch* |
Any git trigger kind (GitHub/GitLab/Gitea/Forgejo) |
github.*, gitea.*, forgejo.* |
owner*, repository, full_name, branch*, base_branch*, head_branch*, repository_id*, pull_number*, issue_number* (plus github.installation_id*) |
The matching provider only |
gitlab.* |
namespace*, project, path_with_namespace, branch*, source_branch*, target_branch*, project_id*, source_project_id*, target_project_id*, merge_request_iid*, issue_iid* |
GitLab only |
p4.* |
server, depot, depot_path, stream, stream_name, client, service_client, user, change, scope |
P4 only; from submitted changelist metadata and configured scopes |
svn.* |
repository_url, repository_root, repository_uuid, repository, project_path, branch, revision, author |
SVN only; revision-pinned |
manual.* |
request_id*, requested_workspace*, requested_by* |
Trusted CLI input only |
scheduled.* |
job_id, schedule_id, scheduled_at, timezone |
Registered but not yet extracted — rejected |
event.* |
— | Forbidden in paths — rejected |
Provider variables must exist for every trigger kind the matching rule
accepts: a template that uses git.branch cannot match a p4 trigger. Git
provider IDs and numbers are decimal strings, or null when absent.
{{segment trigger.name}}/{{segment (default source.namespace "shared")}}/{{segment source.project_key}}Handlebars example
Section titled “Handlebars example”A workspace-scoped Feishu summary override. Place it at
workspaces/p4-main/templates/feishu_bot.summary.hbs:
**{{target.displayText}}**{{#if event.author}}**Author**: @{{event.author}}{{#if event.email}} <{{event.email}}>{{/if}}{{/if}}{{#if vcs.sourcePath}}**Source**: {{vcs.sourcePath}}{{/if}}{{#if vcs.workspace}}**Workspace**: {{vcs.workspace}}{{/if}}{{{summary}}}A problem-comment template iterating the problem list:
## {{summaryTitle}}
{{#if atMentions}}{{atMentions}} {{/if}}Reviewed {{target.displayText}}.
{{{summary}}}
{{#each problems}}### [{{severity}}] {{category}} — {{location}}
{{message}}
{{#if suggestion}}**Suggested fix**
{{suggestion}}{{/if}}
{{#if codeFence}}{{{codeFence}}}{{/if}}{{/each}}Notes:
- Use triple braces (
{{{ }}}) for fields that already contain rendered Markdown or HTML (summary,codeFence); use double braces ({{ }}) for plain-text fields so Handlebars escapes them. - After rendering, AICR fixes and validates the Markdown before dispatch. If a template cannot be made safe and valid, AICR prefers a plain-text fallback over dropping the report.
- Lint a template before deploying it with the
lintCLI command.