Skip to content

feat(linear): connect & manage Linear from iOS via worker-bounce OAuth#860

Merged
arul28 merged 2 commits into
mainfrom
ade/claude-auth-login-b8a15488
Jul 18, 2026
Merged

feat(linear): connect & manage Linear from iOS via worker-bounce OAuth#860
arul28 merged 2 commits into
mainfrom
ade/claude-auth-login-b8a15488

Conversation

@arul28

@arul28 arul28 commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Adds a settings gear to the mobile Linear pane so users can connect, reconnect, and disconnect their Linear workspace — mirroring desktop's Settings › Integrations, which the phone could previously only view.

How it works (worker-bounce OAuth)

The phone can't run desktop's loopback OAuth (no local browser+listener). Instead:

  1. Phone → desktop cto.startLinearMobileOAuth — desktop mints PKCE verifier+state, returns an authorize URL whose redirect_uri is the ade-github-webhook-relay Worker /linear/oauth/callback.
  2. Phone opens it in ASWebAuthenticationSession; Linear redirects to the Worker, which 302-bounces to ade://linear-oauth (captured in-session).
  3. Phone → desktop cto.completeLinearMobileOAuth {sessionId, code, state} — desktop validates state, exchanges the code with its held verifier, stores the token.

The token never leaves the desktop. The phone only relays a PKCE-bound authorization code, useless without the desktop's verifier. API-key entry (cto.setLinearToken) and disconnect (cto.clearLinearToken) round out parity.

