Skip to content

Trigger agents via issue/PR comments — no way to "tag" an agent today #159

Description

@k5s-bot

Summary

We want to trigger agents by commenting on a GitHub issue/PR — e.g. "tag" an
agent in a thread (@some-agent do X, or /agent <name> …) and have it run,
with follow-up comments continuing the same conversation. Today this does not
work: comments are a deliberate no-op, and there is no mechanism to
address ("tag") a specific agent
from the text of a comment. This ticket
captures why, and proposes solutions.

Current behavior (why it doesn't work today)

  • The GitHub adapter only acts on an explicit label application.
    parseGithubEvent (apps/integration-gateway/src/webhooks/github.ts) returns
    an actionable event only for issues.labeled and
    pull_request.labeled. issues.opened, issue_comment.created, and
    everything else map straight to { kind: "ignored" } before any identity
    resolution or orchestrator call. This is intentional and documented
    (docs/integrations-gateway.md §"Implementation status"): "Opening an issue,
    or commenting on one, never causes the agent to run."
  • There is no way to address a specific agent from a comment. Deterministic
    dispatch goes through the IntegrationRoute CRD (ADR 0024), whose
    spec.match keys on { source, event, action, labelName } only
    (apps/agent-orchestrator/src/routing/crd-integration-route-registry.ts).
    There is no mention / command selector, and no mapping from an @handle
    in free text to an Agent CR. Intent from free text otherwise falls back to
    RAG skill retrieval — which infers a skill, it does not let a user pick an
    agent.
  • GitHub-App accounts generally can't be assignees, and the "just assign the
    bot" idea was already rejected during rollout for that reason (ADR 0024) — a
    label replaced assignment. Plain @mention of an App account has the same
    class of limitation, so "tag an agent" needs a real design, not just enabling
    a webhook.
  • The gap is already acknowledged. Per issue Issues Triage Agent Improvements #81 / ADR 0025, the only way to
    continue a triage conversation today is the server-rendered session page
    (POST /sessions/:token/prompts), precisely "since unlabeled
    issue_comment events are a no-op." Comment-triggering would close that gap
    and make follow-ups feel like normal GitHub chat.

What needs to change (building blocks)

  1. Transport — subscribe to and parse issue_comment.created (and probably
    pull_request_review_comment.created) in parseGithubEvent /
    handleGithubWebhook, emitting a new normalized event carrying the comment
    body + id.
  2. Addressing ("tagging") — a grammar to name an agent from the comment text
    and a resolver from that name → an Agent CR / route.
  3. Cross-cutting safety (see bottom) — loop prevention, identity gating,
    re-trigger idempotency, and an ack/status UX that isn't noisy.

Proposed solutions

All assume building block #1. They differ mainly in how you address an agent
(#2)
.

Option A — Slash-command grammar → IntegrationRoute (recommended)

A constrained command posted as a comment, e.g. /agent <name> <request> (or
verbs like /triage, /review). Add event: "issue_comment" (optionally an
explicit command) to IntegrationRoute.spec.match, so a command maps to a
target exactly the way labelName does today. The comment body after the
command becomes the promptTemplate input (renderPromptTemplate already
supports {{body}}, {{senderLogin}}, …; add {{commentBody}}).

  • Pros: Deterministic and self-documenting (/help), reuses the existing
    CRD dispatch and specificity rules, matches ADR 0024's "unambiguous discrete
    action, not free text" philosophy. Trivial to parse → few false triggers.
  • Cons: Less "natural" than an @mention; users must learn the commands.

Option B — @mention handle → Agent resolver

Give each Agent CR a mention handle (e.g. annotation
controller-agent.dev/mention or reuse metadata.name). A comment containing a
known handle (@triage-agent …) resolves directly to that AgentRef,
bypassing label matching; the rest of the comment is the request.

  • Pros: Closest to the literal "tag an agent" ask; discoverable catalog of
    handles; composes with Option A (A = the command transport, B = the resolver).
  • Cons: Needs a handle registry + collision rules; freeform parsing is more
    error-prone; must avoid triggering on incidental mentions.

Option C — Dedicated bot @mention + reaction-based status

Make the GitHub App mentionable and treat any comment that @-mentions the bot
as a trigger, routed by RAG (existing behavior) or by a handle after the
mention. Acknowledge with a reaction (👀 → 🚀 → ✅) instead of a "starting
work" comment, and use "reaction cleared on completion" as the re-trigger
gesture — the comment analogue of today's trigger-label removal in
relayAndReply's finally.

  • Pros: Most natural UX; reactions are low-noise and give a clean
    idempotency/ack story. Cons: App-mention semantics/limitations; RAG
    routing doesn't let a user pick a specific agent without B.

Option D (fallback) — Session-page-only, no comment trigger

Keep comments a no-op; invest instead in making the existing session page the
canonical follow-up channel. Pros: zero new webhook surface/loop risk.
Cons: does not satisfy the actual request ("trigger via comments"); listed
only as the do-nothing baseline.

Recommendation: ship A as the foundation (deterministic, reuses the CRD)
and layer B on top so /agent <name> and @<name> both resolve to the same
Agent — with C's reaction-based ack as the status UX. Reuse the existing
per-issue session id (github:<owner>/<repo>#<number>) so comment threads
naturally become multi-turn sessions.

Cross-cutting concerns (must be handled by any option)

  • Loop prevention: keep the existing senderIsBot drop so the agent can't
    trigger on its own reply comments; additionally require the explicit
    command/mention prefix so ordinary human chatter never triggers.
  • Identity/authorization: run as the commenter — reuse
    identityResolver.resolve(senderLogin, senderIsBot, …) exactly as the label
    paths do; no new authz surface.
  • Idempotency / re-trigger: unlike a label there's nothing to remove after a
    run. Use the comment id as a dedupe key so a redelivered webhook doesn't
    double-run; "post another command" is the natural re-trigger gesture (Option C
    gives an ack analogue via reactions).
  • Fast ack: keep the 202-then-work pattern; GitHub's webhook timeout is
    short.

Acceptance criteria

  • Commenting /agent <name> <request> (and/or @<name> <request>) on an
    issue or PR triggers the named agent, running as the commenter.
  • Bot-authored comments never self-trigger; non-command comments are a
    no-op.
  • Follow-up comments continue the same session as the issue/PR.
  • Redelivered/duplicate webhooks don't double-run (comment-id dedupe).
  • docs/integrations-gateway.md updated to describe the comment trigger.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions