Skip to content

Chapter 11: IDE Integration & Multi-device Workflows ​

Learning Objectives ​

  • The full VS Code extension workflow: inline diffs, @-mentions, parallel conversations
  • Remote Control: start a task at your workstation, continue monitoring from your phone
  • Desktop App: set up automated daily PR review digests
  • Teleport: pull a cloud conversation into your local terminal
  • When to use each surface and how they complement each other

Appendix links: A15 Claude Code Internals explains the harness loop, session management, and compaction mechanics that power all five surfaces. See also A04 Agent Architecture for the ReAct pattern underlying tool-calling across surfaces.

The Claude Code Ecosystem ​

Claude Code is not just a terminal tool. It runs across five surfaces, and each has strengths that the others lack:

Surface           Strengths                      Best For
-----------       -------------------------      -------------------------
Terminal CLI      Full power, scriptable         Heavy development, CI/CD
VS Code           Inline diffs, file tree        Refactoring, code review
JetBrains         Language-aware refactoring     Java/Kotlin/Python projects
Desktop App       Visual review, scheduling      Monitoring, daily digests
Mobile (Remote)   Monitoring, approvals          On-the-go review

Session Mobility ​

Sessions are not locked to a single device. Three mechanisms move them:

MechanismDirectionHow
Remote ControlLocal terminal to mobile/web/remote-control in session, scan QR code
TeleportCloud (claude.ai) to local terminal/teleport pulls the session down
/desktopTerminal to Desktop appHands off for visual review

Demo 28: VS Code Refactoring Workflow ​

28
VS Code Refactoring Workflow
Intermediate~20 min

Scenario ​

You have a 2,000-line Express API where all route handlers are defined inline in server.ts. You need to extract them into separate controller files, add proper TypeScript types, and update all imports. This is exactly the kind of task where VS Code's inline diff view shines.

Step 1: Open the Project and Start Claude ​

Open your project in VS Code with the Claude Code extension installed. Open the Claude Code panel (Cmd+Shift+P, then "Claude Code: Open Panel" or click the Claude icon in the sidebar).

What you see when the panel opens:

terminal
╭─────────────────────────────────────────────────────╮
│  Claude Code (VS Code Extension)                     │
│  Model: claude-sonnet-4-6                            │
│  Project: my-express-api                             │
│  Files: 47 TypeScript files detected                 │
│                                                      │
│  Type a message or use @ to reference files...       │
╰─────────────────────────────────────────────────────╯

Step 2: Reference Files with @-mentions ​

In the Claude Code panel, type your prompt using @-mentions to give Claude precise context:

Look at @server.ts -- it has all route handlers inline. I need you to:

