qwen-code/docs/users/features/channels/gitlab.md
qqqys 3edecac116
feat(channels): support group pairing (#8440)
* feat(channels): support group pairing

* fix(channels): address group pairing review

* fix(web-shell): show group pairing management

* fix(channels): recheck group pairing before history backfill

* test(channels): verify group approval isolation

* fix(channels): address group pairing review findings and pin behaviors (#8440)

- Grandfather the group allowlist file in PairingStore legacy migration
- Offer the pairing groupPolicy option in github/gitlab descriptors
- Re-export DaemonChannelPairingSubject from the webui barrels
- Refresh the GroupGate doc comment and channel docs rows
- Pin the unpinned group pairing behaviors called out in review:
  subject dedup, trigger matrix, notification content/cap/failure/
  thread routing, DM negative space under groupPolicy pairing,
  stored DM loop authz, pairing-enabled guard negative space,
  approval/revocation HTTP bodies, descriptor-driven gate branch,
  and the web-shell group approval mirrors
- Add a compile-time assertion for the revocation request union

* fix(channels): address group pairing review findings (#8440)

- Accept 'pairing' in the GitLab connect warning, descriptor help text,
  and gitlab.md: todos dispatch after one-time group approval.
- Model group approvals in the web-shell e2e mock daemon (approve by
  subject type, GET returns senderIds+groupIds, DELETE accepts groupId)
  and exercise the group pairing flow in the channels spec.
- Add 'pairing' to the groupPolicy enumerations in the plugins and
  per-channel docs (telegram, feishu, dingtalk, qqbot, wecom).
- Update the channel pairing CLI help to cover group requests.
- Cap pending pairing requests at one per sender so a single member
  cannot occupy every shared pending slot.

* fix(channels): address group pairing review findings round 7 (#8440)

* fix(channels): address group pairing review findings round 8 (#8440)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(channels): address group pairing review findings round 9 (#8440)

---------

Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-08-07 09:20:18 +00:00

10 KiB

GitLab

This guide covers setting up a Qwen Code channel that monitors GitLab todos and responds to mentions on issues and merge requests.

Prerequisites

  • A GitLab account (or a dedicated bot account)
  • A GitLab Personal Access Token with read_api and api scopes

Creating a Token

  1. Go to Preferences → Access Tokens
  2. Create a token with these scopes:
    • read_api — read todos and project data
    • api — post notes (comments) on issues/MRs
  3. Save the token securely as an environment variable

Configuration

Add the channel to ~/.qwen/settings.json:

{
  "channels": {
    "my-gitlab": {
      "type": "gitlab",
      "token": "$GITLAB_TOKEN",
      "pollInterval": 60000,
      "senderPolicy": "open",
      "sessionScope": "chat_thread",
      "cwd": "/path/to/your/project",
      "groupPolicy": "open",
      "action_prompt_template": {
        "mentioned": "Project: %project% | URL: %project_url% | Author: %author% | Type: %target_type% | IID: %iid% | Title: %title% | Description: %description% | TodoID: %todo_id%"
      }
    }
  }
}

Set the token as an environment variable:

export GITLAB_TOKEN="glpat-your_token_here"

Self-hosted GitLab

For self-hosted instances, set baseUrl:

{
  "baseUrl": "https://gitlab.example.com"
}

Configuration Options

Option Default Description
token (required) PAT with read_api + api scopes
pollInterval 60000 Poll interval in ms
baseUrl https://gitlab.com GitLab instance URL
action_prompt_template (required for processing) Maps GitLab action names to metadata templates
groupPolicy "disabled" Must be "open", "allowlist" with the project listed, or "pairing" with the project approved
senderPolicy "allowlist" Who can trigger the bot

action_prompt_template

This field controls which todo actions are processed and how metadata is rendered. Only actions with a configured template are dispatched; all others are skipped and marked done.

{
  "action_prompt_template": {
    "mentioned": "Project: %project% | Author: %author% | Title: %title%"
  }
}

The directly_addressed action (comment starting with @bot) automatically falls back to the mentioned template if not explicitly configured.

Available Action Keys

Key Trigger
mentioned Someone @mentions the bot in a comment or description (not at the start)
directly_addressed A comment starts with @bot (falls back to mentioned template)
assigned Someone assigns the bot to an issue/MR
review_requested Someone requests the bot as a reviewer on an MR
approval_required An MR requires the bot's approval (approval rules)
marked Someone marks the bot's comment/issue/MR (star)
build_failed A CI/CD pipeline fails on the bot's branch/MR
unmergeable An MR the bot is involved with becomes unmergeable (conflicts)
merge_train_removed An MR is removed from the merge train

Only keys present in action_prompt_template are processed. Unconfigured actions are skipped and marked done silently.

Template Variables

Variable Value
%project% Project path (e.g., owner/repo)
%project_url% Full project URL
%author% Todo author username
%target_type% Issue or MergeRequest
%iid% Issue/MR internal ID
%title% Issue/MR title
%description% Issue/MR description body
%todo_id% GitLab todo ID
%% Literal % (escape)

Unknown variables are preserved as-is in the output.

Prompt Assembly

The template renders into envelope.metadata (structured context). The triggering text (todo.body or description) goes into envelope.text (primary prompt). The base class assembles the final prompt sent to the agent:

[alice] please fix this bug

Project: owner/repo | URL: https://gitlab.com/owner/repo | Author: alice | Type: Issue | IID: 42 | Title: Test Issue | Description: ... | TodoID: 100
  • Line 1: [sender] prefix + envelope.text (with @bot stripped)
  • Line 3: envelope.metadata (rendered template, sanitized)

You do not need a %body% variable — the comment/description text is always the primary prompt content, and the template provides supplementary context below it.

⚠️ Security

On a public project, setting senderPolicy: "open" allows any GitLab user who @mentions the bot to submit prompts that drive the agent in your cwd.

Always use senderPolicy: "allowlist" with explicit allowedUsers on public projects.

Note that under groupPolicy: "pairing", access is granted per project: once a project is approved, any GitLab user can drive the bot through that project's issues and merge requests. All GitLab traffic is group traffic, so senderPolicy and allowedUsers do not gate members of an approved project. Approvals are keyed by the project path (owner/repo), which changes on rename or transfer — revoke stale group approvals after any project rename, transfer, or deletion.

Mention Detection

The adapter always sets isMentioned = true on dispatched envelopes, because GitLab has already determined the mention when creating the todo. The action_prompt_template config is the real event filter — only actions with a configured template are processed. The @bot mention is stripped from the message text before dispatch via stripBotMention.

⚠️ groupPolicy Must Be "open", "allowlist", or "pairing"

groupPolicy must be set to "open", "allowlist" with the project explicitly listed, or "pairing" for todos to be processed. Under "pairing", the first mention from an unapproved project creates a group pairing request; approve it once with qwen channel pairing approve, and todos from that project are dispatched from then on. The default value "disabled" drops all mentions: todos are marked done and the cursor advances, but no dispatch occurs. A rejection is logged (preflight rejected reason=group_disabled) but the todo is still consumed. If your bot is not responding to mentions, check that groupPolicy is not "disabled".

How It Works

The adapter uses GitLab's Todos API as the message source:

  1. Poll GET /todos?state=pending for new todos
  2. First-poll drain: if the cursor has never been initialized (initialized: false), all pending todos are marked done without dispatch and the cursor advances to the max todo ID. This prevents a backlog flood on first start.
  3. Clean up stale todos: todos with id <= cursor are marked done (best-effort) to prevent them from being re-fetched on every poll
  4. Filter by id > cursor and configured action_prompt_template
  5. Detect mention type via target_url anchor:
    • #note_123 present → comment mention → text is todo.body (the comment)
    • No anchor → description mention → text is the issue/MR description
  6. Dispatch the envelope through handleInbound (requires groupPolicy: "open", "allowlist" with the project listed, or "pairing" with the project approved)
  7. Advance cursor and mark todo done (best-effort)

The cursor (lastProcessedId) advances regardless of dispatch success or failure. Failed dispatches post a ⚠️ error comment on the issue/MR and are not retried — the user can re-mention the bot to trigger a new todo.

Response Feedback

For an accepted comment mention (note with #note_ anchor), the channel adds a 👀 award emoji to the note while the agent is working, then removes it when the run completes, fails, or is cancelled. Both operations are best-effort: an award emoji API or permission failure is logged and never prevents the final response.

Description mentions (no #note_ anchor) do not receive an award emoji because there is no specific note to react to.

Known Limitations

  • First start skips existing pending todos. The cursor initializes to { lastProcessedId: 0, initialized: false } on first launch. On the first poll cycle, all pre-existing pending todos are marked done without dispatch (the initialized flag gates this one-time drain), preventing a backlog flood.
  • The bot does not read prior conversation history — only the triggering content is processed.
  • Confidential (internal) notes: If someone @mentions the bot in a confidential note, the todo body contains that internal text and the agent will process it. The bot's reply is always posted as a public note, potentially exposing internal discussion. GitLab's todo API does not expose note visibility, so the adapter cannot filter this. Avoid @mentioning the bot in confidential notes.
  • Requires read_api + api PAT scopes. Group-level or project-level tokens work if they have these scopes.
  • Todos for Epics, Designs, and Alerts are skipped (only Issues and MRs are processed).

Starting the Channel

qwen channel start my-gitlab