Output Channels and Routing
After a review finishes, AICodeReviewer dispatches the result to one or more
output channels — PR line comments, IM bots, managed issues — based on
routing rules. The outputs namespace defines the channels, the routes,
the template engine, and the zero-problem policy that decides whether a
clean review should notify anyone.
outputs: template_engine: handlebars no_problems: { action: suppress } channels: - name: gitea-pr-review kind: gitea_pr_review trigger: gitea routes: default: line_comments: [gitea-pr-review] summary: [gitea-pr-review]outputs.template_engine
Section titled “outputs.template_engine”| Value | Description |
|---|---|
handlebars (default) |
Handlebars templates (*.hbs). Built-ins live in templates/builtin/*.hbs. |
eta |
Reserved — accepted by the schema, but only Handlebars is implemented; setting it has no effect. |
Override templates per workspace by placing files under
workspaces/<workspace_id>/templates/. Candidate file names are checked in
order: <channel_name>.<kind>.md.hbs → <channel_name>.<kind>.hbs →
<channel_kind>.<kind>.md.hbs → <channel_kind>.<kind>.hbs →
<kind>.md.hbs → <kind>.hbs.
outputs.no_problems — zero-problem policy
Section titled “outputs.no_problems — zero-problem policy”Decides whether a successful review with no actionable problems should notify each channel.
action |
Behavior |
|---|---|
suppress |
Do not notify when there are no problems. |
publish |
Always notify, even with zero problems. |
publish_if_summary |
Notify only if a non-empty summary was produced. |
When nothing is configured, the default depends on the channel kind: managed
problem-issue channels (*_problem_issue) default to publish — publishing is
what drives stale issues to close; IM bots default to publish_if_summary;
everything else defaults to suppress.
The policy is set at three levels, each more specific:
outputs.no_problems(global default for all channels)- per-channel
no_problemsinsideoutputs.channels[] - per-workspace + per-channel via
workspaces.instances.<id>.outputs.channel_overrides.<channel>.no_problems
outputs: no_problems: { action: suppress } channels: - name: feishu-code-review kind: feishu_bot no_problems: { action: suppress }
workspaces: instances: critical-service: outputs: channel_overrides: feishu-code-review: no_problems: { action: publish } # this repo wants an audit trailIf all selected summary channels suppress a zero-problem result, the run is
recorded as skipped with skipReason="no_problems_suppressed". The policy
only gates visible summaries: managed problem-issue channels still reconcile
stored findings on every genuine zero-problem review so confirmed fixes can
close (resolved_action: none opts out).
outputs.channels[] — output targets
Section titled “outputs.channels[] — output targets”Every channel has a name (referenced by routes and workspace output lists)
and a kind. The common fields below apply to most kinds; kind-specific
fields are listed under each kind.
Common fields
Section titled “Common fields”| Field | Type | Description |
|---|---|---|
name |
string | Unique channel id. |
kind |
string | Channel kind (see list below). gitea_finding_issue is removed — use gitea_problem_issue. |
trigger |
string | Trigger name this channel binds to (for VCS-backed kinds). |
mention_author |
bool | @-mention the commit author in the message. Defaults to true for VCS PR/issue kinds and false for IM bots. |
mention_fallback |
enum | all (mention everyone) or skip (no mention if author not found). |
no_problems |
object | Per-channel zero-problem policy (see above). |
commit_url_template |
string | Override commit link for push/commit targets. |
revision_url_template |
string | Override revision link (P4/SVN). |
change_url_template |
string | Override change link. |
marker_prefix |
string | Title prefix for managed issues (e.g. [AICR]). |
marker_label |
string | Hidden label identifying managed issues (e.g. aicr-managed). |
labels |
string[] | Labels to attach. |
label_ids |
int[] | Numeric label ids (some VCS APIs). |
issue_mode |
enum | per_problem, consolidated (default), or per_commit. |
resolved_action |
enum | none, close, mark_resolved, or delete. Action when a problem is fixed. |
assign_committer |
bool | Add the resolved review author to newly created managed issues (default true); see assignment rules below. |
owners_file |
string | Path to OWNERS file (default OWNERS). |
add_owners_as_assignees |
bool | Add matched OWNERS as assignees. |
severity_label_prefix |
string | Auto-created label prefix (e.g. aicr:problem:). |
severity_label_colors |
map | Custom label colors (hex without #). |
review_mode |
enum | auto (default), review, or comment. |
review_event |
enum | COMMENT (default) or REQUEST_CHANGES. |
review_update_strategy |
enum | always_new or update_existing (default). |
notify_feishu |
object | Optional Feishu notify-on-issue-creation (webhook_url_env, secret_env). |
Issue assignment
Section titled “Issue assignment”GitHub/Gitea managed issues resolve the event login, then outputs.author_resolution.email_mappings, then the linked head-commit author, and finally the retained push pusher. Pushes with head-commit metadata use that author’s identity; PR events prefer the PR author over the delivery sender. Git display names are not platform logins. GitHub queries /repos/{owner}/{repo}/commits/{sha}; Gitea/Forgejo queries /repos/{owner}/{repo}/git/commits/{sha}. Queries use the output repository and credentials and are cached per review.
email_blacklist and assign_committer: false block author lookup and fallback. OWNERS assignments remain independent. Missing identities or failed lookups leave the author unassigned. Only explicit HTTP 422 assignee validation errors trigger one creation retry without assignees; other failures propagate. Existing issue assignees are retained.
The publishing account needs assignment permission, and the target user must be eligible. GitHub/Gitea can silently ignore assignment when the publisher lacks the required repository access; check the created issue’s assignees. Private GitHub commit lookup needs Contents read permission. GitLab currently supports MR discussions/notes only; issue creation and assignment are unimplemented.
Channel kinds
Section titled “Channel kinds”| Kind | Description |
|---|---|
gitea_pr_review |
Inline line comments on Gitea/Forgejo pull requests. |
github_pr_review |
Inline line comments on GitHub pull requests. |
gitlab_mr_review |
Inline line comments on GitLab merge requests. |
gitea_problem_issue |
Managed Gitea issues created/closed per problem fingerprint. |
github_problem_issue |
Managed GitHub issues per problem fingerprint (no delete — GitHub does not support it). |
gitlab_problem_issue |
Managed GitLab issues per problem fingerprint (assignees must be project members; CE effectively supports one assignee; delete requires owner/admin). |
gitea_issue |
Post the aggregated review as a comment on an existing Gitea issue. |
github_issue |
Post the aggregated review as a comment on an existing GitHub issue. |
feishu_bot |
Push aggregated problems to a Feishu (飞书) group via custom bot. |
feishu_app |
Send the shared Feishu report card through a custom application’s bot; see setup and member matching. |
wecom_bot |
Push aggregated problems to a WeCom (企业微信) group via webhook. |
wecom_app |
Send the aggregated report through a WeCom self-built application to explicit members or one appchat group; see IM bots. |
review_mode — PR review API strategy
Section titled “review_mode — PR review API strategy”For *_pr_review / *_mr_review kinds:
| Value | Behavior |
|---|---|
auto (default) |
Try the PR review API first; fall back to issue comment on 403/422. |
review |
Always use the PR review API, no fallback. |
comment |
Always post a plain issue comment, never the review API. |
The companion review_event field controls the event type used with the review
API: COMMENT (default) or REQUEST_CHANGES.
PR review summary update strategy
Section titled “PR review summary update strategy”review_update_strategy controls how the PR summary behaves across pushes:
| Value | Behavior |
|---|---|
always_new |
Create a new review/comment on every push (original behavior). |
update_existing (default) |
Find and update the previous AICR summary comment on the PR. Open issues are kept; resolved issues are marked with ✅; new issues are tagged with the introducing commit. |
AICR identifies its own managed comments via stable managed comment markers
derived from marker_prefix/marker_label, so only AICR-owned summary
comments are updated and other comments are left untouched.
outputs.routes — send results to the right channels
Section titled “outputs.routes — send results to the right channels”Routes map review outputs (line_comments and summary) to channel lists.
A default route applies to every event; rules[] override for specific
triggers or target kinds.
outputs: routes: default: line_comments: [gitea-pr-review] summary: [gitea-pr-review] rules: - match: trigger: p4-main target_kind: commit summary: [feishu-code-review] - match: trigger: github target_kind: push summary: [feishu-code-review, github-problem-issues]| Field | Type | Description |
|---|---|---|
default.line_comments |
string[] | Channels for inline line comments. |
default.summary |
string[] | Channels for the aggregated summary. |
rules[].match.trigger |
string | Match events from this trigger name. |
rules[].match.target_kind |
string | Match a target kind (e.g. commit, push, pull_request). pr is normalized to pull_request. |
rules[].line_comments |
string[] | Override line-comment channels for matched events. |
rules[].summary |
string[] | Override summary channels for matched events. |
Per-workspace output lists (workspaces.instances.<id>.outputs.line_comments
and .summary) take precedence over the global routes for that workspace.
Label management (review.labels)
Section titled “Label management (review.labels)”AICodeReviewer can skip reviews based on labels and auto-tag PRs/MRs/issues.
This lives under review (not outputs) but is closely related to output
dispatch.
review: labels: ignore: ["aicr:ignore", "aicr-ignore"] # skip review if any label matches auto_tag: "aicr" # tag added when AICR starts reviewed_tag: "aicr:reviewed" # tag added when review completes| Field | Behavior |
|---|---|
ignore |
Checked at the webhook layer. If a PR/MR/issue carries any listed label, AICR returns immediately without scheduling a review. |
auto_tag |
Fixed tag applied by output dispatchers (gitea_pr_review, github_pr_review, gitlab_mr_review, gitea_issue, gitea_problem_issue, github_problem_issue, gitlab_problem_issue) when publishing. Created automatically if missing. |
reviewed_tag |
Tag applied when a review completes. |
All fields support the global → workspace-level override layering.
Managed problem-issue lifecycle limit
Section titled “Managed problem-issue lifecycle limit”gitea_problem_issue, github_problem_issue, and gitlab_problem_issue
reconcile stale managed
issues by listing only the most recent open issues. The cap lives under
review.problem_issue and can be tightened per workspace.
review: problem_issue: max_recent_issues: 30 # default; valid range is 1..200
workspaces: instances: latency-sensitive-service: review: problem_issue: max_recent_issues: 10If a repository has more open managed issues than the limit, fingerprints outside the recent window are not deduplicated or closed in that run. Later runs — or a temporarily raised cap — handle large cleanup runs.
If one configured output channel cannot publish, AICR logs the channel failure
and continues trying the remaining routed channels. A run where every dispatch
attempt fails is reported as skipped with
skipReason: output_dispatch_failed (instead of
review_orchestration_failed), so the review result and failure cause stay
visible without poisoning the trigger queue.
Non-PR target links
Section titled “Non-PR target links”Built-in templates render target.markdownLink / target.displayText instead
of assuming every review is a PR. Gitea, Forgejo, GitHub, and GitLab commit
links are derived from trigger base_url, repo, and revision. P4/SVN/internal
systems provide explicit URL templates via the trigger’s change_url_template
or revision_url_template (variables are URL-encoded before substitution):
triggers: - name: p4-main kind: p4 change_url_template: "https://swarm.example.com/changes/{{revision}}" - name: svn-main kind: svn revision_url_template: "https://svn.example.com/viewvc/project?view=revision&revision={{revision}}"Where to go next
Section titled “Where to go next”- The full per-channel field contract, including the MCP tool contract that agents use to fetch more context, is in Output channels.
- For trigger-side URL templates and file filters, see VCS providers.