1. Create a controllers/ directory
2. Extract each route group into its own controller file:
   - controllers/users.controller.ts (all /api/users/* handlers)
   - controllers/orders.controller.ts (all /api/orders/* handlers)
   - controllers/products.controller.ts (all /api/products/* handlers)
3. Each controller should export typed handler functions using Express.RequestHandler
4. Update server.ts to import and use the new controllers
5. Make sure @tsconfig.json paths are compatible

Do NOT change any business logic. This is a pure structural refactor.

Step 3: Review with Inline Diffs ​

Claude will propose changes. In VS Code, you see them as inline diffs -- green for additions, red for deletions -- directly in the editor tabs. This is fundamentally different from reviewing changes in the terminal:

terminal
  EDITOR TAB: server.ts (modified)
  ─────────────────────────────────────
  Line 1     import express from 'express';
- Line 2     import { Pool } from 'pg';
- Line 3     import bcrypt from 'bcrypt';
+ Line 2     import { usersRouter } from './controllers/users.controller';
+ Line 3     import { ordersRouter } from './controllers/orders.controller';
+ Line 4     import { productsRouter } from './controllers/products.controller';
  ...
- Line 45    app.get('/api/users', async (req, res) => {
- Line 46      const users = await pool.query('SELECT * FROM users');
- Line 47      res.json(users.rows);
- Line 48    });
  ...
+ Line 12    app.use('/api/users', usersRouter);
+ Line 13    app.use('/api/orders', ordersRouter);
+ Line 14    app.use('/api/products', productsRouter);

  NEW FILE: controllers/users.controller.ts
  ─────────────────────────────────────
+ Line 1     import { Router, RequestHandler } from 'express';
+ Line 2     import { Pool } from 'pg';
+ Line 3
+ Line 4     const router = Router();
+ Line 5
+ Line 6     const getUsers: RequestHandler = async (req, res) => {
+ Line 7       const pool = req.app.locals.pool as Pool;
+ Line 8       const users = await pool.query('SELECT * FROM users');
+ Line 9       res.json(users.rows);
+ Line 10    };
  ...
  • You can see the full file context around each change
  • You can accept or reject individual hunks
  • The file tree shows which files were created or modified
  • TypeScript errors update in real time as changes are applied

Accept/reject workflow:

  • Click the checkmark to accept a change
  • Click the X to reject it
  • If you reject a hunk, tell Claude why in the chat: "The users controller is missing the auth middleware import"
terminal
  Claude Code Panel:
  ─────────────────────────────────────
  You rejected the change to controllers/users.controller.ts.
  Tell Claude why:

  > The users controller is missing the auth middleware import.
  > All /api/users/* routes need authMiddleware applied.

  Claude: Got it. I'll add the auth middleware import and apply it to
  all user routes. Let me update the controller...

  [Proposing changes to controllers/users.controller.ts]
  + Line 2     import { authMiddleware } from '../middleware/auth';
  + Line 7     router.use(authMiddleware);

Step 4: Run Parallel Conversations ​

While Claude is working on the controller extraction, open a second conversation panel (click the + icon) and ask it to work on something independent:

@package.json -- add @types/express if it's not already there, and update
the "scripts" section to include a "typecheck" script that runs tsc --noEmit

Both conversations run simultaneously. Each has its own context and does not interfere with the other.

What Just Happened? ​

1
Read
server.ts via @-mention
↓
2
Read
tsconfig.json via @-mention
↓
3
Write
controllers/users.controller.ts
↓
4
Write
controllers/orders.controller.ts
↓
5
Write
controllers/products.controller.ts
↓
6
Edit
server.ts

What Makes This Better Than Terminal ​

CapabilityTerminalVS Code
See full file context around changesNo, you see diffs onlyYes, inline in editor
Accept/reject individual hunks/accept or /reject the whole thingPer-hunk control
Real-time type checkingNeed to run tsc manuallyAutomatic
Multiple parallel conversationsNeed claude --session-id per terminalClick + to add
File tree awarenessYou describe paths in textClick @-mention

Demo 29: Remote Control -- Start at Work, Monitor From Your Phone ​

29
Remote Control -- Monitor From Your Phone
Intermediate~15 min

Scenario ​

It is 5:45 PM. You have a large migration task -- converting 80 React class components to functional components with hooks. You kick it off on your workstation before leaving, then monitor progress and approve decisions from your phone during the commute.

Step 1: Start the Task on Your Workstation ​

bash
claude --permission-mode acceptEdits

# In the session:
> I need to convert all React class components in src/components/ to functional
> components using hooks. There are about 80 files. Rules:
>
> 1. Convert componentDidMount to useEffect
> 2. Convert componentDidUpdate to useEffect with dependencies
> 3. Convert componentWillUnmount to useEffect cleanup
> 4. Convert this.state/this.setState to useState
> 5. Preserve all existing prop types
> 6. Run npm test after every 10 files and stop if tests fail
>
> Start with the smallest files first to build confidence.

What you see as Claude starts working:

terminal
> [Your prompt above]

I'll start converting the smallest components first. Let me find all
class components and sort them by file size.

[Auto-approved] Grep "extends React.Component" in src/components/**
  Found 82 class components

[Auto-approved] Read src/components/Spinner.tsx (12 lines)
[Auto-approved] Edit src/components/Spinner.tsx
  Converted: class Spinner -> function Spinner with useState

[Auto-approved] Read src/components/Badge.tsx (18 lines)
[Auto-approved] Edit src/components/Badge.tsx
  Converted: class Badge -> function Badge (stateless, simplified)

[Auto-approved] Read src/components/Toggle.tsx (24 lines)
[Auto-approved] Edit src/components/Toggle.tsx
  Converted: class Toggle -> function Toggle with useState

Progress: 3/82 components converted...

Step 2: Enable Remote Control ​

While Claude is working, type:

/remote-control

Claude displays a QR code and a URL:

terminal
> /remote-control

╭───────────────────────────────────────────────────────╮
│                                                       │
│   Remote Control Enabled                              │
│                                                       │
│   Scan the QR code or visit:                          │
│   https://claude.ai/remote/sess_abc123xyz             │
│                                                       │
│   [QR CODE DISPLAYED HERE]                            │
│                                                       │
│   This session will remain active on your machine.    │
│   You can monitor and send messages from any device.  │
│                                                       │
╰───────────────────────────────────────────────────────╯

Step 3: Open on Your Phone ​

Scan the QR code or type the URL on your phone. You now see:

  • Claude's real-time output as it converts files
  • Any permission prompts waiting for approval (in acceptEdits mode, these are only shell commands that are not in the allow list)
  • The ability to type messages to redirect Claude

Step 4: Monitor and Intervene ​

From your phone, you see Claude has converted 30 files and hit a test failure:

terminal
[Auto-approved] Edit src/components/UserProfile.tsx
  Converting class UserProfile to function...

[Auto-approved] Bash npm test

  FAIL  tests/components/UserProfile.test.tsx
  TypeError: Cannot read properties of undefined (reading 'context')

    at UserProfile (src/components/UserProfile.tsx:15:22)
    at renderWithProviders (tests/helpers.tsx:8:5)

  12 tests failed

Tests failed after converting UserProfile.tsx.
The error is: Cannot read properties of undefined (reading context)

This component uses legacy context API (this.context).
Should I:
1. Convert it to useContext() hook
2. Skip this file and continue with others
3. Convert it but add a TODO for manual review

You respond from your phone:

Option 1. Use useContext. If the context provider doesn't exist as a
separate component yet, create one.

Claude continues on your workstation:

terminal
Got it. I'll convert the legacy context usage to useContext.

[Auto-approved] Read src/components/UserProfile.tsx
[Auto-approved] Grep "createContext" in src/**
  Found ThemeContext in src/contexts/theme.ts but no UserContext

[Auto-approved] Write src/contexts/user-context.tsx
  Created UserContext with provider component

[Auto-approved] Edit src/components/UserProfile.tsx
  Replaced this.context with useContext(UserContext)

[Auto-approved] Bash npm test

  PASS  tests/components/UserProfile.test.tsx
  All 12 tests passed

Continuing with remaining components. Progress: 31/82...

Claude continues working. You close your phone and check back 20 minutes later to see the progress summary.

What Just Happened? ​

1
Grep
extends React.Component in src/components/**
↓
2
Read and Edit
smallest components first
↓
3
Bash
npm test (every 10 files)
↓
4
Remote Control
phone notification
↓
5
Write
src/contexts/user-context.tsx
↓
6
Bash
npm test (after fix)

What Is Actually Happening ​

Your workstation (still running)
  +-- Claude Code process
       |-- Local file access (reads/writes your actual files)
       |-- Local tool execution (npm test runs on your machine)
       +-- WebSocket connection to claude.ai

Your phone (browser)
  +-- claude.ai/remote/sess_abc123xyz
       |-- Streams Claude output via WebSocket
       |-- Sends your messages back to the local process
       +-- Renders permission prompts for approval

Key point: the files and tools never leave your workstation. Your phone is a remote display and input device, not a second execution environment.


Demo 30: Desktop App -- Automated Daily PR Review Digest ​

30
Desktop App -- Automated Daily PR Digest
Intermediate~15 min

Scenario ​

You are a tech lead. Every morning, you spend 30 minutes checking what PRs landed overnight, what is still open, and whether anything needs urgent attention. You want Claude to prepare a digest before you arrive.

Step 1: Create the Review Agent ​

In the Desktop App, create a new scheduled task with this configuration:

Schedule: Every weekday at 7:00 AM (cron: 0 7 * * 1-5)

Prompt:

Review all open pull requests in our repository. For each PR:

1. Read the PR description and all changed files
2. Categorize as: needs-review, changes-requested, approved-waiting-merge, or blocked
3. Flag any PRs that have been open more than 3 days without review
4. Flag any PRs with failing CI checks

Produce a digest in this format:

URGENT (needs action today):
- PR #123: "Add payment retry logic" - CI failing on integration tests since yesterday

NEEDS REVIEW (no reviewer assigned):
- PR #145: "Migrate user table to new schema" - opened 2 days ago by @alice

IN PROGRESS (has reviewer, waiting on changes):
- PR #130: "Update API rate limits" - @bob requested changes 1 day ago

READY TO MERGE (approved, CI passing):
- PR #128: "Fix timezone bug in reports" - approved by @carol, all checks pass

STATS:
- Total open PRs: 12
- Average age: 2.3 days
- Oldest: PR #110 (5 days, blocked on design review)

Step 2: Configure MCP for GitHub Access ​

The Desktop App needs access to your GitHub repository. Configure the GitHub MCP server:

json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-server-github"],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here"
      }
    }
  }
}

Step 3: What You See Each Morning ​

When you open the Desktop App at 8:30 AM, the digest is already waiting:

terminal
  Claude Desktop -- Scheduled Report (ran at 7:02 AM)
  ════════════════════════════════════════════════════

  URGENT (needs action today):
  - PR #201: "Hotfix: connection pool exhaustion" - @dave opened at 2AM,
    CI passing, no reviewer yet. Fixes the connection leak we saw in prod.
    3 files changed, looks correct. Recommend fast-track merge.

  NEEDS REVIEW:
  - PR #198: "Add WebSocket support for real-time notifications" - @eve
    opened 2 days ago, 47 files changed. Large PR, suggest splitting
    into transport layer + handler layer.

  IN PROGRESS:
  - PR #195: "Refactor auth middleware" - @frank requested changes from
    @grace 1 day ago. 2 comments unresolved.

  READY TO MERGE:
  - PR #192: "Fix timezone bug in weekly reports" - approved by @carol,
    all 3 CI checks pass. Last activity 6 hours ago.
  - PR #190: "Add retry logic to payment webhook" - approved by @dave,
    squash-ready.

  STATS:
  - Total open PRs: 11
  - Average age: 2.8 days
  - Oldest: PR #185 (6 days, blocked on design review from @henry)
  - PRs merged yesterday: 4

What Just Happened? ​

1
MCP (GitHub)
list open pull requests
↓
2
MCP (GitHub)
read PR diffs and comments
↓
3
MCP (GitHub)
check CI status
↓
4
Write
digest output

Step 4: Act on It ​

Click any PR reference to open it directly. The Desktop App can also let you respond:

Assign me as reviewer on PR #201 and approve it. For PR #198, leave a
comment asking @eve to split it into two PRs: one for the WebSocket
transport layer and one for the notification handlers.

What Claude does:

terminal
Done. Two actions taken:

1. PR #201 "Hotfix: connection pool exhaustion"
   - Assigned you as reviewer
   - Submitted approving review with comment: "LGTM. Connection pool
     fix looks correct. Fast-track merge approved."

2. PR #198 "Add WebSocket support"
   - Posted comment: "@eve This PR covers both the WebSocket transport
     layer and the notification handlers (47 files). Could you split
     this into two PRs? Suggested split:
     - PR A: WebSocket transport (src/transport/*)
     - PR B: Notification handlers (src/handlers/notifications/*)
     This will make review faster and reduce merge conflict risk."

Combining Surfaces ​

A typical day might use three surfaces:

7:00 AM   Desktop App runs the PR digest automatically
8:30 AM   You read the digest on Desktop, approve urgent PRs
9:00 AM   Terminal CLI for deep feature work
12:00 PM  VS Code for reviewing and refactoring a specific module
5:30 PM   Remote Control from phone to monitor a long-running migration

Teleport: Cloud to Local ​

Teleport handles the reverse direction -- you started a conversation on claude.ai (web) and want to continue in your local terminal where Claude has access to your actual files.

bash
# In your terminal:
/teleport

# Claude shows a code to enter on claude.ai, or you paste the session URL:
/teleport https://claude.ai/chat/abc123

What the teleport process looks like:

terminal
$ claude
> /teleport https://claude.ai/chat/abc123

Connecting to cloud session...
Downloading conversation history (23 messages, 4,200 tokens)...

Session teleported successfully.

Context imported:
  - 23 messages from cloud conversation
  - Topic: "Design a caching layer for the user service"
  - Key decisions: Redis for hot data, PostgreSQL for cold data
  - Pending: Implementation plan needs local file access

You can now continue this conversation with full local file access.

> implement the caching plan we discussed -- start with the Redis layer

The conversation history transfers to your local session. Claude now has access to your local filesystem and tools, while keeping the context from the web conversation.

When to use Teleport: You were brainstorming an approach on the web, and now want to implement it. Instead of re-explaining everything, teleport the session and say "implement the plan we just discussed."


When Things Go Wrong ​

IDE Extension Version Mismatch ​

Symptom: The VS Code Claude Code panel shows errors, fails to connect, or features are missing.

terminal
  Claude Code Panel (VS Code):
  ─────────────────────────────────
  Error: Extension version 1.2.0 is not compatible with CLI version 1.5.0.
  Some features may not work correctly.

  Please update the VS Code extension to match your CLI version.

Root cause: The VS Code extension and the CLI tool have different version numbers. Some features (like parallel conversations or inline diff improvements) require matching versions.

Fix:

bash
# Check your CLI version
claude --version

# Update the VS Code extension:
# 1. Open VS Code
# 2. Go to Extensions (Ctrl+Shift+X)
# 3. Search "Claude Code"
# 4. Click "Update" if available

# Or update via command line:
code --install-extension anthropic.claude-code --force

# Update CLI to match if needed:
npm update -g @anthropic-ai/claude-code

Prevention: Enable auto-update for the VS Code extension in VS Code settings. When you update the CLI, always check the extension version too.

Remote Control Connection Issues ​

Symptom: You scan the QR code on your phone but the remote session does not load, or it loads but then disconnects.

terminal
  Phone browser:
  ─────────────────────────────────
  Connecting to remote session...

  Error: Session not found or expired.
  The remote session may have ended or the connection timed out.

Common causes and fixes:

  1. Session ended on workstation: If the Claude process on your workstation exited (crashed, terminal closed, machine went to sleep), the remote session is gone. Restart Claude and run /remote-control again.

  2. Network changed: Your phone switched from WiFi to cellular, breaking the WebSocket. Refresh the browser page to reconnect.

  3. Firewall blocking WebSocket: Corporate networks sometimes block WebSocket connections to external services. Try using your phone's cellular data instead of corporate WiFi.

  4. Session timeout: Remote control sessions time out after extended inactivity (typically 30 minutes of no messages). Re-run /remote-control on your workstation to get a new session URL.

terminal
# On your workstation, check if the session is still alive:
> /remote-control

Remote control is already active for this session.
Session URL: https://claude.ai/remote/sess_def456uvw

If your device cannot connect, try refreshing the page or
scanning the QR code again.

Desktop App Scheduled Task Not Running ​

Symptom: Your 7 AM PR digest does not appear.

Checklist:

terminal
# 1. Is the Desktop App running?
# The scheduled agent requires the Desktop App process to be active.
# Check your system tray / menu bar for the Claude icon.

# 2. Is the MCP server configured?
# Open Desktop App settings and verify the GitHub MCP config.
# The GITHUB_TOKEN must have repo and read:org scopes.

# 3. Check the agent logs:
# Desktop App > Settings > Scheduled Tasks > View Logs

  Agent log (2026-05-27 07:00:01):
  Error: MCP server github failed to start.
  Reason: GITHUB_TOKEN environment variable not set.

# Fix: Update the MCP config with a valid token

Knowledge Check ​

You started a long refactoring task on your workstation and enabled Remote Control. Your phone shows Claude's progress. Where are the files being modified?
On the cloud servers that host the remote control session
On your phone through the browser
On your workstation -- the phone is only a display and input device
Files are synced between your workstation and the cloud
You brainstormed an architecture on claude.ai (web) and now want to implement it locally. What is the fastest way to continue?
Copy-paste the conversation into a new terminal session
Use /teleport to pull the cloud conversation into your local terminal
Start a new session and re-explain the architecture
Use /remote-control to connect the web session to your terminal
In VS Code, Claude proposes a change to a file but it is missing an important import. What should you do?
Accept the change and manually add the import yourself
Reject the entire file change and start over
Reject the specific hunk and tell Claude what is missing in the chat
Close the diff view and edit the file directly

Chapter Summary ​

  • VS Code extension provides inline diffs with per-hunk accept/reject, @-mentions for precise file references, and parallel conversations
  • Remote Control lets you monitor and steer a long-running local session from any device -- files and tools stay on your workstation
  • Desktop App scheduling automates recurring tasks like daily PR digests
  • Teleport pulls web conversations into your local terminal for implementation
  • Use the right surface for the right task: terminal for heavy work, IDE for refactoring, mobile for monitoring
  • When the IDE extension misbehaves, check version compatibility between CLI and extension
  • Remote Control sessions require your workstation to stay active -- if the process dies, the remote session is gone

Further reading: A15 Claude Code Internals explains how session state is managed across surfaces, including the compaction and serialization mechanisms that make Teleport and Remote Control possible.

Next: Chapter 12: CI/CD & GitHub Actions

Released under MIT License