Support Linear agent sessions as a first-class mention surface - #119
Closed
vincelwt wants to merge 3 commits into
Closed
Support Linear agent sessions as a first-class mention surface#119vincelwt wants to merge 3 commits into
vincelwt wants to merge 3 commits into
Conversation
Linear creates an agent session when a workspace member @mentions or delegates an issue to an installed app. Hub could not receive one: the Linear provider only understood issue and comment webhooks, and its authorization asked for neither of the scopes that make an app mentionable. Accept `AgentSessionEvent` deliveries on the existing signed webhook and route them to a new `linear.agent_session` trigger. A session is addressed to this app by name and delivered to no other app, so the mention itself is the authorization and the trigger is exempt from the actor allowlist that externally sourced events otherwise require; project, label, and actor filters still narrow scope when a workspace routes different work to different repositories. The mention text becomes the prompt, so declared inputs are parsed straight from it and an existing named-agent `select` expression can choose which agent runs: `@Paseo agent=fast summarize this` runs the `fast` choice. Hub narrates the run back into the session as Linear activities: a thought on pickup, which is what keeps Linear from marking the session unresponsive within its ten second window, an external link back to the run, the agent's own reply as the session response, and an error activity carrying the failure reason. Activity failures are reported but never fail the run. `agentActivityCreate` is rejected under the narrow `comments:create` grant, so `write` joins `app:mentionable` and `app:assignable` in the requested scopes. They are requested but not required: a workspace connected before agent sessions keeps its issue and comment triggers and only misses mentions until it reconnects. Linear answers a malformed GraphQL document with a bare 400, so the response body is now included in the thrown error. Without it every schema mismatch is indistinguishable in the logs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A reply in an existing Linear session is a prompted event. Hub was starting a fresh agent for each one, so the thread in Linear looked connected while the coding agent did not. Prompted follow-ups now look up the live execution for that session and send the new request as a prompt on the same daemon agent. finish_execution ends the turn but keeps the session open until idle timeout. If no live agent remains, Hub still starts a new one.
Pi has no session modes. Hub still required mode on new triggers, so linear-mention had to send mode: default, and the daemon rejected spawn with "Invalid mode 'default' for provider 'pi'". Authoring now lets mode be omitted; the daemon remains the source of truth for providers that do require one.
Author
|
Closing: this is private Hub work, not for upstream. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Linear opens an agent session when a workspace member
@mentionsor delegates an issue to an installed app. Hub could not receive one: the Linear provider only understood issue and comment webhooks, and its authorization requested neither scope that makes an app mentionable. The practical result was that "mentioning" Paseo meant text-matching@paseoin a comment body, with no session UI, no progress, and a reply that arrived as a loose comment.This makes Paseo a real Linear agent.
AgentSessionEventdeliveries are accepted on the existing signed webhook (payload.agentSession,createdandprompted) and routed to a newlinear.agent_sessiontrigger.selectexpression picks the agent:@Paseo agent=fast summarize thisruns thefastchoice.thoughton pickup, an external link to the run, the agent's ownreplyas the sessionresponse, and anerroractivity carrying the failure reason.${{ paseo.context }}uses Linear's renderedpromptContext, so session runs no longer backfill comment history through the API.Notable decisions
No actor allowlist for sessions.
validateTriggerLaunchSecurityrequires a non-emptyfilters.from_usersfor externally sourced events. A session is exempt: Linear creates one only when a member addresses this app by name, delivers it to no other app, and the install already scoped which teams can see it. Requiring an allowlist would make the documented mention flow impossible to configure. Project, label, state, and actor filters all still apply when set.Scopes are requested, not required.
agentActivityCreateis rejected withInvalid scope: `write` requiredunder the narrowcomments:creategrant, sowritejoinsapp:mentionableandapp:assignable. Adding them toLINEAR_REQUIRED_SCOPESwould flip every existing connection torequiresReauthorizationand silently drop its issue and comment events, so they live in a separateLINEAR_AGENT_SCOPESset instead. Existing workspaces keep working and only miss mentions until they reconnect.One response per session. Linear ends a session when it sees a
response. The agent's ownreplyis the good one, so a small in-process tracker records that it arrived and the terminal hook only fills a gap rather than talking over it. In-memory is deliberate: a restart mid-run costs at most one duplicate closing line.Activity failures never fail a run. Every emission is wrapped and reported; a session that cannot be narrated still runs to completion.
Linear answers a malformed GraphQL document with a bare
400, so the response body is now included in the thrown error. Without it every schema mismatch looked identical in the logs, which is how thewritescope requirement above was found.Verification
Unit tests cover normalization of both actions, webhook routing and signature rejection, filter behaviour including connection scoping, prompt and input parsing, context materialization without API reads, activity emission and its tolerance of Linear failures, and the session-aware reply path.
Also exercised end to end against a real Linear workspace on a self-hosted Hub:
@Paseoappears in Linear's mention menu and opens a session.erroractivity with the reason.@Paseo agent=fast Reply with only your model nameansweredclaude-haiku-4-5while the trigger default isclaude-opus-5, confirming per-mention agent selection.Not included
Follow-up
promptedevents currently start a fresh execution rather than continuing the live agent, because the Hub to daemon protocol has no prompt message (HubExecutionControlActionSchemaisinterruptandarchiveonly). Conversational sessions and mappingpermission_requestedto anelicitationboth depend on that addition and are better as a separate change spanning both repositories.🤖 Generated with Claude Code