Revert "feat(agentex): Linear gateway — invoke agents from Linear" - #400
Merged
Conversation
…)" This reverts commit 4718eee.
✱ Stainless preview buildsThis PR will update the openapi python typescript
|
michael-chou359
added a commit
that referenced
this pull request
Aug 10, 2026
…401) Re-lands the Linear gateway from #399, which was merged (`4718eee`) then reverted by #400 (`bcf5a79`). ## Why it was reverted — and why that wasn't a code problem #399's revert was triggered by the **"Stainless build"** check, which failed in its *merge* step with: > `404 One or both branches not found: main, preview/mc/linear-gateway` — "This is a bug. Please report it at https://github.com/stainless-api/upload-openapi-spec-action/issues" That's a **Stainless SDK-generation / CI-infra failure** (the action couldn't find a preview branch and flags it as its own bug), not a defect in the gateway. **All 42 code checks on `4718eee` passed** — the full unit + sync/async integration matrix. So no code change was needed to re-land; this is the same commit (including the Greptile review fixes). If the Stainless build fails again the same way, it's an infra issue to re-run / raise with the Stainless integration owners, not a blocker on this code. ## What it is (unchanged from #399) Platform-side ingress fronting a Linear agent app; `POST /linear/events` verifies `Linear-Signature` + `webhookTimestamp`, dedups on `Linear-Delivery`, normalizes `AgentSessionEvent` (created/prompted), runs the Slack-gateway selector-cascade dispatch (`task_metadata.channel="linear"`), and replies via `agentActivityCreate` (thought → terminal response/error) using a `client_credentials` app-actor token (re-minted on 401). Runs as a dedicated bot service account. Includes the #399 review fixes: fail-closed on empty signing secret, and no response-body in logs on token failure. ## Testing 21 unit tests pass, ruff clean. Signed ingress + client_credentials token mint validated against live Linear earlier. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> The PR adds a signed Linear webhook gateway that deduplicates deliveries, dispatches Linear agent-session turns through AgentEx, and returns activities using an app-actor OAuth token. - Registers and documents `POST /linear/events`. - Adds signature freshness checks, delivery deduplication, target selection, bot identity propagation, task dispatch, reply polling, and Linear activity delivery. - Adds unit coverage for authentication, normalization, dispatch, identity handling, and token refresh. <details><summary><h3>Confidence Score: 4/5</h3></summary> The follow-up selector handling should be fixed before merging because it can silently alter user prompts in existing Linear sessions. Prompted events pass through the same selector-resolution path as initial events, so a leading word matching an agent or configuration is removed despite the session contract requiring follow-up content to remain intact. **Files Needing Attention:** agentex/src/domain/use_cases/linear_gateway_use_case.py </details> <details><summary><h3>Important Files Changed</h3></summary> | Filename | Overview | |----------|----------| | agentex/src/domain/use_cases/linear_gateway_use_case.py | Implements the complete Linear ingress and dispatch lifecycle, but applies first-turn selector stripping to prompted follow-ups. | | agentex/src/api/routes/linear.py | Adds the Linear webhook route and preserves the raw request body required for HMAC verification. | | agentex/src/api/middleware_utils.py | Whitelists Linear ingress so the gateway's webhook-signature authentication can run. | | agentex/src/api/app.py | Registers the new Linear router while removing a duplicate Slack router registration. | | agentex/openapi.yaml | Documents the new Linear webhook endpoint and its successful response. | | agentex/tests/unit/use_cases/test_linear_gateway_use_case.py | Covers core gateway behavior but does not exercise selector-like first words in prompted follow-ups. | </details> <details><summary><h3>Sequence Diagram</h3></summary> ```mermaid sequenceDiagram participant L as Linear participant API as POST /linear/events participant G as LinearGatewayUseCase participant R as Redis participant ACP as AgentEx ACP participant LA as Linear API L->>API: Signed AgentSessionEvent API->>G: Raw body, headers, payload G->>G: Verify signature and timestamp G->>R: SET delivery ID NX with TTL G-->>L: "200 {ok: true}" G->>LA: Emit thought activity G->>ACP: Resolve target and create/resume task ACP-->>G: Agent reply G->>LA: Emit terminal response or error ``` </details> <a href="https://app.greptile.com/api/ide/cursor?prompt=%23%23%23%20Issue%201%0Aagentex%2Fsrc%2Fdomain%2Fuse_cases%2Flinear_gateway_use_case.py%3A329%0A**Follow-up%20selector%20strips%20content**%0A%0AWhen%20a%20prompted%20follow-up%20starts%20with%20a%20registered%20agent%20or%20configuration%20name%2C%20%60_resolve_target%60%20treats%20that%20word%20as%20a%20selector%20and%20removes%20it%20before%20dispatching%20to%20the%20existing%20session%20task%2C%20causing%20the%20agent%20to%20receive%20a%20truncated%20user%20instruction%20even%20though%20selectors%20are%20intended%20to%20apply%20only%20on%20the%20first%20turn.%0A%0A---%0A%0AFor%20each%20issue%20above%2C%20determine%20whether%20it%20is%20valid%20and%20should%20be%20fixed.%20If%20so%2C%20fix%20it%20directly.&pr=401&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCursorDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCursor.svg?v=6"><img alt="Fix All in Cursor" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCursor.svg?v=6"></picture></a> <a href="https://app.greptile.com/ide/claude-code?prompt=%23%23%23%20Issue%201%0Aagentex%2Fsrc%2Fdomain%2Fuse_cases%2Flinear_gateway_use_case.py%3A329%0A**Follow-up%20selector%20strips%20content**%0A%0AWhen%20a%20prompted%20follow-up%20starts%20with%20a%20registered%20agent%20or%20configuration%20name%2C%20%60_resolve_target%60%20treats%20that%20word%20as%20a%20selector%20and%20removes%20it%20before%20dispatching%20to%20the%20existing%20session%20task%2C%20causing%20the%20agent%20to%20receive%20a%20truncated%20user%20instruction%20even%20though%20selectors%20are%20intended%20to%20apply%20only%20on%20the%20first%20turn.%0A%0A---%0A%0AFor%20each%20issue%20above%2C%20determine%20whether%20it%20is%20valid%20and%20should%20be%20fixed.%20If%20so%2C%20fix%20it%20directly.&repo=scaleapi%2Fscale-agentex&pr=401&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaudeDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"><img alt="Fix All in Claude Code" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInClaude.svg?v=6"></picture></a> <a href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22scaleapi%2Fscale-agentex%22%20on%20the%20existing%20branch%20%22mc%2Flinear-gateway-reland%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22mc%2Flinear-gateway-reland%22.%0A%0A%23%23%23%20Issue%201%0Aagentex%2Fsrc%2Fdomain%2Fuse_cases%2Flinear_gateway_use_case.py%3A329%0A**Follow-up%20selector%20strips%20content**%0A%0AWhen%20a%20prompted%20follow-up%20starts%20with%20a%20registered%20agent%20or%20configuration%20name%2C%20%60_resolve_target%60%20treats%20that%20word%20as%20a%20selector%20and%20removes%20it%20before%20dispatching%20to%20the%20existing%20session%20task%2C%20causing%20the%20agent%20to%20receive%20a%20truncated%20user%20instruction%20even%20though%20selectors%20are%20intended%20to%20apply%20only%20on%20the%20first%20turn.%0A%0A---%0A%0AFor%20each%20issue%20above%2C%20determine%20whether%20it%20is%20valid%20and%20should%20be%20fixed.%20If%20so%2C%20fix%20it%20directly.&repo=scaleapi%2Fscale-agentex&pr=401&platform=github"><picture><source media="(prefers-color-scheme: dark)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source media="(prefers-color-scheme: light)" srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img alt="Fix All in Codex" src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a> <details><summary>Prompt To Fix All With AI</summary> `````markdown ### Issue 1 agentex/src/domain/use_cases/linear_gateway_use_case.py:329 **Follow-up selector strips content** When a prompted follow-up starts with a registered agent or configuration name, `_resolve_target` treats that word as a selector and removes it before dispatching to the existing session task, causing the agent to receive a truncated user instruction even though selectors are intended to apply only on the first turn. --- For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. ````` </details> <sub>Reviews (1): Last reviewed commit: ["feat(agentex): Linear gateway — invoke a..."](e0c6d4a) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=51876870)</sub> > Greptile also left **1 inline comment** on this PR. <!-- /greptile_comment --> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
Reverts #399
Greptile Summary
This PR reverts the Linear gateway by removing its webhook route, use case, tests, authentication exemption, and OpenAPI operation.
Confidence Score: 4/5
The PR appears safe to merge after the non-blocking duplicate Slack router registration is removed.
The Linear gateway is consistently removed across its route, implementation, tests, middleware exemption, and OpenAPI specification, but app initialization now registers both Slack endpoints twice.
Files Needing Attention: agentex/src/api/app.py
Important Files Changed
Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "Revert "feat(agentex): Linear gateway — ..." | Re-trigger Greptile