You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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)
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.
Addressing ("tagging") — a grammar to name an agent from the comment text
and a resolver from that name → an Agent CR / route.
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.
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)
parseGithubEvent(apps/integration-gateway/src/webhooks/github.ts) returnsan actionable event only for
issues.labeledandpull_request.labeled.issues.opened,issue_comment.created, andeverything else map straight to
{ kind: "ignored" }before any identityresolution 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."
dispatch goes through the
IntegrationRouteCRD (ADR 0024), whosespec.matchkeys on{ source, event, action, labelName }only(
apps/agent-orchestrator/src/routing/crd-integration-route-registry.ts).There is no
mention/commandselector, and no mapping from an@handlein free text to an
AgentCR. Intent from free text otherwise falls back toRAG skill retrieval — which infers a skill, it does not let a user pick an
agent.
bot" idea was already rejected during rollout for that reason (ADR 0024) — a
label replaced assignment. Plain
@mentionof an App account has the sameclass of limitation, so "tag an agent" needs a real design, not just enabling
a webhook.
continue a triage conversation today is the server-rendered session page
(
POST /sessions/:token/prompts), precisely "since unlabeledissue_commentevents are a no-op." Comment-triggering would close that gapand make follow-ups feel like normal GitHub chat.
What needs to change (building blocks)
issue_comment.created(and probablypull_request_review_comment.created) inparseGithubEvent/handleGithubWebhook, emitting a new normalized event carrying the commentbody + id.
and a resolver from that name → an
AgentCR / route.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>(orverbs like
/triage,/review). Addevent: "issue_comment"(optionally anexplicit
command) toIntegrationRoute.spec.match, so a command maps to atarget exactly the way
labelNamedoes today. The comment body after thecommand becomes the
promptTemplateinput (renderPromptTemplatealreadysupports
{{body}},{{senderLogin}}, …; add{{commentBody}})./help), reuses the existingCRD dispatch and specificity rules, matches ADR 0024's "unambiguous discrete
action, not free text" philosophy. Trivial to parse → few false triggers.
@mention; users must learn the commands.Option B —
@mentionhandle →AgentresolverGive each
AgentCR a mention handle (e.g. annotationcontroller-agent.dev/mentionor reusemetadata.name). A comment containing aknown handle (
@triage-agent …) resolves directly to thatAgentRef,bypassing label matching; the rest of the comment is the request.
handles; composes with Option A (A = the command transport, B = the resolver).
error-prone; must avoid triggering on incidental mentions.
Option C — Dedicated bot
@mention+ reaction-based statusMake the GitHub App mentionable and treat any comment that
@-mentions the botas 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'sfinally.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 sameAgent— with C's reaction-based ack as the status UX. Reuse the existingper-issue session id (
github:<owner>/<repo>#<number>) so comment threadsnaturally become multi-turn sessions.
Cross-cutting concerns (must be handled by any option)
senderIsBotdrop so the agent can'ttrigger on its own reply comments; additionally require the explicit
command/mention prefix so ordinary human chatter never triggers.
identityResolver.resolve(senderLogin, senderIsBot, …)exactly as the labelpaths do; no new authz surface.
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).
short.
Acceptance criteria
/agent <name> <request>(and/or@<name> <request>) on anissue or PR triggers the named agent, running as the commenter.
no-op.
docs/integrations-gateway.mdupdated to describe the comment trigger.