> For the complete documentation index, see [llms.txt](https://docs-lunar.earthly.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-lunar.earthly.dev/docs/pr-comments.md).

# PR/MR Comments Reference

Reference for the /lunar commands Lunar accepts as comments on pull requests and merge requests, and what each one does to the merge gate.

Lunar watches the comments of GitHub pull requests and GitLab merge requests for commands addressed to it. They operate the merge gate's break-glass from the thread: one command overrides a block, the other takes the override back.

Two rules hold for every command:

* **The command must start the comment.** A mention mid-sentence ("we could `/lunar bypass` this") is conversation, and Lunar ignores it.
* **Lunar answers a command it recognizes.** An honored one is confirmed, and a refused one is answered with the reason rather than ignored. GitLab replies inside the command's discussion; GitHub posts a new comment on the Conversation tab, since a reply is audit evidence and is never edited afterwards.

A command on a request Lunar does not govern gets no reply at all: an untracked repository, or a request whose target branch matches no component. This is deliberate, because one repository can carry webhooks for several Hubs, but from the thread it looks the same as a dropped command. [When a command fails](#when-a-command-fails) covers the other reason a thread stays silent.

## Availability

* **GitHub**: any pull request where the [`Earthly Lunar` check run](/install/git-platforms/github.md#blocking-merges) reports. Whether that check blocks the merge is your branch-protection setting; the commands behave the same either way. Write the command as a plain comment in the **Conversation** tab, since comments inside a review, on a diff line or in the review summary, do not reach Lunar.
* **GitLab**: merge requests on any project Lunar tracks, on every tier. The commands operate whichever [merge gate](/install/git-platforms/gitlab.md#merge-gate) the project has, the external status check on Ultimate and the `Earthly Lunar` commit status on Free and Premium. As on GitHub, whether that signal blocks the merge is your setting (**Pipelines must succeed**, in the commit-status case), and the commands behave the same either way.

The grammar is identical on both platforms, so the phrase an engineer types does not depend on where the repository lives. Only the authorizing role differs, and each command below spells it out.

## `/lunar bypass`

* Form:

  ```
  /lunar bypass: <reason>
  ```

Overrides the merge gate for the request's **current head commit**. Lunar flips its signal to passing (the check run on GitHub, and on GitLab the external status check or, where the tier has none, the commit status), records the override on the audit ledger, and replies confirming who bypassed, which commit it covers, and why. To customize that reply, set [`customization.bypass_template`](/configuration/lunar-config/customization.md#bypass_template).

Lunar also refreshes the results comment, so it stops listing the bypassed checks as failing and credits the override instead. The refresh re-posts the results already stored for the commit rather than re-running the policies, so it needs neither a push nor a fresh evaluation. A commit Lunar has never evaluated has nothing stored to re-post and gets a full evaluation, which is slower.

### `<reason>`

* Required

Why the gate is being overridden, recorded verbatim on the ledger. It may span multiple lines. A comment without one (`/lunar bypass` alone, or `/lunar bypass:` with nothing after it) is refused with usage guidance.

### Authorization

The comment is held to the same permission as the CLI commands, [`bypasses.manage`](/docs/authorization.md#bypasses-manage), checked against the commenter's role on the request's repository.

| Platform | Required role by default                |
| -------- | --------------------------------------- |
| GitHub   | `maintain` or `admin` on the repository |
| GitLab   | Maintainer or above on the project      |

Setting `bypasses.manage` under [`authorization`](/configuration/lunar-config.md#authorization) in `lunar-config.yml` moves this bar for comments and CLI alike: raise it to `admin` / Owner so only administrators can override a gate, or lower it to `write` / Developer so any committer can. The refusal reply names the role the Hub applied.

These are the platforms' own roles. Lunar checks them with the platform when the comment arrives and has no role system of its own, so you grant them as usual: collaborator and team settings on a GitHub repository, project or inherited group membership on GitLab. GitHub computes the role across repository, team, organization, and enterprise grants; a custom role qualifies when its base permissions reach the required role, and is recorded under its own name. On older GitHub Enterprise Server versions that do not report a role name, `maintain` and plain `write` arrive as the same value and are read as `write`, so at the default bar only `admin` qualifies there.

The [configuration repository administrator](/docs/authorization.md#config-repo-administrators) rule does not reach the thread: a comment is authorized on the request's own repository only.

The role that authorized the bypass is recorded with it, provider-qualified: `github:admin`, `gitlab:maintainer`, and so on.

The request's own author may bypass: a self-bypass is allowed, and recorded as such.

### Scope

A bypass covers **one commit**: pushing again re-blocks the request and needs a fresh bypass. Unlike a CLI bypass it carries no expiry; for a time-bound override, use [`lunar policy bypass-pr`](/docs/lunar-cli.md#lunar-policy-bypass-pr) from the CLI, which clears the same gate. The state of the check does not matter: a check stuck pending, one that reads an error, and one that never appeared are all concluded passing the same way a failing one is.

A bypass is for one commit or one window. If a policy should not apply to a component at all, narrow the policy's [`on`](/configuration/lunar-config/on.md) expression in `lunar-config.yml` instead, for example `on: "domain:engineering AND NOT component:github.com/foo/bar"`.

### Audit trail

Every bypass lands on the same ledger the [CLI bypass commands](/docs/lunar-cli.md#bypassing-a-block) write: who, their **verified** role, the reason, the commit, and whether it was a self-bypass. A comment-driven override therefore shows up in `lunar policy bypass-ls`, can be ended early with [`/lunar bypass rm`](#lunar-bypass-rm) or [`lunar policy bypass-rm`](/docs/lunar-cli.md#lunar-policy-bypass-rm), records [what it actually masked](/sql-api/views/bypassed-checks.md) when the pull or merge request merges, and is queryable over the [SQL API](/sql-api/views/bypasses.md) alongside every other override.

## `/lunar bypass rm`

* Form:

  ```
  /lunar bypass rm
  /lunar bypass rm <reason>
  /lunar bypass rm: <reason>
  ```

Withdraws the overrides granted by `/lunar bypass` comments on the same request, without leaving the thread. Lunar re-arms the gate for the current commit, confirms with a reply, and refreshes the results the same way a grant does. If the request has no comment-driven bypass to withdraw, Lunar says so instead. To customize the reply, set [`customization.bypass_revocation_template`](/configuration/lunar-config/customization.md#bypass_revocation_template).

### `<reason>`

* Optional

Why the override is being taken back. It appears in the confirmation reply; the ledger keeps the reason the bypass was granted with either way.

### Authorization

Revoking is held to the same bar as granting ([`bypasses.manage`](#authorization): `maintain` or `admin` on GitHub and Maintainer or above on GitLab by default), so nobody below that bar can re-block a merge someone else authorized.

### What it withdraws

Only the overrides made by `/lunar bypass` comments on this pull or merge request. Anything else is left alone:

* A [`lunar policy bypass-pr`](/docs/lunar-cli.md#lunar-policy-bypass-pr) made from the CLI records an intent formed outside the thread, usually with an expiry. Withdraw it with [`lunar policy bypass-rm`](/docs/lunar-cli.md#lunar-policy-bypass-rm) where it was made.
* Comment bypasses on other requests, and component-wide bypasses, are untouched.

### The gate afterwards

{% hint style="info" %}
**The check reports pending, not failed.** Lunar cannot recompute the verdict at the moment you revoke, so it reports that it has no current verdict, which blocks the merge: the check run goes back to in progress on GitHub, the external status check goes to pending on GitLab Ultimate, and the commit status returns to running on the tiers below it. Revoking also refreshes the results, and that post settles the check, without a push.
{% endhint %}

### Soft revoke

Revocation is the same soft revoke the CLI performs: the ledger row survives with the revoker and timestamp attached, and still appears in `lunar policy bypass-ls` without `--active`. A second `rm` on the same request finds nothing left to withdraw, and Lunar replies saying so.

## When a command fails

Either command can fail before Lunar acts on it, most often because the Git platform is rate limiting Lunar and will not serve the pull or merge request. Lunar answers in the thread saying what went wrong: a GitHub rate limit names how long its window has left to run, and a GitLab one asks you to try again in a few minutes. Nothing was recorded and the gate is untouched, so comment the command again to retry.

The comment's webhook delivery can also be redelivered from the platform, which re-runs the command: **Settings → Webhooks → Recent Deliveries** on GitHub, where it shows as failed, or **Settings → Webhooks → Recent events** on GitLab.

An exhausted rate limit is the one failure that cannot announce itself, since posting a reply spends the same budget the command just failed on. If a command gets no reply at all, check `lunar policy bypass-ls` to see whether the override was recorded before commenting it again.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs-lunar.earthly.dev/docs/pr-comments.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
