> ## Documentation Index
> Fetch the complete documentation index at: https://zeropath.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Bot Commands

> Drive ZeroPath from your pull request — triage findings, assign tickets, generate patches, and rescan, all by mentioning the bot in a comment

## How It Works

Mention the ZeroPath bot in a pull request or merge request comment to send it a command. The bot parses the comment, posts an acknowledgment, executes the action, then **updates the same comment in-place** with the result. This keeps your PR conversation clean — there is one bot reply per command, not a chain.

<Steps>
  <Step title="Mention the bot">
    Start your comment with `@ZeroPath` or `@zeropath-ai` (public aliases), or
    `@<your-bot-username>` (the exact username configured for your GitHub App or
    GitLab integration). Environment-specific bot usernames only match that
    exact integration.
  </Step>

  <Step title="Type a command">
    Use one of the structured commands below, or ask a natural-language question. Targets like `issue 2` are matched against the issues ZeroPath has reported on this PR.
  </Step>

  <Step title="Read the reply">
    The bot posts a "Thinking..." or "Acknowledged" comment immediately, then edits that comment in-place once the action completes. Long-running actions like `retriage` stream a structured summary back when finished.
  </Step>
</Steps>

<Info>
  Bot commands are supported on **GitHub** and **GitLab**. **Bitbucket** and
  **Azure DevOps** support PR scanning but not bot commands yet.
</Info>

<Note>
  Bare `@ZeroPath` with no command makes the bot reply with a hint: `I'm here.
      Try: @ZeroPath fp issue 2 because …`
</Note>

## Command Reference