Security / correctness (from /quality)

  • The four new sync commands are viewerAllowed: true — invocable by a paired, authenticated controller (the phone), same trust as lanes.create/lanes.delete. (An earlier draft had them viewerAllowed: false, which the sync host rejects for all paired devices → feature-dead; fixed + regression-tested.)
  • Advertised as optional mobile capabilities: older brains omit them, and iOS feature-detects via supportsRemoteAction and shows an "update your Mac" hint instead of failing.
  • Failed reconnect reports the actual status (prior token may still be valid), not a false disconnect.
  • Known, accepted limitation: a manually entered API key traverses the LAN sync channel (ws://; only the relay path is wss://) — same exposure as all existing sync traffic. The OAuth path is unaffected. Recommend a follow-up to gate API-key entry to encrypted transports or add app-layer encryption for secret-bearing commands.

Tests

ade-cli sync 145 (gate contract + reconnect-failure regression), desktop cto OAuth 51, worker route 4, iOS ADETests +2 (legacy-host gating). Docs updated (linear-integration, cto, sync-and-multi-device, ios-companion).

Deploy note

The Linear redirect URI is registered. The Worker route requires a wrangler deploy of apps/webhook-relay for the live OAuth callback (done as part of shipping).

🤖 Generated with Claude Code

Greptile Summary

This PR adds mobile Linear connection management through the iOS companion app. The main changes are:

  • Optional sync commands for starting and completing mobile Linear OAuth.
  • Mobile API-key setup and disconnect commands for Linear credentials.
  • Desktop-side PKCE session handling so the token exchange stays on the Mac.
  • A webhook relay callback route that bounces Linear OAuth redirects into ade://linear-oauth.
  • iOS UI for connect, reconnect, disconnect, and legacy-host capability gating.

Confidence Score: 5/5

Safe to merge with low risk.

The changed paths are well-scoped, keep the token exchange on desktop, validate OAuth state before exchange, and preserve backward compatibility through optional capability detection.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • General contract validation was performed by reviewing the vitest run outputs for the linear sync command.
  • The narrow command output confirms all relevant tests are passing, with Test Files 2 passed (2) and Tests 148 passed (148).
  • The verbose log confirms the command, working directory, timestamps, and an EXIT_CODE of 0, indicating clean completion.
  • No PR-stated sync contract or reconnect-failure regression was observed in the evaluation.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
apps/ade-cli/src/services/sync/syncRemoteCommandService.ts Adds mobile Linear OAuth, API-key, and disconnect remote commands with shared connection-status construction.
apps/desktop/src/main/services/cto/linearOAuthService.ts Adds expiring external PKCE sessions for mobile worker-bounce OAuth.
apps/desktop/src/shared/syncMobileCompatibility.ts Declares the new Linear mobile management actions as optional sync capabilities.
apps/ios/ADE/Services/SyncService.swift Adds iOS sync wrappers for Linear mobile OAuth, API-key storage, disconnect, and capability checks.
apps/ios/ADE/Views/Linear/LinearConnectionScreen.swift Introduces the mobile Linear connection-management UI and shared connect actions.
apps/ios/ADE/Views/Linear/LinearOAuthRunner.swift Implements the iOS side of worker-bounce OAuth through ASWebAuthenticationSession and desktop completion.
apps/webhook-relay/src/relay.ts Adds a stateless Linear OAuth callback route that redirects Linear responses into the ADE app scheme.
apps/webhook-relay/test/linearOAuthCallback.test.ts Covers success, error, URL encoding, and method handling for the Linear OAuth callback bounce route.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Phone as iOS Linear pane
participant Desktop as ADE desktop sync host
participant Linear as Linear OAuth
participant Worker as webhook relay Worker

Phone->>Desktop: cto.startLinearMobileOAuth
Desktop->>Desktop: create session, state, PKCE verifier
Desktop-->>Phone: sessionId, authorizeUrl(worker redirect_uri)
Phone->>Linear: ASWebAuthenticationSession authorizeUrl
Linear-->>Worker: "GET /linear/oauth/callback?code&state"
Worker-->>Phone: "302 ade://linear-oauth?code&state"
Phone->>Desktop: cto.completeLinearMobileOAuth(sessionId, code, state)
Desktop->>Desktop: validate state and lookup PKCE verifier
Desktop->>Linear: exchange code + verifier
Linear-->>Desktop: access/refresh token
Desktop->>Desktop: store token locally
Desktop-->>Phone: LinearConnectionStatus
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Phone as iOS Linear pane
participant Desktop as ADE desktop sync host
participant Linear as Linear OAuth
participant Worker as webhook relay Worker

Phone->>Desktop: cto.startLinearMobileOAuth
Desktop->>Desktop: create session, state, PKCE verifier
Desktop-->>Phone: sessionId, authorizeUrl(worker redirect_uri)
Phone->>Linear: ASWebAuthenticationSession authorizeUrl
Linear-->>Worker: "GET /linear/oauth/callback?code&state"
Worker-->>Phone: "302 ade://linear-oauth?code&state"
Phone->>Desktop: cto.completeLinearMobileOAuth(sessionId, code, state)
Desktop->>Desktop: validate state and lookup PKCE verifier
Desktop->>Linear: exchange code + verifier
Linear-->>Desktop: access/refresh token
Desktop->>Desktop: store token locally
Desktop-->>Phone: LinearConnectionStatus
Loading

Reviews (2): Last reviewed commit: "fix(linear): treat failed mobile reconne..." | Re-trigger Greptile

@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jul 18, 2026 6:01am

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@arul28, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0551a838-7275-415c-806a-6aced8aab4b5

📥 Commits

Reviewing files that changed from the base of the PR and between 493cde0 and 3647a28.

⛔ Files ignored due to path filters (6)
  • apps/ios/ADE.xcodeproj/project.pbxproj is excluded by !**/*.xcodeproj/project.pbxproj
  • docs/features/cto/README.md is excluded by !docs/**
  • docs/features/linear-integration/README.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/README.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/ios-companion.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/remote-commands.md is excluded by !docs/**
📒 Files selected for processing (19)
  • apps/ade-cli/src/bootstrap.ts
  • apps/ade-cli/src/services/sync/syncHostService.test.ts
  • apps/ade-cli/src/services/sync/syncRemoteCommandService.test.ts
  • apps/ade-cli/src/services/sync/syncRemoteCommandService.ts
  • apps/ade-cli/src/services/sync/syncService.ts
  • apps/desktop/src/main/services/cto/linearAuth.test.ts
  • apps/desktop/src/main/services/cto/linearOAuthService.ts
  • apps/desktop/src/renderer/components/settings/LinearSection.tsx
  • apps/desktop/src/shared/syncMobileCompatibility.ts
  • apps/desktop/src/shared/types/sync.ts
  • apps/ios/ADE/Models/RemoteModels.swift
  • apps/ios/ADE/Services/SyncService.swift
  • apps/ios/ADE/Views/Linear/LinearConnectionScreen.swift
  • apps/ios/ADE/Views/Linear/LinearIssueListScreen.swift
  • apps/ios/ADE/Views/Linear/LinearOAuthRunner.swift
  • apps/ios/ADE/Views/Linear/LinearPaneSheet.swift
  • apps/ios/ADETests/ADETests.swift
  • apps/webhook-relay/src/relay.ts
  • apps/webhook-relay/test/linearOAuthCallback.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/claude-auth-login-b8a15488

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@arul28 arul28 changed the title mobile-linear-connection-settings -> Primary feat(linear): connect & manage Linear from iOS via worker-bounce OAuth Jul 18, 2026
@arul28

arul28 commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a14f11fe5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/webhook-relay/src/relay.ts Outdated
Add a settings gear to the mobile Linear pane that lets users connect,
reconnect, and disconnect their Linear workspace — mirroring desktop's
Settings › Integrations, which the phone previously could only view.

Backend (sync): four new CTO sync commands — startLinearMobileOAuth,
completeLinearMobileOAuth, setLinearToken, clearLinearToken — advertised as
optional mobile capabilities (older brains omit them; iOS feature-detects and
degrades gracefully with an "update your Mac" hint). linearOAuthService gains an
external-redirect flow (startExternalSession/completeExternalSession) reusing the
existing PKCE + token-exchange path with no loopback server; the desktop loopback
flow is unchanged. The authorization code is exchanged and the token stored
desktop-side — it never leaves the machine.

OAuth transport: Linear redirects to the ade-github-webhook-relay Worker
(/linear/oauth/callback), which 302-bounces to ade://linear-oauth for
ASWebAuthenticationSession to capture. The code is PKCE-bound to a verifier that
stays on the desktop.

iOS: gear → LinearConnectionScreen (status + org logo, reconnect, machine-wide
disconnect confirm); inline-actionable disconnected pane (Sign in with Linear +
API-key fallback); all affordances gated on supportsRemoteAction. Desktop
LinearSection now renders the workspace logo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arul28

arul28 commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@arul28
arul28 force-pushed the ade/claude-auth-login-b8a15488 branch from 1a14f11 to fe3ad3c Compare July 18, 2026 05:48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe3ad3ca12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/ios/ADE/Views/Linear/LinearOAuthRunner.swift
…ker bounce

Address @codex review:
- P2: a failed OAuth completion can return connected:true with a failure
  message (desktop preserves the prior token rather than wiping the UI). The
  iOS runner treated connected as success and showed a false "Connected"
  confirmation. Now any non-empty status.message on completion is surfaced as
  a failure; a genuine success carries no message.
- P3: the Worker bounced spaces as "+" (URLSearchParams), which iOS
  URLComponents leaves intact ("User+declined"). Emit %20 so Linear's
  user-facing error text stays readable. + worker regression test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arul28

arul28 commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

@codex review — addressed both findings in 3647a28: reconnect-failure now surfaces as a failure (no false success), and the Worker %20-encodes spaces so error text stays readable (regression test added).

@arul28
arul28 merged commit 43a50a6 into main Jul 18, 2026
35 checks passed
@arul28
arul28 deleted the ade/claude-auth-login-b8a15488 branch July 18, 2026 06:05
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 3647a2823f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant