mr-milchick 2.0.4

CLI for merge request governance in GitLab CI pipelines
Documentation
# Message Templates

Mr Milchick now supports connector-specific message templates in `mr-milchick.toml`.

Templates only affect connector output in this version:

- GitLab summary comments
- Slack app root and thread messages
- Slack workflow title and thread payloads

CLI output, rule findings, and policy behavior are unchanged.

## How Templates Work

- Every connector has built-in default templates compiled into the binary.
- You can override any template field in `mr-milchick.toml`.
- Overrides are field-by-field. If you only set one field, the others keep their defaults.
- Templates use `{{placeholder}}` interpolation only.
- Unknown or malformed placeholders cause a warning and that one field falls back to the built-in default.

## Template Layout

```toml
[templates.gitlab]
summary = """..."""

[templates.slack_app]
first_root = """..."""
first_thread = """..."""
update_root = """..."""
update_thread = """..."""

[templates.slack_workflow]
first_title = """..."""
first_thread = """..."""
update_title = """..."""
update_thread = """..."""
```

## Available Placeholders

These placeholders are available in all connector templates:

- `mr_number`
- `mr_ref`
- `mr_title`
- `mr_url`
- `mr_author_username`
- `source_branch`
- `target_branch`
- `is_draft`
- `changed_file_count`
- `findings_count`
- `blocking_findings_count`
- `warning_findings_count`
- `info_findings_count`
- `actions_count`
- `reviewers_count`
- `new_reviewers_count`
- `existing_reviewers_count`
- `mr_link`
- `reviewers_list`
- `new_reviewers_list`
- `existing_reviewers_list`
- `findings_block`
- `actions_block`
- `tone_message`
- `tone_category`

Additional shared placeholders currently exposed by the renderer:

- `summary_title`
- `summary_intro`
- `summary_footer`
- `notification_title`
- `notification_subject`
- `reviewers_line`
- `mr_ref_link`

GitLab summary templates also support:

- `closing_tone_message`
- `closing_tone_category`

## Placeholder Semantics

Some placeholders are rendered differently per connector on purpose.

- `mr_link` is already formatted for the target connector.
  GitLab example: `[Frontend adjustments](https://gitlab.example.com/...)`
  Slack app example: `<https://gitlab.example.com/...|Frontend adjustments>`
  Slack workflow example: `Frontend adjustments (https://gitlab.example.com/...)`
- `reviewers_list`, `new_reviewers_list`, and `existing_reviewers_list` are already formatted for the connector.
- `findings_block` is preformatted multi-line content for the connector.
- `actions_block` is preformatted multi-line content for the connector.
- Empty optional values resolve to `""`.
- When there are no findings, `findings_block` resolves to `No findings were produced.`
- When there are no visible actions, `actions_block` resolves to `None`

## Tone Behavior

Tone is still deterministic and selected from the tone registry.

- GitLab summary `tone_*` uses `Observation`
- GitLab summary `closing_tone_*` uses the same footer logic as before:
  - `Blocking`
  - `NoAction`
  - `Praise`
  - `Refinement`
- Slack app and Slack workflow `tone_*` use `ReviewRequest` when reviewers are being assigned, otherwise `Observation`

That means you can either render the selected line directly with `{{tone_message}}` or refer to its category with `{{tone_category}}`.

## Default Shape By Connector

The built-in defaults preserve the existing message behavior.

### GitLab Summary

The default GitLab template renders:

- a summary heading
- the opening tone line
- the findings block
- the actions block
- the closing tone footer

Example override:

```toml
[templates.gitlab]
summary = """
## {{summary_title}}

{{tone_message}}

MR: {{mr_link}}
Branches: `{{source_branch}}` -> `{{target_branch}}`
Changed files: {{changed_file_count}}

{{findings_block}}

{{actions_block}}

_{{closing_tone_message}}_
"""
```

Example output:

```md
## Mr. Milchick Review Summary

Mr. Milchick is reviewing the situation.

MR: [Frontend adjustments](https://gitlab.example.com/group/project/-/merge_requests/3995)
Branches: `feat/buttons` -> `develop`
Changed files: 3

- **Warning**: Missing label.

- Assigned reviewers: @principal-reviewer, @bob

_A refinement opportunity has been identified._
```

### Slack App

Slack app now uses four template fields:

- `first_root`
- `first_thread`
- `update_root`
- `update_thread`

`first_*` is intended for the lighter initial notification. `update_*` is intended for the fuller follow-up/update notification.

Example override:

```toml
[templates.slack_app]
first_root = "{{notification_subject}}"
first_thread = """
*{{notification_title}}*
Merge request: {{mr_link}}
{{reviewers_line}}
"""
update_root = "{{notification_subject}}"
update_thread = """
Merge request: {{mr_link}}
{{findings_block}}
{{actions_block}}
_{{summary_footer}}_
"""
```

Example output:

```text
Mr. Milchick took a first look at <https://gitlab.example.com/group/project/-/merge_requests/3995|MR #3995>, by @arthur
```

```text
*The department would appreciate a timely review.*
Merge request: <https://gitlab.example.com/group/project/-/merge_requests/3995|Frontend adjustments>
_Assigned reviewers_ *@principal-reviewer* *@bob*
```

Notes:

- Slack user mention rewriting still happens after template rendering.
- If your template includes `@principal-reviewer`, the Slack app sink can still rewrite it to `<@U...>` through `MR_MILCHICK_SLACK_USER_MAP`.

### Slack Workflow

Slack workflow also uses four fields:

- `first_title`
- `first_thread`
- `update_title`
- `update_thread`

`first_*` is intended for the lighter initial notification. `update_*` is intended for the fuller follow-up/update notification.

Example override:

```toml
[templates.slack_workflow]
first_title = "{{notification_subject}}"
first_thread = """
{{notification_title}}
Merge request: {{mr_link}}
{{reviewers_line}}
"""
update_title = "{{notification_subject}}"
update_thread = """
Merge request: {{mr_link}}
{{findings_block}}
{{actions_block}}
{{summary_footer}}
"""
```

Example output:

```text
Mr. Milchick took a first look at MR #3995 (https://gitlab.example.com/group/project/-/merge_requests/3995), by @arthur
```

```text
A pleasant review opportunity has arrived for your consideration.
Merge request: Frontend adjustments (https://gitlab.example.com/group/project/-/merge_requests/3995)
Assigned reviewers @principal-reviewer @bob
```

## Practical Starting Templates

### Minimal GitLab Customization

```toml
[templates.gitlab]
summary = """
## Review Summary

Merge request: {{mr_link}}

{{findings_block}}

{{actions_block}}
"""
```

### Minimal Slack App Customization

```toml
[templates.slack_app]
first_root = "{{mr_ref_link}} needs attention"
```

### Minimal Slack Workflow Customization

```toml
[templates.slack_workflow]
update_thread = """
Merge request: {{mr_link}}
{{reviewers_line}}
{{findings_block}}
{{actions_block}}
"""
```

## Authoring Tips

- Start with one connector field at a time.
- Prefer the preformatted placeholders like `mr_link`, `reviewers_list`, `findings_block`, and `actions_block` unless you want a very custom layout.
- For GitLab, use Markdown intentionally because the body is posted directly as markdown after the marker is prepended.
- For Slack app, you can use Slack formatting such as `*bold*`, `_italic_`, and `<url|label>`.
- For Slack workflow, prefer plain text because workflow payloads are usually rendered by a downstream workflow step.
- If a template seems ignored, check logs for a warning about an invalid placeholder and confirm that field fell back to the default.