Most categories accept the same **target syntax** (see [Targets](#targets)) and many accept an optional **`because <reason>`** suffix (see [The `because` Modifier](#the-because-modifier) for which commands persist the reason).

### Triage Status

Mark a finding's correctness verdict. These commands change the issue's triage state and trigger a `vulnerability status changed` notification through your configured channels.

| Command                              | Aliases                                               | What It Does                                                                 |
| ------------------------------------ | ----------------------------------------------------- | ---------------------------------------------------------------------------- |
| `@ZeroPath fp <target>`              | `false-positive`, `falsepositive`                     | Mark issue(s) as **false positive**                                          |
| `@ZeroPath true-positive <target>`   | `true positive`                                       | Mark issue(s) as **true positive** (confirmed real)                          |
| `@ZeroPath accepted-risk <target>`   | `acceptedrisk`, `accept-risk`, `acceptrisk`           | Mark issue(s) as **accepted risk** — real, but the team chooses to accept it |
| `@ZeroPath non-exploitable <target>` | `nonexploitable`, `not-exploitable`, `notexploitable` | Mark issue(s) as **non-exploitable** in this codebase's context              |

### Workflow Status

Move a finding through your team's review workflow. These do not change the correctness verdict — use Triage Status for that.

| Command                                    | Aliases                                | Resulting Status   |
| ------------------------------------------ | -------------------------------------- | ------------------ |
| `@ZeroPath in-progress <target>`           | `inprogress`, `status reviewing`       | **Reviewing**      |
| `@ZeroPath patching <target>`              | `patch`, `status patching`             | **Patching**       |
| `@ZeroPath closed <target>`                | `close`, `resolved`, `status resolved` | **Resolved**       |
| `@ZeroPath backlog <target>`               | `defer`, `deferred`, `status backlog`  | **Backlog**        |
| `@ZeroPath status pending_review <target>` | —                                      | **Pending Review** |

### Assignment

Assign the linked Jira or Linear ticket for a finding to a teammate. Requires that the finding has an associated Jira/Linear issue (see [Jira](/integrations/jira) or [Linear](/integrations/linear)).

| Command                                  | What It Does                                                    |
| ---------------------------------------- | --------------------------------------------------------------- |
| `@ZeroPath assign <target> to <email>`   | Assigns the linked ticket to the user with that email           |
| `@ZeroPath assign <target> to @<handle>` | Assigns the linked ticket to the user with that platform handle |

If a target has no linked Jira/Linear ticket, the bot reports `assignment isn't possible (no linked Jira/Linear ticket)` for that issue and continues with the rest.

### Auto-Fix Patches

Trigger ZeroPath's patch generation pipeline for a specific finding. See [Auto-Fix](/scanning/auto-fix) for the full feature.

| Command                             | Aliases                            | What It Does                                 |
| ----------------------------------- | ---------------------------------- | -------------------------------------------- |
| `@ZeroPath generate patch <target>` | `create patch`                     | Generate a fix branch for the target finding |
| `@ZeroPath approve patch <target>`  | `open pr`, `create pr`, `issue pr` | Open the patch as a pull request for review  |

### GitHub Patch PR Changes

On GitHub, when ZeroPath opens an auto-fix patch PR, reviewers can request
follow-up code changes directly from the PR conversation. Start a new PR comment
with `@ZeroPath` or `@zeropath-ai`, then describe the change you want.

```text PR comment theme={null}
@zeropath-ai Please add a regression test for empty usernames
@zeropath-ai Please rename the new helper to `sanitizeDisplayName`
@zeropath-ai Please remove the temporary debug log added by this patch
```

For these requests, ZeroPath:

1. Checks that the PR is a GitHub patch PR created by ZeroPath.
2. Verifies that the current PR head branch is the same patch branch ZeroPath
   created.
3. Applies only the requested change.
4. Commits the change to the existing PR branch.
5. Replies with a summary and commit reference.

<Info>
  Direct patch PR branch changes are currently GitHub-only. GitLab bot commands
  still support triage, assignment, patch generation, rescans, retriage, and
  natural-language questions, but not direct follow-up commits to an existing
  patch PR branch.
</Info>

<Warning>
  ZeroPath refuses to push when the PR branch cannot be verified as a
  ZeroPath-created patch branch, the branch has moved while the bot was working,
  the PR comes from a fork, or the request is unsafe, ambiguous, impossible, or
  would make unrelated changes.
</Warning>

### Scan Operations

| Command                  | Aliases                              | What It Does                                                                               |
| ------------------------ | ------------------------------------ | ------------------------------------------------------------------------------------------ |
| `@ZeroPath rescan`       | `re-scan`, `rescan pr`, `scan again` | Re-run the PR scan. If a scan for the current commit already exists, it is skipped.        |
| `@ZeroPath rescan force` | `force rescan`, `force re-scan`      | Force a rescan even if a scan for the current commit exists, bypassing the duplicate check |

When the bot can't run a rescan, it explains why with one of: `A scan for the current commit already exists. Use \`rescan force\` to bypass the cache.`, `Cannot rescan a closed pull request.\`, or a service-specific reason.

### Re-Triage (Deeper Investigation)

Re-run AI validation on findings using a more thorough investigation than the default PR scan. When the PR description references vulnerabilities by `ZP-ID` tag or dashboard URL (see [Fix Verification](/scanning/fix-verification)), `retriage` re-runs **fix verification** instead.

| Command                                         | Aliases                                        | What It Does                                                                     |
| ----------------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------- |
| `@ZeroPath retriage`                            | `re-triage`, `reinvestigate`, `re-investigate` | Re-investigate **all** issues in this PR                                         |
| `@ZeroPath retriage <target>`                   | (same aliases)                                 | Re-investigate a specific issue or list                                          |
| `@ZeroPath retriage <target> because <context>` | (same aliases)                                 | Same, but pass `<context>` to the AI as additional information for re-evaluation |

The retriage reply, posted in-place over the acknowledgment comment, lists each issue with a verdict (**Confirmed** or **Disconfirmed**), a security assessment, and a link to the issue in the ZeroPath dashboard.

### Natural-Language Questions

Anything that doesn't match a structured command or a GitHub patch PR change
request is treated as a question to the bot. **On GitHub**, the bot replies with
an AI-generated answer in the same comment thread, posting a `Thinking...`
placeholder and editing it in-place with the full answer once ready.

```text PR comment theme={null}
@ZeroPath Is this finding exploitable given our input validation?
@ZeroPath Can you explain what this vulnerability means for our auth flow?
@ZeroPath What's the risk of merging with these open issues?
```

<Note>
  Question-shaped messages (those classified as questions by the LLM) get a
  free-form AI answer on **both** GitHub and GitLab. The platforms diverge only
  when the classifier can't recognize the message at all: **GitLab** returns a
  static reply listing the supported command examples (`I couldn't understand
      that command. Examples: ...`), where **GitHub** falls back to a free-form
  Assistant answer. If you're on GitLab and the bot replies with the static
  command list, rephrase as a clear question or use one of the structured
  commands above.
</Note>

<Warning>
  Comments that look like prompt-injection attempts are blocked automatically.
  If you receive a rejection message, rephrase the question as a direct inquiry
  about a specific reported finding.
</Warning>

## Targets

A **target** specifies which issue(s) the command applies to. The parser accepts:

| Form                    | Example                                  | Resolves To                                                  |
| ----------------------- | ---------------------------------------- | ------------------------------------------------------------ |
| Single issue number     | `issue 2`                                | Issue #2 reported on this PR                                 |
| Multiple issue numbers  | `issues 1, 2, 3`                         | Issues #1, #2, #3                                            |
| All issues in this PR   | `all issues in this pr`                  | Every issue ZeroPath has reported on this PR                 |
| Dashboard URL           | `https://zeropath.com/app/issues/<uuid>` | The issue at that URL                                        |
| Bare issue UUID         | `f47ac10b-58cc-4372-a567-0e02b2c3d479`   | The issue with that UUID                                     |
| Implicit (inline reply) | *no target given*                        | The issue tied to the inline review thread you replied under |

The implicit form is the easiest path: open an inline finding comment, reply to it with `@ZeroPath fp because not reachable from input`, and the bot applies the command to that finding without you having to name an issue number.

A bare `retriage` with no target defaults to **all issues in this PR**.

<Warning>
  Use commas, not the word `and`, to separate multiple issue numbers. The parser
  only recognizes comma-separated lists — `issues 1 and 4` silently targets
  issue #1 only, dropping `and 4`. Always write `issues 1, 4`.
</Warning>

## The `because` Modifier

Every triage, workflow-status, and retriage command accepts an optional `because <reason>` suffix. The text after `because` is captured by the parser as the user's reason for the action.

```text PR comment theme={null}
@ZeroPath fp issue 2 because the user input here is already validated upstream
@ZeroPath accepted-risk issues 1, 4 because we'll address these in Q3
@ZeroPath retriage issue 3 because we added a content-type check on the endpoint
```

How the reason is used depends on the command:

| Command                                                                                           | What happens to `because <reason>`                                                                                                                                          |
| ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fp`, `true-positive`, `accepted-risk`, `non-exploitable`                                         | Persisted on the issue and included in the `vulnerability status changed` notification                                                                                      |
| Workflow status (`in-progress`, `patching`, `closed`, `backlog`, `status …`)                      | Persisted on the issue and included in the `vulnerability status changed` notification                                                                                      |
| `retriage`                                                                                        | Passed to the AI investigation as additional context                                                                                                                        |
| `assign`                                                                                          | Parsed but **not currently persisted** — included for command-syntax consistency only. Use a Jira/Linear comment if you need an audit trail of why a ticket was reassigned. |
| `rescan`, `generate patch`, `approve patch`, natural-language ask, GitHub patch PR change request | Not accepted (no `because` clause is parsed)                                                                                                                                |

## Worked Examples

<CodeGroup>
  ```text Triage one finding theme={null}
  @ZeroPath fp issue 2 because input is sanitized in middleware.ts
  ```

  ```text Bulk-resolve all issues theme={null}
  @ZeroPath resolved all issues in this pr because addressed in commit abc123
  ```

  ```text Assign to a teammate via Linear theme={null}
  @ZeroPath assign issue 3 to @alice
  ```

  ```text Generate then open a patch PR theme={null}
  @ZeroPath generate patch issue 2
  @ZeroPath approve patch issue 2
  ```

  ```text Request a follow-up change on a GitHub patch PR theme={null}
  @zeropath-ai Please add a regression test for empty usernames
  ```

  ```text Rescan after a config change theme={null}
  @ZeroPath rescan force
  ```

  ```text Retriage everything with extra context theme={null}
  @ZeroPath retriage because we updated the auth library to 4.2.0
  ```

  ```text Reply implicitly under an inline comment theme={null}
  @ZeroPath non-exploitable because this code path is dev-only
  ```
</CodeGroup>

## Permissions

When access control is enabled for your organization, the bot verifies that the GitHub or GitLab user who posted the comment is linked to a ZeroPath identity, and that the linked user has the right repository permission for the action. Permissions below use the **exact display names from the Teams settings page**, so an admin can find each one as a checkbox in the team-permissions UI.

| Command                                                                      | Required Permission        |
| ---------------------------------------------------------------------------- | -------------------------- |
| `fp` (false positive)                                                        | **Mark as False Positive** |
| `true-positive`, `non-exploitable`                                           | **Mark as True Positive**  |
| `accepted-risk`                                                              | **Archive Issues**         |
| Workflow status (`in-progress`, `patching`, `closed`, `backlog`, `status …`) | **Mark Issues as Open**    |
| `assign`                                                                     | **Mark Issues as Open**    |
| `rescan`, `rescan force`                                                     | **Mark Issues as Open**    |
| `retriage`                                                                   | **Mark Issues as Open**    |
| Natural-language ask                                                         | **Mark Issues as Open**    |
| `generate patch`                                                             | **Generate Patches**       |
| `approve patch`                                                              | **Create Pull Requests**   |
| GitHub patch PR change request                                               | **Create Pull Requests**   |

<Note>
  These are distinct permissions. A user with **Mark as False Positive** but not
  **Archive Issues** can run `fp` but will be denied on `accepted-risk`, even
  though both are "triage" actions in casual usage. Likewise, `non-exploitable`
  is gated by **Mark as True Positive**, not False Positive — both commands
  assert a vulnerability classification, so they share the True Positive
  permission.
</Note>

If a user lacks the required permission, the bot replies with
`Permission denied (missing <PERMISSION_CONSTANT>).` For example,
`ISSUE_EDIT_OPEN` maps to **Mark Issues as Open**, `PATCH_CREATE` maps to
**Generate Patches**, and `PATCH_ISSUE` maps to **Create Pull Requests**.

If the comment author has no linked ZeroPath identity on GitHub, the bot replies:

> I can't verify your ZeroPath identity for this organization. Your GitHub account isn't linked to a ZeroPath user yet.
>
> To link it, set your GitHub public email (Settings > Public profile) to match your ZeroPath account email, then comment again. The link is saved on our side, so you can switch the email back to private afterward. This should fix the issue most of the time.

On GitLab the bot replies:

> I can't verify your ZeroPath identity for this organization (no linked ZeroPath user). Please contact your org admin to link your account.

See [Teams & Permissions](/platform/teams) for how to link VCS users and configure RBAC.

## Platform Support

| Platform                               | Bot Commands                          |
| -------------------------------------- | ------------------------------------- |
| **GitHub** (Cloud & Enterprise Server) | Yes — full support                    |
| **GitLab** (Cloud & Self-hosted)       | Yes — full support                    |
| **Bitbucket** (Cloud & Data Center)    | PR scanning yes, bot commands not yet |
| **Azure DevOps**                       | PR scanning yes, bot commands not yet |

## Troubleshooting

**The bot replies "I couldn't understand that command."**
The parser fell through to neither an explicit keyword nor a question. Use one of the [worked examples](#worked-examples) as a template, or paste a dashboard URL as the target.

**The bot replies "No matching issues found for that target."**
The issue number you used doesn't correspond to a finding ZeroPath has reported on this PR. Check the PR summary comment for the list of reported issues, or use `all issues in this pr`.

**The bot replies "I can't verify your ZeroPath identity..."**
Your VCS account isn't linked to a ZeroPath user. On GitHub, the fastest fix is to set your GitHub public email (Settings > Public profile) to match your ZeroPath account email, then re-comment — ZeroPath will auto-link the accounts via email correlation. You can switch the email back to private afterward; the link persists. On GitLab the email-correlation fallback isn't implemented yet, so contact your org admin to link accounts under Teams, or run the action from the ZeroPath dashboard.

**`assign` reports "no linked Jira/Linear ticket"**
The target finding has not been pushed to Jira or Linear yet. Configure the [Jira](/integrations/jira) or [Linear](/integrations/linear) integration with auto-ticketing, or create the ticket from the dashboard first.

**The bot rejected my comment as prompt-injection content**
Rephrase as a direct question about a specific reported finding, without instructions framed as bot commands embedded inside it.

**The bot refused to modify a GitHub patch PR**
The bot only commits directly to PR branches that ZeroPath created for patch
PRs. It refuses when it cannot verify the branch, the PR comes from a fork, the
branch moved while the request was being prepared, or the requested change is
unsafe, ambiguous, impossible, unrelated to the patch, or produces no file
changes.

<Info>
  See [PR Scanning](/scanning/pr-scanning) for the surrounding feature (check
  statuses, inline comments, summary comments) and
  [Auto-Fix](/scanning/auto-fix) for what `generate patch` and `approve patch`
  actually produce.
</Info>
